summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/Makefile2
-rw-r--r--drivers/gpio/Kconfig13
-rw-r--r--drivers/gpio/Makefile2
-rw-r--r--drivers/gpio/gpio-stmpe.c161
-rw-r--r--drivers/gpio/gpio.c134
-rw-r--r--drivers/i2c/busses/Kconfig4
-rw-r--r--drivers/i2c/busses/i2c-imx.c324
-rw-r--r--drivers/mfd/Kconfig4
-rw-r--r--drivers/mfd/Makefile1
-rw-r--r--drivers/mfd/mc13xxx.c31
-rw-r--r--drivers/mfd/stmpe-i2c.c153
-rw-r--r--drivers/misc/Kconfig17
-rw-r--r--drivers/misc/Makefile5
-rw-r--r--drivers/misc/jtag.c392
-rw-r--r--drivers/mtd/core.c12
-rw-r--r--drivers/mtd/mtd.h5
-rw-r--r--drivers/mtd/mtdoob.c15
-rw-r--r--drivers/mtd/mtdraw.c19
-rw-r--r--drivers/mtd/nand/Makefile1
-rw-r--r--drivers/mtd/nand/nand_base.c20
-rw-r--r--drivers/mtd/nand/nand_omap_gpmc.c177
-rw-r--r--drivers/mtd/nand/nand_s3c24xx.c10
-rw-r--r--drivers/net/Kconfig5
-rw-r--r--drivers/net/Makefile1
-rw-r--r--drivers/net/gianfar.c548
-rw-r--r--drivers/net/gianfar.h284
-rw-r--r--drivers/net/miidev.c2
-rw-r--r--drivers/spi/Kconfig2
-rw-r--r--drivers/spi/imx_spi.c2
30 files changed, 2157 insertions, 191 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 883b0e7bc9..70797c182c 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -12,11 +12,13 @@ source "drivers/video/Kconfig"
source "drivers/mci/Kconfig"
source "drivers/clk/Kconfig"
source "drivers/mfd/Kconfig"
+source "drivers/misc/Kconfig"
source "drivers/led/Kconfig"
source "drivers/eeprom/Kconfig"
source "drivers/input/Kconfig"
source "drivers/watchdog/Kconfig"
source "drivers/pwm/Kconfig"
source "drivers/dma/Kconfig"
+source "drivers/gpio/Kconfig"
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index ea3263f615..28a5cb8f35 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -15,5 +15,7 @@ obj-$(CONFIG_LED) += led/
obj-y += eeprom/
obj-$(CONFIG_PWM) += pwm/
obj-y += input/
+obj-y += misc/
obj-y += dma/
obj-y += watchdog/
+obj-y += gpio/
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
new file mode 100644
index 0000000000..022a30988e
--- /dev/null
+++ b/drivers/gpio/Kconfig
@@ -0,0 +1,13 @@
+config GPIOLIB
+ bool
+
+if GPIOLIB
+
+menu "GPIO "
+
+config GPIO_STMPE
+ depends on I2C_STMPE
+ bool "STMPE GPIO Expander"
+endmenu
+
+endif
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
new file mode 100644
index 0000000000..945122b083
--- /dev/null
+++ b/drivers/gpio/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_GPIOLIB) += gpio.o
+obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o
diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c
new file mode 100644
index 0000000000..fa3b041534
--- /dev/null
+++ b/drivers/gpio/gpio-stmpe.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2012 Pengutronix
+ * Steffen Trumtrar <s.trumtrar@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <io.h>
+#include <gpio.h>
+#include <init.h>
+#include <mfd/stmpe-i2c.h>
+
+#define GPIO_BASE 0x80
+#define GPIO_SET (GPIO_BASE + 0x02)
+#define GPIO_CLR (GPIO_BASE + 0x04)
+#define GPIO_MP (GPIO_BASE + 0x06)
+#define GPIO_SET_DIR (GPIO_BASE + 0x08)
+#define GPIO_ED (GPIO_BASE + 0x0a)
+#define GPIO_RE (GPIO_BASE + 0x0c)
+#define GPIO_FE (GPIO_BASE + 0x0e)
+#define GPIO_PULL_UP (GPIO_BASE + 0x10)
+#define GPIO_AF (GPIO_BASE + 0x12)
+#define GPIO_LT (GPIO_BASE + 0x16)
+
+#define OFFSET(gpio) (0xff & (1 << (gpio)) ? 1 : 0)
+
+struct stmpe_gpio_chip {
+ struct gpio_chip chip;
+ struct stmpe_client_info *ci;
+};
+
+static void stmpe_gpio_set_value(struct gpio_chip *chip, unsigned gpio, int value)
+{
+ struct stmpe_gpio_chip *stmpegpio = container_of(chip, struct stmpe_gpio_chip, chip);
+ struct stmpe_client_info *ci = (struct stmpe_client_info *)stmpegpio->ci;
+ int ret;
+ u8 val;
+
+ ci->read_reg(ci->stmpe, GPIO_MP + OFFSET(gpio), &val);
+
+ val |= 1 << (gpio % 8);
+
+ if (value)
+ ret = ci->write_reg(ci->stmpe, GPIO_SET + OFFSET(gpio), val);
+ else
+ ret = ci->write_reg(ci->stmpe, GPIO_CLR + OFFSET(gpio), val);
+
+ if (ret)
+ dev_err(chip->dev, "write failed!\n");
+}
+
+static int stmpe_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
+{
+ struct stmpe_gpio_chip *stmpegpio = container_of(chip, struct stmpe_gpio_chip, chip);
+ struct stmpe_client_info *ci = (struct stmpe_client_info *)stmpegpio->ci;
+ int ret;
+ u8 val;
+
+ ci->read_reg(ci->stmpe, GPIO_SET_DIR + OFFSET(gpio), &val);
+ val &= ~(1 << (gpio % 8));
+ ret = ci->write_reg(ci->stmpe, GPIO_SET_DIR + OFFSET(gpio), val);
+
+ if (ret)
+ dev_err(chip->dev, "couldn't change direction. Write failed!\n");
+
+ return ret;
+}
+
+static int stmpe_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, int value)
+{
+ struct stmpe_gpio_chip *stmpegpio = container_of(chip, struct stmpe_gpio_chip, chip);
+ struct stmpe_client_info *ci = (struct stmpe_client_info *)stmpegpio->ci;
+ int ret;
+ u8 val;
+
+ ci->read_reg(ci->stmpe, GPIO_SET_DIR + OFFSET(gpio), &val);
+ val |= 1 << (gpio % 8);
+ ret = ci->write_reg(ci->stmpe, GPIO_SET_DIR + OFFSET(gpio), val);
+
+ stmpe_gpio_set_value(chip, gpio, value);
+
+ if (ret)
+ dev_err(chip->dev, "couldn't change direction. Write failed!\n");
+
+ return ret;
+}
+
+static int stmpe_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
+{
+ struct stmpe_gpio_chip *stmpegpio = container_of(chip, struct stmpe_gpio_chip, chip);
+ struct stmpe_client_info *ci = (struct stmpe_client_info *)stmpegpio->ci;
+ u8 val;
+ int ret;
+
+ ret = ci->read_reg(ci->stmpe, GPIO_MP + OFFSET(gpio), &val);
+
+ if (ret)
+ dev_err(chip->dev, "read failed\n");
+
+ return val & (1 << (gpio % 8)) ? 1 : 0;
+}
+
+static struct gpio_ops stmpe_gpio_ops = {
+ .direction_input = stmpe_gpio_direction_input,
+ .direction_output = stmpe_gpio_direction_output,
+ .get = stmpe_gpio_get_value,
+ .set = stmpe_gpio_set_value,
+};
+
+static int stmpe_gpio_probe(struct device_d *dev)
+{
+ struct stmpe_gpio_chip *stmpegpio;
+ struct stmpe_client_info *ci;
+ int ret;
+
+ stmpegpio = xzalloc(sizeof(*stmpegpio));
+
+ stmpegpio->chip.ops = &stmpe_gpio_ops;
+ stmpegpio->ci = dev->platform_data;
+
+ ci = (struct stmpe_client_info *)stmpegpio->ci;
+
+ if (ci->stmpe->pdata->gpio_base)
+ stmpegpio->chip.base = ci->stmpe->pdata->gpio_base;
+ else
+ stmpegpio->chip.base = -1;
+ stmpegpio->chip.ngpio = 16;
+ stmpegpio->chip.dev = dev;
+
+ ret = gpiochip_add(&stmpegpio->chip);
+
+ if (ret) {
+ dev_err(dev, "couldn't add gpiochip\n");
+ return ret;
+ }
+
+ dev_info(dev, "probed stmpe gpiochip%d with base %d\n", dev->id, stmpegpio->chip.base);
+ return 0;
+}
+
+static struct driver_d stmpe_gpio_driver = {
+ .name = "stmpe-gpio",
+ .probe = stmpe_gpio_probe,
+};
+
+static int stmpe_gpio_add(void)
+{
+ return register_driver(&stmpe_gpio_driver);
+}
+coredevice_initcall(stmpe_gpio_add);
diff --git a/drivers/gpio/gpio.c b/drivers/gpio/gpio.c
new file mode 100644
index 0000000000..6ad8d274e7
--- /dev/null
+++ b/drivers/gpio/gpio.c
@@ -0,0 +1,134 @@
+#include <common.h>
+#include <gpio.h>
+#include <errno.h>
+
+static LIST_HEAD(chip_list);
+
+#define ARCH_NR_GPIOS 256
+
+static struct gpio_chip *gpio_desc[ARCH_NR_GPIOS];
+
+static int gpio_is_valid(unsigned gpio)
+{
+ if (gpio < ARCH_NR_GPIOS)
+ return 1;
+ return 0;
+}
+
+void gpio_set_value(unsigned gpio, int value)
+{
+ struct gpio_chip *chip = gpio_desc[gpio];
+
+ if (!gpio_is_valid(gpio))
+ return;
+ if (!chip)
+ return;
+ if (!chip->ops->set)
+ return;
+ chip->ops->set(chip, gpio - chip->base, value);
+}
+EXPORT_SYMBOL(gpio_set_value);
+
+int gpio_get_value(unsigned gpio)
+{
+ struct gpio_chip *chip = gpio_desc[gpio];
+
+ if (!gpio_is_valid(gpio))
+ return -EINVAL;
+ if (!chip)
+ return -ENODEV;
+ if (!chip->ops->get)
+ return -ENOSYS;
+ return chip->ops->get(chip, gpio - chip->base);
+}
+EXPORT_SYMBOL(gpio_get_value);
+
+int gpio_direction_output(unsigned gpio, int value)
+{
+ struct gpio_chip *chip = gpio_desc[gpio];
+
+ if (!gpio_is_valid(gpio))
+ return -EINVAL;
+ if (!chip)
+ return -ENODEV;
+ if (!chip->ops->direction_output)
+ return -ENOSYS;
+ return chip->ops->direction_output(chip, gpio - chip->base, value);
+}
+EXPORT_SYMBOL(gpio_direction_output);
+
+int gpio_direction_input(unsigned gpio)
+{
+ struct gpio_chip *chip = gpio_desc[gpio];
+
+ if (!gpio_is_valid(gpio))
+ return -EINVAL;
+ if (!chip)
+ return -ENODEV;
+ if (!chip->ops->direction_input)
+ return -ENOSYS;
+ return chip->ops->direction_input(chip, gpio - chip->base);
+}
+EXPORT_SYMBOL(gpio_direction_input);
+
+static int gpiochip_find_base(int start, int ngpio)
+{
+ int i;
+ int spare = 0;
+ int base = -ENOSPC;
+
+ if (start < 0)
+ start = 0;
+
+ for (i = start; i < ARCH_NR_GPIOS; i++) {
+ struct gpio_chip *chip = gpio_desc[i];
+
+ if (!chip) {
+ spare++;
+ if (spare == ngpio) {
+ base = i + 1 - ngpio;
+ break;
+ }
+ } else {
+ spare = 0;
+ i += chip->ngpio - 1;
+ }
+ }
+
+ if (gpio_is_valid(base))
+ debug("%s: found new base at %d\n", __func__, base);
+ return base;
+}
+
+int gpiochip_add(struct gpio_chip *chip)
+{
+ int base, i;
+
+ base = gpiochip_find_base(chip->base, chip->ngpio);
+ if (base < 0)
+ return base;
+
+ if (chip->base >= 0 && chip->base != base)
+ return -EBUSY;
+
+ chip->base = base;
+
+ list_add_tail(&chip->list, &chip_list);
+
+ for (i = chip->base; i < chip->base + chip->ngpio; i++)
+ gpio_desc[i] = chip;
+
+ return 0;
+}
+
+int gpio_get_num(struct device_d *dev, int gpio)
+{
+ struct gpio_chip *chip;
+
+ list_for_each_entry(chip, &chip_list, list) {
+ if (chip->dev == dev)
+ return chip->base + gpio;
+ }
+
+ return -ENODEV;
+}
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 1ce5c00276..3f998eafa5 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -5,8 +5,8 @@
menu "I2C Hardware Bus support"
config I2C_IMX
- bool "i.MX I2C Master driver"
- depends on ARCH_IMX && !ARCH_IMX1
+ bool "MPC85xx/i.MX I2C Master driver"
+ depends on (ARCH_IMX && !ARCH_IMX1) || ARCH_MPC85XX
config I2C_OMAP
bool "OMAP I2C Master driver"
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index da6218f43c..60182042db 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2012 GE Intelligent Platforms, Inc
* Copyright (C) 2002 Motorola GSG-China
* 2009 Marc Kleine-Budde, Pengutronix
*
@@ -22,7 +23,8 @@
*
* Desc.:
* Implementation of I2C Adapter/Algorithm Driver
- * for I2C Bus integrated in Freescale i.MX/MXC processors
+ * for I2C Bus integrated in Freescale i.MX/MXC processors and
+ * 85xx processors.
*
* Derived from Motorola GSG China I2C example driver
*
@@ -36,7 +38,6 @@
#include <clock.h>
#include <common.h>
#include <driver.h>
-#include <gpio.h>
#include <init.h>
#include <malloc.h>
#include <types.h>
@@ -46,23 +47,23 @@
#include <io.h>
#include <i2c/i2c.h>
-#include <mach/generic.h>
#include <mach/clock.h>
/* This will be the driver name */
-#define DRIVER_NAME "i2c-imx"
+#define DRIVER_NAME "i2c-fsl"
/* Default value */
-#define IMX_I2C_BIT_RATE 100000 /* 100kHz */
+#define FSL_I2C_BIT_RATE 100000 /* 100kHz */
-/* IMX I2C registers */
-#define IMX_I2C_IADR 0x00 /* i2c slave address */
-#define IMX_I2C_IFDR 0x04 /* i2c frequency divider */
-#define IMX_I2C_I2CR 0x08 /* i2c control */
-#define IMX_I2C_I2SR 0x0C /* i2c status */
-#define IMX_I2C_I2DR 0x10 /* i2c transfer data */
+/* FSL I2C registers */
+#define FSL_I2C_IADR 0x00 /* i2c slave address */
+#define FSL_I2C_IFDR 0x04 /* i2c frequency divider */
+#define FSL_I2C_I2CR 0x08 /* i2c control */
+#define FSL_I2C_I2SR 0x0C /* i2c status */
+#define FSL_I2C_I2DR 0x10 /* i2c transfer data */
+#define FSL_I2C_DFSRR 0x14 /* i2c digital filter sampling rate */
-/* Bits of IMX I2C registers */
+/* Bits of FSL I2C registers */
#define I2SR_RXAK 0x01
#define I2SR_IIF 0x02
#define I2SR_SRW 0x04
@@ -85,6 +86,7 @@
*
* Duplicated divider values removed from list
*/
+#ifndef CONFIG_PPC
static u16 i2c_clk_div[50][2] = {
{ 22, 0x20 }, { 24, 0x21 }, { 26, 0x22 }, { 28, 0x23 },
{ 30, 0x00 }, { 32, 0x24 }, { 36, 0x25 }, { 40, 0x26 },
@@ -100,24 +102,26 @@ static u16 i2c_clk_div[50][2] = {
{ 1920, 0x1B }, { 2048, 0x3F }, { 2304, 0x1C }, { 2560, 0x1D },
{ 3072, 0x1E }, { 3840, 0x1F }
};
+#endif
-struct imx_i2c_struct {
+struct fsl_i2c_struct {
void __iomem *base;
struct i2c_adapter adapter;
unsigned int disable_delay;
int stopped;
- unsigned int ifdr; /* IMX_I2C_IFDR */
+ unsigned int ifdr; /* FSL_I2C_IFDR */
+ unsigned int dfsrr; /* FSL_I2C_DFSRR */
};
-#define to_imx_i2c_struct(a) container_of(a, struct imx_i2c_struct, adapter)
+#define to_fsl_i2c_struct(a) container_of(a, struct fsl_i2c_struct, adapter)
#ifdef CONFIG_I2C_DEBUG
-static void i2c_imx_dump_reg(struct i2c_adapter *adapter)
+static void i2c_fsl_dump_reg(struct i2c_adapter *adapter)
{
- struct imx_i2c_struct *i2c_imx = to_imx_i2c_struct(adapter);
+ struct fsl_i2c_struct *i2c_fsl = to_fsl_i2c_struct(adapter);
u32 reg_cr, reg_sr;
- reg_cr = readb(i2c_imx->base + IMX_I2C_I2CR);
- reg_sr = readb(i2c_imx->base + IMX_I2C_I2SR);
+ reg_cr = readb(i2c_fsl->base + FSL_I2C_I2CR);
+ reg_sr = readb(i2c_fsl->base + FSL_I2C_I2SR);
dev_dbg(adapter->dev, "CONTROL:\t"
"IEN =%d, IIEN=%d, MSTA=%d, MTX =%d, TXAK=%d, RSTA=%d\n",
@@ -133,22 +137,22 @@ static void i2c_imx_dump_reg(struct i2c_adapter *adapter)
(reg_sr & I2SR_RXAK ? 1 : 0));
}
#else
-static inline void i2c_imx_dump_reg(struct i2c_adapter *adapter)
+static inline void i2c_fsl_dump_reg(struct i2c_adapter *adapter)
{
return;
}
#endif
-static int i2c_imx_bus_busy(struct i2c_adapter *adapter, int for_busy)
+static int i2c_fsl_bus_busy(struct i2c_adapter *adapter, int for_busy)
{
- struct imx_i2c_struct *i2c_imx = to_imx_i2c_struct(adapter);
- void __iomem *base = i2c_imx->base;
+ struct fsl_i2c_struct *i2c_fsl = to_fsl_i2c_struct(adapter);
+ void __iomem *base = i2c_fsl->base;
uint64_t start;
unsigned int temp;
start = get_time_ns();
while (1) {
- temp = readb(base + IMX_I2C_I2SR);
+ temp = readb(base + FSL_I2C_I2SR);
if (for_busy && (temp & I2SR_IBB))
break;
if (!for_busy && !(temp & I2SR_IBB))
@@ -164,15 +168,15 @@ static int i2c_imx_bus_busy(struct i2c_adapter *adapter, int for_busy)
return 0;
}
-static int i2c_imx_trx_complete(struct i2c_adapter *adapter)
+static int i2c_fsl_trx_complete(struct i2c_adapter *adapter)
{
- struct imx_i2c_struct *i2c_imx = to_imx_i2c_struct(adapter);
- void __iomem *base = i2c_imx->base;
+ struct fsl_i2c_struct *i2c_fsl = to_fsl_i2c_struct(adapter);
+ void __iomem *base = i2c_fsl->base;
uint64_t start;
start = get_time_ns();
while (1) {
- unsigned int reg = readb(base + IMX_I2C_I2SR);
+ unsigned int reg = readb(base + FSL_I2C_I2SR);
if (reg & I2SR_IIF)
break;
@@ -181,20 +185,20 @@ static int i2c_imx_trx_complete(struct i2c_adapter *adapter)
return -EIO;
}
}
- writeb(0, base + IMX_I2C_I2SR);
+ writeb(0, base + FSL_I2C_I2SR);
return 0;
}
-static int i2c_imx_acked(struct i2c_adapter *adapter)
+static int i2c_fsl_acked(struct i2c_adapter *adapter)
{
- struct imx_i2c_struct *i2c_imx = to_imx_i2c_struct(adapter);
- void __iomem *base = i2c_imx->base;
+ struct fsl_i2c_struct *i2c_fsl = to_fsl_i2c_struct(adapter);
+ void __iomem *base = i2c_fsl->base;
uint64_t start;
start = get_time_ns();
while (1) {
- unsigned int reg = readb(base + IMX_I2C_I2SR);
+ unsigned int reg = readb(base + FSL_I2C_I2SR);
if (!(reg & I2SR_RXAK))
break;
@@ -207,71 +211,137 @@ static int i2c_imx_acked(struct i2c_adapter *adapter)
return 0;
}
-static int i2c_imx_start(struct i2c_adapter *adapter)
+static int i2c_fsl_start(struct i2c_adapter *adapter)
{
- struct imx_i2c_struct *i2c_imx = to_imx_i2c_struct(adapter);
- void __iomem *base = i2c_imx->base;
+ struct fsl_i2c_struct *i2c_fsl = to_fsl_i2c_struct(adapter);
+ void __iomem *base = i2c_fsl->base;
unsigned int temp = 0;
int result;
- writeb(i2c_imx->ifdr, base + IMX_I2C_IFDR);
+ writeb(i2c_fsl->ifdr, base + FSL_I2C_IFDR);
+ if (i2c_fsl->dfsrr != -1)
+ writeb(i2c_fsl->dfsrr, base + FSL_I2C_DFSRR);
+
/* Enable I2C controller */
- writeb(0, base + IMX_I2C_I2SR);
- writeb(I2CR_IEN, base + IMX_I2C_I2CR);
+ writeb(0, base + FSL_I2C_I2SR);
+ writeb(I2CR_IEN, base + FSL_I2C_I2CR);
/* Wait controller to be stable */
udelay(100);
/* Start I2C transaction */
- temp = readb(base + IMX_I2C_I2CR);
+ temp = readb(base + FSL_I2C_I2CR);
temp |= I2CR_MSTA;
- writeb(temp, base + IMX_I2C_I2CR);
+ writeb(temp, base + FSL_I2C_I2CR);
- result = i2c_imx_bus_busy(adapter, 1);
+ result = i2c_fsl_bus_busy(adapter, 1);
if (result)
return result;
- i2c_imx->stopped = 0;
+ i2c_fsl->stopped = 0;
temp |= I2CR_MTX | I2CR_TXAK;
- writeb(temp, base + IMX_I2C_I2CR);
+ writeb(temp, base + FSL_I2C_I2CR);
return result;
}
-static void i2c_imx_stop(struct i2c_adapter *adapter)
+static void i2c_fsl_stop(struct i2c_adapter *adapter)
{
- struct imx_i2c_struct *i2c_imx = to_imx_i2c_struct(adapter);
- void __iomem *base = i2c_imx->base;
+ struct fsl_i2c_struct *i2c_fsl = to_fsl_i2c_struct(adapter);
+ void __iomem *base = i2c_fsl->base;
unsigned int temp = 0;
- if (!i2c_imx->stopped) {
+ if (!i2c_fsl->stopped) {
/* Stop I2C transaction */
- temp = readb(base + IMX_I2C_I2CR);
+ temp = readb(base + FSL_I2C_I2CR);
temp &= ~(I2CR_MSTA | I2CR_MTX);
- writeb(temp, base + IMX_I2C_I2CR);
+ writeb(temp, base + FSL_I2C_I2CR);
/* wait for the stop condition to be send, otherwise the i2c
* controller is disabled before the STOP is sent completely */
- i2c_imx->stopped = i2c_imx_bus_busy(adapter, 0) ? 0 : 1;
- }
- if (cpu_is_mx1()) {
- /*
- * This delay caused by an i.MXL hardware bug.
- * If no (or too short) delay, no "STOP" bit will be generated.
- */
- udelay(i2c_imx->disable_delay);
+ i2c_fsl->stopped = i2c_fsl_bus_busy(adapter, 0) ? 0 : 1;
}
- if (!i2c_imx->stopped) {
- i2c_imx_bus_busy(adapter, 0);
- i2c_imx->stopped = 1;
+ if (!i2c_fsl->stopped) {
+ i2c_fsl_bus_busy(adapter, 0);
+ i2c_fsl->stopped = 1;
}
/* Disable I2C controller, and force our state to stopped */
- writeb(0, base + IMX_I2C_I2CR);
+ writeb(0, base + FSL_I2C_I2CR);
}
-static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx,
+#ifdef CONFIG_PPC
+static void i2c_fsl_set_clk(struct fsl_i2c_struct *i2c_fsl,
+ unsigned int rate)
+{
+ void __iomem *base;
+ unsigned int i2c_clk;
+ unsigned short divider;
+ /*
+ * We want to choose an FDR/DFSR that generates an I2C bus speed that
+ * is equal to or lower than the requested speed. That means that we
+ * want the first divider that is equal to or greater than the
+ * calculated divider.
+ */
+ u8 dfsr, fdr;
+ /* a, b and dfsr matches identifiers A,B and C respectively in AN2919 */
+ unsigned short a, b, ga, gb;
+ unsigned long c_div, est_div;
+
+ fdr = 0x31; /* Default if no FDR found */
+ base = i2c_fsl->base;
+ i2c_clk = fsl_get_i2c_freq();
+ divider = min((unsigned short)(i2c_clk / rate), (unsigned short) -1);
+
+ /*
+ * Condition 1: dfsr <= 50ns/T (T=period of I2C source clock in ns).
+ * or (dfsr * T) <= 50ns.
+ * Translate to dfsr = 5 * Frequency / 100,000,000
+ */
+ dfsr = (5 * (i2c_clk / 1000)) / 100000;
+ dev_dbg(i2c_fsl->adapter.dev,
+ "<%s> requested speed:%d, i2c_clk:%d\n", __func__,
+ rate, i2c_clk);
+ if (!dfsr)
+ dfsr = 1;
+
+ est_div = ~0;
+ for (ga = 0x4, a = 10; a <= 30; ga++, a += 2) {
+ for (gb = 0; gb < 8; gb++) {
+ b = 16 << gb;
+ c_div = b * (a + ((3*dfsr)/b)*2);
+ if ((c_div > divider) && (c_div < est_div)) {
+ unsigned short bin_gb, bin_ga;
+
+ est_div = c_div;
+ bin_gb = gb << 2;
+ bin_ga = (ga & 0x3) | ((ga & 0x4) << 3);
+ fdr = bin_gb | bin_ga;
+ rate = i2c_clk / est_div;
+ dev_dbg(i2c_fsl->adapter.dev,
+ "FDR:0x%.2x, div:%ld, ga:0x%x, gb:0x%x,"
+ " a:%d, b:%d, speed:%d\n", fdr, est_div,
+ ga, gb, a, b, rate);
+ /* Condition 2 not accounted for */
+ dev_dbg(i2c_fsl->adapter.dev,
+ "Tr <= %d ns\n", (b - 3 * dfsr) *
+ 1000000 / (i2c_clk / 1000));
+ }
+ }
+ if (a == 20)
+ a += 2;
+ if (a == 24)
+ a += 4;
+ }
+ dev_dbg(i2c_fsl->adapter.dev,
+ "divider:%d, est_div:%ld, DFSR:%d\n", divider, est_div, dfsr);
+ dev_dbg(i2c_fsl->adapter.dev, "FDR:0x%.2x, speed:%d\n", fdr, rate);
+ i2c_fsl->ifdr = fdr;
+ i2c_fsl->dfsrr = dfsr;
+}
+#else
+static void i2c_fsl_set_clk(struct fsl_i2c_struct *i2c_fsl,
unsigned int rate)
{
unsigned int i2c_clk_rate;
@@ -279,7 +349,7 @@ static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx,
int i;
/* Divider value calculation */
- i2c_clk_rate = imx_get_i2cclk();
+ i2c_clk_rate = fsl_get_i2cclk();
div = (i2c_clk_rate + rate - 1) / rate;
if (div < i2c_clk_div[0][0])
i = 0;
@@ -290,7 +360,7 @@ static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx,
;
/* Store divider value */
- i2c_imx->ifdr = i2c_clk_div[i][1];
+ i2c_fsl->ifdr = i2c_clk_div[i][1];
/*
* There dummy delay is calculated.
@@ -298,20 +368,21 @@ static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx,
* This delay is used in I2C bus disable function
* to fix chip hardware bug.
*/
- i2c_imx->disable_delay =
+ i2c_fsl->disable_delay =
(500000U * i2c_clk_div[i][0] + (i2c_clk_rate / 2) - 1) /
(i2c_clk_rate / 2);
- dev_dbg(i2c_imx->adapter.dev, "<%s> I2C_CLK=%d, REQ DIV=%d\n",
+ dev_dbg(i2c_fsl->adapter.dev, "<%s> I2C_CLK=%d, REQ DIV=%d\n",
__func__, i2c_clk_rate, div);
- dev_dbg(i2c_imx->adapter.dev, "<%s> IFDR[IC]=0x%x, REAL DIV=%d\n",
+ dev_dbg(i2c_fsl->adapter.dev, "<%s> IFDR[IC]=0x%x, REAL DIV=%d\n",
__func__, i2c_clk_div[i][1], i2c_clk_div[i][0]);
}
+#endif
-static int i2c_imx_write(struct i2c_adapter *adapter, struct i2c_msg *msgs)
+static int i2c_fsl_write(struct i2c_adapter *adapter, struct i2c_msg *msgs)
{
- struct imx_i2c_struct *i2c_imx = to_imx_i2c_struct(adapter);
- void __iomem *base = i2c_imx->base;
+ struct fsl_i2c_struct *i2c_fsl = to_fsl_i2c_struct(adapter);
+ void __iomem *base = i2c_fsl->base;
int i, result;
if ( !(msgs->flags & I2C_M_DATA_ONLY) ) {
@@ -320,12 +391,12 @@ static int i2c_imx_write(struct i2c_adapter *adapter, struct i2c_msg *msgs)
__func__, msgs->addr << 1);
/* write slave address */
- writeb(msgs->addr << 1, base + IMX_I2C_I2DR);
+ writeb(msgs->addr << 1, base + FSL_I2C_I2DR);
- result = i2c_imx_trx_complete(adapter);
+ result = i2c_fsl_trx_complete(adapter);
if (result)
return result;
- result = i2c_imx_acked(adapter);
+ result = i2c_fsl_acked(adapter);
if (result)
return result;
}
@@ -335,27 +406,27 @@ static int i2c_imx_write(struct i2c_adapter *adapter, struct i2c_msg *msgs)
dev_dbg(adapter->dev,
"<%s> write byte: B%d=0x%02X\n",
__func__, i, msgs->buf[i]);
- writeb(msgs->buf[i], base + IMX_I2C_I2DR);
+ writeb(msgs->buf[i], base + FSL_I2C_I2DR);
- result = i2c_imx_trx_complete(adapter);
+ result = i2c_fsl_trx_complete(adapter);
if (result)
return result;
- result = i2c_imx_acked(adapter);
+ result = i2c_fsl_acked(adapter);
if (result)
return result;
}
return 0;
}
-static int i2c_imx_read(struct i2c_adapter *adapter, struct i2c_msg *msgs)
+static int i2c_fsl_read(struct i2c_adapter *adapter, struct i2c_msg *msgs)
{
- struct imx_i2c_struct *i2c_imx = to_imx_i2c_struct(adapter);
- void __iomem *base = i2c_imx->base;
+ struct fsl_i2c_struct *i2c_fsl = to_fsl_i2c_struct(adapter);
+ void __iomem *base = i2c_fsl->base;
int i, result;
unsigned int temp;
/* clear IIF */
- writeb(0x0, base + IMX_I2C_I2SR);
+ writeb(0x0, base + FSL_I2C_I2SR);
if ( !(msgs->flags & I2C_M_DATA_ONLY) ) {
dev_dbg(adapter->dev,
@@ -363,28 +434,28 @@ static int i2c_imx_read(struct i2c_adapter *adapter, struct i2c_msg *msgs)
__func__, (msgs->addr << 1) | 0x01);
/* write slave address */
- writeb((msgs->addr << 1) | 0x01, base + IMX_I2C_I2DR);
+ writeb((msgs->addr << 1) | 0x01, base + FSL_I2C_I2DR);
- result = i2c_imx_trx_complete(adapter);
+ result = i2c_fsl_trx_complete(adapter);
if (result)
return result;
- result = i2c_imx_acked(adapter);
+ result = i2c_fsl_acked(adapter);
if (result)
return result;
}
/* setup bus to read data */
- temp = readb(base + IMX_I2C_I2CR);
+ temp = readb(base + FSL_I2C_I2CR);
temp &= ~I2CR_MTX;
if (msgs->len - 1)
temp &= ~I2CR_TXAK;
- writeb(temp, base + IMX_I2C_I2CR);
+ writeb(temp, base + FSL_I2C_I2CR);
- readb(base + IMX_I2C_I2DR); /* dummy read */
+ readb(base + FSL_I2C_I2DR); /* dummy read */
/* read data */
for (i = 0; i < msgs->len; i++) {
- result = i2c_imx_trx_complete(adapter);
+ result = i2c_fsl_trx_complete(adapter);
if (result)
return result;
@@ -393,23 +464,23 @@ static int i2c_imx_read(struct i2c_adapter *adapter, struct i2c_msg *msgs)
* It must generate STOP before read I2DR to prevent
* controller from generating another clock cycle
*/
- temp = readb(base + IMX_I2C_I2CR);
+ temp = readb(base + FSL_I2C_I2CR);
temp &= ~(I2CR_MSTA | I2CR_MTX);
- writeb(temp, base + IMX_I2C_I2CR);
+ writeb(temp, base + FSL_I2C_I2CR);
/*
* adding this delay helps on low bitrates
*/
- udelay(i2c_imx->disable_delay);
+ udelay(i2c_fsl->disable_delay);
- i2c_imx_bus_busy(adapter, 0);
- i2c_imx->stopped = 1;
+ i2c_fsl_bus_busy(adapter, 0);
+ i2c_fsl->stopped = 1;
} else if (i == (msgs->len - 2)) {
- temp = readb(base + IMX_I2C_I2CR);
+ temp = readb(base + FSL_I2C_I2CR);
temp |= I2CR_TXAK;
- writeb(temp, base + IMX_I2C_I2CR);
+ writeb(temp, base + FSL_I2C_I2CR);
}
- msgs->buf[i] = readb(base + IMX_I2C_I2DR);
+ msgs->buf[i] = readb(base + FSL_I2C_I2DR);
dev_dbg(adapter->dev, "<%s> read byte: B%d=0x%02X\n",
__func__, i, msgs->buf[i]);
@@ -417,76 +488,77 @@ static int i2c_imx_read(struct i2c_adapter *adapter, struct i2c_msg *msgs)
return 0;
}
-static int i2c_imx_xfer(struct i2c_adapter *adapter,
+static int i2c_fsl_xfer(struct i2c_adapter *adapter,
struct i2c_msg *msgs, int num)
{
- struct imx_i2c_struct *i2c_imx = to_imx_i2c_struct(adapter);
- void __iomem *base = i2c_imx->base;
+ struct fsl_i2c_struct *i2c_fsl = to_fsl_i2c_struct(adapter);
+ void __iomem *base = i2c_fsl->base;
unsigned int i, temp;
int result;
/* Start I2C transfer */
- result = i2c_imx_start(adapter);
+ result = i2c_fsl_start(adapter);
if (result)
goto fail0;
/* read/write data */
for (i = 0; i < num; i++) {
if (i && !(msgs[i].flags & I2C_M_DATA_ONLY)) {
- temp = readb(base + IMX_I2C_I2CR);
+ temp = readb(base + FSL_I2C_I2CR);
temp |= I2CR_RSTA;
- writeb(temp, base + IMX_I2C_I2CR);
+ writeb(temp, base + FSL_I2C_I2CR);
- result = i2c_imx_bus_busy(adapter, 1);
+ result = i2c_fsl_bus_busy(adapter, 1);
if (result)
goto fail0;
}
- i2c_imx_dump_reg(adapter);
+ i2c_fsl_dump_reg(adapter);
/* write/read data */
if (msgs[i].flags & I2C_M_RD)
- result = i2c_imx_read(adapter, &msgs[i]);
+ result = i2c_fsl_read(adapter, &msgs[i]);
else
- result = i2c_imx_write(adapter, &msgs[i]);
+ result = i2c_fsl_write(adapter, &msgs[i]);
if (result)
goto fail0;
}
fail0:
/* Stop I2C transfer */
- i2c_imx_stop(adapter);
+ i2c_fsl_stop(adapter);
return (result < 0) ? result : num;
}
-static int __init i2c_imx_probe(struct device_d *pdev)
+static int __init i2c_fsl_probe(struct device_d *pdev)
{
- struct imx_i2c_struct *i2c_imx;
+ struct fsl_i2c_struct *i2c_fsl;
struct i2c_platform_data *pdata;
int ret;
pdata = pdev->platform_data;
- i2c_imx = kzalloc(sizeof(struct imx_i2c_struct), GFP_KERNEL);
+ i2c_fsl = kzalloc(sizeof(struct fsl_i2c_struct), GFP_KERNEL);
- /* Setup i2c_imx driver structure */
- i2c_imx->adapter.master_xfer = i2c_imx_xfer;
- i2c_imx->adapter.nr = pdev->id;
- i2c_imx->adapter.dev = pdev;
- i2c_imx->base = dev_request_mem_region(pdev, 0);
+ /* Setup i2c_fsl driver structure */
+ i2c_fsl->adapter.master_xfer = i2c_fsl_xfer;
+ i2c_fsl->adapter.nr = pdev->id;
+ i2c_fsl->adapter.dev = pdev;
+ i2c_fsl->base = dev_request_mem_region(pdev, 0);
+ i2c_fsl->dfsrr = -1;
/* Set up clock divider */
if (pdata && pdata->bitrate)
- i2c_imx_set_clk(i2c_imx, pdata->bitrate);
+ i2c_fsl_set_clk(i2c_fsl, pdata->bitrate);
else
- i2c_imx_set_clk(i2c_imx, IMX_I2C_BIT_RATE);
+ i2c_fsl_set_clk(i2c_fsl, FSL_I2C_BIT_RATE);
/* Set up chip registers to defaults */
- writeb(0, i2c_imx->base + IMX_I2C_I2CR);
- writeb(0, i2c_imx->base + IMX_I2C_I2SR);
+ writeb(0, i2c_fsl->base + FSL_I2C_I2CR);
+ writeb(0, i2c_fsl->base + FSL_I2C_I2SR);
/* Add I2C adapter */
- ret = i2c_add_numbered_adapter(&i2c_imx->adapter);
+ ret = i2c_add_numbered_adapter(&i2c_fsl->adapter);
if (ret < 0) {
dev_err(pdev, "registration failed\n");
goto fail;
@@ -495,17 +567,17 @@ static int __init i2c_imx_probe(struct device_d *pdev)
return 0;
fail:
- kfree(i2c_imx);
+ kfree(i2c_fsl);
return ret;
}
-static struct driver_d i2c_imx_driver = {
- .probe = i2c_imx_probe,
+static struct driver_d i2c_fsl_driver = {
+ .probe = i2c_fsl_probe,
.name = DRIVER_NAME,
};
-static int __init i2c_adap_imx_init(void)
+static int __init i2c_adap_fsl_init(void)
{
- return register_driver(&i2c_imx_driver);
+ return register_driver(&i2c_fsl_driver);
}
-device_initcall(i2c_adap_imx_init);
+device_initcall(i2c_adap_fsl_init);
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index af67935092..20eef86e39 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -33,4 +33,8 @@ config I2C_TWL6030
select I2C_TWLCORE
bool "TWL6030 driver"
+config I2C_STMPE
+ depends on I2C
+ bool "STMPE-i2c driver"
+
endmenu
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index e11223b1f9..792ae2da8f 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_I2C_LP3972) += lp3972.o
obj-$(CONFIG_I2C_TWLCORE) += twl-core.o
obj-$(CONFIG_I2C_TWL4030) += twl4030.o
obj-$(CONFIG_I2C_TWL6030) += twl6030.o
+obj-$(CONFIG_I2C_STMPE) += stmpe-i2c.o
diff --git a/drivers/mfd/mc13xxx.c b/drivers/mfd/mc13xxx.c
index 8bb0d00f8f..704446d019 100644
--- a/drivers/mfd/mc13xxx.c
+++ b/drivers/mfd/mc13xxx.c
@@ -32,6 +32,21 @@
#define DRIVERNAME "mc13xxx"
+enum mc13xxx_mode {
+ MC13XXX_MODE_I2C,
+ MC13XXX_MODE_SPI,
+};
+
+struct mc13xxx {
+ struct cdev cdev;
+ union {
+ struct i2c_client *client;
+ struct spi_device *spi;
+ };
+ enum mc13xxx_mode mode;
+ int revision;
+};
+
#define to_mc13xxx(a) container_of(a, struct mc13xxx, cdev)
static struct mc13xxx *mc_dev;
@@ -42,6 +57,12 @@ struct mc13xxx *mc13xxx_get(void)
}
EXPORT_SYMBOL(mc13xxx_get);
+int mc13xxx_revision(struct mc13xxx *mc13xxx)
+{
+ return mc13xxx->revision;
+}
+EXPORT_SYMBOL(mc13xxx_revision);
+
#ifdef CONFIG_SPI
static int spi_rw(struct spi_device *spi, void * buf, size_t len)
{
@@ -231,7 +252,7 @@ static struct mc13892_rev mc13892_revisions[] = {
static int mc13xxx_query_revision(struct mc13xxx *mc13xxx)
{
unsigned int rev_id;
- char *chipname, *revstr;
+ char *chipname, revstr[5];
int rev, i;
mc13xxx_reg_read(mc13xxx, MC13XXX_REG_IDENTIFICATION, &rev_id);
@@ -244,9 +265,9 @@ static int mc13xxx_query_revision(struct mc13xxx *mc13xxx)
/* Ver 0.2 is actually 3.2a. Report as 3.2 */
if (rev == 0x02) {
rev = 0x32;
- revstr = "3.2a";
+ strcpy(revstr, "3.2a");
} else
- revstr = asprintf("%d.%d", rev / 0x10, rev % 10);
+ sprintf(revstr, "%d.%d", rev / 0x10, rev % 10);
break;
case 7:
chipname = "MC13892";
@@ -258,12 +279,12 @@ static int mc13xxx_query_revision(struct mc13xxx *mc13xxx)
return -EINVAL;
rev = mc13892_revisions[i].rev;
- revstr = mc13892_revisions[i].revstr;
+ strcpy(revstr, mc13892_revisions[i].revstr);
if (rev == MC13892_REVISION_2_0) {
if ((rev_id >> 9) & 0x3) {
rev = MC13892_REVISION_2_0a;
- revstr = "2.0a";
+ strcpy(revstr, "2.0a");
}
}
break;
diff --git a/drivers/mfd/stmpe-i2c.c b/drivers/mfd/stmpe-i2c.c
new file mode 100644
index 0000000000..4af8b7b88c
--- /dev/null
+++ b/drivers/mfd/stmpe-i2c.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2012 Pengutronix
+ * Steffen Trumtrar <s.trumtrar@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <common.h>
+#include <init.h>
+#include <driver.h>
+#include <xfuncs.h>
+#include <errno.h>
+
+#include <i2c/i2c.h>
+#include <mfd/stmpe-i2c.h>
+
+#define DRIVERNAME "stmpe-i2c"
+
+#define to_stmpe(a) container_of(a, struct stmpe, cdev)
+
+int stmpe_reg_read(struct stmpe *stmpe, u32 reg, u8 *val)
+{
+ int ret;
+
+ ret = i2c_read_reg(stmpe->client, reg, val, 1);
+
+ return ret == 1 ? 0 : ret;
+}
+EXPORT_SYMBOL(stmpe_reg_read)
+
+int stmpe_reg_write(struct stmpe *stmpe, u32 reg, u8 val)
+{
+ int ret;
+
+ ret = i2c_write_reg(stmpe->client, reg, &val, 1);
+
+ return ret == 1 ? 0 : ret;
+}
+EXPORT_SYMBOL(stmpe_reg_write)
+
+int stmpe_set_bits(struct stmpe *stmpe, u32 reg, u8 mask, u8 val)
+{
+ u8 tmp;
+ int err;
+
+ err = stmpe_reg_read(stmpe, reg, &tmp);
+ tmp = (tmp & ~mask) | val;
+
+ if (!err)
+ err = stmpe_reg_write(stmpe, reg, tmp);
+
+ return err;
+}
+EXPORT_SYMBOL(stmpe_set_bits);
+
+static ssize_t stmpe_read(struct cdev *cdev, void *_buf, size_t count, loff_t offset, ulong flags)
+{
+ struct stmpe *stmpe = to_stmpe(cdev);
+ u8 *buf = _buf;
+ size_t i = count;
+ int err;
+
+ while (i) {
+ err = stmpe_reg_read(stmpe, offset, buf);
+ if (err)
+ return (ssize_t)err;
+ buf++;
+ i--;
+ offset++;
+ }
+
+ return count;
+}
+
+static ssize_t stmpe_write(struct cdev *cdev, const void *_buf, size_t count, loff_t offset, ulong flags)
+{
+ struct stmpe *stmpe = to_stmpe(cdev);
+ const u8 *buf = _buf;
+ size_t i = count;
+ int err;
+
+ while (i) {
+ err = stmpe_reg_write(stmpe, offset, *buf);
+ if (err)
+ return (ssize_t)err;
+ buf++;
+ i--;
+ offset++;
+ }
+
+ return count;
+}
+
+static struct file_operations stmpe_fops = {
+ .lseek = dev_lseek_default,
+ .read = stmpe_read,
+ .write = stmpe_write,
+};
+
+static int stmpe_probe(struct device_d *dev)
+{
+ struct stmpe_platform_data *pdata = dev->platform_data;
+ struct stmpe *stmpe_dev;
+ struct stmpe_client_info *i2c_ci;
+
+ if (!pdata) {
+ dev_dbg(dev, "no platform data\n");
+ return -ENODEV;
+ }
+
+ stmpe_dev = xzalloc(sizeof(struct stmpe));
+ stmpe_dev->cdev.name = DRIVERNAME;
+ stmpe_dev->client = to_i2c_client(dev);
+ stmpe_dev->cdev.size = 191; /* 191 known registers */
+ stmpe_dev->cdev.dev = dev;
+ stmpe_dev->cdev.ops = &stmpe_fops;
+ stmpe_dev->pdata = pdata;
+ dev->priv = stmpe_dev;
+
+ i2c_ci = xzalloc(sizeof(struct stmpe_client_info));
+ i2c_ci->stmpe = stmpe_dev;
+ i2c_ci->read_reg = stmpe_reg_read;
+ i2c_ci->write_reg = stmpe_reg_write;
+
+ if (pdata->blocks &= STMPE_BLOCK_GPIO)
+ add_generic_device("stmpe-gpio", DEVICE_ID_DYNAMIC, NULL, 0, 0, IORESOURCE_MEM, i2c_ci);
+
+ devfs_create(&stmpe_dev->cdev);
+
+ return 0;
+}
+
+static struct driver_d stmpe_driver = {
+ .name = DRIVERNAME,
+ .probe = stmpe_probe,
+};
+
+static int stmpe_init(void)
+{
+ register_driver(&stmpe_driver);
+ return 0;
+}
+
+device_initcall(stmpe_init);
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
new file mode 100644
index 0000000000..c3d31ec9a2
--- /dev/null
+++ b/drivers/misc/Kconfig
@@ -0,0 +1,17 @@
+#
+# Misc strange devices
+#
+
+menuconfig MISC_DEVICES
+ bool "Misc devices "
+ help
+ Add support for misc strange devices
+
+if MISC_DEVICES
+
+config JTAG
+ tristate "JTAG Bitbang driver"
+ help
+ Controls JTAG chains connected to I/O pins
+
+endif # MISC_DEVICES
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
new file mode 100644
index 0000000000..b0855777a9
--- /dev/null
+++ b/drivers/misc/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for misc devices that really don't fit anywhere else.
+#
+
+obj-$(CONFIG_JTAG) += jtag.o
diff --git a/drivers/misc/jtag.c b/drivers/misc/jtag.c
new file mode 100644
index 0000000000..99fd081b31
--- /dev/null
+++ b/drivers/misc/jtag.c
@@ -0,0 +1,392 @@
+/*
+ * drivers/misc/jtag.c - More infos in include/jtag.h
+ *
+ * Written Aug 2009 by Davide Rizzo <elpa.rizzo@gmail.com>
+ *
+ * Ported to barebox Jul 2012 by
+ * Wjatscheslaw Stoljarski <wjatscheslaw.stoljarski@kiwigrid.com>
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <fs.h>
+#include <errno.h>
+//#include <linux/list.h>
+#include <jtag.h>
+#include <gpio.h>
+#include <driver.h>
+#include <malloc.h>
+#include <common.h>
+#include <init.h>
+#include <ioctl.h>
+
+#define VERSION_MAJ 1
+#define VERSION_MIN 0
+
+/* Max devices in the jtag chain */
+#define MAX_DEVICES 16
+
+struct jtag_info {
+ struct jtag_platdata *pdata;
+ struct cdev cdev;
+ unsigned int devices; /* Number of devices found in the jtag chain */
+ /* Instruction register length of every device in the chain */
+ unsigned int ir_len[MAX_DEVICES]; /* [devices] */
+};
+
+static const unsigned long bypass = 0xFFFFFFFF;
+
+static void pulse_tms0(const struct jtag_platdata *pdata)
+{
+ gpio_set_value(pdata->gpio_tms, 0);
+ gpio_set_value(pdata->gpio_tclk, 0);
+ gpio_set_value(pdata->gpio_tclk, 1);
+}
+
+static void pulse_tms1(const struct jtag_platdata *pdata)
+{
+ gpio_set_value(pdata->gpio_tms, 1);
+ gpio_set_value(pdata->gpio_tclk, 0);
+ gpio_set_value(pdata->gpio_tclk, 1);
+}
+
+static void jtag_reset(const struct jtag_platdata *pdata)
+{
+ gpio_set_value(pdata->gpio_tms, 1);
+ gpio_set_value(pdata->gpio_tclk, 0);
+ gpio_set_value(pdata->gpio_tclk, 1);
+ gpio_set_value(pdata->gpio_tclk, 0);
+ gpio_set_value(pdata->gpio_tclk, 1);
+ gpio_set_value(pdata->gpio_tclk, 0);
+ gpio_set_value(pdata->gpio_tclk, 1);
+ gpio_set_value(pdata->gpio_tclk, 0);
+ gpio_set_value(pdata->gpio_tclk, 1);
+ gpio_set_value(pdata->gpio_tclk, 0);
+ gpio_set_value(pdata->gpio_tclk, 1);
+}
+
+static void jtag_output(const struct jtag_platdata *pdata,
+ const unsigned long *data, unsigned int bitlen, int notlast)
+{
+ unsigned int a;
+ unsigned long mask;
+ gpio_set_value(pdata->gpio_tms, 0);
+ while (bitlen > 0) {
+ for (a = *data++, mask = 0x00000001; mask != 0 && bitlen > 0;
+ mask <<= 1, bitlen--) {
+ gpio_set_value(pdata->gpio_tdo, (a & mask) ? 1 : 0);
+ if ((bitlen == 1) && !notlast)
+ gpio_set_value(pdata->gpio_tms, 1);
+ gpio_set_value(pdata->gpio_tclk, 0);
+ gpio_set_value(pdata->gpio_tclk, 1);
+ }
+ }
+}
+
+static int jtag_ioctl(struct cdev *inode, int cmd, void *arg)
+{
+ int ret = 0;
+ struct jtag_info *info = (struct jtag_info *)inode->priv;
+ int devices = info->devices;
+ struct jtag_cmd *jcmd = (struct jtag_cmd *)arg;
+ struct jtag_platdata *pdata = info->pdata;
+
+ if (_IOC_TYPE(cmd) != JTAG_IOC_MAGIC) return -ENOTTY;
+ if (_IOC_NR(cmd) > JTAG_IOC_MAXNR) return -ENOTTY;
+
+ switch (cmd) {
+
+ case JTAG_GET_DEVICES:
+ /* Returns how many devices found in the chain */
+ ret = info->devices;
+ break;
+
+ case JTAG_GET_ID:
+ /* Returns ID register of selected device */
+ if ((((struct jtag_rd_id *)arg)->device < 0) ||
+ (((struct jtag_rd_id *)arg)->device >= devices)) {
+ ret = -EINVAL;
+ break;
+ }
+ jtag_reset(pdata);
+ pulse_tms0(pdata);
+ pulse_tms1(pdata);
+ pulse_tms0(pdata);
+ pulse_tms0(pdata);
+ while (devices-- > 0) {
+ unsigned long id = 0;
+ pulse_tms0(pdata);
+ if (gpio_get_value(pdata->gpio_tdi)) {
+ unsigned long mask;
+ for (id = 1, mask = 0x00000002; (mask != 0);
+ mask <<= 1) {
+ pulse_tms0(pdata);
+ if (gpio_get_value(pdata->gpio_tdi))
+ id |= mask;
+ }
+ }
+ if (devices == ((struct jtag_rd_id *)arg)->device) {
+ ((struct jtag_rd_id *)arg)->id = id;
+ ret = 0;
+ break;
+ }
+ }
+ jtag_reset(pdata);
+ break;
+
+ case JTAG_SET_IR_LENGTH:
+ /* Sets up IR length of one device */
+ if ((jcmd->device >= 0) && (jcmd->device < devices))
+ info->ir_len[jcmd->device] = jcmd->bitlen;
+ else
+ ret = -EINVAL;
+ break;
+
+ case JTAG_RESET:
+ /* Resets all JTAG states */
+ jtag_reset(pdata);
+ break;
+
+ case JTAG_IR_WR:
+ /*
+ * Writes Instruction Register
+ * If device == -1 writes same Instruction Register in
+ * all devices.
+ * If device >= 0 writes Instruction Register in selected
+ * device and loads BYPASS instruction in all others.
+ */
+ if ((jcmd->device < -1) || (jcmd->device >= devices)) {
+ ret = -EINVAL;
+ break;
+ }
+ pulse_tms0(pdata);
+ pulse_tms1(pdata);
+ pulse_tms1(pdata);
+ pulse_tms0(pdata);
+ pulse_tms0(pdata);
+ while (devices-- > 0) {
+ if ((jcmd->device == -1) || (jcmd->device == devices))
+ /* Loads desired instruction */
+ jtag_output(pdata, jcmd->data,
+ info->ir_len[devices], devices);
+ else
+ /* Loads BYPASS instruction */
+ jtag_output(pdata, &bypass,
+ info->ir_len[devices], devices);
+ }
+ pulse_tms1(pdata);
+ pulse_tms0(pdata);
+ break;
+
+ case JTAG_DR_WR:
+ /*
+ * Writes Data Register of all devices
+ * If device == -1 writes same Data Register in all devices.
+ * If device >= 0 writes Data Register in selected device
+ * and loads BYPASS instruction in all others.
+ */
+ if ((jcmd->device < -1) || (jcmd->device >= devices)) {
+ ret = -EINVAL;
+ break;
+ }
+ pulse_tms0(pdata);
+ pulse_tms1(pdata);
+ pulse_tms0(pdata);
+ pulse_tms0(pdata);
+ while (devices-- > 0) {
+ if ((jcmd->device == -1) || (devices == jcmd->device))
+ /* Loads desired data */
+ jtag_output(pdata, jcmd->data, jcmd->bitlen,
+ devices);
+ else
+ /* Loads 1 dummy bit in BYPASS data register */
+ jtag_output(pdata, &bypass, 1, devices);
+ }
+ pulse_tms1(pdata);
+ pulse_tms0(pdata);
+ break;
+
+ case JTAG_DR_RD:
+ /* Reads data register of selected device */
+ if ((jcmd->device < 0) || (jcmd->device >= devices))
+ ret = -EINVAL;
+ else {
+ unsigned long mask;
+ int bitlen = jcmd->bitlen;
+ unsigned long *data = jcmd->data;
+ pulse_tms0(pdata);
+ pulse_tms1(pdata);
+ pulse_tms0(pdata);
+ pulse_tms0(pdata);
+ devices -= (jcmd->device + 1);
+ while (devices-- > 0)
+ pulse_tms0(pdata);
+ while (bitlen > 0) {
+ for (*data = 0, mask = 0x00000001;
+ (mask != 0) && (bitlen > 0);
+ mask <<= 1, bitlen--) {
+ if (bitlen == 1)
+ pulse_tms1(pdata);
+ else
+ pulse_tms0(pdata);
+ if (gpio_get_value(pdata->gpio_tdi))
+ *data |= mask;
+ }
+ data++;
+ }
+ pulse_tms1(pdata);
+ pulse_tms0(pdata);
+ }
+ break;
+
+ case JTAG_CLK:
+ /* Generates arg clock pulses */
+ gpio_set_value(pdata->gpio_tms, 0);
+ while ((*(unsigned int *) arg)--) {
+ gpio_set_value(pdata->gpio_tclk, 0);
+ gpio_set_value(pdata->gpio_tclk, 1);
+ }
+ break;
+
+ default:
+ ret = -EFAULT;
+ }
+
+ return ret;
+}
+
+static struct file_operations jtag_operations = {
+ .ioctl = jtag_ioctl,
+};
+
+static int jtag_probe(struct device_d *pdev)
+{
+ int i, ret;
+ struct jtag_info *info;
+ struct jtag_platdata *pdata = pdev->platform_data;
+
+ /* Setup gpio pins */
+ gpio_direction_output(pdata->gpio_tms, 0);
+ gpio_direction_output(pdata->gpio_tclk, 1);
+ gpio_direction_output(pdata->gpio_tdo, 0);
+ gpio_direction_input(pdata->gpio_tdi);
+ if (pdata->use_gpio_trst) {
+ /*
+ * Keep fixed at 1 because some devices in the chain could
+ * not use it, to reset chain use jtag_reset()
+ */
+ gpio_direction_output(pdata->gpio_trst, 1);
+ }
+
+ /* Find how many devices in chain */
+ jtag_reset(pdata);
+ pulse_tms0(pdata);
+ pulse_tms1(pdata);
+ pulse_tms1(pdata);
+ pulse_tms0(pdata);
+ pulse_tms0(pdata);
+ gpio_set_value(pdata->gpio_tdo, 1);
+ /* Fills all IR with bypass instruction */
+ for (i = 0; i < 32 * MAX_DEVICES; i++)
+ pulse_tms0(pdata);
+ pulse_tms1(pdata);
+ pulse_tms1(pdata);
+ pulse_tms1(pdata);
+ pulse_tms0(pdata);
+ pulse_tms0(pdata);
+ gpio_set_value(pdata->gpio_tdo, 0);
+ /* Fills all 1-bit bypass register with 0 */
+ for (i = 0; i < MAX_DEVICES + 2; i++)
+ pulse_tms0(pdata);
+ gpio_set_value(pdata->gpio_tdo, 1);
+ /* Counts chain's bit length */
+ for (i = 0; i < MAX_DEVICES + 1; i++) {
+ pulse_tms0(pdata);
+ if (gpio_get_value(pdata->gpio_tdi))
+ break;
+ }
+ dev_notice(pdev, "%d devices found in chain\n", i);
+
+ /* Allocate structure with chain specific infos */
+ info = xzalloc(sizeof(struct jtag_info) + sizeof(info->ir_len[0]) * i);
+
+ info->devices = i;
+ info->pdata = pdata;
+ pdev->priv = info;
+
+ info->cdev.name = JTAG_NAME;
+ info->cdev.dev = pdev;
+ info->cdev.ops = &jtag_operations;
+ info->cdev.priv = info;
+ ret = devfs_create(&info->cdev);
+
+ if (ret)
+ goto fail_devfs_create;
+
+ return 0;
+
+fail_devfs_create:
+ pdev->priv = NULL;
+ free(info);
+ return ret;
+}
+
+static void jtag_info(struct device_d *pdev)
+{
+ int dn, ret;
+ struct jtag_rd_id jid;
+ struct jtag_info *info = pdev->priv;
+
+ printf(" JTAG:\n");
+ printf(" Devices found: %d\n", info->devices);
+ for (dn = 0; dn < info->devices; dn++) {
+ jid.device = dn;
+ ret = jtag_ioctl(&info->cdev, JTAG_GET_ID, &jid);
+ printf(" Device number: %d\n", dn);
+ if (ret == -1)
+ printf(" JTAG_GET_ID failed: %s\n", strerror(errno));
+ else
+ printf(" ID: 0x%lX\n", jid.id);
+ }
+}
+
+static void jtag_remove(struct device_d *pdev)
+{
+ struct jtag_info *info = (struct jtag_info *) pdev->priv;
+
+ devfs_remove(&info->cdev);
+ pdev->priv = NULL;
+ free(info);
+ dev_notice(pdev, "Device removed\n");
+}
+
+static struct driver_d jtag_driver = {
+ .name = JTAG_NAME,
+ .probe = jtag_probe,
+ .remove = jtag_remove,
+ .info = jtag_info,
+};
+
+static int jtag_module_init(void)
+{
+ return register_driver(&jtag_driver);
+}
+
+device_initcall(jtag_module_init);
+
+MODULE_AUTHOR("Davide Rizzo <elpa.rizzo@gmail.com>");
+MODULE_AUTHOR("Wjatscheslaw Stoljarski <wjatscheslaw.stoljarski@kiwigrid.com>");
+MODULE_DESCRIPTION("JTAG bitbang driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/core.c b/drivers/mtd/core.c
index 5510439a87..a6132e8ac5 100644
--- a/drivers/mtd/core.c
+++ b/drivers/mtd/core.c
@@ -79,7 +79,7 @@ static ssize_t mtd_write(struct cdev* cdev, const void *buf, size_t _count,
return -EINVAL;
}
- dev_dbg(cdev->dev, "write: 0x%08lx 0x%08x\n", offset, count);
+ dev_dbg(cdev->dev, "write: 0x%08lx 0x%08lx\n", offset, count);
while (count) {
now = count > mtd->writesize ? mtd->writesize : count;
@@ -100,7 +100,7 @@ static ssize_t mtd_write(struct cdev* cdev, const void *buf, size_t _count,
ret = mtd->write(mtd, offset, now, &retlen,
buf);
dev_dbg(cdev->dev,
- "offset: 0x%08lx now: 0x%08x retlen: 0x%08x\n",
+ "offset: 0x%08lx now: 0x%08lx retlen: 0x%08lx\n",
offset, now, retlen);
}
if (ret)
@@ -174,7 +174,7 @@ int mtd_ioctl(struct cdev *cdev, int request, void *buf)
}
#ifdef CONFIG_MTD_WRITE
-static ssize_t mtd_erase(struct cdev *cdev, size_t count, loff_t offset)
+static int mtd_erase(struct cdev *cdev, size_t count, loff_t offset)
{
struct mtd_info *mtd = cdev->priv;
struct erase_info erase;
@@ -248,7 +248,7 @@ int add_mtd_device(struct mtd_info *mtd, char *devname)
list_for_each_entry(hook, &mtd_register_hooks, hook)
if (hook->add_mtd_device)
- hook->add_mtd_device(mtd, devname);
+ hook->add_mtd_device(mtd, devname, &hook->priv);
return 0;
}
@@ -259,7 +259,9 @@ int del_mtd_device (struct mtd_info *mtd)
list_for_each_entry(hook, &mtd_register_hooks, hook)
if (hook->del_mtd_device)
- hook->del_mtd_device(mtd);
+ hook->del_mtd_device(mtd, &hook->priv);
+
+ devfs_remove(&mtd->cdev);
unregister_device(&mtd->class_dev);
free(mtd->param_size.value);
free(mtd->cdev.name);
diff --git a/drivers/mtd/mtd.h b/drivers/mtd/mtd.h
index c8af6e3c9d..414bd6cdb5 100644
--- a/drivers/mtd/mtd.h
+++ b/drivers/mtd/mtd.h
@@ -25,8 +25,9 @@
*/
struct mtddev_hook {
struct list_head hook;
- int (*add_mtd_device)(struct mtd_info *mtd, char *devname);
- int (*del_mtd_device)(struct mtd_info *mtd);
+ int (*add_mtd_device)(struct mtd_info *mtd, char *devname, void **priv);
+ int (*del_mtd_device)(struct mtd_info *mtd, void **priv);
+ void *priv;
};
struct cdev;
diff --git a/drivers/mtd/mtdoob.c b/drivers/mtd/mtdoob.c
index e4dd1a00c8..c7bf40cef8 100644
--- a/drivers/mtd/mtdoob.c
+++ b/drivers/mtd/mtdoob.c
@@ -69,7 +69,7 @@ static struct file_operations mtd_ops_oob = {
.lseek = dev_lseek_default,
};
-static int add_mtdoob_device(struct mtd_info *mtd, char *devname)
+static int add_mtdoob_device(struct mtd_info *mtd, char *devname, void **priv)
{
struct mtdoob *mtdoob;
@@ -80,13 +80,26 @@ static int add_mtdoob_device(struct mtd_info *mtd, char *devname)
mtdoob->cdev.priv = mtdoob;
mtdoob->cdev.dev = &mtd->class_dev;
mtdoob->mtd = mtd;
+ *priv = mtdoob;
devfs_create(&mtdoob->cdev);
return 0;
}
+static int del_mtdoob_device(struct mtd_info *mtd, void **priv)
+{
+ struct mtdoob *mtdoob;
+
+ mtdoob = *priv;
+ devfs_remove(&mtdoob->cdev);
+ free(mtdoob);
+
+ return 0;
+}
+
static struct mtddev_hook mtdoob_hook = {
.add_mtd_device = add_mtdoob_device,
+ .del_mtd_device = del_mtdoob_device,
};
static int __init register_mtdoob(void)
diff --git a/drivers/mtd/mtdraw.c b/drivers/mtd/mtdraw.c
index 24f7358098..16157e9f48 100644
--- a/drivers/mtd/mtdraw.c
+++ b/drivers/mtd/mtdraw.c
@@ -137,7 +137,7 @@ static ssize_t mtdraw_read(struct cdev *cdev, void *buf, size_t count,
retlen += ret;
}
if (ret < 0)
- printf("err %d\n", ret);
+ printf("err %lu\n", ret);
else
ret = retlen;
return ret;
@@ -222,7 +222,7 @@ static ssize_t mtdraw_write(struct cdev *cdev, const void *buf, size_t count,
}
}
-static ssize_t mtdraw_erase(struct cdev *cdev, size_t count, loff_t _offset)
+static int mtdraw_erase(struct cdev *cdev, size_t count, loff_t _offset)
{
struct mtd_info *mtd = to_mtd(cdev);
struct erase_info erase;
@@ -275,7 +275,7 @@ static const struct file_operations mtd_raw_fops = {
.lseek = dev_lseek_default,
};
-static int add_mtdraw_device(struct mtd_info *mtd, char *devname)
+static int add_mtdraw_device(struct mtd_info *mtd, char *devname, void **priv)
{
struct mtdraw *mtdraw;
@@ -290,13 +290,26 @@ static int add_mtdraw_device(struct mtd_info *mtd, char *devname)
mtdraw->cdev.priv = mtdraw;
mtdraw->cdev.dev = &mtd->class_dev;
mtdraw->cdev.mtd = mtd;
+ *priv = mtdraw;
devfs_create(&mtdraw->cdev);
return 0;
}
+static int del_mtdraw_device(struct mtd_info *mtd, void **priv)
+{
+ struct mtdraw *mtdraw;
+
+ mtdraw = *priv;
+ devfs_remove(&mtdraw->cdev);
+ free(mtdraw);
+
+ return 0;
+}
+
static struct mtddev_hook mtdraw_hook = {
.add_mtd_device = add_mtdraw_device,
+ .del_mtd_device = del_mtdraw_device,
};
static int __init register_mtdraw(void)
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 8c08c9f82c..d52c272c5c 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -14,4 +14,5 @@ obj-$(CONFIG_NAND_IMX) += nand_imx.o
obj-$(CONFIG_NAND_OMAP_GPMC) += nand_omap_gpmc.o nand_omap_bch_decoder.o
obj-$(CONFIG_NAND_ATMEL) += atmel_nand.o
obj-$(CONFIG_NAND_S3C24XX) += nand_s3c24xx.o
+pbl-$(CONFIG_NAND_S3C24XX) += nand_s3c24xx.o
obj-$(CONFIG_NAND_MXS) += nand_mxs.o
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index a5bf757e47..37e57b32ce 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1000,7 +1000,7 @@ static void nand_set_defaults(struct nand_chip *chip, int busw)
if (!chip->select_chip)
chip->select_chip = nand_select_chip;
- if (!chip->read_byte)
+ if (!chip->read_byte || chip->read_byte == nand_read_byte)
chip->read_byte = busw ? nand_read_byte16 : nand_read_byte;
if (!chip->read_word)
chip->read_word = nand_read_word;
@@ -1009,12 +1009,12 @@ static void nand_set_defaults(struct nand_chip *chip, int busw)
#ifdef CONFIG_MTD_WRITE
if (!chip->block_markbad)
chip->block_markbad = nand_default_block_markbad;
- if (!chip->write_buf)
+ if (!chip->write_buf || chip->write_buf == nand_write_buf)
chip->write_buf = busw ? nand_write_buf16 : nand_write_buf;
#endif
- if (!chip->read_buf)
+ if (!chip->read_buf || chip->read_buf == nand_read_buf)
chip->read_buf = busw ? nand_read_buf16 : nand_read_buf;
- if (!chip->verify_buf)
+ if (!chip->verify_buf || chip->verify_buf == nand_verify_buf)
chip->verify_buf = busw ? nand_verify_buf16 : nand_verify_buf;
#ifdef CONFIG_NAND_BBT
if (!chip->scan_bbt)
@@ -1258,6 +1258,13 @@ ident_done:
break;
}
+ if (chip->options & NAND_BUSWIDTH_AUTO) {
+ chip->options |= busw;
+ nand_set_defaults(chip, busw);
+ if (chip->set_buswidth)
+ chip->set_buswidth(mtd, chip, busw);
+ }
+
/*
* Check, if buswidth is correct. Hardware drivers should set
* chip correct !
@@ -1326,6 +1333,11 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips)
struct nand_chip *chip = mtd->priv;
struct nand_flash_dev *type;
+ if (chip->options & NAND_BUSWIDTH_AUTO && !chip->set_buswidth) {
+ printk(KERN_ERR "buswidth detection but no buswidth callback\n");
+ return -EINVAL;
+ }
+
/* Get buswidth to select the correct functions */
busw = chip->options & NAND_BUSWIDTH_16;
/* Set the default functions */
diff --git a/drivers/mtd/nand/nand_omap_gpmc.c b/drivers/mtd/nand/nand_omap_gpmc.c
index 86d45748ed..fa6074f856 100644
--- a/drivers/mtd/nand/nand_omap_gpmc.c
+++ b/drivers/mtd/nand/nand_omap_gpmc.c
@@ -22,11 +22,7 @@
* static struct gpmc_nand_platform_data nand_plat = {
* .cs = give the chip select of the device
* .device_width = what is the width of the device 8 or 16?
- * .max_timeout = delay desired for operation
* .wait_mon_pin = do you use wait monitoring? if so wait pin
- * .plat_options = platform options.
- * NAND_HWECC_ENABLE/DISABLE - hw ecc enable/disable
- * NAND_WAITPOL_LOW/HIGH - wait pin polarity
* .oob = if you would like to replace oob with a custom OOB.
* .nand_setup = if you would like a special setup function to be called
* .priv = any params you'd like to save(e.g. like nand_setup to use)
@@ -112,12 +108,11 @@ struct gpmc_nand_info {
void *gpmc_address;
void *gpmc_data;
void __iomem *gpmc_base;
- unsigned char wait_mon_mask;
- uint64_t timeout;
+ u32 wait_mon_mask;
unsigned inuse:1;
- unsigned wait_pol:1;
unsigned char ecc_parity_pairs;
enum gpmc_ecc_mode ecc_mode;
+ void *cs_base;
};
/* Typical BOOTROM oob layouts-requires hwecc **/
@@ -191,25 +186,11 @@ static int omap_dev_ready(struct mtd_info *mtd)
{
struct nand_chip *nand = (struct nand_chip *)(mtd->priv);
struct gpmc_nand_info *oinfo = (struct gpmc_nand_info *)(nand->priv);
- uint64_t start = get_time_ns();
- unsigned long comp;
- /* What do we mean by assert and de-assert? */
- comp = (oinfo->wait_pol == NAND_WAITPOL_HIGH) ?
- oinfo->wait_mon_mask : 0x0;
- while (1) {
- /* Breakout condition */
- if (is_timeout(start, oinfo->timeout)) {
- debug("%s timedout\n", __func__);
- return -ETIMEDOUT;
- }
- /* if the wait is released, we are good to go */
- if (comp ==
- (readl(oinfo->gpmc_base + GPMC_STATUS) &&
- oinfo->wait_mon_mask))
- break;
- }
- return 0;
+ if (readl(oinfo->gpmc_base + GPMC_STATUS) & oinfo->wait_mon_mask)
+ return 1;
+ else
+ return 0;
}
/**
@@ -603,6 +584,101 @@ static int omap_gpmc_read_buf_manual(struct mtd_info *mtd, struct nand_chip *chi
return bytes;
}
+/**
+ * omap_read_buf_pref - read data from NAND controller into buffer
+ * @mtd: MTD device structure
+ * @buf: buffer to store date
+ * @len: number of bytes to read
+ */
+static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
+{
+ struct gpmc_nand_info *info = container_of(mtd,
+ struct gpmc_nand_info, minfo);
+ u32 r_count = 0;
+ u32 *p = (u32 *)buf;
+
+ /* take care of subpage reads */
+ if (len % 4) {
+ if (info->nand.options & NAND_BUSWIDTH_16)
+ readsw(info->cs_base, buf, (len % 4) / 2);
+ else
+ readsb(info->cs_base, buf, len % 4);
+ p = (u32 *) (buf + len % 4);
+ len -= len % 4;
+ }
+
+ /* configure and start prefetch transfer */
+ gpmc_prefetch_enable(info->gpmc_cs,
+ PREFETCH_FIFOTHRESHOLD_MAX, 0x0, len, 0x0);
+
+ do {
+ r_count = readl(info->gpmc_base + GPMC_PREFETCH_STATUS);
+ r_count = GPMC_PREFETCH_STATUS_FIFO_CNT(r_count);
+ r_count = r_count >> 2;
+ readsl(info->cs_base, p, r_count);
+ p += r_count;
+ len -= r_count << 2;
+ } while (len);
+
+ /* disable and stop the PFPW engine */
+ gpmc_prefetch_reset(info->gpmc_cs);
+}
+
+/**
+ * omap_write_buf_pref - write buffer to NAND controller
+ * @mtd: MTD device structure
+ * @buf: data buffer
+ * @len: number of bytes to write
+ */
+static void omap_write_buf_pref(struct mtd_info *mtd,
+ const u_char *buf, int len)
+{
+ struct gpmc_nand_info *info = container_of(mtd,
+ struct gpmc_nand_info, minfo);
+ u32 w_count = 0;
+ u_char *buf1 = (u_char *)buf;
+ u32 *p32 = (u32 *)buf;
+ uint64_t start;
+
+ /* take care of subpage writes */
+ while (len % 4 != 0) {
+ writeb(*buf, info->nand.IO_ADDR_W);
+ buf1++;
+ p32 = (u32 *)buf1;
+ len--;
+ }
+
+ /* configure and start prefetch transfer */
+ gpmc_prefetch_enable(info->gpmc_cs,
+ PREFETCH_FIFOTHRESHOLD_MAX, 0x0, len, 0x1);
+
+ while (len >= 0) {
+ w_count = readl(info->gpmc_base + GPMC_PREFETCH_STATUS);
+ w_count = GPMC_PREFETCH_STATUS_FIFO_CNT(w_count);
+ w_count = w_count >> 2;
+ writesl(info->cs_base, p32, w_count);
+ p32 += w_count;
+ len -= w_count << 2;
+ }
+
+ /* wait for data to flushed-out before reset the prefetch */
+ start = get_time_ns();
+ while (1) {
+ u32 regval, status;
+ regval = readl(info->gpmc_base + GPMC_PREFETCH_STATUS);
+ status = GPMC_PREFETCH_STATUS_COUNT(regval);
+ if (!status)
+ break;
+ if (is_timeout(start, 100 * MSECOND)) {
+ dev_err(mtd->dev, "prefetch flush timed out\n");
+ break;
+ }
+ }
+
+ /* disable and stop the PFPW engine */
+ gpmc_prefetch_reset(info->gpmc_cs);
+}
+
/*
* read a page with the ecc layout used by the OMAP4 romcode. The
* romcode expects an unusual ecc layout (f = free, e = ecc):
@@ -803,6 +879,20 @@ static int omap_gpmc_eccmode_set(struct device_d *dev, struct param_d *param, co
return omap_gpmc_eccmode(oinfo, i);
}
+static int gpmc_set_buswidth(struct mtd_info *mtd, struct nand_chip *chip, int buswidth)
+{
+ struct gpmc_nand_info *oinfo = chip->priv;
+
+ if (buswidth == NAND_BUSWIDTH_16)
+ oinfo->pdata->nand_cfg->cfg[0] |= 0x00001000;
+ else
+ oinfo->pdata->nand_cfg->cfg[0] &= ~0x00001000;
+
+ gpmc_cs_config(oinfo->pdata->cs, oinfo->pdata->nand_cfg);
+
+ return 0;
+}
+
/**
* @brief nand device probe.
*
@@ -853,15 +943,23 @@ static int gpmc_nand_probe(struct device_d *pdev)
oinfo->gpmc_command = (void *)(cs_base + GPMC_CS_NAND_COMMAND);
oinfo->gpmc_address = (void *)(cs_base + GPMC_CS_NAND_ADDRESS);
oinfo->gpmc_data = (void *)(cs_base + GPMC_CS_NAND_DATA);
- oinfo->timeout = pdata->max_timeout;
+ oinfo->cs_base = (void *)pdata->nand_cfg->base;
dev_dbg(pdev, "GPMC base=0x%p cmd=0x%p address=0x%p data=0x%p cs_base=0x%p\n",
oinfo->gpmc_base, oinfo->gpmc_command, oinfo->gpmc_address,
oinfo->gpmc_data, cs_base);
- /* If we are 16 bit dev, our gpmc config tells us that */
- if ((readl(cs_base) & 0x3000) == 0x1000) {
- dev_dbg(pdev, "16 bit dev\n");
+ switch (pdata->device_width) {
+ case 0:
+ printk("probe buswidth\n");
+ nand->options |= NAND_BUSWIDTH_AUTO;
+ break;
+ case 8:
+ break;
+ case 16:
nand->options |= NAND_BUSWIDTH_16;
+ break;
+ default:
+ return -EINVAL;
}
/* Same data register for in and out */
@@ -879,11 +977,11 @@ static int gpmc_nand_probe(struct device_d *pdev)
err = -EINVAL;
goto out_release_mem;
}
+
if (pdata->wait_mon_pin) {
/* Set up the wait monitoring mask
* This is GPMC_STATUS reg relevant */
oinfo->wait_mon_mask = (0x1 << (pdata->wait_mon_pin - 1)) << 8;
- oinfo->wait_pol = (pdata->plat_options & NAND_WAITPOL_MASK);
nand->dev_ready = omap_dev_ready;
nand->chip_delay = 0;
} else {
@@ -901,6 +999,8 @@ static int gpmc_nand_probe(struct device_d *pdev)
nand->options |= NAND_OWN_BUFFERS;
nand->buffers = xzalloc(sizeof(*nand->buffers));
+ nand->set_buswidth = gpmc_set_buswidth;
+
/* State my controller */
nand->controller = &oinfo->controller;
@@ -928,18 +1028,12 @@ static int gpmc_nand_probe(struct device_d *pdev)
goto out_release_mem;
}
- switch (pdata->device_width) {
- case 8:
- lsp = &ecc_sp_x8;
- llp = &ecc_lp_x8;
- break;
- case 16:
+ if (nand->options & NAND_BUSWIDTH_16) {
lsp = &ecc_sp_x16;
llp = &ecc_lp_x16;
- break;
- default:
- err = -EINVAL;
- goto out_release_mem;
+ } else {
+ lsp = &ecc_sp_x8;
+ llp = &ecc_lp_x8;
}
switch (minfo->writesize) {
@@ -954,6 +1048,9 @@ static int gpmc_nand_probe(struct device_d *pdev)
goto out_release_mem;
}
+ nand->read_buf = omap_read_buf_pref;
+ nand->write_buf = omap_write_buf_pref;
+
nand->options |= NAND_SKIP_BBTSCAN;
dev_add_param(pdev, "eccmode", omap_gpmc_eccmode_set, NULL, 0);
diff --git a/drivers/mtd/nand/nand_s3c24xx.c b/drivers/mtd/nand/nand_s3c24xx.c
index c6297011a3..3d5732e02a 100644
--- a/drivers/mtd/nand/nand_s3c24xx.c
+++ b/drivers/mtd/nand/nand_s3c24xx.c
@@ -603,6 +603,16 @@ void __nand_boot_init s3c24x0_nand_load_image(void *dest, int size, int page)
disable_nand_controller(host);
}
+#include <asm-generic/sections.h>
+
+void __nand_boot_init nand_boot(void)
+{
+ void *dest = _text;
+ int size = barebox_image_size;
+ int page = 0;
+
+ s3c24x0_nand_load_image(dest, size, page);
+}
#ifdef CONFIG_NAND_S3C_BOOT_DEBUG
#include <command.h>
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 340839d5d9..3c5f729db3 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -118,6 +118,11 @@ config DRIVER_NET_DESIGNWARE_ALTDESCRIPTOR
depends on DRIVER_NET_DESIGNWARE
default n
+config DRIVER_NET_GIANFAR
+ bool "Gianfar Ethernet"
+ depends on ARCH_MPC85XX
+ select MIIDEV
+
source "drivers/net/usb/Kconfig"
endmenu
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 29727b7d5b..4d960e856f 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -14,3 +14,4 @@ obj-$(CONFIG_NET_USB) += usb/
obj-$(CONFIG_DRIVER_NET_TSE) += altera_tse.o
obj-$(CONFIG_DRIVER_NET_KS8851_MLL) += ks8851_mll.o
obj-$(CONFIG_DRIVER_NET_DESIGNWARE) += designware.o
+obj-$(CONFIG_DRIVER_NET_GIANFAR) += gianfar.o
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
new file mode 100644
index 0000000000..19544de261
--- /dev/null
+++ b/drivers/net/gianfar.c
@@ -0,0 +1,548 @@
+/*
+ * Freescale Three Speed Ethernet Controller driver
+ *
+ * This software may be used and distributed according to the
+ * terms of the GNU Public License, Version 2, incorporated
+ * herein by reference.
+ *
+ * Copyright 2012 GE Intelligent Platforms, Inc.
+ * Copyright 2004-2010 Freescale Semiconductor, Inc.
+ * (C) Copyright 2003, Motorola, Inc.
+ * based on work by Andy Fleming
+ */
+
+#include <config.h>
+#include <common.h>
+#include <malloc.h>
+#include <net.h>
+#include <init.h>
+#include <driver.h>
+#include <miidev.h>
+#include <command.h>
+#include <errno.h>
+#include <asm/io.h>
+#include "gianfar.h"
+
+/* 2 seems to be the minimum number of TX descriptors to make it work. */
+#define TX_BUF_CNT 2
+#define RX_BUF_CNT PKTBUFSRX
+#define BUF_ALIGN 8
+
+/*
+ * Initialize required registers to appropriate values, zeroing
+ * those we don't care about (unless zero is bad, in which case,
+ * choose a more appropriate value)
+ */
+static void gfar_init_registers(void __iomem *regs)
+{
+ out_be32(regs + GFAR_IEVENT_OFFSET, GFAR_IEVENT_INIT_CLEAR);
+
+ out_be32(regs + GFAR_IMASK_OFFSET, GFAR_IMASK_INIT_CLEAR);
+
+ out_be32(regs + GFAR_IADDR(0), 0);
+ out_be32(regs + GFAR_IADDR(1), 0);
+ out_be32(regs + GFAR_IADDR(2), 0);
+ out_be32(regs + GFAR_IADDR(3), 0);
+ out_be32(regs + GFAR_IADDR(4), 0);
+ out_be32(regs + GFAR_IADDR(5), 0);
+ out_be32(regs + GFAR_IADDR(6), 0);
+ out_be32(regs + GFAR_IADDR(7), 0);
+
+ out_be32(regs + GFAR_GADDR(0), 0);
+ out_be32(regs + GFAR_GADDR(1), 0);
+ out_be32(regs + GFAR_GADDR(2), 0);
+ out_be32(regs + GFAR_GADDR(3), 0);
+ out_be32(regs + GFAR_GADDR(4), 0);
+ out_be32(regs + GFAR_GADDR(5), 0);
+ out_be32(regs + GFAR_GADDR(6), 0);
+ out_be32(regs + GFAR_GADDR(7), 0);
+
+ out_be32(regs + GFAR_RCTRL_OFFSET, 0x00000000);
+
+ memset((void *)(regs + GFAR_TR64_OFFSET), 0,
+ GFAR_CAM2_OFFSET - GFAR_TR64_OFFSET);
+
+ out_be32(regs + GFAR_CAM1_OFFSET, 0xffffffff);
+ out_be32(regs + GFAR_CAM2_OFFSET, 0xffffffff);
+
+ out_be32(regs + GFAR_MRBLR_OFFSET, MRBLR_INIT_SETTINGS);
+
+ out_be32(regs + GFAR_MINFLR_OFFSET, MINFLR_INIT_SETTINGS);
+
+ out_be32(regs + GFAR_ATTR_OFFSET, ATTR_INIT_SETTINGS);
+ out_be32(regs + GFAR_ATTRELI_OFFSET, ATTRELI_INIT_SETTINGS);
+}
+
+/*
+ * Configure maccfg2 based on negotiated speed and duplex
+ * reported by PHY handling code
+ */
+static void gfar_adjust_link(struct eth_device *edev)
+{
+ struct gfar_private *priv = edev->priv;
+ struct device_d *mdev = priv->miidev.parent;
+ void __iomem *regs = priv->regs;
+ u32 ecntrl, maccfg2;
+ uint32_t status;
+
+ status = miidev_get_status(&priv->miidev);
+
+ priv->link = status & MIIDEV_STATUS_IS_UP;
+ if (status & MIIDEV_STATUS_IS_FULL_DUPLEX)
+ priv->duplexity = 1;
+ else
+ priv->duplexity = 0;
+
+ if (status & MIIDEV_STATUS_IS_1000MBIT)
+ priv->speed = 1000;
+ else if (status & MIIDEV_STATUS_IS_100MBIT)
+ priv->speed = 100;
+ else
+ priv->speed = 10;
+
+ if (priv->link) {
+ /* clear all bits relative with interface mode */
+ ecntrl = in_be32(regs + GFAR_ECNTRL_OFFSET);
+ ecntrl &= ~GFAR_ECNTRL_R100;
+
+ maccfg2 = in_be32(regs + GFAR_MACCFG2_OFFSET);
+ maccfg2 &= ~(GFAR_MACCFG2_IF | GFAR_MACCFG2_FULL_DUPLEX);
+
+ if (priv->duplexity != 0)
+ maccfg2 |= GFAR_MACCFG2_FULL_DUPLEX;
+ else
+ maccfg2 &= ~(GFAR_MACCFG2_FULL_DUPLEX);
+
+ switch (priv->speed) {
+ case 1000:
+ maccfg2 |= GFAR_MACCFG2_GMII;
+ break;
+ case 100:
+ case 10:
+ maccfg2 |= GFAR_MACCFG2_MII;
+ /*
+ * Set R100 bit in all modes although
+ * it is only used in RGMII mode
+ */
+ if (priv->speed == 100)
+ ecntrl |= GFAR_ECNTRL_R100;
+ break;
+ default:
+ dev_info(mdev, "Speed is unknown\n");
+ break;
+ }
+
+ out_be32(regs + GFAR_ECNTRL_OFFSET, ecntrl);
+ out_be32(regs + GFAR_MACCFG2_OFFSET, maccfg2);
+
+ dev_info(mdev, "Speed: %d, %s duplex\n", priv->speed,
+ (priv->duplexity) ? "full" : "half");
+
+ } else {
+ dev_info(mdev, "No link.\n");
+ }
+}
+
+/* Stop the interface */
+static void gfar_halt(struct eth_device *edev)
+{
+ struct gfar_private *priv = edev->priv;
+ void __iomem *regs = priv->regs;
+ int value;
+
+ clrbits_be32(regs + GFAR_DMACTRL_OFFSET, GFAR_DMACTRL_GRS |
+ GFAR_DMACTRL_GTS);
+ setbits_be32(regs + GFAR_DMACTRL_OFFSET, GFAR_DMACTRL_GRS |
+ GFAR_DMACTRL_GTS);
+
+ value = in_be32(regs + GFAR_IEVENT_OFFSET);
+ value &= (GFAR_IEVENT_GRSC | GFAR_IEVENT_GTSC);
+
+ while (value != (GFAR_IEVENT_GRSC | GFAR_IEVENT_GTSC)) {
+ value = in_be32(regs + GFAR_IEVENT_OFFSET);
+ value &= (GFAR_IEVENT_GRSC | GFAR_IEVENT_GTSC);
+ }
+
+ clrbits_be32(regs + GFAR_MACCFG1_OFFSET,
+ GFAR_MACCFG1_TX_EN | GFAR_MACCFG1_RX_EN);
+}
+
+/* Initializes registers for the controller. */
+static int gfar_init(struct eth_device *edev)
+{
+ struct gfar_private *priv = edev->priv;
+ void __iomem *regs = priv->regs;
+
+ gfar_halt(edev);
+
+ /* Init MACCFG2. Default to GMII */
+ out_be32(regs + GFAR_MACCFG2_OFFSET, MACCFG2_INIT_SETTINGS);
+ out_be32(regs + GFAR_ECNTRL_OFFSET, ECNTRL_INIT_SETTINGS);
+
+ priv->rxidx = 0;
+ priv->txidx = 0;
+
+ gfar_init_registers(regs);
+
+ miidev_restart_aneg(&priv->miidev);
+
+ return 0;
+}
+
+static int gfar_open(struct eth_device *edev)
+{
+ int ix;
+ struct gfar_private *priv = edev->priv;
+ void __iomem *regs = priv->regs;
+
+ /* Point to the buffer descriptors */
+ out_be32(regs + GFAR_TBASE0_OFFSET, (unsigned int)priv->txbd);
+ out_be32(regs + GFAR_RBASE0_OFFSET, (unsigned int)priv->rxbd);
+
+ /* Initialize the Rx Buffer descriptors */
+ for (ix = 0; ix < RX_BUF_CNT; ix++) {
+ priv->rxbd[ix].status = RXBD_EMPTY;
+ priv->rxbd[ix].length = 0;
+ priv->rxbd[ix].bufPtr = (uint) NetRxPackets[ix];
+ }
+ priv->rxbd[RX_BUF_CNT - 1].status |= RXBD_WRAP;
+
+ /* Initialize the TX Buffer Descriptors */
+ for (ix = 0; ix < TX_BUF_CNT; ix++) {
+ priv->txbd[ix].status = 0;
+ priv->txbd[ix].length = 0;
+ priv->txbd[ix].bufPtr = 0;
+ }
+ priv->txbd[TX_BUF_CNT - 1].status |= TXBD_WRAP;
+
+ miidev_wait_aneg(&priv->miidev);
+ gfar_adjust_link(edev);
+
+ /* Enable Transmit and Receive */
+ setbits_be32(regs + GFAR_MACCFG1_OFFSET, GFAR_MACCFG1_RX_EN |
+ GFAR_MACCFG1_TX_EN);
+
+ /* Tell the DMA it is clear to go */
+ setbits_be32(regs + GFAR_DMACTRL_OFFSET, DMACTRL_INIT_SETTINGS);
+ out_be32(regs + GFAR_TSTAT_OFFSET, GFAR_TSTAT_CLEAR_THALT);
+ out_be32(regs + GFAR_RSTAT_OFFSET, GFAR_RSTAT_CLEAR_RHALT);
+ clrbits_be32(regs + GFAR_DMACTRL_OFFSET, GFAR_DMACTRL_GRS |
+ GFAR_DMACTRL_GTS);
+
+ return 0;
+}
+
+static int gfar_get_ethaddr(struct eth_device *edev, unsigned char *mac)
+{
+ return -ENODEV;
+}
+
+static int gfar_set_ethaddr(struct eth_device *edev, unsigned char *mac)
+{
+ struct gfar_private *priv = edev->priv;
+ void __iomem *regs = priv->regs;
+ char tmpbuf[MAC_ADDR_LEN];
+ uint tempval;
+ int ix;
+
+ for (ix = 0; ix < MAC_ADDR_LEN; ix++)
+ tmpbuf[MAC_ADDR_LEN - 1 - ix] = mac[ix];
+
+ tempval = (tmpbuf[0] << 24) | (tmpbuf[1] << 16) | (tmpbuf[2] << 8) |
+ tmpbuf[3];
+
+ out_be32(regs + GFAR_MACSTRADDR1_OFFSET, tempval);
+
+ tempval = *((uint *)(tmpbuf + 4));
+
+ out_be32(regs + GFAR_MACSTRADDR2_OFFSET, tempval);
+
+ return 0;
+}
+
+/* Writes the given phy's reg with value, using the specified MDIO regs */
+static int gfar_local_mdio_write(void __iomem *phyregs, uint addr, uint reg,
+ uint value)
+{
+ uint64_t start;
+
+ out_be32(phyregs + GFAR_MIIMADD_OFFSET, (addr << 8) | (reg & 0x1f));
+ out_be32(phyregs + GFAR_MIIMCON_OFFSET, value);
+
+ start = get_time_ns();
+ while (!is_timeout(start, 10 * MSECOND)) {
+ if (!(in_be32(phyregs + GFAR_MIIMMIND_OFFSET) &
+ GFAR_MIIMIND_BUSY))
+ return 0;
+ }
+
+ return -EIO;
+}
+
+/*
+ * Reads register regnum on the device's PHY through the
+ * specified registers. It lowers and raises the read
+ * command, and waits for the data to become valid (miimind
+ * notvalid bit cleared), and the bus to cease activity (miimind
+ * busy bit cleared), and then returns the value
+ */
+static uint gfar_local_mdio_read(void __iomem *phyregs, uint phyid, uint regnum)
+{
+ uint64_t start;
+
+ /* Put the address of the phy, and the register number into MIIMADD */
+ out_be32(phyregs + GFAR_MIIMADD_OFFSET, (phyid << 8) | (regnum & 0x1f));
+
+ /* Clear the command register, and wait */
+ out_be32(phyregs + GFAR_MIIMCOM_OFFSET, 0);
+
+ /* Initiate a read command, and wait */
+ out_be32(phyregs + GFAR_MIIMCOM_OFFSET, GFAR_MIIM_READ_COMMAND);
+
+ start = get_time_ns();
+ while (!is_timeout(start, 10 * MSECOND)) {
+ if (!(in_be32(phyregs + GFAR_MIIMMIND_OFFSET) &
+ (GFAR_MIIMIND_NOTVALID | GFAR_MIIMIND_BUSY)))
+ return in_be32(phyregs + GFAR_MIIMSTAT_OFFSET);
+ }
+
+ return -EIO;
+}
+
+static void gfar_configure_serdes(struct gfar_private *priv)
+{
+ gfar_local_mdio_write(priv->phyregs_sgmii,
+ in_be32(priv->regs + GFAR_TBIPA_OFFSET), GFAR_TBI_ANA,
+ priv->tbiana);
+ gfar_local_mdio_write(priv->phyregs_sgmii,
+ in_be32(priv->regs + GFAR_TBIPA_OFFSET),
+ GFAR_TBI_TBICON, GFAR_TBICON_CLK_SELECT);
+ gfar_local_mdio_write(priv->phyregs_sgmii,
+ in_be32(priv->regs + GFAR_TBIPA_OFFSET), GFAR_TBI_CR,
+ priv->tbicr);
+}
+
+/* Reset the internal and external PHYs. */
+static void gfar_init_phy(struct eth_device *dev)
+{
+ struct gfar_private *priv = dev->priv;
+ void __iomem *regs = priv->regs;
+ uint64_t start;
+
+ /* Assign a Physical address to the TBI */
+ out_be32(regs + GFAR_TBIPA_OFFSET, GFAR_TBIPA_VALUE);
+
+ /* Reset MII (due to new addresses) */
+ out_be32(priv->phyregs + GFAR_MIIMCFG_OFFSET, GFAR_MIIMCFG_RESET);
+ out_be32(priv->phyregs + GFAR_MIIMCFG_OFFSET, GFAR_MIIMCFG_INIT_VALUE);
+
+ start = get_time_ns();
+ while (!is_timeout(start, 10 * MSECOND)) {
+ if (!(in_be32(priv->phyregs + GFAR_MIIMMIND_OFFSET) &
+ GFAR_MIIMIND_BUSY))
+ break;
+ }
+
+ gfar_local_mdio_write(priv->phyregs, priv->phyaddr, GFAR_MIIM_CR,
+ GFAR_MIIM_CR_RST);
+
+ start = get_time_ns();
+ while (!is_timeout(start, 10 * MSECOND)) {
+ if (!(gfar_local_mdio_read(priv->phyregs, priv->phyaddr,
+ GFAR_MIIM_CR) & GFAR_MIIM_CR_RST))
+ break;
+ }
+
+ if (in_be32(regs + GFAR_ECNTRL_OFFSET) & GFAR_ECNTRL_SGMII_MODE)
+ gfar_configure_serdes(priv);
+}
+
+static int gfar_send(struct eth_device *edev, void *packet, int length)
+{
+ struct gfar_private *priv = edev->priv;
+ void __iomem *regs = priv->regs;
+ struct device_d *dev = edev->parent;
+ uint64_t start;
+ uint tidx;
+
+ tidx = priv->txidx;
+ priv->txbd[tidx].bufPtr = (uint) packet;
+ priv->txbd[tidx].length = length;
+ priv->txbd[tidx].status |= (TXBD_READY | TXBD_LAST |
+ TXBD_CRC | TXBD_INTERRUPT);
+
+ /* Tell the DMA to go */
+ out_be32(regs + GFAR_TSTAT_OFFSET, GFAR_TSTAT_CLEAR_THALT);
+
+ /* Wait for buffer to be transmitted */
+ start = get_time_ns();
+ while (priv->txbd[tidx].status & TXBD_READY) {
+ if (is_timeout(start, 5 * MSECOND)) {
+ break;
+ }
+ }
+
+ if (priv->txbd[tidx].status & TXBD_READY) {
+ dev_err(dev, "tx timeout: 0x%x\n", priv->txbd[tidx].status);
+ return -EBUSY;
+ }
+ else if (priv->txbd[tidx].status & TXBD_STATS) {
+ dev_err(dev, "TX error: 0x%x\n", priv->txbd[tidx].status);
+ return -EIO;
+ }
+
+ priv->txidx = (priv->txidx + 1) % TX_BUF_CNT;
+
+ return 0;
+}
+
+static int gfar_recv(struct eth_device *edev)
+{
+ struct gfar_private *priv = edev->priv;
+ struct device_d *dev = edev->parent;
+ void __iomem *regs = priv->regs;
+ int length;
+
+ if (priv->rxbd[priv->rxidx].status & RXBD_EMPTY) {
+ return 0; /* no data */
+ }
+
+ length = priv->rxbd[priv->rxidx].length;
+
+ /* Send the packet up if there were no errors */
+ if (!(priv->rxbd[priv->rxidx].status & RXBD_STATS)) {
+ net_receive(NetRxPackets[priv->rxidx], length - 4);
+ } else {
+ dev_err(dev, "Got error %x\n",
+ (priv->rxbd[priv->rxidx].status & RXBD_STATS));
+ }
+
+ priv->rxbd[priv->rxidx].length = 0;
+
+ /* Set the wrap bit if this is the last element in the list */
+ if ((priv->rxidx + 1) == RX_BUF_CNT)
+ priv->rxbd[priv->rxidx].status = RXBD_WRAP;
+ else
+ priv->rxbd[priv->rxidx].status = 0;
+
+ priv->rxbd[priv->rxidx].status |= RXBD_EMPTY;
+ priv->rxidx = (priv->rxidx + 1) % RX_BUF_CNT;
+
+ if (in_be32(regs + GFAR_IEVENT_OFFSET) & GFAR_IEVENT_BSY) {
+ out_be32(regs + GFAR_IEVENT_OFFSET, GFAR_IEVENT_BSY);
+ out_be32(regs + GFAR_RSTAT_OFFSET, GFAR_RSTAT_CLEAR_RHALT);
+ }
+
+ return 0;
+}
+
+/* Read a MII PHY register. */
+static int gfar_miiphy_read(struct mii_device *mdev, int addr, int reg)
+{
+ struct eth_device *edev = mdev->edev;
+ struct device_d *dev = edev->parent;
+ struct gfar_private *priv = edev->priv;
+ int ret;
+
+ ret = gfar_local_mdio_read(priv->phyregs, addr, reg);
+ if (ret == -EIO)
+ dev_err(dev, "Can't read PHY at address %d\n", addr);
+
+ return ret;
+}
+
+/* Write a MII PHY register. */
+static int gfar_miiphy_write(struct mii_device *mdev, int addr, int reg,
+ int value)
+{
+ struct eth_device *edev = mdev->edev;
+ struct device_d *dev = edev->parent;
+ struct gfar_private *priv = edev->priv;
+ unsigned short val = value;
+ int ret;
+
+ ret = gfar_local_mdio_write(priv->phyregs, addr, reg, val);
+
+ if (ret)
+ dev_err(dev, "Can't write PHY at address %d\n", addr);
+
+ return 0;
+}
+
+/*
+ * Initialize device structure. Returns success if
+ * initialization succeeded.
+ */
+static int gfar_probe(struct device_d *dev)
+{
+ struct gfar_info_struct *gfar_info = dev->platform_data;
+ struct eth_device *edev;
+ struct gfar_private *priv;
+ size_t size;
+ char *p;
+
+ priv = xzalloc(sizeof(struct gfar_private));
+
+ if (NULL == priv)
+ return -ENODEV;
+
+ edev = &priv->edev;
+
+ priv->regs = dev_request_mem_region(dev, 0);
+ priv->phyregs = dev_request_mem_region(dev, 1);
+ priv->phyregs_sgmii = dev_request_mem_region(dev, 2);
+
+ priv->phyaddr = gfar_info->phyaddr;
+ priv->tbicr = gfar_info->tbicr;
+ priv->tbiana = gfar_info->tbiana;
+
+ /*
+ * Allocate descriptors 64-bit aligned. Descriptors
+ * are 8 bytes in size.
+ */
+ size = ((TX_BUF_CNT * sizeof(struct txbd8)) +
+ (RX_BUF_CNT * sizeof(struct rxbd8))) + BUF_ALIGN;
+ p = (char *)xmemalign(BUF_ALIGN, size);
+ priv->txbd = (struct txbd8 *)p;
+ priv->rxbd = (struct rxbd8 *)(p + (TX_BUF_CNT * sizeof(struct txbd8)));
+
+ edev->priv = priv;
+ edev->init = gfar_init;
+ edev->open = gfar_open;
+ edev->halt = gfar_halt;
+ edev->send = gfar_send;
+ edev->recv = gfar_recv;
+ edev->get_ethaddr = gfar_get_ethaddr;
+ edev->set_ethaddr = gfar_set_ethaddr;
+ edev->parent = dev;
+
+ setbits_be32(priv->regs + GFAR_MACCFG1_OFFSET, GFAR_MACCFG1_SOFT_RESET);
+ udelay(2);
+ clrbits_be32(priv->regs + GFAR_MACCFG1_OFFSET, GFAR_MACCFG1_SOFT_RESET);
+
+ priv->miidev.read = gfar_miiphy_read;
+ priv->miidev.write = gfar_miiphy_write;
+ priv->miidev.address = priv->phyaddr;
+ priv->miidev.flags = 0;
+ priv->miidev.edev = edev;
+ priv->miidev.parent = dev;
+
+ gfar_init_phy(edev);
+
+ mii_register(&priv->miidev);
+
+ return eth_register(edev);
+}
+
+static struct driver_d gfar_eth_driver = {
+ .name = "gfar",
+ .probe = gfar_probe,
+};
+
+static int gfar_eth_init(void)
+{
+ register_driver(&gfar_eth_driver);
+ return 0;
+}
+
+device_initcall(gfar_eth_init);
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
new file mode 100644
index 0000000000..a4ad99e3b7
--- /dev/null
+++ b/drivers/net/gianfar.h
@@ -0,0 +1,284 @@
+/*
+ * gianfar.h
+ *
+ * Driver for the Motorola Triple Speed Ethernet Controller
+ *
+ * This software may be used and distributed according to the
+ * terms of the GNU Public License, Version 2, incorporated
+ * herein by reference.
+ *
+ * Copyright 2012 GE Intelligent Platforms, Inc.
+ * Copyright 2004, 2007, 2009 Freescale Semiconductor, Inc.
+ * (C) Copyright 2003, Motorola, Inc.
+ * based on tsec.h by Xianghua Xiao and Andy Fleming 2003-2009
+ */
+
+#ifndef __GIANFAR_H
+#define __GIANFAR_H
+
+#include <net.h>
+#include <config.h>
+#include <mach/gianfar.h>
+
+#define MAC_ADDR_LEN 6
+
+/* TBI register addresses */
+#define GFAR_TBI_CR 0x00
+#define GFAR_TBI_SR 0x01
+#define GFAR_TBI_ANA 0x04
+#define GFAR_TBI_ANLPBPA 0x05
+#define GFAR_TBI_ANEX 0x06
+#define GFAR_TBI_TBICON 0x11
+
+/* TBI MDIO register bit fields*/
+#define GFAR_TBICON_CLK_SELECT 0x0020
+#define GFAR_TBIANA_ASYMMETRIC_PAUSE 0x0100
+#define GFAR_TBIANA_SYMMETRIC_PAUSE 0x0080
+#define GFAR_TBIANA_HALF_DUPLEX 0x0040
+#define GFAR_TBIANA_FULL_DUPLEX 0x0020
+/* The two reserved bits below are used in AN3869 to enable SGMII. */
+#define GFAR_TBIANA_RESERVED1 0x4000
+#define GFAR_TBIANA_RESERVED15 0x0001
+#define GFAR_TBICR_PHY_RESET 0x8000
+#define GFAR_TBICR_ANEG_ENABLE 0x1000
+#define GFAR_TBICR_RESTART_ANEG 0x0200
+#define GFAR_TBICR_FULL_DUPLEX 0x0100
+#define GFAR_TBICR_SPEED1_SET 0x0040
+
+/* MAC register bits */
+#define GFAR_MACCFG1_SOFT_RESET 0x80000000
+#define GFAR_MACCFG1_RESET_RX_MC 0x00080000
+#define GFAR_MACCFG1_RESET_TX_MC 0x00040000
+#define GFAR_MACCFG1_RESET_RX_FUN 0x00020000
+#define TESC_MACCFG1_RESET_TX_FUN 0x00010000
+#define GFAR_MACCFG1_LOOPBACK 0x00000100
+#define GFAR_MACCFG1_RX_FLOW 0x00000020
+#define GFAR_MACCFG1_TX_FLOW 0x00000010
+#define GFAR_MACCFG1_SYNCD_RX_EN 0x00000008
+#define GFAR_MACCFG1_RX_EN 0x00000004
+#define GFAR_MACCFG1_SYNCD_TX_EN 0x00000002
+#define GFAR_MACCFG1_TX_EN 0x00000001
+
+#define MACCFG2_INIT_SETTINGS 0x00007205
+#define GFAR_MACCFG2_FULL_DUPLEX 0x00000001
+#define GFAR_MACCFG2_IF 0x00000300
+#define GFAR_MACCFG2_GMII 0x00000200
+#define GFAR_MACCFG2_MII 0x00000100
+
+#define ECNTRL_INIT_SETTINGS 0x00001000
+#define GFAR_ECNTRL_TBI_MODE 0x00000020
+#define GFAR_ECNTRL_R100 0x00000008
+#define GFAR_ECNTRL_SGMII_MODE 0x00000002
+
+#ifndef GFAR_TBIPA_VALUE
+ #define GFAR_TBIPA_VALUE 0x1f
+#endif
+#define GFAR_MIIMCFG_INIT_VALUE 0x00000003
+#define GFAR_MIIMCFG_RESET 0x80000000
+
+#define GFAR_MIIMIND_BUSY 0x00000001
+#define GFAR_MIIMIND_NOTVALID 0x00000004
+
+#define GFAR_MIIM_CONTROL 0x00000000
+#define GFAR_MIIM_CONTROL_RESET 0x00009140
+#define GFAR_MIIM_CONTROL_INIT 0x00001140
+#define GFAR_MIIM_CONTROL_RESTART 0x00001340
+#define GFAR_MIIM_ANEN 0x00001000
+
+#define GFAR_MIIM_CR 0x00000000
+#define GFAR_MIIM_CR_RST 0x00008000
+#define GFAR_MIIM_CR_INIT 0x00001000
+
+#define GFAR_MIIM_STATUS 0x1
+#define GFAR_MIIM_STATUS_AN_DONE 0x00000020
+#define GFAR_MIIM_STATUS_LINK 0x0004
+
+#define GFAR_MIIM_PHYIR1 0x2
+#define GFAR_MIIM_PHYIR2 0x3
+
+#define GFAR_MIIM_ANAR 0x4
+#define GFAR_MIIM_ANAR_INIT 0x1e1
+
+#define GFAR_MIIM_TBI_ANLPBPA 0x5
+#define GFAR_MIIM_TBI_ANLPBPA_HALF 0x00000040
+#define GFAR_MIIM_TBI_ANLPBPA_FULL 0x00000020
+
+#define GFAR_MIIM_TBI_ANEX 0x6
+#define GFAR_MIIM_TBI_ANEX_NP 0x00000004
+#define GFAR_MIIM_TBI_ANEX_PRX 0x00000002
+
+#define GFAR_MIIM_GBIT_CONTROL 0x9
+#define GFAR_MIIM_GBIT_CONTROL_INIT 0xe00
+
+#define GFAR_MIIM_EXT_PAGE_ACCESS 0x1f
+
+#define GFAR_MIIM_GBIT_CON 0x09
+#define GFAR_MIIM_GBIT_CON_ADVERT 0x0e00
+
+#define GFAR_MIIM_READ_COMMAND 0x00000001
+
+#define MRBLR_INIT_SETTINGS 1536
+
+#define MINFLR_INIT_SETTINGS 0x00000040
+
+#define DMACTRL_INIT_SETTINGS 0x000000c3
+#define GFAR_DMACTRL_GRS 0x00000010
+#define GFAR_DMACTRL_GTS 0x00000008
+
+#define GFAR_TSTAT_CLEAR_THALT 0x80000000
+#define GFAR_RSTAT_CLEAR_RHALT 0x00800000
+
+#define GFAR_IEVENT_INIT_CLEAR 0xffffffff
+#define GFAR_IEVENT_BABR 0x80000000
+#define GFAR_IEVENT_RXC 0x40000000
+#define GFAR_IEVENT_BSY 0x20000000
+#define GFAR_IEVENT_EBERR 0x10000000
+#define GFAR_IEVENT_MSRO 0x04000000
+#define GFAR_IEVENT_GTSC 0x02000000
+#define GFAR_IEVENT_BABT 0x01000000
+#define GFAR_IEVENT_TXC 0x00800000
+#define GFAR_IEVENT_TXE 0x00400000
+#define GFAR_IEVENT_TXB 0x00200000
+#define GFAR_IEVENT_TXF 0x00100000
+#define GFAR_IEVENT_IE 0x00080000
+#define GFAR_IEVENT_LC 0x00040000
+#define GFAR_IEVENT_CRL 0x00020000
+#define GFAR_IEVENT_XFUN 0x00010000
+#define GFAR_IEVENT_RXB0 0x00008000
+#define GFAR_IEVENT_GRSC 0x00000100
+#define GFAR_IEVENT_RXF0 0x00000080
+
+#define GFAR_IMASK_INIT_CLEAR 0x00000000
+
+/* Default Attribute fields */
+#define ATTR_INIT_SETTINGS 0x000000c0
+#define ATTRELI_INIT_SETTINGS 0x00000000
+
+/* TxBD status field bits */
+#define TXBD_READY 0x8000
+#define TXBD_PADCRC 0x4000
+#define TXBD_WRAP 0x2000
+#define TXBD_INTERRUPT 0x1000
+#define TXBD_LAST 0x0800
+#define TXBD_CRC 0x0400
+#define TXBD_DEF 0x0200
+#define TXBD_HUGEFRAME 0x0080
+#define TXBD_LATECOLLISION 0x0080
+#define TXBD_RETRYLIMIT 0x0040
+#define TXBD_RETRYCOUNTMASK 0x003c
+#define TXBD_UNDERRUN 0x0002
+#define TXBD_STATS 0x03ff
+
+/* RxBD status field bits */
+#define RXBD_EMPTY 0x8000
+#define RXBD_RO1 0x4000
+#define RXBD_WRAP 0x2000
+#define RXBD_INTERRUPT 0x1000
+#define RXBD_LAST 0x0800
+#define RXBD_FIRST 0x0400
+#define RXBD_MISS 0x0100
+#define RXBD_BROADCAST 0x0080
+#define RXBD_MULTICAST 0x0040
+#define RXBD_LARGE 0x0020
+#define RXBD_NONOCTET 0x0010
+#define RXBD_SHORT 0x0008
+#define RXBD_CRCERR 0x0004
+#define RXBD_OVERRUN 0x0002
+#define RXBD_TRUNCATED 0x0001
+#define RXBD_STATS 0x003f
+
+struct txbd8 {
+ ushort status; /* Status Fields */
+ ushort length; /* Buffer length */
+ uint bufPtr; /* Buffer Pointer */
+};
+
+struct rxbd8 {
+ ushort status; /* Status Fields */
+ ushort length; /* Buffer Length */
+ uint bufPtr; /* Buffer Pointer */
+};
+
+/* eTSEC general control and status registers */
+#define GFAR_IEVENT_OFFSET 0x010 /* Interrupt Event */
+#define GFAR_IMASK_OFFSET 0x014 /* Interrupt Mask */
+#define GFAR_ECNTRL_OFFSET 0x020 /* Ethernet Control */
+#define GFAR_MINFLR_OFFSET 0x024 /* Minimum Frame Length */
+#define GFAR_DMACTRL_OFFSET 0x02c /* DMA Control */
+#define GFAR_TBIPA_OFFSET 0x030 /* TBI PHY address */
+
+/* eTSEC transmit control and status register */
+#define GFAR_TSTAT_OFFSET 0x104 /* transmit status register */
+#define GFAR_TBASE0_OFFSET 0x204 /* TxBD Base Address */
+
+/* eTSEC receive control and status register */
+#define GFAR_RCTRL_OFFSET 0x300 /* Receive Control */
+#define GFAR_RSTAT_OFFSET 0x304 /* transmit status register */
+#define GFAR_MRBLR_OFFSET 0x340 /* Maximum Receive Buffer Length */
+#define GFAR_RBASE0_OFFSET 0x404 /* RxBD Base Address */
+
+/* eTSEC MAC registers */
+#define GFAR_MACCFG1_OFFSET 0x500 /* MAC Configuration #1 */
+#define GFAR_MACCFG2_OFFSET 0x504 /* MAC Configuration #2 */
+#define GFAR_MIIMCFG_OFFSET 0x520 /* MII management configuration */
+#define GFAR_MIIMCOM_OFFSET 0x524 /* MII management command */
+#define GFAR_MIIMADD_OFFSET 0x528 /* MII management address */
+#define GFAR_MIIMCON_OFFSET 0x52c /* MII management control */
+#define GFAR_MIIMSTAT_OFFSET 0x530 /* MII management status */
+#define GFAR_MIIMMIND_OFFSET 0x534 /* MII management indicator */
+#define GFAR_MACSTRADDR1_OFFSET 0x540 /* MAC station address #1 */
+#define GFAR_MACSTRADDR2_OFFSET 0x544 /* MAC station address #2 */
+
+/* eTSEC transmit and receive counters registers. */
+#define GFAR_TR64_OFFSET 0x680
+/* eTSEC counter control and TOE statistics registers */
+#define GFAR_CAM1_OFFSET 0x738
+#define GFAR_CAM2_OFFSET 0x73c
+
+/* Individual/group address registers */
+#define GFAR_IADDR0_OFFSET 0x800
+#define GFAR_IADDR1_OFFSET 0x804
+#define GFAR_IADDR2_OFFSET 0x808
+#define GFAR_IADDR3_OFFSET 0x80c
+#define GFAR_IADDR4_OFFSET 0x810
+#define GFAR_IADDR5_OFFSET 0x814
+#define GFAR_IADDR6_OFFSET 0x818
+#define GFAR_IADDR7_OFFSET 0x81c
+
+#define GFAR_IADDR(REGNUM) (GFAR_IADDR##REGNUM##_OFFSET)
+
+/* Group address registers */
+#define GFAR_GADDR0_OFFSET 0x880
+#define GFAR_GADDR1_OFFSET 0x884
+#define GFAR_GADDR2_OFFSET 0x888
+#define GFAR_GADDR3_OFFSET 0x88c
+#define GFAR_GADDR4_OFFSET 0x890
+#define GFAR_GADDR5_OFFSET 0x894
+#define GFAR_GADDR6_OFFSET 0x898
+#define GFAR_GADDR7_OFFSET 0x89c
+
+#define GFAR_GADDR(REGNUM) (GFAR_GADDR##REGNUM##_OFFSET)
+
+/* eTSEC DMA attributes registers */
+#define GFAR_ATTR_OFFSET 0xbf8 /* Default Attribute Register */
+#define GFAR_ATTRELI_OFFSET 0xbfc /* Default Attribute Extract Len/Idx */
+
+struct gfar_private {
+ struct eth_device edev;
+ void __iomem *regs;
+ void __iomem *phyregs;
+ void __iomem *phyregs_sgmii;
+ struct phy_info *phyinfo;
+ struct mii_device miidev;
+ volatile struct txbd8 *txbd;
+ volatile struct rxbd8 *rxbd;
+ uint txidx;
+ uint rxidx;
+ uint phyaddr;
+ uint tbicr;
+ uint tbiana;
+ uint link;
+ uint duplexity;
+ uint speed;
+};
+#endif /* __GIANFAR_H */
diff --git a/drivers/net/miidev.c b/drivers/net/miidev.c
index b49944bbfe..75b53e3c5c 100644
--- a/drivers/net/miidev.c
+++ b/drivers/net/miidev.c
@@ -116,7 +116,7 @@ int miidev_wait_aneg(struct mii_device *mdev)
return -ETIMEDOUT;
}
- } while (!(status & BMSR_LSTATUS));
+ } while (!(status & BMSR_ANEGCOMPLETE));
return 0;
}
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index a249b81f51..b5c55a4afc 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -16,7 +16,7 @@ config DRIVER_SPI_IMX_0_0
config DRIVER_SPI_IMX_0_7
bool
- depends on ARCH_IMX25
+ depends on ARCH_IMX25 || ARCH_IMX35
default y
config DRIVER_SPI_IMX_2_3
diff --git a/drivers/spi/imx_spi.c b/drivers/spi/imx_spi.c
index 2e59b3c8dd..80a14504f0 100644
--- a/drivers/spi/imx_spi.c
+++ b/drivers/spi/imx_spi.c
@@ -517,7 +517,7 @@ static int imx_spi_probe(struct device_d *dev)
version = SPI_IMX_VER_0_0;
#endif
#ifdef CONFIG_DRIVER_SPI_IMX_0_7
- if (cpu_is_mx25())
+ if (cpu_is_mx25() || cpu_is_mx35())
version = SPI_IMX_VER_0_7;
#endif
#ifdef CONFIG_DRIVER_SPI_IMX_2_3