mirror of
https://github.com/a52xq-dev/kernel.git
synced 2026-10-18 21:58:11 +07:00
CRIS: Drop support for the CRIS port
The port was added back in 2000 so it's no longer even a good source of inspiration for newer ports (if it ever was) The last SoC (ARTPEC-3) with a CRIS main CPU was launched in 2008. Coupled with time and working developer board hardware being in low supply, it's time to drop the port from Linux. So long and thanks for all the fish! Signed-off-by: Jesper Nilsson <jesper.nilsson@axis.com> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
parent
bb9d812643
commit
c690eddc2f
430 changed files with 0 additions and 99983 deletions
|
|
@ -112,8 +112,6 @@ cputopology.txt
|
|||
- documentation on how CPU topology info is exported via sysfs.
|
||||
crc32.txt
|
||||
- brief tutorial on CRC computation
|
||||
cris/
|
||||
- directory with info about Linux on CRIS architecture.
|
||||
crypto/
|
||||
- directory with info on the Crypto API.
|
||||
dcdbas.txt
|
||||
|
|
|
|||
|
|
@ -1,195 +0,0 @@
|
|||
Linux on the CRIS architecture
|
||||
==============================
|
||||
|
||||
This is a port of Linux to Axis Communications ETRAX 100LX,
|
||||
ETRAX FS and ARTPEC-3 embedded network CPUs.
|
||||
|
||||
For more information about CRIS and ETRAX please see further below.
|
||||
|
||||
In order to compile this you need a version of gcc with support for the
|
||||
ETRAX chip family. Please see this link for more information on how to
|
||||
download the compiler and other tools useful when building and booting
|
||||
software for the ETRAX platform:
|
||||
|
||||
http://developer.axis.com/wiki/doku.php?id=axis:install-howto-2_20
|
||||
|
||||
What is CRIS ?
|
||||
--------------
|
||||
|
||||
CRIS is an acronym for 'Code Reduced Instruction Set'. It is the CPU
|
||||
architecture in Axis Communication AB's range of embedded network CPU's,
|
||||
called ETRAX.
|
||||
|
||||
The ETRAX 100LX chip
|
||||
--------------------
|
||||
|
||||
For reference, please see the following link:
|
||||
|
||||
http://www.axis.com/products/dev_etrax_100lx/index.htm
|
||||
|
||||
The ETRAX 100LX is a 100 MIPS processor with 8kB cache, MMU, and a very broad
|
||||
range of built-in interfaces, all with modern scatter/gather DMA.
|
||||
|
||||
Memory interfaces:
|
||||
|
||||
* SRAM
|
||||
* NOR-flash/ROM
|
||||
* EDO or page-mode DRAM
|
||||
* SDRAM
|
||||
|
||||
I/O interfaces:
|
||||
|
||||
* one 10/100 Mbit/s ethernet controller
|
||||
* four serial-ports (up to 6 Mbit/s)
|
||||
* two synchronous serial-ports for multimedia codec's etc.
|
||||
* USB host controller and USB slave
|
||||
* ATA
|
||||
* SCSI
|
||||
* two parallel-ports
|
||||
* two generic 8-bit ports
|
||||
|
||||
(not all interfaces are available at the same time due to chip pin
|
||||
multiplexing)
|
||||
|
||||
ETRAX 100LX is CRISv10 architecture.
|
||||
|
||||
|
||||
The ETRAX FS and ARTPEC-3 chips
|
||||
-------------------------------
|
||||
|
||||
The ETRAX FS is a 200MHz 32-bit RISC processor with on-chip 16kB
|
||||
I-cache and 16kB D-cache and with a wide range of device interfaces
|
||||
including multiple high speed serial ports and an integrated USB 1.1 PHY.
|
||||
|
||||
The ARTPEC-3 is a variant of the ETRAX FS with additional IO-units
|
||||
used by the Axis Communications network cameras.
|
||||
|
||||
See below link for more information:
|
||||
|
||||
http://www.axis.com/products/dev_etrax_fs/index.htm
|
||||
|
||||
ETRAX FS and ARTPEC-3 are both CRISv32 architectures.
|
||||
|
||||
Bootlog
|
||||
-------
|
||||
|
||||
Just as an example, this is the debug-output from a boot of Linux 2.4 on
|
||||
a board with ETRAX 100LX. The displayed BogoMIPS value is 5 times too small :)
|
||||
At the end you see some user-mode programs booting like telnet and ftp daemons.
|
||||
|
||||
Linux version 2.4.1 (bjornw@godzilla.axis.se) (gcc version 2.96 20000427 (experimental)) #207 Wed Feb 21 15:48:15 CET 2001
|
||||
ROM fs in RAM, size 1376256 bytes
|
||||
Setting up paging and the MMU.
|
||||
On node 0 totalpages: 2048
|
||||
zone(0): 2048 pages.
|
||||
zone(1): 0 pages.
|
||||
zone(2): 0 pages.
|
||||
Linux/CRIS port on ETRAX 100LX (c) 2001 Axis Communications AB
|
||||
Kernel command line:
|
||||
Calibrating delay loop... 19.91 BogoMIPS
|
||||
Memory: 13872k/16384k available (587k kernel code, 2512k reserved, 44k data, 24k init)
|
||||
kmem_create: Forcing size word alignment - vm_area_struct
|
||||
kmem_create: Forcing size word alignment - filp
|
||||
Dentry-cache hash table entries: 2048 (order: 1, 16384 bytes)
|
||||
Buffer-cache hash table entries: 2048 (order: 0, 8192 bytes)
|
||||
Page-cache hash table entries: 2048 (order: 0, 8192 bytes)
|
||||
kmem_create: Forcing size word alignment - kiobuf
|
||||
kmem_create: Forcing size word alignment - bdev_cache
|
||||
Inode-cache hash table entries: 1024 (order: 0, 8192 bytes)
|
||||
kmem_create: Forcing size word alignment - inode_cache
|
||||
POSIX conformance testing by UNIFIX
|
||||
Linux NET4.0 for Linux 2.4
|
||||
Based upon Swansea University Computer Society NET3.039
|
||||
Starting kswapd v1.8
|
||||
kmem_create: Forcing size word alignment - file lock cache
|
||||
kmem_create: Forcing size word alignment - blkdev_requests
|
||||
block: queued sectors max/low 9109kB/3036kB, 64 slots per queue
|
||||
ETRAX 100LX 10/100MBit ethernet v2.0 (c) 2000 Axis Communications AB
|
||||
eth0 initialized
|
||||
eth0: changed MAC to 00:40:8C:CD:00:00
|
||||
ETRAX 100LX serial-driver $Revision: 1.7 $, (c) 2000 Axis Communications AB
|
||||
ttyS0 at 0xb0000060 is a builtin UART with DMA
|
||||
ttyS1 at 0xb0000068 is a builtin UART with DMA
|
||||
ttyS2 at 0xb0000070 is a builtin UART with DMA
|
||||
ttyS3 at 0xb0000078 is a builtin UART with DMA
|
||||
Axis flash mapping: 200000 at 50000000
|
||||
Axis flash: Found 1 x16 CFI device at 0x0 in 16 bit mode
|
||||
Amd/Fujitsu Extended Query Table v1.0 at 0x0040
|
||||
Axis flash: JEDEC Device ID is 0xC4. Assuming broken CFI table.
|
||||
Axis flash: Swapping erase regions for broken CFI table.
|
||||
number of CFI chips: 1
|
||||
Using default partition table
|
||||
I2C driver v2.2, (c) 1999-2001 Axis Communications AB
|
||||
ETRAX 100LX GPIO driver v2.1, (c) 2001 Axis Communications AB
|
||||
NET4: Linux TCP/IP 1.0 for NET4.0
|
||||
IP Protocols: ICMP, UDP, TCP
|
||||
kmem_create: Forcing size word alignment - ip_dst_cache
|
||||
IP: routing cache hash table of 1024 buckets, 8Kbytes
|
||||
TCP: Hash tables configured (established 2048 bind 2048)
|
||||
NET4: Unix domain sockets 1.0/SMP for Linux NET4.0.
|
||||
VFS: Mounted root (cramfs filesystem) readonly.
|
||||
Init starts up...
|
||||
Mounted none on /proc ok.
|
||||
Setting up eth0 with ip 10.13.9.116 and mac 00:40:8c:18:04:60
|
||||
eth0: changed MAC to 00:40:8C:18:04:60
|
||||
Setting up lo with ip 127.0.0.1
|
||||
Default gateway is 10.13.9.1
|
||||
Hostname is bbox1
|
||||
Telnetd starting, using port 23.
|
||||
using /bin/sash as shell.
|
||||
sftpd[15]: sftpd $Revision: 1.7 $ starting up
|
||||
|
||||
|
||||
|
||||
And here is how some /proc entries look:
|
||||
|
||||
17# cd /proc
|
||||
17# cat cpuinfo
|
||||
cpu : CRIS
|
||||
cpu revision : 10
|
||||
cpu model : ETRAX 100LX
|
||||
cache size : 8 kB
|
||||
fpu : no
|
||||
mmu : yes
|
||||
ethernet : 10/100 Mbps
|
||||
token ring : no
|
||||
scsi : yes
|
||||
ata : yes
|
||||
usb : yes
|
||||
bogomips : 99.84
|
||||
|
||||
17# cat meminfo
|
||||
total: used: free: shared: buffers: cached:
|
||||
Mem: 7028736 925696 6103040 114688 0 229376
|
||||
Swap: 0 0 0
|
||||
MemTotal: 6864 kB
|
||||
MemFree: 5960 kB
|
||||
MemShared: 112 kB
|
||||
Buffers: 0 kB
|
||||
Cached: 224 kB
|
||||
Active: 224 kB
|
||||
Inact_dirty: 0 kB
|
||||
Inact_clean: 0 kB
|
||||
Inact_target: 0 kB
|
||||
HighTotal: 0 kB
|
||||
HighFree: 0 kB
|
||||
LowTotal: 6864 kB
|
||||
LowFree: 5960 kB
|
||||
SwapTotal: 0 kB
|
||||
SwapFree: 0 kB
|
||||
17# ls -l /bin
|
||||
-rwxr-xr-x 1 342 100 10356 Jan 01 00:00 ifconfig
|
||||
-rwxr-xr-x 1 342 100 17548 Jan 01 00:00 init
|
||||
-rwxr-xr-x 1 342 100 9488 Jan 01 00:00 route
|
||||
-rwxr-xr-x 1 342 100 46036 Jan 01 00:00 sftpd
|
||||
-rwxr-xr-x 1 342 100 48104 Jan 01 00:00 sh
|
||||
-rwxr-xr-x 1 342 100 16252 Jan 01 00:00 telnetd
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
Axis Communications AB
|
||||
ARTPEC series SoC Device Tree Bindings
|
||||
|
||||
|
||||
CRISv32 based SoCs are ETRAX FS and ARTPEC-3:
|
||||
|
||||
- compatible = "axis,crisv32";
|
||||
|
||||
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
Boards based on the CRIS SoCs:
|
||||
|
||||
Required root node properties:
|
||||
- compatible = should be one or more of the following:
|
||||
- "axis,dev88" - for Axis devboard 88 with ETRAX FS
|
||||
|
||||
Optional:
|
||||
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
* CRISv32 Interrupt Controller
|
||||
|
||||
Interrupt controller for the CRISv32 SoCs.
|
||||
|
||||
Main node required properties:
|
||||
|
||||
- compatible : should be:
|
||||
"axis,crisv32-intc"
|
||||
- interrupt-controller : Identifies the node as an interrupt controller
|
||||
- #interrupt-cells : Specifies the number of cells needed to encode an
|
||||
interrupt source. The type shall be a <u32> and the value shall be 1.
|
||||
- reg: physical base address and size of the intc registers map.
|
||||
|
||||
Example:
|
||||
|
||||
intc: interrupt-controller {
|
||||
compatible = "axis,crisv32-intc";
|
||||
reg = <0xb001c000 0x1000>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <1>;
|
||||
};
|
||||
|
||||
|
||||
10
MAINTAINERS
10
MAINTAINERS
|
|
@ -3704,16 +3704,6 @@ S: Maintained
|
|||
F: Documentation/filesystems/cramfs.txt
|
||||
F: fs/cramfs/
|
||||
|
||||
CRIS PORT
|
||||
M: Mikael Starvik <starvik@axis.com>
|
||||
M: Jesper Nilsson <jesper.nilsson@axis.com>
|
||||
L: linux-cris-kernel@axis.com
|
||||
W: http://developer.axis.com
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jesper/cris.git
|
||||
S: Maintained
|
||||
F: arch/cris/
|
||||
F: drivers/tty/serial/crisv10.*
|
||||
|
||||
CRYPTO API
|
||||
M: Herbert Xu <herbert@gondor.apana.org.au>
|
||||
M: "David S. Miller" <davem@davemloft.net>
|
||||
|
|
|
|||
|
|
@ -1,595 +0,0 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
config MMU
|
||||
bool
|
||||
default y
|
||||
|
||||
config ZONE_DMA
|
||||
bool
|
||||
default y
|
||||
|
||||
config RWSEM_GENERIC_SPINLOCK
|
||||
bool
|
||||
default y
|
||||
|
||||
config RWSEM_XCHGADD_ALGORITHM
|
||||
bool
|
||||
|
||||
config ARCH_HAS_ILOG2_U32
|
||||
bool
|
||||
default n
|
||||
|
||||
config ARCH_HAS_ILOG2_U64
|
||||
bool
|
||||
default n
|
||||
|
||||
config GENERIC_HWEIGHT
|
||||
bool
|
||||
default y
|
||||
|
||||
config GENERIC_CALIBRATE_DELAY
|
||||
bool
|
||||
default y
|
||||
|
||||
config NO_IOPORT_MAP
|
||||
def_bool y if !PCI
|
||||
|
||||
config NO_DMA
|
||||
def_bool y if !PCI
|
||||
|
||||
config FORCE_MAX_ZONEORDER
|
||||
int
|
||||
default 6
|
||||
|
||||
config TRACE_IRQFLAGS_SUPPORT
|
||||
depends on ETRAX_ARCH_V32
|
||||
def_bool y
|
||||
|
||||
config STACKTRACE_SUPPORT
|
||||
def_bool y
|
||||
|
||||
config LOCKDEP_SUPPORT
|
||||
depends on ETRAX_ARCH_V32
|
||||
def_bool y
|
||||
|
||||
config CRIS
|
||||
bool
|
||||
default y
|
||||
select HAVE_IDE
|
||||
select GENERIC_ATOMIC64
|
||||
select HAVE_UID16
|
||||
select VIRT_TO_BUS
|
||||
select ARCH_WANT_IPC_PARSE_VERSION
|
||||
select GENERIC_IRQ_SHOW
|
||||
select GENERIC_IOMAP
|
||||
select MODULES_USE_ELF_RELA
|
||||
select CLONE_BACKWARDS2
|
||||
select HAVE_EXIT_THREAD if ETRAX_ARCH_V32
|
||||
select OLD_SIGSUSPEND
|
||||
select OLD_SIGACTION
|
||||
select GPIOLIB
|
||||
select IRQ_DOMAIN if ETRAX_ARCH_V32
|
||||
select OF if ETRAX_ARCH_V32
|
||||
select OF_EARLY_FLATTREE if ETRAX_ARCH_V32
|
||||
select CLKSRC_MMIO if ETRAX_ARCH_V32
|
||||
select GENERIC_CLOCKEVENTS if ETRAX_ARCH_V32
|
||||
select GENERIC_SCHED_CLOCK if ETRAX_ARCH_V32
|
||||
select HAVE_DEBUG_BUGVERBOSE if ETRAX_ARCH_V32
|
||||
select HAVE_NMI
|
||||
select DMA_DIRECT_OPS if PCI
|
||||
|
||||
config HZ
|
||||
int
|
||||
default 100
|
||||
|
||||
config NR_CPUS
|
||||
int
|
||||
default "1"
|
||||
|
||||
config BUILTIN_DTB
|
||||
string "DTB to build into the kernel image"
|
||||
depends on OF
|
||||
|
||||
source "init/Kconfig"
|
||||
|
||||
source "kernel/Kconfig.freezer"
|
||||
|
||||
menu "General setup"
|
||||
|
||||
source "fs/Kconfig.binfmt"
|
||||
|
||||
config ETRAX_CMDLINE
|
||||
string "Kernel command line"
|
||||
default "root=/dev/mtdblock3"
|
||||
help
|
||||
Pass additional commands to the kernel.
|
||||
|
||||
config ETRAX_WATCHDOG
|
||||
bool "Enable ETRAX watchdog"
|
||||
help
|
||||
Enable the built-in watchdog timer support on ETRAX based embedded
|
||||
network computers.
|
||||
|
||||
config ETRAX_WATCHDOG_NICE_DOGGY
|
||||
bool "Disable watchdog during Oops printouts"
|
||||
depends on ETRAX_WATCHDOG
|
||||
help
|
||||
By enabling this you make sure that the watchdog does not bite while
|
||||
printing oopses. Recommended for development systems but not for
|
||||
production releases.
|
||||
|
||||
config ETRAX_FAST_TIMER
|
||||
bool "Enable ETRAX fast timer API"
|
||||
help
|
||||
This options enables the API to a fast timer implementation using
|
||||
timer1 to get sub jiffie resolution timers (primarily one-shot
|
||||
timers).
|
||||
This is needed if CONFIG_ETRAX_SERIAL_FAST_TIMER is enabled.
|
||||
|
||||
config ETRAX_KMALLOCED_MODULES
|
||||
bool "Enable module allocation with kmalloc"
|
||||
help
|
||||
Enable module allocation with kmalloc instead of vmalloc.
|
||||
|
||||
source "kernel/Kconfig.preempt"
|
||||
|
||||
source mm/Kconfig
|
||||
|
||||
endmenu
|
||||
|
||||
menu "Hardware setup"
|
||||
|
||||
choice
|
||||
prompt "Processor type"
|
||||
default ETRAX100LX
|
||||
|
||||
config ETRAX100LX
|
||||
bool "ETRAX-100LX-v1"
|
||||
select ARCH_USES_GETTIMEOFFSET
|
||||
help
|
||||
Support version 1 of the ETRAX 100LX.
|
||||
|
||||
config ETRAX100LX_V2
|
||||
bool "ETRAX-100LX-v2"
|
||||
select ARCH_USES_GETTIMEOFFSET
|
||||
help
|
||||
Support version 2 of the ETRAX 100LX.
|
||||
|
||||
config ETRAXFS
|
||||
bool "ETRAX-FS-V32"
|
||||
help
|
||||
Support CRIS V32.
|
||||
|
||||
config CRIS_MACH_ARTPEC3
|
||||
bool "ARTPEC-3"
|
||||
help
|
||||
Support Axis ARTPEC-3.
|
||||
|
||||
endchoice
|
||||
|
||||
config ETRAX_ARCH_V10
|
||||
bool
|
||||
default y if ETRAX100LX || ETRAX100LX_V2
|
||||
default n if !(ETRAX100LX || ETRAX100LX_V2)
|
||||
select TTY
|
||||
|
||||
config ETRAX_ARCH_V32
|
||||
bool
|
||||
default y if (ETRAXFS || CRIS_MACH_ARTPEC3)
|
||||
default n if !(ETRAXFS || CRIS_MACH_ARTPEC3)
|
||||
|
||||
config ETRAX_DRAM_SIZE
|
||||
int "DRAM size (dec, in MB)"
|
||||
default "8"
|
||||
help
|
||||
Size of DRAM (decimal in MB) typically 2, 8 or 16.
|
||||
|
||||
config ETRAX_VMEM_SIZE
|
||||
int "Video memory size (dec, in MB)"
|
||||
depends on ETRAX_ARCH_V32 && !ETRAXFS
|
||||
default 8 if !ETRAXFS
|
||||
help
|
||||
Size of Video accessible memory (decimal, in MB).
|
||||
|
||||
config ETRAX_FLASH_BUSWIDTH
|
||||
int "Buswidth of NOR flash in bytes"
|
||||
default "2"
|
||||
help
|
||||
Width in bytes of the NOR Flash bus (1, 2 or 4). Is usually 2.
|
||||
|
||||
config ETRAX_FLASH1_SIZE
|
||||
int "FLASH1 size (dec, in MB. 0 = Unknown)"
|
||||
default "0"
|
||||
|
||||
choice
|
||||
prompt "Product debug-port"
|
||||
default ETRAX_DEBUG_PORT0
|
||||
|
||||
config ETRAX_DEBUG_PORT0
|
||||
bool "Serial-0"
|
||||
help
|
||||
Choose a serial port for the ETRAX debug console. Default to
|
||||
port 0.
|
||||
|
||||
config ETRAX_DEBUG_PORT1
|
||||
bool "Serial-1"
|
||||
help
|
||||
Use serial port 1 for the console.
|
||||
|
||||
config ETRAX_DEBUG_PORT2
|
||||
bool "Serial-2"
|
||||
help
|
||||
Use serial port 2 for the console.
|
||||
|
||||
config ETRAX_DEBUG_PORT3
|
||||
bool "Serial-3"
|
||||
help
|
||||
Use serial port 3 for the console.
|
||||
|
||||
config ETRAX_DEBUG_PORT_NULL
|
||||
bool "disabled"
|
||||
help
|
||||
Disable serial-port debugging.
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Kernel GDB port"
|
||||
depends on ETRAX_KGDB
|
||||
default ETRAX_KGDB_PORT0
|
||||
help
|
||||
Choose a serial port for kernel debugging. NOTE: This port should
|
||||
not be enabled under Drivers for built-in interfaces (as it has its
|
||||
own initialization code) and should not be the same as the debug port.
|
||||
|
||||
config ETRAX_KGDB_PORT0
|
||||
bool "Serial-0"
|
||||
help
|
||||
Use serial port 0 for kernel debugging.
|
||||
|
||||
config ETRAX_KGDB_PORT1
|
||||
bool "Serial-1"
|
||||
help
|
||||
Use serial port 1 for kernel debugging.
|
||||
|
||||
config ETRAX_KGDB_PORT2
|
||||
bool "Serial-2"
|
||||
help
|
||||
Use serial port 2 for kernel debugging.
|
||||
|
||||
config ETRAX_KGDB_PORT3
|
||||
bool "Serial-3"
|
||||
help
|
||||
Use serial port 3 for kernel debugging.
|
||||
|
||||
endchoice
|
||||
|
||||
source arch/cris/arch-v10/Kconfig
|
||||
source arch/cris/arch-v32/Kconfig
|
||||
|
||||
endmenu
|
||||
|
||||
source "net/Kconfig"
|
||||
|
||||
# bring in ETRAX built-in drivers
|
||||
menu "Drivers for built-in interfaces"
|
||||
source arch/cris/arch-v10/drivers/Kconfig
|
||||
source arch/cris/arch-v32/drivers/Kconfig
|
||||
|
||||
config ETRAX_AXISFLASHMAP
|
||||
bool "Axis flash-map support"
|
||||
select MTD
|
||||
select MTD_CFI
|
||||
select MTD_CFI_AMDSTD
|
||||
select MTD_JEDECPROBE if ETRAX_ARCH_V32
|
||||
select MTD_BLOCK
|
||||
select MTD_COMPLEX_MAPPINGS
|
||||
help
|
||||
This option enables MTD mapping of flash devices. Needed to use
|
||||
flash memories. If unsure, say Y.
|
||||
|
||||
config ETRAX_SYNCHRONOUS_SERIAL
|
||||
bool "Synchronous serial-port support"
|
||||
help
|
||||
Select this to enable the synchronous serial port driver.
|
||||
|
||||
config ETRAX_SYNCHRONOUS_SERIAL_PORT0
|
||||
bool "Synchronous serial port 0 enabled"
|
||||
depends on ETRAX_SYNCHRONOUS_SERIAL
|
||||
help
|
||||
Enabled synchronous serial port 0.
|
||||
|
||||
config ETRAX_SYNCHRONOUS_SERIAL0_DMA
|
||||
bool "Enable DMA on synchronous serial port 0."
|
||||
depends on ETRAX_SYNCHRONOUS_SERIAL_PORT0
|
||||
help
|
||||
A synchronous serial port can run in manual or DMA mode.
|
||||
Selecting this option will make it run in DMA mode.
|
||||
|
||||
config ETRAX_SYNCHRONOUS_SERIAL_PORT1
|
||||
bool "Synchronous serial port 1 enabled"
|
||||
depends on ETRAX_SYNCHRONOUS_SERIAL && (ETRAXFS || ETRAX_ARCH_V10)
|
||||
help
|
||||
Enabled synchronous serial port 1.
|
||||
|
||||
config ETRAX_SYNCHRONOUS_SERIAL1_DMA
|
||||
bool "Enable DMA on synchronous serial port 1."
|
||||
depends on ETRAX_SYNCHRONOUS_SERIAL_PORT1
|
||||
help
|
||||
A synchronous serial port can run in manual or DMA mode.
|
||||
Selecting this option will make it run in DMA mode.
|
||||
|
||||
choice
|
||||
prompt "Network LED behavior"
|
||||
depends on ETRAX_ETHERNET
|
||||
default ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY
|
||||
|
||||
config ETRAX_NETWORK_LED_ON_WHEN_LINK
|
||||
bool "LED_on_when_link"
|
||||
help
|
||||
Selecting LED_on_when_link will light the LED when there is a
|
||||
connection and will flash off when there is activity.
|
||||
|
||||
Selecting LED_on_when_activity will light the LED only when
|
||||
there is activity.
|
||||
|
||||
This setting will also affect the behaviour of other activity LEDs
|
||||
e.g. Bluetooth.
|
||||
|
||||
config ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY
|
||||
bool "LED_on_when_activity"
|
||||
help
|
||||
Selecting LED_on_when_link will light the LED when there is a
|
||||
connection and will flash off when there is activity.
|
||||
|
||||
Selecting LED_on_when_activity will light the LED only when
|
||||
there is activity.
|
||||
|
||||
This setting will also affect the behaviour of other activity LEDs
|
||||
e.g. Bluetooth.
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Ser0 DMA out channel"
|
||||
depends on ETRAX_SERIAL_PORT0
|
||||
default ETRAX_SERIAL_PORT0_DMA6_OUT if ETRAX_ARCH_V32
|
||||
default ETRAX_SERIAL_PORT0_NO_DMA_OUT if ETRAX_ARCH_V10
|
||||
|
||||
config ETRAX_SERIAL_PORT0_NO_DMA_OUT
|
||||
bool "Ser0 uses no DMA for output"
|
||||
help
|
||||
Do not use DMA for ser0 output.
|
||||
|
||||
config ETRAX_SERIAL_PORT0_DMA6_OUT
|
||||
bool "Ser0 uses DMA6 for output"
|
||||
depends on ETRAXFS
|
||||
help
|
||||
Enables the DMA6 output channel for ser0 (ttyS0).
|
||||
If you do not enable DMA, an interrupt for each character will be
|
||||
used when transmitting data.
|
||||
Normally you want to use DMA, unless you use the DMA channel for
|
||||
something else.
|
||||
|
||||
config ETRAX_SERIAL_PORT0_DMA0_OUT
|
||||
bool "Ser0 uses DMA0 for output"
|
||||
depends on CRIS_MACH_ARTPEC3
|
||||
help
|
||||
Enables the DMA0 output channel for ser0 (ttyS0).
|
||||
If you do not enable DMA, an interrupt for each character will be
|
||||
used when transmitting data.
|
||||
Normally you want to use DMA, unless you use the DMA channel for
|
||||
something else.
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Ser0 DMA in channel "
|
||||
depends on ETRAX_SERIAL_PORT0
|
||||
default ETRAX_SERIAL_PORT0_NO_DMA_IN if ETRAX_ARCH_V32
|
||||
default ETRAX_SERIAL_PORT0_DMA7_IN if ETRAX_ARCH_V10
|
||||
help
|
||||
What DMA channel to use for ser0.
|
||||
|
||||
config ETRAX_SERIAL_PORT0_NO_DMA_IN
|
||||
bool "Ser0 uses no DMA for input"
|
||||
help
|
||||
Do not use DMA for ser0 input.
|
||||
|
||||
config ETRAX_SERIAL_PORT0_DMA7_IN
|
||||
bool "Ser0 uses DMA7 for input"
|
||||
depends on ETRAXFS
|
||||
help
|
||||
Enables the DMA7 input channel for ser0 (ttyS0).
|
||||
If you do not enable DMA, an interrupt for each character will be
|
||||
used when receiving data.
|
||||
Normally you want to use DMA, unless you use the DMA channel for
|
||||
something else.
|
||||
|
||||
config ETRAX_SERIAL_PORT0_DMA1_IN
|
||||
bool "Ser0 uses DMA1 for input"
|
||||
depends on CRIS_MACH_ARTPEC3
|
||||
help
|
||||
Enables the DMA1 input channel for ser0 (ttyS0).
|
||||
If you do not enable DMA, an interrupt for each character will be
|
||||
used when receiving data.
|
||||
Normally you want to use DMA, unless you use the DMA channel for
|
||||
something else.
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Ser1 DMA in channel "
|
||||
depends on ETRAX_SERIAL_PORT1
|
||||
default ETRAX_SERIAL_PORT1_NO_DMA_IN if ETRAX_ARCH_V32
|
||||
default ETRAX_SERIAL_PORT1_DMA9_IN if ETRAX_ARCH_V10
|
||||
help
|
||||
What DMA channel to use for ser1.
|
||||
|
||||
config ETRAX_SERIAL_PORT1_NO_DMA_IN
|
||||
bool "Ser1 uses no DMA for input"
|
||||
help
|
||||
Do not use DMA for ser1 input.
|
||||
|
||||
config ETRAX_SERIAL_PORT1_DMA5_IN
|
||||
bool "Ser1 uses DMA5 for input"
|
||||
depends on ETRAX_ARCH_V32
|
||||
help
|
||||
Enables the DMA5 input channel for ser1 (ttyS1).
|
||||
If you do not enable DMA, an interrupt for each character will be
|
||||
used when receiving data.
|
||||
Normally you want this on, unless you use the DMA channel for
|
||||
something else.
|
||||
|
||||
config ETRAX_SERIAL_PORT1_DMA9_IN
|
||||
depends on ETRAX_ARCH_V10
|
||||
bool "Ser1 uses DMA9 for input"
|
||||
|
||||
endchoice
|
||||
|
||||
|
||||
choice
|
||||
prompt "Ser1 DMA out channel"
|
||||
depends on ETRAX_SERIAL_PORT1
|
||||
default ETRAX_SERIAL_PORT1_NO_DMA_OUT if ETRAX_ARCH_V32
|
||||
default ETRAX_SERIAL_PORT1_DMA8_OUT if ETRAX_ARCH_V10
|
||||
help
|
||||
What DMA channel to use for ser1.
|
||||
|
||||
config ETRAX_SERIAL_PORT1_NO_DMA_OUT
|
||||
bool "Ser1 uses no DMA for output"
|
||||
help
|
||||
Do not use DMA for ser1 output.
|
||||
|
||||
config ETRAX_SERIAL_PORT1_DMA8_OUT
|
||||
depends on ETRAX_ARCH_V10
|
||||
bool "Ser1 uses DMA8 for output"
|
||||
|
||||
config ETRAX_SERIAL_PORT1_DMA4_OUT
|
||||
depends on ETRAX_ARCH_V32
|
||||
bool "Ser1 uses DMA4 for output"
|
||||
help
|
||||
Enables the DMA4 output channel for ser1 (ttyS1).
|
||||
If you do not enable DMA, an interrupt for each character will be
|
||||
used when transmitting data.
|
||||
Normally you want this on, unless you use the DMA channel for
|
||||
something else.
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Ser2 DMA out channel"
|
||||
depends on ETRAX_SERIAL_PORT2
|
||||
default ETRAX_SERIAL_PORT2_NO_DMA_OUT if ETRAX_ARCH_V32
|
||||
default ETRAX_SERIAL_PORT2_DMA2_OUT if ETRAX_ARCH_V10
|
||||
|
||||
config ETRAX_SERIAL_PORT2_NO_DMA_OUT
|
||||
bool "Ser2 uses no DMA for output"
|
||||
help
|
||||
Do not use DMA for ser2 output.
|
||||
|
||||
config ETRAX_SERIAL_PORT2_DMA2_OUT
|
||||
bool "Ser2 uses DMA2 for output"
|
||||
depends on ETRAXFS || ETRAX_ARCH_V10
|
||||
help
|
||||
Enables the DMA2 output channel for ser2 (ttyS2).
|
||||
If you do not enable DMA, an interrupt for each character will be
|
||||
used when transmitting data.
|
||||
Normally you want to use DMA, unless you use the DMA channel for
|
||||
something else.
|
||||
|
||||
config ETRAX_SERIAL_PORT2_DMA6_OUT
|
||||
bool "Ser2 uses DMA6 for output"
|
||||
depends on CRIS_MACH_ARTPEC3
|
||||
help
|
||||
Enables the DMA6 output channel for ser2 (ttyS2).
|
||||
If you do not enable DMA, an interrupt for each character will be
|
||||
used when transmitting data.
|
||||
Normally you want to use DMA, unless you use the DMA channel for
|
||||
something else.
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Ser2 DMA in channel"
|
||||
depends on ETRAX_SERIAL_PORT2
|
||||
default ETRAX_SERIAL_PORT2_NO_DMA_IN if ETRAX_ARCH_V32
|
||||
default ETRAX_SERIAL_PORT2_DMA3_IN if ETRAX_ARCH_V10
|
||||
help
|
||||
What DMA channel to use for ser2.
|
||||
|
||||
config ETRAX_SERIAL_PORT2_NO_DMA_IN
|
||||
bool "Ser2 uses no DMA for input"
|
||||
help
|
||||
Do not use DMA for ser2 input.
|
||||
|
||||
config ETRAX_SERIAL_PORT2_DMA3_IN
|
||||
bool "Ser2 uses DMA3 for input"
|
||||
depends on ETRAXFS || ETRAX_ARCH_V10
|
||||
help
|
||||
Enables the DMA3 input channel for ser2 (ttyS2).
|
||||
If you do not enable DMA, an interrupt for each character will be
|
||||
used when receiving data.
|
||||
Normally you want to use DMA, unless you use the DMA channel for
|
||||
something else.
|
||||
|
||||
config ETRAX_SERIAL_PORT2_DMA7_IN
|
||||
bool "Ser2 uses DMA7 for input"
|
||||
depends on CRIS_MACH_ARTPEC3
|
||||
help
|
||||
Enables the DMA7 input channel for ser2 (ttyS2).
|
||||
If you do not enable DMA, an interrupt for each character will be
|
||||
used when receiving data.
|
||||
Normally you want to use DMA, unless you use the DMA channel for
|
||||
something else.
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Ser3 DMA in channel"
|
||||
depends on ETRAX_SERIAL_PORT3
|
||||
default ETRAX_SERIAL_PORT3_NO_DMA_IN if ETRAX_ARCH_V32
|
||||
default ETRAX_SERIAL_PORT3_DMA5_IN if ETRAX_ARCH_V10
|
||||
help
|
||||
What DMA channel to use for ser3.
|
||||
|
||||
config ETRAX_SERIAL_PORT3_NO_DMA_IN
|
||||
bool "Ser3 uses no DMA for input"
|
||||
help
|
||||
Do not use DMA for ser3 input.
|
||||
|
||||
config ETRAX_SERIAL_PORT3_DMA5_IN
|
||||
depends on ETRAX_ARCH_V10
|
||||
bool "DMA 5"
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Ser3 DMA out channel"
|
||||
depends on ETRAX_SERIAL_PORT3
|
||||
default ETRAX_SERIAL_PORT3_NO_DMA_OUT if ETRAX_ARCH_V32
|
||||
default ETRAX_SERIAL_PORT3_DMA4_OUT if ETRAX_ARCH_V10
|
||||
|
||||
config ETRAX_SERIAL_PORT3_NO_DMA_OUT
|
||||
bool "Ser3 uses no DMA for output"
|
||||
help
|
||||
Do not use DMA for ser3 output.
|
||||
|
||||
config ETRAX_SERIAL_PORT3_DMA4_OUT
|
||||
depends on ETRAX_ARCH_V10
|
||||
bool "DMA 4"
|
||||
|
||||
endchoice
|
||||
|
||||
endmenu
|
||||
|
||||
source "drivers/Kconfig"
|
||||
|
||||
source "fs/Kconfig"
|
||||
|
||||
source "arch/cris/Kconfig.debug"
|
||||
|
||||
source "security/Kconfig"
|
||||
|
||||
source "crypto/Kconfig"
|
||||
|
||||
source "lib/Kconfig"
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
menu "Kernel hacking"
|
||||
|
||||
config PROFILING
|
||||
bool "Kernel profiling support"
|
||||
|
||||
config SYSTEM_PROFILER
|
||||
bool "System profiling support"
|
||||
|
||||
source "lib/Kconfig.debug"
|
||||
|
||||
config ETRAX_KGDB
|
||||
bool "Use kernel GDB debugger"
|
||||
depends on DEBUG_KERNEL
|
||||
---help---
|
||||
The CRIS version of gdb can be used to remotely debug a running
|
||||
Linux kernel via the serial debug port. Provided you have gdb-cris
|
||||
installed, run gdb-cris vmlinux, then type
|
||||
|
||||
(gdb) set remotebaud 115200 <- kgdb uses 115200 as default
|
||||
(gdb) target remote /dev/ttyS0 <- maybe you use another port
|
||||
|
||||
This should connect you to your booted kernel (or boot it now if you
|
||||
didn't before). The kernel halts when it boots, waiting for gdb if
|
||||
this option is turned on!
|
||||
|
||||
|
||||
config DEBUG_NMI_OOPS
|
||||
bool "NMI causes oops printout"
|
||||
depends on DEBUG_KERNEL
|
||||
help
|
||||
If the system locks up without any debug information you can say Y
|
||||
here to make it possible to dump an OOPS with an external NMI.
|
||||
|
||||
config NO_SEGFAULT_TERMINATION
|
||||
bool "Keep segfaulting processes"
|
||||
help
|
||||
Place segfaulting user mode processes on a wait queue instead of
|
||||
delivering a terminating SIGSEGV to allow debugging with gdb.
|
||||
|
||||
endmenu
|
||||
|
|
@ -1,104 +0,0 @@
|
|||
#
|
||||
# cris/Makefile
|
||||
#
|
||||
# This file is included by the global makefile so that you can add your own
|
||||
# architecture-specific flags and dependencies. Remember to do have actions
|
||||
# for "archclean" and "archdep" for cleaning up and making dependencies for
|
||||
# this architecture
|
||||
#
|
||||
# This file is subject to the terms and conditions of the GNU General Public
|
||||
# License. See the file "COPYING" in the main directory of this archive
|
||||
# for more details.
|
||||
|
||||
KBUILD_DEFCONFIG := etrax-100lx_v2_defconfig
|
||||
|
||||
arch-y := v10
|
||||
arch-$(CONFIG_ETRAX_ARCH_V10) := v10
|
||||
arch-$(CONFIG_ETRAX_ARCH_V32) := v32
|
||||
|
||||
# No config available for make clean etc
|
||||
mach-y := fs
|
||||
mach-$(CONFIG_CRIS_MACH_ARTPEC3) := a3
|
||||
mach-$(CONFIG_ETRAXFS) := fs
|
||||
|
||||
ifneq ($(arch-y),)
|
||||
SARCH := arch-$(arch-y)
|
||||
inc := -Iarch/cris/include/uapi/$(SARCH)
|
||||
inc += -Iarch/cris/include/$(SARCH)
|
||||
inc += -Iarch/cris/include/uapi/$(SARCH)/arch
|
||||
inc += -Iarch/cris/include/$(SARCH)/arch
|
||||
else
|
||||
SARCH :=
|
||||
inc :=
|
||||
endif
|
||||
|
||||
ifneq ($(mach-y),)
|
||||
MACH := mach-$(mach-y)
|
||||
inc += -Iarch/cris/include/$(SARCH)/$(MACH)/
|
||||
inc += -Iarch/cris/include/$(SARCH)/$(MACH)/mach
|
||||
else
|
||||
MACH :=
|
||||
endif
|
||||
|
||||
ifneq ($(CONFIG_BUILTIN_DTB),"")
|
||||
core-$(CONFIG_OF) += arch/cris/boot/dts/
|
||||
endif
|
||||
|
||||
LD = $(CROSS_COMPILE)ld -mcrislinux
|
||||
|
||||
OBJCOPYFLAGS := -O binary -R .note -R .comment -S
|
||||
|
||||
KBUILD_AFLAGS += -mlinux -march=$(arch-y) $(inc)
|
||||
KBUILD_CFLAGS += -mlinux -march=$(arch-y) -pipe $(inc)
|
||||
KBUILD_CPPFLAGS += $(inc)
|
||||
|
||||
ifdef CONFIG_FRAME_POINTER
|
||||
KBUILD_CFLAGS := $(subst -fomit-frame-pointer,,$(KBUILD_CFLAGS)) -g
|
||||
KBUILD_CFLAGS += -fno-omit-frame-pointer
|
||||
endif
|
||||
|
||||
head-y := arch/cris/$(SARCH)/kernel/head.o
|
||||
|
||||
LIBGCC = $(shell $(CC) $(KBUILD_CFLAGS) -print-file-name=libgcc.a)
|
||||
|
||||
core-y += arch/cris/kernel/ arch/cris/mm/
|
||||
core-y += arch/cris/$(SARCH)/kernel/ arch/cris/$(SARCH)/mm/
|
||||
ifdef CONFIG_ETRAX_ARCH_V32
|
||||
core-y += arch/cris/$(SARCH)/$(MACH)/
|
||||
endif
|
||||
drivers-y += arch/cris/$(SARCH)/drivers/
|
||||
libs-y += arch/cris/$(SARCH)/lib/ $(LIBGCC)
|
||||
|
||||
# cris source path
|
||||
SRC_ARCH = $(srctree)/arch/cris
|
||||
# cris object files path
|
||||
OBJ_ARCH = $(objtree)/arch/cris
|
||||
|
||||
boot := arch/cris/boot
|
||||
MACHINE := arch/cris/$(SARCH)
|
||||
|
||||
all: zImage
|
||||
|
||||
zImage Image: vmlinux
|
||||
$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
|
||||
|
||||
archprepare:
|
||||
|
||||
archclean:
|
||||
$(Q)if [ -e arch/cris/boot ]; then \
|
||||
$(MAKE) $(clean)=arch/cris/boot; \
|
||||
fi
|
||||
|
||||
CLEAN_FILES += \
|
||||
$(boot)/zImage \
|
||||
$(boot)/compressed/decompress.bin \
|
||||
$(boot)/compressed/piggy.gz \
|
||||
$(boot)/rescue/rescue.bin
|
||||
|
||||
|
||||
# MRPROPER_FILES +=
|
||||
|
||||
define archhelp
|
||||
echo '* zImage - Compressed kernel image (arch/cris/boot/zImage)'
|
||||
echo '* Image - Uncompressed kernel image (arch/cris/boot/Image)'
|
||||
endef
|
||||
|
|
@ -1,399 +0,0 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
if ETRAX_ARCH_V10
|
||||
|
||||
menu "CRIS v10 options"
|
||||
|
||||
# ETRAX 100LX v1 has a MMU "feature" requiring a low mapping
|
||||
config CRIS_LOW_MAP
|
||||
bool
|
||||
depends on ETRAX_ARCH_V10 && ETRAX100LX
|
||||
default y
|
||||
|
||||
config ETRAX_DRAM_VIRTUAL_BASE
|
||||
hex
|
||||
depends on ETRAX_ARCH_V10
|
||||
default "c0000000" if !ETRAX100LX
|
||||
default "60000000" if ETRAX100LX
|
||||
|
||||
choice
|
||||
prompt "Product LED port"
|
||||
depends on ETRAX_ARCH_V10
|
||||
default ETRAX_PA_LEDS
|
||||
|
||||
config ETRAX_PA_LEDS
|
||||
bool "Port-PA-LEDs"
|
||||
help
|
||||
The ETRAX network driver is responsible for flashing LED's when
|
||||
packets arrive and are sent. It uses macros defined in
|
||||
<file:arch/cris/include/asm/io.h>, and those macros are defined after
|
||||
what YOU choose in this option. The actual bits used are configured
|
||||
separately. Select this if the LEDs are on port PA. Some products
|
||||
put the leds on PB or a memory-mapped latch (CSP0) instead.
|
||||
|
||||
config ETRAX_PB_LEDS
|
||||
bool "Port-PB-LEDs"
|
||||
help
|
||||
The ETRAX network driver is responsible for flashing LED's when
|
||||
packets arrive and are sent. It uses macros defined in
|
||||
<file:arch/cris/include/asm/io.h>, and those macros are defined after
|
||||
what YOU choose in this option. The actual bits used are configured
|
||||
separately. Select this if the LEDs are on port PB. Some products
|
||||
put the leds on PA or a memory-mapped latch (CSP0) instead.
|
||||
|
||||
config ETRAX_CSP0_LEDS
|
||||
bool "Port-CSP0-LEDs"
|
||||
help
|
||||
The ETRAX network driver is responsible for flashing LED's when
|
||||
packets arrive and are sent. It uses macros defined in
|
||||
<file:arch/cris/include/asm/io.h>, and those macros are defined after
|
||||
what YOU choose in this option. The actual bits used are configured
|
||||
separately. Select this if the LEDs are on a memory-mapped latch
|
||||
using chip select CSP0, this is mapped at 0x90000000.
|
||||
Some products put the leds on PA or PB instead.
|
||||
|
||||
config ETRAX_NO_LEDS
|
||||
bool "None"
|
||||
help
|
||||
Select this option if you don't have any LED at all.
|
||||
|
||||
endchoice
|
||||
|
||||
config ETRAX_LED1G
|
||||
int "First green LED bit"
|
||||
depends on ETRAX_ARCH_V10 && !ETRAX_NO_LEDS
|
||||
default "2"
|
||||
help
|
||||
Bit to use for the first green LED.
|
||||
Most Axis products use bit 2 here.
|
||||
|
||||
config ETRAX_LED1R
|
||||
int "First red LED bit"
|
||||
depends on ETRAX_ARCH_V10 && !ETRAX_NO_LEDS
|
||||
default "3"
|
||||
help
|
||||
Bit to use for the first red LED.
|
||||
Most Axis products use bit 3 here.
|
||||
For products with only one controllable LED,
|
||||
set this to same as CONFIG_ETRAX_LED1G (normally 2).
|
||||
|
||||
config ETRAX_LED2G
|
||||
int "Second green LED bit"
|
||||
depends on ETRAX_ARCH_V10 && !ETRAX_NO_LEDS
|
||||
default "4"
|
||||
help
|
||||
Bit to use for the second green LED. The "Active" LED.
|
||||
Most Axis products use bit 4 here.
|
||||
For products with only one controllable LED,
|
||||
set this to same as CONFIG_ETRAX_LED1G (normally 2).
|
||||
|
||||
config ETRAX_LED2R
|
||||
int "Second red LED bit"
|
||||
depends on ETRAX_ARCH_V10 && !ETRAX_NO_LEDS
|
||||
default "5"
|
||||
help
|
||||
Bit to use for the second red LED.
|
||||
Most Axis products use bit 5 here.
|
||||
For products with only one controllable LED,
|
||||
set this to same as CONFIG_ETRAX_LED1G (normally 2).
|
||||
|
||||
config ETRAX_LED3G
|
||||
int "Third green LED bit"
|
||||
depends on ETRAX_ARCH_V10 && !ETRAX_NO_LEDS
|
||||
default "2"
|
||||
help
|
||||
Bit to use for the third green LED. The "Drive" LED.
|
||||
For products with only one or two controllable LEDs,
|
||||
set this to same as CONFIG_ETRAX_LED1G (normally 2).
|
||||
|
||||
config ETRAX_LED3R
|
||||
int "Third red LED bit"
|
||||
depends on ETRAX_ARCH_V10 && !ETRAX_NO_LEDS
|
||||
default "2"
|
||||
help
|
||||
Bit to use for the third red LED.
|
||||
For products with only one or two controllable LEDs,
|
||||
set this to same as CONFIG_ETRAX_LED1G (normally 2).
|
||||
|
||||
config ETRAX_LED4R
|
||||
int "Fourth red LED bit"
|
||||
depends on ETRAX_CSP0_LEDS
|
||||
default "2"
|
||||
help
|
||||
Bit to use for the fourth red LED.
|
||||
For products with only one or two controllable LEDs,
|
||||
set this to same as CONFIG_ETRAX_LED1G (normally 2).
|
||||
|
||||
config ETRAX_LED4G
|
||||
int "Fourth green LED bit"
|
||||
depends on ETRAX_CSP0_LEDS
|
||||
default "2"
|
||||
help
|
||||
Bit to use for the fourth green LED.
|
||||
For products with only one or two controllable LEDs,
|
||||
set this to same as CONFIG_ETRAX_LED1G (normally 2).
|
||||
|
||||
config ETRAX_LED5R
|
||||
int "Fifth red LED bit"
|
||||
depends on ETRAX_CSP0_LEDS
|
||||
default "2"
|
||||
help
|
||||
Bit to use for the fifth red LED.
|
||||
For products with only one or two controllable LEDs,
|
||||
set this to same as CONFIG_ETRAX_LED1G (normally 2).
|
||||
|
||||
config ETRAX_LED5G
|
||||
int "Fifth green LED bit"
|
||||
depends on ETRAX_CSP0_LEDS
|
||||
default "2"
|
||||
help
|
||||
Bit to use for the fifth green LED.
|
||||
For products with only one or two controllable LEDs,
|
||||
set this to same as CONFIG_ETRAX_LED1G (normally 2).
|
||||
|
||||
config ETRAX_LED6R
|
||||
int "Sixth red LED bit"
|
||||
depends on ETRAX_CSP0_LEDS
|
||||
default "2"
|
||||
help
|
||||
Bit to use for the sixth red LED.
|
||||
For products with only one or two controllable LEDs,
|
||||
set this to same as CONFIG_ETRAX_LED1G (normally 2).
|
||||
|
||||
config ETRAX_LED6G
|
||||
int "Sixth green LED bit"
|
||||
depends on ETRAX_CSP0_LEDS
|
||||
default "2"
|
||||
help
|
||||
Bit to use for the sixth green LED. The "Drive" LED.
|
||||
For products with only one or two controllable LEDs,
|
||||
set this to same as CONFIG_ETRAX_LED1G (normally 2).
|
||||
|
||||
config ETRAX_LED7R
|
||||
int "Seventh red LED bit"
|
||||
depends on ETRAX_CSP0_LEDS
|
||||
default "2"
|
||||
help
|
||||
Bit to use for the seventh red LED.
|
||||
For products with only one or two controllable LEDs,
|
||||
set this to same as CONFIG_ETRAX_LED1G (normally 2).
|
||||
|
||||
config ETRAX_LED7G
|
||||
int "Seventh green LED bit"
|
||||
depends on ETRAX_CSP0_LEDS
|
||||
default "2"
|
||||
help
|
||||
Bit to use for the seventh green LED.
|
||||
For products with only one or two controllable LEDs,
|
||||
set this to same as CONFIG_ETRAX_LED1G (normally 2).
|
||||
|
||||
config ETRAX_LED8Y
|
||||
int "Eighth yellow LED bit"
|
||||
depends on ETRAX_CSP0_LEDS
|
||||
default "2"
|
||||
help
|
||||
Bit to use for the eighth yellow LED. The "Drive" LED.
|
||||
For products with only one or two controllable LEDs,
|
||||
set this to same as CONFIG_ETRAX_LED1G (normally 2).
|
||||
|
||||
config ETRAX_LED9Y
|
||||
int "Ninth yellow LED bit"
|
||||
depends on ETRAX_CSP0_LEDS
|
||||
default "2"
|
||||
help
|
||||
Bit to use for the ninth yellow LED.
|
||||
For products with only one or two controllable LEDs,
|
||||
set this to same as CONFIG_ETRAX_LED1G (normally 2).
|
||||
|
||||
config ETRAX_LED10Y
|
||||
int "Tenth yellow LED bit"
|
||||
depends on ETRAX_CSP0_LEDS
|
||||
default "2"
|
||||
help
|
||||
Bit to use for the tenth yellow LED.
|
||||
For products with only one or two controllable LEDs,
|
||||
set this to same as CONFIG_ETRAX_LED1G (normally 2).
|
||||
|
||||
config ETRAX_LED11Y
|
||||
int "Eleventh yellow LED bit"
|
||||
depends on ETRAX_CSP0_LEDS
|
||||
default "2"
|
||||
help
|
||||
Bit to use for the eleventh yellow LED.
|
||||
For products with only one or two controllable LEDs,
|
||||
set this to same as CONFIG_ETRAX_LED1G (normally 2).
|
||||
|
||||
config ETRAX_LED12R
|
||||
int "Twelfth red LED bit"
|
||||
depends on ETRAX_CSP0_LEDS
|
||||
default "2"
|
||||
help
|
||||
Bit to use for the twelfth red LED.
|
||||
For products with only one or two controllable LEDs,
|
||||
set this to same as CONFIG_ETRAX_LED1G (normally 2).
|
||||
|
||||
|
||||
choice
|
||||
prompt "Product rescue-port"
|
||||
depends on ETRAX_ARCH_V10
|
||||
default ETRAX_RESCUE_SER0
|
||||
|
||||
config ETRAX_RESCUE_SER0
|
||||
bool "Serial-0"
|
||||
help
|
||||
Select one of the four serial ports as a rescue port. The default
|
||||
is port 0.
|
||||
|
||||
config ETRAX_RESCUE_SER1
|
||||
bool "Serial-1"
|
||||
help
|
||||
Use serial port 1 as the rescue port.
|
||||
|
||||
config ETRAX_RESCUE_SER2
|
||||
bool "Serial-2"
|
||||
help
|
||||
Use serial port 2 as the rescue port.
|
||||
|
||||
config ETRAX_RESCUE_SER3
|
||||
bool "Serial-3"
|
||||
help
|
||||
Use serial port 3 as the rescue port.
|
||||
|
||||
endchoice
|
||||
|
||||
config ETRAX_DEF_R_WAITSTATES
|
||||
hex "R_WAITSTATES"
|
||||
depends on ETRAX_ARCH_V10
|
||||
default "95a6"
|
||||
help
|
||||
Waitstates for SRAM, Flash and peripherals (not DRAM). 95f8 is a
|
||||
good choice for most Axis products...
|
||||
|
||||
config ETRAX_DEF_R_BUS_CONFIG
|
||||
hex "R_BUS_CONFIG"
|
||||
depends on ETRAX_ARCH_V10
|
||||
default "104"
|
||||
help
|
||||
Assorted bits controlling write mode, DMA burst length etc. 104 is
|
||||
a good choice for most Axis products...
|
||||
|
||||
config ETRAX_SDRAM
|
||||
bool "SDRAM support"
|
||||
depends on ETRAX_ARCH_V10
|
||||
help
|
||||
Enable this if you use SDRAM chips and configure
|
||||
R_SDRAM_CONFIG and R_SDRAM_TIMING as well.
|
||||
|
||||
config ETRAX_DEF_R_DRAM_CONFIG
|
||||
hex "R_DRAM_CONFIG"
|
||||
depends on ETRAX_ARCH_V10 && !ETRAX_SDRAM
|
||||
default "1a200040"
|
||||
help
|
||||
The R_DRAM_CONFIG register specifies everything on how the DRAM
|
||||
chips in the system are connected to the ETRAX CPU. This is
|
||||
different depending on the manufacturer, chip type and number of
|
||||
chips. So this value often needs to be different for each Axis
|
||||
product.
|
||||
|
||||
config ETRAX_DEF_R_DRAM_TIMING
|
||||
hex "R_DRAM_TIMING"
|
||||
depends on ETRAX_ARCH_V10 && !ETRAX_SDRAM
|
||||
default "5611"
|
||||
help
|
||||
Different DRAM chips have different speeds. Current Axis products
|
||||
use 50ns DRAM chips which can use the timing: 5611.
|
||||
|
||||
config ETRAX_DEF_R_SDRAM_CONFIG
|
||||
hex "R_SDRAM_CONFIG"
|
||||
depends on ETRAX_ARCH_V10 && ETRAX_SDRAM
|
||||
default "d2fa7878"
|
||||
help
|
||||
The R_SDRAM_CONFIG register specifies everything on how the SDRAM
|
||||
chips in the system are connected to the ETRAX CPU. This is
|
||||
different depending on the manufacturer, chip type and number of
|
||||
chips. So this value often needs to be different for each Axis
|
||||
product.
|
||||
|
||||
config ETRAX_DEF_R_SDRAM_TIMING
|
||||
hex "R_SDRAM_TIMING"
|
||||
depends on ETRAX_ARCH_V10 && ETRAX_SDRAM
|
||||
default "80004801"
|
||||
help
|
||||
Different SDRAM chips have different timing.
|
||||
|
||||
config ETRAX_DEF_R_PORT_PA_DIR
|
||||
hex "R_PORT_PA_DIR"
|
||||
depends on ETRAX_ARCH_V10
|
||||
default "1c"
|
||||
help
|
||||
Configures the direction of general port A bits. 1 is out, 0 is in.
|
||||
This is often totally different depending on the product used.
|
||||
There are some guidelines though - if you know that only LED's are
|
||||
connected to port PA, then they are usually connected to bits 2-4
|
||||
and you can therefore use 1c. On other boards which don't have the
|
||||
LED's at the general ports, these bits are used for all kinds of
|
||||
stuff. If you don't know what to use, it is always safe to put all
|
||||
as inputs, although floating inputs isn't good.
|
||||
|
||||
config ETRAX_DEF_R_PORT_PA_DATA
|
||||
hex "R_PORT_PA_DATA"
|
||||
depends on ETRAX_ARCH_V10
|
||||
default "00"
|
||||
help
|
||||
Configures the initial data for the general port A bits. Most
|
||||
products should use 00 here.
|
||||
|
||||
config ETRAX_DEF_R_PORT_PB_CONFIG
|
||||
hex "R_PORT_PB_CONFIG"
|
||||
depends on ETRAX_ARCH_V10
|
||||
default "00"
|
||||
help
|
||||
Configures the type of the general port B bits. 1 is chip select,
|
||||
0 is port. Most products should use 00 here.
|
||||
|
||||
config ETRAX_DEF_R_PORT_PB_DIR
|
||||
hex "R_PORT_PB_DIR"
|
||||
depends on ETRAX_ARCH_V10
|
||||
default "00"
|
||||
help
|
||||
Configures the direction of general port B bits. 1 is out, 0 is in.
|
||||
This is often totally different depending on the product used. Bits
|
||||
0 and 1 on port PB are usually used for I2C communication, but the
|
||||
kernel I2C driver sets the appropriate directions itself so you
|
||||
don't need to take that into consideration when setting this option.
|
||||
If you don't know what to use, it is always safe to put all as
|
||||
inputs.
|
||||
|
||||
config ETRAX_DEF_R_PORT_PB_DATA
|
||||
hex "R_PORT_PB_DATA"
|
||||
depends on ETRAX_ARCH_V10
|
||||
default "ff"
|
||||
help
|
||||
Configures the initial data for the general port A bits. Most
|
||||
products should use FF here.
|
||||
|
||||
config ETRAX_SOFT_SHUTDOWN
|
||||
bool "Software Shutdown Support"
|
||||
depends on ETRAX_ARCH_V10
|
||||
help
|
||||
Enable this if ETRAX is used with a power-supply that can be turned
|
||||
off and on with PS_ON signal. Gives the possibility to detect
|
||||
powerbutton and then do a power off after unmounting disks.
|
||||
|
||||
config ETRAX_SHUTDOWN_BIT
|
||||
int "Shutdown bit on port CSP0"
|
||||
depends on ETRAX_SOFT_SHUTDOWN
|
||||
default "12"
|
||||
help
|
||||
Configure what pin on CSPO-port that is used for controlling power
|
||||
supply.
|
||||
|
||||
config ETRAX_POWERBUTTON_BIT
|
||||
int "Power button bit on port G"
|
||||
depends on ETRAX_SOFT_SHUTDOWN
|
||||
default "25"
|
||||
help
|
||||
Configure where power button is connected.
|
||||
|
||||
endmenu
|
||||
|
||||
endif
|
||||
|
|
@ -1,244 +0,0 @@
|
|||
Memory management for CRIS/MMU
|
||||
------------------------------
|
||||
HISTORY:
|
||||
|
||||
$Log: README.mm,v $
|
||||
Revision 1.1 2001/12/17 13:59:27 bjornw
|
||||
Initial revision
|
||||
|
||||
Revision 1.1 2000/07/10 16:25:21 bjornw
|
||||
Initial revision
|
||||
|
||||
Revision 1.4 2000/01/17 02:31:59 bjornw
|
||||
Added discussion of paging and VM.
|
||||
|
||||
Revision 1.3 1999/12/03 16:43:23 hp
|
||||
Blurb about that the 3.5G-limitation is not a MMU limitation
|
||||
|
||||
Revision 1.2 1999/12/03 16:04:21 hp
|
||||
Picky comment about not mapping the first page
|
||||
|
||||
Revision 1.1 1999/12/03 15:41:30 bjornw
|
||||
First version of CRIS/MMU memory layout specification.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
------------------------------
|
||||
|
||||
See the ETRAX-NG HSDD for reference.
|
||||
|
||||
We use the page-size of 8 kbytes, as opposed to the i386 page-size of 4 kbytes.
|
||||
|
||||
The MMU can, apart from the normal mapping of pages, also do a top-level
|
||||
segmentation of the kernel memory space. We use this feature to avoid having
|
||||
to use page-tables to map the physical memory into the kernel's address
|
||||
space. We also use it to keep the user-mode virtual mapping in the same
|
||||
map during kernel-mode, so that the kernel easily can access the corresponding
|
||||
user-mode process' data.
|
||||
|
||||
As a comparison, the Linux/i386 2.0 puts the kernel and physical RAM at
|
||||
address 0, overlapping with the user-mode virtual space, so that descriptor
|
||||
registers are needed for each memory access to specify which MMU space to
|
||||
map through. That changed in 2.2, putting the kernel/physical RAM at
|
||||
0xc0000000, to co-exist with the user-mode mapping. We will do something
|
||||
quite similar, but with the additional complexity of having to map the
|
||||
internal chip I/O registers and the flash memory area (including SRAM
|
||||
and peripherial chip-selets).
|
||||
|
||||
The kernel-mode segmentation map:
|
||||
|
||||
------------------------ ------------------------
|
||||
FFFFFFFF| | => cached | |
|
||||
| kernel seg_f | flash | |
|
||||
F0000000|______________________| | |
|
||||
EFFFFFFF| | => uncached | |
|
||||
| kernel seg_e | flash | |
|
||||
E0000000|______________________| | DRAM |
|
||||
DFFFFFFF| | paged to any | Un-cached |
|
||||
| kernel seg_d | =======> | |
|
||||
D0000000|______________________| | |
|
||||
CFFFFFFF| | | |
|
||||
| kernel seg_c |==\ | |
|
||||
C0000000|______________________| \ |______________________|
|
||||
BFFFFFFF| | uncached | |
|
||||
| kernel seg_b |=====\=========>| Registers |
|
||||
B0000000|______________________| \c |______________________|
|
||||
AFFFFFFF| | \a | |
|
||||
| | \c | FLASH/SRAM/Peripheral|
|
||||
| | \h |______________________|
|
||||
| | \e | |
|
||||
| | \d | |
|
||||
| kernel seg_0 - seg_a | \==>| DRAM |
|
||||
| | | Cached |
|
||||
| | paged to any | |
|
||||
| | =======> |______________________|
|
||||
| | | |
|
||||
| | | Illegal |
|
||||
| | |______________________|
|
||||
| | | |
|
||||
| | | FLASH/SRAM/Peripheral|
|
||||
00000000|______________________| |______________________|
|
||||
|
||||
In user-mode it looks the same except that only the space 0-AFFFFFFF is
|
||||
available. Therefore, in this model, the virtual address space per process
|
||||
is limited to 0xb0000000 bytes (minus 8192 bytes, since the first page,
|
||||
0..8191, is never mapped, in order to trap NULL references).
|
||||
|
||||
It also means that the total physical RAM that can be mapped is 256 MB
|
||||
(kseg_c above). More RAM can be mapped by choosing a different segmentation
|
||||
and shrinking the user-mode memory space.
|
||||
|
||||
The MMU can map all 4 GB in user mode, but doing that would mean that a
|
||||
few extra instructions would be needed for each access to user mode
|
||||
memory.
|
||||
|
||||
The kernel needs access to both cached and uncached flash. Uncached is
|
||||
necessary because of the special write/erase sequences. Also, the
|
||||
peripherial chip-selects are decoded from that region.
|
||||
|
||||
The kernel also needs its own virtual memory space. That is kseg_d. It
|
||||
is used by the vmalloc() kernel function to allocate virtual contiguous
|
||||
chunks of memory not possible using the normal kmalloc physical RAM
|
||||
allocator.
|
||||
|
||||
The setting of the actual MMU control registers to use this layout would
|
||||
be something like this:
|
||||
|
||||
R_MMU_KSEG = ( ( seg_f, seg ) | // Flash cached
|
||||
( seg_e, seg ) | // Flash uncached
|
||||
( seg_d, page ) | // kernel vmalloc area
|
||||
( seg_c, seg ) | // kernel linear segment
|
||||
( seg_b, seg ) | // kernel linear segment
|
||||
( seg_a, page ) |
|
||||
( seg_9, page ) |
|
||||
( seg_8, page ) |
|
||||
( seg_7, page ) |
|
||||
( seg_6, page ) |
|
||||
( seg_5, page ) |
|
||||
( seg_4, page ) |
|
||||
( seg_3, page ) |
|
||||
( seg_2, page ) |
|
||||
( seg_1, page ) |
|
||||
( seg_0, page ) );
|
||||
|
||||
R_MMU_KBASE_HI = ( ( base_f, 0x0 ) | // flash/sram/periph cached
|
||||
( base_e, 0x8 ) | // flash/sram/periph uncached
|
||||
( base_d, 0x0 ) | // don't care
|
||||
( base_c, 0x4 ) | // physical RAM cached area
|
||||
( base_b, 0xb ) | // uncached on-chip registers
|
||||
( base_a, 0x0 ) | // don't care
|
||||
( base_9, 0x0 ) | // don't care
|
||||
( base_8, 0x0 ) ); // don't care
|
||||
|
||||
R_MMU_KBASE_LO = ( ( base_7, 0x0 ) | // don't care
|
||||
( base_6, 0x0 ) | // don't care
|
||||
( base_5, 0x0 ) | // don't care
|
||||
( base_4, 0x0 ) | // don't care
|
||||
( base_3, 0x0 ) | // don't care
|
||||
( base_2, 0x0 ) | // don't care
|
||||
( base_1, 0x0 ) | // don't care
|
||||
( base_0, 0x0 ) ); // don't care
|
||||
|
||||
NOTE: while setting up the MMU, we run in a non-mapped mode in the DRAM (0x40
|
||||
segment) and need to setup the seg_4 to a unity mapping, so that we don't get
|
||||
a fault before we have had time to jump into the real kernel segment (0xc0). This
|
||||
is done in head.S temporarily, but fixed by the kernel later in paging_init.
|
||||
|
||||
|
||||
Paging - PTE's, PMD's and PGD's
|
||||
-------------------------------
|
||||
|
||||
[ References: asm/pgtable.h, asm/page.h, asm/mmu.h ]
|
||||
|
||||
The paging mechanism uses virtual addresses to split a process memory-space into
|
||||
pages, a page being the smallest unit that can be freely remapped in memory. On
|
||||
Linux/CRIS, a page is 8192 bytes (for technical reasons not equal to 4096 as in
|
||||
most other 32-bit architectures). It would be inefficient to let a virtual memory
|
||||
mapping be controlled by a long table of page mappings, so it is broken down into
|
||||
a 2-level structure with a Page Directory containing pointers to Page Tables which
|
||||
each have maps of up to 2048 pages (8192 / sizeof(void *)). Linux can actually
|
||||
handle 3-level structures as well, with a Page Middle Directory in between, but
|
||||
in many cases, this is folded into a two-level structure by excluding the Middle
|
||||
Directory.
|
||||
|
||||
We'll take a look at how an address is translated while we discuss how it's handled
|
||||
in the Linux kernel.
|
||||
|
||||
The example address is 0xd004000c; in binary this is:
|
||||
|
||||
31 23 15 7 0
|
||||
11010000 00000100 00000000 00001100
|
||||
|
||||
|______| |__________||____________|
|
||||
PGD PTE page offset
|
||||
|
||||
Given the top-level Page Directory, the offset in that directory is calculated
|
||||
using the upper 8 bits:
|
||||
|
||||
static inline pgd_t * pgd_offset(struct mm_struct * mm, unsigned long address)
|
||||
{
|
||||
return mm->pgd + (address >> PGDIR_SHIFT);
|
||||
}
|
||||
|
||||
PGDIR_SHIFT is the log2 of the amount of memory an entry in the PGD can map; in our
|
||||
case it is 24, corresponding to 16 MB. This means that each entry in the PGD
|
||||
corresponds to 16 MB of virtual memory.
|
||||
|
||||
The pgd_t from our example will therefore be the 208'th (0xd0) entry in mm->pgd.
|
||||
|
||||
Since the Middle Directory does not exist, it is a unity mapping:
|
||||
|
||||
static inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
|
||||
{
|
||||
return (pmd_t *) dir;
|
||||
}
|
||||
|
||||
The Page Table provides the final lookup by using bits 13 to 23 as index:
|
||||
|
||||
static inline pte_t * pte_offset(pmd_t * dir, unsigned long address)
|
||||
{
|
||||
return (pte_t *) pmd_page(*dir) + ((address >> PAGE_SHIFT) &
|
||||
(PTRS_PER_PTE - 1));
|
||||
}
|
||||
|
||||
PAGE_SHIFT is the log2 of the size of a page; 13 in our case. PTRS_PER_PTE is
|
||||
the number of pointers that fit in a Page Table and is used to mask off the
|
||||
PGD-part of the address.
|
||||
|
||||
The so-far unused bits 0 to 12 are used to index inside a page linearily.
|
||||
|
||||
The VM system
|
||||
-------------
|
||||
|
||||
The kernels own page-directory is the swapper_pg_dir, cleared in paging_init,
|
||||
and contains the kernels virtual mappings (the kernel itself is not paged - it
|
||||
is mapped linearily using kseg_c as described above). Architectures without
|
||||
kernel segments like the i386, need to setup swapper_pg_dir directly in head.S
|
||||
to map the kernel itself. swapper_pg_dir is pointed to by init_mm.pgd as the
|
||||
init-task's PGD.
|
||||
|
||||
To see what support functions are used to setup a page-table, let's look at the
|
||||
kernel's internal paged memory system, vmalloc/vfree.
|
||||
|
||||
void * vmalloc(unsigned long size)
|
||||
|
||||
The vmalloc-system keeps a paged segment in kernel-space at 0xd0000000. What
|
||||
happens first is that a virtual address chunk is allocated to the request using
|
||||
get_vm_area(size). After that, physical RAM pages are allocated and put into
|
||||
the kernel's page-table using alloc_area_pages(addr, size).
|
||||
|
||||
static int alloc_area_pages(unsigned long address, unsigned long size)
|
||||
|
||||
First the PGD entry is found using init_mm.pgd. This is passed to
|
||||
alloc_area_pmd (remember the 3->2 folding). It uses pte_alloc_kernel to
|
||||
check if the PGD entry points anywhere - if not, a page table page is
|
||||
allocated and the PGD entry updated. Then the alloc_area_pte function is
|
||||
used just like alloc_area_pmd to check which page table entry is desired,
|
||||
and a physical page is allocated and the table entry updated. All of this
|
||||
is repeated at the top-level until the entire address range specified has
|
||||
been mapped.
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,561 +0,0 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
if ETRAX_ARCH_V10
|
||||
|
||||
config ETRAX_ETHERNET
|
||||
bool "Ethernet support"
|
||||
depends on ETRAX_ARCH_V10 && NETDEVICES
|
||||
select MII
|
||||
help
|
||||
This option enables the ETRAX 100LX built-in 10/100Mbit Ethernet
|
||||
controller.
|
||||
|
||||
config ETRAX_SERIAL
|
||||
bool "Serial-port support"
|
||||
depends on ETRAX_ARCH_V10
|
||||
help
|
||||
Enables the ETRAX 100 serial driver for ser0 (ttyS0)
|
||||
You probably want this enabled.
|
||||
|
||||
config ETRAX_SERIAL_FAST_TIMER
|
||||
bool "Use fast timers for serial DMA flush (experimental)"
|
||||
depends on ETRAX_SERIAL
|
||||
help
|
||||
Select this to have the serial DMAs flushed at a higher rate than
|
||||
normally, possible by using the fast timer API, the timeout is
|
||||
approx. 4 character times.
|
||||
If unsure, say N.
|
||||
|
||||
config ETRAX_SERIAL_FLUSH_DMA_FAST
|
||||
bool "Fast serial port DMA flush"
|
||||
depends on ETRAX_SERIAL && !ETRAX_SERIAL_FAST_TIMER
|
||||
help
|
||||
Select this to have the serial DMAs flushed at a higher rate than
|
||||
normally possible through a fast timer interrupt (currently at
|
||||
15360 Hz).
|
||||
If unsure, say N.
|
||||
|
||||
config ETRAX_SERIAL_RX_TIMEOUT_TICKS
|
||||
int "Receive flush timeout (ticks) "
|
||||
depends on ETRAX_SERIAL && !ETRAX_SERIAL_FAST_TIMER && !ETRAX_SERIAL_FLUSH_DMA_FAST
|
||||
default "5"
|
||||
help
|
||||
Number of timer ticks between flush of receive fifo (1 tick = 10ms).
|
||||
Try 0-3 for low latency applications. Approx 5 for high load
|
||||
applications (e.g. PPP). Maybe this should be more adaptive some
|
||||
day...
|
||||
|
||||
config ETRAX_SERIAL_PORT0
|
||||
bool "Serial port 0 enabled"
|
||||
depends on ETRAX_SERIAL
|
||||
help
|
||||
Enables the ETRAX 100 serial driver for ser0 (ttyS0)
|
||||
Normally you want this on, unless you use external DMA 1 that uses
|
||||
the same DMA channels.
|
||||
|
||||
choice
|
||||
prompt "Ser0 DTR, RI, DSR and CD assignment"
|
||||
depends on ETRAX_SERIAL_PORT0
|
||||
default ETRAX_SER0_DTR_RI_DSR_CD_ON_NONE
|
||||
|
||||
config ETRAX_SER0_DTR_RI_DSR_CD_ON_NONE
|
||||
bool "No_DTR_RI_DSR_CD"
|
||||
|
||||
config ETRAX_SER0_DTR_RI_DSR_CD_ON_PA
|
||||
bool "DTR_RI_DSR_CD_on_PA"
|
||||
|
||||
config ETRAX_SER0_DTR_RI_DSR_CD_ON_PB
|
||||
bool "DTR_RI_DSR_CD_on_PB"
|
||||
help
|
||||
Enables the status and control signals DTR, RI, DSR and CD on PB for
|
||||
ser0.
|
||||
|
||||
config ETRAX_SER0_DTR_RI_DSR_CD_MIXED
|
||||
bool "DTR_RI_DSR_CD_mixed_on_PA_and_PB"
|
||||
|
||||
endchoice
|
||||
|
||||
config ETRAX_SER0_DTR_ON_PA_BIT
|
||||
int "Ser0 DTR on PA bit (-1 = not used)" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PA || ETRAX_SER0_DTR_RI_DSR_CD_MIXED
|
||||
depends on ETRAX_SERIAL_PORT0
|
||||
default "-1" if !ETRAX_SER0_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER0_DTR_RI_DSR_CD_MIXED
|
||||
default "4" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PA || ETRAX_SER0_DTR_RI_DSR_CD_MIXED
|
||||
|
||||
config ETRAX_SER0_RI_ON_PA_BIT
|
||||
int "Ser0 RI on PA bit (-1 = not used)" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PA || ETRAX_SER0_DTR_RI_DSR_CD_MIXED
|
||||
depends on ETRAX_SERIAL_PORT0
|
||||
default "-1" if !ETRAX_SER0_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER0_DTR_RI_DSR_CD_MIXED
|
||||
default "5" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PA || ETRAX_SER0_DTR_RI_DSR_CD_MIXED
|
||||
|
||||
config ETRAX_SER0_DSR_ON_PA_BIT
|
||||
int "Ser0 DSR on PA bit (-1 = not used)" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PA || ETRAX_SER0_DTR_RI_DSR_CD_MIXED
|
||||
depends on ETRAX_SERIAL_PORT0
|
||||
default "-1" if !ETRAX_SER0_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER0_DTR_RI_DSR_CD_MIXED
|
||||
default "6" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PA || ETRAX_SER0_DTR_RI_DSR_CD_MIXED
|
||||
|
||||
config ETRAX_SER0_CD_ON_PA_BIT
|
||||
int "Ser0 CD on PA bit (-1 = not used)" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PA || ETRAX_SER0_DTR_RI_DSR_CD_MIXED
|
||||
depends on ETRAX_SERIAL_PORT0
|
||||
default "-1" if !ETRAX_SER0_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER0_DTR_RI_DSR_CD_MIXED
|
||||
default "7" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PA || ETRAX_SER0_DTR_RI_DSR_CD_MIXED
|
||||
|
||||
config ETRAX_SER0_DTR_ON_PB_BIT
|
||||
int "Ser0 DTR on PB bit (-1 = not used)" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PB || ETRAX_SER0_DTR_RI_DSR_CD_MIXED
|
||||
depends on ETRAX_SERIAL_PORT0
|
||||
default "-1" if !ETRAX_SER0_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER0_DTR_RI_DSR_CD_MIXED
|
||||
default "4" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PB || ETRAX_SER0_DTR_RI_DSR_CD_MIXED
|
||||
help
|
||||
Specify the pin of the PB port to carry the DTR signal for serial
|
||||
port 0.
|
||||
|
||||
config ETRAX_SER0_RI_ON_PB_BIT
|
||||
int "Ser0 RI on PB bit (-1 = not used)" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PB || ETRAX_SER0_DTR_RI_DSR_CD_MIXED
|
||||
depends on ETRAX_SERIAL_PORT0
|
||||
default "-1" if !ETRAX_SER0_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER0_DTR_RI_DSR_CD_MIXED
|
||||
default "5" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PB || ETRAX_SER0_DTR_RI_DSR_CD_MIXED
|
||||
help
|
||||
Specify the pin of the PB port to carry the RI signal for serial
|
||||
port 0.
|
||||
|
||||
config ETRAX_SER0_DSR_ON_PB_BIT
|
||||
int "Ser0 DSR on PB bit (-1 = not used)" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PB || ETRAX_SER0_DTR_RI_DSR_CD_MIXED
|
||||
depends on ETRAX_SERIAL_PORT0
|
||||
default "-1" if !ETRAX_SER0_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER0_DTR_RI_DSR_CD_MIXED
|
||||
default "6" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PB || ETRAX_SER0_DTR_RI_DSR_CD_MIXED
|
||||
help
|
||||
Specify the pin of the PB port to carry the DSR signal for serial
|
||||
port 0.
|
||||
|
||||
config ETRAX_SER0_CD_ON_PB_BIT
|
||||
int "Ser0 CD on PB bit (-1 = not used)" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PB || ETRAX_SER0_DTR_RI_DSR_CD_MIXED
|
||||
depends on ETRAX_SERIAL_PORT0
|
||||
default "-1" if !ETRAX_SER0_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER0_DTR_RI_DSR_CD_MIXED
|
||||
default "7" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PB || ETRAX_SER0_DTR_RI_DSR_CD_MIXED
|
||||
help
|
||||
Specify the pin of the PB port to carry the CD signal for serial
|
||||
port 0.
|
||||
|
||||
config ETRAX_SERIAL_PORT1
|
||||
bool "Serial port 1 enabled"
|
||||
depends on ETRAX_SERIAL
|
||||
help
|
||||
Enables the ETRAX 100 serial driver for ser1 (ttyS1).
|
||||
|
||||
choice
|
||||
prompt "Ser1 DTR, RI, DSR and CD assignment"
|
||||
depends on ETRAX_SERIAL_PORT1
|
||||
default ETRAX_SER1_DTR_RI_DSR_CD_ON_NONE
|
||||
|
||||
config ETRAX_SER1_DTR_RI_DSR_CD_ON_NONE
|
||||
bool "No_DTR_RI_DSR_CD"
|
||||
|
||||
config ETRAX_SER1_DTR_RI_DSR_CD_ON_PA
|
||||
bool "DTR_RI_DSR_CD_on_PA"
|
||||
|
||||
config ETRAX_SER1_DTR_RI_DSR_CD_ON_PB
|
||||
bool "DTR_RI_DSR_CD_on_PB"
|
||||
help
|
||||
Enables the status and control signals DTR, RI, DSR and CD on PB for
|
||||
ser1.
|
||||
|
||||
config ETRAX_SER1_DTR_RI_DSR_CD_MIXED
|
||||
bool "DTR_RI_DSR_CD_mixed_on_PA_and_PB"
|
||||
|
||||
endchoice
|
||||
|
||||
config ETRAX_SER1_DTR_ON_PA_BIT
|
||||
int "Ser1 DTR on PA bit (-1 = not used)" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PA || ETRAX_SER1_DTR_RI_DSR_CD_MIXED
|
||||
depends on ETRAX_SERIAL_PORT1
|
||||
default "-1" if !ETRAX_SER1_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER1_DTR_RI_DSR_CD_MIXED
|
||||
default "4" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PA || ETRAX_SER1_DTR_RI_DSR_CD_MIXED
|
||||
|
||||
config ETRAX_SER1_RI_ON_PA_BIT
|
||||
int "Ser1 RI on PA bit (-1 = not used)" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PA || ETRAX_SER1_DTR_RI_DSR_CD_MIXED
|
||||
depends on ETRAX_SERIAL_PORT1
|
||||
default "-1" if !ETRAX_SER1_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER1_DTR_RI_DSR_CD_MIXED
|
||||
default "5" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PA || ETRAX_SER1_DTR_RI_DSR_CD_MIXED
|
||||
|
||||
config ETRAX_SER1_DSR_ON_PA_BIT
|
||||
int "Ser1 DSR on PA bit (-1 = not used)" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PA || ETRAX_SER1_DTR_RI_DSR_CD_MIXED
|
||||
depends on ETRAX_SERIAL_PORT1
|
||||
default "-1" if !ETRAX_SER1_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER1_DTR_RI_DSR_CD_MIXED
|
||||
default "6" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PA || ETRAX_SER1_DTR_RI_DSR_CD_MIXED
|
||||
|
||||
config ETRAX_SER1_CD_ON_PA_BIT
|
||||
int "Ser1 CD on PA bit (-1 = not used)" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PA || ETRAX_SER1_DTR_RI_DSR_CD_MIXED
|
||||
depends on ETRAX_SERIAL_PORT1
|
||||
default "-1" if !ETRAX_SER1_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER1_DTR_RI_DSR_CD_MIXED
|
||||
default "7" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PA || ETRAX_SER1_DTR_RI_DSR_CD_MIXED
|
||||
|
||||
config ETRAX_SER1_DTR_ON_PB_BIT
|
||||
int "Ser1 DTR on PB bit (-1 = not used)" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PB || ETRAX_SER1_DTR_RI_DSR_CD_MIXED
|
||||
depends on ETRAX_SERIAL_PORT1
|
||||
default "-1" if !ETRAX_SER1_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER1_DTR_RI_DSR_CD_MIXED
|
||||
default "4" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PB || ETRAX_SER1_DTR_RI_DSR_CD_MIXED
|
||||
help
|
||||
Specify the pin of the PB port to carry the DTR signal for serial
|
||||
port 1.
|
||||
|
||||
config ETRAX_SER1_RI_ON_PB_BIT
|
||||
int "Ser1 RI on PB bit (-1 = not used)" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PB || ETRAX_SER1_DTR_RI_DSR_CD_MIXED
|
||||
depends on ETRAX_SERIAL_PORT1
|
||||
default "-1" if !ETRAX_SER1_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER1_DTR_RI_DSR_CD_MIXED
|
||||
default "5" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PB || ETRAX_SER1_DTR_RI_DSR_CD_MIXED
|
||||
help
|
||||
Specify the pin of the PB port to carry the RI signal for serial
|
||||
port 1.
|
||||
|
||||
config ETRAX_SER1_DSR_ON_PB_BIT
|
||||
int "Ser1 DSR on PB bit (-1 = not used)" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PB || ETRAX_SER1_DTR_RI_DSR_CD_MIXED
|
||||
depends on ETRAX_SERIAL_PORT1
|
||||
default "-1" if !ETRAX_SER1_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER1_DTR_RI_DSR_CD_MIXED
|
||||
default "6" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PB || ETRAX_SER1_DTR_RI_DSR_CD_MIXED
|
||||
help
|
||||
Specify the pin of the PB port to carry the DSR signal for serial
|
||||
port 1.
|
||||
|
||||
config ETRAX_SER1_CD_ON_PB_BIT
|
||||
int "Ser1 CD on PB bit (-1 = not used)" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PB || ETRAX_SER1_DTR_RI_DSR_CD_MIXED
|
||||
depends on ETRAX_SERIAL_PORT1
|
||||
default "-1" if !ETRAX_SER1_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER1_DTR_RI_DSR_CD_MIXED
|
||||
default "7" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PB || ETRAX_SER1_DTR_RI_DSR_CD_MIXED
|
||||
help
|
||||
Specify the pin of the PB port to carry the CD signal for serial
|
||||
port 1.
|
||||
|
||||
comment "Make sure you do not have the same PB bits more than once!"
|
||||
depends on ETRAX_SERIAL && ETRAX_SER0_DTR_RI_DSR_CD_ON_PB && ETRAX_SER1_DTR_RI_DSR_CD_ON_PB
|
||||
|
||||
config ETRAX_SERIAL_PORT2
|
||||
bool "Serial port 2 enabled"
|
||||
depends on ETRAX_SERIAL
|
||||
help
|
||||
Enables the ETRAX 100 serial driver for ser2 (ttyS2).
|
||||
|
||||
choice
|
||||
prompt "Ser2 DTR, RI, DSR and CD assignment"
|
||||
depends on ETRAX_SERIAL_PORT2
|
||||
default ETRAX_SER2_DTR_RI_DSR_CD_ON_NONE
|
||||
|
||||
config ETRAX_SER2_DTR_RI_DSR_CD_ON_NONE
|
||||
bool "No_DTR_RI_DSR_CD"
|
||||
|
||||
config ETRAX_SER2_DTR_RI_DSR_CD_ON_PA
|
||||
bool "DTR_RI_DSR_CD_on_PA"
|
||||
help
|
||||
Enables the status and control signals DTR, RI, DSR and CD on PA for
|
||||
ser2.
|
||||
|
||||
config ETRAX_SER2_DTR_RI_DSR_CD_ON_PB
|
||||
bool "DTR_RI_DSR_CD_on_PB"
|
||||
|
||||
config ETRAX_SER2_DTR_RI_DSR_CD_MIXED
|
||||
bool "DTR_RI_DSR_CD_mixed_on_PA_and_PB"
|
||||
|
||||
endchoice
|
||||
|
||||
config ETRAX_SER2_DTR_ON_PA_BIT
|
||||
int "Ser2 DTR on PA bit (-1 = not used)" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PA || ETRAX_SER2_DTR_RI_DSR_CD_MIXED
|
||||
depends on ETRAX_SERIAL_PORT2
|
||||
default "-1" if !ETRAX_SER2_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER2_DTR_RI_DSR_CD_MIXED
|
||||
default "4" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PA || ETRAX_SER2_DTR_RI_DSR_CD_MIXED
|
||||
help
|
||||
Specify the pin of the PA port to carry the DTR signal for serial
|
||||
port 2.
|
||||
|
||||
config ETRAX_SER2_RI_ON_PA_BIT
|
||||
int "Ser2 RI on PA bit (-1 = not used)" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PA || ETRAX_SER2_DTR_RI_DSR_CD_MIXED
|
||||
depends on ETRAX_SERIAL_PORT2
|
||||
default "-1" if !ETRAX_SER2_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER2_DTR_RI_DSR_CD_MIXED
|
||||
default "5" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PA || ETRAX_SER2_DTR_RI_DSR_CD_MIXED
|
||||
help
|
||||
Specify the pin of the PA port to carry the RI signal for serial
|
||||
port 2.
|
||||
|
||||
config ETRAX_SER2_DSR_ON_PA_BIT
|
||||
int "Ser2 DSR on PA bit (-1 = not used)" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PA || ETRAX_SER2_DTR_RI_DSR_CD_MIXED
|
||||
depends on ETRAX_SERIAL_PORT2
|
||||
default "-1" if !ETRAX_SER2_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER2_DTR_RI_DSR_CD_MIXED
|
||||
default "6" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PA || ETRAX_SER2_DTR_RI_DSR_CD_MIXED
|
||||
help
|
||||
Specify the pin of the PA port to carry the DTR signal for serial
|
||||
port 2.
|
||||
|
||||
config ETRAX_SER2_CD_ON_PA_BIT
|
||||
int "Ser2 CD on PA bit (-1 = not used)" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PA || ETRAX_SER2_DTR_RI_DSR_CD_MIXED
|
||||
depends on ETRAX_SERIAL_PORT2
|
||||
default "-1" if !ETRAX_SER2_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER2_DTR_RI_DSR_CD_MIXED
|
||||
default "7" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PA || ETRAX_SER2_DTR_RI_DSR_CD_MIXED
|
||||
help
|
||||
Specify the pin of the PA port to carry the CD signal for serial
|
||||
port 2.
|
||||
|
||||
config ETRAX_SER2_DTR_ON_PB_BIT
|
||||
int "Ser2 DTR on PB bit (-1 = not used)" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PB || ETRAX_SER2_DTR_RI_DSR_CD_MIXED
|
||||
depends on ETRAX_SERIAL_PORT2
|
||||
default "-1" if !ETRAX_SER2_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER2_DTR_RI_DSR_CD_MIXED
|
||||
default "4" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PB || ETRAX_SER2_DTR_RI_DSR_CD_MIXED
|
||||
|
||||
config ETRAX_SER2_RI_ON_PB_BIT
|
||||
int "Ser2 RI on PB bit (-1 = not used)" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PB || ETRAX_SER2_DTR_RI_DSR_CD_MIXED
|
||||
depends on ETRAX_SERIAL_PORT2
|
||||
default "-1" if !ETRAX_SER2_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER2_DTR_RI_DSR_CD_MIXED
|
||||
default "5" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PB || ETRAX_SER2_DTR_RI_DSR_CD_MIXED
|
||||
|
||||
config ETRAX_SER2_DSR_ON_PB_BIT
|
||||
int "Ser2 DSR on PB bit (-1 = not used)" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PB || ETRAX_SER2_DTR_RI_DSR_CD_MIXED
|
||||
depends on ETRAX_SERIAL_PORT2
|
||||
default "-1" if !ETRAX_SER2_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER2_DTR_RI_DSR_CD_MIXED
|
||||
default "6" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PB || ETRAX_SER2_DTR_RI_DSR_CD_MIXED
|
||||
|
||||
config ETRAX_SER2_CD_ON_PB_BIT
|
||||
int "Ser2 CD on PB bit (-1 = not used)" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PB || ETRAX_SER2_DTR_RI_DSR_CD_MIXED
|
||||
depends on ETRAX_SERIAL_PORT2
|
||||
default "-1" if !ETRAX_SER2_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER2_DTR_RI_DSR_CD_MIXED
|
||||
default "7" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PB || ETRAX_SER2_DTR_RI_DSR_CD_MIXED
|
||||
|
||||
config ETRAX_SERIAL_PORT3
|
||||
bool "Serial port 3 enabled"
|
||||
depends on ETRAX_SERIAL
|
||||
help
|
||||
Enables the ETRAX 100 serial driver for ser3 (ttyS3).
|
||||
|
||||
choice
|
||||
prompt "Ser3 DTR, RI, DSR and CD assignment"
|
||||
depends on ETRAX_SERIAL_PORT3
|
||||
default ETRAX_SER3_DTR_RI_DSR_CD_ON_NONE
|
||||
|
||||
config ETRAX_SER3_DTR_RI_DSR_CD_ON_NONE
|
||||
bool "No_DTR_RI_DSR_CD"
|
||||
|
||||
config ETRAX_SER3_DTR_RI_DSR_CD_ON_PA
|
||||
bool "DTR_RI_DSR_CD_on_PA"
|
||||
|
||||
config ETRAX_SER3_DTR_RI_DSR_CD_ON_PB
|
||||
bool "DTR_RI_DSR_CD_on_PB"
|
||||
|
||||
config ETRAX_SER3_DTR_RI_DSR_CD_MIXED
|
||||
bool "DTR_RI_DSR_CD_mixed_on_PA_and_PB"
|
||||
|
||||
endchoice
|
||||
|
||||
config ETRAX_SER3_DTR_ON_PA_BIT
|
||||
int "Ser3 DTR on PA bit (-1 = not used)" if ETRAX_SER3_DTR_RI_DSR_CD_ON_PA || ETRAX_SER3_DTR_RI_DSR_CD_MIXED
|
||||
depends on ETRAX_SERIAL_PORT3
|
||||
default "-1"
|
||||
|
||||
config ETRAX_SER3_RI_ON_PA_BIT
|
||||
int "Ser3 RI on PA bit (-1 = not used)" if ETRAX_SER3_DTR_RI_DSR_CD_ON_PA || ETRAX_SER3_DTR_RI_DSR_CD_MIXED
|
||||
depends on ETRAX_SERIAL_PORT3
|
||||
default "-1"
|
||||
|
||||
config ETRAX_SER3_DSR_ON_PA_BIT
|
||||
int "Ser3 DSR on PA bit (-1 = not used)" if ETRAX_SER3_DTR_RI_DSR_CD_ON_PA || ETRAX_SER3_DTR_RI_DSR_CD_MIXED
|
||||
depends on ETRAX_SERIAL_PORT3
|
||||
default "-1"
|
||||
|
||||
config ETRAX_SER3_CD_ON_PA_BIT
|
||||
int "Ser3 CD on PA bit (-1 = not used)" if ETRAX_SER3_DTR_RI_DSR_CD_ON_PA || ETRAX_SER3_DTR_RI_DSR_CD_MIXED
|
||||
depends on ETRAX_SERIAL_PORT3
|
||||
default "-1"
|
||||
|
||||
config ETRAX_SER3_DTR_ON_PB_BIT
|
||||
int "Ser3 DTR on PB bit (-1 = not used)" if ETRAX_SER3_DTR_RI_DSR_CD_ON_PB || ETRAX_SER3_DTR_RI_DSR_CD_MIXED
|
||||
depends on ETRAX_SERIAL_PORT3
|
||||
default "-1"
|
||||
|
||||
config ETRAX_SER3_RI_ON_PB_BIT
|
||||
int "Ser3 RI on PB bit (-1 = not used)" if ETRAX_SER3_DTR_RI_DSR_CD_ON_PB || ETRAX_SER3_DTR_RI_DSR_CD_MIXED
|
||||
depends on ETRAX_SERIAL_PORT3
|
||||
default "-1"
|
||||
|
||||
config ETRAX_SER3_DSR_ON_PB_BIT
|
||||
int "Ser3 DSR on PB bit (-1 = not used)" if ETRAX_SER3_DTR_RI_DSR_CD_ON_PB || ETRAX_SER3_DTR_RI_DSR_CD_MIXED
|
||||
depends on ETRAX_SERIAL_PORT3
|
||||
default "-1"
|
||||
|
||||
config ETRAX_SER3_CD_ON_PB_BIT
|
||||
int "Ser3 CD on PB bit (-1 = not used)" if ETRAX_SER3_DTR_RI_DSR_CD_ON_PB || ETRAX_SER3_DTR_RI_DSR_CD_MIXED
|
||||
depends on ETRAX_SERIAL_PORT3
|
||||
default "-1"
|
||||
|
||||
config ETRAX_RS485
|
||||
bool "RS-485 support"
|
||||
depends on ETRAX_SERIAL
|
||||
help
|
||||
Enables support for RS-485 serial communication. For a primer on
|
||||
RS-485, see <http://en.wikipedia.org/wiki/Rs485>
|
||||
|
||||
config ETRAX_RS485_ON_PA
|
||||
bool "RS-485 mode on PA"
|
||||
depends on ETRAX_RS485
|
||||
help
|
||||
Control Driver Output Enable on RS485 transceiver using a pin on PA
|
||||
port:
|
||||
Axis 2400/2401 uses PA 3.
|
||||
|
||||
config ETRAX_RS485_ON_PA_BIT
|
||||
int "RS-485 mode on PA bit"
|
||||
depends on ETRAX_RS485_ON_PA
|
||||
default "3"
|
||||
help
|
||||
Control Driver Output Enable on RS485 transceiver using a this bit
|
||||
on PA port.
|
||||
|
||||
config ETRAX_RS485_DISABLE_RECEIVER
|
||||
bool "Disable serial receiver"
|
||||
depends on ETRAX_RS485
|
||||
help
|
||||
It's necessary to disable the serial receiver to avoid serial
|
||||
loopback. Not all products are able to do this in software only.
|
||||
Axis 2400/2401 must disable receiver.
|
||||
|
||||
config ETRAX_USB_HOST
|
||||
bool "USB host"
|
||||
select USB
|
||||
help
|
||||
This option enables the host functionality of the ETRAX 100LX
|
||||
built-in USB controller. In host mode the controller is designed
|
||||
for CTRL and BULK traffic only, INTR traffic may work as well
|
||||
however (depending on the requirements of timeliness).
|
||||
|
||||
config ETRAX_PTABLE_SECTOR
|
||||
int "Byte-offset of partition table sector"
|
||||
depends on ETRAX_AXISFLASHMAP
|
||||
default "65536"
|
||||
help
|
||||
Byte-offset of the partition table in the first flash chip.
|
||||
The default value is 64kB and should not be changed unless
|
||||
you know exactly what you are doing. The only valid reason
|
||||
for changing this is when the flash block size is bigger
|
||||
than 64kB (e.g. when using two parallel 16 bit flashes).
|
||||
|
||||
config ETRAX_I2C
|
||||
bool "I2C support"
|
||||
depends on ETRAX_ARCH_V10
|
||||
help
|
||||
Enables an I2C driver on ETRAX100.
|
||||
EXAMPLE usage:
|
||||
i2c_arg = I2C_WRITEARG(STA013_WRITE_ADDR, reg, val);
|
||||
ioctl(fd, _IO(ETRAXI2C_IOCTYPE, I2C_WRITEREG), i2c_arg);
|
||||
i2c_arg = I2C_READARG(STA013_READ_ADDR, reg);
|
||||
val = ioctl(fd, _IO(ETRAXI2C_IOCTYPE, I2C_READREG), i2c_arg);
|
||||
|
||||
# this is true for most products since PB-I2C seems to be somewhat
|
||||
# flawed..
|
||||
config ETRAX_I2C_USES_PB_NOT_PB_I2C
|
||||
bool "I2C uses PB not PB-I2C"
|
||||
depends on ETRAX_I2C
|
||||
help
|
||||
Select whether to use the special I2C mode in the PB I/O register or
|
||||
not. This option needs to be selected in order to use some drivers
|
||||
that access the I2C I/O pins directly instead of going through the
|
||||
I2C driver, like the DS1302 realtime-clock driver. If you are
|
||||
uncertain, choose Y here.
|
||||
|
||||
config ETRAX_I2C_DATA_PORT
|
||||
int "I2C SDA bit number"
|
||||
depends on ETRAX_I2C_USES_PB_NOT_PB_I2C
|
||||
default "0"
|
||||
help
|
||||
Selects the pin on Port B where the data pin is connected
|
||||
|
||||
config ETRAX_I2C_CLK_PORT
|
||||
int "I2C SCL bit number"
|
||||
depends on ETRAX_I2C_USES_PB_NOT_PB_I2C
|
||||
default "1"
|
||||
help
|
||||
Select the pin on Port B where the clock pin is connected
|
||||
|
||||
config ETRAX_I2C_EEPROM
|
||||
bool "I2C EEPROM (non-volatile RAM) support"
|
||||
depends on ETRAX_I2C
|
||||
help
|
||||
Enables I2C EEPROM (non-volatile RAM) on PB0 and PB1 using the I2C
|
||||
driver. Select size option: Probed, 2k, 8k, 16k.
|
||||
(Probing works for 2k and 8k but not that well for 16k)
|
||||
|
||||
choice
|
||||
prompt "EEPROM size"
|
||||
depends on ETRAX_I2C_EEPROM
|
||||
default ETRAX_I2C_EEPROM_PROBE
|
||||
|
||||
config ETRAX_I2C_EEPROM_PROBE
|
||||
bool "Probed"
|
||||
help
|
||||
Specifies size or auto probe of the EEPROM size.
|
||||
Options: Probed, 2k, 8k, 16k.
|
||||
(Probing works for 2k and 8k but not that well for 16k)
|
||||
|
||||
config ETRAX_I2C_EEPROM_2KB
|
||||
bool "2kB"
|
||||
help
|
||||
Use a 2kB EEPROM.
|
||||
|
||||
config ETRAX_I2C_EEPROM_8KB
|
||||
bool "8kB"
|
||||
help
|
||||
Use a 8kB EEPROM.
|
||||
|
||||
config ETRAX_I2C_EEPROM_16KB
|
||||
bool "16kB"
|
||||
help
|
||||
Use a 16kB EEPROM.
|
||||
|
||||
endchoice
|
||||
|
||||
config ETRAX_GPIO
|
||||
bool "GPIO support"
|
||||
depends on ETRAX_ARCH_V10
|
||||
---help---
|
||||
Enables the ETRAX general port device (major 120, minors 0 and 1).
|
||||
You can use this driver to access the general port bits. It supports
|
||||
these ioctl's:
|
||||
#include <linux/etraxgpio.h>
|
||||
fd = open("/dev/gpioa", O_RDWR); // or /dev/gpiob
|
||||
ioctl(fd, _IO(ETRAXGPIO_IOCTYPE, IO_SETBITS), bits_to_set);
|
||||
ioctl(fd, _IO(ETRAXGPIO_IOCTYPE, IO_CLRBITS), bits_to_clear);
|
||||
val = ioctl(fd, _IO(ETRAXGPIO_IOCTYPE, IO_READBITS), NULL);
|
||||
Remember that you need to setup the port directions appropriately in
|
||||
the General configuration.
|
||||
|
||||
config ETRAX_PA_CHANGEABLE_DIR
|
||||
hex "PA user changeable dir mask"
|
||||
depends on ETRAX_GPIO
|
||||
default "00"
|
||||
help
|
||||
This is a bitmask with information of what bits in PA that a user
|
||||
can change direction on using ioctl's.
|
||||
Bit set = changeable.
|
||||
You probably want 00 here.
|
||||
|
||||
config ETRAX_PA_CHANGEABLE_BITS
|
||||
hex "PA user changeable bits mask"
|
||||
depends on ETRAX_GPIO
|
||||
default "FF"
|
||||
help
|
||||
This is a bitmask with information of what bits in PA that a user
|
||||
can change the value on using ioctl's.
|
||||
Bit set = changeable.
|
||||
You probably want 00 here.
|
||||
|
||||
config ETRAX_PB_CHANGEABLE_DIR
|
||||
hex "PB user changeable dir mask"
|
||||
depends on ETRAX_GPIO
|
||||
default "00"
|
||||
help
|
||||
This is a bitmask with information of what bits in PB that a user
|
||||
can change direction on using ioctl's.
|
||||
Bit set = changeable.
|
||||
You probably want 00 here.
|
||||
|
||||
config ETRAX_PB_CHANGEABLE_BITS
|
||||
hex "PB user changeable bits mask"
|
||||
depends on ETRAX_GPIO
|
||||
default "FF"
|
||||
help
|
||||
This is a bitmask with information of what bits in PB that a user
|
||||
can change the value on using ioctl's.
|
||||
Bit set = changeable.
|
||||
You probably want 00 here.
|
||||
|
||||
endif
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Makefile for Etrax-specific drivers
|
||||
#
|
||||
|
||||
obj-$(CONFIG_ETRAX_AXISFLASHMAP) += axisflashmap.o
|
||||
obj-$(CONFIG_ETRAX_I2C) += i2c.o
|
||||
obj-$(CONFIG_ETRAX_I2C_EEPROM) += eeprom.o
|
||||
obj-$(CONFIG_ETRAX_GPIO) += gpio.o
|
||||
obj-$(CONFIG_ETRAX_SYNCHRONOUS_SERIAL) += sync_serial.o
|
||||
|
||||
|
|
@ -1,413 +0,0 @@
|
|||
/*
|
||||
* Physical mapping layer for MTD using the Axis partitiontable format
|
||||
*
|
||||
* Copyright (c) 2001, 2002 Axis Communications AB
|
||||
*
|
||||
* This file is under the GPL.
|
||||
*
|
||||
* First partition is always sector 0 regardless of if we find a partitiontable
|
||||
* or not. In the start of the next sector, there can be a partitiontable that
|
||||
* tells us what other partitions to define. If there isn't, we use a default
|
||||
* partition split defined below.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <linux/mtd/concat.h>
|
||||
#include <linux/mtd/map.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/mtdram.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
|
||||
#include <asm/axisflashmap.h>
|
||||
#include <asm/mmu.h>
|
||||
#include <arch/sv_addr_ag.h>
|
||||
|
||||
#ifdef CONFIG_CRIS_LOW_MAP
|
||||
#define FLASH_UNCACHED_ADDR KSEG_8
|
||||
#define FLASH_CACHED_ADDR KSEG_5
|
||||
#else
|
||||
#define FLASH_UNCACHED_ADDR KSEG_E
|
||||
#define FLASH_CACHED_ADDR KSEG_F
|
||||
#endif
|
||||
|
||||
#if CONFIG_ETRAX_FLASH_BUSWIDTH==1
|
||||
#define flash_data __u8
|
||||
#elif CONFIG_ETRAX_FLASH_BUSWIDTH==2
|
||||
#define flash_data __u16
|
||||
#elif CONFIG_ETRAX_FLASH_BUSWIDTH==4
|
||||
#define flash_data __u32
|
||||
#endif
|
||||
|
||||
/* From head.S */
|
||||
extern unsigned long romfs_start, romfs_length, romfs_in_flash;
|
||||
|
||||
/* The master mtd for the entire flash. */
|
||||
struct mtd_info* axisflash_mtd = NULL;
|
||||
|
||||
/* Map driver functions. */
|
||||
|
||||
static map_word flash_read(struct map_info *map, unsigned long ofs)
|
||||
{
|
||||
map_word tmp;
|
||||
tmp.x[0] = *(flash_data *)(map->map_priv_1 + ofs);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static void flash_copy_from(struct map_info *map, void *to,
|
||||
unsigned long from, ssize_t len)
|
||||
{
|
||||
memcpy(to, (void *)(map->map_priv_1 + from), len);
|
||||
}
|
||||
|
||||
static void flash_write(struct map_info *map, map_word d, unsigned long adr)
|
||||
{
|
||||
*(flash_data *)(map->map_priv_1 + adr) = (flash_data)d.x[0];
|
||||
}
|
||||
|
||||
/*
|
||||
* The map for chip select e0.
|
||||
*
|
||||
* We run into tricky coherence situations if we mix cached with uncached
|
||||
* accesses to we only use the uncached version here.
|
||||
*
|
||||
* The size field is the total size where the flash chips may be mapped on the
|
||||
* chip select. MTD probes should find all devices there and it does not matter
|
||||
* if there are unmapped gaps or aliases (mirrors of flash devices). The MTD
|
||||
* probes will ignore them.
|
||||
*
|
||||
* The start address in map_priv_1 is in virtual memory so we cannot use
|
||||
* MEM_CSE0_START but must rely on that FLASH_UNCACHED_ADDR is the start
|
||||
* address of cse0.
|
||||
*/
|
||||
static struct map_info map_cse0 = {
|
||||
.name = "cse0",
|
||||
.size = MEM_CSE0_SIZE,
|
||||
.bankwidth = CONFIG_ETRAX_FLASH_BUSWIDTH,
|
||||
.read = flash_read,
|
||||
.copy_from = flash_copy_from,
|
||||
.write = flash_write,
|
||||
.map_priv_1 = FLASH_UNCACHED_ADDR
|
||||
};
|
||||
|
||||
/*
|
||||
* The map for chip select e1.
|
||||
*
|
||||
* If there was a gap between cse0 and cse1, map_priv_1 would get the wrong
|
||||
* address, but there isn't.
|
||||
*/
|
||||
static struct map_info map_cse1 = {
|
||||
.name = "cse1",
|
||||
.size = MEM_CSE1_SIZE,
|
||||
.bankwidth = CONFIG_ETRAX_FLASH_BUSWIDTH,
|
||||
.read = flash_read,
|
||||
.copy_from = flash_copy_from,
|
||||
.write = flash_write,
|
||||
.map_priv_1 = FLASH_UNCACHED_ADDR + MEM_CSE0_SIZE
|
||||
};
|
||||
|
||||
/* If no partition-table was found, we use this default-set. */
|
||||
#define MAX_PARTITIONS 7
|
||||
#define NUM_DEFAULT_PARTITIONS 3
|
||||
|
||||
/*
|
||||
* Default flash size is 2MB. CONFIG_ETRAX_PTABLE_SECTOR is most likely the
|
||||
* size of one flash block and "filesystem"-partition needs 5 blocks to be able
|
||||
* to use JFFS.
|
||||
*/
|
||||
static struct mtd_partition axis_default_partitions[NUM_DEFAULT_PARTITIONS] = {
|
||||
{
|
||||
.name = "boot firmware",
|
||||
.size = CONFIG_ETRAX_PTABLE_SECTOR,
|
||||
.offset = 0
|
||||
},
|
||||
{
|
||||
.name = "kernel",
|
||||
.size = 0x200000 - (6 * CONFIG_ETRAX_PTABLE_SECTOR),
|
||||
.offset = CONFIG_ETRAX_PTABLE_SECTOR
|
||||
},
|
||||
{
|
||||
.name = "filesystem",
|
||||
.size = 5 * CONFIG_ETRAX_PTABLE_SECTOR,
|
||||
.offset = 0x200000 - (5 * CONFIG_ETRAX_PTABLE_SECTOR)
|
||||
}
|
||||
};
|
||||
|
||||
/* Initialize the ones normally used. */
|
||||
static struct mtd_partition axis_partitions[MAX_PARTITIONS] = {
|
||||
{
|
||||
.name = "part0",
|
||||
.size = CONFIG_ETRAX_PTABLE_SECTOR,
|
||||
.offset = 0
|
||||
},
|
||||
{
|
||||
.name = "part1",
|
||||
.size = 0,
|
||||
.offset = 0
|
||||
},
|
||||
{
|
||||
.name = "part2",
|
||||
.size = 0,
|
||||
.offset = 0
|
||||
},
|
||||
{
|
||||
.name = "part3",
|
||||
.size = 0,
|
||||
.offset = 0
|
||||
},
|
||||
{
|
||||
.name = "part4",
|
||||
.size = 0,
|
||||
.offset = 0
|
||||
},
|
||||
{
|
||||
.name = "part5",
|
||||
.size = 0,
|
||||
.offset = 0
|
||||
},
|
||||
{
|
||||
.name = "part6",
|
||||
.size = 0,
|
||||
.offset = 0
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* Probe a chip select for AMD-compatible (JEDEC) or CFI-compatible flash
|
||||
* chips in that order (because the amd_flash-driver is faster).
|
||||
*/
|
||||
static struct mtd_info *probe_cs(struct map_info *map_cs)
|
||||
{
|
||||
struct mtd_info *mtd_cs = NULL;
|
||||
|
||||
printk(KERN_INFO
|
||||
"%s: Probing a 0x%08lx bytes large window at 0x%08lx.\n",
|
||||
map_cs->name, map_cs->size, map_cs->map_priv_1);
|
||||
|
||||
#ifdef CONFIG_MTD_CFI
|
||||
mtd_cs = do_map_probe("cfi_probe", map_cs);
|
||||
#endif
|
||||
#ifdef CONFIG_MTD_JEDECPROBE
|
||||
if (!mtd_cs)
|
||||
mtd_cs = do_map_probe("jedec_probe", map_cs);
|
||||
#endif
|
||||
|
||||
return mtd_cs;
|
||||
}
|
||||
|
||||
/*
|
||||
* Probe each chip select individually for flash chips. If there are chips on
|
||||
* both cse0 and cse1, the mtd_info structs will be concatenated to one struct
|
||||
* so that MTD partitions can cross chip boundaries.
|
||||
*
|
||||
* The only known restriction to how you can mount your chips is that each
|
||||
* chip select must hold similar flash chips. But you need external hardware
|
||||
* to do that anyway and you can put totally different chips on cse0 and cse1
|
||||
* so it isn't really much of a restriction.
|
||||
*/
|
||||
static struct mtd_info *flash_probe(void)
|
||||
{
|
||||
struct mtd_info *mtd_cse0;
|
||||
struct mtd_info *mtd_cse1;
|
||||
struct mtd_info *mtd_cse;
|
||||
|
||||
mtd_cse0 = probe_cs(&map_cse0);
|
||||
mtd_cse1 = probe_cs(&map_cse1);
|
||||
|
||||
if (!mtd_cse0 && !mtd_cse1) {
|
||||
/* No chip found. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (mtd_cse0 && mtd_cse1) {
|
||||
struct mtd_info *mtds[] = { mtd_cse0, mtd_cse1 };
|
||||
|
||||
/* Since the concatenation layer adds a small overhead we
|
||||
* could try to figure out if the chips in cse0 and cse1 are
|
||||
* identical and reprobe the whole cse0+cse1 window. But since
|
||||
* flash chips are slow, the overhead is relatively small.
|
||||
* So we use the MTD concatenation layer instead of further
|
||||
* complicating the probing procedure.
|
||||
*/
|
||||
mtd_cse = mtd_concat_create(mtds, ARRAY_SIZE(mtds),
|
||||
"cse0+cse1");
|
||||
if (!mtd_cse) {
|
||||
printk(KERN_ERR "%s and %s: Concatenation failed!\n",
|
||||
map_cse0.name, map_cse1.name);
|
||||
|
||||
/* The best we can do now is to only use what we found
|
||||
* at cse0.
|
||||
*/
|
||||
mtd_cse = mtd_cse0;
|
||||
map_destroy(mtd_cse1);
|
||||
}
|
||||
} else {
|
||||
mtd_cse = mtd_cse0? mtd_cse0 : mtd_cse1;
|
||||
}
|
||||
|
||||
return mtd_cse;
|
||||
}
|
||||
|
||||
/*
|
||||
* Probe the flash chip(s) and, if it succeeds, read the partition-table
|
||||
* and register the partitions with MTD.
|
||||
*/
|
||||
static int __init init_axis_flash(void)
|
||||
{
|
||||
struct mtd_info *mymtd;
|
||||
int err = 0;
|
||||
int pidx = 0;
|
||||
struct partitiontable_head *ptable_head = NULL;
|
||||
struct partitiontable_entry *ptable;
|
||||
int use_default_ptable = 1; /* Until proven otherwise. */
|
||||
const char pmsg[] = " /dev/flash%d at 0x%08x, size 0x%08x\n";
|
||||
|
||||
if (!(mymtd = flash_probe())) {
|
||||
/* There's no reason to use this module if no flash chip can
|
||||
* be identified. Make sure that's understood.
|
||||
*/
|
||||
printk(KERN_INFO "axisflashmap: Found no flash chip.\n");
|
||||
} else {
|
||||
printk(KERN_INFO "%s: 0x%08x bytes of flash memory.\n",
|
||||
mymtd->name, mymtd->size);
|
||||
axisflash_mtd = mymtd;
|
||||
}
|
||||
|
||||
if (mymtd) {
|
||||
mymtd->owner = THIS_MODULE;
|
||||
ptable_head = (struct partitiontable_head *)(FLASH_CACHED_ADDR +
|
||||
CONFIG_ETRAX_PTABLE_SECTOR +
|
||||
PARTITION_TABLE_OFFSET);
|
||||
}
|
||||
pidx++; /* First partition is always set to the default. */
|
||||
|
||||
if (ptable_head && (ptable_head->magic == PARTITION_TABLE_MAGIC)
|
||||
&& (ptable_head->size <
|
||||
(MAX_PARTITIONS * sizeof(struct partitiontable_entry) +
|
||||
PARTITIONTABLE_END_MARKER_SIZE))
|
||||
&& (*(unsigned long*)((void*)ptable_head + sizeof(*ptable_head) +
|
||||
ptable_head->size -
|
||||
PARTITIONTABLE_END_MARKER_SIZE)
|
||||
== PARTITIONTABLE_END_MARKER)) {
|
||||
/* Looks like a start, sane length and end of a
|
||||
* partition table, lets check csum etc.
|
||||
*/
|
||||
int ptable_ok = 0;
|
||||
struct partitiontable_entry *max_addr =
|
||||
(struct partitiontable_entry *)
|
||||
((unsigned long)ptable_head + sizeof(*ptable_head) +
|
||||
ptable_head->size);
|
||||
unsigned long offset = CONFIG_ETRAX_PTABLE_SECTOR;
|
||||
unsigned char *p;
|
||||
unsigned long csum = 0;
|
||||
|
||||
ptable = (struct partitiontable_entry *)
|
||||
((unsigned long)ptable_head + sizeof(*ptable_head));
|
||||
|
||||
/* Lets be PARANOID, and check the checksum. */
|
||||
p = (unsigned char*) ptable;
|
||||
|
||||
while (p <= (unsigned char*)max_addr) {
|
||||
csum += *p++;
|
||||
csum += *p++;
|
||||
csum += *p++;
|
||||
csum += *p++;
|
||||
}
|
||||
ptable_ok = (csum == ptable_head->checksum);
|
||||
|
||||
/* Read the entries and use/show the info. */
|
||||
printk(KERN_INFO " Found a%s partition table at 0x%p-0x%p.\n",
|
||||
(ptable_ok ? " valid" : "n invalid"), ptable_head,
|
||||
max_addr);
|
||||
|
||||
/* We have found a working bootblock. Now read the
|
||||
* partition table. Scan the table. It ends when
|
||||
* there is 0xffffffff, that is, empty flash.
|
||||
*/
|
||||
while (ptable_ok
|
||||
&& ptable->offset != 0xffffffff
|
||||
&& ptable < max_addr
|
||||
&& pidx < MAX_PARTITIONS) {
|
||||
|
||||
axis_partitions[pidx].offset = offset + ptable->offset;
|
||||
axis_partitions[pidx].size = ptable->size;
|
||||
|
||||
printk(pmsg, pidx, axis_partitions[pidx].offset,
|
||||
axis_partitions[pidx].size);
|
||||
pidx++;
|
||||
ptable++;
|
||||
}
|
||||
use_default_ptable = !ptable_ok;
|
||||
}
|
||||
|
||||
if (romfs_in_flash) {
|
||||
/* Add an overlapping device for the root partition (romfs). */
|
||||
|
||||
axis_partitions[pidx].name = "romfs";
|
||||
axis_partitions[pidx].size = romfs_length;
|
||||
axis_partitions[pidx].offset = romfs_start - FLASH_CACHED_ADDR;
|
||||
axis_partitions[pidx].mask_flags |= MTD_WRITEABLE;
|
||||
|
||||
printk(KERN_INFO
|
||||
" Adding readonly flash partition for romfs image:\n");
|
||||
printk(pmsg, pidx, axis_partitions[pidx].offset,
|
||||
axis_partitions[pidx].size);
|
||||
pidx++;
|
||||
}
|
||||
|
||||
if (mymtd) {
|
||||
if (use_default_ptable) {
|
||||
printk(KERN_INFO " Using default partition table.\n");
|
||||
err = mtd_device_register(mymtd,
|
||||
axis_default_partitions,
|
||||
NUM_DEFAULT_PARTITIONS);
|
||||
} else {
|
||||
err = mtd_device_register(mymtd, axis_partitions,
|
||||
pidx);
|
||||
}
|
||||
|
||||
if (err)
|
||||
panic("axisflashmap could not add MTD partitions!\n");
|
||||
}
|
||||
|
||||
if (!romfs_in_flash) {
|
||||
/* Create an RAM device for the root partition (romfs). */
|
||||
|
||||
#if !defined(CONFIG_MTD_MTDRAM) || (CONFIG_MTDRAM_TOTAL_SIZE != 0)
|
||||
/* No use trying to boot this kernel from RAM. Panic! */
|
||||
printk(KERN_EMERG "axisflashmap: Cannot create an MTD RAM "
|
||||
"device due to kernel (mis)configuration!\n");
|
||||
panic("This kernel cannot boot from RAM!\n");
|
||||
#else
|
||||
struct mtd_info *mtd_ram;
|
||||
|
||||
mtd_ram = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
|
||||
if (!mtd_ram)
|
||||
panic("axisflashmap couldn't allocate memory for "
|
||||
"mtd_info!\n");
|
||||
|
||||
printk(KERN_INFO " Adding RAM partition for romfs image:\n");
|
||||
printk(pmsg, pidx, (unsigned)romfs_start,
|
||||
(unsigned)romfs_length);
|
||||
|
||||
err = mtdram_init_device(mtd_ram,
|
||||
(void *)romfs_start,
|
||||
romfs_length,
|
||||
"romfs");
|
||||
if (err)
|
||||
panic("axisflashmap could not initialize MTD RAM "
|
||||
"device!\n");
|
||||
#endif
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
/* This adds the above to the kernels init-call chain. */
|
||||
module_init(init_axis_flash);
|
||||
|
||||
EXPORT_SYMBOL(axisflash_mtd);
|
||||
|
|
@ -1,852 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*!*****************************************************************************
|
||||
*!
|
||||
*! Implements an interface for i2c compatible eeproms to run under Linux.
|
||||
*! Supports 2k, 8k(?) and 16k. Uses adaptive timing adjustments by
|
||||
*! Johan.Adolfsson@axis.com
|
||||
*!
|
||||
*! Probing results:
|
||||
*! 8k or not is detected (the assumes 2k or 16k)
|
||||
*! 2k or 16k detected using test reads and writes.
|
||||
*!
|
||||
*!------------------------------------------------------------------------
|
||||
*! HISTORY
|
||||
*!
|
||||
*! DATE NAME CHANGES
|
||||
*! ---- ---- -------
|
||||
*! Aug 28 1999 Edgar Iglesias Initial Version
|
||||
*! Aug 31 1999 Edgar Iglesias Allow simultaneous users.
|
||||
*! Sep 03 1999 Edgar Iglesias Updated probe.
|
||||
*! Sep 03 1999 Edgar Iglesias Added bail-out stuff if we get interrupted
|
||||
*! in the spin-lock.
|
||||
*!
|
||||
*! (c) 1999 Axis Communications AB, Lund, Sweden
|
||||
*!*****************************************************************************/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include "i2c.h"
|
||||
|
||||
#define D(x)
|
||||
|
||||
/* If we should use adaptive timing or not: */
|
||||
/* #define EEPROM_ADAPTIVE_TIMING */
|
||||
|
||||
#define EEPROM_MAJOR_NR 122 /* use a LOCAL/EXPERIMENTAL major for now */
|
||||
#define EEPROM_MINOR_NR 0
|
||||
|
||||
/* Empirical sane initial value of the delay, the value will be adapted to
|
||||
* what the chip needs when using EEPROM_ADAPTIVE_TIMING.
|
||||
*/
|
||||
#define INITIAL_WRITEDELAY_US 4000
|
||||
#define MAX_WRITEDELAY_US 10000 /* 10 ms according to spec for 2KB EEPROM */
|
||||
|
||||
/* This one defines how many times to try when eeprom fails. */
|
||||
#define EEPROM_RETRIES 10
|
||||
|
||||
#define EEPROM_2KB (2 * 1024)
|
||||
/*#define EEPROM_4KB (4 * 1024)*/ /* Exists but not used in Axis products */
|
||||
#define EEPROM_8KB (8 * 1024 - 1 ) /* Last byte has write protection bit */
|
||||
#define EEPROM_16KB (16 * 1024)
|
||||
|
||||
#define i2c_delay(x) udelay(x)
|
||||
|
||||
/*
|
||||
* This structure describes the attached eeprom chip.
|
||||
* The values are probed for.
|
||||
*/
|
||||
|
||||
struct eeprom_type
|
||||
{
|
||||
unsigned long size;
|
||||
unsigned long sequential_write_pagesize;
|
||||
unsigned char select_cmd;
|
||||
unsigned long usec_delay_writecycles; /* Min time between write cycles
|
||||
(up to 10ms for some models) */
|
||||
unsigned long usec_delay_step; /* For adaptive algorithm */
|
||||
int adapt_state; /* 1 = To high , 0 = Even, -1 = To low */
|
||||
|
||||
/* this one is to keep the read/write operations atomic */
|
||||
struct mutex lock;
|
||||
int retry_cnt_addr; /* Used to keep track of number of retries for
|
||||
adaptive timing adjustments */
|
||||
int retry_cnt_read;
|
||||
};
|
||||
|
||||
static int eeprom_open(struct inode * inode, struct file * file);
|
||||
static loff_t eeprom_lseek(struct file * file, loff_t offset, int orig);
|
||||
static ssize_t eeprom_read(struct file * file, char * buf, size_t count,
|
||||
loff_t *off);
|
||||
static ssize_t eeprom_write(struct file * file, const char * buf, size_t count,
|
||||
loff_t *off);
|
||||
static int eeprom_close(struct inode * inode, struct file * file);
|
||||
|
||||
static int eeprom_address(unsigned long addr);
|
||||
static int read_from_eeprom(char * buf, int count);
|
||||
static int eeprom_write_buf(loff_t addr, const char * buf, int count);
|
||||
static int eeprom_read_buf(loff_t addr, char * buf, int count);
|
||||
|
||||
static void eeprom_disable_write_protect(void);
|
||||
|
||||
|
||||
static const char eeprom_name[] = "eeprom";
|
||||
|
||||
/* chip description */
|
||||
static struct eeprom_type eeprom;
|
||||
|
||||
/* This is the exported file-operations structure for this device. */
|
||||
const struct file_operations eeprom_fops =
|
||||
{
|
||||
.llseek = eeprom_lseek,
|
||||
.read = eeprom_read,
|
||||
.write = eeprom_write,
|
||||
.open = eeprom_open,
|
||||
.release = eeprom_close
|
||||
};
|
||||
|
||||
/* eeprom init call. Probes for different eeprom models. */
|
||||
|
||||
int __init eeprom_init(void)
|
||||
{
|
||||
mutex_init(&eeprom.lock);
|
||||
|
||||
#ifdef CONFIG_ETRAX_I2C_EEPROM_PROBE
|
||||
#define EETEXT "Found"
|
||||
#else
|
||||
#define EETEXT "Assuming"
|
||||
#endif
|
||||
if (register_chrdev(EEPROM_MAJOR_NR, eeprom_name, &eeprom_fops))
|
||||
{
|
||||
printk(KERN_INFO "%s: unable to get major %d for eeprom device\n",
|
||||
eeprom_name, EEPROM_MAJOR_NR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printk("EEPROM char device v0.3, (c) 2000 Axis Communications AB\n");
|
||||
|
||||
/*
|
||||
* Note: Most of this probing method was taken from the printserver (5470e)
|
||||
* codebase. It did not contain a way of finding the 16kB chips
|
||||
* (M24128 or variants). The method used here might not work
|
||||
* for all models. If you encounter problems the easiest way
|
||||
* is probably to define your model within #ifdef's, and hard-
|
||||
* code it.
|
||||
*/
|
||||
|
||||
eeprom.size = 0;
|
||||
eeprom.usec_delay_writecycles = INITIAL_WRITEDELAY_US;
|
||||
eeprom.usec_delay_step = 128;
|
||||
eeprom.adapt_state = 0;
|
||||
|
||||
#ifdef CONFIG_ETRAX_I2C_EEPROM_PROBE
|
||||
i2c_start();
|
||||
i2c_outbyte(0x80);
|
||||
if(!i2c_getack())
|
||||
{
|
||||
/* It's not 8k.. */
|
||||
int success = 0;
|
||||
unsigned char buf_2k_start[16];
|
||||
|
||||
/* Im not sure this will work... :) */
|
||||
/* assume 2kB, if failure go for 16kB */
|
||||
/* Test with 16kB settings.. */
|
||||
/* If it's a 2kB EEPROM and we address it outside it's range
|
||||
* it will mirror the address space:
|
||||
* 1. We read two locations (that are mirrored),
|
||||
* if the content differs * it's a 16kB EEPROM.
|
||||
* 2. if it doesn't differ - write different value to one of the locations,
|
||||
* check the other - if content still is the same it's a 2k EEPROM,
|
||||
* restore original data.
|
||||
*/
|
||||
#define LOC1 8
|
||||
#define LOC2 (0x1fb) /*1fb, 3ed, 5df, 7d1 */
|
||||
|
||||
/* 2k settings */
|
||||
i2c_stop();
|
||||
eeprom.size = EEPROM_2KB;
|
||||
eeprom.select_cmd = 0xA0;
|
||||
eeprom.sequential_write_pagesize = 16;
|
||||
if( eeprom_read_buf( 0, buf_2k_start, 16 ) == 16 )
|
||||
{
|
||||
D(printk("2k start: '%16.16s'\n", buf_2k_start));
|
||||
}
|
||||
else
|
||||
{
|
||||
printk(KERN_INFO "%s: Failed to read in 2k mode!\n", eeprom_name);
|
||||
}
|
||||
|
||||
/* 16k settings */
|
||||
eeprom.size = EEPROM_16KB;
|
||||
eeprom.select_cmd = 0xA0;
|
||||
eeprom.sequential_write_pagesize = 64;
|
||||
|
||||
{
|
||||
unsigned char loc1[4], loc2[4], tmp[4];
|
||||
if( eeprom_read_buf(LOC2, loc2, 4) == 4)
|
||||
{
|
||||
if( eeprom_read_buf(LOC1, loc1, 4) == 4)
|
||||
{
|
||||
D(printk("0 loc1: (%i) '%4.4s' loc2 (%i) '%4.4s'\n",
|
||||
LOC1, loc1, LOC2, loc2));
|
||||
#if 0
|
||||
if (memcmp(loc1, loc2, 4) != 0 )
|
||||
{
|
||||
/* It's 16k */
|
||||
printk(KERN_INFO "%s: 16k detected in step 1\n", eeprom_name);
|
||||
eeprom.size = EEPROM_16KB;
|
||||
success = 1;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* Do step 2 check */
|
||||
/* Invert value */
|
||||
loc1[0] = ~loc1[0];
|
||||
if (eeprom_write_buf(LOC1, loc1, 1) == 1)
|
||||
{
|
||||
/* If 2k EEPROM this write will actually write 10 bytes
|
||||
* from pos 0
|
||||
*/
|
||||
D(printk("1 loc1: (%i) '%4.4s' loc2 (%i) '%4.4s'\n",
|
||||
LOC1, loc1, LOC2, loc2));
|
||||
if( eeprom_read_buf(LOC1, tmp, 4) == 4)
|
||||
{
|
||||
D(printk("2 loc1: (%i) '%4.4s' tmp '%4.4s'\n",
|
||||
LOC1, loc1, tmp));
|
||||
if (memcmp(loc1, tmp, 4) != 0 )
|
||||
{
|
||||
printk(KERN_INFO "%s: read and write differs! Not 16kB\n",
|
||||
eeprom_name);
|
||||
loc1[0] = ~loc1[0];
|
||||
|
||||
if (eeprom_write_buf(LOC1, loc1, 1) == 1)
|
||||
{
|
||||
success = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
printk(KERN_INFO "%s: Restore 2k failed during probe,"
|
||||
" EEPROM might be corrupt!\n", eeprom_name);
|
||||
|
||||
}
|
||||
i2c_stop();
|
||||
/* Go to 2k mode and write original data */
|
||||
eeprom.size = EEPROM_2KB;
|
||||
eeprom.select_cmd = 0xA0;
|
||||
eeprom.sequential_write_pagesize = 16;
|
||||
if( eeprom_write_buf(0, buf_2k_start, 16) == 16)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
printk(KERN_INFO "%s: Failed to write back 2k start!\n",
|
||||
eeprom_name);
|
||||
}
|
||||
|
||||
eeprom.size = EEPROM_2KB;
|
||||
}
|
||||
}
|
||||
|
||||
if(!success)
|
||||
{
|
||||
if( eeprom_read_buf(LOC2, loc2, 1) == 1)
|
||||
{
|
||||
D(printk("0 loc1: (%i) '%4.4s' loc2 (%i) '%4.4s'\n",
|
||||
LOC1, loc1, LOC2, loc2));
|
||||
if (memcmp(loc1, loc2, 4) == 0 )
|
||||
{
|
||||
/* Data the same, must be mirrored -> 2k */
|
||||
/* Restore data */
|
||||
printk(KERN_INFO "%s: 2k detected in step 2\n", eeprom_name);
|
||||
loc1[0] = ~loc1[0];
|
||||
if (eeprom_write_buf(LOC1, loc1, 1) == 1)
|
||||
{
|
||||
success = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
printk(KERN_INFO "%s: Restore 2k failed during probe,"
|
||||
" EEPROM might be corrupt!\n", eeprom_name);
|
||||
|
||||
}
|
||||
|
||||
eeprom.size = EEPROM_2KB;
|
||||
}
|
||||
else
|
||||
{
|
||||
printk(KERN_INFO "%s: 16k detected in step 2\n",
|
||||
eeprom_name);
|
||||
loc1[0] = ~loc1[0];
|
||||
/* Data differs, assume 16k */
|
||||
/* Restore data */
|
||||
if (eeprom_write_buf(LOC1, loc1, 1) == 1)
|
||||
{
|
||||
success = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
printk(KERN_INFO "%s: Restore 16k failed during probe,"
|
||||
" EEPROM might be corrupt!\n", eeprom_name);
|
||||
}
|
||||
|
||||
eeprom.size = EEPROM_16KB;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} /* read LOC1 */
|
||||
} /* address LOC1 */
|
||||
if (!success)
|
||||
{
|
||||
printk(KERN_INFO "%s: Probing failed!, using 2KB!\n", eeprom_name);
|
||||
eeprom.size = EEPROM_2KB;
|
||||
}
|
||||
} /* read */
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
i2c_outbyte(0x00);
|
||||
if(!i2c_getack())
|
||||
{
|
||||
/* No 8k */
|
||||
eeprom.size = EEPROM_2KB;
|
||||
}
|
||||
else
|
||||
{
|
||||
i2c_start();
|
||||
i2c_outbyte(0x81);
|
||||
if (!i2c_getack())
|
||||
{
|
||||
eeprom.size = EEPROM_2KB;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* It's a 8kB */
|
||||
i2c_inbyte();
|
||||
eeprom.size = EEPROM_8KB;
|
||||
}
|
||||
}
|
||||
}
|
||||
i2c_stop();
|
||||
#elif defined(CONFIG_ETRAX_I2C_EEPROM_16KB)
|
||||
eeprom.size = EEPROM_16KB;
|
||||
#elif defined(CONFIG_ETRAX_I2C_EEPROM_8KB)
|
||||
eeprom.size = EEPROM_8KB;
|
||||
#elif defined(CONFIG_ETRAX_I2C_EEPROM_2KB)
|
||||
eeprom.size = EEPROM_2KB;
|
||||
#endif
|
||||
|
||||
switch(eeprom.size)
|
||||
{
|
||||
case (EEPROM_2KB):
|
||||
printk("%s: " EETEXT " i2c compatible 2kB eeprom.\n", eeprom_name);
|
||||
eeprom.sequential_write_pagesize = 16;
|
||||
eeprom.select_cmd = 0xA0;
|
||||
break;
|
||||
case (EEPROM_8KB):
|
||||
printk("%s: " EETEXT " i2c compatible 8kB eeprom.\n", eeprom_name);
|
||||
eeprom.sequential_write_pagesize = 16;
|
||||
eeprom.select_cmd = 0x80;
|
||||
break;
|
||||
case (EEPROM_16KB):
|
||||
printk("%s: " EETEXT " i2c compatible 16kB eeprom.\n", eeprom_name);
|
||||
eeprom.sequential_write_pagesize = 64;
|
||||
eeprom.select_cmd = 0xA0;
|
||||
break;
|
||||
default:
|
||||
eeprom.size = 0;
|
||||
printk("%s: Did not find a supported eeprom\n", eeprom_name);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
eeprom_disable_write_protect();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Opens the device. */
|
||||
static int eeprom_open(struct inode * inode, struct file * file)
|
||||
{
|
||||
if(iminor(inode) != EEPROM_MINOR_NR)
|
||||
return -ENXIO;
|
||||
if(imajor(inode) != EEPROM_MAJOR_NR)
|
||||
return -ENXIO;
|
||||
|
||||
if( eeprom.size > 0 )
|
||||
{
|
||||
/* OK */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* No EEprom found */
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
/* Changes the current file position. */
|
||||
|
||||
static loff_t eeprom_lseek(struct file * file, loff_t offset, int orig)
|
||||
{
|
||||
/*
|
||||
* orig 0: position from beginning of eeprom
|
||||
* orig 1: relative from current position
|
||||
* orig 2: position from last eeprom address
|
||||
*/
|
||||
|
||||
switch (orig)
|
||||
{
|
||||
case 0:
|
||||
file->f_pos = offset;
|
||||
break;
|
||||
case 1:
|
||||
file->f_pos += offset;
|
||||
break;
|
||||
case 2:
|
||||
file->f_pos = eeprom.size - offset;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* truncate position */
|
||||
if (file->f_pos < 0)
|
||||
{
|
||||
file->f_pos = 0;
|
||||
return(-EOVERFLOW);
|
||||
}
|
||||
|
||||
if (file->f_pos >= eeprom.size)
|
||||
{
|
||||
file->f_pos = eeprom.size - 1;
|
||||
return(-EOVERFLOW);
|
||||
}
|
||||
|
||||
return ( file->f_pos );
|
||||
}
|
||||
|
||||
/* Reads data from eeprom. */
|
||||
|
||||
static int eeprom_read_buf(loff_t addr, char * buf, int count)
|
||||
{
|
||||
return eeprom_read(NULL, buf, count, &addr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Reads data from eeprom. */
|
||||
|
||||
static ssize_t eeprom_read(struct file * file, char * buf, size_t count, loff_t *off)
|
||||
{
|
||||
int read=0;
|
||||
unsigned long p = *off;
|
||||
|
||||
unsigned char page;
|
||||
|
||||
if(p >= eeprom.size) /* Address i 0 - (size-1) */
|
||||
{
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (mutex_lock_interruptible(&eeprom.lock))
|
||||
return -EINTR;
|
||||
|
||||
page = (unsigned char) (p >> 8);
|
||||
|
||||
if(!eeprom_address(p))
|
||||
{
|
||||
printk(KERN_INFO "%s: Read failed to address the eeprom: "
|
||||
"0x%08X (%i) page: %i\n", eeprom_name, (int)p, (int)p, page);
|
||||
i2c_stop();
|
||||
|
||||
/* don't forget to wake them up */
|
||||
mutex_unlock(&eeprom.lock);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if( (p + count) > eeprom.size)
|
||||
{
|
||||
/* truncate count */
|
||||
count = eeprom.size - p;
|
||||
}
|
||||
|
||||
/* stop dummy write op and initiate the read op */
|
||||
i2c_start();
|
||||
|
||||
/* special case for small eeproms */
|
||||
if(eeprom.size < EEPROM_16KB)
|
||||
{
|
||||
i2c_outbyte( eeprom.select_cmd | 1 | (page << 1) );
|
||||
}
|
||||
|
||||
/* go on with the actual read */
|
||||
read = read_from_eeprom( buf, count);
|
||||
|
||||
if(read > 0)
|
||||
{
|
||||
*off += read;
|
||||
}
|
||||
|
||||
mutex_unlock(&eeprom.lock);
|
||||
return read;
|
||||
}
|
||||
|
||||
/* Writes data to eeprom. */
|
||||
|
||||
static int eeprom_write_buf(loff_t addr, const char * buf, int count)
|
||||
{
|
||||
return eeprom_write(NULL, buf, count, &addr);
|
||||
}
|
||||
|
||||
|
||||
/* Writes data to eeprom. */
|
||||
|
||||
static ssize_t eeprom_write(struct file * file, const char * buf, size_t count,
|
||||
loff_t *off)
|
||||
{
|
||||
int i, written, restart=1;
|
||||
unsigned long p;
|
||||
|
||||
if (!access_ok(VERIFY_READ, buf, count))
|
||||
{
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
/* bail out if we get interrupted */
|
||||
if (mutex_lock_interruptible(&eeprom.lock))
|
||||
return -EINTR;
|
||||
for(i = 0; (i < EEPROM_RETRIES) && (restart > 0); i++)
|
||||
{
|
||||
restart = 0;
|
||||
written = 0;
|
||||
p = *off;
|
||||
|
||||
|
||||
while( (written < count) && (p < eeprom.size))
|
||||
{
|
||||
/* address the eeprom */
|
||||
if(!eeprom_address(p))
|
||||
{
|
||||
printk(KERN_INFO "%s: Write failed to address the eeprom: "
|
||||
"0x%08X (%i) \n", eeprom_name, (int)p, (int)p);
|
||||
i2c_stop();
|
||||
|
||||
/* don't forget to wake them up */
|
||||
mutex_unlock(&eeprom.lock);
|
||||
return -EFAULT;
|
||||
}
|
||||
#ifdef EEPROM_ADAPTIVE_TIMING
|
||||
/* Adaptive algorithm to adjust timing */
|
||||
if (eeprom.retry_cnt_addr > 0)
|
||||
{
|
||||
/* To Low now */
|
||||
D(printk(">D=%i d=%i\n",
|
||||
eeprom.usec_delay_writecycles, eeprom.usec_delay_step));
|
||||
|
||||
if (eeprom.usec_delay_step < 4)
|
||||
{
|
||||
eeprom.usec_delay_step++;
|
||||
eeprom.usec_delay_writecycles += eeprom.usec_delay_step;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
if (eeprom.adapt_state > 0)
|
||||
{
|
||||
/* To Low before */
|
||||
eeprom.usec_delay_step *= 2;
|
||||
if (eeprom.usec_delay_step > 2)
|
||||
{
|
||||
eeprom.usec_delay_step--;
|
||||
}
|
||||
eeprom.usec_delay_writecycles += eeprom.usec_delay_step;
|
||||
}
|
||||
else if (eeprom.adapt_state < 0)
|
||||
{
|
||||
/* To High before (toggle dir) */
|
||||
eeprom.usec_delay_writecycles += eeprom.usec_delay_step;
|
||||
if (eeprom.usec_delay_step > 1)
|
||||
{
|
||||
eeprom.usec_delay_step /= 2;
|
||||
eeprom.usec_delay_step--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
eeprom.adapt_state = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* To High (or good) now */
|
||||
D(printk("<D=%i d=%i\n",
|
||||
eeprom.usec_delay_writecycles, eeprom.usec_delay_step));
|
||||
|
||||
if (eeprom.adapt_state < 0)
|
||||
{
|
||||
/* To High before */
|
||||
if (eeprom.usec_delay_step > 1)
|
||||
{
|
||||
eeprom.usec_delay_step *= 2;
|
||||
eeprom.usec_delay_step--;
|
||||
|
||||
if (eeprom.usec_delay_writecycles > eeprom.usec_delay_step)
|
||||
{
|
||||
eeprom.usec_delay_writecycles -= eeprom.usec_delay_step;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (eeprom.adapt_state > 0)
|
||||
{
|
||||
/* To Low before (toggle dir) */
|
||||
if (eeprom.usec_delay_writecycles > eeprom.usec_delay_step)
|
||||
{
|
||||
eeprom.usec_delay_writecycles -= eeprom.usec_delay_step;
|
||||
}
|
||||
if (eeprom.usec_delay_step > 1)
|
||||
{
|
||||
eeprom.usec_delay_step /= 2;
|
||||
eeprom.usec_delay_step--;
|
||||
}
|
||||
|
||||
eeprom.adapt_state = -1;
|
||||
}
|
||||
|
||||
if (eeprom.adapt_state > -100)
|
||||
{
|
||||
eeprom.adapt_state--;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Restart adaption */
|
||||
D(printk("#Restart\n"));
|
||||
eeprom.usec_delay_step++;
|
||||
}
|
||||
}
|
||||
#endif /* EEPROM_ADAPTIVE_TIMING */
|
||||
/* write until we hit a page boundary or count */
|
||||
do
|
||||
{
|
||||
i2c_outbyte(buf[written]);
|
||||
if(!i2c_getack())
|
||||
{
|
||||
restart=1;
|
||||
printk(KERN_INFO "%s: write error, retrying. %d\n", eeprom_name, i);
|
||||
i2c_stop();
|
||||
break;
|
||||
}
|
||||
written++;
|
||||
p++;
|
||||
} while( written < count && ( p % eeprom.sequential_write_pagesize ));
|
||||
|
||||
/* end write cycle */
|
||||
i2c_stop();
|
||||
i2c_delay(eeprom.usec_delay_writecycles);
|
||||
} /* while */
|
||||
} /* for */
|
||||
|
||||
mutex_unlock(&eeprom.lock);
|
||||
if (written == 0 && p >= eeprom.size){
|
||||
return -ENOSPC;
|
||||
}
|
||||
*off = p;
|
||||
return written;
|
||||
}
|
||||
|
||||
/* Closes the device. */
|
||||
|
||||
static int eeprom_close(struct inode * inode, struct file * file)
|
||||
{
|
||||
/* do nothing for now */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Sets the current address of the eeprom. */
|
||||
|
||||
static int eeprom_address(unsigned long addr)
|
||||
{
|
||||
int i;
|
||||
unsigned char page, offset;
|
||||
|
||||
page = (unsigned char) (addr >> 8);
|
||||
offset = (unsigned char) addr;
|
||||
|
||||
for(i = 0; i < EEPROM_RETRIES; i++)
|
||||
{
|
||||
/* start a dummy write for addressing */
|
||||
i2c_start();
|
||||
|
||||
if(eeprom.size == EEPROM_16KB)
|
||||
{
|
||||
i2c_outbyte( eeprom.select_cmd );
|
||||
i2c_getack();
|
||||
i2c_outbyte(page);
|
||||
}
|
||||
else
|
||||
{
|
||||
i2c_outbyte( eeprom.select_cmd | (page << 1) );
|
||||
}
|
||||
if(!i2c_getack())
|
||||
{
|
||||
/* retry */
|
||||
i2c_stop();
|
||||
/* Must have a delay here.. 500 works, >50, 100->works 5th time*/
|
||||
i2c_delay(MAX_WRITEDELAY_US / EEPROM_RETRIES * i);
|
||||
/* The chip needs up to 10 ms from write stop to next start */
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
i2c_outbyte(offset);
|
||||
|
||||
if(!i2c_getack())
|
||||
{
|
||||
/* retry */
|
||||
i2c_stop();
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
eeprom.retry_cnt_addr = i;
|
||||
D(printk("%i\n", eeprom.retry_cnt_addr));
|
||||
if(eeprom.retry_cnt_addr == EEPROM_RETRIES)
|
||||
{
|
||||
/* failed */
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Reads from current address. */
|
||||
|
||||
static int read_from_eeprom(char * buf, int count)
|
||||
{
|
||||
int i, read=0;
|
||||
|
||||
for(i = 0; i < EEPROM_RETRIES; i++)
|
||||
{
|
||||
if(eeprom.size == EEPROM_16KB)
|
||||
{
|
||||
i2c_outbyte( eeprom.select_cmd | 1 );
|
||||
}
|
||||
|
||||
if(i2c_getack())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(i == EEPROM_RETRIES)
|
||||
{
|
||||
printk(KERN_INFO "%s: failed to read from eeprom\n", eeprom_name);
|
||||
i2c_stop();
|
||||
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
while( (read < count))
|
||||
{
|
||||
if (put_user(i2c_inbyte(), &buf[read++]))
|
||||
{
|
||||
i2c_stop();
|
||||
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
/*
|
||||
* make sure we don't ack last byte or you will get very strange
|
||||
* results!
|
||||
*/
|
||||
if(read < count)
|
||||
{
|
||||
i2c_sendack();
|
||||
}
|
||||
}
|
||||
|
||||
/* stop the operation */
|
||||
i2c_stop();
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
/* Disables write protection if applicable. */
|
||||
|
||||
#define DBP_SAVE(x)
|
||||
#define ax_printf printk
|
||||
static void eeprom_disable_write_protect(void)
|
||||
{
|
||||
/* Disable write protect */
|
||||
if (eeprom.size == EEPROM_8KB)
|
||||
{
|
||||
/* Step 1 Set WEL = 1 (write 00000010 to address 1FFFh */
|
||||
i2c_start();
|
||||
i2c_outbyte(0xbe);
|
||||
if(!i2c_getack())
|
||||
{
|
||||
DBP_SAVE(ax_printf("Get ack returns false\n"));
|
||||
}
|
||||
i2c_outbyte(0xFF);
|
||||
if(!i2c_getack())
|
||||
{
|
||||
DBP_SAVE(ax_printf("Get ack returns false 2\n"));
|
||||
}
|
||||
i2c_outbyte(0x02);
|
||||
if(!i2c_getack())
|
||||
{
|
||||
DBP_SAVE(ax_printf("Get ack returns false 3\n"));
|
||||
}
|
||||
i2c_stop();
|
||||
|
||||
i2c_delay(1000);
|
||||
|
||||
/* Step 2 Set RWEL = 1 (write 00000110 to address 1FFFh */
|
||||
i2c_start();
|
||||
i2c_outbyte(0xbe);
|
||||
if(!i2c_getack())
|
||||
{
|
||||
DBP_SAVE(ax_printf("Get ack returns false 55\n"));
|
||||
}
|
||||
i2c_outbyte(0xFF);
|
||||
if(!i2c_getack())
|
||||
{
|
||||
DBP_SAVE(ax_printf("Get ack returns false 52\n"));
|
||||
}
|
||||
i2c_outbyte(0x06);
|
||||
if(!i2c_getack())
|
||||
{
|
||||
DBP_SAVE(ax_printf("Get ack returns false 53\n"));
|
||||
}
|
||||
i2c_stop();
|
||||
|
||||
/* Step 3 Set BP1, BP0, and/or WPEN bits (write 00000110 to address 1FFFh */
|
||||
i2c_start();
|
||||
i2c_outbyte(0xbe);
|
||||
if(!i2c_getack())
|
||||
{
|
||||
DBP_SAVE(ax_printf("Get ack returns false 56\n"));
|
||||
}
|
||||
i2c_outbyte(0xFF);
|
||||
if(!i2c_getack())
|
||||
{
|
||||
DBP_SAVE(ax_printf("Get ack returns false 57\n"));
|
||||
}
|
||||
i2c_outbyte(0x06);
|
||||
if(!i2c_getack())
|
||||
{
|
||||
DBP_SAVE(ax_printf("Get ack returns false 58\n"));
|
||||
}
|
||||
i2c_stop();
|
||||
|
||||
/* Write protect disabled */
|
||||
}
|
||||
}
|
||||
device_initcall(eeprom_init);
|
||||
|
|
@ -1,857 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Etrax general port I/O device
|
||||
*
|
||||
* Copyright (c) 1999-2007 Axis Communications AB
|
||||
*
|
||||
* Authors: Bjorn Wesen (initial version)
|
||||
* Ola Knutsson (LED handling)
|
||||
* Johan Adolfsson (read/set directions, write, port G)
|
||||
*/
|
||||
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include <asm/etraxgpio.h>
|
||||
#include <arch/svinto.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/irq.h>
|
||||
#include <arch/io_interface_mux.h>
|
||||
|
||||
#define GPIO_MAJOR 120 /* experimental MAJOR number */
|
||||
|
||||
#define D(x)
|
||||
|
||||
#if 0
|
||||
static int dp_cnt;
|
||||
#define DP(x) do { dp_cnt++; if (dp_cnt % 1000 == 0) x; }while(0)
|
||||
#else
|
||||
#define DP(x)
|
||||
#endif
|
||||
|
||||
static char gpio_name[] = "etrax gpio";
|
||||
|
||||
#if 0
|
||||
static wait_queue_head_t *gpio_wq;
|
||||
#endif
|
||||
|
||||
static long gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
|
||||
static ssize_t gpio_write(struct file *file, const char __user *buf,
|
||||
size_t count, loff_t *off);
|
||||
static int gpio_open(struct inode *inode, struct file *filp);
|
||||
static int gpio_release(struct inode *inode, struct file *filp);
|
||||
static __poll_t gpio_poll(struct file *filp, struct poll_table_struct *wait);
|
||||
|
||||
/* private data per open() of this driver */
|
||||
|
||||
struct gpio_private {
|
||||
struct gpio_private *next;
|
||||
/* These fields are for PA and PB only */
|
||||
volatile unsigned char *port, *shadow;
|
||||
volatile unsigned char *dir, *dir_shadow;
|
||||
unsigned char changeable_dir;
|
||||
unsigned char changeable_bits;
|
||||
unsigned char clk_mask;
|
||||
unsigned char data_mask;
|
||||
unsigned char write_msb;
|
||||
unsigned char pad1, pad2, pad3;
|
||||
/* These fields are generic */
|
||||
unsigned long highalarm, lowalarm;
|
||||
wait_queue_head_t alarm_wq;
|
||||
int minor;
|
||||
};
|
||||
|
||||
/* linked list of alarms to check for */
|
||||
|
||||
static struct gpio_private *alarmlist;
|
||||
|
||||
static int gpio_some_alarms; /* Set if someone uses alarm */
|
||||
static unsigned long gpio_pa_irq_enabled_mask;
|
||||
|
||||
static DEFINE_SPINLOCK(gpio_lock); /* Protect directions etc */
|
||||
|
||||
/* Port A and B use 8 bit access, but Port G is 32 bit */
|
||||
#define NUM_PORTS (GPIO_MINOR_B+1)
|
||||
|
||||
static volatile unsigned char *ports[NUM_PORTS] = {
|
||||
R_PORT_PA_DATA,
|
||||
R_PORT_PB_DATA,
|
||||
};
|
||||
static volatile unsigned char *shads[NUM_PORTS] = {
|
||||
&port_pa_data_shadow,
|
||||
&port_pb_data_shadow
|
||||
};
|
||||
|
||||
/* What direction bits that are user changeable 1=changeable*/
|
||||
#ifndef CONFIG_ETRAX_PA_CHANGEABLE_DIR
|
||||
#define CONFIG_ETRAX_PA_CHANGEABLE_DIR 0x00
|
||||
#endif
|
||||
#ifndef CONFIG_ETRAX_PB_CHANGEABLE_DIR
|
||||
#define CONFIG_ETRAX_PB_CHANGEABLE_DIR 0x00
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_ETRAX_PA_CHANGEABLE_BITS
|
||||
#define CONFIG_ETRAX_PA_CHANGEABLE_BITS 0xFF
|
||||
#endif
|
||||
#ifndef CONFIG_ETRAX_PB_CHANGEABLE_BITS
|
||||
#define CONFIG_ETRAX_PB_CHANGEABLE_BITS 0xFF
|
||||
#endif
|
||||
|
||||
|
||||
static unsigned char changeable_dir[NUM_PORTS] = {
|
||||
CONFIG_ETRAX_PA_CHANGEABLE_DIR,
|
||||
CONFIG_ETRAX_PB_CHANGEABLE_DIR
|
||||
};
|
||||
static unsigned char changeable_bits[NUM_PORTS] = {
|
||||
CONFIG_ETRAX_PA_CHANGEABLE_BITS,
|
||||
CONFIG_ETRAX_PB_CHANGEABLE_BITS
|
||||
};
|
||||
|
||||
static volatile unsigned char *dir[NUM_PORTS] = {
|
||||
R_PORT_PA_DIR,
|
||||
R_PORT_PB_DIR
|
||||
};
|
||||
|
||||
static volatile unsigned char *dir_shadow[NUM_PORTS] = {
|
||||
&port_pa_dir_shadow,
|
||||
&port_pb_dir_shadow
|
||||
};
|
||||
|
||||
/* All bits in port g that can change dir. */
|
||||
static const unsigned long int changeable_dir_g_mask = 0x01FFFF01;
|
||||
|
||||
/* Port G is 32 bit, handle it special, some bits are both inputs
|
||||
and outputs at the same time, only some of the bits can change direction
|
||||
and some of them in groups of 8 bit. */
|
||||
static unsigned long changeable_dir_g;
|
||||
static unsigned long dir_g_in_bits;
|
||||
static unsigned long dir_g_out_bits;
|
||||
static unsigned long dir_g_shadow; /* 1=output */
|
||||
|
||||
#define USE_PORTS(priv) ((priv)->minor <= GPIO_MINOR_B)
|
||||
|
||||
|
||||
static __poll_t gpio_poll(struct file *file, poll_table *wait)
|
||||
{
|
||||
__poll_t mask = 0;
|
||||
struct gpio_private *priv = file->private_data;
|
||||
unsigned long data;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
|
||||
poll_wait(file, &priv->alarm_wq, wait);
|
||||
if (priv->minor == GPIO_MINOR_A) {
|
||||
unsigned long tmp;
|
||||
data = *R_PORT_PA_DATA;
|
||||
/* PA has support for high level interrupt -
|
||||
* lets activate for those low and with highalarm set
|
||||
*/
|
||||
tmp = ~data & priv->highalarm & 0xFF;
|
||||
tmp = (tmp << R_IRQ_MASK1_SET__pa0__BITNR);
|
||||
|
||||
gpio_pa_irq_enabled_mask |= tmp;
|
||||
*R_IRQ_MASK1_SET = tmp;
|
||||
} else if (priv->minor == GPIO_MINOR_B)
|
||||
data = *R_PORT_PB_DATA;
|
||||
else if (priv->minor == GPIO_MINOR_G)
|
||||
data = *R_PORT_G_DATA;
|
||||
else {
|
||||
mask = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((data & priv->highalarm) ||
|
||||
(~data & priv->lowalarm)) {
|
||||
mask = EPOLLIN|EPOLLRDNORM;
|
||||
}
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
DP(printk("gpio_poll ready: mask 0x%08X\n", mask));
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
int etrax_gpio_wake_up_check(void)
|
||||
{
|
||||
struct gpio_private *priv;
|
||||
unsigned long data = 0;
|
||||
int ret = 0;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
priv = alarmlist;
|
||||
while (priv) {
|
||||
if (USE_PORTS(priv))
|
||||
data = *priv->port;
|
||||
else if (priv->minor == GPIO_MINOR_G)
|
||||
data = *R_PORT_G_DATA;
|
||||
|
||||
if ((data & priv->highalarm) ||
|
||||
(~data & priv->lowalarm)) {
|
||||
DP(printk("etrax_gpio_wake_up_check %i\n",priv->minor));
|
||||
wake_up_interruptible(&priv->alarm_wq);
|
||||
ret = 1;
|
||||
}
|
||||
priv = priv->next;
|
||||
}
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static irqreturn_t
|
||||
gpio_poll_timer_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
if (gpio_some_alarms) {
|
||||
etrax_gpio_wake_up_check();
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
static irqreturn_t
|
||||
gpio_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
unsigned long tmp;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
|
||||
/* Find what PA interrupts are active */
|
||||
tmp = (*R_IRQ_READ1);
|
||||
|
||||
/* Find those that we have enabled */
|
||||
tmp &= gpio_pa_irq_enabled_mask;
|
||||
|
||||
/* Clear them.. */
|
||||
*R_IRQ_MASK1_CLR = tmp;
|
||||
gpio_pa_irq_enabled_mask &= ~tmp;
|
||||
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
|
||||
if (gpio_some_alarms)
|
||||
return IRQ_RETVAL(etrax_gpio_wake_up_check());
|
||||
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
static void gpio_write_bit(struct gpio_private *priv,
|
||||
unsigned char data, int bit)
|
||||
{
|
||||
*priv->port = *priv->shadow &= ~(priv->clk_mask);
|
||||
if (data & 1 << bit)
|
||||
*priv->port = *priv->shadow |= priv->data_mask;
|
||||
else
|
||||
*priv->port = *priv->shadow &= ~(priv->data_mask);
|
||||
|
||||
/* For FPGA: min 5.0ns (DCC) before CCLK high */
|
||||
*priv->port = *priv->shadow |= priv->clk_mask;
|
||||
}
|
||||
|
||||
static void gpio_write_byte(struct gpio_private *priv, unsigned char data)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (priv->write_msb)
|
||||
for (i = 7; i >= 0; i--)
|
||||
gpio_write_bit(priv, data, i);
|
||||
else
|
||||
for (i = 0; i <= 7; i++)
|
||||
gpio_write_bit(priv, data, i);
|
||||
}
|
||||
|
||||
static ssize_t gpio_write(struct file *file, const char __user *buf,
|
||||
size_t count, loff_t *off)
|
||||
{
|
||||
struct gpio_private *priv = file->private_data;
|
||||
unsigned long flags;
|
||||
ssize_t retval = count;
|
||||
|
||||
if (priv->minor != GPIO_MINOR_A && priv->minor != GPIO_MINOR_B)
|
||||
return -EFAULT;
|
||||
|
||||
if (!access_ok(VERIFY_READ, buf, count))
|
||||
return -EFAULT;
|
||||
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
|
||||
/* It must have been configured using the IO_CFG_WRITE_MODE */
|
||||
/* Perhaps a better error code? */
|
||||
if (priv->clk_mask == 0 || priv->data_mask == 0) {
|
||||
retval = -EPERM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
D(printk(KERN_DEBUG "gpio_write: %02X to data 0x%02X "
|
||||
"clk 0x%02X msb: %i\n",
|
||||
count, priv->data_mask, priv->clk_mask, priv->write_msb));
|
||||
|
||||
while (count--)
|
||||
gpio_write_byte(priv, *buf++);
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int
|
||||
gpio_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct gpio_private *priv;
|
||||
int p = iminor(inode);
|
||||
unsigned long flags;
|
||||
|
||||
if (p > GPIO_MINOR_LAST)
|
||||
return -EINVAL;
|
||||
|
||||
priv = kzalloc(sizeof(struct gpio_private), GFP_KERNEL);
|
||||
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->minor = p;
|
||||
|
||||
/* initialize the io/alarm struct */
|
||||
|
||||
if (USE_PORTS(priv)) { /* A and B */
|
||||
priv->port = ports[p];
|
||||
priv->shadow = shads[p];
|
||||
priv->dir = dir[p];
|
||||
priv->dir_shadow = dir_shadow[p];
|
||||
priv->changeable_dir = changeable_dir[p];
|
||||
priv->changeable_bits = changeable_bits[p];
|
||||
} else {
|
||||
priv->port = NULL;
|
||||
priv->shadow = NULL;
|
||||
priv->dir = NULL;
|
||||
priv->dir_shadow = NULL;
|
||||
priv->changeable_dir = 0;
|
||||
priv->changeable_bits = 0;
|
||||
}
|
||||
|
||||
priv->highalarm = 0;
|
||||
priv->lowalarm = 0;
|
||||
priv->clk_mask = 0;
|
||||
priv->data_mask = 0;
|
||||
init_waitqueue_head(&priv->alarm_wq);
|
||||
|
||||
filp->private_data = priv;
|
||||
|
||||
/* link it into our alarmlist */
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
priv->next = alarmlist;
|
||||
alarmlist = priv;
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
gpio_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct gpio_private *p;
|
||||
struct gpio_private *todel;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
|
||||
p = alarmlist;
|
||||
todel = filp->private_data;
|
||||
|
||||
/* unlink from alarmlist and free the private structure */
|
||||
|
||||
if (p == todel) {
|
||||
alarmlist = todel->next;
|
||||
} else {
|
||||
while (p->next != todel)
|
||||
p = p->next;
|
||||
p->next = todel->next;
|
||||
}
|
||||
|
||||
kfree(todel);
|
||||
/* Check if there are still any alarms set */
|
||||
p = alarmlist;
|
||||
while (p) {
|
||||
if (p->highalarm | p->lowalarm) {
|
||||
gpio_some_alarms = 1;
|
||||
goto out;
|
||||
}
|
||||
p = p->next;
|
||||
}
|
||||
gpio_some_alarms = 0;
|
||||
out:
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Main device API. ioctl's to read/set/clear bits, as well as to
|
||||
* set alarms to wait for using a subsequent select().
|
||||
*/
|
||||
inline unsigned long setget_input(struct gpio_private *priv, unsigned long arg)
|
||||
{
|
||||
/* Set direction 0=unchanged 1=input,
|
||||
* return mask with 1=input */
|
||||
if (USE_PORTS(priv)) {
|
||||
*priv->dir = *priv->dir_shadow &=
|
||||
~((unsigned char)arg & priv->changeable_dir);
|
||||
return ~(*priv->dir_shadow) & 0xFF; /* Only 8 bits */
|
||||
}
|
||||
|
||||
if (priv->minor != GPIO_MINOR_G)
|
||||
return 0;
|
||||
|
||||
/* We must fiddle with R_GEN_CONFIG to change dir */
|
||||
if (((arg & dir_g_in_bits) != arg) &&
|
||||
(arg & changeable_dir_g)) {
|
||||
arg &= changeable_dir_g;
|
||||
/* Clear bits in genconfig to set to input */
|
||||
if (arg & (1<<0)) {
|
||||
genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, g0dir);
|
||||
dir_g_in_bits |= (1<<0);
|
||||
dir_g_out_bits &= ~(1<<0);
|
||||
}
|
||||
if ((arg & 0x0000FF00) == 0x0000FF00) {
|
||||
genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, g8_15dir);
|
||||
dir_g_in_bits |= 0x0000FF00;
|
||||
dir_g_out_bits &= ~0x0000FF00;
|
||||
}
|
||||
if ((arg & 0x00FF0000) == 0x00FF0000) {
|
||||
genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, g16_23dir);
|
||||
dir_g_in_bits |= 0x00FF0000;
|
||||
dir_g_out_bits &= ~0x00FF0000;
|
||||
}
|
||||
if (arg & (1<<24)) {
|
||||
genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, g24dir);
|
||||
dir_g_in_bits |= (1<<24);
|
||||
dir_g_out_bits &= ~(1<<24);
|
||||
}
|
||||
D(printk(KERN_DEBUG "gpio: SETINPUT on port G set "
|
||||
"genconfig to 0x%08lX "
|
||||
"in_bits: 0x%08lX "
|
||||
"out_bits: 0x%08lX\n",
|
||||
(unsigned long)genconfig_shadow,
|
||||
dir_g_in_bits, dir_g_out_bits));
|
||||
*R_GEN_CONFIG = genconfig_shadow;
|
||||
/* Must be a >120 ns delay before writing this again */
|
||||
|
||||
}
|
||||
return dir_g_in_bits;
|
||||
} /* setget_input */
|
||||
|
||||
inline unsigned long setget_output(struct gpio_private *priv, unsigned long arg)
|
||||
{
|
||||
if (USE_PORTS(priv)) {
|
||||
*priv->dir = *priv->dir_shadow |=
|
||||
((unsigned char)arg & priv->changeable_dir);
|
||||
return *priv->dir_shadow;
|
||||
}
|
||||
if (priv->minor != GPIO_MINOR_G)
|
||||
return 0;
|
||||
|
||||
/* We must fiddle with R_GEN_CONFIG to change dir */
|
||||
if (((arg & dir_g_out_bits) != arg) &&
|
||||
(arg & changeable_dir_g)) {
|
||||
/* Set bits in genconfig to set to output */
|
||||
if (arg & (1<<0)) {
|
||||
genconfig_shadow |= IO_MASK(R_GEN_CONFIG, g0dir);
|
||||
dir_g_out_bits |= (1<<0);
|
||||
dir_g_in_bits &= ~(1<<0);
|
||||
}
|
||||
if ((arg & 0x0000FF00) == 0x0000FF00) {
|
||||
genconfig_shadow |= IO_MASK(R_GEN_CONFIG, g8_15dir);
|
||||
dir_g_out_bits |= 0x0000FF00;
|
||||
dir_g_in_bits &= ~0x0000FF00;
|
||||
}
|
||||
if ((arg & 0x00FF0000) == 0x00FF0000) {
|
||||
genconfig_shadow |= IO_MASK(R_GEN_CONFIG, g16_23dir);
|
||||
dir_g_out_bits |= 0x00FF0000;
|
||||
dir_g_in_bits &= ~0x00FF0000;
|
||||
}
|
||||
if (arg & (1<<24)) {
|
||||
genconfig_shadow |= IO_MASK(R_GEN_CONFIG, g24dir);
|
||||
dir_g_out_bits |= (1<<24);
|
||||
dir_g_in_bits &= ~(1<<24);
|
||||
}
|
||||
D(printk(KERN_INFO "gpio: SETOUTPUT on port G set "
|
||||
"genconfig to 0x%08lX "
|
||||
"in_bits: 0x%08lX "
|
||||
"out_bits: 0x%08lX\n",
|
||||
(unsigned long)genconfig_shadow,
|
||||
dir_g_in_bits, dir_g_out_bits));
|
||||
*R_GEN_CONFIG = genconfig_shadow;
|
||||
/* Must be a >120 ns delay before writing this again */
|
||||
}
|
||||
return dir_g_out_bits & 0x7FFFFFFF;
|
||||
} /* setget_output */
|
||||
|
||||
static int
|
||||
gpio_leds_ioctl(unsigned int cmd, unsigned long arg);
|
||||
|
||||
static long gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned long val;
|
||||
int ret = 0;
|
||||
|
||||
struct gpio_private *priv = file->private_data;
|
||||
if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE)
|
||||
return -EINVAL;
|
||||
|
||||
switch (_IOC_NR(cmd)) {
|
||||
case IO_READBITS: /* Use IO_READ_INBITS and IO_READ_OUTBITS instead */
|
||||
// read the port
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
if (USE_PORTS(priv)) {
|
||||
ret = *priv->port;
|
||||
} else if (priv->minor == GPIO_MINOR_G) {
|
||||
ret = (*R_PORT_G_DATA) & 0x7FFFFFFF;
|
||||
}
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
|
||||
break;
|
||||
case IO_SETBITS:
|
||||
// set changeable bits with a 1 in arg
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
|
||||
if (USE_PORTS(priv)) {
|
||||
*priv->port = *priv->shadow |=
|
||||
((unsigned char)arg & priv->changeable_bits);
|
||||
} else if (priv->minor == GPIO_MINOR_G) {
|
||||
*R_PORT_G_DATA = port_g_data_shadow |= (arg & dir_g_out_bits);
|
||||
}
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
|
||||
break;
|
||||
case IO_CLRBITS:
|
||||
// clear changeable bits with a 1 in arg
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
if (USE_PORTS(priv)) {
|
||||
*priv->port = *priv->shadow &=
|
||||
~((unsigned char)arg & priv->changeable_bits);
|
||||
} else if (priv->minor == GPIO_MINOR_G) {
|
||||
*R_PORT_G_DATA = port_g_data_shadow &= ~((unsigned long)arg & dir_g_out_bits);
|
||||
}
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
break;
|
||||
case IO_HIGHALARM:
|
||||
// set alarm when bits with 1 in arg go high
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
priv->highalarm |= arg;
|
||||
gpio_some_alarms = 1;
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
break;
|
||||
case IO_LOWALARM:
|
||||
// set alarm when bits with 1 in arg go low
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
priv->lowalarm |= arg;
|
||||
gpio_some_alarms = 1;
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
break;
|
||||
case IO_CLRALARM:
|
||||
/* clear alarm for bits with 1 in arg */
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
priv->highalarm &= ~arg;
|
||||
priv->lowalarm &= ~arg;
|
||||
{
|
||||
/* Must update gpio_some_alarms */
|
||||
struct gpio_private *p = alarmlist;
|
||||
int some_alarms;
|
||||
p = alarmlist;
|
||||
some_alarms = 0;
|
||||
while (p) {
|
||||
if (p->highalarm | p->lowalarm) {
|
||||
some_alarms = 1;
|
||||
break;
|
||||
}
|
||||
p = p->next;
|
||||
}
|
||||
gpio_some_alarms = some_alarms;
|
||||
}
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
break;
|
||||
case IO_READDIR: /* Use IO_SETGET_INPUT/OUTPUT instead! */
|
||||
/* Read direction 0=input 1=output */
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
if (USE_PORTS(priv)) {
|
||||
ret = *priv->dir_shadow;
|
||||
} else if (priv->minor == GPIO_MINOR_G) {
|
||||
/* Note: Some bits are both in and out,
|
||||
* Those that are dual is set here as well.
|
||||
*/
|
||||
ret = (dir_g_shadow | dir_g_out_bits) & 0x7FFFFFFF;
|
||||
}
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
break;
|
||||
case IO_SETINPUT: /* Use IO_SETGET_INPUT instead! */
|
||||
/* Set direction 0=unchanged 1=input,
|
||||
* return mask with 1=input
|
||||
*/
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
ret = setget_input(priv, arg) & 0x7FFFFFFF;
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
break;
|
||||
case IO_SETOUTPUT: /* Use IO_SETGET_OUTPUT instead! */
|
||||
/* Set direction 0=unchanged 1=output,
|
||||
* return mask with 1=output
|
||||
*/
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
ret = setget_output(priv, arg) & 0x7FFFFFFF;
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
break;
|
||||
case IO_SHUTDOWN:
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
SOFT_SHUTDOWN();
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
break;
|
||||
case IO_GET_PWR_BT:
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
#if defined (CONFIG_ETRAX_SOFT_SHUTDOWN)
|
||||
ret = (*R_PORT_G_DATA & ( 1 << CONFIG_ETRAX_POWERBUTTON_BIT));
|
||||
#else
|
||||
ret = 0;
|
||||
#endif
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
break;
|
||||
case IO_CFG_WRITE_MODE:
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
priv->clk_mask = arg & 0xFF;
|
||||
priv->data_mask = (arg >> 8) & 0xFF;
|
||||
priv->write_msb = (arg >> 16) & 0x01;
|
||||
/* Check if we're allowed to change the bits and
|
||||
* the direction is correct
|
||||
*/
|
||||
if (!((priv->clk_mask & priv->changeable_bits) &&
|
||||
(priv->data_mask & priv->changeable_bits) &&
|
||||
(priv->clk_mask & *priv->dir_shadow) &&
|
||||
(priv->data_mask & *priv->dir_shadow)))
|
||||
{
|
||||
priv->clk_mask = 0;
|
||||
priv->data_mask = 0;
|
||||
ret = -EPERM;
|
||||
}
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
break;
|
||||
case IO_READ_INBITS:
|
||||
/* *arg is result of reading the input pins */
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
if (USE_PORTS(priv)) {
|
||||
val = *priv->port;
|
||||
} else if (priv->minor == GPIO_MINOR_G) {
|
||||
val = *R_PORT_G_DATA;
|
||||
}
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
if (copy_to_user((void __user *)arg, &val, sizeof(val)))
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
case IO_READ_OUTBITS:
|
||||
/* *arg is result of reading the output shadow */
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
if (USE_PORTS(priv)) {
|
||||
val = *priv->shadow;
|
||||
} else if (priv->minor == GPIO_MINOR_G) {
|
||||
val = port_g_data_shadow;
|
||||
}
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
if (copy_to_user((void __user *)arg, &val, sizeof(val)))
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
case IO_SETGET_INPUT:
|
||||
/* bits set in *arg is set to input,
|
||||
* *arg updated with current input pins.
|
||||
*/
|
||||
if (copy_from_user(&val, (void __user *)arg, sizeof(val)))
|
||||
{
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
val = setget_input(priv, val);
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
if (copy_to_user((void __user *)arg, &val, sizeof(val)))
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
case IO_SETGET_OUTPUT:
|
||||
/* bits set in *arg is set to output,
|
||||
* *arg updated with current output pins.
|
||||
*/
|
||||
if (copy_from_user(&val, (void __user *)arg, sizeof(val))) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
val = setget_output(priv, val);
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
if (copy_to_user((void __user *)arg, &val, sizeof(val)))
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
default:
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
if (priv->minor == GPIO_MINOR_LEDS)
|
||||
ret = gpio_leds_ioctl(cmd, arg);
|
||||
else
|
||||
ret = -EINVAL;
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
} /* switch */
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
gpio_leds_ioctl(unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
unsigned char green;
|
||||
unsigned char red;
|
||||
|
||||
switch (_IOC_NR(cmd)) {
|
||||
case IO_LEDACTIVE_SET:
|
||||
green = ((unsigned char)arg) & 1;
|
||||
red = (((unsigned char)arg) >> 1) & 1;
|
||||
CRIS_LED_ACTIVE_SET_G(green);
|
||||
CRIS_LED_ACTIVE_SET_R(red);
|
||||
break;
|
||||
|
||||
case IO_LED_SETBIT:
|
||||
CRIS_LED_BIT_SET(arg);
|
||||
break;
|
||||
|
||||
case IO_LED_CLRBIT:
|
||||
CRIS_LED_BIT_CLR(arg);
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
} /* switch */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations gpio_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.poll = gpio_poll,
|
||||
.unlocked_ioctl = gpio_ioctl,
|
||||
.write = gpio_write,
|
||||
.open = gpio_open,
|
||||
.release = gpio_release,
|
||||
.llseek = noop_llseek,
|
||||
};
|
||||
|
||||
static void ioif_watcher(const unsigned int gpio_in_available,
|
||||
const unsigned int gpio_out_available,
|
||||
const unsigned char pa_available,
|
||||
const unsigned char pb_available)
|
||||
{
|
||||
unsigned long int flags;
|
||||
|
||||
D(printk(KERN_DEBUG "gpio.c: ioif_watcher called\n"));
|
||||
D(printk(KERN_DEBUG "gpio.c: G in: 0x%08x G out: 0x%08x "
|
||||
"PA: 0x%02x PB: 0x%02x\n",
|
||||
gpio_in_available, gpio_out_available,
|
||||
pa_available, pb_available));
|
||||
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
|
||||
dir_g_in_bits = gpio_in_available;
|
||||
dir_g_out_bits = gpio_out_available;
|
||||
|
||||
/* Initialise the dir_g_shadow etc. depending on genconfig */
|
||||
/* 0=input 1=output */
|
||||
if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, g0dir, out))
|
||||
dir_g_shadow |= (1 << 0);
|
||||
if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, g8_15dir, out))
|
||||
dir_g_shadow |= 0x0000FF00;
|
||||
if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, g16_23dir, out))
|
||||
dir_g_shadow |= 0x00FF0000;
|
||||
if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, g24dir, out))
|
||||
dir_g_shadow |= (1 << 24);
|
||||
|
||||
changeable_dir_g = changeable_dir_g_mask;
|
||||
changeable_dir_g &= dir_g_out_bits;
|
||||
changeable_dir_g &= dir_g_in_bits;
|
||||
|
||||
/* Correct the bits that can change direction */
|
||||
dir_g_out_bits &= ~changeable_dir_g;
|
||||
dir_g_out_bits |= dir_g_shadow;
|
||||
dir_g_in_bits &= ~changeable_dir_g;
|
||||
dir_g_in_bits |= (~dir_g_shadow & changeable_dir_g);
|
||||
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
|
||||
printk(KERN_INFO "GPIO port G: in_bits: 0x%08lX out_bits: 0x%08lX "
|
||||
"val: %08lX\n",
|
||||
dir_g_in_bits, dir_g_out_bits, (unsigned long)*R_PORT_G_DATA);
|
||||
printk(KERN_INFO "GPIO port G: dir: %08lX changeable: %08lX\n",
|
||||
dir_g_shadow, changeable_dir_g);
|
||||
}
|
||||
|
||||
/* main driver initialization routine, called from mem.c */
|
||||
|
||||
static int __init gpio_init(void)
|
||||
{
|
||||
int res;
|
||||
#if defined (CONFIG_ETRAX_CSP0_LEDS)
|
||||
int i;
|
||||
#endif
|
||||
|
||||
res = register_chrdev(GPIO_MAJOR, gpio_name, &gpio_fops);
|
||||
if (res < 0) {
|
||||
printk(KERN_ERR "gpio: couldn't get a major number.\n");
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Clear all leds */
|
||||
#if defined (CONFIG_ETRAX_CSP0_LEDS) || defined (CONFIG_ETRAX_PA_LEDS) || defined (CONFIG_ETRAX_PB_LEDS)
|
||||
CRIS_LED_NETWORK_SET(0);
|
||||
CRIS_LED_ACTIVE_SET(0);
|
||||
CRIS_LED_DISK_READ(0);
|
||||
CRIS_LED_DISK_WRITE(0);
|
||||
|
||||
#if defined (CONFIG_ETRAX_CSP0_LEDS)
|
||||
for (i = 0; i < 32; i++)
|
||||
CRIS_LED_BIT_SET(i);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/* The I/O interface allocation watcher will be called when
|
||||
* registering it. */
|
||||
if (cris_io_interface_register_watcher(ioif_watcher)){
|
||||
printk(KERN_WARNING "gpio_init: Failed to install IO "
|
||||
"if allocator watcher\n");
|
||||
}
|
||||
|
||||
printk(KERN_INFO "ETRAX 100LX GPIO driver v2.5, (c) 2001-2008 "
|
||||
"Axis Communications AB\n");
|
||||
/* We call etrax_gpio_wake_up_check() from timer interrupt and
|
||||
* from default_idle() in kernel/process.c
|
||||
* The check in default_idle() reduces latency from ~15 ms to ~6 ms
|
||||
* in some tests.
|
||||
*/
|
||||
res = request_irq(TIMER0_IRQ_NBR, gpio_poll_timer_interrupt,
|
||||
IRQF_SHARED, "gpio poll", gpio_name);
|
||||
if (res) {
|
||||
printk(KERN_CRIT "err: timer0 irq for gpio\n");
|
||||
return res;
|
||||
}
|
||||
res = request_irq(PA_IRQ_NBR, gpio_interrupt,
|
||||
IRQF_SHARED, "gpio PA", gpio_name);
|
||||
if (res)
|
||||
printk(KERN_CRIT "err: PA irq for gpio\n");
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* this makes sure that gpio_init is called during kernel boot */
|
||||
module_init(gpio_init);
|
||||
|
||||
|
|
@ -1,699 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*!***************************************************************************
|
||||
*!
|
||||
*! FILE NAME : i2c.c
|
||||
*!
|
||||
*! DESCRIPTION: implements an interface for IIC/I2C, both directly from other
|
||||
*! kernel modules (i2c_writereg/readreg) and from userspace using
|
||||
*! ioctl()'s
|
||||
*!
|
||||
*! (C) Copyright 1999-2007 Axis Communications AB, LUND, SWEDEN
|
||||
*!
|
||||
*!***************************************************************************/
|
||||
|
||||
/****************** INCLUDE FILES SECTION ***********************************/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <asm/etraxi2c.h>
|
||||
|
||||
#include <arch/svinto.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/delay.h>
|
||||
#include <arch/io_interface_mux.h>
|
||||
|
||||
#include "i2c.h"
|
||||
|
||||
/****************** I2C DEFINITION SECTION *************************/
|
||||
|
||||
#define D(x)
|
||||
|
||||
#define I2C_MAJOR 123 /* LOCAL/EXPERIMENTAL */
|
||||
static const char i2c_name[] = "i2c";
|
||||
|
||||
#define CLOCK_LOW_TIME 8
|
||||
#define CLOCK_HIGH_TIME 8
|
||||
#define START_CONDITION_HOLD_TIME 8
|
||||
#define STOP_CONDITION_HOLD_TIME 8
|
||||
#define ENABLE_OUTPUT 0x01
|
||||
#define ENABLE_INPUT 0x00
|
||||
#define I2C_CLOCK_HIGH 1
|
||||
#define I2C_CLOCK_LOW 0
|
||||
#define I2C_DATA_HIGH 1
|
||||
#define I2C_DATA_LOW 0
|
||||
|
||||
#ifdef CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C
|
||||
/* Use PB and not PB_I2C */
|
||||
#ifndef CONFIG_ETRAX_I2C_DATA_PORT
|
||||
#define CONFIG_ETRAX_I2C_DATA_PORT 0
|
||||
#endif
|
||||
#ifndef CONFIG_ETRAX_I2C_CLK_PORT
|
||||
#define CONFIG_ETRAX_I2C_CLK_PORT 1
|
||||
#endif
|
||||
|
||||
#define SDABIT CONFIG_ETRAX_I2C_DATA_PORT
|
||||
#define SCLBIT CONFIG_ETRAX_I2C_CLK_PORT
|
||||
#define i2c_enable()
|
||||
#define i2c_disable()
|
||||
|
||||
/* enable or disable output-enable, to select output or input on the i2c bus */
|
||||
|
||||
#define i2c_dir_out() \
|
||||
REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, SDABIT, 1)
|
||||
#define i2c_dir_in() \
|
||||
REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, SDABIT, 0)
|
||||
|
||||
/* control the i2c clock and data signals */
|
||||
|
||||
#define i2c_clk(x) \
|
||||
REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, SCLBIT, x)
|
||||
#define i2c_data(x) \
|
||||
REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, SDABIT, x)
|
||||
|
||||
/* read a bit from the i2c interface */
|
||||
|
||||
#define i2c_getbit() (((*R_PORT_PB_READ & (1 << SDABIT))) >> SDABIT)
|
||||
|
||||
#else
|
||||
/* enable or disable the i2c interface */
|
||||
|
||||
#define i2c_enable() *R_PORT_PB_I2C = (port_pb_i2c_shadow |= IO_MASK(R_PORT_PB_I2C, i2c_en))
|
||||
#define i2c_disable() *R_PORT_PB_I2C = (port_pb_i2c_shadow &= ~IO_MASK(R_PORT_PB_I2C, i2c_en))
|
||||
|
||||
/* enable or disable output-enable, to select output or input on the i2c bus */
|
||||
|
||||
#define i2c_dir_out() \
|
||||
*R_PORT_PB_I2C = (port_pb_i2c_shadow &= ~IO_MASK(R_PORT_PB_I2C, i2c_oe_)); \
|
||||
REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, 0, 1);
|
||||
#define i2c_dir_in() \
|
||||
*R_PORT_PB_I2C = (port_pb_i2c_shadow |= IO_MASK(R_PORT_PB_I2C, i2c_oe_)); \
|
||||
REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, 0, 0);
|
||||
|
||||
/* control the i2c clock and data signals */
|
||||
|
||||
#define i2c_clk(x) \
|
||||
*R_PORT_PB_I2C = (port_pb_i2c_shadow = (port_pb_i2c_shadow & \
|
||||
~IO_MASK(R_PORT_PB_I2C, i2c_clk)) | IO_FIELD(R_PORT_PB_I2C, i2c_clk, (x))); \
|
||||
REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, 1, x);
|
||||
|
||||
#define i2c_data(x) \
|
||||
*R_PORT_PB_I2C = (port_pb_i2c_shadow = (port_pb_i2c_shadow & \
|
||||
~IO_MASK(R_PORT_PB_I2C, i2c_d)) | IO_FIELD(R_PORT_PB_I2C, i2c_d, (x))); \
|
||||
REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, 0, x);
|
||||
|
||||
/* read a bit from the i2c interface */
|
||||
|
||||
#define i2c_getbit() (*R_PORT_PB_READ & 0x1)
|
||||
#endif
|
||||
|
||||
/* use the kernels delay routine */
|
||||
|
||||
#define i2c_delay(usecs) udelay(usecs)
|
||||
|
||||
static DEFINE_SPINLOCK(i2c_lock); /* Protect directions etc */
|
||||
|
||||
/****************** FUNCTION DEFINITION SECTION *************************/
|
||||
|
||||
|
||||
/* generate i2c start condition */
|
||||
|
||||
void
|
||||
i2c_start(void)
|
||||
{
|
||||
/*
|
||||
* SCL=1 SDA=1
|
||||
*/
|
||||
i2c_dir_out();
|
||||
i2c_delay(CLOCK_HIGH_TIME/6);
|
||||
i2c_data(I2C_DATA_HIGH);
|
||||
i2c_clk(I2C_CLOCK_HIGH);
|
||||
i2c_delay(CLOCK_HIGH_TIME);
|
||||
/*
|
||||
* SCL=1 SDA=0
|
||||
*/
|
||||
i2c_data(I2C_DATA_LOW);
|
||||
i2c_delay(START_CONDITION_HOLD_TIME);
|
||||
/*
|
||||
* SCL=0 SDA=0
|
||||
*/
|
||||
i2c_clk(I2C_CLOCK_LOW);
|
||||
i2c_delay(CLOCK_LOW_TIME);
|
||||
}
|
||||
|
||||
/* generate i2c stop condition */
|
||||
|
||||
void
|
||||
i2c_stop(void)
|
||||
{
|
||||
i2c_dir_out();
|
||||
|
||||
/*
|
||||
* SCL=0 SDA=0
|
||||
*/
|
||||
i2c_clk(I2C_CLOCK_LOW);
|
||||
i2c_data(I2C_DATA_LOW);
|
||||
i2c_delay(CLOCK_LOW_TIME*2);
|
||||
/*
|
||||
* SCL=1 SDA=0
|
||||
*/
|
||||
i2c_clk(I2C_CLOCK_HIGH);
|
||||
i2c_delay(CLOCK_HIGH_TIME*2);
|
||||
/*
|
||||
* SCL=1 SDA=1
|
||||
*/
|
||||
i2c_data(I2C_DATA_HIGH);
|
||||
i2c_delay(STOP_CONDITION_HOLD_TIME);
|
||||
|
||||
i2c_dir_in();
|
||||
}
|
||||
|
||||
/* write a byte to the i2c interface */
|
||||
|
||||
void
|
||||
i2c_outbyte(unsigned char x)
|
||||
{
|
||||
int i;
|
||||
|
||||
i2c_dir_out();
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (x & 0x80) {
|
||||
i2c_data(I2C_DATA_HIGH);
|
||||
} else {
|
||||
i2c_data(I2C_DATA_LOW);
|
||||
}
|
||||
|
||||
i2c_delay(CLOCK_LOW_TIME/2);
|
||||
i2c_clk(I2C_CLOCK_HIGH);
|
||||
i2c_delay(CLOCK_HIGH_TIME);
|
||||
i2c_clk(I2C_CLOCK_LOW);
|
||||
i2c_delay(CLOCK_LOW_TIME/2);
|
||||
x <<= 1;
|
||||
}
|
||||
i2c_data(I2C_DATA_LOW);
|
||||
i2c_delay(CLOCK_LOW_TIME/2);
|
||||
|
||||
/*
|
||||
* enable input
|
||||
*/
|
||||
i2c_dir_in();
|
||||
}
|
||||
|
||||
/* read a byte from the i2c interface */
|
||||
|
||||
unsigned char
|
||||
i2c_inbyte(void)
|
||||
{
|
||||
unsigned char aBitByte = 0;
|
||||
int i;
|
||||
|
||||
/* Switch off I2C to get bit */
|
||||
i2c_disable();
|
||||
i2c_dir_in();
|
||||
i2c_delay(CLOCK_HIGH_TIME/2);
|
||||
|
||||
/* Get bit */
|
||||
aBitByte |= i2c_getbit();
|
||||
|
||||
/* Enable I2C */
|
||||
i2c_enable();
|
||||
i2c_delay(CLOCK_LOW_TIME/2);
|
||||
|
||||
for (i = 1; i < 8; i++) {
|
||||
aBitByte <<= 1;
|
||||
/* Clock pulse */
|
||||
i2c_clk(I2C_CLOCK_HIGH);
|
||||
i2c_delay(CLOCK_HIGH_TIME);
|
||||
i2c_clk(I2C_CLOCK_LOW);
|
||||
i2c_delay(CLOCK_LOW_TIME);
|
||||
|
||||
/* Switch off I2C to get bit */
|
||||
i2c_disable();
|
||||
i2c_dir_in();
|
||||
i2c_delay(CLOCK_HIGH_TIME/2);
|
||||
|
||||
/* Get bit */
|
||||
aBitByte |= i2c_getbit();
|
||||
|
||||
/* Enable I2C */
|
||||
i2c_enable();
|
||||
i2c_delay(CLOCK_LOW_TIME/2);
|
||||
}
|
||||
i2c_clk(I2C_CLOCK_HIGH);
|
||||
i2c_delay(CLOCK_HIGH_TIME);
|
||||
|
||||
/*
|
||||
* we leave the clock low, getbyte is usually followed
|
||||
* by sendack/nack, they assume the clock to be low
|
||||
*/
|
||||
i2c_clk(I2C_CLOCK_LOW);
|
||||
return aBitByte;
|
||||
}
|
||||
|
||||
/*#---------------------------------------------------------------------------
|
||||
*#
|
||||
*# FUNCTION NAME: i2c_getack
|
||||
*#
|
||||
*# DESCRIPTION : checks if ack was received from ic2
|
||||
*#
|
||||
*#--------------------------------------------------------------------------*/
|
||||
|
||||
int
|
||||
i2c_getack(void)
|
||||
{
|
||||
int ack = 1;
|
||||
/*
|
||||
* enable output
|
||||
*/
|
||||
i2c_dir_out();
|
||||
/*
|
||||
* Release data bus by setting
|
||||
* data high
|
||||
*/
|
||||
i2c_data(I2C_DATA_HIGH);
|
||||
/*
|
||||
* enable input
|
||||
*/
|
||||
i2c_dir_in();
|
||||
i2c_delay(CLOCK_HIGH_TIME/4);
|
||||
/*
|
||||
* generate ACK clock pulse
|
||||
*/
|
||||
i2c_clk(I2C_CLOCK_HIGH);
|
||||
/*
|
||||
* Use PORT PB instead of I2C
|
||||
* for input. (I2C not working)
|
||||
*/
|
||||
i2c_clk(1);
|
||||
i2c_data(1);
|
||||
/*
|
||||
* switch off I2C
|
||||
*/
|
||||
i2c_data(1);
|
||||
i2c_disable();
|
||||
i2c_dir_in();
|
||||
/*
|
||||
* now wait for ack
|
||||
*/
|
||||
i2c_delay(CLOCK_HIGH_TIME/2);
|
||||
/*
|
||||
* check for ack
|
||||
*/
|
||||
if(i2c_getbit())
|
||||
ack = 0;
|
||||
i2c_delay(CLOCK_HIGH_TIME/2);
|
||||
if(!ack){
|
||||
if(!i2c_getbit()) /* receiver pulld SDA low */
|
||||
ack = 1;
|
||||
i2c_delay(CLOCK_HIGH_TIME/2);
|
||||
}
|
||||
|
||||
/*
|
||||
* our clock is high now, make sure data is low
|
||||
* before we enable our output. If we keep data high
|
||||
* and enable output, we would generate a stop condition.
|
||||
*/
|
||||
i2c_data(I2C_DATA_LOW);
|
||||
|
||||
/*
|
||||
* end clock pulse
|
||||
*/
|
||||
i2c_enable();
|
||||
i2c_dir_out();
|
||||
i2c_clk(I2C_CLOCK_LOW);
|
||||
i2c_delay(CLOCK_HIGH_TIME/4);
|
||||
/*
|
||||
* enable output
|
||||
*/
|
||||
i2c_dir_out();
|
||||
/*
|
||||
* remove ACK clock pulse
|
||||
*/
|
||||
i2c_data(I2C_DATA_HIGH);
|
||||
i2c_delay(CLOCK_LOW_TIME/2);
|
||||
return ack;
|
||||
}
|
||||
|
||||
/*#---------------------------------------------------------------------------
|
||||
*#
|
||||
*# FUNCTION NAME: I2C::sendAck
|
||||
*#
|
||||
*# DESCRIPTION : Send ACK on received data
|
||||
*#
|
||||
*#--------------------------------------------------------------------------*/
|
||||
void
|
||||
i2c_sendack(void)
|
||||
{
|
||||
/*
|
||||
* enable output
|
||||
*/
|
||||
i2c_delay(CLOCK_LOW_TIME);
|
||||
i2c_dir_out();
|
||||
/*
|
||||
* set ack pulse high
|
||||
*/
|
||||
i2c_data(I2C_DATA_LOW);
|
||||
/*
|
||||
* generate clock pulse
|
||||
*/
|
||||
i2c_delay(CLOCK_HIGH_TIME/6);
|
||||
i2c_clk(I2C_CLOCK_HIGH);
|
||||
i2c_delay(CLOCK_HIGH_TIME);
|
||||
i2c_clk(I2C_CLOCK_LOW);
|
||||
i2c_delay(CLOCK_LOW_TIME/6);
|
||||
/*
|
||||
* reset data out
|
||||
*/
|
||||
i2c_data(I2C_DATA_HIGH);
|
||||
i2c_delay(CLOCK_LOW_TIME);
|
||||
|
||||
i2c_dir_in();
|
||||
}
|
||||
|
||||
/*#---------------------------------------------------------------------------
|
||||
*#
|
||||
*# FUNCTION NAME: i2c_sendnack
|
||||
*#
|
||||
*# DESCRIPTION : Sends NACK on received data
|
||||
*#
|
||||
*#--------------------------------------------------------------------------*/
|
||||
void
|
||||
i2c_sendnack(void)
|
||||
{
|
||||
/*
|
||||
* enable output
|
||||
*/
|
||||
i2c_delay(CLOCK_LOW_TIME);
|
||||
i2c_dir_out();
|
||||
/*
|
||||
* set data high
|
||||
*/
|
||||
i2c_data(I2C_DATA_HIGH);
|
||||
/*
|
||||
* generate clock pulse
|
||||
*/
|
||||
i2c_delay(CLOCK_HIGH_TIME/6);
|
||||
i2c_clk(I2C_CLOCK_HIGH);
|
||||
i2c_delay(CLOCK_HIGH_TIME);
|
||||
i2c_clk(I2C_CLOCK_LOW);
|
||||
i2c_delay(CLOCK_LOW_TIME);
|
||||
|
||||
i2c_dir_in();
|
||||
}
|
||||
|
||||
/*#---------------------------------------------------------------------------
|
||||
*#
|
||||
*# FUNCTION NAME: i2c_writereg
|
||||
*#
|
||||
*# DESCRIPTION : Writes a value to an I2C device
|
||||
*#
|
||||
*#--------------------------------------------------------------------------*/
|
||||
int
|
||||
i2c_writereg(unsigned char theSlave, unsigned char theReg,
|
||||
unsigned char theValue)
|
||||
{
|
||||
int error, cntr = 3;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock(&i2c_lock);
|
||||
|
||||
do {
|
||||
error = 0;
|
||||
/*
|
||||
* we don't like to be interrupted
|
||||
*/
|
||||
local_irq_save(flags);
|
||||
|
||||
i2c_start();
|
||||
/*
|
||||
* send slave address
|
||||
*/
|
||||
i2c_outbyte((theSlave & 0xfe));
|
||||
/*
|
||||
* wait for ack
|
||||
*/
|
||||
if(!i2c_getack())
|
||||
error = 1;
|
||||
/*
|
||||
* now select register
|
||||
*/
|
||||
i2c_dir_out();
|
||||
i2c_outbyte(theReg);
|
||||
/*
|
||||
* now it's time to wait for ack
|
||||
*/
|
||||
if(!i2c_getack())
|
||||
error |= 2;
|
||||
/*
|
||||
* send register register data
|
||||
*/
|
||||
i2c_outbyte(theValue);
|
||||
/*
|
||||
* now it's time to wait for ack
|
||||
*/
|
||||
if(!i2c_getack())
|
||||
error |= 4;
|
||||
/*
|
||||
* end byte stream
|
||||
*/
|
||||
i2c_stop();
|
||||
/*
|
||||
* enable interrupt again
|
||||
*/
|
||||
local_irq_restore(flags);
|
||||
|
||||
} while(error && cntr--);
|
||||
|
||||
i2c_delay(CLOCK_LOW_TIME);
|
||||
|
||||
spin_unlock(&i2c_lock);
|
||||
|
||||
return -error;
|
||||
}
|
||||
|
||||
/*#---------------------------------------------------------------------------
|
||||
*#
|
||||
*# FUNCTION NAME: i2c_readreg
|
||||
*#
|
||||
*# DESCRIPTION : Reads a value from the decoder registers.
|
||||
*#
|
||||
*#--------------------------------------------------------------------------*/
|
||||
unsigned char
|
||||
i2c_readreg(unsigned char theSlave, unsigned char theReg)
|
||||
{
|
||||
unsigned char b = 0;
|
||||
int error, cntr = 3;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock(&i2c_lock);
|
||||
|
||||
do {
|
||||
error = 0;
|
||||
/*
|
||||
* we don't like to be interrupted
|
||||
*/
|
||||
local_irq_save(flags);
|
||||
/*
|
||||
* generate start condition
|
||||
*/
|
||||
i2c_start();
|
||||
|
||||
/*
|
||||
* send slave address
|
||||
*/
|
||||
i2c_outbyte((theSlave & 0xfe));
|
||||
/*
|
||||
* wait for ack
|
||||
*/
|
||||
if(!i2c_getack())
|
||||
error = 1;
|
||||
/*
|
||||
* now select register
|
||||
*/
|
||||
i2c_dir_out();
|
||||
i2c_outbyte(theReg);
|
||||
/*
|
||||
* now it's time to wait for ack
|
||||
*/
|
||||
if(!i2c_getack())
|
||||
error = 1;
|
||||
/*
|
||||
* repeat start condition
|
||||
*/
|
||||
i2c_delay(CLOCK_LOW_TIME);
|
||||
i2c_start();
|
||||
/*
|
||||
* send slave address
|
||||
*/
|
||||
i2c_outbyte(theSlave | 0x01);
|
||||
/*
|
||||
* wait for ack
|
||||
*/
|
||||
if(!i2c_getack())
|
||||
error = 1;
|
||||
/*
|
||||
* fetch register
|
||||
*/
|
||||
b = i2c_inbyte();
|
||||
/*
|
||||
* last received byte needs to be nacked
|
||||
* instead of acked
|
||||
*/
|
||||
i2c_sendnack();
|
||||
/*
|
||||
* end sequence
|
||||
*/
|
||||
i2c_stop();
|
||||
/*
|
||||
* enable interrupt again
|
||||
*/
|
||||
local_irq_restore(flags);
|
||||
|
||||
} while(error && cntr--);
|
||||
|
||||
spin_unlock(&i2c_lock);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
static int
|
||||
i2c_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
i2c_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Main device API. ioctl's to write or read to/from i2c registers.
|
||||
*/
|
||||
|
||||
static long i2c_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
if(_IOC_TYPE(cmd) != ETRAXI2C_IOCTYPE) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (_IOC_NR(cmd)) {
|
||||
case I2C_WRITEREG:
|
||||
/* write to an i2c slave */
|
||||
D(printk(KERN_DEBUG "i2cw %d %d %d\n",
|
||||
I2C_ARGSLAVE(arg),
|
||||
I2C_ARGREG(arg),
|
||||
I2C_ARGVALUE(arg)));
|
||||
|
||||
return i2c_writereg(I2C_ARGSLAVE(arg),
|
||||
I2C_ARGREG(arg),
|
||||
I2C_ARGVALUE(arg));
|
||||
case I2C_READREG:
|
||||
{
|
||||
unsigned char val;
|
||||
/* read from an i2c slave */
|
||||
D(printk(KERN_DEBUG "i2cr %d %d ",
|
||||
I2C_ARGSLAVE(arg),
|
||||
I2C_ARGREG(arg)));
|
||||
val = i2c_readreg(I2C_ARGSLAVE(arg), I2C_ARGREG(arg));
|
||||
D(printk(KERN_DEBUG "= %d\n", val));
|
||||
return val;
|
||||
}
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations i2c_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.unlocked_ioctl = i2c_ioctl,
|
||||
.open = i2c_open,
|
||||
.release = i2c_release,
|
||||
.llseek = noop_llseek,
|
||||
};
|
||||
|
||||
int __init
|
||||
i2c_init(void)
|
||||
{
|
||||
static int res = 0;
|
||||
static int first = 1;
|
||||
|
||||
if (!first) {
|
||||
return res;
|
||||
}
|
||||
first = 0;
|
||||
|
||||
/* Setup and enable the Port B I2C interface */
|
||||
|
||||
#ifndef CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C
|
||||
if ((res = cris_request_io_interface(if_i2c, "I2C"))) {
|
||||
printk(KERN_CRIT "i2c_init: Failed to get IO interface\n");
|
||||
return res;
|
||||
}
|
||||
|
||||
*R_PORT_PB_I2C = port_pb_i2c_shadow |=
|
||||
IO_STATE(R_PORT_PB_I2C, i2c_en, on) |
|
||||
IO_FIELD(R_PORT_PB_I2C, i2c_d, 1) |
|
||||
IO_FIELD(R_PORT_PB_I2C, i2c_clk, 1) |
|
||||
IO_STATE(R_PORT_PB_I2C, i2c_oe_, enable);
|
||||
|
||||
port_pb_dir_shadow &= ~IO_MASK(R_PORT_PB_DIR, dir0);
|
||||
port_pb_dir_shadow &= ~IO_MASK(R_PORT_PB_DIR, dir1);
|
||||
|
||||
*R_PORT_PB_DIR = (port_pb_dir_shadow |=
|
||||
IO_STATE(R_PORT_PB_DIR, dir0, input) |
|
||||
IO_STATE(R_PORT_PB_DIR, dir1, output));
|
||||
#else
|
||||
if ((res = cris_io_interface_allocate_pins(if_i2c,
|
||||
'b',
|
||||
CONFIG_ETRAX_I2C_DATA_PORT,
|
||||
CONFIG_ETRAX_I2C_DATA_PORT))) {
|
||||
printk(KERN_WARNING "i2c_init: Failed to get IO pin for I2C data port\n");
|
||||
return res;
|
||||
} else if ((res = cris_io_interface_allocate_pins(if_i2c,
|
||||
'b',
|
||||
CONFIG_ETRAX_I2C_CLK_PORT,
|
||||
CONFIG_ETRAX_I2C_CLK_PORT))) {
|
||||
cris_io_interface_free_pins(if_i2c,
|
||||
'b',
|
||||
CONFIG_ETRAX_I2C_DATA_PORT,
|
||||
CONFIG_ETRAX_I2C_DATA_PORT);
|
||||
printk(KERN_WARNING "i2c_init: Failed to get IO pin for I2C clk port\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int __init
|
||||
i2c_register(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = i2c_init();
|
||||
if (res < 0)
|
||||
return res;
|
||||
res = register_chrdev(I2C_MAJOR, i2c_name, &i2c_fops);
|
||||
if(res < 0) {
|
||||
printk(KERN_ERR "i2c: couldn't get a major number.\n");
|
||||
return res;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "I2C driver v2.2, (c) 1999-2004 Axis Communications AB\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* this makes sure that i2c_register is called during boot */
|
||||
|
||||
module_init(i2c_register);
|
||||
|
||||
/****************** END OF FILE i2c.c ********************************/
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* i2c.h */
|
||||
int i2c_init(void);
|
||||
|
||||
/* High level I2C actions */
|
||||
int i2c_writereg(unsigned char theSlave, unsigned char theReg, unsigned char theValue);
|
||||
unsigned char i2c_readreg(unsigned char theSlave, unsigned char theReg);
|
||||
|
||||
/* Low level I2C */
|
||||
void i2c_start(void);
|
||||
void i2c_stop(void);
|
||||
void i2c_outbyte(unsigned char x);
|
||||
unsigned char i2c_inbyte(void);
|
||||
int i2c_getack(void);
|
||||
void i2c_sendack(void);
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,18 +0,0 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Makefile for the linux kernel.
|
||||
#
|
||||
|
||||
extra-y := head.o
|
||||
|
||||
|
||||
obj-y := entry.o traps.o shadows.o debugport.o irq.o \
|
||||
process.o setup.o signal.o traps.o time.o ptrace.o \
|
||||
dma.o io_interface_mux.o
|
||||
|
||||
obj-$(CONFIG_ETRAX_KGDB) += kgdb.o
|
||||
obj-$(CONFIG_ETRAX_FAST_TIMER) += fasttimer.o
|
||||
obj-$(CONFIG_MODULES) += crisksyms.o
|
||||
|
||||
clean:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue