SVN-Revision: 26021master
parent
58a5102338
commit
c75b0ca1a8
@ -0,0 +1,31 @@ |
||||
CONFIG_CPU_MIPSR2_IRQ_EI=y |
||||
CONFIG_CPU_MIPSR2_IRQ_VI=y |
||||
# CONFIG_CRYPTO is not set |
||||
CONFIG_DM9000=y |
||||
CONFIG_DM9000_DEBUGLEVEL=4 |
||||
CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL=y |
||||
CONFIG_HAVE_IDE=y |
||||
CONFIG_HW_HAS_PCI=y |
||||
CONFIG_IFX_VPE_CACHE_SPLIT=y |
||||
CONFIG_IFX_VPE_EXT=y |
||||
CONFIG_LANTIQ_MACH_95C3AM1=y |
||||
CONFIG_LANTIQ_MACH_EASY98000=y |
||||
CONFIG_LANTIQ_MACH_EASY98020=y |
||||
CONFIG_LANTIQ_PROM_ASC0=y |
||||
# CONFIG_LANTIQ_PROM_ASC1 is not set |
||||
CONFIG_M25PXX_USE_FAST_READ=y |
||||
CONFIG_MIPS_MT=y |
||||
# CONFIG_MIPS_VPE_APSP_API is not set |
||||
CONFIG_MIPS_VPE_LOADER=y |
||||
CONFIG_MIPS_VPE_LOADER_TOM=y |
||||
CONFIG_MTD_M25P80=y |
||||
CONFIG_MTSCHED=y |
||||
# CONFIG_PCI is not set |
||||
# CONFIG_PERFCTRS is not set |
||||
CONFIG_SOC_LANTIQ_FALCON=y |
||||
# CONFIG_SOC_LANTIQ_XWAY is not set |
||||
CONFIG_SPI=y |
||||
# CONFIG_SPI_BITBANG is not set |
||||
CONFIG_SPI_FALCON=y |
||||
# CONFIG_SPI_GPIO is not set |
||||
CONFIG_SPI_MASTER=y |
@ -0,0 +1,14 @@ |
||||
define Profile/Generic |
||||
NAME:=Generic - all boards
|
||||
PACKAGES:= \
|
||||
kmod-leds-gpio \
|
||||
kmod-dm9000 \
|
||||
kmod-i2c-core kmod-i2c-algo-bit kmod-i2c-gpio kmod-eeprom-at24 \
|
||||
kmod-spi-bitbang kmod-spi-gpio kmod-eeprom-at25 \
|
||||
gpon-dti-agent \
|
||||
uboot-easy980x0_norflash uboot-easy980x0_serialflash uboot-easy98020
|
||||
endef |
||||
|
||||
$(eval $(call Profile,Generic)) |
||||
|
||||
|
@ -0,0 +1,27 @@ |
||||
define Profile/EASY98000 |
||||
NAME:=EASY98000
|
||||
PACKAGES:= \
|
||||
kmod-dm9000 \
|
||||
kmod-i2c-core kmod-i2c-algo-bit kmod-i2c-gpio kmod-eeprom-at24 \
|
||||
kmod-spi-bitbang kmod-spi-gpio kmod-eeprom-at25 \
|
||||
uboot-easy980x0_norflash uboot-easy980x0_serialflash
|
||||
endef |
||||
|
||||
define Profile/EASY98000/Description |
||||
Lantiq EASY98000 evalkit
|
||||
endef |
||||
|
||||
$(eval $(call Profile,EASY98000)) |
||||
|
||||
define Profile/EASY98020 |
||||
NAME:=EASY98020
|
||||
PACKAGES:= \
|
||||
kmod-leds-gpio uboot-easy98020
|
||||
endef |
||||
|
||||
define Profile/EASY98020/Description |
||||
Lantiq EASY98020 evalkit
|
||||
endef |
||||
|
||||
$(eval $(call Profile,EASY98020)) |
||||
|
@ -0,0 +1,13 @@ |
||||
ARCH:=mips
|
||||
SUBTARGET:=falcon
|
||||
BOARDNAME:=Falcon
|
||||
FEATURES:=squashfs jffs2
|
||||
DEVICE_TYPE:=other
|
||||
|
||||
DEFAULT_PACKAGES+= kmod-ifxos gpon-base-files kmod-leds-gpio \
|
||||
kmod-gpon-optic-drv gpon-optic-drv kmod-gpon-onu-drv gpon-onu-drv \
|
||||
gpon-pe-firmware gpon-omci-api gpon-omci-onu gpon-luci
|
||||
|
||||
define Target/Description |
||||
Lantiq Falcon
|
||||
endef |
@ -1,12 +1,12 @@ |
||||
--- a/kernel/irq/chip.c
|
||||
+++ b/kernel/irq/chip.c
|
||||
@@ -650,6 +650,9 @@ handle_percpu_irq(unsigned int irq, stru
|
||||
@@ -678,6 +678,9 @@
|
||||
|
||||
kstat_incr_irqs_this_cpu(irq, desc);
|
||||
|
||||
+ if (unlikely(!desc->action || (desc->status & IRQ_DISABLED)))
|
||||
+ return;
|
||||
+
|
||||
if (desc->chip->ack)
|
||||
desc->chip->ack(irq);
|
||||
if (desc->irq_data.chip->irq_ack)
|
||||
desc->irq_data.chip->irq_ack(&desc->irq_data);
|
||||
|
||||
|
@ -0,0 +1,90 @@ |
||||
--- /dev/null
|
||||
+++ b/arch/mips/include/asm/mach-lantiq/dev-leds-gpio.h
|
||||
@@ -0,0 +1,21 @@
|
||||
+/*
|
||||
+ * Lantiq GPIO LED device support
|
||||
+ *
|
||||
+ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
|
||||
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.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.
|
||||
+ */
|
||||
+
|
||||
+#ifndef _LANTIQ_DEV_LEDS_GPIO_H
|
||||
+#define _LANTIQ_DEV_LEDS_GPIO_H
|
||||
+
|
||||
+#include <linux/leds.h>
|
||||
+
|
||||
+void lq_add_device_leds_gpio(int id,
|
||||
+ unsigned num_leds,
|
||||
+ struct gpio_led *leds) __init;
|
||||
+
|
||||
+#endif /* _LANTIQ_DEV_LEDS_GPIO_H */
|
||||
--- /dev/null
|
||||
+++ b/arch/mips/lantiq/dev-leds-gpio.c
|
||||
@@ -0,0 +1,57 @@
|
||||
+/*
|
||||
+ * Lantiq GPIO LED device support
|
||||
+ *
|
||||
+ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
|
||||
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
|
||||
+ *
|
||||
+ * Parts of this file are based on Atheros' 2.6.15 BSP
|
||||
+ *
|
||||
+ * 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.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/slab.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+
|
||||
+#include "dev-leds-gpio.h"
|
||||
+
|
||||
+void __init lq_add_device_leds_gpio(int id, unsigned num_leds,
|
||||
+ struct gpio_led *leds)
|
||||
+{
|
||||
+ struct platform_device *pdev;
|
||||
+ struct gpio_led_platform_data pdata;
|
||||
+ struct gpio_led *p;
|
||||
+ int err;
|
||||
+
|
||||
+ p = kmalloc(num_leds * sizeof(*p), GFP_KERNEL);
|
||||
+ if (!p)
|
||||
+ return;
|
||||
+
|
||||
+ memcpy(p, leds, num_leds * sizeof(*p));
|
||||
+
|
||||
+ pdev = platform_device_alloc("leds-gpio", id);
|
||||
+ if (!pdev)
|
||||
+ goto err_free_leds;
|
||||
+
|
||||
+ memset(&pdata, 0, sizeof(pdata));
|
||||
+ pdata.num_leds = num_leds;
|
||||
+ pdata.leds = p;
|
||||
+
|
||||
+ err = platform_device_add_data(pdev, &pdata, sizeof(pdata));
|
||||
+ if (err)
|
||||
+ goto err_put_pdev;
|
||||
+
|
||||
+ err = platform_device_add(pdev);
|
||||
+ if (err)
|
||||
+ goto err_put_pdev;
|
||||
+
|
||||
+ return;
|
||||
+
|
||||
+err_put_pdev:
|
||||
+ platform_device_put(pdev);
|
||||
+
|
||||
+err_free_leds:
|
||||
+ kfree(p);
|
||||
+}
|
||||
--- a/arch/mips/lantiq/Makefile
|
||||
+++ b/arch/mips/lantiq/Makefile
|
||||
@@ -1,2 +1,2 @@
|
||||
-obj-y := irq.o setup.o clk.o prom.o
|
||||
+obj-y := dev-leds-gpio.o irq.o setup.o clk.o prom.o
|
||||
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
|
@ -1,99 +0,0 @@ |
||||
--- a/drivers/mtd/maps/lantiq.c
|
||||
+++ b/drivers/mtd/maps/lantiq.c
|
||||
@@ -24,6 +24,10 @@
|
||||
#include <lantiq.h>
|
||||
#include <lantiq_platform.h>
|
||||
|
||||
+#ifdef CONFIG_SOC_LANTIQ_XWAY
|
||||
+#include <xway.h>
|
||||
+#endif
|
||||
+
|
||||
static map_word
|
||||
lq_read16(struct map_info *map, unsigned long adr)
|
||||
{
|
||||
@@ -77,6 +81,75 @@ lq_copy_to(struct map_info *map, unsigne
|
||||
spin_unlock_irqrestore(&ebu_lock, flags);
|
||||
}
|
||||
|
||||
+static unsigned long
|
||||
+find_uImage_size(struct map_info *map, unsigned long offset)
|
||||
+{
|
||||
+#define UBOOT_MAGIC 0x56190527
|
||||
+ unsigned long magic;
|
||||
+ unsigned long temp;
|
||||
+ map->copy_from(map, &magic, offset, 4);
|
||||
+ if (le32_to_cpu(magic) != UBOOT_MAGIC)
|
||||
+ return 0;
|
||||
+ map->copy_from(map, &temp, offset + 12, 4);
|
||||
+ return temp + 0x40;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+detect_squashfs_partition(struct map_info *map, unsigned long offset)
|
||||
+{
|
||||
+ unsigned long temp;
|
||||
+ map->copy_from(map, &temp, offset, 4);
|
||||
+ return le32_to_cpu(temp) == SQUASHFS_MAGIC;
|
||||
+}
|
||||
+
|
||||
+static struct mtd_partition split_partitions[] = {
|
||||
+ {
|
||||
+ .name = "kernel",
|
||||
+ .offset = 0x0,
|
||||
+ .size = 0x0,
|
||||
+ }, {
|
||||
+ .name = "rootfs",
|
||||
+ .offset = 0x0,
|
||||
+ .size = 0x0,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static int
|
||||
+mtd_split_linux(struct map_info *map, struct mtd_info *mtd,
|
||||
+ struct mtd_partition *parts, int nr_parts)
|
||||
+{
|
||||
+ int base_part = 0;
|
||||
+ int i;
|
||||
+ for (i = 0; i < nr_parts && !base_part; i++) {
|
||||
+ if(!strcmp("linux", parts[i].name))
|
||||
+ base_part = i;
|
||||
+ }
|
||||
+ if (!base_part)
|
||||
+ return 0;
|
||||
+ split_partitions[0].size = find_uImage_size(map, parts[base_part].offset);
|
||||
+ if (!split_partitions[0].size) {
|
||||
+ printk(KERN_INFO "lq_nor: no uImage found in linux partition");
|
||||
+ return -1;
|
||||
+ }
|
||||
+ if (!detect_squashfs_partition(map,
|
||||
+ parts[base_part].offset + split_partitions[0].size)) {
|
||||
+ split_partitions[0].size &= ~(mtd->erasesize - 1);
|
||||
+ split_partitions[0].size += mtd->erasesize;
|
||||
+ }
|
||||
+ split_partitions[0].offset = parts[base_part].offset;
|
||||
+ split_partitions[1].offset =
|
||||
+ parts[base_part].offset + split_partitions[0].size;
|
||||
+ split_partitions[1].size =
|
||||
+ parts[base_part].size - split_partitions[0].size;
|
||||
+
|
||||
+ base_part++;
|
||||
+ add_mtd_partitions(mtd, parts, base_part);
|
||||
+ add_mtd_partitions(mtd, split_partitions, 2);
|
||||
+ if(nr_parts != base_part)
|
||||
+ add_mtd_partitions(mtd, &parts[base_part], nr_parts - base_part);
|
||||
+ return nr_parts + 2;
|
||||
+}
|
||||
+
|
||||
static const char *part_probe_types[] = { "cmdlinepart", NULL };
|
||||
|
||||
static struct map_info lq_map = {
|
||||
@@ -142,7 +215,8 @@ lq_mtd_probe(struct platform_device *pde
|
||||
parts = lq_mtd_data->parts;
|
||||
}
|
||||
|
||||
- add_mtd_partitions(lq_mtd, parts, nr_parts);
|
||||
+ if (!mtd_split_linux(&lq_map, lq_mtd, parts, nr_parts))
|
||||
+ add_mtd_partitions(lq_mtd, parts, nr_parts);
|
||||
return 0;
|
||||
}
|
||||
|
@ -0,0 +1,116 @@ |
||||
--- a/drivers/mtd/Kconfig
|
||||
+++ b/drivers/mtd/Kconfig
|
||||
@@ -63,6 +63,10 @@ config MTD_ROOTFS_SPLIT
|
||||
depends on MTD_PARTITIONS
|
||||
default y
|
||||
|
||||
+config MTD_UIMAGE_SPLIT
|
||||
+ bool "Automatically split 'linux' partition into 'kernel' and 'rootfs'"
|
||||
+ default y
|
||||
+
|
||||
config MTD_REDBOOT_PARTS
|
||||
tristate "RedBoot partition table parsing"
|
||||
depends on MTD_PARTITIONS
|
||||
--- a/drivers/mtd/mtdpart.c
|
||||
+++ b/drivers/mtd/mtdpart.c
|
||||
@@ -722,6 +722,82 @@ static int refresh_rootfs_split(struct m
|
||||
}
|
||||
#endif /* CONFIG_MTD_ROOTFS_SPLIT */
|
||||
|
||||
+
|
||||
+#ifdef CONFIG_MTD_UIMAGE_SPLIT
|
||||
+static unsigned long find_uimage_size(struct mtd_info *mtd,
|
||||
+ unsigned long offset)
|
||||
+{
|
||||
+#define UBOOT_MAGIC 0x56190527
|
||||
+ unsigned long magic = 0;
|
||||
+ unsigned long temp;
|
||||
+ size_t len;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = mtd->read(mtd, offset, 4, &len, (void *)&magic);
|
||||
+ if (ret || len != sizeof(magic))
|
||||
+ return 0;
|
||||
+
|
||||
+ if (le32_to_cpu(magic) != UBOOT_MAGIC)
|
||||
+ return 0;
|
||||
+
|
||||
+ ret = mtd->read(mtd, offset + 12, 4, &len, (void *)&temp);
|
||||
+ if (ret || len != sizeof(temp))
|
||||
+ return 0;
|
||||
+
|
||||
+ return temp + 0x40;
|
||||
+}
|
||||
+
|
||||
+static int detect_squashfs_partition(struct mtd_info *mtd, unsigned long offset)
|
||||
+{
|
||||
+ unsigned long temp;
|
||||
+ size_t len;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = mtd->read(mtd, offset, 4, &len, (void *)&temp);
|
||||
+ if (ret || len != sizeof(temp))
|
||||
+ return 0;
|
||||
+
|
||||
+ return le32_to_cpu(temp) == SQUASHFS_MAGIC;
|
||||
+}
|
||||
+
|
||||
+static int split_uimage(struct mtd_info *mtd,
|
||||
+ const struct mtd_partition *part)
|
||||
+{
|
||||
+ static struct mtd_partition split_partitions[] = {
|
||||
+ {
|
||||
+ .name = "kernel",
|
||||
+ .offset = 0x0,
|
||||
+ .size = 0x0,
|
||||
+ }, {
|
||||
+ .name = "rootfs",
|
||||
+ .offset = 0x0,
|
||||
+ .size = 0x0,
|
||||
+ },
|
||||
+ };
|
||||
+
|
||||
+ split_partitions[0].size = find_uimage_size(mtd, part->offset);
|
||||
+ if (!split_partitions[0].size) {
|
||||
+ printk(KERN_NOTICE "no uImage found in linux partition\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ if (!detect_squashfs_partition(mtd,
|
||||
+ part->offset
|
||||
+ + split_partitions[0].size)) {
|
||||
+ split_partitions[0].size &= ~(mtd->erasesize - 1);
|
||||
+ split_partitions[0].size += mtd->erasesize;
|
||||
+ }
|
||||
+
|
||||
+ split_partitions[0].offset = part->offset;
|
||||
+ split_partitions[1].offset = part->offset + split_partitions[0].size;
|
||||
+ split_partitions[1].size = part->size - split_partitions[0].size;
|
||||
+
|
||||
+ add_mtd_partitions(mtd, split_partitions, 2);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
/*
|
||||
* This function, given a master MTD object and a partition table, creates
|
||||
* and registers slave MTD objects which are bound to the master according to
|
||||
@@ -746,6 +822,17 @@ int add_mtd_partitions(struct mtd_info *
|
||||
if (!slave)
|
||||
return -ENOMEM;
|
||||
|
||||
+#ifdef CONFIG_MTD_UIMAGE_SPLIT
|
||||
+ if (!strcmp(parts[i].name, "linux")) {
|
||||
+ ret = split_uimage(master, &parts[i]);
|
||||
+
|
||||
+ if (ret) {
|
||||
+ printk(KERN_WARNING
|
||||
+ "Can't split linux partition\n");
|
||||
+ }
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
if (!strcmp(parts[i].name, "rootfs")) {
|
||||
#ifdef CONFIG_MTD_ROOTFS_ROOT_DEV
|
||||
if (ROOT_DEV == 0) {
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,827 @@ |
||||
--- a/drivers/i2c/busses/Makefile
|
||||
+++ b/drivers/i2c/busses/Makefile
|
||||
@@ -76,5 +76,6 @@
|
||||
obj-$(CONFIG_I2C_STUB) += i2c-stub.o
|
||||
obj-$(CONFIG_SCx200_ACB) += scx200_acb.o
|
||||
obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o
|
||||
+obj-$(CONFIG_I2C_FALCON) += i2c-falcon.o
|
||||
|
||||
ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG
|
||||
--- a/drivers/i2c/busses/Kconfig
|
||||
+++ b/drivers/i2c/busses/Kconfig
|
||||
@@ -281,6 +281,10 @@
|
||||
|
||||
comment "I2C system bus drivers (mostly embedded / system-on-chip)"
|
||||
|
||||
+config I2C_FALCON
|
||||
+ tristate "Falcon I2C interface"
|
||||
+# depends on SOC_FALCON
|
||||
+
|
||||
config I2C_AT91
|
||||
tristate "Atmel AT91 I2C Two-Wire interface (TWI)"
|
||||
depends on ARCH_AT91 && EXPERIMENTAL && BROKEN
|
||||
--- /dev/null
|
||||
+++ b/drivers/i2c/busses/i2c-falcon.c
|
||||
@@ -0,0 +1,802 @@
|
||||
+/*
|
||||
+ * 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.
|
||||
+ */
|
||||
+
|
||||
+/* #define DEBUG */
|
||||
+
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/ioport.h>
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/i2c.h>
|
||||
+#include <linux/interrupt.h>
|
||||
+#include <linux/spinlock.h>
|
||||
+#include <linux/io.h>
|
||||
+#include <linux/clk.h>
|
||||
+#include <linux/err.h>
|
||||
+
|
||||
+/* CURRENT ISSUES:
|
||||
+ * - no high speed support
|
||||
+ * - rx issue with "address mode" & "tx end" interrupts
|
||||
+ * - ten bit mode is not tested
|
||||
+ */
|
||||
+
|
||||
+/* mapping for access macros */
|
||||
+#define reg_r32(reg) __raw_readl(reg)
|
||||
+#define reg_w32(val, reg) __raw_writel(val, reg)
|
||||
+#define reg_w32_mask(clear, set, reg) \
|
||||
+ reg_w32((reg_r32(reg) & ~(clear)) | (set), reg)
|
||||
+#define reg_r32_table(reg, idx) reg_r32(&((uint32_t *)®)[idx])
|
||||
+#define reg_w32_table(val, reg, idx) reg_w32(val, &((uint32_t *)®)[idx])
|
||||
+#define i2c (priv->membase)
|
||||
+#include <falcon/i2c_reg.h>
|
||||
+
|
||||
+/* enable hacks to overcome current issue */
|
||||
+#define FALCON_FIX_ME
|
||||
+
|
||||
+#define FALCON_I2C_ADDR 0x00
|
||||
+#define FALCON_I2C_READY_TIMEOUT 1000
|
||||
+#define FALCON_I2C_WAIT_TIMEOUT 10
|
||||
+
|
||||
+#define DRV_NAME "i2c-falcon"
|
||||
+
|
||||
+#if defined(DEBUG)
|
||||
+#define static /* no static functions for better debugging */
|
||||
+#endif
|
||||
+
|
||||
+#define FALCON_I2C_ARB_LOST (1 << 0)
|
||||
+#define FALCON_I2C_NACK (1 << 1)
|
||||
+#define FALCON_I2C_RX_UFL (1 << 2)
|
||||
+#define FALCON_I2C_RX_OFL (1 << 3)
|
||||
+#define FALCON_I2C_TX_UFL (1 << 4)
|
||||
+#define FALCON_I2C_TX_OFL (1 << 5)
|
||||
+#define FALCON_I2C_BURST_REQ (1 << 6)
|
||||
+#define FALCON_I2C_RX (1 << 7)
|
||||
+#define FALCON_I2C_TX_END (1 << 8)
|
||||
+#define FALCON_I2C_ADDR_MATCH (1 << 9) /* doesn't trigger */
|
||||
+
|
||||
+struct falcon_i2c {
|
||||
+ spinlock_t lock;
|
||||
+
|
||||
+ enum {
|
||||
+ FALCON_I2C_MODE_100 = 1,
|
||||
+ FALCON_I2C_MODE_400 = 2,
|
||||
+ FALCON_I2C_MODE_3400 = 3
|
||||
+ } mode; /* current speed mode */
|
||||
+
|
||||
+ int ten_bit; /* current address mode */
|
||||
+ unsigned long status; /* bus events holder */
|
||||
+ struct clk *clk; /* clock input for i2c hardware block */
|
||||
+ struct gpon_reg_i2c __iomem *membase; /* base of mapped registers */
|
||||
+ int irq_lb, irq_b, irq_err, irq_p; /* last burst, burst, error,
|
||||
+ protocol IRQs */
|
||||
+ struct completion done;
|
||||
+ struct i2c_adapter adap;
|
||||
+ struct device *dev;
|
||||
+};
|
||||
+
|
||||
+#define FALCON_I2C_ERROR_MASK (FALCON_I2C_NACK \
|
||||
+ | FALCON_I2C_ARB_LOST \
|
||||
+ | FALCON_I2C_RX_OFL \
|
||||
+ | FALCON_I2C_RX_UFL \
|
||||
+ | FALCON_I2C_TX_OFL \
|
||||
+ | FALCON_I2C_TX_UFL)
|
||||
+
|
||||
+#define FALCON_I2C_ERROR(priv) (priv->status & FALCON_I2C_ERROR_MASK)
|
||||
+#define FALCON_I2C_ERROR_CLEAR(priv) do { \
|
||||
+ priv->status &= \
|
||||
+ ~FALCON_I2C_ERROR_MASK; \
|
||||
+ } while (0)
|
||||
+
|
||||
+static void falcon_addr_configure(struct falcon_i2c *priv, int ten_bit)
|
||||
+{
|
||||
+ u32 ten_bit_mask = ten_bit ? I2C_ADDR_CFG_TBAM_10bit : 0;
|
||||
+
|
||||
+ /* configure address */
|
||||
+ i2c_w32(I2C_ADDR_CFG_SOPE_EN /* generate stop when no more data in the
|
||||
+ fifo */
|
||||
+ | I2C_ADDR_CFG_SONA_EN /* generate stop when NA received */
|
||||
+ | I2C_ADDR_CFG_MnS_EN /* we are master device */
|
||||
+ | ten_bit_mask
|
||||
+ | FALCON_I2C_ADDR, /* our address */
|
||||
+ addr_cfg);
|
||||
+}
|
||||
+
|
||||
+static irqreturn_t falcon_i2c_isr(int irq, void *dev_id)
|
||||
+{
|
||||
+ u32 i_raw, i_pro, i_err;
|
||||
+ struct falcon_i2c *priv = dev_id;
|
||||
+ unsigned long flags;
|
||||
+ unsigned int old_status;
|
||||
+
|
||||
+ spin_lock_irqsave(&priv->lock, flags);
|
||||
+
|
||||
+ old_status = (unsigned int)priv->status;
|
||||
+
|
||||
+ i_raw = i2c_r32(mis);
|
||||
+
|
||||
+ /* protocol interrupt */
|
||||
+ if (i_raw & I2C_RIS_I2C_P_INT_INTOCC) {
|
||||
+ i_pro = i2c_r32(p_irqss);
|
||||
+
|
||||
+ /* tx -> rx switch */
|
||||
+ if (i_pro & I2C_P_IRQSS_RX)
|
||||
+ priv->status |= FALCON_I2C_RX;
|
||||
+
|
||||
+ /* tx end */
|
||||
+ if (i_pro & I2C_P_IRQSS_TX_END)
|
||||
+ priv->status |= FALCON_I2C_TX_END;
|
||||
+
|
||||
+ /* not acknowledge */
|
||||
+ if (i_pro & I2C_P_IRQSS_NACK)
|
||||
+ priv->status |= FALCON_I2C_NACK;
|
||||
+
|
||||
+ /* arbitration lost */
|
||||
+ if (i_pro & I2C_P_IRQSS_AL)
|
||||
+ priv->status |= FALCON_I2C_ARB_LOST;
|
||||
+
|
||||
+ /* address match */
|
||||
+ if (i_pro & I2C_P_IRQSS_AM)
|
||||
+ priv->status |= FALCON_I2C_ADDR_MATCH;
|
||||
+
|
||||
+ i2c_w32(i_pro, p_irqsc);
|
||||
+ }
|
||||
+
|
||||
+ /* error interrupt */
|
||||
+ if (i_raw & I2C_RIS_I2C_ERR_INT_INTOCC) {
|
||||
+ i_err = i2c_r32(err_irqss);
|
||||
+
|
||||
+ /* tx fifo overflow */
|
||||
+ if (i_err & I2C_ERR_IRQSS_TXF_OFL)
|
||||
+ priv->status |= FALCON_I2C_TX_OFL;
|
||||
+
|
||||
+ /* tx fifo underflow */
|
||||
+ if (i_err & I2C_ERR_IRQSS_TXF_UFL)
|
||||
+ priv->status |= FALCON_I2C_TX_UFL;
|
||||
+
|
||||
+ /* rx fifo overflow */
|
||||
+ if (i_err & I2C_ERR_IRQSS_RXF_OFL)
|
||||
+ priv->status |= FALCON_I2C_RX_OFL;
|
||||
+
|
||||
+ /* rx fifo underflow */
|
||||
+ if (i_err & I2C_ERR_IRQSS_RXF_UFL)
|
||||
+ priv->status |= FALCON_I2C_RX_UFL;
|
||||
+
|
||||
+ i2c_w32(i_err, err_irqsc);
|
||||
+ }
|
||||
+
|
||||
+ /* burst request */
|
||||
+ if (i_raw & I2C_RIS_BREQ_INT_INTOCC) {
|
||||
+ i2c_w32_mask(I2C_IMSC_BREQ_INT_EN, 0, imsc);
|
||||
+ i2c_w32_mask(0, I2C_ICR_BREQ_INT_CLR, icr);
|
||||
+
|
||||
+ priv->status |= FALCON_I2C_BURST_REQ;
|
||||
+ }
|
||||
+
|
||||
+ /* last burst request */
|
||||
+ if (i_raw & I2C_RIS_LBREQ_INT_INTOCC) {
|
||||
+ i2c_w32_mask(I2C_IMSC_LBREQ_INT_EN, 0, imsc);
|
||||
+ i2c_w32_mask(0, I2C_ICR_LBREQ_INT_CLR, icr);
|
||||
+
|
||||
+ priv->status |= FALCON_I2C_BURST_REQ;
|
||||
+ }
|
||||
+
|
||||
+ if (old_status != (unsigned int)priv->status)
|
||||
+ complete(&priv->done);
|
||||
+
|
||||
+ spin_unlock_irqrestore(&priv->lock, flags);
|
||||
+
|
||||
+ return IRQ_HANDLED;
|
||||
+}
|
||||
+
|
||||
+static int falcon_i2c_ready(struct falcon_i2c *priv)
|
||||
+{
|
||||
+ int timeout;
|
||||
+ u32 bus_stat;
|
||||
+ unsigned long flags;
|
||||
+ int ret;
|
||||
+
|
||||
+ for (timeout = 0; timeout < FALCON_I2C_READY_TIMEOUT; timeout++) {
|
||||
+ bus_stat = i2c_r32(bus_stat);
|
||||
+
|
||||
+ if (bus_stat & I2C_BUS_STAT_BS_SC) {
|
||||
+ cpu_relax();
|
||||
+ } else {
|
||||
+ spin_lock_irqsave(&priv->lock, flags);
|
||||
+
|
||||
+ if (FALCON_I2C_ERROR(priv)) {
|
||||
+ ret = priv->status;
|
||||
+
|
||||
+ dev_dbg(priv->dev, "bus ready wait error 0x%08lx\n", priv->status);
|
||||
+
|
||||
+ FALCON_I2C_ERROR_CLEAR(priv);
|
||||
+ } else {
|
||||
+ ret = 0;
|
||||
+ }
|
||||
+
|
||||
+ spin_unlock_irqrestore(&priv->lock, flags);
|
||||
+
|
||||
+ return ret;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ dev_dbg(priv->dev, "bus ready wait timeout\n");
|
||||
+
|
||||
+ return -ETIME;
|
||||
+}
|
||||
+
|
||||
+static int falcon_i2c_wait(struct falcon_i2c *priv, unsigned long status)
|
||||
+{
|
||||
+ int ret = 0;
|
||||
+ unsigned long flags;
|
||||
+ unsigned int timeout;
|
||||
+
|
||||
+ spin_lock_irqsave(&priv->lock, flags);
|
||||
+
|
||||
+ priv->status &= FALCON_I2C_BURST_REQ;
|
||||
+
|
||||
+ /* check if the event already occurred */
|
||||
+ if ((priv->status & status) == status) {
|
||||
+ priv->status &= ~status;
|
||||
+ spin_unlock_irqrestore(&priv->lock, flags);
|
||||
+
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ spin_unlock_irqrestore(&priv->lock, flags);
|
||||
+
|
||||
+ /* unmask burst interrupts */
|
||||
+ i2c_w32_mask(0, I2C_IMSC_LBREQ_INT_EN | I2C_IMSC_BREQ_INT_EN, imsc);
|
||||
+
|
||||
+ for (timeout = 0; timeout < FALCON_I2C_WAIT_TIMEOUT; timeout++) {
|
||||
+ /* wait for the data request */
|
||||
+ wait_for_completion_timeout(&priv->done, HZ / 10);
|
||||
+
|
||||
+ /* handle errors */
|
||||
+ spin_lock_irqsave(&priv->lock, flags);
|
||||
+
|
||||
+ if (FALCON_I2C_ERROR(priv)) {
|
||||
+ dev_dbg(priv->dev, "wait error 0x%08lx (waiting for 0x%08lx)\n",
|
||||
+ priv->status,
|
||||
+ status);
|
||||
+
|
||||
+ if (priv->status & FALCON_I2C_NACK)
|
||||
+ ret = -ENXIO;
|
||||
+ else
|
||||
+ ret = -EREMOTEIO;
|
||||
+
|
||||
+ FALCON_I2C_ERROR_CLEAR(priv);
|
||||
+ } else {
|
||||
+ if ((priv->status & status) == status) {
|
||||
+ priv->status &= ~status;
|
||||
+ spin_unlock_irqrestore(&priv->lock, flags);
|
||||
+
|
||||
+ return 0;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ spin_unlock_irqrestore(&priv->lock, flags);
|
||||
+
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ dev_dbg(priv->dev, "wait timeout error 0x%08lx (waiting for 0x%08lx)\n",
|
||||
+ priv->status,
|
||||
+ status);
|
||||
+
|
||||
+ return -ETIME;
|
||||
+}
|
||||
+
|
||||
+static int falcon_i2c_tx(struct falcon_i2c *priv, int ten_bit, u16 addr,
|
||||
+ u8 *buf, int len)
|
||||
+{
|
||||
+ int i;
|
||||
+ int ret;
|
||||
+
|
||||
+ dev_dbg(priv->dev, "%s\n", __func__);
|
||||
+
|
||||
+ /* tell fifo the number of bytes we are going to send */
|
||||
+ i2c_w32(len + (ten_bit ? 2 : 1), tps_ctrl);
|
||||
+
|
||||
+ /* wait for the data request */
|
||||
+ ret = falcon_i2c_wait(priv, FALCON_I2C_BURST_REQ);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* send slave address */
|
||||
+ if (ten_bit) {
|
||||
+ i2c_w32(0x78 | ((addr >> 7) & 0x7), txd);
|
||||
+ i2c_w32(0x78 | ((addr & 0x7f) << 1) | 0, txd);
|
||||
+ } else {
|
||||
+ i2c_w32((addr << 1) | 0, txd);
|
||||
+ }
|
||||
+
|
||||
+ /* fill fifo */
|
||||
+ for (i = 0; i < len; i++) {
|
||||
+ ret = falcon_i2c_wait(priv, FALCON_I2C_BURST_REQ);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ i2c_w32(buf[i], txd);
|
||||
+ }
|
||||
+
|
||||
+ return falcon_i2c_wait(priv, FALCON_I2C_TX_END);
|
||||
+}
|
||||
+
|
||||
+static int falcon_i2c_rx(struct falcon_i2c *priv, int ten_bit, u16 addr,
|
||||
+ u8 *buf, int len)
|
||||
+{
|
||||
+ int i;
|
||||
+ int ret;
|
||||
+
|
||||
+ dev_dbg(priv->dev, "%s\n", __func__);
|
||||
+
|
||||
+ /* we need to transmit address only */
|
||||
+ i2c_w32(ten_bit ? 2 : 1, tps_ctrl);
|
||||
+
|
||||
+ /* set maximum received packet size */
|
||||
+ i2c_w32(len, mrps_ctrl);
|
||||
+
|
||||
+ /* wait for the data request */
|
||||
+ ret = falcon_i2c_wait(priv, FALCON_I2C_BURST_REQ);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* write down the address */
|
||||
+ if (ten_bit) {
|
||||
+ i2c_w32(0x78 | ((addr >> 7) & 0x7), txd);
|
||||
+ i2c_w32(0x78 | ((addr & 0x7f) << 1) | 1, txd);
|
||||
+ } else {
|
||||
+ i2c_w32((addr << 1) | 1, txd);
|
||||
+ }
|
||||
+
|
||||
+ /* wait for the read request */
|
||||
+ ret = falcon_i2c_wait(priv, FALCON_I2C_TX_END
|
||||
+#ifndef FALCON_FIX_ME
|
||||
+ | FALCON_I2C_ADDR_MATCH
|
||||
+#endif
|
||||
+ | FALCON_I2C_RX);
|
||||
+
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* read bytes */
|
||||
+ for (i = 0; i < len; i++) {
|
||||
+#ifdef FALCON_FIX_ME
|
||||
+ while (i2c_r32(rps_stat) == 0)
|
||||
+ cpu_relax();
|
||||
+#else
|
||||
+ ret = falcon_i2c_wait(priv, FALCON_I2C_BURST_REQ);
|
||||
+
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+#endif
|
||||
+
|
||||
+ buf[i] = i2c_r32(rxd);
|
||||
+ }
|
||||
+
|
||||
+#ifndef FALCON_FIX_ME
|
||||
+ /* wait for transmission end */
|
||||
+ return falcon_i2c_wait(priv, FALCON_I2C_TX_END);
|
||||
+#else
|
||||
+ return 0;
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
+static int falcon_i2c_xfer_msg(struct falcon_i2c *priv, struct i2c_msg *msg)
|
||||
+{
|
||||
+ int ret;
|
||||
+ int ten_bit;
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ dev_dbg(priv->dev, "%s %u byte(s) %s 0x%02x\n",
|
||||
+ (msg->flags & I2C_M_RD) ? "read" : "write", msg->len,
|
||||
+ (msg->flags & I2C_M_RD) ? "from" : "to", msg->addr);
|
||||
+
|
||||
+ if (msg->flags & I2C_M_TEN)
|
||||
+ ten_bit = 1;
|
||||
+ else
|
||||
+ ten_bit = 0;
|
||||
+
|
||||
+ /* reconfigure bus if need to send message in different address mode */
|
||||
+ spin_lock_irqsave(&priv->lock, flags);
|
||||
+ if (ten_bit != priv->ten_bit) {
|
||||
+
|
||||
+ /* disable bus */
|
||||
+ i2c_w32_mask(I2C_RUN_CTRL_RUN_EN, 0, run_ctrl);
|
||||
+
|
||||
+ /* reconfigure address */
|
||||
+ falcon_addr_configure(priv, ten_bit);
|
||||
+
|
||||
+ /* enable bus */
|
||||
+ i2c_w32_mask(0, I2C_RUN_CTRL_RUN_EN, run_ctrl);
|
||||
+
|
||||
+ priv->ten_bit = ten_bit;
|
||||
+ }
|
||||
+ spin_unlock_irqrestore(&priv->lock, flags);
|
||||
+
|
||||
+ /* read/write actual message */
|
||||
+ if (msg->flags & I2C_M_RD)
|
||||
+ ret = falcon_i2c_rx(priv, ten_bit, msg->addr, msg->buf,
|
||||
+ msg->len);
|
||||
+ else
|
||||
+ ret = falcon_i2c_tx(priv, ten_bit, msg->addr, msg->buf,
|
||||
+ msg->len);
|
||||
+
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int falcon_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
|
||||
+ int num)
|
||||
+{
|
||||
+ int i;
|
||||
+ int ret;
|
||||
+ unsigned long flags;
|
||||
+ struct falcon_i2c *priv = i2c_get_adapdata(adap);
|
||||
+
|
||||
+ dev_dbg(priv->dev, "xfer %u messages\n", num);
|
||||
+
|
||||
+ /* transfer each message */
|
||||
+ for (i = 0; i < num; i++) {
|
||||
+#ifdef FALCON_FIX_ME
|
||||
+ /* disable bus */
|
||||
+ i2c_w32_mask(I2C_RUN_CTRL_RUN_EN, 0, run_ctrl);
|
||||
+ /* enable bus */
|
||||
+ i2c_w32_mask(0, I2C_RUN_CTRL_RUN_EN, run_ctrl);
|
||||
+#endif
|
||||
+
|
||||
+ /* clear bus status */
|
||||
+ spin_lock_irqsave(&priv->lock, flags);
|
||||
+ priv->status = 0;
|
||||
+ spin_unlock_irqrestore(&priv->lock, flags);
|
||||
+
|
||||
+ /* wait for the bus to become ready */
|
||||
+ ret = falcon_i2c_ready(priv);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* transfer message */
|
||||
+ ret = falcon_i2c_xfer_msg(priv, &msg[i]);
|
||||
+
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* check for unhandled errors */
|
||||
+ spin_lock_irqsave(&priv->lock, flags);
|
||||
+ if (FALCON_I2C_ERROR(priv))
|
||||
+ ret = priv->status;
|
||||
+ spin_unlock_irqrestore(&priv->lock, flags);
|
||||
+
|
||||
+ if (ret) {
|
||||
+ dev_warn(priv->dev, "message %u unhandled error 0x%x\n",
|
||||
+ i, ret);
|
||||
+
|
||||
+ return ret;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static u32 falcon_i2c_func(struct i2c_adapter *adap)
|
||||
+{
|
||||
+ return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SMBUS_EMUL;
|
||||
+}
|
||||
+
|
||||
+static struct i2c_algorithm falcon_i2c_algorithm = {
|
||||
+ .master_xfer = falcon_i2c_xfer,
|
||||
+ .functionality = falcon_i2c_func,
|
||||
+};
|
||||
+
|
||||
+static int falcon_i2c_hw_init(struct i2c_adapter *adap)
|
||||
+{
|
||||
+ struct falcon_i2c *priv = i2c_get_adapdata(adap);
|
||||
+
|
||||
+ /* disable bus */
|
||||
+ i2c_w32_mask(I2C_RUN_CTRL_RUN_EN, 0, run_ctrl);
|
||||
+
|
||||
+ /* set normal operation clock divider */
|
||||
+ i2c_w32(1 << I2C_CLC_RMC_OFFSET, clc);
|
||||
+
|
||||
+ /* set frequency */
|
||||
+ if (priv->mode == FALCON_I2C_MODE_100) {
|
||||
+ dev_dbg(priv->dev, "set standard mode (100 kHz)\n");
|
||||
+
|
||||
+ i2c_w32(0, fdiv_high_cfg);
|
||||
+
|
||||
+ i2c_w32((1 << I2C_FDIV_CFG_INC_OFFSET)
|
||||
+ | (499 << I2C_FDIV_CFG_DEC_OFFSET),
|
||||
+ fdiv_cfg);
|
||||
+ } else if (priv->mode == FALCON_I2C_MODE_400) {
|
||||
+ dev_dbg(priv->dev, "set fast mode (400 kHz)\n");
|
||||
+
|
||||
+ i2c_w32(0, fdiv_high_cfg);
|
||||
+
|
||||
+ i2c_w32((1 << I2C_FDIV_CFG_INC_OFFSET)
|
||||
+ | (124 << I2C_FDIV_CFG_DEC_OFFSET),
|
||||
+ fdiv_cfg);
|
||||
+ } else if (priv->mode == FALCON_I2C_MODE_3400) {
|
||||
+ dev_dbg(priv->dev, "set high mode (3.4 MHz)\n");
|
||||
+
|
||||
+ i2c_w32(0, fdiv_cfg);
|
||||
+
|
||||
+ /* TODO recalculate value for 100MHz input */
|
||||
+ i2c_w32((41 << I2C_FDIV_CFG_INC_OFFSET)
|
||||
+ | (152 << I2C_FDIV_CFG_DEC_OFFSET),
|
||||
+ fdiv_high_cfg);
|
||||
+ } else {
|
||||
+ dev_warn(priv->dev, "unknown mode\n");
|
||||
+
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ /* configure fifo */
|
||||
+ i2c_w32(I2C_FIFO_CFG_TXFC /* tx fifo as flow controller */
|
||||
+ | I2C_FIFO_CFG_RXFC /* rx fifo as flow controller */
|
||||
+ | I2C_FIFO_CFG_TXFA_TXFA2 /* tx fifo 4-byte aligned */
|
||||
+ | I2C_FIFO_CFG_RXFA_RXFA2 /* rx fifo 4-byte aligned */
|
||||
+ | I2C_FIFO_CFG_TXBS_TXBS0 /* tx fifo burst size is 1 word */
|
||||
+ | I2C_FIFO_CFG_RXBS_RXBS0, /* rx fifo burst size is 1 word */
|
||||
+ fifo_cfg);
|
||||
+
|
||||
+ /* configure address */
|
||||
+ falcon_addr_configure(priv, priv->ten_bit);
|
||||
+
|
||||
+ /* enable bus */
|
||||
+ i2c_w32_mask(0, I2C_RUN_CTRL_RUN_EN, run_ctrl);
|
||||
+
|
||||
+ /* mask burst interrupts */
|
||||
+ i2c_w32_mask(I2C_IMSC_LBREQ_INT_EN | I2C_IMSC_BREQ_INT_EN, 0, imsc);
|
||||
+
|
||||
+ /* enable interrupts */
|
||||
+ i2c_w32(I2C_IMSC_LBREQ_INT_EN
|
||||
+ | I2C_IMSC_BREQ_INT_EN
|
||||
+ | I2C_IMSC_I2C_P_INT_EN
|
||||
+ | I2C_IMSC_I2C_ERR_INT_EN,
|
||||
+ imsc);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int __devinit falcon_i2c_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ int ret = 0;
|
||||
+ struct falcon_i2c *priv;
|
||||
+ struct i2c_adapter *adap;
|
||||
+ struct resource *mmres, *ioarea,
|
||||
+ *irqres_lb, *irqres_b, *irqres_err, *irqres_p;
|
||||
+ struct clk *clk;
|
||||
+
|
||||
+ dev_dbg(&pdev->dev, "probing\n");
|
||||
+
|
||||
+ mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
+ irqres_lb = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
|
||||
+ "i2c_lb");
|
||||
+ irqres_b = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "i2c_b");
|
||||
+ irqres_err = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
|
||||
+ "i2c_err");
|
||||
+ irqres_p = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "i2c_p");
|
||||
+
|
||||
+ if (!mmres || !irqres_lb || !irqres_b || !irqres_err || !irqres_p) {
|
||||
+ dev_err(&pdev->dev, "no resources\n");
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ clk = clk_get(&pdev->dev, "fpi");
|
||||
+ if (IS_ERR(clk)) {
|
||||
+ dev_err(&pdev->dev, "failed to get fpi clk\n");
|
||||
+ return -ENOENT;
|
||||
+ }
|
||||
+
|
||||
+ if (clk_get_rate(clk) != 100000000) {
|
||||
+ dev_err(&pdev->dev, "input clock is not 100MHz\n");
|
||||
+ return -ENOENT;
|
||||
+ }
|
||||
+
|
||||
+ /* allocate private data */
|
||||
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
||||
+ if (!priv) {
|
||||
+ dev_err(&pdev->dev, "can't allocate private data\n");
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
+ adap = &priv->adap;
|
||||
+ i2c_set_adapdata(adap, priv);
|
||||
+ adap->owner = THIS_MODULE;
|
||||
+ adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
|
||||
+ strlcpy(adap->name, DRV_NAME "-adapter", sizeof(adap->name));
|
||||
+ adap->algo = &falcon_i2c_algorithm;
|
||||
+
|
||||
+ priv->ten_bit = 0;
|
||||
+ priv->mode = FALCON_I2C_MODE_100;
|
||||
+ priv->clk = clk;
|
||||
+ priv->dev = &pdev->dev;
|
||||
+
|
||||
+ spin_lock_init(&priv->lock);
|
||||
+
|
||||
+ ioarea = request_mem_region(mmres->start, resource_size(mmres),
|
||||
+ pdev->name);
|
||||
+
|
||||
+ if (ioarea == NULL) {
|
||||
+ dev_err(&pdev->dev, "I2C region already claimed\n");
|
||||
+ ret = -ENXIO;
|
||||
+ goto err_free_priv;
|
||||
+ }
|
||||
+
|
||||
+ /* map memory */
|
||||
+ priv->membase = ioremap_nocache(mmres->start & ~KSEG1,
|
||||
+ resource_size(mmres));
|
||||
+ if (priv->membase == NULL) {
|
||||
+ ret = -ENOMEM;
|
||||
+ goto err_release_region;
|
||||
+ }
|
||||
+
|
||||
+ priv->irq_lb = irqres_lb->start;
|
||||
+ ret = request_irq(priv->irq_lb, falcon_i2c_isr, IRQF_DISABLED,
|
||||
+ irqres_lb->name, priv);
|
||||
+ if (ret) {
|
||||
+ dev_err(&pdev->dev, "can't get last burst IRQ %d\n", irqres_lb->start);
|
||||
+ ret = -ENODEV;
|
||||
+ goto err_unmap_mem;
|
||||
+ }
|
||||
+
|
||||
+ priv->irq_b = irqres_b->start;
|
||||
+ ret = request_irq(priv->irq_b, falcon_i2c_isr, IRQF_DISABLED,
|
||||
+ irqres_b->name, priv);
|
||||
+ if (ret) {
|
||||
+ dev_err(&pdev->dev, "can't get burst IRQ %d\n", irqres_b->start);
|
||||
+ ret = -ENODEV;
|
||||
+ goto err_free_lb_irq;
|
||||
+ }
|
||||
+
|
||||
+ priv->irq_err = irqres_err->start;
|
||||
+ ret = request_irq(priv->irq_err, falcon_i2c_isr, IRQF_DISABLED,
|
||||
+ irqres_err->name, priv);
|
||||
+ if (ret) {
|
||||
+ dev_err(&pdev->dev, "can't get error IRQ %d\n", irqres_err->start);
|
||||
+ ret = -ENODEV;
|
||||
+ goto err_free_b_irq;
|
||||
+ }
|
||||
+
|
||||
+ priv->irq_p = irqres_p->start;
|
||||
+ ret = request_irq(priv->irq_p, falcon_i2c_isr, IRQF_DISABLED,
|
||||
+ irqres_p->name, priv);
|
||||
+ if (ret) {
|
||||
+ dev_err(&pdev->dev, "can't get protocol IRQ %d\n", irqres_p->start);
|
||||
+ ret = -ENODEV;
|
||||
+ goto err_free_err_irq;
|
||||
+ }
|
||||
+
|
||||
+ dev_dbg(&pdev->dev, "mapped io-space to %p\n", priv->membase);
|
||||
+ dev_dbg(&pdev->dev, "use IRQs %d, %d, %d, %d\n", irqres_lb->start,
|
||||
+ irqres_b->start, irqres_err->start, irqres_p->start);
|
||||
+
|
||||
+ /* add our adapter to the i2c stack */
|
||||
+ ret = i2c_add_numbered_adapter(adap);
|
||||
+ if (ret) {
|
||||
+ dev_err(&pdev->dev, "can't register I2C adapter\n");
|
||||
+ goto err_free_p_irq;
|
||||
+ }
|
||||
+
|
||||
+ platform_set_drvdata(pdev, priv);
|
||||
+ i2c_set_adapdata(adap, priv);
|
||||
+
|
||||
+ /* print module version information */
|
||||
+ dev_dbg(&pdev->dev, "module id=%u revision=%u\n",
|
||||
+ (i2c_r32(id) & I2C_ID_ID_MASK) >> I2C_ID_ID_OFFSET,
|
||||
+ (i2c_r32(id) & I2C_ID_REV_MASK) >> I2C_ID_REV_OFFSET);
|
||||
+
|
||||
+ init_completion(&priv->done);
|
||||
+
|
||||
+ /* initialize HW */
|
||||
+ ret = falcon_i2c_hw_init(adap);
|
||||
+ if (ret) {
|
||||
+ dev_err(&pdev->dev, "can't configure adapter\n");
|
||||
+ goto err_remove_adapter;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+err_remove_adapter:
|
||||
+ i2c_del_adapter(adap);
|
||||
+ platform_set_drvdata(pdev, NULL);
|
||||
+
|
||||
+err_free_p_irq:
|
||||
+ free_irq(priv->irq_p, priv);
|
||||
+
|
||||
+err_free_err_irq:
|
||||
+ free_irq(priv->irq_err, priv);
|
||||
+
|
||||
+err_free_b_irq:
|
||||
+ free_irq(priv->irq_b, priv);
|
||||
+
|
||||
+err_free_lb_irq:
|
||||
+ free_irq(priv->irq_lb, priv);
|
||||
+
|
||||
+err_unmap_mem:
|
||||
+ iounmap(priv->membase);
|
||||
+
|
||||
+err_release_region:
|
||||
+ release_mem_region(mmres->start, resource_size(mmres));
|
||||
+
|
||||
+err_free_priv:
|
||||
+ kfree(priv);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int __devexit falcon_i2c_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct falcon_i2c *priv = platform_get_drvdata(pdev);
|
||||
+ struct resource *mmres;
|
||||
+
|
||||
+ /* disable bus */
|
||||
+ i2c_w32_mask(I2C_RUN_CTRL_RUN_EN, 0, run_ctrl);
|
||||
+
|
||||
+ /* remove driver */
|
||||
+ platform_set_drvdata(pdev, NULL);
|
||||
+ i2c_del_adapter(&priv->adap);
|
||||
+
|
||||
+ free_irq(priv->irq_lb, priv);
|
||||
+ free_irq(priv->irq_b, priv);
|
||||
+ free_irq(priv->irq_err, priv);
|
||||
+ free_irq(priv->irq_p, priv);
|
||||
+
|
||||
+ kfree(priv);
|
||||
+
|
||||
+ mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
+ release_mem_region(mmres->start, resource_size(mmres));
|
||||
+
|
||||
+ dev_dbg(&pdev->dev, "removed\n");
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static struct platform_driver falcon_i2c_driver = {
|
||||
+ .probe = falcon_i2c_probe,
|
||||
+ .remove = __devexit_p(falcon_i2c_remove),
|
||||
+ .driver = {
|
||||
+ .name = DRV_NAME,
|
||||
+ .owner = THIS_MODULE,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static int __init falcon_i2c_init(void)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = platform_driver_register(&falcon_i2c_driver);
|
||||
+
|
||||
+ if (ret)
|
||||
+ printk(KERN_DEBUG DRV_NAME ": can't register platform driver");
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static void __exit falcon_i2c_exit(void)
|
||||
+{
|
||||
+ platform_driver_unregister(&falcon_i2c_driver);
|
||||
+}
|
||||
+
|
||||
+module_init(falcon_i2c_init);
|
||||
+module_exit(falcon_i2c_exit);
|
||||
+
|
||||
+MODULE_DESCRIPTION("Lantiq FALC(tm) ON - I2C bus adapter");
|
||||
+MODULE_ALIAS("platform:i2c_falcon");
|
||||
+MODULE_LICENSE("GPL");
|
@ -0,0 +1,497 @@ |
||||
--- a/drivers/spi/Makefile
|
||||
+++ b/drivers/spi/Makefile
|
||||
@@ -22,6 +22,7 @@ obj-$(CONFIG_SPI_DESIGNWARE) += dw_spi.
|
||||
obj-$(CONFIG_SPI_DW_PCI) += dw_spi_pci.o
|
||||
obj-$(CONFIG_SPI_DW_MMIO) += dw_spi_mmio.o
|
||||
obj-$(CONFIG_SPI_EP93XX) += ep93xx_spi.o
|
||||
+obj-$(CONFIG_SPI_FALCON) += spi_falcon.o
|
||||
obj-$(CONFIG_SPI_GPIO) += spi_gpio.o
|
||||
obj-$(CONFIG_SPI_GPIO_OLD) += spi_gpio_old.o
|
||||
obj-$(CONFIG_SPI_IMX) += spi_imx.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/spi/spi_falcon.c
|
||||
@@ -0,0 +1,471 @@
|
||||
+/*
|
||||
+ * 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.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/device.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/spi/spi.h>
|
||||
+#include <linux/delay.h>
|
||||
+#include <linux/workqueue.h>
|
||||
+
|
||||
+#include <lantiq.h> /* ebu_lock */
|
||||
+#include <falcon/ebu_reg.h>
|
||||
+#include <falcon/sys1_reg.h>
|
||||
+
|
||||
+#define DRV_NAME "falcon_spi"
|
||||
+
|
||||
+#define FALCON_SPI_XFER_BEGIN (1 << 0)
|
||||
+#define FALCON_SPI_XFER_END (1 << 1)
|
||||
+
|
||||
+/* mapping for access macros */
|
||||
+#define reg_r32(reg) __raw_readl(reg)
|
||||
+#define reg_w32(val, reg) __raw_writel(val, reg)
|
||||
+#define reg_w32_mask(clear, set, reg) reg_w32((reg_r32(reg) \
|
||||
+ & ~(clear)) | (set), reg)
|
||||
+#define reg_r32_table(reg, idx) reg_r32(&((uint32_t *)®)[idx])
|
||||
+#define reg_w32_table(val, reg, idx) reg_w32(val, &((uint32_t *)®)[idx])
|
||||
+
|
||||
+#define ebu (priv->ebu_membase)
|
||||
+#define sys1 (priv->sys1_membase)
|
||||
+
|
||||
+struct falcon_spi {
|
||||
+ u32 sfcmd; /* for caching of opcode, direction, ... */
|
||||
+
|
||||
+ struct spi_master *master;
|
||||
+
|
||||
+ struct gpon_reg_ebu __iomem *ebu_membase;
|
||||
+ struct gpon_reg_sys1 __iomem *sys1_membase;
|
||||
+};
|
||||
+
|
||||
+int falcon_spi_xfer(struct spi_device *spi,
|
||||
+ struct spi_transfer *t,
|
||||
+ unsigned long flags)
|
||||
+{
|
||||
+ struct device *dev = &spi->dev;
|
||||
+ struct falcon_spi *priv = spi_master_get_devdata(spi->master);
|
||||
+ const u8 *txp = t->tx_buf;
|
||||
+ u8 *rxp = t->rx_buf;
|
||||
+ unsigned int bytelen = ((8 * t->len + 7) / 8);
|
||||
+ unsigned int len, alen, dumlen;
|
||||
+ u32 val;
|
||||
+ enum {
|
||||
+ state_init,
|
||||
+ state_command_prepare,
|
||||
+ state_write,
|
||||
+ state_read,
|
||||
+ state_disable_cs,
|
||||
+ state_end
|
||||
+ } state = state_init;
|
||||
+
|
||||
+ do {
|
||||
+ switch (state) {
|
||||
+ case state_init: /* detect phase of upper layer sequence */
|
||||
+ {
|
||||
+ /* initial write ? */
|
||||
+ if (flags & FALCON_SPI_XFER_BEGIN) {
|
||||
+ if (!txp) {
|
||||
+ dev_err(dev,
|
||||
+ "BEGIN without tx data!\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+ /*
|
||||
+ * Prepare the parts of the sfcmd register,
|
||||
+ * which should not
|
||||
+ * change during a sequence!
|
||||
+ * Only exception are the length fields,
|
||||
+ * especially alen and dumlen.
|
||||
+ */
|
||||
+
|
||||
+ priv->sfcmd = ((spi->chip_select
|
||||
+ << SFCMD_CS_OFFSET)
|
||||
+ & SFCMD_CS_MASK);
|
||||
+ priv->sfcmd |= SFCMD_KEEP_CS_KEEP_SELECTED;
|
||||
+ priv->sfcmd |= *txp;
|
||||
+ txp++;
|
||||
+ bytelen--;
|
||||
+ if (bytelen) {
|
||||
+ /* more data:
|
||||
+ * maybe address and/or dummy */
|
||||
+ state = state_command_prepare;
|
||||
+ break;
|
||||
+ } else {
|
||||
+ dev_dbg(dev, "write cmd %02X\n",
|
||||
+ priv->sfcmd & SFCMD_OPC_MASK);
|
||||
+ }
|
||||
+ }
|
||||
+ /* continued write ? */
|
||||
+ if (txp && bytelen) {
|
||||
+ state = state_write;
|
||||
+ break;
|
||||
+ }
|
||||
+ /* read data? */
|
||||
+ if (rxp && bytelen) {
|
||||
+ state = state_read;
|
||||
+ break;
|
||||
+ }
|
||||
+ /* end of sequence? */
|
||||
+ if (flags & FALCON_SPI_XFER_END)
|
||||
+ state = state_disable_cs;
|
||||
+ else
|
||||
+ state = state_end;
|
||||
+ break;
|
||||
+ }
|
||||
+ case state_command_prepare: /* collect tx data for
|
||||
+ address and dummy phase */
|
||||
+ {
|
||||
+ /* txp is valid, already checked */
|
||||
+ val = 0;
|
||||
+ alen = 0;
|
||||
+ dumlen = 0;
|
||||
+ while (bytelen > 0) {
|
||||
+ if (alen < 3) {
|
||||
+ val = (val<<8)|(*txp++);
|
||||
+ alen++;
|
||||
+ } else if ((dumlen < 15) && (*txp == 0)) {
|
||||
+ /*
|
||||
+ * assume dummy bytes are set to 0
|
||||
+ * from upper layer
|
||||
+ */
|
||||
+ dumlen++;
|
||||
+ txp++;
|
||||
+ } else
|
||||
+ break;
|
||||
+ bytelen--;
|
||||
+ }
|
||||
+ priv->sfcmd &= ~(SFCMD_ALEN_MASK | SFCMD_DUMLEN_MASK);
|
||||
+ priv->sfcmd |= (alen << SFCMD_ALEN_OFFSET) |
|
||||
+ (dumlen << SFCMD_DUMLEN_OFFSET);
|
||||
+ if (alen > 0)
|
||||
+ ebu_w32(val, sfaddr);
|
||||
+
|
||||
+ dev_dbg(dev, "write cmd %02X, alen=%d "
|
||||
+ "(addr=%06X) dumlen=%d\n",
|
||||
+ priv->sfcmd & SFCMD_OPC_MASK,
|
||||
+ alen, val, dumlen);
|
||||
+
|
||||
+ if (bytelen > 0) {
|
||||
+ /* continue with write */
|
||||
+ state = state_write;
|
||||
+ } else if (flags & FALCON_SPI_XFER_END) {
|
||||
+ /* end of sequence? */
|
||||
+ state = state_disable_cs;
|
||||
+ } else {
|
||||
+ /* go to end and expect another
|
||||
+ * call (read or write) */
|
||||
+ state = state_end;
|
||||
+ }
|
||||
+ break;
|
||||
+ }
|
||||
+ case state_write:
|
||||
+ {
|
||||
+ /* txp still valid */
|
||||
+ priv->sfcmd |= SFCMD_DIR_WRITE;
|
||||
+ len = 0;
|
||||
+ val = 0;
|
||||
+ do {
|
||||
+ if (bytelen--)
|
||||
+ val |= (*txp++) << (8 * len++);
|
||||
+ if ((flags & FALCON_SPI_XFER_END)
|
||||
+ && (bytelen == 0)) {
|
||||
+ priv->sfcmd &=
|
||||
+ ~SFCMD_KEEP_CS_KEEP_SELECTED;
|
||||
+ }
|
||||
+ if ((len == 4) || (bytelen == 0)) {
|
||||
+ ebu_w32(val, sfdata);
|
||||
+ ebu_w32(priv->sfcmd
|
||||
+ | (len<<SFCMD_DLEN_OFFSET),
|
||||
+ sfcmd);
|
||||
+ len = 0;
|
||||
+ val = 0;
|
||||
+ priv->sfcmd &= ~(SFCMD_ALEN_MASK
|
||||
+ | SFCMD_DUMLEN_MASK);
|
||||
+ }
|
||||
+ } while (bytelen);
|
||||
+ state = state_end;
|
||||
+ break;
|
||||
+ }
|
||||
+ case state_read:
|
||||
+ {
|
||||
+ /* read data */
|
||||
+ priv->sfcmd &= ~SFCMD_DIR_WRITE;
|
||||
+ do {
|
||||
+ if ((flags & FALCON_SPI_XFER_END)
|
||||
+ && (bytelen <= 4)) {
|
||||
+ priv->sfcmd &=
|
||||
+ ~SFCMD_KEEP_CS_KEEP_SELECTED;
|
||||
+ }
|
||||
+ len = (bytelen > 4) ? 4 : bytelen;
|
||||
+ bytelen -= len;
|
||||
+ ebu_w32(priv->sfcmd
|
||||
+ |(len<<SFCMD_DLEN_OFFSET), sfcmd);
|
||||
+ priv->sfcmd &= ~(SFCMD_ALEN_MASK
|
||||
+ | SFCMD_DUMLEN_MASK);
|
||||
+ do {
|
||||
+ val = ebu_r32(sfstat);
|
||||
+ if (val & SFSTAT_CMD_ERR) {
|
||||
+ /* reset error status */
|
||||
+ dev_err(dev, "SFSTAT: CMD_ERR "
|
||||
+ "(%x)\n", val);
|
||||
+ ebu_w32(SFSTAT_CMD_ERR, sfstat);
|
||||
+ return -1;
|
||||
+ }
|
||||
+ } while (val & SFSTAT_CMD_PEND);
|
||||
+ val = ebu_r32(sfdata);
|
||||
+ do {
|
||||
+ *rxp = (val & 0xFF);
|
||||
+ rxp++;
|
||||
+ val >>= 8;
|
||||
+ len--;
|
||||
+ } while (len);
|
||||
+ } while (bytelen);
|
||||
+ state = state_end;
|
||||
+ break;
|
||||
+ }
|
||||
+ case state_disable_cs:
|
||||
+ {
|
||||
+ priv->sfcmd &= ~SFCMD_KEEP_CS_KEEP_SELECTED;
|
||||
+ ebu_w32(priv->sfcmd | (0<<SFCMD_DLEN_OFFSET), sfcmd);
|
||||
+ val = ebu_r32(sfstat);
|
||||
+ if (val & SFSTAT_CMD_ERR) {
|
||||
+ /* reset error status */
|
||||
+ dev_err(dev, "SFSTAT: CMD_ERR (%x)\n", val);
|
||||
+ ebu_w32(SFSTAT_CMD_ERR, sfstat);
|
||||
+ return -1;
|
||||
+ }
|
||||
+ state = state_end;
|
||||
+ break;
|
||||
+ }
|
||||
+ case state_end:
|
||||
+ break;
|
||||
+ }
|
||||
+ } while (state != state_end);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int falcon_spi_setup(struct spi_device *spi)
|
||||
+{
|
||||
+ struct device *dev = &spi->dev;
|
||||
+ struct falcon_spi *priv = spi_master_get_devdata(spi->master);
|
||||
+ const u32 ebuclk = 100*1000*1000;
|
||||
+ unsigned int i;
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ dev_dbg(dev, "setup\n");
|
||||
+
|
||||
+ if (spi->master->bus_num > 0 || spi->chip_select > 0)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ spin_lock_irqsave(&ebu_lock, flags);
|
||||
+
|
||||
+ if (ebuclk < spi->max_speed_hz) {
|
||||
+ /* set EBU clock to 100 MHz */
|
||||
+ sys1_w32_mask(0, EBUCC_EBUDIV_SELF100, ebucc);
|
||||
+ i = 1; /* divider */
|
||||
+ } else {
|
||||
+ /* set EBU clock to 50 MHz */
|
||||
+ sys1_w32_mask(EBUCC_EBUDIV_SELF100, 0, ebucc);
|
||||
+
|
||||
+ /* search for suitable divider */
|
||||
+ for (i = 1; i < 7; i++) {
|
||||
+ if (ebuclk / i <= spi->max_speed_hz)
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* setup period of serial clock */
|
||||
+ ebu_w32_mask(SFTIME_SCKF_POS_MASK
|
||||
+ | SFTIME_SCKR_POS_MASK
|
||||
+ | SFTIME_SCK_PER_MASK,
|
||||
+ (i << SFTIME_SCKR_POS_OFFSET)
|
||||
+ | (i << (SFTIME_SCK_PER_OFFSET + 1)),
|
||||
+ sftime);
|
||||
+
|
||||
+ /* set some bits of unused_wd, to not trigger HOLD/WP
|
||||
+ * signals on non QUAD flashes */
|
||||
+ ebu_w32((SFIO_UNUSED_WD_MASK & (0x8|0x4)), sfio);
|
||||
+
|
||||
+ ebu_w32(BUSRCON0_AGEN_SERIAL_FLASH | BUSRCON0_PORTW_8_BIT_MUX,
|
||||
+ busrcon0);
|
||||
+ ebu_w32(BUSWCON0_AGEN_SERIAL_FLASH, buswcon0);
|
||||
+ /* set address wrap around to maximum for 24-bit addresses */
|
||||
+ ebu_w32_mask(SFCON_DEV_SIZE_MASK, SFCON_DEV_SIZE_A23_0, sfcon);
|
||||
+
|
||||
+ spin_unlock_irqrestore(&ebu_lock, flags);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int falcon_spi_transfer(struct spi_device *spi, struct spi_message *m)
|
||||
+{
|
||||
+ struct falcon_spi *priv = spi_master_get_devdata(spi->master);
|
||||
+ struct spi_transfer *t;
|
||||
+ unsigned long spi_flags;
|
||||
+ unsigned long flags;
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ priv->sfcmd = 0;
|
||||
+ m->actual_length = 0;
|
||||
+
|
||||
+ spi_flags = FALCON_SPI_XFER_BEGIN;
|
||||
+ list_for_each_entry(t, &m->transfers, transfer_list) {
|
||||
+ if (list_is_last(&t->transfer_list, &m->transfers))
|
||||
+ spi_flags |= FALCON_SPI_XFER_END;
|
||||
+
|
||||
+ spin_lock_irqsave(&ebu_lock, flags);
|
||||
+ ret = falcon_spi_xfer(spi, t, spi_flags);
|
||||
+ spin_unlock_irqrestore(&ebu_lock, flags);
|
||||
+
|
||||
+ if (ret)
|
||||
+ break;
|
||||
+
|
||||
+ m->actual_length += t->len;
|
||||
+
|
||||
+ if (t->delay_usecs || t->cs_change)
|
||||
+ BUG();
|
||||
+
|
||||
+ spi_flags = 0;
|
||||
+ }
|
||||
+
|
||||
+ m->status = ret;
|
||||
+ m->complete(m->context);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void falcon_spi_cleanup(struct spi_device *spi)
|
||||
+{
|
||||
+ struct device *dev = &spi->dev;
|
||||
+
|
||||
+ dev_dbg(dev, "cleanup\n");
|
||||
+}
|
||||
+
|
||||
+static int __devinit falcon_spi_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ struct falcon_spi *priv;
|
||||
+ struct spi_master *master;
|
||||
+ struct resource *memres_ebu, *memres_sys1;
|
||||
+ int ret;
|
||||
+
|
||||
+ dev_dbg(dev, "probing\n");
|
||||
+
|
||||
+ memres_ebu = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ebu");
|
||||
+ memres_sys1 = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
||||
+ "sys1");
|
||||
+
|
||||
+ if (!memres_ebu || !memres_sys1) {
|
||||
+ dev_err(dev, "no resources\n");
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ master = spi_alloc_master(&pdev->dev, sizeof(*priv));
|
||||
+ if (!master) {
|
||||
+ dev_err(dev, "no memory for spi_master\n");
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
+ priv = spi_master_get_devdata(master);
|
||||
+
|
||||
+ priv->ebu_membase = ioremap_nocache(memres_ebu->start & ~KSEG1,
|
||||
+ resource_size(memres_ebu));
|
||||
+
|
||||
+ if (!priv->ebu_membase) {
|
||||
+ dev_err(dev, "can't map ebu memory\n");
|
||||
+
|
||||
+ ret = -ENOMEM;
|
||||
+ goto free_master;
|
||||
+ }
|
||||
+
|
||||
+ priv->sys1_membase = ioremap_nocache(memres_sys1->start & ~KSEG1,
|
||||
+ resource_size(memres_sys1));
|
||||
+
|
||||
+ if (!priv->sys1_membase) {
|
||||
+ dev_err(dev, "can't map sys1 memory\n");
|
||||
+
|
||||
+ ret = -ENOMEM;
|
||||
+ goto unmap_ebu;
|
||||
+ }
|
||||
+
|
||||
+ priv->master = master;
|
||||
+
|
||||
+ master->mode_bits = SPI_MODE_3;
|
||||
+ master->num_chipselect = 1;
|
||||
+ master->bus_num = 0;
|
||||
+
|
||||
+ master->setup = falcon_spi_setup;
|
||||
+ master->transfer = falcon_spi_transfer;
|
||||
+ master->cleanup = falcon_spi_cleanup;
|
||||
+
|
||||
+ platform_set_drvdata(pdev, priv);
|
||||
+
|
||||
+ ret = spi_register_master(master);
|
||||
+ if (ret)
|
||||
+ goto unmap_sys1;
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+unmap_sys1:
|
||||
+ iounmap(priv->sys1_membase);
|
||||
+
|
||||
+unmap_ebu:
|
||||
+ iounmap(priv->ebu_membase);
|
||||
+
|
||||
+free_master:
|
||||
+ spi_master_put(master);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int __devexit falcon_spi_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ struct falcon_spi *priv = platform_get_drvdata(pdev);
|
||||
+
|
||||
+ dev_dbg(dev, "removed\n");
|
||||
+
|
||||
+ spi_unregister_master(priv->master);
|
||||
+
|
||||
+ iounmap(priv->sys1_membase);
|
||||
+ iounmap(priv->ebu_membase);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static struct platform_driver falcon_spi_driver = {
|
||||
+ .probe = falcon_spi_probe,
|
||||
+ .remove = __devexit_p(falcon_spi_remove),
|
||||
+ .driver = {
|
||||
+ .name = DRV_NAME,
|
||||
+ .owner = THIS_MODULE
|
||||
+ }
|
||||
+};
|
||||
+
|
||||
+static int __init falcon_spi_init(void)
|
||||
+{
|
||||
+ return platform_driver_register(&falcon_spi_driver);
|
||||
+}
|
||||
+
|
||||
+static void __exit falcon_spi_exit(void)
|
||||
+{
|
||||
+ platform_driver_unregister(&falcon_spi_driver);
|
||||
+}
|
||||
+
|
||||
+module_init(falcon_spi_init);
|
||||
+module_exit(falcon_spi_exit);
|
||||
+
|
||||
+MODULE_LICENSE("GPL");
|
||||
+MODULE_DESCRIPTION("Lantiq Falcon SPI controller driver");
|
||||
--- a/drivers/spi/Kconfig
|
||||
+++ b/drivers/spi/Kconfig
|
||||
@@ -169,6 +169,10 @@ config SPI_LM70_LLP
|
||||
which interfaces to an LM70 temperature sensor using
|
||||
a parallel port.
|
||||
|
||||
+config SPI_FALCON
|
||||
+ tristate "Falcon SPI controller support"
|
||||
+ depends on SOC_LANTIQ_FALCON
|
||||
+
|
||||
config SPI_MPC52xx
|
||||
tristate "Freescale MPC52xx SPI (non-PSC) controller support"
|
||||
depends on PPC_MPC52xx && SPI
|
@ -0,0 +1,10 @@ |
||||
--- a/drivers/mtd/devices/m25p80.c
|
||||
+++ b/drivers/mtd/devices/m25p80.c
|
||||
@@ -206,6 +206,7 @@ static void m25p_addr2cmd(struct m25p *f
|
||||
cmd[1] = addr >> (flash->addr_width * 8 - 8);
|
||||
cmd[2] = addr >> (flash->addr_width * 8 - 16);
|
||||
cmd[3] = addr >> (flash->addr_width * 8 - 24);
|
||||
+ cmd[4] = 0;
|
||||
}
|
||||
|
||||
static int m25p_cmdsz(struct m25p *flash)
|
@ -0,0 +1,193 @@ |
||||
--- a/arch/mips/lantiq/falcon/Makefile
|
||||
+++ b/arch/mips/lantiq/falcon/Makefile
|
||||
@@ -1,3 +1,4 @@
|
||||
obj-y := clk-falcon.o devices.o gpio.o prom.o sysctrl.o reset.o
|
||||
obj-y += softdog_vpe.o
|
||||
obj-$(CONFIG_LANTIQ_MACH_EASY98000) += mach-easy98000.o
|
||||
+obj-$(CONFIG_LANTIQ_MACH_EASY98000) += dev-leds-easy98000-cpld.o
|
||||
--- /dev/null
|
||||
+++ b/arch/mips/lantiq/falcon/dev-leds-easy98000-cpld.c
|
||||
@@ -0,0 +1,160 @@
|
||||
+/*
|
||||
+ * EASY98000 CPLD LED driver
|
||||
+ *
|
||||
+ * Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com>
|
||||
+ *
|
||||
+ * 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.
|
||||
+ *
|
||||
+ */
|
||||
+
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/version.h>
|
||||
+#include <linux/types.h>
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/errno.h>
|
||||
+#include <linux/leds.h>
|
||||
+#include <linux/slab.h>
|
||||
+
|
||||
+#include "dev-leds-easy98000-cpld.h"
|
||||
+
|
||||
+const char *led_name[8] = {
|
||||
+ "ge0_act",
|
||||
+ "ge0_link",
|
||||
+ "ge1_act",
|
||||
+ "ge1_link",
|
||||
+ "fe2_act",
|
||||
+ "fe2_link",
|
||||
+ "fe3_act",
|
||||
+ "fe3_link"
|
||||
+};
|
||||
+
|
||||
+#define cpld_base7 ((u16 *)(KSEG1 | 0x17c0000c))
|
||||
+#define cpld_base8 ((u16 *)(KSEG1 | 0x17c00012))
|
||||
+
|
||||
+#define lq_r16(reg) __raw_readw(reg)
|
||||
+#define lq_w16(val, reg) __raw_writew(val, reg)
|
||||
+
|
||||
+struct cpld_led_dev {
|
||||
+ struct led_classdev cdev;
|
||||
+ u8 mask;
|
||||
+ u16 *base;
|
||||
+};
|
||||
+
|
||||
+struct cpld_led_drvdata {
|
||||
+ struct cpld_led_dev *led_devs;
|
||||
+ int num_leds;
|
||||
+};
|
||||
+
|
||||
+void led_set(u8 mask, u16 *base)
|
||||
+{
|
||||
+ lq_w16(lq_r16(base) | mask, base);
|
||||
+}
|
||||
+
|
||||
+void led_clear(u8 mask, u16 *base)
|
||||
+{
|
||||
+ lq_w16(lq_r16(base) & (~mask), base);
|
||||
+}
|
||||
+
|
||||
+void led_blink_clear(u8 mask, u16 *base)
|
||||
+{
|
||||
+ led_clear(mask, base);
|
||||
+}
|
||||
+
|
||||
+static void led_brightness(struct led_classdev *led_cdev,
|
||||
+ enum led_brightness value)
|
||||
+{
|
||||
+ struct cpld_led_dev *led_dev =
|
||||
+ container_of(led_cdev, struct cpld_led_dev, cdev);
|
||||
+
|
||||
+ if (value)
|
||||
+ led_set(led_dev->mask, led_dev->base);
|
||||
+ else
|
||||
+ led_clear(led_dev->mask, led_dev->base);
|
||||
+}
|
||||
+
|
||||
+static int led_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ int i;
|
||||
+ char name[32];
|
||||
+ struct cpld_led_drvdata *drvdata;
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ drvdata = kzalloc(sizeof(struct cpld_led_drvdata) +
|
||||
+ sizeof(struct cpld_led_dev) * MAX_LED,
|
||||
+ GFP_KERNEL);
|
||||
+ if (!drvdata)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ drvdata->led_devs = (struct cpld_led_dev *) &drvdata[1];
|
||||
+
|
||||
+ for (i = 0; i < MAX_LED; i++) {
|
||||
+ struct cpld_led_dev *led_dev = &drvdata->led_devs[i];
|
||||
+ led_dev->cdev.brightness_set = led_brightness;
|
||||
+ led_dev->cdev.default_trigger = NULL;
|
||||
+ led_dev->mask = 1 << (i % 8);
|
||||
+ if(i < 8) {
|
||||
+ sprintf(name, "easy98000-cpld:%s", led_name[i]);
|
||||
+ led_dev->base = cpld_base8;
|
||||
+ } else {
|
||||
+ sprintf(name, "easy98000-cpld:red:%d", i-8);
|
||||
+ led_dev->base = cpld_base7;
|
||||
+ }
|
||||
+ led_dev->cdev.name = name;
|
||||
+ ret = led_classdev_register(&pdev->dev, &led_dev->cdev);
|
||||
+ if (ret)
|
||||
+ goto err;
|
||||
+ }
|
||||
+ platform_set_drvdata(pdev, drvdata);
|
||||
+ return 0;
|
||||
+
|
||||
+err:
|
||||
+ printk("led_probe: 3\n");
|
||||
+ for (i = i - 1; i >= 0; i--)
|
||||
+ led_classdev_unregister(&drvdata->led_devs[i].cdev);
|
||||
+
|
||||
+ kfree(drvdata);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int led_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ int i;
|
||||
+ struct cpld_led_drvdata *drvdata = platform_get_drvdata(pdev);
|
||||
+ for (i = 0; i < MAX_LED; i++)
|
||||
+ led_classdev_unregister(&drvdata->led_devs[i].cdev);
|
||||
+ kfree(drvdata);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static struct platform_driver led_driver = {
|
||||
+ .probe = led_probe,
|
||||
+ .remove = led_remove,
|
||||
+ .driver = {
|
||||
+ .name = LED_NAME,
|
||||
+ .owner = THIS_MODULE,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+int __init easy98000_cpld_led_init(void)
|
||||
+{
|
||||
+ pr_info(LED_DESC ", Version " LED_VERSION
|
||||
+ " (c) Copyright 2011, Lantiq Deutschland GmbH\n");
|
||||
+ return platform_driver_register(&led_driver);
|
||||
+}
|
||||
+
|
||||
+void __exit easy98000_cpld_led_exit(void)
|
||||
+{
|
||||
+ platform_driver_unregister(&led_driver);
|
||||
+}
|
||||
+
|
||||
+module_init(easy98000_cpld_led_init);
|
||||
+module_exit(easy98000_cpld_led_exit);
|
||||
+
|
||||
+MODULE_DESCRIPTION(LED_NAME);
|
||||
+MODULE_DESCRIPTION(LED_DESC);
|
||||
+MODULE_AUTHOR("Ralph Hempel <ralph.hempel@lantiq.com>");
|
||||
+MODULE_LICENSE("GPL v2");
|
||||
+
|
||||
--- /dev/null
|
||||
+++ b/arch/mips/lantiq/falcon/dev-leds-easy98000-cpld.h
|
||||
@@ -0,0 +1,20 @@
|
||||
+/*
|
||||
+ * EASY98000 CPLD LED driver
|
||||
+ *
|
||||
+ * Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com>
|
||||
+ *
|
||||
+ * 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.
|
||||
+ *
|
||||
+ */
|
||||
+#ifndef _INCLUDE_EASY98000_CPLD_LED_H_
|
||||
+#define _INCLUDE_EASY98000_CPLD_LED_H_
|
||||
+
|
||||
+#define LED_NAME "easy98000_cpld_led"
|
||||
+#define LED_DESC "EASY98000 LED driver"
|
||||
+#define LED_VERSION "1.0.0"
|
||||
+
|
||||
+#define MAX_LED 16
|
||||
+
|
||||
+#endif /* _INCLUDE_EASY98000_CPLD_LED_H_ */
|
@ -0,0 +1,120 @@ |
||||
--- /dev/null
|
||||
+++ b/arch/mips/lantiq/falcon/mach-easy98020.c
|
||||
@@ -0,0 +1,97 @@
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/leds.h>
|
||||
+#include <linux/gpio.h>
|
||||
+#include <linux/gpio_buttons.h>
|
||||
+#include <linux/mtd/mtd.h>
|
||||
+#include <linux/mtd/partitions.h>
|
||||
+#include <linux/input.h>
|
||||
+#include <linux/interrupt.h>
|
||||
+#include <linux/spi/spi.h>
|
||||
+#include <linux/spi/flash.h>
|
||||
+#include <machine.h>
|
||||
+
|
||||
+#include "devices.h"
|
||||
+#include "dev-leds-gpio.h"
|
||||
+
|
||||
+#define EASY98020_GPIO_LED_0 9
|
||||
+#define EASY98020_GPIO_LED_1 10
|
||||
+#define EASY98020_GPIO_LED_2 11
|
||||
+#define EASY98020_GPIO_LED_3 12
|
||||
+
|
||||
+extern unsigned char lq_ethaddr[6];
|
||||
+
|
||||
+#ifdef CONFIG_MTD_PARTITIONS
|
||||
+static struct mtd_partition easy98020_spi_partitions[] =
|
||||
+{
|
||||
+ {
|
||||
+ .name = "uboot",
|
||||
+ .offset = 0x0,
|
||||
+ .size = 0x40000,
|
||||
+ },
|
||||
+ {
|
||||
+ .name = "uboot_env",
|
||||
+ .offset = 0x40000,
|
||||
+ .size = 0x40000, /* 2 sectors for redundant env. */
|
||||
+ },
|
||||
+ {
|
||||
+ .name = "linux",
|
||||
+ .offset = 0x80000,
|
||||
+ .size = 0xF80000, /* map only 16 MiB */
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static struct flash_platform_data easy98020_spi_flash_platform_data = {
|
||||
+ .name = "sflash",
|
||||
+ .parts = easy98020_spi_partitions,
|
||||
+ .nr_parts = ARRAY_SIZE(easy98020_spi_partitions)
|
||||
+};
|
||||
+#endif
|
||||
+
|
||||
+static struct spi_board_info easy98020_spi_flash_data __initdata = {
|
||||
+ .modalias = "m25p80",
|
||||
+ .bus_num = 0,
|
||||
+ .chip_select = 0,
|
||||
+ .max_speed_hz = 10 * 1000 * 1000,
|
||||
+ .mode = SPI_MODE_3,
|
||||
+#ifdef CONFIG_MTD_PARTITIONS
|
||||
+ .platform_data = &easy98020_spi_flash_platform_data
|
||||
+#endif
|
||||
+};
|
||||
+
|
||||
+static struct gpio_led easy98020_leds_gpio[] __initdata = {
|
||||
+ {
|
||||
+ .name = "easy98020:green:0",
|
||||
+ .gpio = EASY98020_GPIO_LED_0,
|
||||
+ .active_low = 0,
|
||||
+ }, {
|
||||
+ .name = "easy98020:green:1",
|
||||
+ .gpio = EASY98020_GPIO_LED_1,
|
||||
+ .active_low = 0,
|
||||
+ }, {
|
||||
+ .name = "easy98020:green:2",
|
||||
+ .gpio = EASY98020_GPIO_LED_2,
|
||||
+ .active_low = 0,
|
||||
+ }, {
|
||||
+ .name = "easy98020:green:3",
|
||||
+ .gpio = EASY98020_GPIO_LED_3,
|
||||
+ .active_low = 0,
|
||||
+ }
|
||||
+};
|
||||
+
|
||||
+static void __init easy98020_init(void)
|
||||
+{
|
||||
+ falcon_register_asc(0);
|
||||
+ falcon_register_gpio();
|
||||
+ falcon_register_wdt();
|
||||
+ falcon_register_i2c();
|
||||
+ falcon_register_spi_flash(&easy98020_spi_flash_data);
|
||||
+ lq_add_device_leds_gpio(-1, ARRAY_SIZE(easy98020_leds_gpio),
|
||||
+ easy98020_leds_gpio);
|
||||
+ falcon_register_crypto();
|
||||
+}
|
||||
+
|
||||
+MIPS_MACHINE(LANTIQ_MACH_EASY98020,
|
||||
+ "EASY98020",
|
||||
+ "EASY98020 Eval Board",
|
||||
+ easy98020_init);
|
||||
--- a/arch/mips/lantiq/falcon/Kconfig
|
||||
+++ b/arch/mips/lantiq/falcon/Kconfig
|
||||
@@ -6,6 +6,10 @@ config LANTIQ_MACH_EASY98000
|
||||
bool "Easy98000"
|
||||
default y
|
||||
|
||||
+config LANTIQ_MACH_EASY98020
|
||||
+ bool "Easy98020"
|
||||
+ default y
|
||||
+
|
||||
endmenu
|
||||
|
||||
endif
|
||||
--- a/arch/mips/lantiq/falcon/Makefile
|
||||
+++ b/arch/mips/lantiq/falcon/Makefile
|
||||
@@ -2,3 +2,4 @@ obj-y := clk-falcon.o devices.o gpio.o p
|
||||
obj-y += softdog_vpe.o
|
||||
obj-$(CONFIG_LANTIQ_MACH_EASY98000) += mach-easy98000.o
|
||||
obj-$(CONFIG_LANTIQ_MACH_EASY98000) += dev-leds-easy98000-cpld.o
|
||||
+obj-$(CONFIG_LANTIQ_MACH_EASY98020) += mach-easy98020.o
|
@ -0,0 +1,136 @@ |
||||
--- /dev/null
|
||||
+++ b/arch/mips/lantiq/falcon/mach-95C3AM1.c
|
||||
@@ -0,0 +1,103 @@
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/i2c-gpio.h>
|
||||
+#include <machine.h>
|
||||
+
|
||||
+#include "devices.h"
|
||||
+#include "dev-leds-gpio.h"
|
||||
+
|
||||
+#define BOARD_95C3AM1_GPIO_LED_0 10
|
||||
+#define BOARD_95C3AM1_GPIO_LED_1 11
|
||||
+#define BOARD_95C3AM1_GPIO_LED_2 12
|
||||
+#define BOARD_95C3AM1_GPIO_LED_3 13
|
||||
+
|
||||
+extern unsigned char lq_ethaddr[6];
|
||||
+
|
||||
+#ifdef CONFIG_MTD_PARTITIONS
|
||||
+static struct mtd_partition board_95C3AM1_partitions[] =
|
||||
+{
|
||||
+ {
|
||||
+ .name = "uboot",
|
||||
+ .offset = 0x0,
|
||||
+ .size = 0x40000,
|
||||
+ },
|
||||
+ {
|
||||
+ .name = "uboot_env",
|
||||
+ .offset = 0x40000,
|
||||
+ .size = 0x40000, /* 2 sectors for redundant env. */
|
||||
+ },
|
||||
+ {
|
||||
+ .name = "linux",
|
||||
+ .offset = 0x80000,
|
||||
+ .size = 0xF80000, /* map only 16 MiB */
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static struct flash_platform_data board_95C3AM1_flash_platform_data = {
|
||||
+ .name = "sflash",
|
||||
+ .parts = board_95C3AM1_partitions,
|
||||
+ .nr_parts = ARRAY_SIZE(board_95C3AM1_partitions)
|
||||
+};
|
||||
+#endif
|
||||
+
|
||||
+static struct spi_board_info board_95C3AM1_flash_data __initdata = {
|
||||
+ .modalias = "m25p80",
|
||||
+ .bus_num = 0,
|
||||
+ .chip_select = 0,
|
||||
+ .max_speed_hz = 10 * 1000 * 1000,
|
||||
+ .mode = SPI_MODE_3,
|
||||
+#ifdef CONFIG_MTD_PARTITIONS
|
||||
+ .platform_data = &board_95C3AM1_flash_platform_data
|
||||
+#endif
|
||||
+};
|
||||
+
|
||||
+static struct gpio_led board_95C3AM1_leds_gpio[] __initdata = {
|
||||
+ {
|
||||
+ .name = "power",
|
||||
+ .gpio = BOARD_95C3AM1_GPIO_LED_0,
|
||||
+ .active_low = 0,
|
||||
+ }, {
|
||||
+ .name = "optical",
|
||||
+ .gpio = BOARD_95C3AM1_GPIO_LED_1,
|
||||
+ .active_low = 0,
|
||||
+ }, {
|
||||
+ .name = "lan",
|
||||
+ .gpio = BOARD_95C3AM1_GPIO_LED_2,
|
||||
+ .active_low = 0,
|
||||
+ }, {
|
||||
+ .name = "update",
|
||||
+ .gpio = BOARD_95C3AM1_GPIO_LED_3,
|
||||
+ .active_low = 0,
|
||||
+ }
|
||||
+};
|
||||
+
|
||||
+static struct i2c_gpio_platform_data board_95C3AM1_i2c_gpio_data = {
|
||||
+ .sda_pin = 107,
|
||||
+ .scl_pin = 108,
|
||||
+};
|
||||
+
|
||||
+static struct platform_device board_95C3AM1_i2c_gpio_device = {
|
||||
+ .name = "i2c-gpio",
|
||||
+ .id = 0,
|
||||
+ .dev = {
|
||||
+ .platform_data = &board_95C3AM1_i2c_gpio_data,
|
||||
+ }
|
||||
+};
|
||||
+
|
||||
+static void __init board_95C3AM1_init(void)
|
||||
+{
|
||||
+ falcon_register_asc(0);
|
||||
+ falcon_register_gpio();
|
||||
+ falcon_register_wdt();
|
||||
+ falcon_register_i2c();
|
||||
+ falcon_register_spi_flash(&board_95C3AM1_flash_data);
|
||||
+ platform_device_register(&board_95C3AM1_i2c_gpio_device);
|
||||
+ lq_add_device_leds_gpio(-1, ARRAY_SIZE(board_95C3AM1_leds_gpio),
|
||||
+ board_95C3AM1_leds_gpio);
|
||||
+ falcon_register_crypto();
|
||||
+}
|
||||
+
|
||||
+MIPS_MACHINE(LANTIQ_MACH_95C3AM1,
|
||||
+ "95C3AM1",
|
||||
+ "95C3AM1 Board",
|
||||
+ board_95C3AM1_init);
|
||||
--- a/arch/mips/include/asm/mach-lantiq/machine.h
|
||||
+++ b/arch/mips/include/asm/mach-lantiq/machine.h
|
||||
@@ -7,6 +7,7 @@ enum lantiq_mach_type {
|
||||
LANTIQ_MACH_EASY98000, /* Falcon Eval Board, NOR Flash */
|
||||
LANTIQ_MACH_EASY98000SF, /* Falcon Eval Board, Serial Flash */
|
||||
LANTIQ_MACH_EASY98020, /* Falcon Reference Board */
|
||||
+ LANTIQ_MACH_95C3AM1, /* Board 95C3AM1 */
|
||||
|
||||
/* XWAY */
|
||||
LANTIQ_MACH_EASY4010, /* Twinpass evalkit */
|
||||
--- a/arch/mips/lantiq/falcon/Kconfig
|
||||
+++ b/arch/mips/lantiq/falcon/Kconfig
|
||||
@@ -10,6 +10,10 @@ config LANTIQ_MACH_EASY98020
|
||||
bool "Easy98020"
|
||||
default y
|
||||
|
||||
+config LANTIQ_MACH_95C3AM1
|
||||
+ bool "95C3AM1"
|
||||
+ default y
|
||||
+
|
||||
endmenu
|
||||
|
||||
endif
|
||||
--- a/arch/mips/lantiq/falcon/Makefile
|
||||
+++ b/arch/mips/lantiq/falcon/Makefile
|
||||
@@ -3,3 +3,4 @@ obj-y += softdog_vpe.o
|
||||
obj-$(CONFIG_LANTIQ_MACH_EASY98000) += mach-easy98000.o
|
||||
obj-$(CONFIG_LANTIQ_MACH_EASY98000) += dev-leds-easy98000-cpld.o
|
||||
obj-$(CONFIG_LANTIQ_MACH_EASY98020) += mach-easy98020.o
|
||||
+obj-$(CONFIG_LANTIQ_MACH_95C3AM1) += mach-95C3AM1.o
|
Loading…
Reference in new issue