aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/DocBook/Makefile2
-rw-r--r--Documentation/DocBook/kernel-api.tmpl1
-rw-r--r--Documentation/acpi-hotkey.txt2
-rw-r--r--Documentation/fujitsu/frv/kernel-ABI.txt192
-rw-r--r--Documentation/kernel-parameters.txt34
-rw-r--r--Documentation/networking/packet_mmap.txt2
-rw-r--r--Documentation/networking/tuntap.txt2
-rw-r--r--Documentation/sound/alsa/ALSA-Configuration.txt69
-rw-r--r--arch/arm/configs/at91rm9200dk_defconfig2
-rw-r--r--arch/arm/configs/at91rm9200ek_defconfig2
-rw-r--r--arch/arm/kernel/armksyms.c13
-rw-r--r--arch/arm/kernel/setup.c3
-rw-r--r--arch/arm/mach-at91rm9200/Makefile9
-rw-r--r--arch/arm/mach-at91rm9200/board-csb337.c3
-rw-r--r--arch/arm/mach-at91rm9200/board-csb637.c3
-rw-r--r--arch/arm/mach-at91rm9200/board-dk.c10
-rw-r--r--arch/arm/mach-at91rm9200/board-ek.c10
-rw-r--r--arch/arm/mach-at91rm9200/devices.c154
-rw-r--r--arch/arm/mach-at91rm9200/leds.c100
-rw-r--r--arch/arm/mach-ep93xx/core.c10
-rw-r--r--arch/arm/mach-ep93xx/ts72xx.c39
-rw-r--r--arch/arm/mach-imx/dma.c511
-rw-r--r--arch/arm/mach-imx/generic.c13
-rw-r--r--arch/arm/mach-imx/mx1ads.c18
-rw-r--r--arch/arm/mach-ixp23xx/espresso.c9
-rw-r--r--arch/arm/mach-ixp23xx/pci.c18
-rw-r--r--arch/arm/mach-omap1/Kconfig20
-rw-r--r--arch/arm/mach-omap1/Makefile11
-rw-r--r--arch/arm/mach-omap1/board-ams-delta.c116
-rw-r--r--arch/arm/mach-omap1/board-generic.c2
-rw-r--r--arch/arm/mach-omap1/board-h2.c200
-rw-r--r--arch/arm/mach-omap1/board-h3.c277
-rw-r--r--arch/arm/mach-omap1/board-innovator.c56
-rw-r--r--arch/arm/mach-omap1/board-netstar.c160
-rw-r--r--arch/arm/mach-omap1/board-nokia770.c268
-rw-r--r--arch/arm/mach-omap1/board-osk.c95
-rw-r--r--arch/arm/mach-omap1/board-palmte.c12
-rw-r--r--arch/arm/mach-omap1/board-perseus2.c123
-rw-r--r--arch/arm/mach-omap1/board-voiceblue.c8
-rw-r--r--arch/arm/mach-omap1/clock.c9
-rw-r--r--arch/arm/mach-omap1/clock.h91
-rw-r--r--arch/arm/mach-omap1/devices.c40
-rw-r--r--arch/arm/mach-omap1/io.c4
-rw-r--r--arch/arm/mach-omap1/irq.c18
-rw-r--r--arch/arm/mach-omap1/mux.c30
-rw-r--r--arch/arm/mach-omap1/pm.c770
-rw-r--r--arch/arm/mach-omap1/serial.c6
-rw-r--r--arch/arm/mach-omap1/sleep.S (renamed from arch/arm/plat-omap/sleep.S)111
-rw-r--r--arch/arm/mach-omap1/time.c197
-rw-r--r--arch/arm/mach-omap2/Kconfig3
-rw-r--r--arch/arm/mach-omap2/Makefile6
-rw-r--r--arch/arm/mach-omap2/board-apollon.c285
-rw-r--r--arch/arm/mach-omap2/board-h4.c174
-rw-r--r--arch/arm/mach-omap2/clock.c79
-rw-r--r--arch/arm/mach-omap2/clock.h37
-rw-r--r--arch/arm/mach-omap2/devices.c42
-rw-r--r--arch/arm/mach-omap2/io.c21
-rw-r--r--arch/arm/mach-omap2/memory.c102
-rw-r--r--arch/arm/mach-omap2/memory.h34
-rw-r--r--arch/arm/mach-omap2/mux.c45
-rw-r--r--arch/arm/mach-omap2/pm.c149
-rw-r--r--arch/arm/mach-omap2/prcm-regs.h (renamed from arch/arm/mach-omap2/prcm.h)188
-rw-r--r--arch/arm/mach-omap2/prcm.c40
-rw-r--r--arch/arm/mach-omap2/sleep.S144
-rw-r--r--arch/arm/mach-omap2/sram-fn.S4
-rw-r--r--arch/arm/mach-pxa/poodle.c4
-rw-r--r--arch/arm/mach-s3c2410/Kconfig7
-rw-r--r--arch/arm/mach-s3c2410/Makefile2
-rw-r--r--arch/arm/mach-s3c2410/clock.c2
-rw-r--r--arch/arm/mach-s3c2410/common-smdk.c134
-rw-r--r--arch/arm/mach-s3c2410/common-smdk.h15
-rw-r--r--arch/arm/mach-s3c2410/mach-anubis.c4
-rw-r--r--arch/arm/mach-s3c2410/mach-rx3715.c35
-rw-r--r--arch/arm/mach-s3c2410/mach-smdk2410.c13
-rw-r--r--arch/arm/mach-s3c2410/mach-smdk2440.c17
-rw-r--r--arch/arm/mach-sa1100/collie.c72
-rw-r--r--arch/arm/mm/consistent.c17
-rw-r--r--arch/arm/mm/mm-armv.c11
-rw-r--r--arch/arm/mm/proc-xsc3.S2
-rw-r--r--arch/arm/plat-omap/Kconfig4
-rw-r--r--arch/arm/plat-omap/Makefile6
-rw-r--r--arch/arm/plat-omap/clock.c67
-rw-r--r--arch/arm/plat-omap/devices.c143
-rw-r--r--arch/arm/plat-omap/dma.c6
-rw-r--r--arch/arm/plat-omap/dmtimer.c26
-rw-r--r--arch/arm/plat-omap/fb.c80
-rw-r--r--arch/arm/plat-omap/gpio.c86
-rw-r--r--arch/arm/plat-omap/mcbsp.c345
-rw-r--r--arch/arm/plat-omap/ocpi.c3
-rw-r--r--arch/arm/plat-omap/pm.c1
-rw-r--r--arch/arm/plat-omap/sram.c143
-rw-r--r--arch/arm/plat-omap/timer32k.c325
-rw-r--r--arch/i386/kernel/crash.c2
-rw-r--r--block/ll_rw_blk.c2
-rw-r--r--drivers/char/watchdog/Kconfig7
-rw-r--r--drivers/char/watchdog/Makefile1
-rw-r--r--drivers/char/watchdog/at91_wdt.c228
-rw-r--r--drivers/char/watchdog/pcwd.c137
-rw-r--r--drivers/char/watchdog/pcwd_usb.c3
-rw-r--r--drivers/hwmon/hdaps.c37
-rw-r--r--drivers/ieee1394/sbp2.c32
-rw-r--r--drivers/md/dm-target.c3
-rw-r--r--drivers/md/raid1.c6
-rw-r--r--drivers/md/raid10.c6
-rw-r--r--drivers/md/raid5.c34
-rw-r--r--drivers/md/raid6main.c29
-rw-r--r--drivers/mmc/Kconfig18
-rw-r--r--drivers/mmc/Makefile2
-rw-r--r--drivers/mmc/at91_mci.c988
-rw-r--r--drivers/mmc/imxmmc.c1096
-rw-r--r--drivers/mmc/imxmmc.h67
-rw-r--r--drivers/mtd/chips/Kconfig21
-rw-r--r--drivers/net/8139cp.c12
-rw-r--r--drivers/net/arcnet/arcnet.c3
-rw-r--r--drivers/net/b44.c3
-rw-r--r--drivers/net/chelsio/sge.c3
-rw-r--r--drivers/net/e1000/e1000_main.c3
-rw-r--r--drivers/net/eql.c3
-rw-r--r--drivers/net/irda/sa1100_ir.c3
-rw-r--r--drivers/net/ne2k-pci.c4
-rw-r--r--drivers/net/ns83820.c3
-rw-r--r--drivers/net/starfire.c3
-rw-r--r--drivers/net/tg3.c15
-rw-r--r--drivers/net/tokenring/abyss.c3
-rw-r--r--drivers/net/tokenring/madgemc.c3
-rw-r--r--drivers/net/wireless/ipw2200.c9
-rw-r--r--drivers/net/yellowfin.c3
-rw-r--r--drivers/s390/block/dasd_erp.c8
-rw-r--r--drivers/s390/char/sclp_rw.c2
-rw-r--r--drivers/s390/char/tape_block.c13
-rw-r--r--drivers/s390/net/lcs.c13
-rw-r--r--drivers/scsi/aic7xxx/Kconfig.aic7xxx2
-rw-r--r--drivers/serial/jsm/jsm.h2
-rw-r--r--drivers/serial/jsm/jsm_driver.c2
-rw-r--r--drivers/serial/jsm/jsm_neo.c2
-rw-r--r--fs/direct-io.c3
-rw-r--r--fs/dquot.c6
-rw-r--r--fs/exec.c2
-rw-r--r--fs/fcntl.c3
-rw-r--r--fs/freevxfs/vxfs_olt.c9
-rw-r--r--fs/hfsplus/bnode.c6
-rw-r--r--fs/hfsplus/btree.c3
-rw-r--r--fs/inode.c15
-rw-r--r--fs/jffs2/background.c3
-rw-r--r--fs/smbfs/file.c6
-rw-r--r--fs/sysfs/dir.c2
-rw-r--r--fs/sysfs/file.c2
-rw-r--r--fs/sysfs/inode.c3
-rw-r--r--fs/sysv/dir.c6
-rw-r--r--fs/udf/inode.c6
-rw-r--r--fs/xfs/linux-2.6/xfs_file.c113
-rw-r--r--fs/xfs/linux-2.6/xfs_linux.h1
-rw-r--r--fs/xfs/linux-2.6/xfs_lrw.c120
-rw-r--r--fs/xfs/linux-2.6/xfs_lrw.h11
-rw-r--r--fs/xfs/linux-2.6/xfs_super.c11
-rw-r--r--fs/xfs/linux-2.6/xfs_vnode.h12
-rw-r--r--fs/xfs/quota/xfs_qm.c17
-rw-r--r--fs/xfs/quota/xfs_trans_dquot.c68
-rw-r--r--fs/xfs/xfs_bmap.c11
-rw-r--r--fs/xfs/xfs_bmap.h9
-rw-r--r--fs/xfs/xfs_clnt.h1
-rw-r--r--fs/xfs/xfs_error.h3
-rw-r--r--fs/xfs/xfs_mount.c71
-rw-r--r--fs/xfs/xfs_mount.h5
-rw-r--r--fs/xfs/xfs_quota.h5
-rw-r--r--fs/xfs/xfs_vfsops.c10
-rw-r--r--fs/xfs/xfs_vnodeops.c4
-rw-r--r--include/asm-arm/arch-at91rm9200/at91rm9200_mci.h104
-rw-r--r--include/asm-arm/arch-at91rm9200/board.h24
-rw-r--r--include/asm-arm/arch-ep93xx/ts72xx.h11
-rw-r--r--include/asm-arm/arch-imx/dma.h17
-rw-r--r--include/asm-arm/arch-imx/imx-dma.h90
-rw-r--r--include/asm-arm/arch-imx/mmc.h12
-rw-r--r--include/asm-arm/arch-ixp23xx/memory.h17
-rw-r--r--include/asm-arm/arch-ixp23xx/platform.h1
-rw-r--r--include/asm-arm/arch-omap/aic23.h4
-rw-r--r--include/asm-arm/arch-omap/board-ams-delta.h65
-rw-r--r--include/asm-arm/arch-omap/board-apollon.h45
-rw-r--r--include/asm-arm/arch-omap/board-h2.h4
-rw-r--r--include/asm-arm/arch-omap/board-h3.h4
-rw-r--r--include/asm-arm/arch-omap/board-h4.h8
-rw-r--r--include/asm-arm/arch-omap/board-netstar.h19
-rw-r--r--include/asm-arm/arch-omap/board-nokia.h54
-rw-r--r--include/asm-arm/arch-omap/board-perseus2.h4
-rw-r--r--include/asm-arm/arch-omap/board.h30
-rw-r--r--include/asm-arm/arch-omap/clock.h13
-rw-r--r--include/asm-arm/arch-omap/dma.h1
-rw-r--r--include/asm-arm/arch-omap/dmtimer.h1
-rw-r--r--include/asm-arm/arch-omap/dsp.h6
-rw-r--r--include/asm-arm/arch-omap/dsp_common.h13
-rw-r--r--include/asm-arm/arch-omap/gpioexpander.h24
-rw-r--r--include/asm-arm/arch-omap/hardware.h8
-rw-r--r--include/asm-arm/arch-omap/irda.h36
-rw-r--r--include/asm-arm/arch-omap/irqs.h5
-rw-r--r--include/asm-arm/arch-omap/keypad.h36
-rw-r--r--include/asm-arm/arch-omap/lcd_lph8923.h14
-rw-r--r--include/asm-arm/arch-omap/mcbsp.h65
-rw-r--r--include/asm-arm/arch-omap/mcspi.h16
-rw-r--r--include/asm-arm/arch-omap/menelaus.h2
-rw-r--r--include/asm-arm/arch-omap/mux.h54
-rw-r--r--include/asm-arm/arch-omap/omap-alsa.h124
-rw-r--r--include/asm-arm/arch-omap/omapfb.h98
-rw-r--r--include/asm-arm/arch-omap/param.h8
-rw-r--r--include/asm-arm/arch-omap/pm.h81
-rw-r--r--include/asm-arm/arch-omap/prcm.h404
-rw-r--r--include/asm-arm/arch-omap/sram.h2
-rw-r--r--include/asm-arm/arch-omap/system.h17
-rw-r--r--include/asm-arm/arch-s3c2410/entry-macro.S167
-rw-r--r--include/asm-arm/dma-mapping.h22
-rw-r--r--include/asm-arm/memory.h8
-rw-r--r--include/asm-arm/pgtable-hwdef.h1
-rw-r--r--include/asm-arm/pgtable.h1
-rw-r--r--include/linux/fs.h2
-rw-r--r--include/linux/hrtimer.h2
-rw-r--r--include/sound/core.h2
-rw-r--r--include/sound/pcm.h15
-rw-r--r--include/sound/pcm_oss.h3
-rw-r--r--ipc/shm.c15
-rw-r--r--ipc/util.c6
-rw-r--r--kernel/power/Kconfig2
-rw-r--r--kernel/printk.c6
-rw-r--r--kernel/ptrace.c3
-rw-r--r--kernel/signal.c6
-rw-r--r--kernel/time.c8
-rw-r--r--kernel/timer.c3
-rw-r--r--mm/highmem.c15
-rw-r--r--mm/mmap.c9
-rw-r--r--mm/page-writeback.c2
-rw-r--r--mm/slab.c18
-rw-r--r--mm/swap_state.c3
-rw-r--r--mm/vmalloc.c3
-rw-r--r--sound/core/Kconfig5
-rw-r--r--sound/core/control.c6
-rw-r--r--sound/core/control_compat.c6
-rw-r--r--sound/core/init.c9
-rw-r--r--sound/core/oss/pcm_oss.c288
-rw-r--r--sound/core/pcm.c14
-rw-r--r--sound/core/pcm_lib.c49
-rw-r--r--sound/core/pcm_native.c157
-rw-r--r--sound/isa/Kconfig23
-rw-r--r--sound/isa/Makefile2
-rw-r--r--sound/isa/adlib.c161
-rw-r--r--sound/isa/cmi8330.c4
-rw-r--r--sound/isa/opti9xx/Makefile2
-rw-r--r--sound/isa/opti9xx/miro.c1455
-rw-r--r--sound/isa/opti9xx/miro.h73
-rw-r--r--sound/pci/Kconfig30
-rw-r--r--sound/pci/Makefile3
-rw-r--r--sound/pci/als300.c866
-rw-r--r--sound/pci/cs4281.c28
-rw-r--r--sound/pci/hda/hda_codec.c2
-rw-r--r--sound/pci/hda/hda_intel.c2
-rw-r--r--sound/pci/hda/patch_analog.c9
-rw-r--r--sound/pci/hda/patch_realtek.c298
-rw-r--r--sound/pci/hda/patch_sigmatel.c53
-rw-r--r--sound/pci/ice1712/aureon.c163
-rw-r--r--sound/pci/ice1712/ice1712.c2
-rw-r--r--sound/pci/ice1712/ice1712.h1
-rw-r--r--sound/pci/maestro3.c57
-rw-r--r--sound/pci/pcxhr/pcxhr_core.c9
-rw-r--r--sound/pci/riptide/Makefile3
-rw-r--r--sound/pci/riptide/riptide.c2223
-rw-r--r--sound/pci/via82xx.c1
-rw-r--r--sound/usb/usbmixer.c37
264 files changed, 15463 insertions, 2602 deletions
diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
index 7d87dd73cbe..5a2882d275b 100644
--- a/Documentation/DocBook/Makefile
+++ b/Documentation/DocBook/Makefile
@@ -2,7 +2,7 @@
# This makefile is used to generate the kernel documentation,
# primarily based on in-line comments in various source files.
# See Documentation/kernel-doc-nano-HOWTO.txt for instruction in how
-# to ducument the SRC - and how to read it.
+# to document the SRC - and how to read it.
# To add a new book the only step required is to add the book to the
# list of DOCBOOKS.
diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl
index 8c9c6704e85..ca02e04a906 100644
--- a/Documentation/DocBook/kernel-api.tmpl
+++ b/Documentation/DocBook/kernel-api.tmpl
@@ -322,7 +322,6 @@ X!Earch/i386/kernel/mca.c
<chapter id="sysfs">
<title>The Filesystem for Exporting Kernel Objects</title>
!Efs/sysfs/file.c
-!Efs/sysfs/dir.c
!Efs/sysfs/symlink.c
!Efs/sysfs/bin.c
</chapter>
diff --git a/Documentation/acpi-hotkey.txt b/Documentation/acpi-hotkey.txt
index 744f1aec655..38040fa3764 100644
--- a/Documentation/acpi-hotkey.txt
+++ b/Documentation/acpi-hotkey.txt
@@ -30,7 +30,7 @@ specific hotkey(event))
echo "event_num:event_type:event_argument" >
/proc/acpi/hotkey/action.
The result of the execution of this aml method is
-attached to /proc/acpi/hotkey/poll_method, which is dnyamically
+attached to /proc/acpi/hotkey/poll_method, which is dynamically
created. Please use command "cat /proc/acpi/hotkey/polling_method"
to retrieve it.
diff --git a/Documentation/fujitsu/frv/kernel-ABI.txt b/Documentation/fujitsu/frv/kernel-ABI.txt
index 0ed9b0a779b..8b0a5fc8bfd 100644
--- a/Documentation/fujitsu/frv/kernel-ABI.txt
+++ b/Documentation/fujitsu/frv/kernel-ABI.txt
@@ -1,17 +1,19 @@
- =================================
- INTERNAL KERNEL ABI FOR FR-V ARCH
- =================================
-
-The internal FRV kernel ABI is not quite the same as the userspace ABI. A number of the registers
-are used for special purposed, and the ABI is not consistent between modules vs core, and MMU vs
-no-MMU.
-
-This partly stems from the fact that FRV CPUs do not have a separate supervisor stack pointer, and
-most of them do not have any scratch registers, thus requiring at least one general purpose
-register to be clobbered in such an event. Also, within the kernel core, it is possible to simply
-jump or call directly between functions using a relative offset. This cannot be extended to modules
-for the displacement is likely to be too far. Thus in modules the address of a function to call
-must be calculated in a register and then used, requiring two extra instructions.
+ =================================
+ INTERNAL KERNEL ABI FOR FR-V ARCH
+ =================================
+
+The internal FRV kernel ABI is not quite the same as the userspace ABI. A
+number of the registers are used for special purposed, and the ABI is not
+consistent between modules vs core, and MMU vs no-MMU.
+
+This partly stems from the fact that FRV CPUs do not have a separate
+supervisor stack pointer, and most of them do not have any scratch
+registers, thus requiring at least one general purpose register to be
+clobbered in such an event. Also, within the kernel core, it is possible to
+simply jump or call directly between functions using a relative offset.
+This cannot be extended to modules for the displacement is likely to be too
+far. Thus in modules the address of a function to call must be calculated
+in a register and then used, requiring two extra instructions.
This document has the following sections:
@@ -39,7 +41,8 @@ When a system call is made, the following registers are effective:
CPU OPERATING MODES
===================
-The FR-V CPU has three basic operating modes. In order of increasing capability:
+The FR-V CPU has three basic operating modes. In order of increasing
+capability:
(1) User mode.
@@ -47,42 +50,46 @@ The FR-V CPU has three basic operating modes. In order of increasing capability:
(2) Kernel mode.
- Normal kernel mode. There are many additional control registers available that may be
- accessed in this mode, in addition to all the stuff available to user mode. This has two
- submodes:
+ Normal kernel mode. There are many additional control registers
+ available that may be accessed in this mode, in addition to all the
+ stuff available to user mode. This has two submodes:
(a) Exceptions enabled (PSR.T == 1).
- Exceptions will invoke the appropriate normal kernel mode handler. On entry to the
- handler, the PSR.T bit will be cleared.
+ Exceptions will invoke the appropriate normal kernel mode
+ handler. On entry to the handler, the PSR.T bit will be cleared.
(b) Exceptions disabled (PSR.T == 0).
- No exceptions or interrupts may happen. Any mandatory exceptions will cause the CPU to
- halt unless the CPU is told to jump into debug mode instead.
+ No exceptions or interrupts may happen. Any mandatory exceptions
+ will cause the CPU to halt unless the CPU is told to jump into
+ debug mode instead.
(3) Debug mode.
- No exceptions may happen in this mode. Memory protection and management exceptions will be
- flagged for later consideration, but the exception handler won't be invoked. Debugging traps
- such as hardware breakpoints and watchpoints will be ignored. This mode is entered only by
- debugging events obtained from the other two modes.
+ No exceptions may happen in this mode. Memory protection and
+ management exceptions will be flagged for later consideration, but
+ the exception handler won't be invoked. Debugging traps such as
+ hardware breakpoints and watchpoints will be ignored. This mode is
+ entered only by debugging events obtained from the other two modes.
- All kernel mode registers may be accessed, plus a few extra debugging specific registers.
+ All kernel mode registers may be accessed, plus a few extra debugging
+ specific registers.
=================================
INTERNAL KERNEL-MODE REGISTER ABI
=================================
-There are a number of permanent register assignments that are set up by entry.S in the exception
-prologue. Note that there is a complete set of exception prologues for each of user->kernel
-transition and kernel->kernel transition. There are also user->debug and kernel->debug mode
-transition prologues.
+There are a number of permanent register assignments that are set up by
+entry.S in the exception prologue. Note that there is a complete set of
+exception prologues for each of user->kernel transition and kernel->kernel
+transition. There are also user->debug and kernel->debug mode transition
+prologues.
REGISTER FLAVOUR USE
- =============== ======= ====================================================
+ =============== ======= ==============================================
GR1 Supervisor stack pointer
GR15 Current thread info pointer
GR16 GP-Rel base register for small data
@@ -92,10 +99,12 @@ transition prologues.
GR31 NOMMU Destroyed by debug mode entry
GR31 MMU Destroyed by TLB miss kernel mode entry
CCR.ICC2 Virtual interrupt disablement tracking
- CCCR.CC3 Cleared by exception prologue (atomic op emulation)
+ CCCR.CC3 Cleared by exception prologue
+ (atomic op emulation)
SCR0 MMU See mmu-layout.txt.
SCR1 MMU See mmu-layout.txt.
- SCR2 MMU Save for EAR0 (destroyed by icache insns in debug mode)
+ SCR2 MMU Save for EAR0 (destroyed by icache insns
+ in debug mode)
SCR3 MMU Save for GR31 during debug exceptions
DAMR/IAMR NOMMU Fixed memory protection layout.
DAMR/IAMR MMU See mmu-layout.txt.
@@ -104,18 +113,21 @@ transition prologues.
Certain registers are also used or modified across function calls:
REGISTER CALL RETURN
- =============== =============================== ===============================
+ =============== =============================== ======================
GR0 Fixed Zero -
GR2 Function call frame pointer
GR3 Special Preserved
GR3-GR7 - Clobbered
- GR8 Function call arg #1 Return value (or clobbered)
- GR9 Function call arg #2 Return value MSW (or clobbered)
+ GR8 Function call arg #1 Return value
+ (or clobbered)
+ GR9 Function call arg #2 Return value MSW
+ (or clobbered)
GR10-GR13 Function call arg #3-#6 Clobbered
GR14 - Clobbered
GR15-GR16 Special Preserved
GR17-GR27 - Preserved
- GR28-GR31 Special Only accessed explicitly
+ GR28-GR31 Special Only accessed
+ explicitly
LR Return address after CALL Clobbered
CCR/CCCR - Mostly Clobbered
@@ -124,46 +136,53 @@ Certain registers are also used or modified across function calls:
INTERNAL DEBUG-MODE REGISTER ABI
================================
-This is the same as the kernel-mode register ABI for functions calls. The difference is that in
-debug-mode there's a different stack and a different exception frame. Almost all the global
-registers from kernel-mode (including the stack pointer) may be changed.
+This is the same as the kernel-mode register ABI for functions calls. The
+difference is that in debug-mode there's a different stack and a different
+exception frame. Almost all the global registers from kernel-mode
+(including the stack pointer) may be changed.
REGISTER FLAVOUR USE
- =============== ======= ====================================================
+ =============== ======= ==============================================
GR1 Debug stack pointer
GR16 GP-Rel base register for small data
- GR31 Current debug exception frame pointer (__debug_frame)
+ GR31 Current debug exception frame pointer
+ (__debug_frame)
SCR3 MMU Saved value of GR31
-Note that debug mode is able to interfere with the kernel's emulated atomic ops, so it must be
-exceedingly careful not to do any that would interact with the main kernel in this regard. Hence
-the debug mode code (gdbstub) is almost completely self-contained. The only external code used is
-the sprintf family of functions.
+Note that debug mode is able to interfere with the kernel's emulated atomic
+ops, so it must be exceedingly careful not to do any that would interact
+with the main kernel in this regard. Hence the debug mode code (gdbstub) is
+almost completely self-contained. The only external code used is the
+sprintf family of functions.
-Futhermore, break.S is so complicated because single-step mode does not switch off on entry to an
-exception. That means unless manually disabled, single-stepping will blithely go on stepping into
-things like interrupts. See gdbstub.txt for more information.
+Futhermore, break.S is so complicated because single-step mode does not
+switch off on entry to an exception. That means unless manually disabled,
+single-stepping will blithely go on stepping into things like interrupts.
+See gdbstub.txt for more information.
==========================
VIRTUAL INTERRUPT HANDLING
==========================
-Because accesses to the PSR is so slow, and to disable interrupts we have to access it twice (once
-to read and once to write), we don't actually disable interrupts at all if we don't have to. What
-we do instead is use the ICC2 condition code flags to note virtual disablement, such that if we
-then do take an interrupt, we note the flag, really disable interrupts, set another flag and resume
-execution at the point the interrupt happened. Setting condition flags as a side effect of an
-arithmetic or logical instruction is really fast. This use of the ICC2 only occurs within the
+Because accesses to the PSR is so slow, and to disable interrupts we have
+to access it twice (once to read and once to write), we don't actually
+disable interrupts at all if we don't have to. What we do instead is use
+the ICC2 condition code flags to note virtual disablement, such that if we
+then do take an interrupt, we note the flag, really disable interrupts, set
+another flag and resume execution at the point the interrupt happened.
+Setting condition flags as a side effect of an arithmetic or logical
+instruction is really fast. This use of the ICC2 only occurs within the
kernel - it does not affect userspace.
The flags we use are:
(*) CCR.ICC2.Z [Zero flag]
- Set to virtually disable interrupts, clear when interrupts are virtually enabled. Can be
- modified by logical instructions without affecting the Carry flag.
+ Set to virtually disable interrupts, clear when interrupts are
+ virtually enabled. Can be modified by logical instructions without
+ affecting the Carry flag.
(*) CCR.ICC2.C [Carry flag]
@@ -176,8 +195,9 @@ What happens is this:
ICC2.Z is 0, ICC2.C is 1.
- (2) An interrupt occurs. The exception prologue examines ICC2.Z and determines that nothing needs
- doing. This is done simply with an unlikely BEQ instruction.
+ (2) An interrupt occurs. The exception prologue examines ICC2.Z and
+ determines that nothing needs doing. This is done simply with an
+ unlikely BEQ instruction.
(3) The interrupts are disabled (local_irq_disable)
@@ -187,48 +207,56 @@ What happens is this:
ICC2.Z would be set to 0.
- A TIHI #2 instruction (trap #2 if condition HI - Z==0 && C==0) would be used to trap if
- interrupts were now virtually enabled, but physically disabled - which they're not, so the
- trap isn't taken. The kernel would then be back to state (1).
+ A TIHI #2 instruction (trap #2 if condition HI - Z==0 && C==0) would
+ be used to trap if interrupts were now virtually enabled, but
+ physically disabled - which they're not, so the trap isn't taken. The
+ kernel would then be back to state (1).
- (5) An interrupt occurs. The exception prologue examines ICC2.Z and determines that the interrupt
- shouldn't actually have happened. It jumps aside, and there disabled interrupts by setting
- PSR.PIL to 14 and then it clears ICC2.C.
+ (5) An interrupt occurs. The exception prologue examines ICC2.Z and
+ determines that the interrupt shouldn't actually have happened. It
+ jumps aside, and there disabled interrupts by setting PSR.PIL to 14
+ and then it clears ICC2.C.
(6) If interrupts were then saved and disabled again (local_irq_save):
- ICC2.Z would be shifted into the save variable and masked off (giving a 1).
+ ICC2.Z would be shifted into the save variable and masked off
+ (giving a 1).
- ICC2.Z would then be set to 1 (thus unchanged), and ICC2.C would be unaffected (ie: 0).
+ ICC2.Z would then be set to 1 (thus unchanged), and ICC2.C would be
+ unaffected (ie: 0).
(7) If interrupts were then restored from state (6) (local_irq_restore):
- ICC2.Z would be set to indicate the result of XOR'ing the saved value (ie: 1) with 1, which
- gives a result of 0 - thus leaving ICC2.Z set.
+ ICC2.Z would be set to indicate the result of XOR'ing the saved
+ value (ie: 1) with 1, which gives a result of 0 - thus leaving
+ ICC2.Z set.
ICC2.C would remain unaffected (ie: 0).
- A TIHI #2 instruction would be used to again assay the current state, but this would do
- nothing as Z==1.
+ A TIHI #2 instruction would be used to again assay the current state,
+ but this would do nothing as Z==1.
(8) If interrupts were then enabled (local_irq_enable):
- ICC2.Z would be cleared. ICC2.C would be left unaffected. Both flags would now be 0.
+ ICC2.Z would be cleared. ICC2.C would be left unaffected. Both
+ flags would now be 0.
- A TIHI #2 instruction again issued to assay the current state would then trap as both Z==0
- [interrupts virtually enabled] and C==0 [interrupts really disabled] would then be true.
+ A TIHI #2 instruction again issued to assay the current state would
+ then trap as both Z==0 [interrupts virtually enabled] and C==0
+ [interrupts really disabled] would then be true.
- (9) The trap #2 handler would simply enable hardware interrupts (set PSR.PIL to 0), set ICC2.C to
- 1 and return.
+ (9) The trap #2 handler would simply enable hardware interrupts
+ (set PSR.PIL to 0), set ICC2.C to 1 and return.
(10) Immediately upon returning, the pending interrupt would be taken.
-(11) The interrupt handler would take the path of actually processing the interrupt (ICC2.Z is
- clear, BEQ fails as per step (2)).
+(11) The interrupt handler would take the path of actually processing the
+ interrupt (ICC2.Z is clear, BEQ fails as per step (2)).
-(12) The interrupt handler would then set ICC2.C to 1 since hardware interrupts are definitely
- enabled - or else the kernel wouldn't be here.
+(12) The interrupt handler would then set ICC2.C to 1 since hardware
+ interrupts are definitely enabled - or else the kernel wouldn't be here.
(13) On return from the interrupt handler, things would be back to state (1).
-This trap (#2) is only available in kernel mode. In user mode it will result in SIGILL.
+This trap (#2) is only available in kernel mode. In user mode it will
+result in SIGILL.
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index f8cb55c30b0..b3a6187e530 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1,4 +1,4 @@
-February 2003 Kernel Parameters v2.5.59
+ Kernel Parameters
~~~~~~~~~~~~~~~~~
The following is a consolidated list of the kernel parameters as implemented
@@ -17,9 +17,17 @@ are specified on the kernel command line with the module name plus
usbcore.blinkenlights=1
-The text in square brackets at the beginning of the description states the
-restrictions on the kernel for the said kernel parameter to be valid. The
-restrictions referred to are that the relevant option is valid if:
+This document may not be entirely up to date and comprehensive. The command
+"modinfo -p ${modulename}" shows a current list of all parameters of a loadable
+module. Loadable modules, after being loaded into the running kernel, also
+reveal their parameters in /sys/module/${modulename}/parameters/. Some of these
+parameters may be changed at runtime by the command
+"echo -n ${value} > /sys/module/${modulename}/parameters/${parm}".
+
+The parameters listed below are only valid if certain kernel build options were
+enabled and if respective hardware is present. The text in square brackets at
+the beginning of each description states the restrictions within which a
+parameter is applicable:
ACPI ACPI support is enabled.
ALSA ALSA sound support is enabled.
@@ -1046,10 +1054,10 @@ running once the system is up.
noltlbs [PPC] Do not use large page/tlb entries for kernel
lowmem mapping on PPC40x.
- nomce [IA-32] Machine Check Exception
-
nomca [IA-64] Disable machine check abort handling
+ nomce [IA-32] Machine Check Exception
+
noresidual [PPC] Don't use residual data on PReP machines.
noresume [SWSUSP] Disables resume and restores original swap
@@ -1682,20 +1690,6 @@ running once the system is up.
______________________________________________________________________
-Changelog:
-
-2000-06-?? Mr. Unknown
- The last known update (for 2.4.0) - the changelog was not kept before.
-
-2002-11-24 Petr Baudis <pasky@ucw.cz>
- Randy Dunlap <randy.dunlap@verizon.net>
- Update for 2.5.49, description for most of the options introduced,
- references to other documentation (C files, READMEs, ..), added S390,
- PPC, SPARC, MTD, ALSA and OSS category. Minor corrections and
- reformatting.
-
-2005-10-19 Randy Dunlap <rdunlap@xenotime.net>
- Lots of typos, whitespace, some reformatting.
TODO:
diff --git a/Documentation/networking/packet_mmap.txt b/Documentation/networking/packet_mmap.txt
index 4fc8e987432..aaf99d5f0da 100644
--- a/Documentation/networking/packet_mmap.txt
+++ b/Documentation/networking/packet_mmap.txt
@@ -254,7 +254,7 @@ and, the number of frames be
<block number> * <block size> / <frame size>
-Suposse the following parameters, which apply for 2.6 kernel and an
+Suppose the following parameters, which apply for 2.6 kernel and an
i386 architecture:
<size-max> = 131072 bytes
diff --git a/Documentation/networking/tuntap.txt b/Documentation/networking/tuntap.txt
index ec3d109d787..76750fb9151 100644
--- a/Documentation/networking/tuntap.txt
+++ b/Documentation/networking/tuntap.txt
@@ -138,7 +138,7 @@ This means that you have to read/write IP packets when you are using tun and
ethernet frames when using tap.
5. What is the difference between BPF and TUN/TAP driver?
-BFP is an advanced packet filter. It can be attached to existing
+BPF is an advanced packet filter. It can be attached to existing
network interface. It does not provide a virtual network interface.
A TUN/TAP driver does provide a virtual network interface and it is possible
to attach BPF to this interface.
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt
index 1def6049784..0ee2c7dfc48 100644
--- a/Documentation/sound/alsa/ALSA-Configuration.txt
+++ b/Documentation/sound/alsa/ALSA-Configuration.txt
@@ -120,6 +120,34 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
enable - enable card
- Default: enabled, for PCI and ISA PnP cards
+ Module snd-adlib
+ ----------------
+
+ Module for AdLib FM cards.
+
+ port - port # for OPL chip
+
+ This module supports multiple cards. It does not support autoprobe, so
+ the port must be specified. For actual AdLib FM cards it will be 0x388.
+ Note that this card does not have PCM support and no mixer; only FM
+ synthesis.
+
+ Make sure you have "sbiload" from the alsa-tools package available and,
+ after loading the module, find out the assigned ALSA sequencer port
+ number through "sbiload -l". Example output:
+
+ Port Client name Port name
+ 64:0 OPL2 FM synth OPL2 FM Port
+
+ Load the std.sb and drums.sb patches also supplied by sbiload:
+
+ sbiload -p 64:0 std.sb drums.sb
+
+ If you use this driver to drive an OPL3, you can use std.o3 and drums.o3
+ instead. To have the card produce sound, use aplaymidi from alsa-utils:
+
+ aplaymidi -p 64:0 foo.mid
+
Module snd-ad1816a
------------------
@@ -190,6 +218,15 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
The power-management is supported.
+ Module snd-als300
+ -----------------
+
+ Module for Avance Logic ALS300 and ALS300+
+
+ This module supports multiple cards.
+
+ The power-management is supported.
+
Module snd-als4000
------------------
@@ -701,6 +738,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
uniwill 3-jack
F1734 2-jack
lg LG laptop (m1 express dual)
+ lg-lw LG LW20 laptop
test for testing/debugging purpose, almost all controls can be
adjusted. Appearing only when compiled with
$CONFIG_SND_DEBUG=y
@@ -1013,6 +1051,23 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
The power-management is supported.
+ Module snd-miro
+ ---------------
+
+ Module for Miro soundcards: miroSOUND PCM 1 pro,
+ miroSOUND PCM 12,
+ miroSOUND PCM 20 Radio.
+
+ port - Port # (0x530,0x604,0xe80,0xf40)
+ irq - IRQ # (5,7,9,10,11)
+ dma1 - 1st dma # (0,1,3)
+ dma2 - 2nd dma # (0,1)
+ mpu_port - MPU-401 port # (0x300,0x310,0x320,0x330)
+ mpu_irq - MPU-401 irq # (5,7,9,10)
+ fm_port - FM Port # (0x388)
+ wss - enable WSS mode
+ ide - enable onboard ide support
+
Module snd-mixart
-----------------
@@ -1202,6 +1257,20 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
The power-management is supported.
+ Module snd-riptide
+ ------------------
+
+ Module for Conexant Riptide chip
+
+ joystick_port - Joystick port # (default: 0x200)
+ mpu_port - MPU401 port # (default: 0x330)
+ opl3_port - OPL3 port # (default: 0x388)
+
+ This module supports multiple cards.
+ The driver requires the firmware loader support on kernel.
+ You need to install the firmware file "riptide.hex" to the standard
+ firmware path (e.g. /lib/firmware).
+
Module snd-rme32
----------------
diff --git a/arch/arm/configs/at91rm9200dk_defconfig b/arch/arm/configs/at91rm9200dk_defconfig
index 1fe73d19888..9e1c1cceb73 100644
--- a/arch/arm/configs/at91rm9200dk_defconfig
+++ b/arch/arm/configs/at91rm9200dk_defconfig
@@ -379,7 +379,7 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=2
# CONFIG_MTD_DOC2001 is not set
# CONFIG_MTD_DOC2001PLUS is not set
CONFIG_MTD_AT91_DATAFLASH=y
-CONFIG_MTD_AT91_DATAFLASH_CARD=y
+# CONFIG_MTD_AT91_DATAFLASH_CARD is not set
#
# NAND Flash Device Drivers
diff --git a/arch/arm/configs/at91rm9200ek_defconfig b/arch/arm/configs/at91rm9200ek_defconfig
index b7d934cdb1b..6e0805a971d 100644
--- a/arch/arm/configs/at91rm9200ek_defconfig
+++ b/arch/arm/configs/at91rm9200ek_defconfig
@@ -370,7 +370,7 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=2
# CONFIG_MTD_DOC2001 is not set
# CONFIG_MTD_DOC2001PLUS is not set
CONFIG_MTD_AT91_DATAFLASH=y
-CONFIG_MTD_AT91_DATAFLASH_CARD=y
+# CONFIG_MTD_AT91_DATAFLASH_CARD is not set
#
# NAND Flash Device Drivers
diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c
index 1574941ebfe..ee083b3f052 100644
--- a/arch/arm/kernel/armksyms.c
+++ b/arch/arm/kernel/armksyms.c
@@ -100,23 +100,12 @@ EXPORT_SYMBOL(__raw_writesl);
#endif
/* string / mem functions */
-EXPORT_SYMBOL(strcpy);
-EXPORT_SYMBOL(strncpy);
-EXPORT_SYMBOL(strcat);
-EXPORT_SYMBOL(strncat);
-EXPORT_SYMBOL(strcmp);
-EXPORT_SYMBOL(strncmp);
EXPORT_SYMBOL(strchr);
-EXPORT_SYMBOL(strlen);
-EXPORT_SYMBOL(strnlen);
EXPORT_SYMBOL(strpbrk);
EXPORT_SYMBOL(strrchr);
-EXPORT_SYMBOL(strstr);
EXPORT_SYMBOL(memset);
EXPORT_SYMBOL(memcpy);
EXPORT_SYMBOL(memmove);
-EXPORT_SYMBOL(memcmp);
-EXPORT_SYMBOL(memscan);
EXPORT_SYMBOL(memchr);
EXPORT_SYMBOL(__memzero);
@@ -190,8 +179,6 @@ EXPORT_SYMBOL(_find_next_bit_be);
/* syscalls */
EXPORT_SYMBOL(sys_write);
-EXPORT_SYMBOL(sys_read);
EXPORT_SYMBOL(sys_lseek);
-EXPORT_SYMBOL(sys_open);
EXPORT_SYMBOL(sys_exit);
EXPORT_SYMBOL(sys_wait4);
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index b7cd280bfd6..43752840395 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -252,6 +252,9 @@ static void __init dump_cpu_info(int cpu)
dump_cache("cache", cpu, CACHE_ISIZE(info));
}
}
+
+ if (arch_is_coherent())
+ printk("Cache coherency enabled\n");
}
int cpu_architecture(void)
diff --git a/arch/arm/mach-at91rm9200/Makefile b/arch/arm/mach-at91rm9200/Makefile
index 75e6ee318de..ef88c4128ed 100644
--- a/arch/arm/mach-at91rm9200/Makefile
+++ b/arch/arm/mach-at91rm9200/Makefile
@@ -16,11 +16,12 @@ obj-$(CONFIG_MACH_CSB637) += board-csb637.o
#obj-$(CONFIG_MACH_KB9200) += board-kb9202.o
# LEDs support
-#led-$(CONFIG_ARCH_AT91RM9200DK) += leds.o
-#led-$(CONFIG_MACH_AT91RM9200EK) += leds.o
-#led-$(CONFIG_MACH_CSB337) += leds.o
-#led-$(CONFIG_MACH_CSB637) += leds.o
+led-$(CONFIG_ARCH_AT91RM9200DK) += leds.o
+led-$(CONFIG_MACH_AT91RM9200EK) += leds.o
+led-$(CONFIG_MACH_CSB337) += leds.o
+led-$(CONFIG_MACH_CSB637) += leds.o
#led-$(CONFIG_MACH_KB9200) += leds.o
+#led-$(CONFIG_MACH_KAFA) += leds.o
obj-$(CONFIG_LEDS) += $(led-y)
# VGA support
diff --git a/arch/arm/mach-at91rm9200/board-csb337.c b/arch/arm/mach-at91rm9200/board-csb337.c
index 54022e58d50..f45104ceea8 100644
--- a/arch/arm/mach-at91rm9200/board-csb337.c
+++ b/arch/arm/mach-at91rm9200/board-csb337.c
@@ -67,6 +67,9 @@ static void __init csb337_map_io(void)
/* Initialize clocks: 3.6864 MHz crystal */
at91_clock_init(3686400);
+ /* Setup the LEDs */
+ at91_init_leds(AT91_PIN_PB2, AT91_PIN_PB2);
+
#ifdef CONFIG_SERIAL_AT91
at91_console_port = CSB337_SERIAL_CONSOLE;
memcpy(at91_serial_map, serial, sizeof(serial));
diff --git a/arch/arm/mach-at91rm9200/board-csb637.c b/arch/arm/mach-at91rm9200/board-csb637.c
index 8195f9d919e..f2c2d6e79bc 100644
--- a/arch/arm/mach-at91rm9200/board-csb637.c
+++ b/arch/arm/mach-at91rm9200/board-csb637.c
@@ -67,6 +67,9 @@ static void __init csb637_map_io(void)
/* Initialize clocks: 3.6864 MHz crystal */
at91_clock_init(3686400);
+ /* Setup the LEDs */
+ at91_init_leds(AT91_PIN_PB2, AT91_PIN_PB2);
+
#ifdef CONFIG_SERIAL_AT91
at91_console_port = CSB637_SERIAL_CONSOLE;
memcpy(at91_serial_map, serial, sizeof(serial));
diff --git a/arch/arm/mach-at91rm9200/board-dk.c b/arch/arm/mach-at91rm9200/board-dk.c
index 8a783368366..2d7200ed66e 100644
--- a/arch/arm/mach-at91rm9200/board-dk.c
+++ b/arch/arm/mach-at91rm9200/board-dk.c
@@ -70,6 +70,9 @@ static void __init dk_map_io(void)
/* Initialize clocks: 18.432 MHz crystal */
at91_clock_init(18432000);
+ /* Setup the LEDs */
+ at91_init_leds(AT91_PIN_PB2, AT91_PIN_PB2);
+
#ifdef CONFIG_SERIAL_AT91
at91_console_port = DK_SERIAL_CONSOLE;
memcpy(at91_serial_map, serial, sizeof(serial));
@@ -118,9 +121,14 @@ static void __init dk_board_init(void)
at91_add_device_udc(&dk_udc_data);
/* Compact Flash */
at91_add_device_cf(&dk_cf_data);
+#ifdef CONFIG_MTD_AT91_DATAFLASH_CARD
+ /* DataFlash card */
+ at91_set_gpio_output(AT91_PIN_PB7, 0);
+#else
/* MMC */
- at91_set_gpio_output(AT91_PIN_PB7, 1); /* this MMC card slot can optionally use SPI signaling (CS3). default: MMC */
+ at91_set_gpio_output(AT91_PIN_PB7, 1); /* this MMC card slot can optionally use SPI signaling (CS3). */
at91_add_device_mmc(&dk_mmc_data);
+#endif
/* VGA */
// dk_add_device_video();
}
diff --git a/arch/arm/mach-at91rm9200/board-ek.c b/arch/arm/mach-at91rm9200/board-ek.c
index fd0752eba89..80d90f5135a 100644
--- a/arch/arm/mach-at91rm9200/board-ek.c
+++ b/arch/arm/mach-at91rm9200/board-ek.c
@@ -70,6 +70,9 @@ static void __init ek_map_io(void)
/* Initialize clocks: 18.432 MHz crystal */
at91_clock_init(18432000);
+ /* Setup the LEDs */
+ at91_init_leds(AT91_PIN_PB1, AT91_PIN_PB2);
+
#ifdef CONFIG_SERIAL_AT91
at91_console_port = EK_SERIAL_CONSOLE;
memcpy(at91_serial_map, serial, sizeof(serial));
@@ -111,9 +114,14 @@ static void __init ek_board_init(void)
at91_add_device_usbh(&ek_usbh_data);
/* USB Device */
at91_add_device_udc(&ek_udc_data);
+#ifdef CONFIG_MTD_AT91_DATAFLASH_CARD
+ /* DataFlash card */
+ at91_set_gpio_output(AT91_PIN_PB22, 0);
+#else
/* MMC */
- at91_set_gpio_output(AT91_PIN_PB22, 1); /* this MMC card slot can optionally use SPI signaling (CS3). default: MMC */
+ at91_set_gpio_output(AT91_PIN_PB22, 1); /* this MMC card slot can optionally use SPI signaling (CS3). */
at91_add_device_mmc(&ek_mmc_data);
+#endif
/* VGA */
// ek_add_device_video();
}
diff --git a/arch/arm/mach-at91rm9200/devices.c b/arch/arm/mach-at91rm9200/devices.c
index 57eedd5beaf..1781b8f342c 100644
--- a/arch/arm/mach-at91rm9200/devices.c
+++ b/arch/arm/mach-at91rm9200/devices.c
@@ -28,10 +28,10 @@
static u64 ohci_dmamask = 0xffffffffUL;
static struct at91_usbh_data usbh_data;
-static struct resource at91rm9200_usbh_resource[] = {
+static struct resource at91_usbh_resource[] = {
[0] = {
.start = AT91_UHP_BASE,
- .end = AT91_UHP_BASE + SZ_1M -1,
+ .end = AT91_UHP_BASE + SZ_1M - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
@@ -49,8 +49,8 @@ static struct platform_device at91rm9200_usbh_device = {
.coherent_dma_mask = 0xffffffff,
.platform_data = &usbh_data,
},
- .resource = at91rm9200_usbh_resource,
- .num_resources = ARRAY_SIZE(at91rm9200_usbh_resource),
+ .resource = at91_usbh_resource,
+ .num_resources = ARRAY_SIZE(at91_usbh_resource),
};
void __init at91_add_device_usbh(struct at91_usbh_data *data)
@@ -121,6 +121,19 @@ void __init at91_add_device_udc(struct at91_udc_data *data) {}
static u64 eth_dmamask = 0xffffffffUL;
static struct at91_eth_data eth_data;
+static struct resource at91_eth_resources[] = {
+ [0] = {
+ .start = AT91_BASE_EMAC,
+ .end = AT91_BASE_EMAC + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91_ID_EMAC,
+ .end = AT91_ID_EMAC,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
static struct platform_device at91rm9200_eth_device = {
.name = "at91_ether",
.id = -1,
@@ -129,7 +142,8 @@ static struct platform_device at91rm9200_eth_device = {
.coherent_dma_mask = 0xffffffff,
.platform_data = &eth_data,
},
- .num_resources = 0,
+ .resource = at91_eth_resources,
+ .num_resources = ARRAY_SIZE(at91_eth_resources),
};
void __init at91_add_device_eth(struct at91_eth_data *data)
@@ -224,15 +238,20 @@ static u64 mmc_dmamask = 0xffffffffUL;
static struct at91_mmc_data mmc_data;
static struct resource at91_mmc_resources[] = {
- {
+ [0] = {
.start = AT91_BASE_MCI,
.end = AT91_BASE_MCI + SZ_16K - 1,
.flags = IORESOURCE_MEM,
- }
+ },
+ [1] = {
+ .start = AT91_ID_MCI,
+ .end = AT91_ID_MCI,
+ .flags = IORESOURCE_IRQ,
+ },
};
static struct platform_device at91rm9200_mmc_device = {
- .name = "at91rm9200_mci",
+ .name = "at91_mci",
.id = -1,
.dev = {
.dma_mask = &mmc_dmamask,
@@ -290,4 +309,123 @@ void __init at91_add_device_mmc(struct at91_mmc_data *data)
void __init at91_add_device_mmc(struct at91_mmc_data *data) {}
#endif
+/* --------------------------------------------------------------------
+ * NAND / SmartMedia
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_MTD_NAND_AT91) || defined(CONFIG_MTD_NAND_AT91_MODULE)
+static struct at91_nand_data nand_data;
+
+static struct resource at91_nand_resources[] = {
+ {
+ .start = AT91_SMARTMEDIA_BASE,
+ .end = AT91_SMARTMEDIA_BASE + SZ_8M - 1,
+ .flags = IORESOURCE_MEM,
+ }
+};
+
+static struct platform_device at91_nand_device = {
+ .name = "at91_nand",
+ .id = -1,
+ .dev = {
+ .platform_data = &nand_data,
+ },
+ .resource = at91_nand_resources,
+ .num_resources = ARRAY_SIZE(at91_nand_resources),
+};
+
+void __init at91_add_device_nand(struct at91_nand_data *data)
+{
+ if (!data)
+ return;
+
+ /* enable pin */
+ if (data->enable_pin)
+ at91_set_gpio_output(data->enable_pin, 1);
+
+ /* ready/busy pin */
+ if (data->rdy_pin)
+ at91_set_gpio_input(data->rdy_pin, 1);
+
+ /* card detect pin */
+ if (data->det_pin)
+ at91_set_gpio_input(data->det_pin, 1);
+
+ at91_set_A_periph(AT91_PIN_PC1, 0); /* SMOE */
+ at91_set_A_periph(AT91_PIN_PC3, 0); /* SMWE */
+
+ nand_data = *data;
+ platform_device_register(&at91_nand_device);
+}
+#else
+void __init at91_add_device_nand(struct at91_nand_data *data) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ * TWI (i2c)
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE)
+static struct platform_device at91rm9200_twi_device = {
+ .name = "at91_i2c",
+ .id = -1,
+ .num_resources = 0,
+};
+
+void __init at91_add_device_i2c(void)
+{
+ /* pins used for TWI interface */
+ at91_set_A_periph(AT91_PIN_PA25, 0); /* TWD */
+ at91_set_multi_drive(AT91_PIN_PA25, 1);
+
+ at91_set_A_periph(AT91_PIN_PA26, 0); /* TWCK */
+ at91_set_multi_drive(AT91_PIN_PA26, 1);
+
+ platform_device_register(&at91rm9200_twi_device);
+}
+#else
+void __init at91_add_device_i2c(void) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ * RTC
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_AT91_RTC) || defined(CONFIG_AT91_RTC_MODULE)
+static struct platform_device at91rm9200_rtc_device = {
+ .name = "at91_rtc",
+ .id = -1,
+ .num_resources = 0,
+};
+
+void __init at91_add_device_rtc(void)
+{
+ platform_device_register(&at91rm9200_rtc_device);
+}
+#else
+void __init at91_add_device_rtc(void) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ * LEDs
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_LEDS)
+u8 at91_leds_cpu;
+u8 at91_leds_timer;
+
+void __init at91_init_leds(u8 cpu_led, u8 timer_led)
+{
+ at91_leds_cpu = cpu_led;
+ at91_leds_timer = timer_led;
+}
+
+#else
+void __init at91_init_leds(u8 cpu_led, u8 timer_led) {}
+#endif
+
+
/* -------------------------------------------------------------------- */
diff --git a/arch/arm/mach-at91rm9200/leds.c b/arch/arm/mach-at91rm9200/leds.c
new file mode 100644
index 00000000000..28150e8905b
--- /dev/null
+++ b/arch/arm/mach-at91rm9200/leds.c
@@ -0,0 +1,100 @@
+/*
+ * LED driver for Atmel AT91-based boards.
+ *
+ * Copyright (C) SAN People (Pty) Ltd
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+*/
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <asm/mach-types.h>
+#include <asm/leds.h>
+#include <asm/arch/board.h>
+#include <asm/arch/gpio.h>
+
+
+static inline void at91_led_on(unsigned int led)
+{
+ at91_set_gpio_value(led, 0);
+}
+
+static inline void at91_led_off(unsigned int led)
+{
+ at91_set_gpio_value(led, 1);
+}
+
+static inline void at91_led_toggle(unsigned int led)
+{
+ unsigned long is_off = at91_get_gpio_value(led);
+ if (is_off)
+ at91_led_on(led);
+ else
+ at91_led_off(led);
+}
+
+
+/*
+ * Handle LED events.
+ */
+static void at91_leds_event(led_event_t evt)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ switch(evt) {
+ case led_start: /* System startup */
+ at91_led_on(at91_leds_cpu);
+ break;
+
+ case led_stop: /* System stop / suspend */
+ at91_led_off(at91_leds_cpu);
+ break;
+
+#ifdef CONFIG_LEDS_TIMER
+ case led_timer: /* Every 50 timer ticks */
+ at91_led_toggle(at91_leds_timer);
+ break;
+#endif
+
+#ifdef CONFIG_LEDS_CPU
+ case led_idle_start: /* Entering idle state */
+ at91_led_off(at91_leds_cpu);
+ break;
+
+ case led_idle_end: /* Exit idle state */
+ at91_led_on(at91_leds_cpu);
+ break;
+#endif
+
+ default:
+ break;
+ }
+
+ local_irq_restore(flags);
+}
+
+
+static int __init leds_init(void)
+{
+ if (!at91_leds_timer || !at91_leds_cpu)
+ return -ENODEV;
+
+ /* Enable PIO to access the LEDs */
+ at91_set_gpio_output(at91_leds_timer, 1);
+ at91_set_gpio_output(at91_leds_cpu, 1);
+
+ leds_event = at91_leds_event;
+
+ leds_event(led_start);
+ return 0;
+}
+
+__initcall(leds_init);
diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
index 2d892e4daa0..dcd41762538 100644
--- a/arch/arm/mach-ep93xx/core.c
+++ b/arch/arm/mach-ep93xx/core.c
@@ -424,6 +424,14 @@ static struct amba_device uart3_device = {
.periphid = 0x00041010,
};
+
+static struct platform_device ep93xx_rtc_device = {
+ .name = "ep93xx-rtc",
+ .id = -1,
+ .num_resources = 0,
+};
+
+
void __init ep93xx_init_devices(void)
{
unsigned int v;
@@ -439,4 +447,6 @@ void __init ep93xx_init_devices(void)
amba_device_register(&uart1_device, &iomem_resource);
amba_device_register(&uart2_device, &iomem_resource);
amba_device_register(&uart3_device, &iomem_resource);
+
+ platform_device_register(&ep93xx_rtc_device);
}
diff --git a/arch/arm/mach-ep93xx/ts72xx.c b/arch/arm/mach-ep93xx/ts72xx.c
index 777e75daa8a..9be01b0c3f4 100644
--- a/arch/arm/mach-ep93xx/ts72xx.c
+++ b/arch/arm/mach-ep93xx/ts72xx.c
@@ -17,6 +17,8 @@
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/mtd/physmap.h>
+#include <linux/platform_device.h>
+#include <linux/m48t86.h>
#include <asm/io.h>
#include <asm/hardware.h>
#include <asm/mach-types.h>
@@ -39,6 +41,16 @@ static struct map_desc ts72xx_io_desc[] __initdata = {
.pfn = __phys_to_pfn(TS72XX_OPTIONS2_PHYS_BASE),
.length = TS72XX_OPTIONS2_SIZE,
.type = MT_DEVICE,
+ }, {
+ .virtual = TS72XX_RTC_INDEX_VIRT_BASE,
+ .pfn = __phys_to_pfn(TS72XX_RTC_INDEX_PHYS_BASE),
+ .length = TS72XX_RTC_INDEX_SIZE,
+ .type = MT_DEVICE,
+ }, {
+ .virtual = TS72XX_RTC_DATA_VIRT_BASE,
+ .pfn = __phys_to_pfn(TS72XX_RTC_DATA_PHYS_BASE),
+ .length = TS72XX_RTC_DATA_SIZE,
+ .type = MT_DEVICE,
}
};
@@ -99,11 +111,38 @@ static void __init ts72xx_map_io(void)
}
}
+static unsigned char ts72xx_rtc_readb(unsigned long addr)
+{
+ __raw_writeb(addr, TS72XX_RTC_INDEX_VIRT_BASE);
+ return __raw_readb(TS72XX_RTC_DATA_VIRT_BASE);
+}
+
+static void ts72xx_rtc_writeb(unsigned char value, unsigned long addr)
+{
+ __raw_writeb(addr, TS72XX_RTC_INDEX_VIRT_BASE);
+ __raw_writeb(value, TS72XX_RTC_DATA_VIRT_BASE);
+}
+
+static struct m48t86_ops ts72xx_rtc_ops = {
+ .readb = ts72xx_rtc_readb,
+ .writeb = ts72xx_rtc_writeb,
+};
+
+static struct platform_device ts72xx_rtc_device = {
+ .name = "rtc-m48t86",
+ .id = -1,
+ .dev = {
+ .platform_data = &ts72xx_rtc_ops,
+ },
+ .num_resources = 0,
+};
+
static void __init ts72xx_init_machine(void)
{
ep93xx_init_devices();
if (board_is_ts7200())
physmap_configure(TS72XX_NOR_PHYS_BASE, 0x01000000, 1, NULL);
+ platform_device_register(&ts72xx_rtc_device);
}
MACHINE_START(TS72XX, "Technologic Systems TS-72xx SBC")
diff --git a/arch/arm/mach-imx/dma.c b/arch/arm/mach-imx/dma.c
index 71a59e19616..4ca51dcf13a 100644
--- a/arch/arm/mach-imx/dma.c
+++ b/arch/arm/mach-imx/dma.c
@@ -7,11 +7,18 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
- * 03/03/2004 Sascha Hauer <sascha@saschahauer.de>
+ * 2004-03-03 Sascha Hauer <sascha@saschahauer.de>
* initial version heavily inspired by
* linux/arch/arm/mach-pxa/dma.c
+ *
+ * 2005-04-17 Pavel Pisa <pisa@cmp.felk.cvut.cz>
+ * Changed to support scatter gather DMA
+ * by taking Russell's code from RiscPC
+ *
*/
+#undef DEBUG
+
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -22,69 +29,368 @@
#include <asm/irq.h>
#include <asm/hardware.h>
#include <asm/dma.h>
+#include <asm/arch/imx-dma.h>
+
+struct imx_dma_channel imx_dma_channels[IMX_DMA_CHANNELS];
+
+/*
+ * imx_dma_sg_next - prepare next chunk for scatter-gather DMA emulation
+ * @dma_ch: i.MX DMA channel number
+ * @lastcount: number of bytes transferred during last transfer
+ *
+ * Functions prepares DMA controller for next sg data chunk transfer.
+ * The @lastcount argument informs function about number of bytes transferred
+ * during last block. Zero value can be used for @lastcount to setup DMA
+ * for the first chunk.
+ */
+static inline int imx_dma_sg_next(imx_dmach_t dma_ch, unsigned int lastcount)
+{
+ struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch];
+ unsigned int nextcount;
+ unsigned int nextaddr;
+
+ if (!imxdma->name) {
+ printk(KERN_CRIT "%s: called for not allocated channel %d\n",
+ __FUNCTION__, dma_ch);
+ return 0;
+ }
+
+ imxdma->resbytes -= lastcount;
+
+ if (!imxdma->sg) {
+ pr_debug("imxdma%d: no sg data\n", dma_ch);
+ return 0;
+ }
+
+ imxdma->sgbc += lastcount;
+ if ((imxdma->sgbc >= imxdma->sg->length) || !imxdma->resbytes) {
+ if ((imxdma->sgcount <= 1) || !imxdma->resbytes) {
+ pr_debug("imxdma%d: sg transfer limit reached\n",
+ dma_ch);
+ imxdma->sgcount=0;
+ imxdma->sg = NULL;
+ return 0;
+ } else {
+ imxdma->sgcount--;
+ imxdma->sg++;
+ imxdma->sgbc = 0;
+ }
+ }
+ nextcount = imxdma->sg->length - imxdma->sgbc;
+ nextaddr = imxdma->sg->dma_address + imxdma->sgbc;
-static struct dma_channel {
- char *name;
- void (*irq_handler) (int, void *, struct pt_regs *);
- void (*err_handler) (int, void *, struct pt_regs *);
- void *data;
-} dma_channels[11];
+ if(imxdma->resbytes < nextcount)
+ nextcount = imxdma->resbytes;
-/* set err_handler to NULL to have the standard info-only error handler */
+ if ((imxdma->dma_mode & DMA_MODE_MASK) == DMA_MODE_READ)
+ DAR(dma_ch) = nextaddr;
+ else
+ SAR(dma_ch) = nextaddr;
+
+ CNTR(dma_ch) = nextcount;
+ pr_debug("imxdma%d: next sg chunk dst 0x%08x, src 0x%08x, size 0x%08x\n",
+ dma_ch, DAR(dma_ch), SAR(dma_ch), CNTR(dma_ch));
+
+ return nextcount;
+}
+
+/*
+ * imx_dma_setup_sg_base - scatter-gather DMA emulation
+ * @dma_ch: i.MX DMA channel number
+ * @sg: pointer to the scatter-gather list/vector
+ * @sgcount: scatter-gather list hungs count
+ *
+ * Functions sets up i.MX DMA state for emulated scatter-gather transfer
+ * and sets up channel registers to be ready for the first chunk
+ */
+static int
+imx_dma_setup_sg_base(imx_dmach_t dma_ch,
+ struct scatterlist *sg, unsigned int sgcount)
+{
+ struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch];
+
+ imxdma->sg = sg;
+ imxdma->sgcount = sgcount;
+ imxdma->sgbc = 0;
+ return imx_dma_sg_next(dma_ch, 0);
+}
+
+/**
+ * imx_dma_setup_single - setup i.MX DMA channel for linear memory to/from device transfer
+ * @dma_ch: i.MX DMA channel number
+ * @dma_address: the DMA/physical memory address of the linear data block
+ * to transfer
+ * @dma_length: length of the data block in bytes
+ * @dev_addr: physical device port address
+ * @dmamode: DMA transfer mode, %DMA_MODE_READ from the device to the memory
+ * or %DMA_MODE_WRITE from memory to the device
+ *
+ * The function setups DMA channel source and destination addresses for transfer
+ * specified by provided parameters. The scatter-gather emulation is disabled,
+ * because linear data block
+ * form the physical address range is transfered.
+ * Return value: if incorrect parameters are provided -%EINVAL.
+ * Zero indicates success.
+ */
int
-imx_request_dma(char *name, imx_dma_prio prio,
- void (*irq_handler) (int, void *, struct pt_regs *),
- void (*err_handler) (int, void *, struct pt_regs *), void *data)
+imx_dma_setup_single(imx_dmach_t dma_ch, dma_addr_t dma_address,
+ unsigned int dma_length, unsigned int dev_addr,
+ dmamode_t dmamode)
{
- unsigned long flags;
- int i, found = 0;
+ struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch];
- /* basic sanity checks */
- if (!name || !irq_handler)
+ imxdma->sg = NULL;
+ imxdma->sgcount = 0;
+ imxdma->dma_mode = dmamode;
+ imxdma->resbytes = dma_length;
+
+ if (!dma_address) {
+ printk(KERN_ERR "imxdma%d: imx_dma_setup_single null address\n",
+ dma_ch);
return -EINVAL;
+ }
- local_irq_save(flags);
+ if (!dma_length) {
+ printk(KERN_ERR "imxdma%d: imx_dma_setup_single zero length\n",
+ dma_ch);
+ return -EINVAL;
+ }
- /* try grabbing a DMA channel with the requested priority */
- for (i = prio; i < prio + (prio == DMA_PRIO_LOW) ? 8 : 4; i++) {
- if (!dma_channels[i].name) {
- found = 1;
- break;
- }
+ if ((dmamode & DMA_MODE_MASK) == DMA_MODE_READ) {
+ pr_debug("imxdma%d: mx_dma_setup_single2dev dma_addressg=0x%08x dma_length=%d dev_addr=0x%08x for read\n",
+ dma_ch, (unsigned int)dma_address, dma_length,
+ dev_addr);
+ SAR(dma_ch) = dev_addr;
+ DAR(dma_ch) = (unsigned int)dma_address;
+ } else if ((dmamode & DMA_MODE_MASK) == DMA_MODE_WRITE) {
+ pr_debug("imxdma%d: mx_dma_setup_single2dev dma_addressg=0x%08x dma_length=%d dev_addr=0x%08x for write\n",
+ dma_ch, (unsigned int)dma_address, dma_length,
+ dev_addr);
+ SAR(dma_ch) = (unsigned int)dma_address;
+ DAR(dma_ch) = dev_addr;
+ } else {
+ printk(KERN_ERR "imxdma%d: imx_dma_setup_single bad dmamode\n",
+ dma_ch);
+ return -EINVAL;
}
- if (!found) {
- /* requested prio group is full, try hier priorities */
- for (i = prio - 1; i >= 0; i--) {
- if (!dma_channels[i].name) {
- found = 1;
- break;
- }
- }
+ CNTR(dma_ch) = dma_length;
+
+ return 0;
+}
+
+/**
+ * imx_dma_setup_sg - setup i.MX DMA channel SG list to/from device transfer
+ * @dma_ch: i.MX DMA channel number
+ * @sg: pointer to the scatter-gather list/vector
+ * @sgcount: scatter-gather list hungs count
+ * @dma_length: total length of the transfer request in bytes
+ * @dev_addr: physical device port address
+ * @dmamode: DMA transfer mode, %DMA_MODE_READ from the device to the memory
+ * or %DMA_MODE_WRITE from memory to the device
+ *
+ * The function setups DMA channel state and registers to be ready for transfer
+ * specified by provided parameters. The scatter-gather emulation is set up
+ * according to the parameters.
+ *
+ * The full preparation of the transfer requires setup of more register
+ * by the caller before imx_dma_enable() can be called.
+ *
+ * %BLR(dma_ch) holds transfer burst length in bytes, 0 means 64 bytes
+ *
+ * %RSSR(dma_ch) has to be set to the DMA request line source %DMA_REQ_xxx
+ *
+ * %CCR(dma_ch) has to specify transfer parameters, the next settings is typical
+ * for linear or simple scatter-gather transfers if %DMA_MODE_READ is specified
+ *
+ * %CCR_DMOD_LINEAR | %CCR_DSIZ_32 | %CCR_SMOD_FIFO | %CCR_SSIZ_x
+ *
+ * The typical setup for %DMA_MODE_WRITE is specified by next options combination
+ *
+ * %CCR_SMOD_LINEAR | %CCR_SSIZ_32 | %CCR_DMOD_FIFO | %CCR_DSIZ_x
+ *
+ * Be carefull there and do not mistakenly mix source and target device
+ * port sizes constants, they are really different:
+ * %CCR_SSIZ_8, %CCR_SSIZ_16, %CCR_SSIZ_32,
+ * %CCR_DSIZ_8, %CCR_DSIZ_16, %CCR_DSIZ_32
+ *
+ * Return value: if incorrect parameters are provided -%EINVAL.
+ * Zero indicates success.
+ */
+int
+imx_dma_setup_sg(imx_dmach_t dma_ch,
+ struct scatterlist *sg, unsigned int sgcount, unsigned int dma_length,
+ unsigned int dev_addr, dmamode_t dmamode)
+{
+ int res;
+ struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch];
+
+ imxdma->sg = NULL;
+ imxdma->sgcount = 0;
+ imxdma->dma_mode = dmamode;
+ imxdma->resbytes = dma_length;
+
+ if (!sg || !sgcount) {
+ printk(KERN_ERR "imxdma%d: imx_dma_setup_sg epty sg list\n",
+ dma_ch);
+ return -EINVAL;
+ }
+
+ if (!sg->length) {
+ printk(KERN_ERR "imxdma%d: imx_dma_setup_sg zero length\n",
+ dma_ch);
+ return -EINVAL;
}
- if (found) {
- DIMR &= ~(1 << i);
- dma_channels[i].name = name;
- dma_channels[i].irq_handler = irq_handler;
- dma_channels[i].err_handler = err_handler;
- dma_channels[i].data = data;
+ if ((dmamode & DMA_MODE_MASK) == DMA_MODE_READ) {
+ pr_debug("imxdma%d: mx_dma_setup_sg2dev sg=%p sgcount=%d total length=%d dev_addr=0x%08x for read\n",
+ dma_ch, sg, sgcount, dma_length, dev_addr);
+ SAR(dma_ch) = dev_addr;
+ } else if ((dmamode & DMA_MODE_MASK) == DMA_MODE_WRITE) {
+ pr_debug("imxdma%d: mx_dma_setup_sg2dev sg=%p sgcount=%d total length=%d dev_addr=0x%08x for write\n",
+ dma_ch, sg, sgcount, dma_length, dev_addr);
+ DAR(dma_ch) = dev_addr;
} else {
- printk(KERN_WARNING "No more available DMA channels for %s\n",
- name);
- i = -ENODEV;
+ printk(KERN_ERR "imxdma%d: imx_dma_setup_sg bad dmamode\n",
+ dma_ch);
+ return -EINVAL;
+ }
+
+ res = imx_dma_setup_sg_base(dma_ch, sg, sgcount);
+ if (res <= 0) {
+ printk(KERN_ERR "imxdma%d: no sg chunk ready\n", dma_ch);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * imx_dma_setup_handlers - setup i.MX DMA channel end and error notification handlers
+ * @dma_ch: i.MX DMA channel number
+ * @irq_handler: the pointer to the function called if the transfer
+ * ends successfully
+ * @err_handler: the pointer to the function called if the premature
+ * end caused by error occurs
+ * @data: user specified value to be passed to the handlers
+ */
+int
+imx_dma_setup_handlers(imx_dmach_t dma_ch,
+ void (*irq_handler) (int, void *, struct pt_regs *),
+ void (*err_handler) (int, void *, struct pt_regs *),
+ void *data)
+{
+ struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch];
+ unsigned long flags;
+
+ if (!imxdma->name) {
+ printk(KERN_CRIT "%s: called for not allocated channel %d\n",
+ __FUNCTION__, dma_ch);
+ return -ENODEV;
+ }
+
+ local_irq_save(flags);
+ DISR = (1 << dma_ch);
+ imxdma->irq_handler = irq_handler;
+ imxdma->err_handler = err_handler;
+ imxdma->data = data;
+ local_irq_restore(flags);
+ return 0;
+}
+
+/**
+ * imx_dma_enable - function to start i.MX DMA channel operation
+ * @dma_ch: i.MX DMA channel number
+ *
+ * The channel has to be allocated by driver through imx_dma_request()
+ * or imx_dma_request_by_prio() function.
+ * The transfer parameters has to be set to the channel registers through
+ * call of the imx_dma_setup_single() or imx_dma_setup_sg() function
+ * and registers %BLR(dma_ch), %RSSR(dma_ch) and %CCR(dma_ch) has to
+ * be set prior this function call by the channel user.
+ */
+void imx_dma_enable(imx_dmach_t dma_ch)
+{
+ struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch];
+ unsigned long flags;
+
+ pr_debug("imxdma%d: imx_dma_enable\n", dma_ch);
+
+ if (!imxdma->name) {
+ printk(KERN_CRIT "%s: called for not allocated channel %d\n",
+ __FUNCTION__, dma_ch);
+ return;
+ }
+
+ local_irq_save(flags);
+ DISR = (1 << dma_ch);
+ DIMR &= ~(1 << dma_ch);
+ CCR(dma_ch) |= CCR_CEN;
+ local_irq_restore(flags);
+}
+
+/**
+ * imx_dma_disable - stop, finish i.MX DMA channel operatin
+ * @dma_ch: i.MX DMA channel number
+ */
+void imx_dma_disable(imx_dmach_t dma_ch)
+{
+ unsigned long flags;
+
+ pr_debug("imxdma%d: imx_dma_disable\n", dma_ch);
+
+ local_irq_save(flags);
+ DIMR |= (1 << dma_ch);
+ CCR(dma_ch) &= ~CCR_CEN;
+ DISR = (1 << dma_ch);
+ local_irq_restore(flags);
+}
+
+/**
+ * imx_dma_request - request/allocate specified channel number
+ * @dma_ch: i.MX DMA channel number
+ * @name: the driver/caller own non-%NULL identification
+ */
+int imx_dma_request(imx_dmach_t dma_ch, const char *name)
+{
+ struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch];
+ unsigned long flags;
+
+ /* basic sanity checks */
+ if (!name)
+ return -EINVAL;
+
+ if (dma_ch >= IMX_DMA_CHANNELS) {
+ printk(KERN_CRIT "%s: called for non-existed channel %d\n",
+ __FUNCTION__, dma_ch);
+ return -EINVAL;
}
+ local_irq_save(flags);
+ if (imxdma->name) {
+ local_irq_restore(flags);
+ return -ENODEV;
+ }
+
+ imxdma->name = name;
+ imxdma->irq_handler = NULL;
+ imxdma->err_handler = NULL;
+ imxdma->data = NULL;
+ imxdma->sg = NULL;
local_irq_restore(flags);
- return i;
+ return 0;
}
-void
-imx_free_dma(int dma_ch)
+/**
+ * imx_dma_free - release previously acquired channel
+ * @dma_ch: i.MX DMA channel number
+ */
+void imx_dma_free(imx_dmach_t dma_ch)
{
unsigned long flags;
+ struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch];
- if (!dma_channels[dma_ch].name) {
+ if (!imxdma->name) {
printk(KERN_CRIT
"%s: trying to free channel %d which is already freed\n",
__FUNCTION__, dma_ch);
@@ -92,27 +398,84 @@ imx_free_dma(int dma_ch)
}
local_irq_save(flags);
- DIMR &= ~(1 << dma_ch);
- dma_channels[dma_ch].name = NULL;
+ /* Disable interrupts */
+ DIMR |= (1 << dma_ch);
+ CCR(dma_ch) &= ~CCR_CEN;
+ imxdma->name = NULL;
local_irq_restore(flags);
}
-static irqreturn_t
-dma_err_handler(int irq, void *dev_id, struct pt_regs *regs)
+/**
+ * imx_dma_request_by_prio - find and request some of free channels best suiting requested priority
+ * @dma_ch: i.MX DMA channel number
+ * @name: the driver/caller own non-%NULL identification
+ * @prio: one of the hardware distinguished priority level:
+ * %DMA_PRIO_HIGH, %DMA_PRIO_MEDIUM, %DMA_PRIO_LOW
+ *
+ * This function tries to find free channel in the specified priority group
+ * if the priority cannot be achieved it tries to look for free channel
+ * in the higher and then even lower priority groups.
+ *
+ * Return value: If there is no free channel to allocate, -%ENODEV is returned.
+ * Zero value indicates successful channel allocation.
+ */
+int
+imx_dma_request_by_prio(imx_dmach_t * pdma_ch, const char *name,
+ imx_dma_prio prio)
+{
+ int i;
+ int best;
+
+ switch (prio) {
+ case (DMA_PRIO_HIGH):
+ best = 8;
+ break;
+ case (DMA_PRIO_MEDIUM):
+ best = 4;
+ break;
+ case (DMA_PRIO_LOW):
+ default:
+ best = 0;
+ break;
+ }
+
+ for (i = best; i < IMX_DMA_CHANNELS; i++) {
+ if (!imx_dma_request(i, name)) {
+ *pdma_ch = i;
+ return 0;
+ }
+ }
+
+ for (i = best - 1; i >= 0; i--) {
+ if (!imx_dma_request(i, name)) {
+ *pdma_ch = i;
+ return 0;
+ }
+ }
+
+ printk(KERN_ERR "%s: no free DMA channel found\n", __FUNCTION__);
+
+ return -ENODEV;
+}
+
+static irqreturn_t dma_err_handler(int irq, void *dev_id, struct pt_regs *regs)
{
int i, disr = DISR;
- struct dma_channel *channel;
+ struct imx_dma_channel *channel;
unsigned int err_mask = DBTOSR | DRTOSR | DSESR | DBOSR;
DISR = disr;
- for (i = 0; i < 11; i++) {
- channel = &dma_channels[i];
+ for (i = 0; i < IMX_DMA_CHANNELS; i++) {
+ channel = &imx_dma_channels[i];
- if ( (err_mask & 1<<i) && channel->name && channel->err_handler) {
+ if ((err_mask & 1 << i) && channel->name
+ && channel->err_handler) {
channel->err_handler(i, channel->data, regs);
continue;
}
+ imx_dma_channels[i].sg = NULL;
+
if (DBTOSR & (1 << i)) {
printk(KERN_WARNING
"Burst timeout on channel %d (%s)\n",
@@ -141,17 +504,27 @@ dma_err_handler(int irq, void *dev_id, struct pt_regs *regs)
return IRQ_HANDLED;
}
-static irqreturn_t
-dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
{
int i, disr = DISR;
+ pr_debug("imxdma: dma_irq_handler called, disr=0x%08x\n",
+ disr);
+
DISR = disr;
- for (i = 0; i < 11; i++) {
+ for (i = 0; i < IMX_DMA_CHANNELS; i++) {
if (disr & (1 << i)) {
- struct dma_channel *channel = &dma_channels[i];
- if (channel->name && channel->irq_handler) {
- channel->irq_handler(i, channel->data, regs);
+ struct imx_dma_channel *channel = &imx_dma_channels[i];
+ if (channel->name) {
+ if (imx_dma_sg_next(i, CNTR(i))) {
+ CCR(i) &= ~CCR_CEN;
+ mb();
+ CCR(i) |= CCR_CEN;
+ } else {
+ if (channel->irq_handler)
+ channel->irq_handler(i,
+ channel->data, regs);
+ }
} else {
/*
* IRQ for an unregistered DMA channel:
@@ -165,10 +538,10 @@ dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
return IRQ_HANDLED;
}
-static int __init
-imx_dma_init(void)
+static int __init imx_dma_init(void)
{
int ret;
+ int i;
/* reset DMA module */
DCR = DCR_DRST;
@@ -189,15 +562,27 @@ imx_dma_init(void)
DCR = DCR_DEN;
/* clear all interrupts */
- DISR = 0x3ff;
+ DISR = (1 << IMX_DMA_CHANNELS) - 1;
/* enable interrupts */
- DIMR = 0;
+ DIMR = (1 << IMX_DMA_CHANNELS) - 1;
+
+ for (i = 0; i < IMX_DMA_CHANNELS; i++) {
+ imx_dma_channels[i].sg = NULL;
+ imx_dma_channels[i].dma_num = i;
+ }
return ret;
}
arch_initcall(imx_dma_init);
-EXPORT_SYMBOL(imx_request_dma);
-EXPORT_SYMBOL(imx_free_dma);
+EXPORT_SYMBOL(imx_dma_setup_single);
+EXPORT_SYMBOL(imx_dma_setup_sg);
+EXPORT_SYMBOL(imx_dma_setup_handlers);
+EXPORT_SYMBOL(imx_dma_enable);
+EXPORT_SYMBOL(imx_dma_disable);
+EXPORT_SYMBOL(imx_dma_request);
+EXPORT_SYMBOL(imx_dma_free);
+EXPORT_SYMBOL(imx_dma_request_by_prio);
+EXPORT_SYMBOL(imx_dma_channels);
diff --git a/arch/arm/mach-imx/generic.c b/arch/arm/mach-imx/generic.c
index 37613ad6836..9d8331be2b5 100644
--- a/arch/arm/mach-imx/generic.c
+++ b/arch/arm/mach-imx/generic.c
@@ -33,6 +33,7 @@
#include <asm/arch/imx-regs.h>
#include <asm/mach/map.h>
+#include <asm/arch/mmc.h>
void imx_gpio_mode(int gpio_mode)
{
@@ -175,13 +176,25 @@ static struct resource imx_mmc_resources[] = {
},
};
+static u64 imxmmmc_dmamask = 0xffffffffUL;
+
static struct platform_device imx_mmc_device = {
.name = "imx-mmc",
.id = 0,
+ .dev = {
+ .dma_mask = &imxmmmc_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ },
.num_resources = ARRAY_SIZE(imx_mmc_resources),
.resource = imx_mmc_resources,
};
+void __init imx_set_mmc_info(struct imxmmc_platform_data *info)
+{
+ imx_mmc_device.dev.platform_data = info;
+}
+EXPORT_SYMBOL(imx_set_mmc_info);
+
static struct resource imx_uart1_resources[] = {
[0] = {
.start = 0x00206000,
diff --git a/arch/arm/mach-imx/mx1ads.c b/arch/arm/mach-imx/mx1ads.c
index 8ab1b040288..e34d0df90ae 100644
--- a/arch/arm/mach-imx/mx1ads.c
+++ b/arch/arm/mach-imx/mx1ads.c
@@ -25,6 +25,7 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
+#include <asm/arch/mmc.h>
#include <linux/interrupt.h>
#include "generic.h"
@@ -51,12 +52,29 @@ static struct platform_device *devices[] __initdata = {
&cs89x0_device,
};
+#ifdef CONFIG_MMC_IMX
+static int mx1ads_mmc_card_present(void)
+{
+ /* MMC/SD Card Detect is PB 20 on MX1ADS V1.0.7 */
+ return (SSR(1) & (1 << 20) ? 0 : 1);
+}
+
+static struct imxmmc_platform_data mx1ads_mmc_info = {
+ .card_present = mx1ads_mmc_card_present,
+};
+#endif
+
static void __init
mx1ads_init(void)
{
#ifdef CONFIG_LEDS
imx_gpio_mode(GPIO_PORTA | GPIO_OUT | 2);
#endif
+#ifdef CONFIG_MMC_IMX
+ /* SD/MMC card detect */
+ imx_gpio_mode(GPIO_PORTB | GPIO_GIUS | GPIO_IN | 20);
+ imx_set_mmc_info(&mx1ads_mmc_info);
+#endif
platform_add_devices(devices, ARRAY_SIZE(devices));
}
diff --git a/arch/arm/mach-ixp23xx/espresso.c b/arch/arm/mach-ixp23xx/espresso.c
index 2327c979041..bf688c12863 100644
--- a/arch/arm/mach-ixp23xx/espresso.c
+++ b/arch/arm/mach-ixp23xx/espresso.c
@@ -44,6 +44,15 @@
#include <asm/mach/irq.h>
#include <asm/mach/pci.h>
+static int __init espresso_pci_init(void)
+{
+ if (machine_is_espresso())
+ ixp23xx_pci_slave_init();
+
+ return 0;
+};
+subsys_initcall(espresso_pci_init);
+
static void __init espresso_init(void)
{
physmap_configure(0x90000000, 0x02000000, 2, NULL);
diff --git a/arch/arm/mach-ixp23xx/pci.c b/arch/arm/mach-ixp23xx/pci.c
index 5330ad78c1b..ac72f94c5b4 100644
--- a/arch/arm/mach-ixp23xx/pci.c
+++ b/arch/arm/mach-ixp23xx/pci.c
@@ -201,7 +201,7 @@ int clear_master_aborts(void)
return 0;
}
-void __init ixp23xx_pci_preinit(void)
+static void __init ixp23xx_pci_common_init(void)
{
#ifdef __ARMEB__
*IXP23XX_PCI_CONTROL |= 0x20000; /* set I/O swapping */
@@ -219,7 +219,18 @@ void __init ixp23xx_pci_preinit(void)
*IXP23XX_PCI_CPP_ADDR_BITS &= ~(1 << 1);
} else {
*IXP23XX_PCI_CPP_ADDR_BITS |= (1 << 1);
+
+ /*
+ * Enable coherency on A2 silicon.
+ */
+ if (arch_is_coherent())
+ *IXP23XX_CPP2XSI_CURR_XFER_REG3 &= ~IXP23XX_CPP2XSI_COH_OFF;
}
+}
+
+void __init ixp23xx_pci_preinit(void)
+{
+ ixp23xx_pci_common_init();
hook_fault_code(16+6, ixp23xx_pci_abort_handler, SIGBUS,
"PCI config cycle to non-existent device");
@@ -273,3 +284,8 @@ int ixp23xx_pci_setup(int nr, struct pci_sys_data *sys)
return 1;
}
+
+void ixp23xx_pci_slave_init(void)
+{
+ ixp23xx_pci_common_init();
+}
diff --git a/arch/arm/mach-omap1/Kconfig b/arch/arm/mach-omap1/Kconfig
index 86a0f0d1434..f8d716ccc1d 100644
--- a/arch/arm/mach-omap1/Kconfig
+++ b/arch/arm/mach-omap1/Kconfig
@@ -69,12 +69,6 @@ config MACH_VOICEBLUE
Support for Voiceblue GSM/VoIP gateway. Say Y here if you have
such a board.
-config MACH_NETSTAR
- bool "NetStar"
- depends on ARCH_OMAP1 && ARCH_OMAP15XX
- help
- Support for NetStar PBX. Say Y here if you have such a board.
-
config MACH_OMAP_PALMTE
bool "Palm Tungsten E"
depends on ARCH_OMAP1 && ARCH_OMAP15XX
@@ -85,6 +79,20 @@ config MACH_OMAP_PALMTE
informations.
Say Y here if you have such a PDA, say NO otherwise.
+config MACH_NOKIA770
+ bool "Nokia 770"
+ depends on ARCH_OMAP1 && ARCH_OMAP16XX
+ help
+ Support for the Nokia 770 Internet Tablet. Say Y here if you
+ have such a device.
+
+config MACH_AMS_DELTA
+ bool "Amstrad E3 (Delta)"
+ depends on ARCH_OMAP1 && ARCH_OMAP15XX
+ help
+ Support for the Amstrad E3 (codename Delta) videophone. Say Y here
+ if you have such a device.
+
config MACH_OMAP_GENERIC
bool "Generic OMAP board"
depends on ARCH_OMAP1 && (ARCH_OMAP15XX || ARCH_OMAP16XX)
diff --git a/arch/arm/mach-omap1/Makefile b/arch/arm/mach-omap1/Makefile
index b0b00156faa..9ea719550ad 100644
--- a/arch/arm/mach-omap1/Makefile
+++ b/arch/arm/mach-omap1/Makefile
@@ -3,7 +3,13 @@
#
# Common support
-obj-y := io.o id.o clock.o irq.o time.o mux.o serial.o devices.o
+obj-y := io.o id.o clock.o irq.o mux.o serial.o devices.o
+
+obj-$(CONFIG_OMAP_MPU_TIMER) += time.o
+
+# Power Management
+obj-$(CONFIG_PM) += pm.o sleep.o
+
led-y := leds.o
# Specific board support
@@ -14,8 +20,9 @@ obj-$(CONFIG_MACH_OMAP_PERSEUS2) += board-perseus2.o
obj-$(CONFIG_MACH_OMAP_OSK) += board-osk.o
obj-$(CONFIG_MACH_OMAP_H3) += board-h3.o
obj-$(CONFIG_MACH_VOICEBLUE) += board-voiceblue.o
-obj-$(CONFIG_MACH_NETSTAR) += board-netstar.o
obj-$(CONFIG_MACH_OMAP_PALMTE) += board-palmte.o
+obj-$(CONFIG_MACH_NOKIA770) += board-nokia770.o
+obj-$(CONFIG_MACH_AMS_DELTA) += board-ams-delta.o
ifeq ($(CONFIG_ARCH_OMAP15XX),y)
# Innovator-1510 FPGA
diff --git a/arch/arm/mach-omap1/board-ams-delta.c b/arch/arm/mach-omap1/board-ams-delta.c
new file mode 100644
index 00000000000..6178f046f12
--- /dev/null
+++ b/arch/arm/mach-omap1/board-ams-delta.c
@@ -0,0 +1,116 @@
+/*
+ * linux/arch/arm/mach-omap1/board-ams-delta.c
+ *
+ * Modified from board-generic.c
+ *
+ * Board specific inits for the Amstrad E3 (codename Delta) videophone
+ *
+ * Copyright (C) 2006 Jonathan McDowell <noodles@earth.li>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <asm/arch/board-ams-delta.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/usb.h>
+#include <asm/arch/board.h>
+#include <asm/arch/common.h>
+
+static u8 ams_delta_latch1_reg;
+static u16 ams_delta_latch2_reg;
+
+void ams_delta_latch1_write(u8 mask, u8 value)
+{
+ ams_delta_latch1_reg &= ~mask;
+ ams_delta_latch1_reg |= value;
+ *(volatile __u8 *) AMS_DELTA_LATCH1_VIRT = ams_delta_latch1_reg;
+}
+
+void ams_delta_latch2_write(u16 mask, u16 value)
+{
+ ams_delta_latch2_reg &= ~mask;
+ ams_delta_latch2_reg |= value;
+ *(volatile __u16 *) AMS_DELTA_LATCH2_VIRT = ams_delta_latch2_reg;
+}
+
+static void __init ams_delta_init_irq(void)
+{
+ omap1_init_common_hw();
+ omap_init_irq();
+ omap_gpio_init();
+}
+
+static struct map_desc ams_delta_io_desc[] __initdata = {
+ // AMS_DELTA_LATCH1
+ {
+ .virtual = AMS_DELTA_LATCH1_VIRT,
+ .pfn = __phys_to_pfn(AMS_DELTA_LATCH1_PHYS),
+ .length = 0x01000000,
+ .type = MT_DEVICE
+ },
+ // AMS_DELTA_LATCH2
+ {
+ .virtual = AMS_DELTA_LATCH2_VIRT,
+ .pfn = __phys_to_pfn(AMS_DELTA_LATCH2_PHYS),
+ .length = 0x01000000,
+ .type = MT_DEVICE
+ },
+ // AMS_DELTA_MODEM
+ {
+ .virtual = AMS_DELTA_MODEM_VIRT,
+ .pfn = __phys_to_pfn(AMS_DELTA_MODEM_PHYS),
+ .length = 0x01000000,
+ .type = MT_DEVICE
+ }
+};
+
+static struct omap_uart_config ams_delta_uart_config __initdata = {
+ .enabled_uarts = 1,
+};
+
+static struct omap_board_config_kernel ams_delta_config[] = {
+ { OMAP_TAG_UART, &ams_delta_uart_config },
+};
+
+static void __init ams_delta_init(void)
+{
+ iotable_init(ams_delta_io_desc, ARRAY_SIZE(ams_delta_io_desc));
+
+ omap_board_config = ams_delta_config;
+ omap_board_config_size = ARRAY_SIZE(ams_delta_config);
+ omap_serial_init();
+
+ /* Clear latch2 (NAND, LCD, modem enable) */
+ ams_delta_latch2_write(~0, 0);
+}
+
+static void __init ams_delta_map_io(void)
+{
+ omap1_map_common_io();
+}
+
+MACHINE_START(AMS_DELTA, "Amstrad E3 (Delta)")
+ /* Maintainer: Jonathan McDowell <noodles@earth.li> */
+ .phys_io = 0xfff00000,
+ .io_pg_offst = ((0xfef00000) >> 18) & 0xfffc,
+ .boot_params = 0x10000100,
+ .map_io = ams_delta_map_io,
+ .init_irq = ams_delta_init_irq,
+ .init_machine = ams_delta_init,
+ .timer = &omap_timer,
+MACHINE_END
+
+EXPORT_SYMBOL(ams_delta_latch1_write);
+EXPORT_SYMBOL(ams_delta_latch2_write);
diff --git a/arch/arm/mach-omap1/board-generic.c b/arch/arm/mach-omap1/board-generic.c
index a177e78b2b8..33d01adab1e 100644
--- a/arch/arm/mach-omap1/board-generic.c
+++ b/arch/arm/mach-omap1/board-generic.c
@@ -88,7 +88,7 @@ static struct omap_board_config_kernel generic_config[] = {
static void __init omap_generic_init(void)
{
#ifdef CONFIG_ARCH_OMAP15XX
- if (cpu_is_omap1510()) {
+ if (cpu_is_omap15xx()) {
generic_config[0].data = &generic1510_usb_config;
}
#endif
diff --git a/arch/arm/mach-omap1/board-h2.c b/arch/arm/mach-omap1/board-h2.c
index 89f0cc74a51..cd3a06dfc0a 100644
--- a/arch/arm/mach-omap1/board-h2.c
+++ b/arch/arm/mach-omap1/board-h2.c
@@ -24,7 +24,9 @@
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
+#include <linux/input.h>
#include <asm/hardware.h>
#include <asm/mach-types.h>
@@ -35,12 +37,55 @@
#include <asm/arch/gpio.h>
#include <asm/arch/mux.h>
#include <asm/arch/tc.h>
+#include <asm/arch/irda.h>
#include <asm/arch/usb.h>
+#include <asm/arch/keypad.h>
#include <asm/arch/common.h>
+#include <asm/arch/mcbsp.h>
+#include <asm/arch/omap-alsa.h>
extern int omap_gpio_init(void);
-static struct mtd_partition h2_partitions[] = {
+static int h2_keymap[] = {
+ KEY(0, 0, KEY_LEFT),
+ KEY(0, 1, KEY_RIGHT),
+ KEY(0, 2, KEY_3),
+ KEY(0, 3, KEY_F10),
+ KEY(0, 4, KEY_F5),
+ KEY(0, 5, KEY_9),
+ KEY(1, 0, KEY_DOWN),
+ KEY(1, 1, KEY_UP),
+ KEY(1, 2, KEY_2),
+ KEY(1, 3, KEY_F9),
+ KEY(1, 4, KEY_F7),
+ KEY(1, 5, KEY_0),
+ KEY(2, 0, KEY_ENTER),
+ KEY(2, 1, KEY_6),
+ KEY(2, 2, KEY_1),
+ KEY(2, 3, KEY_F2),
+ KEY(2, 4, KEY_F6),
+ KEY(2, 5, KEY_HOME),
+ KEY(3, 0, KEY_8),
+ KEY(3, 1, KEY_5),
+ KEY(3, 2, KEY_F12),
+ KEY(3, 3, KEY_F3),
+ KEY(3, 4, KEY_F8),
+ KEY(3, 5, KEY_END),
+ KEY(4, 0, KEY_7),
+ KEY(4, 1, KEY_4),
+ KEY(4, 2, KEY_F11),
+ KEY(4, 3, KEY_F1),
+ KEY(4, 4, KEY_F4),
+ KEY(4, 5, KEY_ESC),
+ KEY(5, 0, KEY_F13),
+ KEY(5, 1, KEY_F14),
+ KEY(5, 2, KEY_F15),
+ KEY(5, 3, KEY_F16),
+ KEY(5, 4, KEY_SLEEP),
+ 0
+};
+
+static struct mtd_partition h2_nor_partitions[] = {
/* bootloader (U-Boot, etc) in first sector */
{
.name = "bootloader",
@@ -71,26 +116,26 @@ static struct mtd_partition h2_partitions[] = {
}
};
-static struct flash_platform_data h2_flash_data = {
+static struct flash_platform_data h2_nor_data = {
.map_name = "cfi_probe",
.width = 2,
- .parts = h2_partitions,
- .nr_parts = ARRAY_SIZE(h2_partitions),
+ .parts = h2_nor_partitions,
+ .nr_parts = ARRAY_SIZE(h2_nor_partitions),
};
-static struct resource h2_flash_resource = {
+static struct resource h2_nor_resource = {
/* This is on CS3, wherever it's mapped */
.flags = IORESOURCE_MEM,
};
-static struct platform_device h2_flash_device = {
+static struct platform_device h2_nor_device = {
.name = "omapflash",
.id = 0,
.dev = {
- .platform_data = &h2_flash_data,
+ .platform_data = &h2_nor_data,
},
.num_resources = 1,
- .resource = &h2_flash_resource,
+ .resource = &h2_nor_resource,
};
static struct resource h2_smc91x_resources[] = {
@@ -113,9 +158,119 @@ static struct platform_device h2_smc91x_device = {
.resource = h2_smc91x_resources,
};
+static struct resource h2_kp_resources[] = {
+ [0] = {
+ .start = INT_KEYBOARD,
+ .end = INT_KEYBOARD,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct omap_kp_platform_data h2_kp_data = {
+ .rows = 8,
+ .cols = 8,
+ .keymap = h2_keymap,
+ .rep = 1,
+};
+
+static struct platform_device h2_kp_device = {
+ .name = "omap-keypad",
+ .id = -1,
+ .dev = {
+ .platform_data = &h2_kp_data,
+ },
+ .num_resources = ARRAY_SIZE(h2_kp_resources),
+ .resource = h2_kp_resources,
+};
+
+#define H2_IRDA_FIRSEL_GPIO_PIN 17
+
+#if defined(CONFIG_OMAP_IR) || defined(CONFIG_OMAP_IR_MODULE)
+static int h2_transceiver_mode(struct device *dev, int state)
+{
+ if (state & IR_SIRMODE)
+ omap_set_gpio_dataout(H2_IRDA_FIRSEL_GPIO_PIN, 0);
+ else /* MIR/FIR */
+ omap_set_gpio_dataout(H2_IRDA_FIRSEL_GPIO_PIN, 1);
+
+ return 0;
+}
+#endif
+
+static struct omap_irda_config h2_irda_data = {
+ .transceiver_cap = IR_SIRMODE | IR_MIRMODE | IR_FIRMODE,
+ .rx_channel = OMAP_DMA_UART3_RX,
+ .tx_channel = OMAP_DMA_UART3_TX,
+ .dest_start = UART3_THR,
+ .src_start = UART3_RHR,
+ .tx_trigger = 0,
+ .rx_trigger = 0,
+};
+
+static struct resource h2_irda_resources[] = {
+ [0] = {
+ .start = INT_UART3,
+ .end = INT_UART3,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+static struct platform_device h2_irda_device = {
+ .name = "omapirda",
+ .id = 0,
+ .dev = {
+ .platform_data = &h2_irda_data,
+ },
+ .num_resources = ARRAY_SIZE(h2_irda_resources),
+ .resource = h2_irda_resources,
+};
+
+static struct platform_device h2_lcd_device = {
+ .name = "lcd_h2",
+ .id = -1,
+};
+
+static struct omap_mcbsp_reg_cfg mcbsp_regs = {
+ .spcr2 = FREE | FRST | GRST | XRST | XINTM(3),
+ .spcr1 = RINTM(3) | RRST,
+ .rcr2 = RPHASE | RFRLEN2(OMAP_MCBSP_WORD_8) |
+ RWDLEN2(OMAP_MCBSP_WORD_16) | RDATDLY(1),
+ .rcr1 = RFRLEN1(OMAP_MCBSP_WORD_8) | RWDLEN1(OMAP_MCBSP_WORD_16),
+ .xcr2 = XPHASE | XFRLEN2(OMAP_MCBSP_WORD_8) |
+ XWDLEN2(OMAP_MCBSP_WORD_16) | XDATDLY(1) | XFIG,
+ .xcr1 = XFRLEN1(OMAP_MCBSP_WORD_8) | XWDLEN1(OMAP_MCBSP_WORD_16),
+ .srgr1 = FWID(15),
+ .srgr2 = GSYNC | CLKSP | FSGM | FPER(31),
+
+ .pcr0 = CLKXM | CLKRM | FSXP | FSRP | CLKXP | CLKRP,
+ //.pcr0 = CLKXP | CLKRP, /* mcbsp: slave */
+};
+
+static struct omap_alsa_codec_config alsa_config = {
+ .name = "H2 TSC2101",
+ .mcbsp_regs_alsa = &mcbsp_regs,
+ .codec_configure_dev = NULL, // tsc2101_configure,
+ .codec_set_samplerate = NULL, // tsc2101_set_samplerate,
+ .codec_clock_setup = NULL, // tsc2101_clock_setup,
+ .codec_clock_on = NULL, // tsc2101_clock_on,
+ .codec_clock_off = NULL, // tsc2101_clock_off,
+ .get_default_samplerate = NULL, // tsc2101_get_default_samplerate,
+};
+
+static struct platform_device h2_mcbsp1_device = {
+ .name = "omap_alsa_mcbsp",
+ .id = 1,
+ .dev = {
+ .platform_data = &alsa_config,
+ },
+};
+
static struct platform_device *h2_devices[] __initdata = {
- &h2_flash_device,
+ &h2_nor_device,
&h2_smc91x_device,
+ &h2_irda_device,
+ &h2_kp_device,
+ &h2_lcd_device,
+ &h2_mcbsp1_device,
};
static void __init h2_init_smc91x(void)
@@ -164,7 +319,6 @@ static struct omap_uart_config h2_uart_config __initdata = {
};
static struct omap_lcd_config h2_lcd_config __initdata = {
- .panel_name = "h2",
.ctrl_name = "internal",
};
@@ -177,16 +331,34 @@ static struct omap_board_config_kernel h2_config[] = {
static void __init h2_init(void)
{
- /* NOTE: revC boards support NAND-boot, which can put NOR on CS2B
- * and NAND (either 16bit or 8bit) on CS3.
+ /* Here we assume the NOR boot config: NOR on CS3 (possibly swapped
+ * to address 0 by a dip switch), NAND on CS2B. The NAND driver will
+ * notice whether a NAND chip is enabled at probe time.
+ *
+ * FIXME revC boards (and H3) support NAND-boot, with a dip switch to
+ * put NOR on CS2B and NAND (which on H2 may be 16bit) on CS3. Try
+ * detecting that in code here, to avoid probing every possible flash
+ * configuration...
*/
- h2_flash_resource.end = h2_flash_resource.start = omap_cs3_phys();
- h2_flash_resource.end += SZ_32M - 1;
+ h2_nor_resource.end = h2_nor_resource.start = omap_cs3_phys();
+ h2_nor_resource.end += SZ_32M - 1;
+
+ omap_cfg_reg(L3_1610_FLASH_CS2B_OE);
+ omap_cfg_reg(M8_1610_FLASH_CS2B_WE);
/* MMC: card detect and WP */
// omap_cfg_reg(U19_ARMIO1); /* CD */
omap_cfg_reg(BALLOUT_V8_ARMIO3); /* WP */
+ /* Irda */
+#if defined(CONFIG_OMAP_IR) || defined(CONFIG_OMAP_IR_MODULE)
+ omap_writel(omap_readl(FUNC_MUX_CTRL_A) | 7, FUNC_MUX_CTRL_A);
+ if (!(omap_request_gpio(H2_IRDA_FIRSEL_GPIO_PIN))) {
+ omap_set_gpio_direction(H2_IRDA_FIRSEL_GPIO_PIN, 0);
+ h2_irda_data.transceiver_mode = h2_transceiver_mode;
+ }
+#endif
+
platform_add_devices(h2_devices, ARRAY_SIZE(h2_devices));
omap_board_config = h2_config;
omap_board_config_size = ARRAY_SIZE(h2_config);
diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c
index d9f38626599..4b8d0ec73cb 100644
--- a/arch/arm/mach-omap1/board-h3.c
+++ b/arch/arm/mach-omap1/board-h3.c
@@ -21,8 +21,11 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/errno.h>
+#include <linux/workqueue.h>
#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
+#include <linux/input.h>
#include <asm/setup.h>
#include <asm/page.h>
@@ -33,15 +36,59 @@
#include <asm/mach/map.h>
#include <asm/arch/gpio.h>
+#include <asm/arch/gpioexpander.h>
#include <asm/arch/irqs.h>
#include <asm/arch/mux.h>
#include <asm/arch/tc.h>
+#include <asm/arch/irda.h>
#include <asm/arch/usb.h>
+#include <asm/arch/keypad.h>
+#include <asm/arch/dma.h>
#include <asm/arch/common.h>
extern int omap_gpio_init(void);
-static struct mtd_partition h3_partitions[] = {
+static int h3_keymap[] = {
+ KEY(0, 0, KEY_LEFT),
+ KEY(0, 1, KEY_RIGHT),
+ KEY(0, 2, KEY_3),
+ KEY(0, 3, KEY_F10),
+ KEY(0, 4, KEY_F5),
+ KEY(0, 5, KEY_9),
+ KEY(1, 0, KEY_DOWN),
+ KEY(1, 1, KEY_UP),
+ KEY(1, 2, KEY_2),
+ KEY(1, 3, KEY_F9),
+ KEY(1, 4, KEY_F7),
+ KEY(1, 5, KEY_0),
+ KEY(2, 0, KEY_ENTER),
+ KEY(2, 1, KEY_6),
+ KEY(2, 2, KEY_1),
+ KEY(2, 3, KEY_F2),
+ KEY(2, 4, KEY_F6),
+ KEY(2, 5, KEY_HOME),
+ KEY(3, 0, KEY_8),
+ KEY(3, 1, KEY_5),
+ KEY(3, 2, KEY_F12),
+ KEY(3, 3, KEY_F3),
+ KEY(3, 4, KEY_F8),
+ KEY(3, 5, KEY_END),
+ KEY(4, 0, KEY_7),
+ KEY(4, 1, KEY_4),
+ KEY(4, 2, KEY_F11),
+ KEY(4, 3, KEY_F1),
+ KEY(4, 4, KEY_F4),
+ KEY(4, 5, KEY_ESC),
+ KEY(5, 0, KEY_F13),
+ KEY(5, 1, KEY_F14),
+ KEY(5, 2, KEY_F15),
+ KEY(5, 3, KEY_F16),
+ KEY(5, 4, KEY_SLEEP),
+ 0
+};
+
+
+static struct mtd_partition nor_partitions[] = {
/* bootloader (U-Boot, etc) in first sector */
{
.name = "bootloader",
@@ -72,26 +119,80 @@ static struct mtd_partition h3_partitions[] = {
}
};
-static struct flash_platform_data h3_flash_data = {
+static struct flash_platform_data nor_data = {
.map_name = "cfi_probe",
.width = 2,
- .parts = h3_partitions,
- .nr_parts = ARRAY_SIZE(h3_partitions),
+ .parts = nor_partitions,
+ .nr_parts = ARRAY_SIZE(nor_partitions),
};
-static struct resource h3_flash_resource = {
+static struct resource nor_resource = {
/* This is on CS3, wherever it's mapped */
.flags = IORESOURCE_MEM,
};
-static struct platform_device flash_device = {
+static struct platform_device nor_device = {
.name = "omapflash",
.id = 0,
.dev = {
- .platform_data = &h3_flash_data,
+ .platform_data = &nor_data,
+ },
+ .num_resources = 1,
+ .resource = &nor_resource,
+};
+
+static struct mtd_partition nand_partitions[] = {
+#if 0
+ /* REVISIT: enable these partitions if you make NAND BOOT work */
+ {
+ .name = "xloader",
+ .offset = 0,
+ .size = 64 * 1024,
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
+ },
+ {
+ .name = "bootloader",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 256 * 1024,
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
+ },
+ {
+ .name = "params",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 192 * 1024,
+ },
+ {
+ .name = "kernel",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 2 * SZ_1M,
+ },
+#endif
+ {
+ .name = "filesystem",
+ .size = MTDPART_SIZ_FULL,
+ .offset = MTDPART_OFS_APPEND,
+ },
+};
+
+/* dip switches control NAND chip access: 8 bit, 16 bit, or neither */
+static struct nand_platform_data nand_data = {
+ .options = NAND_SAMSUNG_LP_OPTIONS,
+ .parts = nand_partitions,
+ .nr_parts = ARRAY_SIZE(nand_partitions),
+};
+
+static struct resource nand_resource = {
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device nand_device = {
+ .name = "omapnand",
+ .id = 0,
+ .dev = {
+ .platform_data = &nand_data,
},
.num_resources = 1,
- .resource = &h3_flash_resource,
+ .resource = &nand_resource,
};
static struct resource smc91x_resources[] = {
@@ -138,10 +239,136 @@ static struct platform_device intlat_device = {
.resource = intlat_resources,
};
+static struct resource h3_kp_resources[] = {
+ [0] = {
+ .start = INT_KEYBOARD,
+ .end = INT_KEYBOARD,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct omap_kp_platform_data h3_kp_data = {
+ .rows = 8,
+ .cols = 8,
+ .keymap = h3_keymap,
+ .rep = 1,
+};
+
+static struct platform_device h3_kp_device = {
+ .name = "omap-keypad",
+ .id = -1,
+ .dev = {
+ .platform_data = &h3_kp_data,
+ },
+ .num_resources = ARRAY_SIZE(h3_kp_resources),
+ .resource = h3_kp_resources,
+};
+
+
+/* Select between the IrDA and aGPS module
+ */
+static int h3_select_irda(struct device *dev, int state)
+{
+ unsigned char expa;
+ int err = 0;
+
+ if ((err = read_gpio_expa(&expa, 0x26))) {
+ printk(KERN_ERR "Error reading from I/O EXPANDER \n");
+ return err;
+ }
+
+ /* 'P6' enable/disable IRDA_TX and IRDA_RX */
+ if (state & IR_SEL) { /* IrDA */
+ if ((err = write_gpio_expa(expa | 0x40, 0x26))) {
+ printk(KERN_ERR "Error writing to I/O EXPANDER \n");
+ return err;
+ }
+ } else {
+ if ((err = write_gpio_expa(expa & ~0x40, 0x26))) {
+ printk(KERN_ERR "Error writing to I/O EXPANDER \n");
+ return err;
+ }
+ }
+ return err;
+}
+
+static void set_trans_mode(void *data)
+{
+ int *mode = data;
+ unsigned char expa;
+ int err = 0;
+
+ if ((err = read_gpio_expa(&expa, 0x27)) != 0) {
+ printk(KERN_ERR "Error reading from I/O expander\n");
+ }
+
+ expa &= ~0x03;
+
+ if (*mode & IR_SIRMODE) {
+ expa |= 0x01;
+ } else { /* MIR/FIR */
+ expa |= 0x03;
+ }
+
+ if ((err = write_gpio_expa(expa, 0x27)) != 0) {
+ printk(KERN_ERR "Error writing to I/O expander\n");
+ }
+}
+
+static int h3_transceiver_mode(struct device *dev, int mode)
+{
+ struct omap_irda_config *irda_config = dev->platform_data;
+
+ cancel_delayed_work(&irda_config->gpio_expa);
+ PREPARE_WORK(&irda_config->gpio_expa, set_trans_mode, &mode);
+ schedule_work(&irda_config->gpio_expa);
+
+ return 0;
+}
+
+static struct omap_irda_config h3_irda_data = {
+ .transceiver_cap = IR_SIRMODE | IR_MIRMODE | IR_FIRMODE,
+ .transceiver_mode = h3_transceiver_mode,
+ .select_irda = h3_select_irda,
+ .rx_channel = OMAP_DMA_UART3_RX,
+ .tx_channel = OMAP_DMA_UART3_TX,
+ .dest_start = UART3_THR,
+ .src_start = UART3_RHR,
+ .tx_trigger = 0,
+ .rx_trigger = 0,
+};
+
+static struct resource h3_irda_resources[] = {
+ [0] = {
+ .start = INT_UART3,
+ .end = INT_UART3,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device h3_irda_device = {
+ .name = "omapirda",
+ .id = 0,
+ .dev = {
+ .platform_data = &h3_irda_data,
+ },
+ .num_resources = ARRAY_SIZE(h3_irda_resources),
+ .resource = h3_irda_resources,
+};
+
+static struct platform_device h3_lcd_device = {
+ .name = "lcd_h3",
+ .id = -1,
+};
+
static struct platform_device *devices[] __initdata = {
- &flash_device,
+ &nor_device,
+ &nand_device,
&smc91x_device,
&intlat_device,
+ &h3_irda_device,
+ &h3_kp_device,
+ &h3_lcd_device,
};
static struct omap_usb_config h3_usb_config __initdata = {
@@ -171,7 +398,6 @@ static struct omap_uart_config h3_uart_config __initdata = {
};
static struct omap_lcd_config h3_lcd_config __initdata = {
- .panel_name = "h3",
.ctrl_name = "internal",
};
@@ -182,11 +408,36 @@ static struct omap_board_config_kernel h3_config[] = {
{ OMAP_TAG_LCD, &h3_lcd_config },
};
+#define H3_NAND_RB_GPIO_PIN 10
+
+static int nand_dev_ready(struct nand_platform_data *data)
+{
+ return omap_get_gpio_datain(H3_NAND_RB_GPIO_PIN);
+}
+
static void __init h3_init(void)
{
- h3_flash_resource.end = h3_flash_resource.start = omap_cs3_phys();
- h3_flash_resource.end += OMAP_CS3_SIZE - 1;
- (void) platform_add_devices(devices, ARRAY_SIZE(devices));
+ /* Here we assume the NOR boot config: NOR on CS3 (possibly swapped
+ * to address 0 by a dip switch), NAND on CS2B. The NAND driver will
+ * notice whether a NAND chip is enabled at probe time.
+ *
+ * H3 support NAND-boot, with a dip switch to put NOR on CS2B and NAND
+ * (which on H2 may be 16bit) on CS3. Try detecting that in code here,
+ * to avoid probing every possible flash configuration...
+ */
+ nor_resource.end = nor_resource.start = omap_cs3_phys();
+ nor_resource.end += SZ_32M - 1;
+
+ nand_resource.end = nand_resource.start = OMAP_CS2B_PHYS;
+ nand_resource.end += SZ_4K - 1;
+ if (!(omap_request_gpio(H3_NAND_RB_GPIO_PIN)))
+ nand_data.dev_ready = nand_dev_ready;
+
+ /* GPIO10 Func_MUX_CTRL reg bit 29:27, Configure V2 to mode1 as GPIO */
+ /* GPIO10 pullup/down register, Enable pullup on GPIO10 */
+ omap_cfg_reg(V2_1710_GPIO10);
+
+ platform_add_devices(devices, ARRAY_SIZE(devices));
omap_board_config = h3_config;
omap_board_config_size = ARRAY_SIZE(h3_config);
omap_serial_init();
diff --git a/arch/arm/mach-omap1/board-innovator.c b/arch/arm/mach-omap1/board-innovator.c
index a04e4332915..e90c137a4cf 100644
--- a/arch/arm/mach-omap1/board-innovator.c
+++ b/arch/arm/mach-omap1/board-innovator.c
@@ -22,6 +22,7 @@
#include <linux/delay.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
+#include <linux/input.h>
#include <asm/hardware.h>
#include <asm/mach-types.h>
@@ -34,8 +35,22 @@
#include <asm/arch/gpio.h>
#include <asm/arch/tc.h>
#include <asm/arch/usb.h>
+#include <asm/arch/keypad.h>
#include <asm/arch/common.h>
+static int innovator_keymap[] = {
+ KEY(0, 0, KEY_F1),
+ KEY(0, 3, KEY_DOWN),
+ KEY(1, 1, KEY_F2),
+ KEY(1, 2, KEY_RIGHT),
+ KEY(2, 0, KEY_F3),
+ KEY(2, 1, KEY_F4),
+ KEY(2, 2, KEY_UP),
+ KEY(3, 2, KEY_ENTER),
+ KEY(3, 3, KEY_LEFT),
+ 0
+};
+
static struct mtd_partition innovator_partitions[] = {
/* bootloader (U-Boot, etc) in first sector */
{
@@ -97,6 +112,31 @@ static struct platform_device innovator_flash_device = {
.resource = &innovator_flash_resource,
};
+static struct resource innovator_kp_resources[] = {
+ [0] = {
+ .start = INT_KEYBOARD,
+ .end = INT_KEYBOARD,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct omap_kp_platform_data innovator_kp_data = {
+ .rows = 8,
+ .cols = 8,
+ .keymap = innovator_keymap,
+};
+
+static struct platform_device innovator_kp_device = {
+ .name = "omap-keypad",
+ .id = -1,
+ .dev = {
+ .platform_data = &innovator_kp_data,
+ },
+ .num_resources = ARRAY_SIZE(innovator_kp_resources),
+ .resource = innovator_kp_resources,
+};
+
+
#ifdef CONFIG_ARCH_OMAP15XX
/* Only FPGA needs to be mapped here. All others are done with ioremap */
@@ -129,9 +169,16 @@ static struct platform_device innovator1510_smc91x_device = {
.resource = innovator1510_smc91x_resources,
};
+static struct platform_device innovator1510_lcd_device = {
+ .name = "lcd_inn1510",
+ .id = -1,
+};
+
static struct platform_device *innovator1510_devices[] __initdata = {
&innovator_flash_device,
&innovator1510_smc91x_device,
+ &innovator_kp_device,
+ &innovator1510_lcd_device,
};
#endif /* CONFIG_ARCH_OMAP15XX */
@@ -158,9 +205,16 @@ static struct platform_device innovator1610_smc91x_device = {
.resource = innovator1610_smc91x_resources,
};
+static struct platform_device innovator1610_lcd_device = {
+ .name = "inn1610_lcd",
+ .id = -1,
+};
+
static struct platform_device *innovator1610_devices[] __initdata = {
&innovator_flash_device,
&innovator1610_smc91x_device,
+ &innovator_kp_device,
+ &innovator1610_lcd_device,
};
#endif /* CONFIG_ARCH_OMAP16XX */
@@ -206,7 +260,6 @@ static struct omap_usb_config innovator1510_usb_config __initdata = {
};
static struct omap_lcd_config innovator1510_lcd_config __initdata = {
- .panel_name = "inn1510",
.ctrl_name = "internal",
};
#endif
@@ -228,7 +281,6 @@ static struct omap_usb_config h2_usb_config __initdata = {
};
static struct omap_lcd_config innovator1610_lcd_config __initdata = {
- .panel_name = "inn1610",
.ctrl_name = "internal",
};
#endif
diff --git a/arch/arm/mach-omap1/board-netstar.c b/arch/arm/mach-omap1/board-netstar.c
deleted file mode 100644
index 7520e602d7a..00000000000
--- a/arch/arm/mach-omap1/board-netstar.c
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Modified from board-generic.c
- *
- * Copyright (C) 2004 2N Telekomunikace, Ladislav Michl <michl@2n.cz>
- *
- * Code for Netstar OMAP board.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/delay.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
-
-#include <asm/hardware.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-
-#include <asm/arch/gpio.h>
-#include <asm/arch/mux.h>
-#include <asm/arch/usb.h>
-#include <asm/arch/common.h>
-
-extern void __init omap_init_time(void);
-extern int omap_gpio_init(void);
-
-static struct resource netstar_smc91x_resources[] = {
- [0] = {
- .start = OMAP_CS1_PHYS + 0x300,
- .end = OMAP_CS1_PHYS + 0x300 + 16,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = OMAP_GPIO_IRQ(8),
- .end = OMAP_GPIO_IRQ(8),
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device netstar_smc91x_device = {
- .name = "smc91x",
- .id = 0,
- .num_resources = ARRAY_SIZE(netstar_smc91x_resources),
- .resource = netstar_smc91x_resources,
-};
-
-static struct platform_device *netstar_devices[] __initdata = {
- &netstar_smc91x_device,
-};
-
-static struct omap_uart_config netstar_uart_config __initdata = {
- .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
-};
-
-static struct omap_board_config_kernel netstar_config[] = {
- { OMAP_TAG_UART, &netstar_uart_config },
-};
-
-static void __init netstar_init_irq(void)
-{
- omap1_init_common_hw();
- omap_init_irq();
- omap_gpio_init();
-}
-
-static void __init netstar_init(void)
-{
- /* green LED */
- omap_request_gpio(4);
- omap_set_gpio_direction(4, 0);
- /* smc91x reset */
- omap_request_gpio(7);
- omap_set_gpio_direction(7, 0);
- omap_set_gpio_dataout(7, 1);
- udelay(2); /* wait at least 100ns */
- omap_set_gpio_dataout(7, 0);
- mdelay(50); /* 50ms until PHY ready */
- /* smc91x interrupt pin */
- omap_request_gpio(8);
-
- omap_request_gpio(12);
- omap_request_gpio(13);
- omap_request_gpio(14);
- omap_request_gpio(15);
- set_irq_type(OMAP_GPIO_IRQ(12), IRQT_FALLING);
- set_irq_type(OMAP_GPIO_IRQ(13), IRQT_FALLING);
- set_irq_type(OMAP_GPIO_IRQ(14), IRQT_FALLING);
- set_irq_type(OMAP_GPIO_IRQ(15), IRQT_FALLING);
-
- platform_add_devices(netstar_devices, ARRAY_SIZE(netstar_devices));
-
- /* Switch on green LED */
- omap_set_gpio_dataout(4, 0);
- /* Switch off red LED */
- omap_writeb(0x00, OMAP_LPG1_PMR); /* Disable clock */
- omap_writeb(0x80, OMAP_LPG1_LCR);
-
- omap_board_config = netstar_config;
- omap_board_config_size = ARRAY_SIZE(netstar_config);
- omap_serial_init();
-}
-
-static void __init netstar_map_io(void)
-{
- omap1_map_common_io();
-}
-
-#define MACHINE_PANICED 1
-#define MACHINE_REBOOTING 2
-#define MACHINE_REBOOT 4
-static unsigned long machine_state;
-
-static int panic_event(struct notifier_block *this, unsigned long event,
- void *ptr)
-{
- if (test_and_set_bit(MACHINE_PANICED, &machine_state))
- return NOTIFY_DONE;
-
- /* Switch off green LED */
- omap_set_gpio_dataout(4, 1);
- /* Flash red LED */
- omap_writeb(0x78, OMAP_LPG1_LCR);
- omap_writeb(0x01, OMAP_LPG1_PMR); /* Enable clock */
-
- return NOTIFY_DONE;
-}
-
-static struct notifier_block panic_block = {
- .notifier_call = panic_event,
-};
-
-static int __init netstar_late_init(void)
-{
- /* TODO: Setup front panel switch here */
-
- /* Setup panic notifier */
- atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
-
- return 0;
-}
-
-postcore_initcall(netstar_late_init);
-
-MACHINE_START(NETSTAR, "NetStar OMAP5910")
- /* Maintainer: Ladislav Michl <michl@2n.cz> */
- .phys_io = 0xfff00000,
- .io_pg_offst = ((0xfef00000) >> 18) & 0xfffc,
- .boot_params = 0x10000100,
- .map_io = netstar_map_io,
- .init_irq = netstar_init_irq,
- .init_machine = netstar_init,
- .timer = &omap_timer,
-MACHINE_END
diff --git a/arch/arm/mach-omap1/board-nokia770.c b/arch/arm/mach-omap1/board-nokia770.c
new file mode 100644
index 00000000000..02b980d77b1
--- /dev/null
+++ b/arch/arm/mach-omap1/board-nokia770.c
@@ -0,0 +1,268 @@
+/*
+ * linux/arch/arm/mach-omap1/board-nokia770.c
+ *
+ * Modified from board-generic.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/clk.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/ads7846.h>
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/usb.h>
+#include <asm/arch/board.h>
+#include <asm/arch/keypad.h>
+#include <asm/arch/common.h>
+#include <asm/arch/dsp_common.h>
+#include <asm/arch/aic23.h>
+#include <asm/arch/gpio.h>
+
+static void __init omap_nokia770_init_irq(void)
+{
+ /* On Nokia 770, the SleepX signal is masked with an
+ * MPUIO line by default. It has to be unmasked for it
+ * to become functional */
+
+ /* SleepX mask direction */
+ omap_writew((omap_readw(0xfffb5008) & ~2), 0xfffb5008);
+ /* Unmask SleepX signal */
+ omap_writew((omap_readw(0xfffb5004) & ~2), 0xfffb5004);
+
+ omap1_init_common_hw();
+ omap_init_irq();
+}
+
+static int nokia770_keymap[] = {
+ KEY(0, 1, GROUP_0 | KEY_UP),
+ KEY(0, 2, GROUP_1 | KEY_F5),
+ KEY(1, 0, GROUP_0 | KEY_LEFT),
+ KEY(1, 1, GROUP_0 | KEY_ENTER),
+ KEY(1, 2, GROUP_0 | KEY_RIGHT),
+ KEY(2, 0, GROUP_1 | KEY_ESC),
+ KEY(2, 1, GROUP_0 | KEY_DOWN),
+ KEY(2, 2, GROUP_1 | KEY_F4),
+ KEY(3, 0, GROUP_2 | KEY_F7),
+ KEY(3, 1, GROUP_2 | KEY_F8),
+ KEY(3, 2, GROUP_2 | KEY_F6),
+ 0
+};
+
+static struct resource nokia770_kp_resources[] = {
+ [0] = {
+ .start = INT_KEYBOARD,
+ .end = INT_KEYBOARD,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct omap_kp_platform_data nokia770_kp_data = {
+ .rows = 8,
+ .cols = 8,
+ .keymap = nokia770_keymap
+};
+
+static struct platform_device nokia770_kp_device = {
+ .name = "omap-keypad",
+ .id = -1,
+ .dev = {
+ .platform_data = &nokia770_kp_data,
+ },
+ .num_resources = ARRAY_SIZE(nokia770_kp_resources),
+ .resource = nokia770_kp_resources,
+};
+
+static struct platform_device *nokia770_devices[] __initdata = {
+ &nokia770_kp_device,
+};
+
+static struct ads7846_platform_data nokia770_ads7846_platform_data __initdata = {
+ .x_max = 0x0fff,
+ .y_max = 0x0fff,
+ .x_plate_ohms = 180,
+ .pressure_max = 255,
+ .debounce_max = 10,
+ .debounce_tol = 3,
+};
+
+static struct spi_board_info nokia770_spi_board_info[] __initdata = {
+ [0] = {
+ .modalias = "lcd_lph8923",
+ .bus_num = 2,
+ .chip_select = 3,
+ .max_speed_hz = 12000000,
+ },
+ [1] = {
+ .modalias = "ads7846",
+ .bus_num = 2,
+ .chip_select = 0,
+ .max_speed_hz = 2500000,
+ .irq = OMAP_GPIO_IRQ(15),
+ .platform_data = &nokia770_ads7846_platform_data,
+ },
+};
+
+
+/* assume no Mini-AB port */
+
+static struct omap_usb_config nokia770_usb_config __initdata = {
+ .otg = 1,
+ .register_host = 1,
+ .register_dev = 1,
+ .hmc_mode = 16,
+ .pins[0] = 6,
+};
+
+static struct omap_mmc_config nokia770_mmc_config __initdata = {
+ .mmc[0] = {
+ .enabled = 0,
+ .wire4 = 0,
+ .wp_pin = -1,
+ .power_pin = -1,
+ .switch_pin = -1,
+ },
+ .mmc[1] = {
+ .enabled = 0,
+ .wire4 = 0,
+ .wp_pin = -1,
+ .power_pin = -1,
+ .switch_pin = -1,
+ },
+};
+
+static struct omap_board_config_kernel nokia770_config[] = {
+ { OMAP_TAG_USB, NULL },
+ { OMAP_TAG_MMC, &nokia770_mmc_config },
+};
+
+/*
+ * audio power control
+ */
+#define HEADPHONE_GPIO 14
+#define AMPLIFIER_CTRL_GPIO 58
+
+static struct clk *dspxor_ck;
+static DECLARE_MUTEX(audio_pwr_sem);
+/*
+ * audio_pwr_state
+ * +--+-------------------------+---------------------------------------+
+ * |-1|down |power-up request -> 0 |
+ * +--+-------------------------+---------------------------------------+
+ * | 0|up |power-down(1) request -> 1 |
+ * | | |power-down(2) request -> (ignore) |
+ * +--+-------------------------+---------------------------------------+
+ * | 1|up, |power-up request -> 0 |
+ * | |received down(1) request |power-down(2) request -> -1 |
+ * +--+-------------------------+---------------------------------------+
+ */
+static int audio_pwr_state = -1;
+
+/*
+ * audio_pwr_up / down should be called under audio_pwr_sem
+ */
+static void nokia770_audio_pwr_up(void)
+{
+ clk_enable(dspxor_ck);
+
+ /* Turn on codec */
+ tlv320aic23_power_up();
+
+ if (omap_get_gpio_datain(HEADPHONE_GPIO))
+ /* HP not connected, turn on amplifier */
+ omap_set_gpio_dataout(AMPLIFIER_CTRL_GPIO, 1);
+ else
+ /* HP connected, do not turn on amplifier */
+ printk("HP connected\n");
+}
+
+static void codec_delayed_power_down(void *arg)
+{
+ down(&audio_pwr_sem);
+ if (audio_pwr_state == -1)
+ tlv320aic23_power_down();
+ clk_disable(dspxor_ck);
+ up(&audio_pwr_sem);
+}
+
+static DECLARE_WORK(codec_power_down_work, codec_delayed_power_down, NULL);
+
+static void nokia770_audio_pwr_down(void)
+{
+ /* Turn off amplifier */
+ omap_set_gpio_dataout(AMPLIFIER_CTRL_GPIO, 0);
+
+ /* Turn off codec: schedule delayed work */
+ schedule_delayed_work(&codec_power_down_work, HZ / 20); /* 50ms */
+}
+
+void nokia770_audio_pwr_up_request(int stage)
+{
+ down(&audio_pwr_sem);
+ if (audio_pwr_state == -1)
+ nokia770_audio_pwr_up();
+ /* force audio_pwr_state = 0, even if it was 1. */
+ audio_pwr_state = 0;
+ up(&audio_pwr_sem);
+}
+
+void nokia770_audio_pwr_down_request(int stage)
+{
+ down(&audio_pwr_sem);
+ switch (stage) {
+ case 1:
+ if (audio_pwr_state == 0)
+ audio_pwr_state = 1;
+ break;
+ case 2:
+ if (audio_pwr_state == 1) {
+ nokia770_audio_pwr_down();
+ audio_pwr_state = -1;
+ }
+ break;
+ }
+ up(&audio_pwr_sem);
+}
+
+static void __init omap_nokia770_init(void)
+{
+ nokia770_config[0].data = &nokia770_usb_config;
+
+ platform_add_devices(nokia770_devices, ARRAY_SIZE(nokia770_devices));
+ spi_register_board_info(nokia770_spi_board_info,
+ ARRAY_SIZE(nokia770_spi_board_info));
+ omap_board_config = nokia770_config;
+ omap_board_config_size = ARRAY_SIZE(nokia770_config);
+ omap_serial_init();
+ omap_dsp_audio_pwr_up_request = nokia770_audio_pwr_up_request;
+ omap_dsp_audio_pwr_down_request = nokia770_audio_pwr_down_request;
+ dspxor_ck = clk_get(0, "dspxor_ck");
+}
+
+static void __init omap_nokia770_map_io(void)
+{
+ omap1_map_common_io();
+}
+
+MACHINE_START(NOKIA770, "Nokia 770")
+ .phys_io = 0xfff00000,
+ .io_pg_offst = ((0xfef00000) >> 18) & 0xfffc,
+ .boot_params = 0x10000100,
+ .map_io = omap_nokia770_map_io,
+ .init_irq = omap_nokia770_init_irq,
+ .init_machine = omap_nokia770_init,
+ .timer = &omap_timer,
+MACHINE_END
diff --git a/arch/arm/mach-omap1/board-osk.c b/arch/arm/mach-omap1/board-osk.c
index 543fa136106..1160093e8ef 100644
--- a/arch/arm/mach-omap1/board-osk.c
+++ b/arch/arm/mach-omap1/board-osk.c
@@ -33,6 +33,7 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
+#include <linux/input.h>
#include <asm/hardware.h>
#include <asm/mach-types.h>
@@ -44,7 +45,24 @@
#include <asm/arch/usb.h>
#include <asm/arch/mux.h>
#include <asm/arch/tc.h>
+#include <asm/arch/keypad.h>
#include <asm/arch/common.h>
+#include <asm/arch/mcbsp.h>
+#include <asm/arch/omap-alsa.h>
+
+static int osk_keymap[] = {
+ KEY(0, 0, KEY_F1),
+ KEY(0, 3, KEY_UP),
+ KEY(1, 1, KEY_LEFTCTRL),
+ KEY(1, 2, KEY_LEFT),
+ KEY(2, 0, KEY_SPACE),
+ KEY(2, 1, KEY_ESC),
+ KEY(2, 2, KEY_DOWN),
+ KEY(3, 2, KEY_ENTER),
+ KEY(3, 3, KEY_RIGHT),
+ 0
+};
+
static struct mtd_partition osk_partitions[] = {
/* bootloader (U-Boot, etc) in first sector */
@@ -133,9 +151,69 @@ static struct platform_device osk5912_cf_device = {
.resource = osk5912_cf_resources,
};
+#define DEFAULT_BITPERSAMPLE 16
+
+static struct omap_mcbsp_reg_cfg mcbsp_regs = {
+ .spcr2 = FREE | FRST | GRST | XRST | XINTM(3),
+ .spcr1 = RINTM(3) | RRST,
+ .rcr2 = RPHASE | RFRLEN2(OMAP_MCBSP_WORD_8) |
+ RWDLEN2(OMAP_MCBSP_WORD_16) | RDATDLY(0),
+ .rcr1 = RFRLEN1(OMAP_MCBSP_WORD_8) | RWDLEN1(OMAP_MCBSP_WORD_16),
+ .xcr2 = XPHASE | XFRLEN2(OMAP_MCBSP_WORD_8) |
+ XWDLEN2(OMAP_MCBSP_WORD_16) | XDATDLY(0) | XFIG,
+ .xcr1 = XFRLEN1(OMAP_MCBSP_WORD_8) | XWDLEN1(OMAP_MCBSP_WORD_16),
+ .srgr1 = FWID(DEFAULT_BITPERSAMPLE - 1),
+ .srgr2 = GSYNC | CLKSP | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1),
+ /*.pcr0 = FSXM | FSRM | CLKXM | CLKRM | CLKXP | CLKRP,*/ /* mcbsp: master */
+ .pcr0 = CLKXP | CLKRP, /* mcbsp: slave */
+};
+
+static struct omap_alsa_codec_config alsa_config = {
+ .name = "OSK AIC23",
+ .mcbsp_regs_alsa = &mcbsp_regs,
+ .codec_configure_dev = NULL, // aic23_configure,
+ .codec_set_samplerate = NULL, // aic23_set_samplerate,
+ .codec_clock_setup = NULL, // aic23_clock_setup,
+ .codec_clock_on = NULL, // aic23_clock_on,
+ .codec_clock_off = NULL, // aic23_clock_off,
+ .get_default_samplerate = NULL, // aic23_get_default_samplerate,
+};
+
static struct platform_device osk5912_mcbsp1_device = {
- .name = "omap_mcbsp",
- .id = 1,
+ .name = "omap_alsa_mcbsp",
+ .id = 1,
+ .dev = {
+ .platform_data = &alsa_config,
+ },
+};
+
+static struct resource osk5912_kp_resources[] = {
+ [0] = {
+ .start = INT_KEYBOARD,
+ .end = INT_KEYBOARD,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct omap_kp_platform_data osk_kp_data = {
+ .rows = 8,
+ .cols = 8,
+ .keymap = osk_keymap,
+};
+
+static struct platform_device osk5912_kp_device = {
+ .name = "omap-keypad",
+ .id = -1,
+ .dev = {
+ .platform_data = &osk_kp_data,
+ },
+ .num_resources = ARRAY_SIZE(osk5912_kp_resources),
+ .resource = osk5912_kp_resources,
+};
+
+static struct platform_device osk5912_lcd_device = {
+ .name = "lcd_osk",
+ .id = -1,
};
static struct platform_device *osk5912_devices[] __initdata = {
@@ -143,6 +221,8 @@ static struct platform_device *osk5912_devices[] __initdata = {
&osk5912_smc91x_device,
&osk5912_cf_device,
&osk5912_mcbsp1_device,
+ &osk5912_kp_device,
+ &osk5912_lcd_device,
};
static void __init osk_init_smc91x(void)
@@ -197,7 +277,6 @@ static struct omap_uart_config osk_uart_config __initdata = {
};
static struct omap_lcd_config osk_lcd_config __initdata = {
- .panel_name = "osk",
.ctrl_name = "internal",
};
@@ -255,8 +334,18 @@ static void __init osk_mistral_init(void)
static void __init osk_mistral_init(void) { }
#endif
+#define EMIFS_CS3_VAL (0x88013141)
+
static void __init osk_init(void)
{
+ /* Workaround for wrong CS3 (NOR flash) timing
+ * There are some U-Boot versions out there which configure
+ * wrong CS3 memory timings. This mainly leads to CRC
+ * or similiar errors if you use NOR flash (e.g. with JFFS2)
+ */
+ if (EMIFS_CCS(3) != EMIFS_CS3_VAL)
+ EMIFS_CCS(3) = EMIFS_CS3_VAL;
+
osk_flash_resource.end = osk_flash_resource.start = omap_cs3_phys();
osk_flash_resource.end += SZ_32M - 1;
platform_add_devices(osk5912_devices, ARRAY_SIZE(osk5912_devices));
diff --git a/arch/arm/mach-omap1/board-palmte.c b/arch/arm/mach-omap1/board-palmte.c
index e488f723677..4bc8a62909b 100644
--- a/arch/arm/mach-omap1/board-palmte.c
+++ b/arch/arm/mach-omap1/board-palmte.c
@@ -38,6 +38,15 @@ static void __init omap_generic_init_irq(void)
omap_init_irq();
}
+static struct platform_device palmte_lcd_device = {
+ .name = "lcd_palmte",
+ .id = -1,
+};
+
+static struct platform_device *devices[] __initdata = {
+ &palmte_lcd_device,
+};
+
static struct omap_usb_config palmte_usb_config __initdata = {
.register_dev = 1,
.hmc_mode = 0,
@@ -55,7 +64,6 @@ static struct omap_mmc_config palmte_mmc_config __initdata = {
};
static struct omap_lcd_config palmte_lcd_config __initdata = {
- .panel_name = "palmte",
.ctrl_name = "internal",
};
@@ -69,6 +77,8 @@ static void __init omap_generic_init(void)
{
omap_board_config = palmte_config;
omap_board_config_size = ARRAY_SIZE(palmte_config);
+
+ platform_add_devices(devices, ARRAY_SIZE(devices));
}
static void __init omap_generic_map_io(void)
diff --git a/arch/arm/mach-omap1/board-perseus2.c b/arch/arm/mach-omap1/board-perseus2.c
index 3913a3cc0ce..64b45d8ae35 100644
--- a/arch/arm/mach-omap1/board-perseus2.c
+++ b/arch/arm/mach-omap1/board-perseus2.c
@@ -16,7 +16,9 @@
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
+#include <linux/input.h>
#include <asm/hardware.h>
#include <asm/mach-types.h>
@@ -28,9 +30,44 @@
#include <asm/arch/gpio.h>
#include <asm/arch/mux.h>
#include <asm/arch/fpga.h>
+#include <asm/arch/keypad.h>
#include <asm/arch/common.h>
#include <asm/arch/board.h>
+static int p2_keymap[] = {
+ KEY(0,0,KEY_UP),
+ KEY(0,1,KEY_RIGHT),
+ KEY(0,2,KEY_LEFT),
+ KEY(0,3,KEY_DOWN),
+ KEY(0,4,KEY_CENTER),
+ KEY(0,5,KEY_0_5),
+ KEY(1,0,KEY_SOFT2),
+ KEY(1,1,KEY_SEND),
+ KEY(1,2,KEY_END),
+ KEY(1,3,KEY_VOLUMEDOWN),
+ KEY(1,4,KEY_VOLUMEUP),
+ KEY(1,5,KEY_RECORD),
+ KEY(2,0,KEY_SOFT1),
+ KEY(2,1,KEY_3),
+ KEY(2,2,KEY_6),
+ KEY(2,3,KEY_9),
+ KEY(2,4,KEY_SHARP),
+ KEY(2,5,KEY_2_5),
+ KEY(3,0,KEY_BACK),
+ KEY(3,1,KEY_2),
+ KEY(3,2,KEY_5),
+ KEY(3,3,KEY_8),
+ KEY(3,4,KEY_0),
+ KEY(3,5,KEY_HEADSETHOOK),
+ KEY(4,0,KEY_HOME),
+ KEY(4,1,KEY_1),
+ KEY(4,2,KEY_4),
+ KEY(4,3,KEY_7),
+ KEY(4,4,KEY_STAR),
+ KEY(4,5,KEY_POWER),
+ 0
+};
+
static struct resource smc91x_resources[] = {
[0] = {
.start = H2P2_DBG_FPGA_ETHR_START, /* Physical */
@@ -44,7 +81,7 @@ static struct resource smc91x_resources[] = {
},
};
-static struct mtd_partition p2_partitions[] = {
+static struct mtd_partition nor_partitions[] = {
/* bootloader (U-Boot, etc) in first sector */
{
.name = "bootloader",
@@ -75,27 +112,47 @@ static struct mtd_partition p2_partitions[] = {
},
};
-static struct flash_platform_data p2_flash_data = {
+static struct flash_platform_data nor_data = {
.map_name = "cfi_probe",
.width = 2,
- .parts = p2_partitions,
- .nr_parts = ARRAY_SIZE(p2_partitions),
+ .parts = nor_partitions,
+ .nr_parts = ARRAY_SIZE(nor_partitions),
};
-static struct resource p2_flash_resource = {
+static struct resource nor_resource = {
.start = OMAP_CS0_PHYS,
.end = OMAP_CS0_PHYS + SZ_32M - 1,
.flags = IORESOURCE_MEM,
};
-static struct platform_device p2_flash_device = {
+static struct platform_device nor_device = {
.name = "omapflash",
.id = 0,
.dev = {
- .platform_data = &p2_flash_data,
+ .platform_data = &nor_data,
+ },
+ .num_resources = 1,
+ .resource = &nor_resource,
+};
+
+static struct nand_platform_data nand_data = {
+ .options = NAND_SAMSUNG_LP_OPTIONS,
+};
+
+static struct resource nand_resource = {
+ .start = OMAP_CS3_PHYS,
+ .end = OMAP_CS3_PHYS + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device nand_device = {
+ .name = "omapnand",
+ .id = 0,
+ .dev = {
+ .platform_data = &nand_data,
},
.num_resources = 1,
- .resource = &p2_flash_resource,
+ .resource = &nand_resource,
};
static struct platform_device smc91x_device = {
@@ -105,17 +162,55 @@ static struct platform_device smc91x_device = {
.resource = smc91x_resources,
};
+static struct resource kp_resources[] = {
+ [0] = {
+ .start = INT_730_MPUIO_KEYPAD,
+ .end = INT_730_MPUIO_KEYPAD,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct omap_kp_platform_data kp_data = {
+ .rows = 8,
+ .cols = 8,
+ .keymap = p2_keymap,
+};
+
+static struct platform_device kp_device = {
+ .name = "omap-keypad",
+ .id = -1,
+ .dev = {
+ .platform_data = &kp_data,
+ },
+ .num_resources = ARRAY_SIZE(kp_resources),
+ .resource = kp_resources,
+};
+
+static struct platform_device lcd_device = {
+ .name = "lcd_p2",
+ .id = -1,
+};
+
static struct platform_device *devices[] __initdata = {
- &p2_flash_device,
+ &nor_device,
+ &nand_device,
&smc91x_device,
+ &kp_device,
+ &lcd_device,
};
+#define P2_NAND_RB_GPIO_PIN 62
+
+static int nand_dev_ready(struct nand_platform_data *data)
+{
+ return omap_get_gpio_datain(P2_NAND_RB_GPIO_PIN);
+}
+
static struct omap_uart_config perseus2_uart_config __initdata = {
.enabled_uarts = ((1 << 0) | (1 << 1)),
};
static struct omap_lcd_config perseus2_lcd_config __initdata = {
- .panel_name = "p2",
.ctrl_name = "internal",
};
@@ -126,7 +221,13 @@ static struct omap_board_config_kernel perseus2_config[] = {
static void __init omap_perseus2_init(void)
{
- (void) platform_add_devices(devices, ARRAY_SIZE(devices));
+ if (!(omap_request_gpio(P2_NAND_RB_GPIO_PIN)))
+ nand_data.dev_ready = nand_dev_ready;
+
+ omap_cfg_reg(L3_1610_FLASH_CS2B_OE);
+ omap_cfg_reg(M8_1610_FLASH_CS2B_WE);
+
+ platform_add_devices(devices, ARRAY_SIZE(devices));
omap_board_config = perseus2_config;
omap_board_config_size = ARRAY_SIZE(perseus2_config);
diff --git a/arch/arm/mach-omap1/board-voiceblue.c b/arch/arm/mach-omap1/board-voiceblue.c
index 52e4a9d6964..447a586eb33 100644
--- a/arch/arm/mach-omap1/board-voiceblue.c
+++ b/arch/arm/mach-omap1/board-voiceblue.c
@@ -155,9 +155,9 @@ static struct omap_uart_config voiceblue_uart_config __initdata = {
};
static struct omap_board_config_kernel voiceblue_config[] = {
- { OMAP_TAG_USB, &voiceblue_usb_config },
- { OMAP_TAG_MMC, &voiceblue_mmc_config },
- { OMAP_TAG_UART, &voiceblue_uart_config },
+ { OMAP_TAG_USB, &voiceblue_usb_config },
+ { OMAP_TAG_MMC, &voiceblue_mmc_config },
+ { OMAP_TAG_UART, &voiceblue_uart_config },
};
static void __init voiceblue_init_irq(void)
@@ -235,7 +235,7 @@ static struct notifier_block panic_block = {
static int __init voiceblue_setup(void)
{
/* Setup panic notifier */
- atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
+ notifier_chain_register(&panic_notifier_list, &panic_block);
return 0;
}
diff --git a/arch/arm/mach-omap1/clock.c b/arch/arm/mach-omap1/clock.c
index 75110ba1042..619db18144e 100644
--- a/arch/arm/mach-omap1/clock.c
+++ b/arch/arm/mach-omap1/clock.c
@@ -345,7 +345,7 @@ static unsigned calc_ext_dsor(unsigned long rate)
*/
for (dsor = 2; dsor < 96; ++dsor) {
if ((dsor & 1) && dsor > 8)
- continue;
+ continue;
if (rate >= 96000000 / dsor)
break;
}
@@ -687,6 +687,11 @@ int __init omap1_clk_init(void)
clk_register(*clkp);
continue;
}
+
+ if (((*clkp)->flags &CLOCK_IN_OMAP310) && cpu_is_omap310()) {
+ clk_register(*clkp);
+ continue;
+ }
}
info = omap_get_config(OMAP_TAG_CLOCK, struct omap_clock_config);
@@ -784,7 +789,7 @@ int __init omap1_clk_init(void)
clk_enable(&armxor_ck.clk);
clk_enable(&armtim_ck.clk); /* This should be done by timer code */
- if (cpu_is_omap1510())
+ if (cpu_is_omap15xx())
clk_enable(&arm_gpio_ck);
return 0;
diff --git a/arch/arm/mach-omap1/clock.h b/arch/arm/mach-omap1/clock.h
index 4f18d1b9444..b7c68819c4e 100644
--- a/arch/arm/mach-omap1/clock.h
+++ b/arch/arm/mach-omap1/clock.h
@@ -151,7 +151,7 @@ static struct clk ck_ref = {
.name = "ck_ref",
.rate = 12000000,
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- ALWAYS_ENABLED,
+ CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
.enable = &omap1_clk_enable_generic,
.disable = &omap1_clk_disable_generic,
};
@@ -160,7 +160,7 @@ static struct clk ck_dpll1 = {
.name = "ck_dpll1",
.parent = &ck_ref,
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- RATE_PROPAGATES | ALWAYS_ENABLED,
+ CLOCK_IN_OMAP310 | RATE_PROPAGATES | ALWAYS_ENABLED,
.enable = &omap1_clk_enable_generic,
.disable = &omap1_clk_disable_generic,
};
@@ -183,7 +183,8 @@ static struct clk arm_ck = {
.name = "arm_ck",
.parent = &ck_dpll1,
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- RATE_CKCTL | RATE_PROPAGATES | ALWAYS_ENABLED,
+ CLOCK_IN_OMAP310 | RATE_CKCTL | RATE_PROPAGATES |
+ ALWAYS_ENABLED,
.rate_offset = CKCTL_ARMDIV_OFFSET,
.recalc = &omap1_ckctl_recalc,
.enable = &omap1_clk_enable_generic,
@@ -195,7 +196,8 @@ static struct arm_idlect1_clk armper_ck = {
.name = "armper_ck",
.parent = &ck_dpll1,
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- RATE_CKCTL | CLOCK_IDLE_CONTROL,
+ CLOCK_IN_OMAP310 | RATE_CKCTL |
+ CLOCK_IDLE_CONTROL,
.enable_reg = (void __iomem *)ARM_IDLECT2,
.enable_bit = EN_PERCK,
.rate_offset = CKCTL_PERDIV_OFFSET,
@@ -209,7 +211,7 @@ static struct arm_idlect1_clk armper_ck = {
static struct clk arm_gpio_ck = {
.name = "arm_gpio_ck",
.parent = &ck_dpll1,
- .flags = CLOCK_IN_OMAP1510,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
.enable_reg = (void __iomem *)ARM_IDLECT2,
.enable_bit = EN_GPIOCK,
.recalc = &followparent_recalc,
@@ -222,7 +224,7 @@ static struct arm_idlect1_clk armxor_ck = {
.name = "armxor_ck",
.parent = &ck_ref,
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- CLOCK_IDLE_CONTROL,
+ CLOCK_IN_OMAP310 | CLOCK_IDLE_CONTROL,
.enable_reg = (void __iomem *)ARM_IDLECT2,
.enable_bit = EN_XORPCK,
.recalc = &followparent_recalc,
@@ -237,7 +239,7 @@ static struct arm_idlect1_clk armtim_ck = {
.name = "armtim_ck",
.parent = &ck_ref,
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- CLOCK_IDLE_CONTROL,
+ CLOCK_IN_OMAP310 | CLOCK_IDLE_CONTROL,
.enable_reg = (void __iomem *)ARM_IDLECT2,
.enable_bit = EN_TIMCK,
.recalc = &followparent_recalc,
@@ -252,7 +254,7 @@ static struct arm_idlect1_clk armwdt_ck = {
.name = "armwdt_ck",
.parent = &ck_ref,
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- CLOCK_IDLE_CONTROL,
+ CLOCK_IN_OMAP310 | CLOCK_IDLE_CONTROL,
.enable_reg = (void __iomem *)ARM_IDLECT2,
.enable_bit = EN_WDTCK,
.recalc = &omap1_watchdog_recalc,
@@ -344,9 +346,9 @@ static struct arm_idlect1_clk tc_ck = {
.name = "tc_ck",
.parent = &ck_dpll1,
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- CLOCK_IN_OMAP730 | RATE_CKCTL |
- RATE_PROPAGATES | ALWAYS_ENABLED |
- CLOCK_IDLE_CONTROL,
+ CLOCK_IN_OMAP730 | CLOCK_IN_OMAP310 |
+ RATE_CKCTL | RATE_PROPAGATES |
+ ALWAYS_ENABLED | CLOCK_IDLE_CONTROL,
.rate_offset = CKCTL_TCDIV_OFFSET,
.recalc = &omap1_ckctl_recalc,
.enable = &omap1_clk_enable_generic,
@@ -358,7 +360,8 @@ static struct arm_idlect1_clk tc_ck = {
static struct clk arminth_ck1510 = {
.name = "arminth_ck",
.parent = &tc_ck.clk,
- .flags = CLOCK_IN_OMAP1510 | ALWAYS_ENABLED,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 |
+ ALWAYS_ENABLED,
.recalc = &followparent_recalc,
/* Note: On 1510 the frequency follows TC_CK
*
@@ -372,7 +375,8 @@ static struct clk tipb_ck = {
/* No-idle controlled by "tc_ck" */
.name = "tibp_ck",
.parent = &tc_ck.clk,
- .flags = CLOCK_IN_OMAP1510 | ALWAYS_ENABLED,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 |
+ ALWAYS_ENABLED,
.recalc = &followparent_recalc,
.enable = &omap1_clk_enable_generic,
.disable = &omap1_clk_disable_generic,
@@ -417,7 +421,7 @@ static struct clk dma_ck = {
.name = "dma_ck",
.parent = &tc_ck.clk,
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- ALWAYS_ENABLED,
+ CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
.recalc = &followparent_recalc,
.enable = &omap1_clk_enable_generic,
.disable = &omap1_clk_disable_generic,
@@ -437,7 +441,7 @@ static struct arm_idlect1_clk api_ck = {
.name = "api_ck",
.parent = &tc_ck.clk,
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- CLOCK_IDLE_CONTROL,
+ CLOCK_IN_OMAP310 | CLOCK_IDLE_CONTROL,
.enable_reg = (void __iomem *)ARM_IDLECT2,
.enable_bit = EN_APICK,
.recalc = &followparent_recalc,
@@ -451,7 +455,8 @@ static struct arm_idlect1_clk lb_ck = {
.clk = {
.name = "lb_ck",
.parent = &tc_ck.clk,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IDLE_CONTROL,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 |
+ CLOCK_IDLE_CONTROL,
.enable_reg = (void __iomem *)ARM_IDLECT2,
.enable_bit = EN_LBCK,
.recalc = &followparent_recalc,
@@ -495,8 +500,8 @@ static struct arm_idlect1_clk lcd_ck_1510 = {
.clk = {
.name = "lcd_ck",
.parent = &ck_dpll1,
- .flags = CLOCK_IN_OMAP1510 | RATE_CKCTL |
- CLOCK_IDLE_CONTROL,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 |
+ RATE_CKCTL | CLOCK_IDLE_CONTROL,
.enable_reg = (void __iomem *)ARM_IDLECT2,
.enable_bit = EN_LCDCK,
.rate_offset = CKCTL_LCDDIV_OFFSET,
@@ -512,8 +517,9 @@ static struct clk uart1_1510 = {
/* Direct from ULPD, no real parent */
.parent = &armper_ck.clk,
.rate = 12000000,
- .flags = CLOCK_IN_OMAP1510 | ENABLE_REG_32BIT |
- ALWAYS_ENABLED | CLOCK_NO_IDLE_PARENT,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 |
+ ENABLE_REG_32BIT | ALWAYS_ENABLED |
+ CLOCK_NO_IDLE_PARENT,
.enable_reg = (void __iomem *)MOD_CONF_CTRL_0,
.enable_bit = 29, /* Chooses between 12MHz and 48MHz */
.set_rate = &omap1_set_uart_rate,
@@ -544,8 +550,8 @@ static struct clk uart2_ck = {
.parent = &armper_ck.clk,
.rate = 12000000,
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- ENABLE_REG_32BIT | ALWAYS_ENABLED |
- CLOCK_NO_IDLE_PARENT,
+ CLOCK_IN_OMAP310 | ENABLE_REG_32BIT |
+ ALWAYS_ENABLED | CLOCK_NO_IDLE_PARENT,
.enable_reg = (void __iomem *)MOD_CONF_CTRL_0,
.enable_bit = 30, /* Chooses between 12MHz and 48MHz */
.set_rate = &omap1_set_uart_rate,
@@ -559,8 +565,9 @@ static struct clk uart3_1510 = {
/* Direct from ULPD, no real parent */
.parent = &armper_ck.clk,
.rate = 12000000,
- .flags = CLOCK_IN_OMAP1510 | ENABLE_REG_32BIT |
- ALWAYS_ENABLED | CLOCK_NO_IDLE_PARENT,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 |
+ ENABLE_REG_32BIT | ALWAYS_ENABLED |
+ CLOCK_NO_IDLE_PARENT,
.enable_reg = (void __iomem *)MOD_CONF_CTRL_0,
.enable_bit = 31, /* Chooses between 12MHz and 48MHz */
.set_rate = &omap1_set_uart_rate,
@@ -590,7 +597,7 @@ static struct clk usb_clko = { /* 6 MHz output on W4_USB_CLKO */
/* Direct from ULPD, no parent */
.rate = 6000000,
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- RATE_FIXED | ENABLE_REG_32BIT,
+ CLOCK_IN_OMAP310 | RATE_FIXED | ENABLE_REG_32BIT,
.enable_reg = (void __iomem *)ULPD_CLOCK_CTRL,
.enable_bit = USB_MCLK_EN_BIT,
.enable = &omap1_clk_enable_generic,
@@ -601,7 +608,7 @@ static struct clk usb_hhc_ck1510 = {
.name = "usb_hhc_ck",
/* Direct from ULPD, no parent */
.rate = 48000000, /* Actually 2 clocks, 12MHz and 48MHz */
- .flags = CLOCK_IN_OMAP1510 |
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 |
RATE_FIXED | ENABLE_REG_32BIT,
.enable_reg = (void __iomem *)MOD_CONF_CTRL_0,
.enable_bit = USB_HOST_HHC_UHOST_EN,
@@ -637,7 +644,9 @@ static struct clk mclk_1510 = {
.name = "mclk",
/* Direct from ULPD, no parent. May be enabled by ext hardware. */
.rate = 12000000,
- .flags = CLOCK_IN_OMAP1510 | RATE_FIXED,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | RATE_FIXED,
+ .enable_reg = (void __iomem *)SOFT_REQ_REG,
+ .enable_bit = 6,
.enable = &omap1_clk_enable_generic,
.disable = &omap1_clk_disable_generic,
};
@@ -659,7 +668,7 @@ static struct clk bclk_1510 = {
.name = "bclk",
/* Direct from ULPD, no parent. May be enabled by ext hardware. */
.rate = 12000000,
- .flags = CLOCK_IN_OMAP1510 | RATE_FIXED,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | RATE_FIXED,
.enable = &omap1_clk_enable_generic,
.disable = &omap1_clk_disable_generic,
};
@@ -678,12 +687,14 @@ static struct clk bclk_16xx = {
};
static struct clk mmc1_ck = {
- .name = "mmc1_ck",
+ .name = "mmc_ck",
+ .id = 1,
/* Functional clock is direct from ULPD, interface clock is ARMPER */
.parent = &armper_ck.clk,
.rate = 48000000,
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- RATE_FIXED | ENABLE_REG_32BIT | CLOCK_NO_IDLE_PARENT,
+ CLOCK_IN_OMAP310 | RATE_FIXED | ENABLE_REG_32BIT |
+ CLOCK_NO_IDLE_PARENT,
.enable_reg = (void __iomem *)MOD_CONF_CTRL_0,
.enable_bit = 23,
.enable = &omap1_clk_enable_generic,
@@ -691,7 +702,8 @@ static struct clk mmc1_ck = {
};
static struct clk mmc2_ck = {
- .name = "mmc2_ck",
+ .name = "mmc_ck",
+ .id = 2,
/* Functional clock is direct from ULPD, interface clock is ARMPER */
.parent = &armper_ck.clk,
.rate = 48000000,
@@ -706,7 +718,7 @@ static struct clk mmc2_ck = {
static struct clk virtual_ck_mpu = {
.name = "mpu",
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- VIRTUAL_CLOCK | ALWAYS_ENABLED,
+ CLOCK_IN_OMAP310 | VIRTUAL_CLOCK | ALWAYS_ENABLED,
.parent = &arm_ck, /* Is smarter alias for */
.recalc = &followparent_recalc,
.set_rate = &omap1_select_table_rate,
@@ -715,6 +727,20 @@ static struct clk virtual_ck_mpu = {
.disable = &omap1_clk_disable_generic,
};
+/* virtual functional clock domain for I2C. Just for making sure that ARMXOR_CK
+remains active during MPU idle whenever this is enabled */
+static struct clk i2c_fck = {
+ .name = "i2c_fck",
+ .id = 1,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+ VIRTUAL_CLOCK | CLOCK_NO_IDLE_PARENT |
+ ALWAYS_ENABLED,
+ .parent = &armxor_ck.clk,
+ .recalc = &followparent_recalc,
+ .enable = &omap1_clk_enable_generic,
+ .disable = &omap1_clk_disable_generic,
+};
+
static struct clk * onchip_clks[] = {
/* non-ULPD clocks */
&ck_ref,
@@ -763,6 +789,7 @@ static struct clk * onchip_clks[] = {
&mmc2_ck,
/* Virtual clocks */
&virtual_ck_mpu,
+ &i2c_fck,
};
#endif
diff --git a/arch/arm/mach-omap1/devices.c b/arch/arm/mach-omap1/devices.c
index ecbc47514ad..876c38da14f 100644
--- a/arch/arm/mach-omap1/devices.c
+++ b/arch/arm/mach-omap1/devices.c
@@ -99,6 +99,45 @@ static void omap_init_rtc(void)
static inline void omap_init_rtc(void) {}
#endif
+#if defined(CONFIG_OMAP_STI)
+
+#define OMAP1_STI_BASE IO_ADDRESS(0xfffea000)
+#define OMAP1_STI_CHANNEL_BASE (OMAP1_STI_BASE + 0x400)
+
+static struct resource sti_resources[] = {
+ {
+ .start = OMAP1_STI_BASE,
+ .end = OMAP1_STI_BASE + SZ_1K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = OMAP1_STI_CHANNEL_BASE,
+ .end = OMAP1_STI_CHANNEL_BASE + SZ_1K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = INT_1610_STI,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static struct platform_device sti_device = {
+ .name = "sti",
+ .id = -1,
+ .dev = {
+ .release = omap_nop_release,
+ },
+ .num_resources = ARRAY_SIZE(sti_resources),
+ .resource = sti_resources,
+};
+
+static inline void omap_init_sti(void)
+{
+ platform_device_register(&sti_device);
+}
+#else
+static inline void omap_init_sti(void) {}
+#endif
/*-------------------------------------------------------------------------*/
@@ -129,6 +168,7 @@ static int __init omap1_init_devices(void)
*/
omap_init_irda();
omap_init_rtc();
+ omap_init_sti();
return 0;
}
diff --git a/arch/arm/mach-omap1/io.c b/arch/arm/mach-omap1/io.c
index 82d556be79c..be3a2a4ee2b 100644
--- a/arch/arm/mach-omap1/io.c
+++ b/arch/arm/mach-omap1/io.c
@@ -18,6 +18,7 @@
#include <asm/io.h>
#include <asm/arch/mux.h>
#include <asm/arch/tc.h>
+#include <asm/arch/omapfb.h>
extern int omap1_clk_init(void);
extern void omap_check_revision(void);
@@ -110,7 +111,7 @@ void __init omap1_map_common_io(void)
}
#endif
#ifdef CONFIG_ARCH_OMAP15XX
- if (cpu_is_omap1510()) {
+ if (cpu_is_omap15xx()) {
iotable_init(omap1510_io_desc, ARRAY_SIZE(omap1510_io_desc));
}
#endif
@@ -121,6 +122,7 @@ void __init omap1_map_common_io(void)
#endif
omap_sram_init();
+ omapfb_reserve_mem();
}
/*
diff --git a/arch/arm/mach-omap1/irq.c b/arch/arm/mach-omap1/irq.c
index ed65a7d2e94..a0431c00fa8 100644
--- a/arch/arm/mach-omap1/irq.c
+++ b/arch/arm/mach-omap1/irq.c
@@ -60,7 +60,7 @@ struct omap_irq_bank {
unsigned long wake_enable;
};
-static unsigned int irq_bank_count = 0;
+static unsigned int irq_bank_count;
static struct omap_irq_bank *irq_banks;
static inline unsigned int irq_bank_readl(int bank, int offset)
@@ -142,28 +142,28 @@ static void omap_irq_set_cfg(int irq, int fiq, int priority, int trigger)
#ifdef CONFIG_ARCH_OMAP730
static struct omap_irq_bank omap730_irq_banks[] = {
- { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3f8e22f },
- { .base_reg = OMAP_IH2_BASE, .trigger_map = 0xfdb9c1f2 },
+ { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3f8e22f },
+ { .base_reg = OMAP_IH2_BASE, .trigger_map = 0xfdb9c1f2 },
{ .base_reg = OMAP_IH2_BASE + 0x100, .trigger_map = 0x800040f3 },
};
#endif
#ifdef CONFIG_ARCH_OMAP15XX
static struct omap_irq_bank omap1510_irq_banks[] = {
- { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3febfff },
- { .base_reg = OMAP_IH2_BASE, .trigger_map = 0xffbfffed },
+ { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3febfff },
+ { .base_reg = OMAP_IH2_BASE, .trigger_map = 0xffbfffed },
};
static struct omap_irq_bank omap310_irq_banks[] = {
- { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3faefc3 },
- { .base_reg = OMAP_IH2_BASE, .trigger_map = 0x65b3c061 },
+ { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3faefc3 },
+ { .base_reg = OMAP_IH2_BASE, .trigger_map = 0x65b3c061 },
};
#endif
#if defined(CONFIG_ARCH_OMAP16XX)
static struct omap_irq_bank omap1610_irq_banks[] = {
- { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3fefe8f },
- { .base_reg = OMAP_IH2_BASE, .trigger_map = 0xfdb7c1fd },
+ { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3fefe8f },
+ { .base_reg = OMAP_IH2_BASE, .trigger_map = 0xfdb7c1fd },
{ .base_reg = OMAP_IH2_BASE + 0x100, .trigger_map = 0xffffb7ff },
{ .base_reg = OMAP_IH2_BASE + 0x200, .trigger_map = 0xffffffff },
};
diff --git a/arch/arm/mach-omap1/mux.c b/arch/arm/mach-omap1/mux.c
index d4b8d624e74..10fe0b3efca 100644
--- a/arch/arm/mach-omap1/mux.c
+++ b/arch/arm/mach-omap1/mux.c
@@ -35,16 +35,20 @@
#ifdef CONFIG_ARCH_OMAP730
struct pin_config __initdata_or_module omap730_pins[] = {
-MUX_CFG_730("E2_730_KBR0", 12, 21, 0, 0, 20, 1, NA, 0, 0)
-MUX_CFG_730("J7_730_KBR1", 12, 25, 0, 0, 24, 1, NA, 0, 0)
-MUX_CFG_730("E1_730_KBR2", 12, 29, 0, 0, 28, 1, NA, 0, 0)
-MUX_CFG_730("F3_730_KBR3", 13, 1, 0, 0, 0, 1, NA, 0, 0)
-MUX_CFG_730("D2_730_KBR4", 13, 5, 0, 0, 4, 1, NA, 0, 0)
-MUX_CFG_730("C2_730_KBC0", 13, 9, 0, 0, 8, 1, NA, 0, 0)
-MUX_CFG_730("D3_730_KBC1", 13, 13, 0, 0, 12, 1, NA, 0, 0)
-MUX_CFG_730("E4_730_KBC2", 13, 17, 0, 0, 16, 1, NA, 0, 0)
-MUX_CFG_730("F4_730_KBC3", 13, 21, 0, 0, 20, 1, NA, 0, 0)
-MUX_CFG_730("E3_730_KBC4", 13, 25, 0, 0, 24, 1, NA, 0, 0)
+MUX_CFG_730("E2_730_KBR0", 12, 21, 0, 20, 1, 0)
+MUX_CFG_730("J7_730_KBR1", 12, 25, 0, 24, 1, 0)
+MUX_CFG_730("E1_730_KBR2", 12, 29, 0, 28, 1, 0)
+MUX_CFG_730("F3_730_KBR3", 13, 1, 0, 0, 1, 0)
+MUX_CFG_730("D2_730_KBR4", 13, 5, 0, 4, 1, 0)
+MUX_CFG_730("C2_730_KBC0", 13, 9, 0, 8, 1, 0)
+MUX_CFG_730("D3_730_KBC1", 13, 13, 0, 12, 1, 0)
+MUX_CFG_730("E4_730_KBC2", 13, 17, 0, 16, 1, 0)
+MUX_CFG_730("F4_730_KBC3", 13, 21, 0, 20, 1, 0)
+MUX_CFG_730("E3_730_KBC4", 13, 25, 0, 24, 1, 0)
+
+MUX_CFG_730("AA17_730_USB_DM", 2, 21, 0, 20, 0, 0)
+MUX_CFG_730("W16_730_USB_PU_EN", 2, 25, 0, 24, 0, 0)
+MUX_CFG_730("W17_730_USB_VBUSI", 2, 29, 0, 28, 0, 0)
};
#endif
@@ -73,8 +77,8 @@ MUX_CFG("UART3_BCLK", A, 0, 0, 2, 6, 0, NA, 0, 0)
MUX_CFG("Y15_1610_UART3_RTS", A, 0, 1, 2, 6, 0, NA, 0, 0)
/* PWT & PWL, conflicts with UART3 */
-MUX_CFG("PWT", 6, 0, 2, 0, 30, 0, NA, 0, 0)
-MUX_CFG("PWL", 6, 3, 1, 0, 31, 1, NA, 0, 0)
+MUX_CFG("PWT", 6, 0, 2, 0, 30, 0, NA, 0, 0)
+MUX_CFG("PWL", 6, 3, 1, 0, 31, 1, NA, 0, 0)
/* USB internal master generic */
MUX_CFG("R18_USB_VBUS", 7, 9, 2, 1, 11, 0, NA, 0, 1)
@@ -151,7 +155,7 @@ MUX_CFG("MCBSP3_CLKX", 9, 3, 1, 1, 29, 0, NA, 0, 1)
/* Misc ballouts */
MUX_CFG("BALLOUT_V8_ARMIO3", B, 18, 0, 2, 25, 1, NA, 0, 1)
-MUX_CFG("N20_HDQ", 6, 18, 1, 1, 4, 0, 1, 4, 0)
+MUX_CFG("N20_HDQ", 6, 18, 1, 1, 4, 0, 1, 4, 0)
/* OMAP-1610 MMC2 */
MUX_CFG("W8_1610_MMC2_DAT0", B, 21, 6, 2, 23, 1, 2, 1, 1)
diff --git a/arch/arm/mach-omap1/pm.c b/arch/arm/mach-omap1/pm.c
new file mode 100644
index 00000000000..ddf6b07dc9c
--- /dev/null
+++ b/arch/arm/mach-omap1/pm.c
@@ -0,0 +1,770 @@
+/*
+ * linux/arch/arm/mach-omap1/pm.c
+ *
+ * OMAP Power Management Routines
+ *
+ * Original code for the SA11x0:
+ * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
+ *
+ * Modified for the PXA250 by Nicolas Pitre:
+ * Copyright (c) 2002 Monta Vista Software, Inc.
+ *
+ * Modified for the OMAP1510 by David Singleton:
+ * Copyright (c) 2002 Monta Vista Software, Inc.
+ *
+ * Cleanup 2004 for OMAP1510/1610 by Dirk Behme <dirk.behme@de.bosch.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/pm.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/pm.h>
+#include <linux/interrupt.h>
+#include <linux/sysfs.h>
+#include <linux/module.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/atomic.h>
+#include <asm/mach/time.h>
+#include <asm/mach/irq.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/irqs.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/sram.h>
+#include <asm/arch/tc.h>
+#include <asm/arch/pm.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/tps65010.h>
+#include <asm/arch/dma.h>
+#include <asm/arch/dsp_common.h>
+#include <asm/arch/dmtimer.h>
+
+static unsigned int arm_sleep_save[ARM_SLEEP_SAVE_SIZE];
+static unsigned short dsp_sleep_save[DSP_SLEEP_SAVE_SIZE];
+static unsigned short ulpd_sleep_save[ULPD_SLEEP_SAVE_SIZE];
+static unsigned int mpui730_sleep_save[MPUI730_SLEEP_SAVE_SIZE];
+static unsigned int mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_SIZE];
+static unsigned int mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_SIZE];
+
+static unsigned short enable_dyn_sleep = 1;
+
+static ssize_t omap_pm_sleep_while_idle_show(struct subsystem * subsys, char *buf)
+{
+ return sprintf(buf, "%hu\n", enable_dyn_sleep);
+}
+
+static ssize_t omap_pm_sleep_while_idle_store(struct subsystem * subsys,
+ const char * buf,
+ size_t n)
+{
+ unsigned short value;
+ if (sscanf(buf, "%hu", &value) != 1 ||
+ (value != 0 && value != 1)) {
+ printk(KERN_ERR "idle_sleep_store: Invalid value\n");
+ return -EINVAL;
+ }
+ enable_dyn_sleep = value;
+ return n;
+}
+
+static struct subsys_attribute sleep_while_idle_attr = {
+ .attr = {
+ .name = __stringify(sleep_while_idle),
+ .mode = 0644,
+ },
+ .show = omap_pm_sleep_while_idle_show,
+ .store = omap_pm_sleep_while_idle_store,
+};
+
+extern struct subsystem power_subsys;
+static void (*omap_sram_idle)(void) = NULL;
+static void (*omap_sram_suspend)(unsigned long r0, unsigned long r1) = NULL;
+
+/*
+ * Let's power down on idle, but only if we are really
+ * idle, because once we start down the path of
+ * going idle we continue to do idle even if we get
+ * a clock tick interrupt . .
+ */
+void omap_pm_idle(void)
+{
+ extern __u32 arm_idlect1_mask;
+ __u32 use_idlect1 = arm_idlect1_mask;
+#ifndef CONFIG_OMAP_MPU_TIMER
+ int do_sleep;
+#endif
+
+ local_irq_disable();
+ local_fiq_disable();
+ if (need_resched()) {
+ local_fiq_enable();
+ local_irq_enable();
+ return;
+ }
+
+ /*
+ * Since an interrupt may set up a timer, we don't want to
+ * reprogram the hardware timer with interrupts enabled.
+ * Re-enable interrupts only after returning from idle.
+ */
+ timer_dyn_reprogram();
+
+#ifdef CONFIG_OMAP_MPU_TIMER
+#warning Enable 32kHz OS timer in order to allow sleep states in idle
+ use_idlect1 = use_idlect1 & ~(1 << 9);
+#else
+
+ do_sleep = 0;
+ while (enable_dyn_sleep) {
+
+#ifdef CONFIG_CBUS_TAHVO_USB
+ extern int vbus_active;
+ /* Clock requirements? */
+ if (vbus_active)
+ break;
+#endif
+ do_sleep = 1;
+ break;
+ }
+
+#ifdef CONFIG_OMAP_DM_TIMER
+ use_idlect1 = omap_dm_timer_modify_idlect_mask(use_idlect1);
+#endif
+
+ if (omap_dma_running()) {
+ use_idlect1 &= ~(1 << 6);
+ if (omap_lcd_dma_ext_running())
+ use_idlect1 &= ~(1 << 12);
+ }
+
+ /* We should be able to remove the do_sleep variable and multiple
+ * tests above as soon as drivers, timer and DMA code have been fixed.
+ * Even the sleep block count should become obsolete. */
+ if ((use_idlect1 != ~0) || !do_sleep) {
+
+ __u32 saved_idlect1 = omap_readl(ARM_IDLECT1);
+ if (cpu_is_omap15xx())
+ use_idlect1 &= OMAP1510_BIG_SLEEP_REQUEST;
+ else
+ use_idlect1 &= OMAP1610_IDLECT1_SLEEP_VAL;
+ omap_writel(use_idlect1, ARM_IDLECT1);
+ __asm__ volatile ("mcr p15, 0, r0, c7, c0, 4");
+ omap_writel(saved_idlect1, ARM_IDLECT1);
+
+ local_fiq_enable();
+ local_irq_enable();
+ return;
+ }
+ omap_sram_suspend(omap_readl(ARM_IDLECT1),
+ omap_readl(ARM_IDLECT2));
+#endif
+
+ local_fiq_enable();
+ local_irq_enable();
+}
+
+/*
+ * Configuration of the wakeup event is board specific. For the
+ * moment we put it into this helper function. Later it may move
+ * to board specific files.
+ */
+static void omap_pm_wakeup_setup(void)
+{
+ u32 level1_wake = 0;
+ u32 level2_wake = OMAP_IRQ_BIT(INT_UART2);
+
+ /*
+ * Turn off all interrupts except GPIO bank 1, L1-2nd level cascade,
+ * and the L2 wakeup interrupts: keypad and UART2. Note that the
+ * drivers must still separately call omap_set_gpio_wakeup() to
+ * wake up to a GPIO interrupt.
+ */
+ if (cpu_is_omap730())
+ level1_wake = OMAP_IRQ_BIT(INT_730_GPIO_BANK1) |
+ OMAP_IRQ_BIT(INT_730_IH2_IRQ);
+ else if (cpu_is_omap15xx())
+ level1_wake = OMAP_IRQ_BIT(INT_GPIO_BANK1) |
+ OMAP_IRQ_BIT(INT_1510_IH2_IRQ);
+ else if (cpu_is_omap16xx())
+ level1_wake = OMAP_IRQ_BIT(INT_GPIO_BANK1) |
+ OMAP_IRQ_BIT(INT_1610_IH2_IRQ);
+
+ omap_writel(~level1_wake, OMAP_IH1_MIR);
+
+ if (cpu_is_omap730()) {
+ omap_writel(~level2_wake, OMAP_IH2_0_MIR);
+ omap_writel(~(OMAP_IRQ_BIT(INT_730_WAKE_UP_REQ) |
+ OMAP_IRQ_BIT(INT_730_MPUIO_KEYPAD)),
+ OMAP_IH2_1_MIR);
+ } else if (cpu_is_omap15xx()) {
+ level2_wake |= OMAP_IRQ_BIT(INT_KEYBOARD);
+ omap_writel(~level2_wake, OMAP_IH2_MIR);
+ } else if (cpu_is_omap16xx()) {
+ level2_wake |= OMAP_IRQ_BIT(INT_KEYBOARD);
+ omap_writel(~level2_wake, OMAP_IH2_0_MIR);
+
+ /* INT_1610_WAKE_UP_REQ is needed for GPIO wakeup... */
+ omap_writel(~OMAP_IRQ_BIT(INT_1610_WAKE_UP_REQ),
+ OMAP_IH2_1_MIR);
+ omap_writel(~0x0, OMAP_IH2_2_MIR);
+ omap_writel(~0x0, OMAP_IH2_3_MIR);
+ }
+
+ /* New IRQ agreement, recalculate in cascade order */
+ omap_writel(1, OMAP_IH2_CONTROL);
+ omap_writel(1, OMAP_IH1_CONTROL);
+}
+
+#define EN_DSPCK 13 /* ARM_CKCTL */
+#define EN_APICK 6 /* ARM_IDLECT2 */
+#define DSP_EN 1 /* ARM_RSTCT1 */
+
+void omap_pm_suspend(void)
+{
+ unsigned long arg0 = 0, arg1 = 0;
+
+ printk("PM: OMAP%x is trying to enter deep sleep...\n", system_rev);
+
+ omap_serial_wake_trigger(1);
+
+ if (machine_is_omap_osk()) {
+ /* Stop LED1 (D9) blink */
+ tps65010_set_led(LED1, OFF);
+ }
+
+ omap_writew(0xffff, ULPD_SOFT_DISABLE_REQ_REG);
+
+ /*
+ * Step 1: turn off interrupts (FIXME: NOTE: already disabled)
+ */
+
+ local_irq_disable();
+ local_fiq_disable();
+
+ /*
+ * Step 2: save registers
+ *
+ * The omap is a strange/beautiful device. The caches, memory
+ * and register state are preserved across power saves.
+ * We have to save and restore very little register state to
+ * idle the omap.
+ *
+ * Save interrupt, MPUI, ARM and UPLD control registers.
+ */
+
+ if (cpu_is_omap730()) {
+ MPUI730_SAVE(OMAP_IH1_MIR);
+ MPUI730_SAVE(OMAP_IH2_0_MIR);
+ MPUI730_SAVE(OMAP_IH2_1_MIR);
+ MPUI730_SAVE(MPUI_CTRL);
+ MPUI730_SAVE(MPUI_DSP_BOOT_CONFIG);
+ MPUI730_SAVE(MPUI_DSP_API_CONFIG);
+ MPUI730_SAVE(EMIFS_CONFIG);
+ MPUI730_SAVE(EMIFF_SDRAM_CONFIG);
+
+ } else if (cpu_is_omap15xx()) {
+ MPUI1510_SAVE(OMAP_IH1_MIR);
+ MPUI1510_SAVE(OMAP_IH2_MIR);
+ MPUI1510_SAVE(MPUI_CTRL);
+ MPUI1510_SAVE(MPUI_DSP_BOOT_CONFIG);
+ MPUI1510_SAVE(MPUI_DSP_API_CONFIG);
+ MPUI1510_SAVE(EMIFS_CONFIG);
+ MPUI1510_SAVE(EMIFF_SDRAM_CONFIG);
+ } else if (cpu_is_omap16xx()) {
+ MPUI1610_SAVE(OMAP_IH1_MIR);
+ MPUI1610_SAVE(OMAP_IH2_0_MIR);
+ MPUI1610_SAVE(OMAP_IH2_1_MIR);
+ MPUI1610_SAVE(OMAP_IH2_2_MIR);
+ MPUI1610_SAVE(OMAP_IH2_3_MIR);
+ MPUI1610_SAVE(MPUI_CTRL);
+ MPUI1610_SAVE(MPUI_DSP_BOOT_CONFIG);
+ MPUI1610_SAVE(MPUI_DSP_API_CONFIG);
+ MPUI1610_SAVE(EMIFS_CONFIG);
+ MPUI1610_SAVE(EMIFF_SDRAM_CONFIG);
+ }
+
+ ARM_SAVE(ARM_CKCTL);
+ ARM_SAVE(ARM_IDLECT1);
+ ARM_SAVE(ARM_IDLECT2);
+ if (!(cpu_is_omap15xx()))
+ ARM_SAVE(ARM_IDLECT3);
+ ARM_SAVE(ARM_EWUPCT);
+ ARM_SAVE(ARM_RSTCT1);
+ ARM_SAVE(ARM_RSTCT2);
+ ARM_SAVE(ARM_SYSST);
+ ULPD_SAVE(ULPD_CLOCK_CTRL);
+ ULPD_SAVE(ULPD_STATUS_REQ);
+
+ /* (Step 3 removed - we now allow deep sleep by default) */
+
+ /*
+ * Step 4: OMAP DSP Shutdown
+ */
+
+ /* stop DSP */
+ omap_writew(omap_readw(ARM_RSTCT1) & ~(1 << DSP_EN), ARM_RSTCT1);
+
+ /* shut down dsp_ck */
+ omap_writew(omap_readw(ARM_CKCTL) & ~(1 << EN_DSPCK), ARM_CKCTL);
+
+ /* temporarily enabling api_ck to access DSP registers */
+ omap_writew(omap_readw(ARM_IDLECT2) | 1 << EN_APICK, ARM_IDLECT2);
+
+ /* save DSP registers */
+ DSP_SAVE(DSP_IDLECT2);
+
+ /* Stop all DSP domain clocks */
+ __raw_writew(0, DSP_IDLECT2);
+
+ /*
+ * Step 5: Wakeup Event Setup
+ */
+
+ omap_pm_wakeup_setup();
+
+ /*
+ * Step 6: ARM and Traffic controller shutdown
+ */
+
+ /* disable ARM watchdog */
+ omap_writel(0x00F5, OMAP_WDT_TIMER_MODE);
+ omap_writel(0x00A0, OMAP_WDT_TIMER_MODE);
+
+ /*
+ * Step 6b: ARM and Traffic controller shutdown
+ *
+ * Step 6 continues here. Prepare jump to power management
+ * assembly code in internal SRAM.
+ *
+ * Since the omap_cpu_suspend routine has been copied to
+ * SRAM, we'll do an indirect procedure call to it and pass the
+ * contents of arm_idlect1 and arm_idlect2 so it can restore
+ * them when it wakes up and it will return.
+ */
+
+ arg0 = arm_sleep_save[ARM_SLEEP_SAVE_ARM_IDLECT1];
+ arg1 = arm_sleep_save[ARM_SLEEP_SAVE_ARM_IDLECT2];
+
+ /*
+ * Step 6c: ARM and Traffic controller shutdown
+ *
+ * Jump to assembly code. The processor will stay there
+ * until wake up.
+ */
+ omap_sram_suspend(arg0, arg1);
+
+ /*
+ * If we are here, processor is woken up!
+ */
+
+ /*
+ * Restore DSP clocks
+ */
+
+ /* again temporarily enabling api_ck to access DSP registers */
+ omap_writew(omap_readw(ARM_IDLECT2) | 1 << EN_APICK, ARM_IDLECT2);
+
+ /* Restore DSP domain clocks */
+ DSP_RESTORE(DSP_IDLECT2);
+
+ /*
+ * Restore ARM state, except ARM_IDLECT1/2 which omap_cpu_suspend did
+ */
+
+ if (!(cpu_is_omap15xx()))
+ ARM_RESTORE(ARM_IDLECT3);
+ ARM_RESTORE(ARM_CKCTL);
+ ARM_RESTORE(ARM_EWUPCT);
+ ARM_RESTORE(ARM_RSTCT1);
+ ARM_RESTORE(ARM_RSTCT2);
+ ARM_RESTORE(ARM_SYSST);
+ ULPD_RESTORE(ULPD_CLOCK_CTRL);
+ ULPD_RESTORE(ULPD_STATUS_REQ);
+
+ if (cpu_is_omap730()) {
+ MPUI730_RESTORE(EMIFS_CONFIG);
+ MPUI730_RESTORE(EMIFF_SDRAM_CONFIG);
+ MPUI730_RESTORE(OMAP_IH1_MIR);
+ MPUI730_RESTORE(OMAP_IH2_0_MIR);
+ MPUI730_RESTORE(OMAP_IH2_1_MIR);
+ } else if (cpu_is_omap15xx()) {
+ MPUI1510_RESTORE(MPUI_CTRL);
+ MPUI1510_RESTORE(MPUI_DSP_BOOT_CONFIG);
+ MPUI1510_RESTORE(MPUI_DSP_API_CONFIG);
+ MPUI1510_RESTORE(EMIFS_CONFIG);
+ MPUI1510_RESTORE(EMIFF_SDRAM_CONFIG);
+ MPUI1510_RESTORE(OMAP_IH1_MIR);
+ MPUI1510_RESTORE(OMAP_IH2_MIR);
+ } else if (cpu_is_omap16xx()) {
+ MPUI1610_RESTORE(MPUI_CTRL);
+ MPUI1610_RESTORE(MPUI_DSP_BOOT_CONFIG);
+ MPUI1610_RESTORE(MPUI_DSP_API_CONFIG);
+ MPUI1610_RESTORE(EMIFS_CONFIG);
+ MPUI1610_RESTORE(EMIFF_SDRAM_CONFIG);
+
+ MPUI1610_RESTORE(OMAP_IH1_MIR);
+ MPUI1610_RESTORE(OMAP_IH2_0_MIR);
+ MPUI1610_RESTORE(OMAP_IH2_1_MIR);
+ MPUI1610_RESTORE(OMAP_IH2_2_MIR);
+ MPUI1610_RESTORE(OMAP_IH2_3_MIR);
+ }
+
+ omap_writew(0, ULPD_SOFT_DISABLE_REQ_REG);
+
+ /*
+ * Reenable interrupts
+ */
+
+ local_irq_enable();
+ local_fiq_enable();
+
+ omap_serial_wake_trigger(0);
+
+ printk("PM: OMAP%x is re-starting from deep sleep...\n", system_rev);
+
+ if (machine_is_omap_osk()) {
+ /* Let LED1 (D9) blink again */
+ tps65010_set_led(LED1, BLINK);
+ }
+}
+
+#if defined(DEBUG) && defined(CONFIG_PROC_FS)
+static int g_read_completed;
+
+/*
+ * Read system PM registers for debugging
+ */
+static int omap_pm_read_proc(
+ char *page_buffer,
+ char **my_first_byte,
+ off_t virtual_start,
+ int length,
+ int *eof,
+ void *data)
+{
+ int my_buffer_offset = 0;
+ char * const my_base = page_buffer;
+
+ ARM_SAVE(ARM_CKCTL);
+ ARM_SAVE(ARM_IDLECT1);
+ ARM_SAVE(ARM_IDLECT2);
+ if (!(cpu_is_omap15xx()))
+ ARM_SAVE(ARM_IDLECT3);
+ ARM_SAVE(ARM_EWUPCT);
+ ARM_SAVE(ARM_RSTCT1);
+ ARM_SAVE(ARM_RSTCT2);
+ ARM_SAVE(ARM_SYSST);
+
+ ULPD_SAVE(ULPD_IT_STATUS);
+ ULPD_SAVE(ULPD_CLOCK_CTRL);
+ ULPD_SAVE(ULPD_SOFT_REQ);
+ ULPD_SAVE(ULPD_STATUS_REQ);
+ ULPD_SAVE(ULPD_DPLL_CTRL);
+ ULPD_SAVE(ULPD_POWER_CTRL);
+
+ if (cpu_is_omap730()) {
+ MPUI730_SAVE(MPUI_CTRL);
+ MPUI730_SAVE(MPUI_DSP_STATUS);
+ MPUI730_SAVE(MPUI_DSP_BOOT_CONFIG);
+ MPUI730_SAVE(MPUI_DSP_API_CONFIG);
+ MPUI730_SAVE(EMIFF_SDRAM_CONFIG);
+ MPUI730_SAVE(EMIFS_CONFIG);
+ } else if (cpu_is_omap15xx()) {
+ MPUI1510_SAVE(MPUI_CTRL);
+ MPUI1510_SAVE(MPUI_DSP_STATUS);
+ MPUI1510_SAVE(MPUI_DSP_BOOT_CONFIG);
+ MPUI1510_SAVE(MPUI_DSP_API_CONFIG);
+ MPUI1510_SAVE(EMIFF_SDRAM_CONFIG);
+ MPUI1510_SAVE(EMIFS_CONFIG);
+ } else if (cpu_is_omap16xx()) {
+ MPUI1610_SAVE(MPUI_CTRL);
+ MPUI1610_SAVE(MPUI_DSP_STATUS);
+ MPUI1610_SAVE(MPUI_DSP_BOOT_CONFIG);
+ MPUI1610_SAVE(MPUI_DSP_API_CONFIG);
+ MPUI1610_SAVE(EMIFF_SDRAM_CONFIG);
+ MPUI1610_SAVE(EMIFS_CONFIG);
+ }
+
+ if (virtual_start == 0) {
+ g_read_completed = 0;
+
+ my_buffer_offset += sprintf(my_base + my_buffer_offset,
+ "ARM_CKCTL_REG: 0x%-8x \n"
+ "ARM_IDLECT1_REG: 0x%-8x \n"
+ "ARM_IDLECT2_REG: 0x%-8x \n"
+ "ARM_IDLECT3_REG: 0x%-8x \n"
+ "ARM_EWUPCT_REG: 0x%-8x \n"
+ "ARM_RSTCT1_REG: 0x%-8x \n"
+ "ARM_RSTCT2_REG: 0x%-8x \n"
+ "ARM_SYSST_REG: 0x%-8x \n"
+ "ULPD_IT_STATUS_REG: 0x%-4x \n"
+ "ULPD_CLOCK_CTRL_REG: 0x%-4x \n"
+ "ULPD_SOFT_REQ_REG: 0x%-4x \n"
+ "ULPD_DPLL_CTRL_REG: 0x%-4x \n"
+ "ULPD_STATUS_REQ_REG: 0x%-4x \n"
+ "ULPD_POWER_CTRL_REG: 0x%-4x \n",
+ ARM_SHOW(ARM_CKCTL),
+ ARM_SHOW(ARM_IDLECT1),
+ ARM_SHOW(ARM_IDLECT2),
+ ARM_SHOW(ARM_IDLECT3),
+ ARM_SHOW(ARM_EWUPCT),
+ ARM_SHOW(ARM_RSTCT1),
+ ARM_SHOW(ARM_RSTCT2),
+ ARM_SHOW(ARM_SYSST),
+ ULPD_SHOW(ULPD_IT_STATUS),
+ ULPD_SHOW(ULPD_CLOCK_CTRL),
+ ULPD_SHOW(ULPD_SOFT_REQ),
+ ULPD_SHOW(ULPD_DPLL_CTRL),
+ ULPD_SHOW(ULPD_STATUS_REQ),
+ ULPD_SHOW(ULPD_POWER_CTRL));
+
+ if (cpu_is_omap730()) {
+ my_buffer_offset += sprintf(my_base + my_buffer_offset,
+ "MPUI730_CTRL_REG 0x%-8x \n"
+ "MPUI730_DSP_STATUS_REG: 0x%-8x \n"
+ "MPUI730_DSP_BOOT_CONFIG_REG: 0x%-8x \n"
+ "MPUI730_DSP_API_CONFIG_REG: 0x%-8x \n"
+ "MPUI730_SDRAM_CONFIG_REG: 0x%-8x \n"
+ "MPUI730_EMIFS_CONFIG_REG: 0x%-8x \n",
+ MPUI730_SHOW(MPUI_CTRL),
+ MPUI730_SHOW(MPUI_DSP_STATUS),
+ MPUI730_SHOW(MPUI_DSP_BOOT_CONFIG),
+ MPUI730_SHOW(MPUI_DSP_API_CONFIG),
+ MPUI730_SHOW(EMIFF_SDRAM_CONFIG),
+ MPUI730_SHOW(EMIFS_CONFIG));
+ } else if (cpu_is_omap15xx()) {
+ my_buffer_offset += sprintf(my_base + my_buffer_offset,
+ "MPUI1510_CTRL_REG 0x%-8x \n"
+ "MPUI1510_DSP_STATUS_REG: 0x%-8x \n"
+ "MPUI1510_DSP_BOOT_CONFIG_REG: 0x%-8x \n"
+ "MPUI1510_DSP_API_CONFIG_REG: 0x%-8x \n"
+ "MPUI1510_SDRAM_CONFIG_REG: 0x%-8x \n"
+ "MPUI1510_EMIFS_CONFIG_REG: 0x%-8x \n",
+ MPUI1510_SHOW(MPUI_CTRL),
+ MPUI1510_SHOW(MPUI_DSP_STATUS),
+ MPUI1510_SHOW(MPUI_DSP_BOOT_CONFIG),
+ MPUI1510_SHOW(MPUI_DSP_API_CONFIG),
+ MPUI1510_SHOW(EMIFF_SDRAM_CONFIG),
+ MPUI1510_SHOW(EMIFS_CONFIG));
+ } else if (cpu_is_omap16xx()) {
+ my_buffer_offset += sprintf(my_base + my_buffer_offset,
+ "MPUI1610_CTRL_REG 0x%-8x \n"
+ "MPUI1610_DSP_STATUS_REG: 0x%-8x \n"
+ "MPUI1610_DSP_BOOT_CONFIG_REG: 0x%-8x \n"
+ "MPUI1610_DSP_API_CONFIG_REG: 0x%-8x \n"
+ "MPUI1610_SDRAM_CONFIG_REG: 0x%-8x \n"
+ "MPUI1610_EMIFS_CONFIG_REG: 0x%-8x \n",
+ MPUI1610_SHOW(MPUI_CTRL),
+ MPUI1610_SHOW(MPUI_DSP_STATUS),
+ MPUI1610_SHOW(MPUI_DSP_BOOT_CONFIG),
+ MPUI1610_SHOW(MPUI_DSP_API_CONFIG),
+ MPUI1610_SHOW(EMIFF_SDRAM_CONFIG),
+ MPUI1610_SHOW(EMIFS_CONFIG));
+ }
+
+ g_read_completed++;
+ } else if (g_read_completed >= 1) {
+ *eof = 1;
+ return 0;
+ }
+ g_read_completed++;
+
+ *my_first_byte = page_buffer;
+ return my_buffer_offset;
+}
+
+static void omap_pm_init_proc(void)
+{
+ struct proc_dir_entry *entry;
+
+ entry = create_proc_read_entry("driver/omap_pm",
+ S_IWUSR | S_IRUGO, NULL,
+ omap_pm_read_proc, NULL);
+}
+
+#endif /* DEBUG && CONFIG_PROC_FS */
+
+static void (*saved_idle)(void) = NULL;
+
+/*
+ * omap_pm_prepare - Do preliminary suspend work.
+ * @state: suspend state we're entering.
+ *
+ */
+static int omap_pm_prepare(suspend_state_t state)
+{
+ int error = 0;
+
+ /* We cannot sleep in idle until we have resumed */
+ saved_idle = pm_idle;
+ pm_idle = NULL;
+
+ switch (state)
+ {
+ case PM_SUSPEND_STANDBY:
+ case PM_SUSPEND_MEM:
+ break;
+
+ case PM_SUSPEND_DISK:
+ return -ENOTSUPP;
+
+ default:
+ return -EINVAL;
+ }
+
+ return error;
+}
+
+
+/*
+ * omap_pm_enter - Actually enter a sleep state.
+ * @state: State we're entering.
+ *
+ */
+
+static int omap_pm_enter(suspend_state_t state)
+{
+ switch (state)
+ {
+ case PM_SUSPEND_STANDBY:
+ case PM_SUSPEND_MEM:
+ omap_pm_suspend();
+ break;
+
+ case PM_SUSPEND_DISK:
+ return -ENOTSUPP;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+
+/**
+ * omap_pm_finish - Finish up suspend sequence.
+ * @state: State we're coming out of.
+ *
+ * This is called after we wake back up (or if entering the sleep state
+ * failed).
+ */
+
+static int omap_pm_finish(suspend_state_t state)
+{
+ pm_idle = saved_idle;
+ return 0;
+}
+
+
+static irqreturn_t omap_wakeup_interrupt(int irq, void * dev,
+ struct pt_regs * regs)
+{
+ return IRQ_HANDLED;
+}
+
+static struct irqaction omap_wakeup_irq = {
+ .name = "peripheral wakeup",
+ .flags = SA_INTERRUPT,
+ .handler = omap_wakeup_interrupt
+};
+
+
+
+static struct pm_ops omap_pm_ops ={
+ .pm_disk_mode = 0,
+ .prepare = omap_pm_prepare,
+ .enter = omap_pm_enter,
+ .finish = omap_pm_finish,
+};
+
+static int __init omap_pm_init(void)
+{
+ printk("Power Management for TI OMAP.\n");
+
+ /*
+ * We copy the assembler sleep/wakeup routines to SRAM.
+ * These routines need to be in SRAM as that's the only
+ * memory the MPU can see when it wakes up.
+ */
+ if (cpu_is_omap730()) {
+ omap_sram_idle = omap_sram_push(omap730_idle_loop_suspend,
+ omap730_idle_loop_suspend_sz);
+ omap_sram_suspend = omap_sram_push(omap730_cpu_suspend,
+ omap730_cpu_suspend_sz);
+ } else if (cpu_is_omap15xx()) {
+ omap_sram_idle = omap_sram_push(omap1510_idle_loop_suspend,
+ omap1510_idle_loop_suspend_sz);
+ omap_sram_suspend = omap_sram_push(omap1510_cpu_suspend,
+ omap1510_cpu_suspend_sz);
+ } else if (cpu_is_omap16xx()) {
+ omap_sram_idle = omap_sram_push(omap1610_idle_loop_suspend,
+ omap1610_idle_loop_suspend_sz);
+ omap_sram_suspend = omap_sram_push(omap1610_cpu_suspend,
+ omap1610_cpu_suspend_sz);
+ }
+
+ if (omap_sram_idle == NULL || omap_sram_suspend == NULL) {
+ printk(KERN_ERR "PM not initialized: Missing SRAM support\n");
+ return -ENODEV;
+ }
+
+ pm_idle = omap_pm_idle;
+
+ if (cpu_is_omap730())
+ setup_irq(INT_730_WAKE_UP_REQ, &omap_wakeup_irq);
+ else if (cpu_is_omap16xx())
+ setup_irq(INT_1610_WAKE_UP_REQ, &omap_wakeup_irq);
+
+ /* Program new power ramp-up time
+ * (0 for most boards since we don't lower voltage when in deep sleep)
+ */
+ omap_writew(ULPD_SETUP_ANALOG_CELL_3_VAL, ULPD_SETUP_ANALOG_CELL_3);
+
+ /* Setup ULPD POWER_CTRL_REG - enter deep sleep whenever possible */
+ omap_writew(ULPD_POWER_CTRL_REG_VAL, ULPD_POWER_CTRL);
+
+ /* Configure IDLECT3 */
+ if (cpu_is_omap730())
+ omap_writel(OMAP730_IDLECT3_VAL, OMAP730_IDLECT3);
+ else if (cpu_is_omap16xx())
+ omap_writel(OMAP1610_IDLECT3_VAL, OMAP1610_IDLECT3);
+
+ pm_set_ops(&omap_pm_ops);
+
+#if defined(DEBUG) && defined(CONFIG_PROC_FS)
+ omap_pm_init_proc();
+#endif
+
+ subsys_create_file(&power_subsys, &sleep_while_idle_attr);
+
+ if (cpu_is_omap16xx()) {
+ /* configure LOW_PWR pin */
+ omap_cfg_reg(T20_1610_LOW_PWR);
+ }
+
+ return 0;
+}
+__initcall(omap_pm_init);
diff --git a/arch/arm/mach-omap1/serial.c b/arch/arm/mach-omap1/serial.c
index e924e0c6a4c..9b4cd698bec 100644
--- a/arch/arm/mach-omap1/serial.c
+++ b/arch/arm/mach-omap1/serial.c
@@ -30,9 +30,9 @@
#include <asm/arch/pm.h>
#endif
-static struct clk * uart1_ck = NULL;
-static struct clk * uart2_ck = NULL;
-static struct clk * uart3_ck = NULL;
+static struct clk * uart1_ck;
+static struct clk * uart2_ck;
+static struct clk * uart3_ck;
static inline unsigned int omap_serial_in(struct plat_serial8250_port *up,
int offset)
diff --git a/arch/arm/plat-omap/sleep.S b/arch/arm/mach-omap1/sleep.S
index 4cd7d292f85..e58295e2d3b 100644
--- a/arch/arm/plat-omap/sleep.S
+++ b/arch/arm/mach-omap1/sleep.S
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/plat-omap/sleep.S
+ * linux/arch/arm/mach-omap1/sleep.S
*
* Low-level OMAP730/1510/1610 sleep/wakeUp support
*
@@ -383,60 +383,133 @@ ENTRY(omap1610_cpu_suspend)
mcr p15, 0, r0, c7, c10, 4
nop
- @ load base address of Traffic Controller
+ @ Load base address of Traffic Controller
mov r6, #TCMIF_ASM_BASE & 0xff000000
orr r6, r6, #TCMIF_ASM_BASE & 0x00ff0000
orr r6, r6, #TCMIF_ASM_BASE & 0x0000ff00
- @ prepare to put SDRAM into self-refresh manually
+ @ Prepare to put SDRAM into self-refresh manually
ldr r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
orr r9, r7, #SELF_REFRESH_MODE & 0xff000000
orr r9, r9, #SELF_REFRESH_MODE & 0x000000ff
str r9, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
- @ prepare to put EMIFS to Sleep
+ @ Prepare to put EMIFS to Sleep
ldr r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
orr r9, r8, #IDLE_EMIFS_REQUEST & 0xff
str r9, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
- @ load base address of ARM_IDLECT1 and ARM_IDLECT2
+ @ Load base address of ARM_IDLECT1 and ARM_IDLECT2
mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000
orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000
orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00
- @ turn off clock domains
- @ do not disable PERCK (0x04)
+ @ Turn off clock domains
+ @ Do not disable PERCK (0x04)
mov r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff
orr r5, r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff00
strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
- @ request ARM idle
+ @ Request ARM idle
mov r3, #OMAP1610_IDLECT1_SLEEP_VAL & 0xff
orr r3, r3, #OMAP1610_IDLECT1_SLEEP_VAL & 0xff00
strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
- @ disable instruction cache
- mrc p15, 0, r9, c1, c0, 0
- bic r2, r9, #0x1000
- mcr p15, 0, r2, c1, c0, 0
- nop
-
/*
* Let's wait for the next wake up event to wake us up. r0 can't be
* used here because r0 holds ARM_IDLECT1
*/
mov r2, #0
mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt
+
+ @ Errata (HEL3SU467, section 1.4.4) specifies nop-instructions
+ @ according to this formula:
+ @ 2 + (4*DPLL_MULT)/DPLL_DIV/ARMDIV
+ @ Max DPLL_MULT = 18
+ @ DPLL_DIV = 1
+ @ ARMDIV = 1
+ @ => 74 nop-instructions
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop @10
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop @20
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop @30
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop @40
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop @50
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop @60
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop @70
+ nop
+ nop
+ nop
+ nop @74
/*
* omap1610_cpu_suspend()'s resume point.
*
* It will just start executing here, so we'll restore stuff from the
* stack.
*/
- @ re-enable Icache
- mcr p15, 0, r9, c1, c0, 0
-
- @ reset the ARM_IDLECT1 and ARM_IDLECT2.
+ @ Restore the ARM_IDLECT1 and ARM_IDLECT2.
strh r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
strh r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
@@ -444,7 +517,7 @@ ENTRY(omap1610_cpu_suspend)
str r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
str r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
- @ restore regs and return
+ @ Restore regs and return
ldmfd sp!, {r0 - r12, pc}
ENTRY(omap1610_cpu_suspend_sz)
diff --git a/arch/arm/mach-omap1/time.c b/arch/arm/mach-omap1/time.c
index cdbf4d7620c..a85fe6066bc 100644
--- a/arch/arm/mach-omap1/time.c
+++ b/arch/arm/mach-omap1/time.c
@@ -51,8 +51,6 @@
struct sys_timer omap_timer;
-#ifdef CONFIG_OMAP_MPU_TIMER
-
/*
* ---------------------------------------------------------------------------
* MPU timer
@@ -222,195 +220,6 @@ unsigned long long sched_clock(void)
return cycles_2_ns(ticks64);
}
-#endif /* CONFIG_OMAP_MPU_TIMER */
-
-#ifdef CONFIG_OMAP_32K_TIMER
-
-#ifdef CONFIG_ARCH_OMAP15XX
-#error OMAP 32KHz timer does not currently work on 15XX!
-#endif
-
-/*
- * ---------------------------------------------------------------------------
- * 32KHz OS timer
- *
- * This currently works only on 16xx, as 1510 does not have the continuous
- * 32KHz synchronous timer. The 32KHz synchronous timer is used to keep track
- * of time in addition to the 32KHz OS timer. Using only the 32KHz OS timer
- * on 1510 would be possible, but the timer would not be as accurate as
- * with the 32KHz synchronized timer.
- * ---------------------------------------------------------------------------
- */
-#define OMAP_32K_TIMER_BASE 0xfffb9000
-#define OMAP_32K_TIMER_CR 0x08
-#define OMAP_32K_TIMER_TVR 0x00
-#define OMAP_32K_TIMER_TCR 0x04
-
-#define OMAP_32K_TICKS_PER_HZ (32768 / HZ)
-
-/*
- * TRM says 1 / HZ = ( TVR + 1) / 32768, so TRV = (32768 / HZ) - 1
- * so with HZ = 100, TVR = 327.68.
- */
-#define OMAP_32K_TIMER_TICK_PERIOD ((32768 / HZ) - 1)
-#define TIMER_32K_SYNCHRONIZED 0xfffbc410
-
-#define JIFFIES_TO_HW_TICKS(nr_jiffies, clock_rate) \
- (((nr_jiffies) * (clock_rate)) / HZ)
-
-static inline void omap_32k_timer_write(int val, int reg)
-{
- omap_writew(val, reg + OMAP_32K_TIMER_BASE);
-}
-
-static inline unsigned long omap_32k_timer_read(int reg)
-{
- return omap_readl(reg + OMAP_32K_TIMER_BASE) & 0xffffff;
-}
-
-/*
- * The 32KHz synchronized timer is an additional timer on 16xx.
- * It is always running.
- */
-static inline unsigned long omap_32k_sync_timer_read(void)
-{
- return omap_readl(TIMER_32K_SYNCHRONIZED);
-}
-
-static inline void omap_32k_timer_start(unsigned long load_val)
-{
- omap_32k_timer_write(load_val, OMAP_32K_TIMER_TVR);
- omap_32k_timer_write(0x0f, OMAP_32K_TIMER_CR);
-}
-
-static inline void omap_32k_timer_stop(void)
-{
- omap_32k_timer_write(0x0, OMAP_32K_TIMER_CR);
-}
-
-/*
- * Rounds down to nearest usec. Note that this will overflow for larger values.
- */
-static inline unsigned long omap_32k_ticks_to_usecs(unsigned long ticks_32k)
-{
- return (ticks_32k * 5*5*5*5*5*5) >> 9;
-}
-
-/*
- * Rounds down to nearest nsec.
- */
-static inline unsigned long long
-omap_32k_ticks_to_nsecs(unsigned long ticks_32k)
-{
- return (unsigned long long) ticks_32k * 1000 * 5*5*5*5*5*5 >> 9;
-}
-
-static unsigned long omap_32k_last_tick = 0;
-
-/*
- * Returns elapsed usecs since last 32k timer interrupt
- */
-static unsigned long omap_32k_timer_gettimeoffset(void)
-{
- unsigned long now = omap_32k_sync_timer_read();
- return omap_32k_ticks_to_usecs(now - omap_32k_last_tick);
-}
-
-/*
- * Returns current time from boot in nsecs. It's OK for this to wrap
- * around for now, as it's just a relative time stamp.
- */
-unsigned long long sched_clock(void)
-{
- return omap_32k_ticks_to_nsecs(omap_32k_sync_timer_read());
-}
-
-/*
- * Timer interrupt for 32KHz timer. When dynamic tick is enabled, this
- * function is also called from other interrupts to remove latency
- * issues with dynamic tick. In the dynamic tick case, we need to lock
- * with irqsave.
- */
-static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
-{
- unsigned long flags;
- unsigned long now;
-
- write_seqlock_irqsave(&xtime_lock, flags);
- now = omap_32k_sync_timer_read();
-
- while (now - omap_32k_last_tick >= OMAP_32K_TICKS_PER_HZ) {
- omap_32k_last_tick += OMAP_32K_TICKS_PER_HZ;
- timer_tick(regs);
- }
-
- /* Restart timer so we don't drift off due to modulo or dynamic tick.
- * By default we program the next timer to be continuous to avoid
- * latencies during high system load. During dynamic tick operation the
- * continuous timer can be overridden from pm_idle to be longer.
- */
- omap_32k_timer_start(omap_32k_last_tick + OMAP_32K_TICKS_PER_HZ - now);
- write_sequnlock_irqrestore(&xtime_lock, flags);
-
- return IRQ_HANDLED;
-}
-
-#ifdef CONFIG_NO_IDLE_HZ
-/*
- * Programs the next timer interrupt needed. Called when dynamic tick is
- * enabled, and to reprogram the ticks to skip from pm_idle. Note that
- * we can keep the timer continuous, and don't need to set it to run in
- * one-shot mode. This is because the timer will get reprogrammed again
- * after next interrupt.
- */
-void omap_32k_timer_reprogram(unsigned long next_tick)
-{
- omap_32k_timer_start(JIFFIES_TO_HW_TICKS(next_tick, 32768) + 1);
-}
-
-static struct irqaction omap_32k_timer_irq;
-extern struct timer_update_handler timer_update;
-
-static int omap_32k_timer_enable_dyn_tick(void)
-{
- /* No need to reprogram timer, just use the next interrupt */
- return 0;
-}
-
-static int omap_32k_timer_disable_dyn_tick(void)
-{
- omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD);
- return 0;
-}
-
-static struct dyn_tick_timer omap_dyn_tick_timer = {
- .enable = omap_32k_timer_enable_dyn_tick,
- .disable = omap_32k_timer_disable_dyn_tick,
- .reprogram = omap_32k_timer_reprogram,
- .handler = omap_32k_timer_interrupt,
-};
-#endif /* CONFIG_NO_IDLE_HZ */
-
-static struct irqaction omap_32k_timer_irq = {
- .name = "32KHz timer",
- .flags = SA_INTERRUPT | SA_TIMER,
- .handler = omap_32k_timer_interrupt,
-};
-
-static __init void omap_init_32k_timer(void)
-{
-
-#ifdef CONFIG_NO_IDLE_HZ
- omap_timer.dyn_tick = &omap_dyn_tick_timer;
-#endif
-
- setup_irq(INT_OS_TIMER, &omap_32k_timer_irq);
- omap_timer.offset = omap_32k_timer_gettimeoffset;
- omap_32k_last_tick = omap_32k_sync_timer_read();
- omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD);
-}
-#endif /* CONFIG_OMAP_32K_TIMER */
/*
* ---------------------------------------------------------------------------
@@ -419,13 +228,7 @@ static __init void omap_init_32k_timer(void)
*/
static void __init omap_timer_init(void)
{
-#if defined(CONFIG_OMAP_MPU_TIMER)
omap_init_mpu_timer();
-#elif defined(CONFIG_OMAP_32K_TIMER)
- omap_init_32k_timer();
-#else
-#error No system timer selected in Kconfig!
-#endif
}
struct sys_timer omap_timer = {
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index 578880943cf..537dd2e6d38 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -20,3 +20,6 @@ config MACH_OMAP_H4
bool "OMAP 2420 H4 board"
depends on ARCH_OMAP2 && ARCH_OMAP24XX
+config MACH_OMAP_APOLLON
+ bool "OMAP 2420 Apollon board"
+ depends on ARCH_OMAP2 && ARCH_OMAP24XX
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 42041166435..111eaa64258 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -3,11 +3,15 @@
#
# Common support
-obj-y := irq.o id.o io.o sram-fn.o clock.o mux.o devices.o serial.o
+obj-y := irq.o id.o io.o sram-fn.o memory.o prcm.o clock.o mux.o devices.o serial.o
obj-$(CONFIG_OMAP_MPU_TIMER) += timer-gp.o
+# Power Management
+obj-$(CONFIG_PM) += pm.o sleep.o
+
# Specific board support
obj-$(CONFIG_MACH_OMAP_GENERIC) += board-generic.o
obj-$(CONFIG_MACH_OMAP_H4) += board-h4.o
+obj-$(CONFIG_MACH_OMAP_APOLLON) += board-apollon.o
diff --git a/arch/arm/mach-omap2/board-apollon.c b/arch/arm/mach-omap2/board-apollon.c
new file mode 100644
index 00000000000..6c6ba172cdf
--- /dev/null
+++ b/arch/arm/mach-omap2/board-apollon.c
@@ -0,0 +1,285 @@
+/*
+ * linux/arch/arm/mach-omap/omap2/board-apollon.c
+ *
+ * Copyright (C) 2005,2006 Samsung Electronics
+ * Author: Kyungmin Park <kyungmin.park@samsung.com>
+ *
+ * Modified from mach-omap/omap2/board-h4.c
+ *
+ * Code for apollon OMAP2 board. Should work on many OMAP2 systems where
+ * the bootloader passes the board-specific data to the kernel.
+ * Do not put any board specific code to this file; create a new machine
+ * type if you need custom low-level initializations.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/onenand.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/flash.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/usb.h>
+#include <asm/arch/board.h>
+#include <asm/arch/common.h>
+#include "prcm-regs.h"
+
+/* LED & Switch macros */
+#define LED0_GPIO13 13
+#define LED1_GPIO14 14
+#define LED2_GPIO15 15
+#define SW_ENTER_GPIO16 16
+#define SW_UP_GPIO17 17
+#define SW_DOWN_GPIO58 58
+
+static struct mtd_partition apollon_partitions[] = {
+ {
+ .name = "X-Loader + U-Boot",
+ .offset = 0,
+ .size = SZ_128K,
+ .mask_flags = MTD_WRITEABLE,
+ },
+ {
+ .name = "params",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_128K,
+ },
+ {
+ .name = "kernel",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_2M,
+ },
+ {
+ .name = "rootfs",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_16M,
+ },
+ {
+ .name = "filesystem00",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_32M,
+ },
+ {
+ .name = "filesystem01",
+ .offset = MTDPART_OFS_APPEND,
+ .size = MTDPART_SIZ_FULL,
+ },
+};
+
+static struct flash_platform_data apollon_flash_data = {
+ .parts = apollon_partitions,
+ .nr_parts = ARRAY_SIZE(apollon_partitions),
+};
+
+static struct resource apollon_flash_resource = {
+ .start = APOLLON_CS0_BASE,
+ .end = APOLLON_CS0_BASE + SZ_128K,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device apollon_onenand_device = {
+ .name = "onenand",
+ .id = -1,
+ .dev = {
+ .platform_data = &apollon_flash_data,
+ },
+ .num_resources = ARRAY_SIZE(&apollon_flash_resource),
+ .resource = &apollon_flash_resource,
+};
+
+static struct resource apollon_smc91x_resources[] = {
+ [0] = {
+ .start = APOLLON_ETHR_START, /* Physical */
+ .end = APOLLON_ETHR_START + 0xf,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = OMAP_GPIO_IRQ(APOLLON_ETHR_GPIO_IRQ),
+ .end = OMAP_GPIO_IRQ(APOLLON_ETHR_GPIO_IRQ),
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device apollon_smc91x_device = {
+ .name = "smc91x",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(apollon_smc91x_resources),
+ .resource = apollon_smc91x_resources,
+};
+
+static struct platform_device apollon_lcd_device = {
+ .name = "apollon_lcd",
+ .id = -1,
+};
+
+static struct platform_device *apollon_devices[] __initdata = {
+ &apollon_onenand_device,
+ &apollon_smc91x_device,
+ &apollon_lcd_device,
+};
+
+static inline void __init apollon_init_smc91x(void)
+{
+ /* Make sure CS1 timings are correct */
+ GPMC_CONFIG1_1 = 0x00011203;
+ GPMC_CONFIG2_1 = 0x001f1f01;
+ GPMC_CONFIG3_1 = 0x00080803;
+ GPMC_CONFIG4_1 = 0x1c091c09;
+ GPMC_CONFIG5_1 = 0x041f1f1f;
+ GPMC_CONFIG6_1 = 0x000004c4;
+ GPMC_CONFIG7_1 = 0x00000f40 | (APOLLON_CS1_BASE >> 24);
+ udelay(100);
+
+ omap_cfg_reg(W4__24XX_GPIO74);
+ if (omap_request_gpio(APOLLON_ETHR_GPIO_IRQ) < 0) {
+ printk(KERN_ERR "Failed to request GPIO%d for smc91x IRQ\n",
+ APOLLON_ETHR_GPIO_IRQ);
+ return;
+ }
+ omap_set_gpio_direction(APOLLON_ETHR_GPIO_IRQ, 1);
+}
+
+static void __init omap_apollon_init_irq(void)
+{
+ omap2_init_common_hw();
+ omap_init_irq();
+ omap_gpio_init();
+ apollon_init_smc91x();
+}
+
+static struct omap_uart_config apollon_uart_config __initdata = {
+ .enabled_uarts = (1 << 0) | (0 << 1) | (0 << 2),
+};
+
+static struct omap_mmc_config apollon_mmc_config __initdata = {
+ .mmc [0] = {
+ .enabled = 0,
+ .wire4 = 0,
+ .wp_pin = -1,
+ .power_pin = -1,
+ .switch_pin = -1,
+ },
+};
+
+static struct omap_lcd_config apollon_lcd_config __initdata = {
+ .ctrl_name = "internal",
+};
+
+static struct omap_board_config_kernel apollon_config[] = {
+ { OMAP_TAG_UART, &apollon_uart_config },
+ { OMAP_TAG_MMC, &apollon_mmc_config },
+ { OMAP_TAG_LCD, &apollon_lcd_config },
+};
+
+static void __init apollon_led_init(void)
+{
+ /* LED0 - AA10 */
+ omap_cfg_reg(AA10_242X_GPIO13);
+ omap_request_gpio(LED0_GPIO13);
+ omap_set_gpio_direction(LED0_GPIO13, 0);
+ omap_set_gpio_dataout(LED0_GPIO13, 0);
+ /* LED1 - AA6 */
+ omap_cfg_reg(AA6_242X_GPIO14);
+ omap_request_gpio(LED1_GPIO14);
+ omap_set_gpio_direction(LED1_GPIO14, 0);
+ omap_set_gpio_dataout(LED1_GPIO14, 0);
+ /* LED2 - AA4 */
+ omap_cfg_reg(AA4_242X_GPIO15);
+ omap_request_gpio(LED2_GPIO15);
+ omap_set_gpio_direction(LED2_GPIO15, 0);
+ omap_set_gpio_dataout(LED2_GPIO15, 0);
+}
+
+static irqreturn_t apollon_sw_interrupt(int irq, void *ignored, struct pt_regs *regs)
+{
+ static unsigned int led0, led1, led2;
+
+ if (irq == OMAP_GPIO_IRQ(SW_ENTER_GPIO16))
+ omap_set_gpio_dataout(LED0_GPIO13, led0 ^= 1);
+ else if (irq == OMAP_GPIO_IRQ(SW_UP_GPIO17))
+ omap_set_gpio_dataout(LED1_GPIO14, led1 ^= 1);
+ else if (irq == OMAP_GPIO_IRQ(SW_DOWN_GPIO58))
+ omap_set_gpio_dataout(LED2_GPIO15, led2 ^= 1);
+
+ return IRQ_HANDLED;
+}
+
+static void __init apollon_sw_init(void)
+{
+ /* Enter SW - Y11 */
+ omap_cfg_reg(Y11_242X_GPIO16);
+ omap_request_gpio(SW_ENTER_GPIO16);
+ omap_set_gpio_direction(SW_ENTER_GPIO16, 1);
+ /* Up SW - AA12 */
+ omap_cfg_reg(AA12_242X_GPIO17);
+ omap_request_gpio(SW_UP_GPIO17);
+ omap_set_gpio_direction(SW_UP_GPIO17, 1);
+ /* Down SW - AA8 */
+ omap_cfg_reg(AA8_242X_GPIO58);
+ omap_request_gpio(SW_DOWN_GPIO58);
+ omap_set_gpio_direction(SW_DOWN_GPIO58, 1);
+
+ set_irq_type(OMAP_GPIO_IRQ(SW_ENTER_GPIO16), IRQT_RISING);
+ if (request_irq(OMAP_GPIO_IRQ(SW_ENTER_GPIO16), &apollon_sw_interrupt,
+ SA_SHIRQ, "enter sw",
+ &apollon_sw_interrupt))
+ return;
+ set_irq_type(OMAP_GPIO_IRQ(SW_UP_GPIO17), IRQT_RISING);
+ if (request_irq(OMAP_GPIO_IRQ(SW_UP_GPIO17), &apollon_sw_interrupt,
+ SA_SHIRQ, "up sw",
+ &apollon_sw_interrupt))
+ return;
+ set_irq_type(OMAP_GPIO_IRQ(SW_DOWN_GPIO58), IRQT_RISING);
+ if (request_irq(OMAP_GPIO_IRQ(SW_DOWN_GPIO58), &apollon_sw_interrupt,
+ SA_SHIRQ, "down sw",
+ &apollon_sw_interrupt))
+ return;
+}
+
+static void __init omap_apollon_init(void)
+{
+ apollon_led_init();
+ apollon_sw_init();
+
+ /* REVISIT: where's the correct place */
+ omap_cfg_reg(W19_24XX_SYS_NIRQ);
+
+ /*
+ * Make sure the serial ports are muxed on at this point.
+ * You have to mux them off in device drivers later on
+ * if not needed.
+ */
+ platform_add_devices(apollon_devices, ARRAY_SIZE(apollon_devices));
+ omap_board_config = apollon_config;
+ omap_board_config_size = ARRAY_SIZE(apollon_config);
+ omap_serial_init();
+}
+
+static void __init omap_apollon_map_io(void)
+{
+ omap2_map_common_io();
+}
+
+MACHINE_START(OMAP_APOLLON, "OMAP24xx Apollon")
+ /* Maintainer: Kyungmin Park <kyungmin.park@samsung.com> */
+ .phys_io = 0x48000000,
+ .io_pg_offst = ((0xd8000000) >> 18) & 0xfffc,
+ .boot_params = 0x80000100,
+ .map_io = omap_apollon_map_io,
+ .init_irq = omap_apollon_init_irq,
+ .init_machine = omap_apollon_init,
+ .timer = &omap_timer,
+MACHINE_END
diff --git a/arch/arm/mach-omap2/board-h4.c b/arch/arm/mach-omap2/board-h4.c
index a300d634d8a..4933fce766c 100644
--- a/arch/arm/mach-omap2/board-h4.c
+++ b/arch/arm/mach-omap2/board-h4.c
@@ -17,6 +17,8 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <linux/input.h>
#include <asm/hardware.h>
#include <asm/mach-types.h>
@@ -25,15 +27,57 @@
#include <asm/mach/flash.h>
#include <asm/arch/gpio.h>
+#include <asm/arch/gpioexpander.h>
#include <asm/arch/mux.h>
#include <asm/arch/usb.h>
+#include <asm/arch/irda.h>
#include <asm/arch/board.h>
#include <asm/arch/common.h>
-#include <asm/arch/prcm.h>
+#include <asm/arch/keypad.h>
+#include <asm/arch/menelaus.h>
+#include <asm/arch/dma.h>
+#include "prcm-regs.h"
#include <asm/io.h>
#include <asm/delay.h>
+static unsigned int row_gpios[6] = { 88, 89, 124, 11, 6, 96 };
+static unsigned int col_gpios[7] = { 90, 91, 100, 36, 12, 97, 98 };
+
+static int h4_keymap[] = {
+ KEY(0, 0, KEY_LEFT),
+ KEY(0, 1, KEY_RIGHT),
+ KEY(0, 2, KEY_A),
+ KEY(0, 3, KEY_B),
+ KEY(0, 4, KEY_C),
+ KEY(1, 0, KEY_DOWN),
+ KEY(1, 1, KEY_UP),
+ KEY(1, 2, KEY_E),
+ KEY(1, 3, KEY_F),
+ KEY(1, 4, KEY_G),
+ KEY(2, 0, KEY_ENTER),
+ KEY(2, 1, KEY_I),
+ KEY(2, 2, KEY_J),
+ KEY(2, 3, KEY_K),
+ KEY(2, 4, KEY_3),
+ KEY(3, 0, KEY_M),
+ KEY(3, 1, KEY_N),
+ KEY(3, 2, KEY_O),
+ KEY(3, 3, KEY_P),
+ KEY(3, 4, KEY_Q),
+ KEY(4, 0, KEY_R),
+ KEY(4, 1, KEY_4),
+ KEY(4, 2, KEY_T),
+ KEY(4, 3, KEY_U),
+ KEY(4, 4, KEY_ENTER),
+ KEY(5, 0, KEY_V),
+ KEY(5, 1, KEY_W),
+ KEY(5, 2, KEY_L),
+ KEY(5, 3, KEY_S),
+ KEY(5, 4, KEY_ENTER),
+ 0
+};
+
static struct mtd_partition h4_partitions[] = {
/* bootloader (U-Boot, etc) in first sector */
{
@@ -108,9 +152,123 @@ static struct platform_device h4_smc91x_device = {
.resource = h4_smc91x_resources,
};
+/* Select between the IrDA and aGPS module
+ */
+static int h4_select_irda(struct device *dev, int state)
+{
+ unsigned char expa;
+ int err = 0;
+
+ if ((err = read_gpio_expa(&expa, 0x21))) {
+ printk(KERN_ERR "Error reading from I/O expander\n");
+ return err;
+ }
+
+ /* 'P6' enable/disable IRDA_TX and IRDA_RX */
+ if (state & IR_SEL) { /* IrDa */
+ if ((err = write_gpio_expa(expa | 0x01, 0x21))) {
+ printk(KERN_ERR "Error writing to I/O expander\n");
+ return err;
+ }
+ } else {
+ if ((err = write_gpio_expa(expa & ~0x01, 0x21))) {
+ printk(KERN_ERR "Error writing to I/O expander\n");
+ return err;
+ }
+ }
+ return err;
+}
+
+static void set_trans_mode(void *data)
+{
+ int *mode = data;
+ unsigned char expa;
+ int err = 0;
+
+ if ((err = read_gpio_expa(&expa, 0x20)) != 0) {
+ printk(KERN_ERR "Error reading from I/O expander\n");
+ }
+
+ expa &= ~0x01;
+
+ if (!(*mode & IR_SIRMODE)) { /* MIR/FIR */
+ expa |= 0x01;
+ }
+
+ if ((err = write_gpio_expa(expa, 0x20)) != 0) {
+ printk(KERN_ERR "Error writing to I/O expander\n");
+ }
+}
+
+static int h4_transceiver_mode(struct device *dev, int mode)
+{
+ struct omap_irda_config *irda_config = dev->platform_data;
+
+ cancel_delayed_work(&irda_config->gpio_expa);
+ PREPARE_WORK(&irda_config->gpio_expa, set_trans_mode, &mode);
+ schedule_work(&irda_config->gpio_expa);
+
+ return 0;
+}
+
+static struct omap_irda_config h4_irda_data = {
+ .transceiver_cap = IR_SIRMODE | IR_MIRMODE | IR_FIRMODE,
+ .transceiver_mode = h4_transceiver_mode,
+ .select_irda = h4_select_irda,
+ .rx_channel = OMAP24XX_DMA_UART3_RX,
+ .tx_channel = OMAP24XX_DMA_UART3_TX,
+ .dest_start = OMAP_UART3_BASE,
+ .src_start = OMAP_UART3_BASE,
+ .tx_trigger = OMAP24XX_DMA_UART3_TX,
+ .rx_trigger = OMAP24XX_DMA_UART3_RX,
+};
+
+static struct resource h4_irda_resources[] = {
+ [0] = {
+ .start = INT_24XX_UART3_IRQ,
+ .end = INT_24XX_UART3_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device h4_irda_device = {
+ .name = "omapirda",
+ .id = -1,
+ .dev = {
+ .platform_data = &h4_irda_data,
+ },
+ .num_resources = 1,
+ .resource = h4_irda_resources,
+};
+
+static struct omap_kp_platform_data h4_kp_data = {
+ .rows = 6,
+ .cols = 7,
+ .keymap = h4_keymap,
+ .rep = 1,
+ .row_gpios = row_gpios,
+ .col_gpios = col_gpios,
+};
+
+static struct platform_device h4_kp_device = {
+ .name = "omap-keypad",
+ .id = -1,
+ .dev = {
+ .platform_data = &h4_kp_data,
+ },
+};
+
+static struct platform_device h4_lcd_device = {
+ .name = "lcd_h4",
+ .id = -1,
+};
+
static struct platform_device *h4_devices[] __initdata = {
&h4_smc91x_device,
&h4_flash_device,
+ &h4_irda_device,
+ &h4_kp_device,
+ &h4_lcd_device,
};
static inline void __init h4_init_smc91x(void)
@@ -157,7 +315,6 @@ static struct omap_mmc_config h4_mmc_config __initdata = {
};
static struct omap_lcd_config h4_lcd_config __initdata = {
- .panel_name = "h4",
.ctrl_name = "internal",
};
@@ -174,6 +331,19 @@ static void __init omap_h4_init(void)
* You have to mux them off in device drivers later on
* if not needed.
*/
+#if defined(CONFIG_OMAP_IR) || defined(CONFIG_OMAP_IR_MODULE)
+ omap_cfg_reg(K15_24XX_UART3_TX);
+ omap_cfg_reg(K14_24XX_UART3_RX);
+#endif
+
+#if defined(CONFIG_KEYBOARD_OMAP) || defined(CONFIG_KEYBOARD_OMAP_MODULE)
+ if (omap_has_menelaus()) {
+ row_gpios[5] = 0;
+ col_gpios[2] = 15;
+ col_gpios[6] = 18;
+ }
+#endif
+
platform_add_devices(h4_devices, ARRAY_SIZE(h4_devices));
omap_board_config = h4_config;
omap_board_config_size = ARRAY_SIZE(h4_config);
diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c
index 180f675c906..72eb4bf571a 100644
--- a/arch/arm/mach-omap2/clock.c
+++ b/arch/arm/mach-omap2/clock.c
@@ -28,14 +28,14 @@
#include <asm/arch/clock.h>
#include <asm/arch/sram.h>
-#include <asm/arch/prcm.h>
+#include "prcm-regs.h"
+#include "memory.h"
#include "clock.h"
//#define DOWN_VARIABLE_DPLL 1 /* Experimental */
static struct prcm_config *curr_prcm_set;
-static struct memory_timings mem_timings;
static u32 curr_perf_level = PRCM_FULL_SPEED;
/*-------------------------------------------------------------------------
@@ -54,11 +54,13 @@ static void omap2_sys_clk_recalc(struct clk * clk)
static u32 omap2_get_dpll_rate(struct clk * tclk)
{
- int dpll_clk, dpll_mult, dpll_div, amult;
+ long long dpll_clk;
+ int dpll_mult, dpll_div, amult;
dpll_mult = (CM_CLKSEL1_PLL >> 12) & 0x03ff; /* 10 bits */
dpll_div = (CM_CLKSEL1_PLL >> 8) & 0x0f; /* 4 bits */
- dpll_clk = (tclk->parent->rate * dpll_mult) / (dpll_div + 1);
+ dpll_clk = (long long)tclk->parent->rate * dpll_mult;
+ do_div(dpll_clk, dpll_div + 1);
amult = CM_CLKSEL2_PLL & 0x3;
dpll_clk *= amult;
@@ -385,75 +387,23 @@ static u32 omap2_dll_force_needed(void)
return 0;
}
-static void omap2_init_memory_params(u32 force_lock_to_unlock_mode)
-{
- unsigned long dll_cnt;
- u32 fast_dll = 0;
-
- mem_timings.m_type = !((SDRC_MR_0 & 0x3) == 0x1); /* DDR = 1, SDR = 0 */
-
- /* 2422 es2.05 and beyond has a single SIP DDR instead of 2 like others.
- * In the case of 2422, its ok to use CS1 instead of CS0.
- */
-
-#if 0 /* FIXME: Enable after 24xx cpu detection works */
- ctype = get_cpu_type();
- if (cpu_is_omap2422())
- mem_timings.base_cs = 1;
- else
-#endif
- mem_timings.base_cs = 0;
-
- if (mem_timings.m_type != M_DDR)
- return;
-
- /* With DDR we need to determine the low frequency DLL value */
- if (((mem_timings.fast_dll_ctrl & (1 << 2)) == M_LOCK_CTRL))
- mem_timings.dll_mode = M_UNLOCK;
- else
- mem_timings.dll_mode = M_LOCK;
-
- if (mem_timings.base_cs == 0) {
- fast_dll = SDRC_DLLA_CTRL;
- dll_cnt = SDRC_DLLA_STATUS & 0xff00;
- } else {
- fast_dll = SDRC_DLLB_CTRL;
- dll_cnt = SDRC_DLLB_STATUS & 0xff00;
- }
- if (force_lock_to_unlock_mode) {
- fast_dll &= ~0xff00;
- fast_dll |= dll_cnt; /* Current lock mode */
- }
- mem_timings.fast_dll_ctrl = fast_dll;
-
- /* No disruptions, DDR will be offline & C-ABI not followed */
- omap2_sram_ddr_init(&mem_timings.slow_dll_ctrl,
- mem_timings.fast_dll_ctrl,
- mem_timings.base_cs,
- force_lock_to_unlock_mode);
- mem_timings.slow_dll_ctrl &= 0xff00; /* Keep lock value */
-
- /* Turn status into unlock ctrl */
- mem_timings.slow_dll_ctrl |=
- ((mem_timings.fast_dll_ctrl & 0xF) | (1 << 2));
-
- /* 90 degree phase for anything below 133Mhz */
- mem_timings.slow_dll_ctrl |= (1 << 1);
-}
-
static u32 omap2_reprogram_sdrc(u32 level, u32 force)
{
+ u32 slow_dll_ctrl, fast_dll_ctrl, m_type;
u32 prev = curr_perf_level, flags;
if ((curr_perf_level == level) && !force)
return prev;
+ m_type = omap2_memory_get_type();
+ slow_dll_ctrl = omap2_memory_get_slow_dll_ctrl();
+ fast_dll_ctrl = omap2_memory_get_fast_dll_ctrl();
+
if (level == PRCM_HALF_SPEED) {
local_irq_save(flags);
PRCM_VOLTSETUP = 0xffff;
omap2_sram_reprogram_sdrc(PRCM_HALF_SPEED,
- mem_timings.slow_dll_ctrl,
- mem_timings.m_type);
+ slow_dll_ctrl, m_type);
curr_perf_level = PRCM_HALF_SPEED;
local_irq_restore(flags);
}
@@ -461,8 +411,7 @@ static u32 omap2_reprogram_sdrc(u32 level, u32 force)
local_irq_save(flags);
PRCM_VOLTSETUP = 0xffff;
omap2_sram_reprogram_sdrc(PRCM_FULL_SPEED,
- mem_timings.fast_dll_ctrl,
- mem_timings.m_type);
+ fast_dll_ctrl, m_type);
curr_perf_level = PRCM_FULL_SPEED;
local_irq_restore(flags);
}
@@ -650,7 +599,7 @@ static u32 omap2_get_clksel(u32 *div_sel, u32 *field_mask,
case 13: /* dss2 */
mask = 0x1; break;
case 25: /* usb */
- mask = 0xf; break;
+ mask = 0x7; break;
}
}
diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h
index 6cab20b1d3c..6c78d471fab 100644
--- a/arch/arm/mach-omap2/clock.h
+++ b/arch/arm/mach-omap2/clock.h
@@ -33,20 +33,6 @@ static u32 omap2_clksel_get_divisor(struct clk *clk);
#define RATE_IN_242X (1 << 0)
#define RATE_IN_243X (1 << 1)
-/* Memory timings */
-#define M_DDR 1
-#define M_LOCK_CTRL (1 << 2)
-#define M_UNLOCK 0
-#define M_LOCK 1
-
-struct memory_timings {
- u32 m_type; /* ddr = 1, sdr = 0 */
- u32 dll_mode; /* use lock mode = 1, unlock mode = 0 */
- u32 slow_dll_ctrl; /* unlock mode, dll value for slow speed */
- u32 fast_dll_ctrl; /* unlock mode, dll value for fast speed */
- u32 base_cs; /* base chip select to use for calculations */
-};
-
/* Key dividers which make up a PRCM set. Ratio's for a PRCM are mandated.
* xtal_speed, dpll_speed, mpu_speed, CM_CLKSEL_MPU,CM_CLKSEL_DSP
* CM_CLKSEL_GFX, CM_CLKSEL1_CORE, CM_CLKSEL1_PLL CM_CLKSEL2_PLL, CM_CLKSEL_MDM
@@ -731,6 +717,16 @@ static struct clk sys_clkout2 = {
.recalc = &omap2_clksel_recalc,
};
+static struct clk emul_ck = {
+ .name = "emul_ck",
+ .parent = &func_54m_ck,
+ .flags = CLOCK_IN_OMAP242X,
+ .enable_reg = (void __iomem *)&PRCM_CLKEMUL_CTRL,
+ .enable_bit = 0,
+ .recalc = &omap2_propagate_rate,
+
+};
+
/*
* MPU clock domain
* Clocks:
@@ -1702,7 +1698,8 @@ static struct clk hdq_fck = {
};
static struct clk i2c2_ick = {
- .name = "i2c2_ick",
+ .name = "i2c_ick",
+ .id = 2,
.parent = &l4_ck,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
.enable_reg = (void __iomem *)&CM_ICLKEN1_CORE,
@@ -1711,7 +1708,8 @@ static struct clk i2c2_ick = {
};
static struct clk i2c2_fck = {
- .name = "i2c2_fck",
+ .name = "i2c_fck",
+ .id = 2,
.parent = &func_12m_ck,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
.enable_reg = (void __iomem *)&CM_FCLKEN1_CORE,
@@ -1729,7 +1727,8 @@ static struct clk i2chs2_fck = {
};
static struct clk i2c1_ick = {
- .name = "i2c1_ick",
+ .name = "i2c_ick",
+ .id = 1,
.parent = &l4_ck,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
.enable_reg = (void __iomem *)&CM_ICLKEN1_CORE,
@@ -1738,7 +1737,8 @@ static struct clk i2c1_ick = {
};
static struct clk i2c1_fck = {
- .name = "i2c1_fck",
+ .name = "i2c_fck",
+ .id = 1,
.parent = &func_12m_ck,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
.enable_reg = (void __iomem *)&CM_FCLKEN1_CORE,
@@ -1971,6 +1971,7 @@ static struct clk *onchip_clks[] = {
&wdt1_osc_ck,
&sys_clkout,
&sys_clkout2,
+ &emul_ck,
/* mpu domain clocks */
&mpu_ck,
/* dsp domain clocks */
diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
index 7181edb8935..def9e5370ed 100644
--- a/arch/arm/mach-omap2/devices.c
+++ b/arch/arm/mach-omap2/devices.c
@@ -74,6 +74,47 @@ static void omap_init_i2c(void) {}
#endif
+#if defined(CONFIG_OMAP_STI)
+
+#define OMAP2_STI_BASE IO_ADDRESS(0x48068000)
+#define OMAP2_STI_CHANNEL_BASE 0x54000000
+#define OMAP2_STI_IRQ 4
+
+static struct resource sti_resources[] = {
+ {
+ .start = OMAP2_STI_BASE,
+ .end = OMAP2_STI_BASE + 0x7ff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = OMAP2_STI_CHANNEL_BASE,
+ .end = OMAP2_STI_CHANNEL_BASE + SZ_64K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = OMAP2_STI_IRQ,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static struct platform_device sti_device = {
+ .name = "sti",
+ .id = -1,
+ .dev = {
+ .release = omap_nop_release,
+ },
+ .num_resources = ARRAY_SIZE(sti_resources),
+ .resource = sti_resources,
+};
+
+static inline void omap_init_sti(void)
+{
+ platform_device_register(&sti_device);
+}
+#else
+static inline void omap_init_sti(void) {}
+#endif
+
/*-------------------------------------------------------------------------*/
static int __init omap2_init_devices(void)
@@ -82,6 +123,7 @@ static int __init omap2_init_devices(void)
* in alphabetical order so they're easier to sort through.
*/
omap_init_i2c();
+ omap_init_sti();
return 0;
}
diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c
index 8ea67bf196a..7d5711611f2 100644
--- a/arch/arm/mach-omap2/io.c
+++ b/arch/arm/mach-omap2/io.c
@@ -16,9 +16,13 @@
#include <linux/kernel.h>
#include <linux/init.h>
-#include <asm/mach/map.h>
+#include <asm/tlb.h>
#include <asm/io.h>
+
+#include <asm/mach/map.h>
+
#include <asm/arch/mux.h>
+#include <asm/arch/omapfb.h>
extern void omap_sram_init(void);
extern int omap2_clk_init(void);
@@ -43,11 +47,24 @@ static struct map_desc omap2_io_desc[] __initdata = {
}
};
-void __init omap_map_common_io(void)
+void __init omap2_map_common_io(void)
{
iotable_init(omap2_io_desc, ARRAY_SIZE(omap2_io_desc));
+
+ /* Normally devicemaps_init() would flush caches and tlb after
+ * mdesc->map_io(), but we must also do it here because of the CPU
+ * revision check below.
+ */
+ local_flush_tlb_all();
+ flush_cache_all();
+
omap2_check_revision();
omap_sram_init();
+ omapfb_reserve_mem();
+}
+
+void __init omap2_init_common_hw(void)
+{
omap2_mux_init();
omap2_clk_init();
}
diff --git a/arch/arm/mach-omap2/memory.c b/arch/arm/mach-omap2/memory.c
new file mode 100644
index 00000000000..1d925d69fc3
--- /dev/null
+++ b/arch/arm/mach-omap2/memory.c
@@ -0,0 +1,102 @@
+/*
+ * linux/arch/arm/mach-omap2/memory.c
+ *
+ * Memory timing related functions for OMAP24XX
+ *
+ * Copyright (C) 2005 Texas Instruments Inc.
+ * Richard Woodruff <r-woodruff2@ti.com>
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ * Tony Lindgren <tony@atomide.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+
+#include <asm/arch/clock.h>
+#include <asm/arch/sram.h>
+
+#include "prcm-regs.h"
+#include "memory.h"
+
+static struct memory_timings mem_timings;
+
+u32 omap2_memory_get_slow_dll_ctrl(void)
+{
+ return mem_timings.slow_dll_ctrl;
+}
+
+u32 omap2_memory_get_fast_dll_ctrl(void)
+{
+ return mem_timings.fast_dll_ctrl;
+}
+
+u32 omap2_memory_get_type(void)
+{
+ return mem_timings.m_type;
+}
+
+void omap2_init_memory_params(u32 force_lock_to_unlock_mode)
+{
+ unsigned long dll_cnt;
+ u32 fast_dll = 0;
+
+ mem_timings.m_type = !((SDRC_MR_0 & 0x3) == 0x1); /* DDR = 1, SDR = 0 */
+
+ /* 2422 es2.05 and beyond has a single SIP DDR instead of 2 like others.
+ * In the case of 2422, its ok to use CS1 instead of CS0.
+ */
+ if (cpu_is_omap2422())
+ mem_timings.base_cs = 1;
+ else
+ mem_timings.base_cs = 0;
+
+ if (mem_timings.m_type != M_DDR)
+ return;
+
+ /* With DDR we need to determine the low frequency DLL value */
+ if (((mem_timings.fast_dll_ctrl & (1 << 2)) == M_LOCK_CTRL))
+ mem_timings.dll_mode = M_UNLOCK;
+ else
+ mem_timings.dll_mode = M_LOCK;
+
+ if (mem_timings.base_cs == 0) {
+ fast_dll = SDRC_DLLA_CTRL;
+ dll_cnt = SDRC_DLLA_STATUS & 0xff00;
+ } else {
+ fast_dll = SDRC_DLLB_CTRL;
+ dll_cnt = SDRC_DLLB_STATUS & 0xff00;
+ }
+ if (force_lock_to_unlock_mode) {
+ fast_dll &= ~0xff00;
+ fast_dll |= dll_cnt; /* Current lock mode */
+ }
+ /* set fast timings with DLL filter disabled */
+ mem_timings.fast_dll_ctrl = (fast_dll | (3 << 8));
+
+ /* No disruptions, DDR will be offline & C-ABI not followed */
+ omap2_sram_ddr_init(&mem_timings.slow_dll_ctrl,
+ mem_timings.fast_dll_ctrl,
+ mem_timings.base_cs,
+ force_lock_to_unlock_mode);
+ mem_timings.slow_dll_ctrl &= 0xff00; /* Keep lock value */
+
+ /* Turn status into unlock ctrl */
+ mem_timings.slow_dll_ctrl |=
+ ((mem_timings.fast_dll_ctrl & 0xF) | (1 << 2));
+
+ /* 90 degree phase for anything below 133Mhz + disable DLL filter */
+ mem_timings.slow_dll_ctrl |= ((1 << 1) | (3 << 8));
+}
diff --git a/arch/arm/mach-omap2/memory.h b/arch/arm/mach-omap2/memory.h
new file mode 100644
index 00000000000..d212eea83a0
--- /dev/null
+++ b/arch/arm/mach-omap2/memory.h
@@ -0,0 +1,34 @@
+/*
+ * linux/arch/arm/mach-omap2/memory.h
+ *
+ * Interface for memory timing related functions for OMAP24XX
+ *
+ * Copyright (C) 2005 Texas Instruments Inc.
+ * Richard Woodruff <r-woodruff2@ti.com>
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ * Tony Lindgren <tony@atomide.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/* Memory timings */
+#define M_DDR 1
+#define M_LOCK_CTRL (1 << 2)
+#define M_UNLOCK 0
+#define M_LOCK 1
+
+struct memory_timings {
+ u32 m_type; /* ddr = 1, sdr = 0 */
+ u32 dll_mode; /* use lock mode = 1, unlock mode = 0 */
+ u32 slow_dll_ctrl; /* unlock mode, dll value for slow speed */
+ u32 fast_dll_ctrl; /* unlock mode, dll value for fast speed */
+ u32 base_cs; /* base chip select to use for calculations */
+};
+
+extern void omap2_init_memory_params(u32 force_lock_to_unlock_mode);
+extern u32 omap2_memory_get_slow_dll_ctrl(void);
+extern u32 omap2_memory_get_fast_dll_ctrl(void);
+extern u32 omap2_memory_get_type(void);
diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c
index ea4654815dd..1197dc38c20 100644
--- a/arch/arm/mach-omap2/mux.c
+++ b/arch/arm/mach-omap2/mux.c
@@ -50,9 +50,54 @@ MUX_CFG_24XX("H19_24XX_I2C2_SDA", 0x114, 0, 0, 0, 1)
/* Menelaus interrupt */
MUX_CFG_24XX("W19_24XX_SYS_NIRQ", 0x12c, 0, 1, 1, 1)
+/* 24xx clocks */
+MUX_CFG_24XX("W14_24XX_SYS_CLKOUT", 0x137, 0, 1, 1, 1)
+
+/* 24xx McBSP */
+MUX_CFG_24XX("Y15_24XX_MCBSP2_CLKX", 0x124, 1, 1, 0, 1)
+MUX_CFG_24XX("R14_24XX_MCBSP2_FSX", 0x125, 1, 1, 0, 1)
+MUX_CFG_24XX("W15_24XX_MCBSP2_DR", 0x126, 1, 1, 0, 1)
+MUX_CFG_24XX("V15_24XX_MCBSP2_DX", 0x127, 1, 1, 0, 1)
+
/* 24xx GPIO */
+MUX_CFG_24XX("M21_242X_GPIO11", 0x0c9, 3, 1, 1, 1)
+MUX_CFG_24XX("AA10_242X_GPIO13", 0x0e5, 3, 0, 0, 1)
+MUX_CFG_24XX("AA6_242X_GPIO14", 0x0e6, 3, 0, 0, 1)
+MUX_CFG_24XX("AA4_242X_GPIO15", 0x0e7, 3, 0, 0, 1)
+MUX_CFG_24XX("Y11_242X_GPIO16", 0x0e8, 3, 0, 0, 1)
+MUX_CFG_24XX("AA12_242X_GPIO17", 0x0e9, 3, 0, 0, 1)
+MUX_CFG_24XX("AA8_242X_GPIO58", 0x0ea, 3, 0, 0, 1)
MUX_CFG_24XX("Y20_24XX_GPIO60", 0x12c, 3, 0, 0, 1)
+MUX_CFG_24XX("W4__24XX_GPIO74", 0x0f2, 3, 0, 0, 1)
MUX_CFG_24XX("M15_24XX_GPIO92", 0x10a, 3, 0, 0, 1)
+MUX_CFG_24XX("V14_24XX_GPIO117", 0x128, 3, 1, 0, 1)
+
+/* TSC IRQ */
+MUX_CFG_24XX("P20_24XX_TSC_IRQ", 0x108, 0, 0, 0, 1)
+
+/* UART3 */
+MUX_CFG_24XX("K15_24XX_UART3_TX", 0x118, 0, 0, 0, 1)
+MUX_CFG_24XX("K14_24XX_UART3_RX", 0x119, 0, 0, 0, 1)
+
+/* Keypad GPIO*/
+MUX_CFG_24XX("T19_24XX_KBR0", 0x106, 3, 1, 1, 1)
+MUX_CFG_24XX("R19_24XX_KBR1", 0x107, 3, 1, 1, 1)
+MUX_CFG_24XX("V18_24XX_KBR2", 0x139, 3, 1, 1, 1)
+MUX_CFG_24XX("M21_24XX_KBR3", 0xc9, 3, 1, 1, 1)
+MUX_CFG_24XX("E5__24XX_KBR4", 0x138, 3, 1, 1, 1)
+MUX_CFG_24XX("M18_24XX_KBR5", 0x10e, 3, 1, 1, 1)
+MUX_CFG_24XX("R20_24XX_KBC0", 0x108, 3, 0, 0, 1)
+MUX_CFG_24XX("M14_24XX_KBC1", 0x109, 3, 0, 0, 1)
+MUX_CFG_24XX("H19_24XX_KBC2", 0x114, 3, 0, 0, 1)
+MUX_CFG_24XX("V17_24XX_KBC3", 0x135, 3, 0, 0, 1)
+MUX_CFG_24XX("P21_24XX_KBC4", 0xca, 3, 0, 0, 1)
+MUX_CFG_24XX("L14_24XX_KBC5", 0x10f, 3, 0, 0, 1)
+MUX_CFG_24XX("N19_24XX_KBC6", 0x110, 3, 0, 0, 1)
+
+/* 24xx Menelaus Keypad GPIO */
+MUX_CFG_24XX("B3__24XX_KBR5", 0x30, 3, 1, 1, 1)
+MUX_CFG_24XX("AA4_24XX_KBC2", 0xe7, 3, 0, 0, 1)
+MUX_CFG_24XX("B13_24XX_KBC6", 0x110, 3, 0, 0, 1)
};
diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c
new file mode 100644
index 00000000000..562168fa2b1
--- /dev/null
+++ b/arch/arm/mach-omap2/pm.c
@@ -0,0 +1,149 @@
+/*
+ * linux/arch/arm/mach-omap2/pm.c
+ *
+ * OMAP2 Power Management Routines
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Tony Lindgren <tony@atomide.com>
+ *
+ * Copyright (C) 2005 Texas Instruments, Inc.
+ * Richard Woodruff <r-woodruff2@ti.com>
+ *
+ * Based on pm.c for omap1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/pm.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/pm.h>
+#include <linux/interrupt.h>
+#include <linux/sysfs.h>
+#include <linux/module.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/atomic.h>
+#include <asm/mach/time.h>
+#include <asm/mach/irq.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/irqs.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/sram.h>
+#include <asm/arch/pm.h>
+
+static struct clk *vclk;
+static void (*omap2_sram_idle)(void);
+static void (*omap2_sram_suspend)(int dllctrl, int cpu_rev);
+static void (*saved_idle)(void);
+
+void omap2_pm_idle(void)
+{
+ local_irq_disable();
+ local_fiq_disable();
+ if (need_resched()) {
+ local_fiq_enable();
+ local_irq_enable();
+ return;
+ }
+
+ /*
+ * Since an interrupt may set up a timer, we don't want to
+ * reprogram the hardware timer with interrupts enabled.
+ * Re-enable interrupts only after returning from idle.
+ */
+ timer_dyn_reprogram();
+
+ omap2_sram_idle();
+ local_fiq_enable();
+ local_irq_enable();
+}
+
+static int omap2_pm_prepare(suspend_state_t state)
+{
+ int error = 0;
+
+ /* We cannot sleep in idle until we have resumed */
+ saved_idle = pm_idle;
+ pm_idle = NULL;
+
+ switch (state)
+ {
+ case PM_SUSPEND_STANDBY:
+ case PM_SUSPEND_MEM:
+ break;
+
+ case PM_SUSPEND_DISK:
+ return -ENOTSUPP;
+
+ default:
+ return -EINVAL;
+ }
+
+ return error;
+}
+
+static int omap2_pm_enter(suspend_state_t state)
+{
+ switch (state)
+ {
+ case PM_SUSPEND_STANDBY:
+ case PM_SUSPEND_MEM:
+ /* FIXME: Add suspend */
+ break;
+
+ case PM_SUSPEND_DISK:
+ return -ENOTSUPP;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int omap2_pm_finish(suspend_state_t state)
+{
+ pm_idle = saved_idle;
+ return 0;
+}
+
+static struct pm_ops omap_pm_ops = {
+ .pm_disk_mode = 0,
+ .prepare = omap2_pm_prepare,
+ .enter = omap2_pm_enter,
+ .finish = omap2_pm_finish,
+};
+
+int __init omap2_pm_init(void)
+{
+ printk("Power Management for TI OMAP.\n");
+
+ vclk = clk_get(NULL, "virt_prcm_set");
+ if (IS_ERR(vclk)) {
+ printk(KERN_ERR "Could not get PM vclk\n");
+ return -ENODEV;
+ }
+
+ /*
+ * We copy the assembler sleep/wakeup routines to SRAM.
+ * These routines need to be in SRAM as that's the only
+ * memory the MPU can see when it wakes up.
+ */
+ omap2_sram_idle = omap_sram_push(omap24xx_idle_loop_suspend,
+ omap24xx_idle_loop_suspend_sz);
+
+ omap2_sram_suspend = omap_sram_push(omap24xx_cpu_suspend,
+ omap24xx_cpu_suspend_sz);
+
+ pm_set_ops(&omap_pm_ops);
+ pm_idle = omap2_pm_idle;
+
+ return 0;
+}
+
+__initcall(omap2_pm_init);
diff --git a/arch/arm/mach-omap2/prcm.h b/arch/arm/mach-omap2/prcm-regs.h
index 2eb89b936c8..22ac7be4f78 100644
--- a/arch/arm/mach-omap2/prcm.h
+++ b/arch/arm/mach-omap2/prcm-regs.h
@@ -1,5 +1,7 @@
/*
- * prcm.h - Access definations for use in OMAP24XX clock and power management
+ * linux/arch/arm/mach-omap2/prcm-reg.h
+ *
+ * OMAP24XX Power Reset and Clock Management (PRCM) registers
*
* Copyright (C) 2005 Texas Instruments, Inc.
*
@@ -18,8 +20,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#ifndef __ASM_ARM_ARCH_DPM_PRCM_H
-#define __ASM_ARM_ARCH_DPM_PRCM_H
+#ifndef __ARCH_ARM_MACH_OMAP2_PRCM_H
+#define __ARCH_ARM_MACH_OMAP2_PRCM_H
/* SET_PERFORMANCE_LEVEL PARAMETERS */
#define PRCM_HALF_SPEED 1
@@ -159,54 +161,63 @@
#define CM_FCLKEN_MDM PRCM_REG32(0xC00)
#define CM_ICLKEN_MDM PRCM_REG32(0xC10)
#define CM_IDLEST_MDM PRCM_REG32(0xC20)
+#define CM_AUTOIDLE_MDM PRCM_REG32(0xC30)
#define CM_CLKSEL_MDM PRCM_REG32(0xC40)
-
-/* FIXME: Move to header for 2430 */
-#define DISP_BASE (OMAP24XX_L4_IO_BASE+0x50000)
+#define CM_CLKSTCTRL_MDM PRCM_REG32(0xC48)
+#define RM_RSTCTRL_MDM PRCM_REG32(0xC50)
+#define RM_RSTST_MDM PRCM_REG32(0xC58)
+#define PM_WKEN_MDM PRCM_REG32(0xCA0)
+#define PM_WKST_MDM PRCM_REG32(0xCB0)
+#define PM_WKDEP_MDM PRCM_REG32(0xCC8)
+#define PM_PWSTCTRL_MDM PRCM_REG32(0xCE0)
+#define PM_PWSTST_MDM PRCM_REG32(0xCE4)
+
+#define OMAP24XX_L4_IO_BASE 0x48000000
+
+#define DISP_BASE (OMAP24XX_L4_IO_BASE + 0x50000)
#define DISP_REG32(offset) __REG32(DISP_BASE + (offset))
-#define GPMC_BASE (OMAP24XX_GPMC_BASE)
-#define GPMC_REG32(offset) __REG32(GPMC_BASE + (offset))
+#define OMAP24XX_GPMC_BASE (L3_24XX_BASE + 0xa000)
+#define GPMC_REG32(offset) __REG32(OMAP24XX_GPMC_BASE + (offset))
-#define GPT1_BASE (OMAP24XX_GPT1)
+/* FIXME: Move these to timer code */
+#define GPT1_BASE (0x48028000)
#define GPT1_REG32(offset) __REG32(GPT1_BASE + (offset))
/* Misc sysconfig */
#define DISPC_SYSCONFIG DISP_REG32(0x410)
-#define SPI_BASE (OMAP24XX_L4_IO_BASE+0x98000)
+#define SPI_BASE (OMAP24XX_L4_IO_BASE + 0x98000)
#define MCSPI1_SYSCONFIG __REG32(SPI_BASE + 0x10)
-#define MCSPI2_SYSCONFIG __REG32(SPI_BASE+0x2000 + 0x10)
-
-//#define DSP_MMU_SYSCONFIG 0x5A000010
-#define CAMERA_MMU_SYSCONFIG __REG32(DISP_BASE+0x2C10)
-//#define IVA_MMU_SYSCONFIG 0x5D000010
-//#define DSP_DMA_SYSCONFIG 0x00FCC02C
-#define CAMERA_DMA_SYSCONFIG __REG32(DISP_BASE+0x282C)
-#define SYSTEM_DMA_SYSCONFIG __REG32(DISP_BASE+0x602C)
+#define MCSPI2_SYSCONFIG __REG32(SPI_BASE + 0x2000 + 0x10)
+#define MCSPI3_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE + 0xb8010)
+
+#define CAMERA_MMU_SYSCONFIG __REG32(DISP_BASE + 0x2C10)
+#define CAMERA_DMA_SYSCONFIG __REG32(DISP_BASE + 0x282C)
+#define SYSTEM_DMA_SYSCONFIG __REG32(DISP_BASE + 0x602C)
#define GPMC_SYSCONFIG GPMC_REG32(0x010)
-#define MAILBOXES_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE+0x94010)
-#define UART1_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE+0x6A054)
-#define UART2_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE+0x6C054)
-#define UART3_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE+0x6E054)
-//#define IVA_SYSCONFIG 0x5C060010
-#define SDRC_SYSCONFIG __REG32(OMAP24XX_SDRC_BASE+0x10)
-#define SMS_SYSCONFIG __REG32(OMAP24XX_SMS_BASE+0x10)
-#define SSI_SYSCONFIG __REG32(DISP_BASE+0x8010)
-//#define VLYNQ_SYSCONFIG 0x67FFFE10
+#define MAILBOXES_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE + 0x94010)
+#define UART1_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE + 0x6A054)
+#define UART2_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE + 0x6C054)
+#define UART3_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE + 0x6E054)
+#define SDRC_SYSCONFIG __REG32(OMAP24XX_SDRC_BASE + 0x10)
+#define OMAP24XX_SMS_BASE (L3_24XX_BASE + 0x8000)
+#define SMS_SYSCONFIG __REG32(OMAP24XX_SMS_BASE + 0x10)
+#define SSI_SYSCONFIG __REG32(DISP_BASE + 0x8010)
/* rkw - good cannidates for PM_ to start what nm was trying */
-#define OMAP24XX_GPT2 (OMAP24XX_L4_IO_BASE+0x2A000)
-#define OMAP24XX_GPT3 (OMAP24XX_L4_IO_BASE+0x78000)
-#define OMAP24XX_GPT4 (OMAP24XX_L4_IO_BASE+0x7A000)
-#define OMAP24XX_GPT5 (OMAP24XX_L4_IO_BASE+0x7C000)
-#define OMAP24XX_GPT6 (OMAP24XX_L4_IO_BASE+0x7E000)
-#define OMAP24XX_GPT7 (OMAP24XX_L4_IO_BASE+0x80000)
-#define OMAP24XX_GPT8 (OMAP24XX_L4_IO_BASE+0x82000)
-#define OMAP24XX_GPT9 (OMAP24XX_L4_IO_BASE+0x84000)
-#define OMAP24XX_GPT10 (OMAP24XX_L4_IO_BASE+0x86000)
-#define OMAP24XX_GPT11 (OMAP24XX_L4_IO_BASE+0x88000)
-#define OMAP24XX_GPT12 (OMAP24XX_L4_IO_BASE+0x8A000)
-
+#define OMAP24XX_GPT2 (OMAP24XX_L4_IO_BASE + 0x2A000)
+#define OMAP24XX_GPT3 (OMAP24XX_L4_IO_BASE + 0x78000)
+#define OMAP24XX_GPT4 (OMAP24XX_L4_IO_BASE + 0x7A000)
+#define OMAP24XX_GPT5 (OMAP24XX_L4_IO_BASE + 0x7C000)
+#define OMAP24XX_GPT6 (OMAP24XX_L4_IO_BASE + 0x7E000)
+#define OMAP24XX_GPT7 (OMAP24XX_L4_IO_BASE + 0x80000)
+#define OMAP24XX_GPT8 (OMAP24XX_L4_IO_BASE + 0x82000)
+#define OMAP24XX_GPT9 (OMAP24XX_L4_IO_BASE + 0x84000)
+#define OMAP24XX_GPT10 (OMAP24XX_L4_IO_BASE + 0x86000)
+#define OMAP24XX_GPT11 (OMAP24XX_L4_IO_BASE + 0x88000)
+#define OMAP24XX_GPT12 (OMAP24XX_L4_IO_BASE + 0x8A000)
+
+/* FIXME: Move these to timer code */
#define GPTIMER1_SYSCONFIG GPT1_REG32(0x010)
#define GPTIMER2_SYSCONFIG __REG32(OMAP24XX_GPT2 + 0x10)
#define GPTIMER3_SYSCONFIG __REG32(OMAP24XX_GPT3 + 0x10)
@@ -220,12 +231,18 @@
#define GPTIMER11_SYSCONFIG __REG32(OMAP24XX_GPT11 + 0x10)
#define GPTIMER12_SYSCONFIG __REG32(OMAP24XX_GPT12 + 0x10)
-#define GPIOX_BASE(X) (OMAP24XX_GPIO_BASE+(0x2000*((X)-1)))
+/* FIXME: Move these to gpio code */
+#define OMAP24XX_GPIO_BASE 0x48018000
+#define GPIOX_BASE(X) (OMAP24XX_GPIO_BASE + (0x2000 * ((X) - 1)))
+
+#define GPIO1_SYSCONFIG __REG32((GPIOX_BASE(1) + 0x10))
+#define GPIO2_SYSCONFIG __REG32((GPIOX_BASE(2) + 0x10))
+#define GPIO3_SYSCONFIG __REG32((GPIOX_BASE(3) + 0x10))
+#define GPIO4_SYSCONFIG __REG32((GPIOX_BASE(4) + 0x10))
-#define GPIO1_SYSCONFIG __REG32((GPIOX_BASE(1)+0x10))
-#define GPIO2_SYSCONFIG __REG32((GPIOX_BASE(2)+0x10))
-#define GPIO3_SYSCONFIG __REG32((GPIOX_BASE(3)+0x10))
-#define GPIO4_SYSCONFIG __REG32((GPIOX_BASE(4)+0x10))
+#if defined(CONFIG_ARCH_OMAP243X)
+#define GPIO5_SYSCONFIG __REG32((OMAP24XX_GPIO5_BASE + 0x10))
+#endif
/* GP TIMER 1 */
#define GPTIMER1_TISTAT GPT1_REG32(0x014)
@@ -243,15 +260,15 @@
#define GPTIMER1_TCAR2 GPT1_REG32(0x044)
/* rkw -- base fix up please... */
-#define GPTIMER3_TISR __REG32(OMAP24XX_L4_IO_BASE+0x78018)
+#define GPTIMER3_TISR __REG32(OMAP24XX_L4_IO_BASE + 0x78018)
/* SDRC */
-#define SDRC_DLLA_CTRL __REG32(OMAP24XX_SDRC_BASE+0x060)
-#define SDRC_DLLA_STATUS __REG32(OMAP24XX_SDRC_BASE+0x064)
-#define SDRC_DLLB_CTRL __REG32(OMAP24XX_SDRC_BASE+0x068)
-#define SDRC_DLLB_STATUS __REG32(OMAP24XX_SDRC_BASE+0x06C)
-#define SDRC_POWER __REG32(OMAP24XX_SDRC_BASE+0x070)
-#define SDRC_MR_0 __REG32(OMAP24XX_SDRC_BASE+0x084)
+#define SDRC_DLLA_CTRL __REG32(OMAP24XX_SDRC_BASE + 0x060)
+#define SDRC_DLLA_STATUS __REG32(OMAP24XX_SDRC_BASE + 0x064)
+#define SDRC_DLLB_CTRL __REG32(OMAP24XX_SDRC_BASE + 0x068)
+#define SDRC_DLLB_STATUS __REG32(OMAP24XX_SDRC_BASE + 0x06C)
+#define SDRC_POWER __REG32(OMAP24XX_SDRC_BASE + 0x070)
+#define SDRC_MR_0 __REG32(OMAP24XX_SDRC_BASE + 0x084)
/* GPIO 1 */
#define GPIO1_BASE GPIOX_BASE(1)
@@ -278,6 +295,8 @@
#define GPIO2_DATAIN GPIO2_REG32(0x038)
#define GPIO2_OE GPIO2_REG32(0x034)
#define GPIO2_DATAOUT GPIO2_REG32(0x03C)
+#define GPIO2_DEBOUNCENABLE GPIO2_REG32(0x050)
+#define GPIO2_DEBOUNCINGTIME GPIO2_REG32(0x054)
/* GPIO 3 */
#define GPIO3_BASE GPIOX_BASE(3)
@@ -294,6 +313,8 @@
#define GPIO3_DATAOUT GPIO3_REG32(0x03C)
#define GPIO3_DEBOUNCENABLE GPIO3_REG32(0x050)
#define GPIO3_DEBOUNCINGTIME GPIO3_REG32(0x054)
+#define GPIO3_DEBOUNCENABLE GPIO3_REG32(0x050)
+#define GPIO3_DEBOUNCINGTIME GPIO3_REG32(0x054)
/* GPIO 4 */
#define GPIO4_BASE GPIOX_BASE(4)
@@ -311,10 +332,26 @@
#define GPIO4_DEBOUNCENABLE GPIO4_REG32(0x050)
#define GPIO4_DEBOUNCINGTIME GPIO4_REG32(0x054)
+#if defined(CONFIG_ARCH_OMAP243X)
+/* GPIO 5 */
+#define GPIO5_REG32(offset) __REG32((OMAP24XX_GPIO5_BASE + (offset)))
+#define GPIO5_IRQENABLE1 GPIO5_REG32(0x01C)
+#define GPIO5_IRQSTATUS1 GPIO5_REG32(0x018)
+#define GPIO5_IRQENABLE2 GPIO5_REG32(0x02C)
+#define GPIO5_IRQSTATUS2 GPIO5_REG32(0x028)
+#define GPIO5_WAKEUPENABLE GPIO5_REG32(0x020)
+#define GPIO5_RISINGDETECT GPIO5_REG32(0x048)
+#define GPIO5_FALLINGDETECT GPIO5_REG32(0x04C)
+#define GPIO5_DATAIN GPIO5_REG32(0x038)
+#define GPIO5_OE GPIO5_REG32(0x034)
+#define GPIO5_DATAOUT GPIO5_REG32(0x03C)
+#define GPIO5_DEBOUNCENABLE GPIO5_REG32(0x050)
+#define GPIO5_DEBOUNCINGTIME GPIO5_REG32(0x054)
+#endif
/* IO CONFIG */
-#define CONTROL_BASE (OMAP24XX_CTRL_BASE)
-#define CONTROL_REG32(offset) __REG32(CONTROL_BASE + (offset))
+#define OMAP24XX_CTRL_BASE (L4_24XX_BASE)
+#define CONTROL_REG32(offset) __REG32(OMAP24XX_CTRL_BASE + (offset))
#define CONTROL_PADCONF_SPI1_NCS2 CONTROL_REG32(0x104)
#define CONTROL_PADCONF_SYS_XTALOUT CONTROL_REG32(0x134)
@@ -322,15 +359,18 @@
#define CONTROL_PADCONF_MCBSP1_DX CONTROL_REG32(0x10C)
#define CONTROL_PADCONF_GPMC_NCS4 CONTROL_REG32(0x090)
#define CONTROL_PADCONF_DSS_D5 CONTROL_REG32(0x0B8)
-#define CONTROL_PADCONF_DSS_D9 CONTROL_REG32(0x0BC)
+#define CONTROL_PADCONF_DSS_D9 CONTROL_REG32(0x0BC) /* 2420 */
#define CONTROL_PADCONF_DSS_D13 CONTROL_REG32(0x0C0)
#define CONTROL_PADCONF_DSS_VSYNC CONTROL_REG32(0x0CC)
+#define CONTROL_PADCONF_SYS_NIRQW0 CONTROL_REG32(0x0BC) /* 2430 */
+#define CONTROL_PADCONF_SSI1_FLAG_TX CONTROL_REG32(0x108) /* 2430 */
/* CONTROL */
#define CONTROL_DEVCONF CONTROL_REG32(0x274)
+#define CONTROL_DEVCONF1 CONTROL_REG32(0x2E8)
/* INTERRUPT CONTROLLER */
-#define INTC_BASE (OMAP24XX_L4_IO_BASE+0xfe000)
+#define INTC_BASE ((L4_24XX_BASE) + 0xfe000)
#define INTC_REG32(offset) __REG32(INTC_BASE + (offset))
#define INTC1_U_BASE INTC_REG32(0x000)
@@ -348,10 +388,12 @@
#define INTC_ISR_CLEAR2 INTC_REG32(0x0D4)
#define INTC_SIR_IRQ INTC_REG32(0x040)
#define INTC_CONTROL INTC_REG32(0x048)
-#define INTC_ILR11 INTC_REG32(0x12C)
+#define INTC_ILR11 INTC_REG32(0x12C) /* PRCM on MPU PIC */
+#define INTC_ILR30 INTC_REG32(0x178)
+#define INTC_ILR31 INTC_REG32(0x17C)
#define INTC_ILR32 INTC_REG32(0x180)
-#define INTC_ILR37 INTC_REG32(0x194)
-#define INTC_SYSCONFIG INTC_REG32(0x010)
+#define INTC_ILR37 INTC_REG32(0x194) /* GPIO4 on MPU PIC */
+#define INTC_SYSCONFIG INTC_REG32(0x010) /* GPT1 on MPU PIC */
/* RAM FIREWALL */
#define RAMFW_BASE (0x68005000)
@@ -373,6 +415,24 @@
#define GPMC_CONFIG6_0 GPMC_REG32(0x074)
#define GPMC_CONFIG7_0 GPMC_REG32(0x078)
+/* GPMC CS1 */
+#define GPMC_CONFIG1_1 GPMC_REG32(0x090)
+#define GPMC_CONFIG2_1 GPMC_REG32(0x094)
+#define GPMC_CONFIG3_1 GPMC_REG32(0x098)
+#define GPMC_CONFIG4_1 GPMC_REG32(0x09C)
+#define GPMC_CONFIG5_1 GPMC_REG32(0x0a0)
+#define GPMC_CONFIG6_1 GPMC_REG32(0x0a4)
+#define GPMC_CONFIG7_1 GPMC_REG32(0x0a8)
+
+/* GPMC CS3 */
+#define GPMC_CONFIG1_3 GPMC_REG32(0x0F0)
+#define GPMC_CONFIG2_3 GPMC_REG32(0x0F4)
+#define GPMC_CONFIG3_3 GPMC_REG32(0x0F8)
+#define GPMC_CONFIG4_3 GPMC_REG32(0x0FC)
+#define GPMC_CONFIG5_3 GPMC_REG32(0x100)
+#define GPMC_CONFIG6_3 GPMC_REG32(0x104)
+#define GPMC_CONFIG7_3 GPMC_REG32(0x108)
+
/* DSS */
#define DSS_CONTROL DISP_REG32(0x040)
#define DISPC_CONTROL DISP_REG32(0x440)
@@ -405,11 +465,15 @@
#define DISPC_DATA_CYCLE2 DISP_REG32(0x5D8)
#define DISPC_DATA_CYCLE3 DISP_REG32(0x5DC)
-/* Wake up define for board */
-#define GPIO97 (1 << 1)
-#define GPIO88 (1 << 24)
+/* HSUSB Suspend */
+#define HSUSB_CTRL __REG8(0x480AC001)
+#define USBOTG_POWER __REG32(0x480AC000)
+
+/* HS MMC */
+#define MMCHS1_SYSCONFIG __REG32(0x4809C010)
+#define MMCHS2_SYSCONFIG __REG32(0x480b4010)
-#endif /* __ASSEMBLER__ */
+#endif /* __ASSEMBLER__ */
#endif
diff --git a/arch/arm/mach-omap2/prcm.c b/arch/arm/mach-omap2/prcm.c
new file mode 100644
index 00000000000..8893479dc7e
--- /dev/null
+++ b/arch/arm/mach-omap2/prcm.c
@@ -0,0 +1,40 @@
+/*
+ * linux/arch/arm/mach-omap2/prcm.c
+ *
+ * OMAP 24xx Power Reset and Clock Management (PRCM) functions
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ *
+ * Written by Tony Lindgren <tony.lindgren@nokia.com>
+ *
+ * Some pieces of code Copyright (C) 2005 Texas Instruments, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+
+#include "prcm-regs.h"
+
+u32 omap_prcm_get_reset_sources(void)
+{
+ return RM_RSTST_WKUP & 0x7f;
+}
+EXPORT_SYMBOL(omap_prcm_get_reset_sources);
+
+/* Resets clock rates and reboots the system. Only called from system.h */
+void omap_prcm_arch_reset(char mode)
+{
+ u32 rate;
+ struct clk *vclk, *sclk;
+
+ vclk = clk_get(NULL, "virt_prcm_set");
+ sclk = clk_get(NULL, "sys_ck");
+ rate = clk_get_rate(sclk);
+ clk_set_rate(vclk, rate); /* go to bypass for OMAP limitation */
+ RM_RSTCTRL_WKUP |= 2;
+}
diff --git a/arch/arm/mach-omap2/sleep.S b/arch/arm/mach-omap2/sleep.S
new file mode 100644
index 00000000000..00299cbeb91
--- /dev/null
+++ b/arch/arm/mach-omap2/sleep.S
@@ -0,0 +1,144 @@
+/*
+ * linux/arch/arm/mach-omap2/sleep.S
+ *
+ * (C) Copyright 2004
+ * Texas Instruments, <www.ti.com>
+ * Richard Woodruff <r-woodruff2@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <linux/config.h>
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/arch/io.h>
+#include <asm/arch/pm.h>
+
+#define A_32KSYNC_CR_V IO_ADDRESS(OMAP_TIMER32K_BASE+0x10)
+#define A_PRCM_VOLTCTRL_V IO_ADDRESS(OMAP24XX_PRCM_BASE+0x50)
+#define A_PRCM_CLKCFG_CTRL_V IO_ADDRESS(OMAP24XX_PRCM_BASE+0x80)
+#define A_CM_CLKEN_PLL_V IO_ADDRESS(OMAP24XX_PRCM_BASE+0x500)
+#define A_CM_IDLEST_CKGEN_V IO_ADDRESS(OMAP24XX_PRCM_BASE+0x520)
+#define A_CM_CLKSEL1_PLL_V IO_ADDRESS(OMAP24XX_PRCM_BASE+0x540)
+#define A_CM_CLKSEL2_PLL_V IO_ADDRESS(OMAP24XX_PRCM_BASE+0x544)
+
+#define A_SDRC_DLLA_CTRL_V IO_ADDRESS(OMAP24XX_SDRC_BASE+0x60)
+#define A_SDRC_POWER_V IO_ADDRESS(OMAP24XX_SDRC_BASE+0x70)
+#define A_SDRC_RFR_CTRL_V IO_ADDRESS(OMAP24XX_SDRC_BASE+0xA4)
+#define A_SDRC0_V (0xC0000000)
+#define A_SDRC_MANUAL_V IO_ADDRESS(OMAP24XX_SDRC_BASE+0xA8)
+
+ .text
+
+/*
+ * Forces OMAP into idle state
+ *
+ * omap24xx_idle_loop_suspend() - This bit of code just executes the WFI
+ * for normal idles.
+ *
+ * Note: This code get's copied to internal SRAM at boot. When the OMAP
+ * wakes up it continues execution at the point it went to sleep.
+ */
+ENTRY(omap24xx_idle_loop_suspend)
+ stmfd sp!, {r0, lr} @ save registers on stack
+ mov r0, #0 @ clear for mcr setup
+ mcr p15, 0, r0, c7, c0, 4 @ wait for interrupt
+ ldmfd sp!, {r0, pc} @ restore regs and return
+
+ENTRY(omap24xx_idle_loop_suspend_sz)
+ .word . - omap24xx_idle_loop_suspend
+
+/*
+ * omap242x_cpu_suspend() - Forces OMAP into deep sleep state by completing
+ * SDRC shutdown then ARM shutdown. Upon wake MPU is back on so just restore
+ * SDRC.
+ *
+ * Input:
+ * R0 : DLL ctrl value pre-Sleep
+ * R1 : Processor+Revision
+ * 2420: 0x21 = 242xES1, 0x26 = 242xES2.2
+ * 2430: 0x31 = 2430ES1, 0x32 = 2430ES2
+ *
+ * The if the DPLL is going to AutoIdle. It seems like the DPLL may be back on
+ * when we get called, but the DLL probably isn't. We will wait a bit more in
+ * case the DPLL isn't quite there yet. The code will wait on DLL for DDR even
+ * if in unlocked mode.
+ *
+ * For less than 242x-ES2.2 upon wake from a sleep mode where the external
+ * oscillator was stopped, a timing bug exists where a non-stabilized 12MHz
+ * clock can pass into the PRCM can cause problems at DSP and IVA.
+ * To work around this the code will switch to the 32kHz source prior to sleep.
+ * Post sleep we will shift back to using the DPLL. Apparently,
+ * CM_IDLEST_CLKGEN does not reflect the full clock change so you need to wait
+ * 3x12MHz + 3x32kHz clocks for a full switch.
+ *
+ * The DLL load value is not kept in RETENTION or OFF. It needs to be restored
+ * at wake
+ */
+ENTRY(omap24xx_cpu_suspend)
+ stmfd sp!, {r0 - r12, lr} @ save registers on stack
+ mov r3, #0x0 @ clear for mrc call
+ mcr p15, 0, r3, c7, c10, 4 @ memory barrier, hope SDR/DDR finished
+ nop
+ nop
+ ldr r3, A_SDRC_POWER @ addr of sdrc power
+ ldr r4, [r3] @ value of sdrc power
+ orr r4, r4, #0x40 @ enable self refresh on idle req
+ mov r5, #0x2000 @ set delay (DPLL relock + DLL relock)
+ str r4, [r3] @ make it so
+ mov r2, #0
+ nop
+ mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt
+ nop
+loop:
+ subs r5, r5, #0x1 @ awake, wait just a bit
+ bne loop
+
+ /* The DPLL has on before we take the DDR out of self refresh */
+ bic r4, r4, #0x40 @ now clear self refresh bit.
+ str r4, [r3] @ put vlaue back.
+ ldr r4, A_SDRC0 @ make a clock happen
+ ldr r4, [r4]
+ nop @ start auto refresh only after clk ok
+ movs r0, r0 @ see if DDR or SDR
+ ldrne r1, A_SDRC_DLLA_CTRL_S @ get addr of DLL ctrl
+ strne r0, [r1] @ rewrite DLLA to force DLL reload
+ addne r1, r1, #0x8 @ move to DLLB
+ strne r0, [r1] @ rewrite DLLB to force DLL reload
+
+ mov r5, #0x1000
+loop2:
+ subs r5, r5, #0x1
+ bne loop2
+ /* resume*/
+ ldmfd sp!, {r0 - r12, pc} @ restore regs and return
+
+A_SDRC_POWER:
+ .word A_SDRC_POWER_V
+A_SDRC0:
+ .word A_SDRC0_V
+A_CM_CLKSEL2_PLL_S:
+ .word A_CM_CLKSEL2_PLL_V
+A_CM_CLKEN_PLL:
+ .word A_CM_CLKEN_PLL_V
+A_SDRC_DLLA_CTRL_S:
+ .word A_SDRC_DLLA_CTRL_V
+A_SDRC_MANUAL_S:
+ .word A_SDRC_MANUAL_V
+
+ENTRY(omap24xx_cpu_suspend_sz)
+ .word . - omap24xx_cpu_suspend
+
diff --git a/arch/arm/mach-omap2/sram-fn.S b/arch/arm/mach-omap2/sram-fn.S
index 2a869e20334..d261e4ff4d9 100644
--- a/arch/arm/mach-omap2/sram-fn.S
+++ b/arch/arm/mach-omap2/sram-fn.S
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/mach-omap1/sram.S
+ * linux/arch/arm/mach-omap2/sram.S
*
* Omap2 specific functions that need to be run in internal SRAM
*
@@ -28,7 +28,7 @@
#include <asm/arch/io.h>
#include <asm/hardware.h>
-#include <asm/arch/prcm.h>
+#include "prcm-regs.h"
#define TIMER_32KSYNCT_CR_V IO_ADDRESS(OMAP24XX_32KSYNCT_BASE + 0x010)
diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c
index b45560a8f6c..a042473deed 100644
--- a/arch/arm/mach-pxa/poodle.c
+++ b/arch/arm/mach-pxa/poodle.c
@@ -307,6 +307,10 @@ static void __init fixup_poodle(struct machine_desc *desc,
struct tag *tags, char **cmdline, struct meminfo *mi)
{
sharpsl_save_param();
+ mi->nr_banks=1;
+ mi->bank[0].start = 0xa0000000;
+ mi->bank[0].node = 0;
+ mi->bank[0].size = (32*1024*1024);
}
MACHINE_START(POODLE, "SHARP Poodle")
diff --git a/arch/arm/mach-s3c2410/Kconfig b/arch/arm/mach-s3c2410/Kconfig
index ed07c4149d8..ce7d8100069 100644
--- a/arch/arm/mach-s3c2410/Kconfig
+++ b/arch/arm/mach-s3c2410/Kconfig
@@ -50,9 +50,15 @@ config MACH_N30
<http://zoo.weinigel.se/n30>.
+config MACH_SMDK
+ bool
+ help
+ Common machine code for SMDK2410 and SMDK2440
+
config ARCH_SMDK2410
bool "SMDK2410/A9M2410"
select CPU_S3C2410
+ select MACH_SMDK
help
Say Y here if you are using the SMDK2410 or the derived module A9M2410
<http://www.fsforth.de>
@@ -60,6 +66,7 @@ config ARCH_SMDK2410
config ARCH_S3C2440
bool "SMDK2440"
select CPU_S3C2440
+ select MACH_SMDK
help
Say Y here if you are using the SMDK2440.
diff --git a/arch/arm/mach-s3c2410/Makefile b/arch/arm/mach-s3c2410/Makefile
index 1b3b476e563..3e5712db6b5 100644
--- a/arch/arm/mach-s3c2410/Makefile
+++ b/arch/arm/mach-s3c2410/Makefile
@@ -48,3 +48,5 @@ obj-$(CONFIG_MACH_VR1000) += mach-vr1000.o usb-simtec.o
obj-$(CONFIG_MACH_RX3715) += mach-rx3715.o
obj-$(CONFIG_MACH_OTOM) += mach-otom.o
obj-$(CONFIG_MACH_NEXCODER_2440) += mach-nexcoder.o
+
+obj-$(CONFIG_MACH_SMDK) += common-smdk.o \ No newline at end of file
diff --git a/arch/arm/mach-s3c2410/clock.c b/arch/arm/mach-s3c2410/clock.c
index fec02c92f95..b7f85e6d6b7 100644
--- a/arch/arm/mach-s3c2410/clock.c
+++ b/arch/arm/mach-s3c2410/clock.c
@@ -249,7 +249,7 @@ static int s3c24xx_upll_enable(struct clk *clk, int enable)
/* if we started the UPLL, then allow to settle */
- if (enable && !(orig & S3C2410_CLKSLOW_UCLK_OFF))
+ if (enable && (orig & S3C2410_CLKSLOW_UCLK_OFF))
udelay(200);
return 0;
diff --git a/arch/arm/mach-s3c2410/common-smdk.c b/arch/arm/mach-s3c2410/common-smdk.c
new file mode 100644
index 00000000000..36b8291b5e0
--- /dev/null
+++ b/arch/arm/mach-s3c2410/common-smdk.c
@@ -0,0 +1,134 @@
+/* linux/arch/arm/mach-s3c2410/common-smdk.c
+ *
+ * Copyright (c) 2006 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * Common code for SMDK2410 and SMDK2440 boards
+ *
+ * http://www.fluff.org/ben/smdk2440/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <asm/arch/regs-gpio.h>
+
+#include <asm/arch/nand.h>
+
+#include "devs.h"
+#include "pm.h"
+
+/* NAND parititon from 2.4.18-swl5 */
+
+static struct mtd_partition smdk_default_nand_part[] = {
+ [0] = {
+ .name = "Boot Agent",
+ .size = SZ_16K,
+ .offset = 0,
+ },
+ [1] = {
+ .name = "S3C2410 flash parition 1",
+ .offset = 0,
+ .size = SZ_2M,
+ },
+ [2] = {
+ .name = "S3C2410 flash partition 2",
+ .offset = SZ_4M,
+ .size = SZ_4M,
+ },
+ [3] = {
+ .name = "S3C2410 flash partition 3",
+ .offset = SZ_8M,
+ .size = SZ_2M,
+ },
+ [4] = {
+ .name = "S3C2410 flash partition 4",
+ .offset = SZ_1M * 10,
+ .size = SZ_4M,
+ },
+ [5] = {
+ .name = "S3C2410 flash partition 5",
+ .offset = SZ_1M * 14,
+ .size = SZ_1M * 10,
+ },
+ [6] = {
+ .name = "S3C2410 flash partition 6",
+ .offset = SZ_1M * 24,
+ .size = SZ_1M * 24,
+ },
+ [7] = {
+ .name = "S3C2410 flash partition 7",
+ .offset = SZ_1M * 48,
+ .size = SZ_16M,
+ }
+};
+
+static struct s3c2410_nand_set smdk_nand_sets[] = {
+ [0] = {
+ .name = "NAND",
+ .nr_chips = 1,
+ .nr_partitions = ARRAY_SIZE(smdk_default_nand_part),
+ .partitions = smdk_default_nand_part,
+ },
+};
+
+/* choose a set of timings which should suit most 512Mbit
+ * chips and beyond.
+*/
+
+static struct s3c2410_platform_nand smdk_nand_info = {
+ .tacls = 20,
+ .twrph0 = 60,
+ .twrph1 = 20,
+ .nr_sets = ARRAY_SIZE(smdk_nand_sets),
+ .sets = smdk_nand_sets,
+};
+
+/* devices we initialise */
+
+static struct platform_device __initdata *smdk_devs[] = {
+ &s3c_device_nand,
+};
+
+void __init smdk_machine_init(void)
+{
+ /* Configure the LEDs (even if we have no LED support)*/
+
+ s3c2410_gpio_cfgpin(S3C2410_GPF4, S3C2410_GPF4_OUTP);
+ s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP);
+ s3c2410_gpio_cfgpin(S3C2410_GPF6, S3C2410_GPF6_OUTP);
+ s3c2410_gpio_cfgpin(S3C2410_GPF7, S3C2410_GPF7_OUTP);
+
+ s3c2410_gpio_setpin(S3C2410_GPF4, 1);
+ s3c2410_gpio_setpin(S3C2410_GPF5, 1);
+ s3c2410_gpio_setpin(S3C2410_GPF6, 1);
+ s3c2410_gpio_setpin(S3C2410_GPF7, 1);
+
+ s3c_device_nand.dev.platform_data = &smdk_nand_info;
+
+ platform_add_devices(smdk_devs, ARRAY_SIZE(smdk_devs));
+
+ s3c2410_pm_init();
+}
diff --git a/arch/arm/mach-s3c2410/common-smdk.h b/arch/arm/mach-s3c2410/common-smdk.h
new file mode 100644
index 00000000000..0e3a3be330a
--- /dev/null
+++ b/arch/arm/mach-s3c2410/common-smdk.h
@@ -0,0 +1,15 @@
+/* linux/arch/arm/mach-s3c2410/common-smdk.h
+ *
+ * Copyright (c) 2006 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * Common code for SMDK2410 and SMDK2440 boards
+ *
+ * http://www.fluff.org/ben/smdk2440/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+extern void smdk_machine_init(void);
diff --git a/arch/arm/mach-s3c2410/mach-anubis.c b/arch/arm/mach-s3c2410/mach-anubis.c
index 3e327b8e46b..cc97fbf6629 100644
--- a/arch/arm/mach-s3c2410/mach-anubis.c
+++ b/arch/arm/mach-s3c2410/mach-anubis.c
@@ -232,8 +232,8 @@ static void anubis_nand_select(struct s3c2410_nand_set *set, int slot)
static struct s3c2410_platform_nand anubis_nand_info = {
.tacls = 25,
- .twrph0 = 80,
- .twrph1 = 80,
+ .twrph0 = 55,
+ .twrph1 = 40,
.nr_sets = ARRAY_SIZE(anubis_nand_sets),
.sets = anubis_nand_sets,
.select_chip = anubis_nand_select,
diff --git a/arch/arm/mach-s3c2410/mach-rx3715.c b/arch/arm/mach-s3c2410/mach-rx3715.c
index 0260ed5ab94..306afc1d7cd 100644
--- a/arch/arm/mach-s3c2410/mach-rx3715.c
+++ b/arch/arm/mach-s3c2410/mach-rx3715.c
@@ -32,6 +32,11 @@
#include <linux/serial_core.h>
#include <linux/serial.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
@@ -46,6 +51,7 @@
#include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-lcd.h>
+#include <asm/arch/nand.h>
#include <asm/arch/fb.h>
#include "clock.h"
@@ -170,12 +176,39 @@ static struct s3c2410fb_mach_info rx3715_lcdcfg __initdata = {
},
};
+static struct mtd_partition rx3715_nand_part[] = {
+ [0] = {
+ .name = "Whole Flash",
+ .offset = 0,
+ .size = MTDPART_SIZ_FULL,
+ .mask_flags = MTD_WRITEABLE,
+ }
+};
+
+static struct s3c2410_nand_set rx3715_nand_sets[] = {
+ [0] = {
+ .name = "Internal",
+ .nr_chips = 1,
+ .nr_partitions = ARRAY_SIZE(rx3715_nand_part),
+ .partitions = rx3715_nand_part,
+ },
+};
+
+static struct s3c2410_platform_nand rx3715_nand_info = {
+ .tacls = 25,
+ .twrph0 = 50,
+ .twrph1 = 15,
+ .nr_sets = ARRAY_SIZE(rx3715_nand_sets),
+ .sets = rx3715_nand_sets,
+};
+
static struct platform_device *rx3715_devices[] __initdata = {
&s3c_device_usb,
&s3c_device_lcd,
&s3c_device_wdt,
&s3c_device_i2c,
&s3c_device_iis,
+ &s3c_device_nand,
};
static struct s3c24xx_board rx3715_board __initdata = {
@@ -185,6 +218,8 @@ static struct s3c24xx_board rx3715_board __initdata = {
static void __init rx3715_map_io(void)
{
+ s3c_device_nand.dev.platform_data = &rx3715_nand_info;
+
s3c24xx_init_io(rx3715_iodesc, ARRAY_SIZE(rx3715_iodesc));
s3c24xx_init_clocks(16934000);
s3c24xx_init_uarts(rx3715_uartcfgs, ARRAY_SIZE(rx3715_uartcfgs));
diff --git a/arch/arm/mach-s3c2410/mach-smdk2410.c b/arch/arm/mach-s3c2410/mach-smdk2410.c
index 1e76e1fdfce..2db932d72c5 100644
--- a/arch/arm/mach-s3c2410/mach-smdk2410.c
+++ b/arch/arm/mach-s3c2410/mach-smdk2410.c
@@ -28,7 +28,8 @@
* Ben Dooks <ben@simtec.co.uk>
*
* 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA
- * 20-Sep-2005 BJD Added static to non-exported items
+ * 20-Sep-2005 BJD Added static to non-exported items
+ * 01-Apr-2006 BJD Moved init code to common smdk
*
***********************************************************************/
@@ -54,6 +55,8 @@
#include "devs.h"
#include "cpu.h"
+#include "common-smdk.h"
+
static struct map_desc smdk2410_iodesc[] __initdata = {
/* nothing here yet */
};
@@ -107,11 +110,6 @@ static void __init smdk2410_map_io(void)
s3c24xx_set_board(&smdk2410_board);
}
-static void __init smdk2410_init_irq(void)
-{
- s3c24xx_init_irq();
-}
-
MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switch
* to SMDK2410 */
/* Maintainer: Jonas Dietsche */
@@ -119,7 +117,8 @@ MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switc
.io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
.boot_params = S3C2410_SDRAM_PA + 0x100,
.map_io = smdk2410_map_io,
- .init_irq = smdk2410_init_irq,
+ .init_irq = s3c24xx_init_irq,
+ .init_machine = smdk_machine_init,
.timer = &s3c24xx_timer,
MACHINE_END
diff --git a/arch/arm/mach-s3c2410/mach-smdk2440.c b/arch/arm/mach-s3c2410/mach-smdk2440.c
index f4315721c3b..5fffd1d5104 100644
--- a/arch/arm/mach-s3c2410/mach-smdk2440.c
+++ b/arch/arm/mach-s3c2410/mach-smdk2440.c
@@ -53,7 +53,8 @@
#include "clock.h"
#include "devs.h"
#include "cpu.h"
-#include "pm.h"
+
+#include "common-smdk.h"
static struct map_desc smdk2440_iodesc[] __initdata = {
/* ISA IO Space map (memory space selected by A24) */
@@ -197,21 +198,9 @@ static void __init smdk2440_map_io(void)
static void __init smdk2440_machine_init(void)
{
- /* Configure the LEDs (even if we have no LED support)*/
-
- s3c2410_gpio_cfgpin(S3C2410_GPF4, S3C2410_GPF4_OUTP);
- s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP);
- s3c2410_gpio_cfgpin(S3C2410_GPF6, S3C2410_GPF6_OUTP);
- s3c2410_gpio_cfgpin(S3C2410_GPF7, S3C2410_GPF7_OUTP);
-
- s3c2410_gpio_setpin(S3C2410_GPF4, 0);
- s3c2410_gpio_setpin(S3C2410_GPF5, 0);
- s3c2410_gpio_setpin(S3C2410_GPF6, 0);
- s3c2410_gpio_setpin(S3C2410_GPF7, 0);
-
s3c24xx_fb_set_platdata(&smdk2440_lcd_cfg);
- s3c2410_pm_init();
+ smdk_machine_init();
}
MACHINE_START(S3C2440, "SMDK2440")
diff --git a/arch/arm/mach-sa1100/collie.c b/arch/arm/mach-sa1100/collie.c
index 10245408247..676b5c5b75b 100644
--- a/arch/arm/mach-sa1100/collie.c
+++ b/arch/arm/mach-sa1100/collie.c
@@ -11,7 +11,8 @@
* published by the Free Software Foundation.
*
* ChangeLog:
- * 03-06-2004 John Lenz <jelenz@wisc.edu>
+ * 2006 Pavel Machek <pavel@suse.cz>
+ * 03-06-2004 John Lenz <lenz@cs.wisc.edu>
* 06-04-2002 Chris Larson <kergoth@digitalnemesis.net>
* 04-16-2001 Lineo Japan,Inc. ...
*/
@@ -87,12 +88,75 @@ static struct mcp_plat_data collie_mcp_data = {
.sclk_rate = 11981000,
};
+#ifdef CONFIG_SHARP_LOCOMO
+/*
+ * low-level UART features.
+ */
+static struct locomo_dev *uart_dev = NULL;
+
+static void collie_uart_set_mctrl(struct uart_port *port, u_int mctrl)
+{
+ if (!uart_dev) return;
+
+ if (mctrl & TIOCM_RTS)
+ locomo_gpio_write(uart_dev, LOCOMO_GPIO_RTS, 0);
+ else
+ locomo_gpio_write(uart_dev, LOCOMO_GPIO_RTS, 1);
+
+ if (mctrl & TIOCM_DTR)
+ locomo_gpio_write(uart_dev, LOCOMO_GPIO_DTR, 0);
+ else
+ locomo_gpio_write(uart_dev, LOCOMO_GPIO_DTR, 1);
+}
+
+static u_int collie_uart_get_mctrl(struct uart_port *port)
+{
+ int ret = TIOCM_CD;
+ unsigned int r;
+ if (!uart_dev) return ret;
+
+ r = locomo_gpio_read_output(uart_dev, LOCOMO_GPIO_CTS & LOCOMO_GPIO_DSR);
+ if (r & LOCOMO_GPIO_CTS)
+ ret |= TIOCM_CTS;
+ if (r & LOCOMO_GPIO_DSR)
+ ret |= TIOCM_DSR;
+
+ return ret;
+}
static struct sa1100_port_fns collie_port_fns __initdata = {
.set_mctrl = collie_uart_set_mctrl,
.get_mctrl = collie_uart_get_mctrl,
};
+static int collie_uart_probe(struct locomo_dev *dev)
+{
+ uart_dev = dev;
+ return 0;
+}
+
+static int collie_uart_remove(struct locomo_dev *dev)
+{
+ uart_dev = NULL;
+ return 0;
+}
+
+static struct locomo_driver collie_uart_driver = {
+ .drv = {
+ .name = "collie_uart",
+ },
+ .devid = LOCOMO_DEVID_UART,
+ .probe = collie_uart_probe,
+ .remove = collie_uart_remove,
+};
+
+static int __init collie_uart_init(void) {
+ return locomo_driver_register(&collie_uart_driver);
+}
+device_initcall(collie_uart_init);
+
+#endif
+
static struct resource locomo_resources[] = {
[0] = {
@@ -218,6 +282,12 @@ static void __init collie_map_io(void)
{
sa1100_map_io();
iotable_init(collie_io_desc, ARRAY_SIZE(collie_io_desc));
+
+#ifdef CONFIG_SHARP_LOCOMO
+ sa1100_register_uart_fns(&collie_port_fns);
+#endif
+ sa1100_register_uart(0, 3);
+ sa1100_register_uart(1, 1);
}
MACHINE_START(COLLIE, "Sharp-Collie")
diff --git a/arch/arm/mm/consistent.c b/arch/arm/mm/consistent.c
index 8a1bfcd5008..50e6b6bfb2e 100644
--- a/arch/arm/mm/consistent.c
+++ b/arch/arm/mm/consistent.c
@@ -18,6 +18,7 @@
#include <linux/device.h>
#include <linux/dma-mapping.h>
+#include <asm/memory.h>
#include <asm/cacheflush.h>
#include <asm/tlbflush.h>
#include <asm/sizes.h>
@@ -272,6 +273,17 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
void *
dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp)
{
+ if (arch_is_coherent()) {
+ void *virt;
+
+ virt = kmalloc(size, gfp);
+ if (!virt)
+ return NULL;
+ *handle = virt_to_dma(dev, virt);
+
+ return virt;
+ }
+
return __dma_alloc(dev, size, handle, gfp,
pgprot_noncached(pgprot_kernel));
}
@@ -350,6 +362,11 @@ void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr
WARN_ON(irqs_disabled());
+ if (arch_is_coherent()) {
+ kfree(cpu_addr);
+ return;
+ }
+
size = PAGE_ALIGN(size);
spin_lock_irqsave(&consistent_lock, flags);
diff --git a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c
index 5e5d05bcad5..f14b2d0f369 100644
--- a/arch/arm/mm/mm-armv.c
+++ b/arch/arm/mm/mm-armv.c
@@ -389,6 +389,17 @@ void __init build_mem_type_table(void)
kern_pgprot = user_pgprot = cp->pte;
/*
+ * Enable CPU-specific coherency if supported.
+ * (Only available on XSC3 at the moment.)
+ */
+ if (arch_is_coherent()) {
+ if (cpu_is_xsc3()) {
+ mem_types[MT_MEMORY].prot_sect |= PMD_SECT_S;
+ mem_types[MT_MEMORY].prot_pte |= L_PTE_COHERENT;
+ }
+ }
+
+ /*
* ARMv6 and above have extended page tables.
*/
if (cpu_arch >= CPU_ARCH_ARMv6 && (cr & CR_XP)) {
diff --git a/arch/arm/mm/proc-xsc3.S b/arch/arm/mm/proc-xsc3.S
index b9dfce57c27..80873b36c3f 100644
--- a/arch/arm/mm/proc-xsc3.S
+++ b/arch/arm/mm/proc-xsc3.S
@@ -371,7 +371,7 @@ ENTRY(cpu_xsc3_switch_mm)
ENTRY(cpu_xsc3_set_pte)
str r1, [r0], #-2048 @ linux version
- bic r2, r1, #0xff0
+ bic r2, r1, #0xdf0 @ Keep C, B, coherency bits
orr r2, r2, #PTE_TYPE_EXT @ extended page
eor r3, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
index 0887bb2a255..ec49495e651 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -70,13 +70,13 @@ config OMAP_MPU_TIMER
config OMAP_32K_TIMER
bool "Use 32KHz timer"
- depends on ARCH_OMAP16XX
+ depends on ARCH_OMAP16XX || ARCH_OMAP24XX
help
Select this option if you want to enable the OMAP 32KHz timer.
This timer saves power compared to the OMAP_MPU_TIMER, and has
support for no tick during idle. The 32KHz timer provides less
intra-tick resolution than OMAP_MPU_TIMER. The 32KHz timer is
- currently only available for OMAP-16xx.
+ currently only available for OMAP16XX and 24XX.
endchoice
diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile
index 9ccf1943fc9..2896b454641 100644
--- a/arch/arm/plat-omap/Makefile
+++ b/arch/arm/plat-omap/Makefile
@@ -3,16 +3,16 @@
#
# Common support
-obj-y := common.o sram.o sram-fn.o clock.o devices.o dma.o mux.o gpio.o mcbsp.o usb.o
+obj-y := common.o sram.o sram-fn.o clock.o devices.o dma.o mux.o gpio.o mcbsp.o usb.o fb.o
obj-m :=
obj-n :=
obj- :=
+obj-$(CONFIG_OMAP_32K_TIMER) += timer32k.o
+
# OCPI interconnect support for 1710, 1610 and 5912
obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o
-# Power Management
-obj-$(CONFIG_PM) += pm.o sleep.o
obj-$(CONFIG_CPU_FREQ) += cpu-omap.o
obj-$(CONFIG_OMAP_DM_TIMER) += dmtimer.o
diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c
index 3c2bfc0efda..06485c193ee 100644
--- a/arch/arm/plat-omap/clock.c
+++ b/arch/arm/plat-omap/clock.c
@@ -21,6 +21,7 @@
#include <linux/string.h>
#include <linux/clk.h>
#include <linux/mutex.h>
+#include <linux/platform_device.h>
#include <asm/io.h>
#include <asm/semaphore.h>
@@ -37,17 +38,37 @@ static struct clk_functions *arch_clock;
* Standard clock functions defined in include/linux/clk.h
*-------------------------------------------------------------------------*/
+/*
+ * Returns a clock. Note that we first try to use device id on the bus
+ * and clock name. If this fails, we try to use clock name only.
+ */
struct clk * clk_get(struct device *dev, const char *id)
{
struct clk *p, *clk = ERR_PTR(-ENOENT);
+ int idno;
+
+ if (dev == NULL || dev->bus != &platform_bus_type)
+ idno = -1;
+ else
+ idno = to_platform_device(dev)->id;
mutex_lock(&clocks_mutex);
+
+ list_for_each_entry(p, &clocks, node) {
+ if (p->id == idno &&
+ strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
+ clk = p;
+ break;
+ }
+ }
+
list_for_each_entry(p, &clocks, node) {
if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
clk = p;
break;
}
}
+
mutex_unlock(&clocks_mutex);
return clk;
@@ -59,6 +80,9 @@ int clk_enable(struct clk *clk)
unsigned long flags;
int ret = 0;
+ if (clk == NULL || IS_ERR(clk))
+ return -EINVAL;
+
spin_lock_irqsave(&clockfw_lock, flags);
if (arch_clock->clk_enable)
ret = arch_clock->clk_enable(clk);
@@ -72,6 +96,9 @@ void clk_disable(struct clk *clk)
{
unsigned long flags;
+ if (clk == NULL || IS_ERR(clk))
+ return;
+
spin_lock_irqsave(&clockfw_lock, flags);
if (arch_clock->clk_disable)
arch_clock->clk_disable(clk);
@@ -84,6 +111,9 @@ int clk_get_usecount(struct clk *clk)
unsigned long flags;
int ret = 0;
+ if (clk == NULL || IS_ERR(clk))
+ return 0;
+
spin_lock_irqsave(&clockfw_lock, flags);
ret = clk->usecount;
spin_unlock_irqrestore(&clockfw_lock, flags);
@@ -97,6 +127,9 @@ unsigned long clk_get_rate(struct clk *clk)
unsigned long flags;
unsigned long ret = 0;
+ if (clk == NULL || IS_ERR(clk))
+ return 0;
+
spin_lock_irqsave(&clockfw_lock, flags);
ret = clk->rate;
spin_unlock_irqrestore(&clockfw_lock, flags);
@@ -121,6 +154,9 @@ long clk_round_rate(struct clk *clk, unsigned long rate)
unsigned long flags;
long ret = 0;
+ if (clk == NULL || IS_ERR(clk))
+ return ret;
+
spin_lock_irqsave(&clockfw_lock, flags);
if (arch_clock->clk_round_rate)
ret = arch_clock->clk_round_rate(clk, rate);
@@ -133,7 +169,10 @@ EXPORT_SYMBOL(clk_round_rate);
int clk_set_rate(struct clk *clk, unsigned long rate)
{
unsigned long flags;
- int ret = 0;
+ int ret = -EINVAL;
+
+ if (clk == NULL || IS_ERR(clk))
+ return ret;
spin_lock_irqsave(&clockfw_lock, flags);
if (arch_clock->clk_set_rate)
@@ -147,7 +186,10 @@ EXPORT_SYMBOL(clk_set_rate);
int clk_set_parent(struct clk *clk, struct clk *parent)
{
unsigned long flags;
- int ret = 0;
+ int ret = -EINVAL;
+
+ if (clk == NULL || IS_ERR(clk) || parent == NULL || IS_ERR(parent))
+ return ret;
spin_lock_irqsave(&clockfw_lock, flags);
if (arch_clock->clk_set_parent)
@@ -163,6 +205,9 @@ struct clk *clk_get_parent(struct clk *clk)
unsigned long flags;
struct clk * ret = NULL;
+ if (clk == NULL || IS_ERR(clk))
+ return ret;
+
spin_lock_irqsave(&clockfw_lock, flags);
if (arch_clock->clk_get_parent)
ret = arch_clock->clk_get_parent(clk);
@@ -199,6 +244,9 @@ __setup("mpurate=", omap_clk_setup);
/* Used for clocks that always have same value as the parent clock */
void followparent_recalc(struct clk *clk)
{
+ if (clk == NULL || IS_ERR(clk))
+ return;
+
clk->rate = clk->parent->rate;
}
@@ -207,6 +255,9 @@ void propagate_rate(struct clk * tclk)
{
struct clk *clkp;
+ if (tclk == NULL || IS_ERR(tclk))
+ return;
+
list_for_each_entry(clkp, &clocks, node) {
if (likely(clkp->parent != tclk))
continue;
@@ -217,6 +268,9 @@ void propagate_rate(struct clk * tclk)
int clk_register(struct clk *clk)
{
+ if (clk == NULL || IS_ERR(clk))
+ return -EINVAL;
+
mutex_lock(&clocks_mutex);
list_add(&clk->node, &clocks);
if (clk->init)
@@ -229,6 +283,9 @@ EXPORT_SYMBOL(clk_register);
void clk_unregister(struct clk *clk)
{
+ if (clk == NULL || IS_ERR(clk))
+ return;
+
mutex_lock(&clocks_mutex);
list_del(&clk->node);
mutex_unlock(&clocks_mutex);
@@ -239,6 +296,9 @@ void clk_deny_idle(struct clk *clk)
{
unsigned long flags;
+ if (clk == NULL || IS_ERR(clk))
+ return;
+
spin_lock_irqsave(&clockfw_lock, flags);
if (arch_clock->clk_deny_idle)
arch_clock->clk_deny_idle(clk);
@@ -250,6 +310,9 @@ void clk_allow_idle(struct clk *clk)
{
unsigned long flags;
+ if (clk == NULL || IS_ERR(clk))
+ return;
+
spin_lock_irqsave(&clockfw_lock, flags);
if (arch_clock->clk_allow_idle)
arch_clock->clk_allow_idle(clk);
diff --git a/arch/arm/plat-omap/devices.c b/arch/arm/plat-omap/devices.c
index 9dcce904b60..079b67deac0 100644
--- a/arch/arm/plat-omap/devices.c
+++ b/arch/arm/plat-omap/devices.c
@@ -24,6 +24,7 @@
#include <asm/arch/board.h>
#include <asm/arch/mux.h>
#include <asm/arch/gpio.h>
+#include <asm/arch/menelaus.h>
void omap_nop_release(struct device *dev)
@@ -98,6 +99,62 @@ static inline void omap_init_i2c(void) {}
#endif
/*-------------------------------------------------------------------------*/
+#if defined(CONFIG_KEYBOARD_OMAP) || defined(CONFIG_KEYBOARD_OMAP_MODULE)
+
+static void omap_init_kp(void)
+{
+ if (machine_is_omap_h2() || machine_is_omap_h3()) {
+ omap_cfg_reg(F18_1610_KBC0);
+ omap_cfg_reg(D20_1610_KBC1);
+ omap_cfg_reg(D19_1610_KBC2);
+ omap_cfg_reg(E18_1610_KBC3);
+ omap_cfg_reg(C21_1610_KBC4);
+
+ omap_cfg_reg(G18_1610_KBR0);
+ omap_cfg_reg(F19_1610_KBR1);
+ omap_cfg_reg(H14_1610_KBR2);
+ omap_cfg_reg(E20_1610_KBR3);
+ omap_cfg_reg(E19_1610_KBR4);
+ omap_cfg_reg(N19_1610_KBR5);
+ } else if (machine_is_omap_perseus2()) {
+ omap_cfg_reg(E2_730_KBR0);
+ omap_cfg_reg(J7_730_KBR1);
+ omap_cfg_reg(E1_730_KBR2);
+ omap_cfg_reg(F3_730_KBR3);
+ omap_cfg_reg(D2_730_KBR4);
+
+ omap_cfg_reg(C2_730_KBC0);
+ omap_cfg_reg(D3_730_KBC1);
+ omap_cfg_reg(E4_730_KBC2);
+ omap_cfg_reg(F4_730_KBC3);
+ omap_cfg_reg(E3_730_KBC4);
+ } else if (machine_is_omap_h4()) {
+ omap_cfg_reg(T19_24XX_KBR0);
+ omap_cfg_reg(R19_24XX_KBR1);
+ omap_cfg_reg(V18_24XX_KBR2);
+ omap_cfg_reg(M21_24XX_KBR3);
+ omap_cfg_reg(E5__24XX_KBR4);
+ if (omap_has_menelaus()) {
+ omap_cfg_reg(B3__24XX_KBR5);
+ omap_cfg_reg(AA4_24XX_KBC2);
+ omap_cfg_reg(B13_24XX_KBC6);
+ } else {
+ omap_cfg_reg(M18_24XX_KBR5);
+ omap_cfg_reg(H19_24XX_KBC2);
+ omap_cfg_reg(N19_24XX_KBC6);
+ }
+ omap_cfg_reg(R20_24XX_KBC0);
+ omap_cfg_reg(M14_24XX_KBC1);
+ omap_cfg_reg(V17_24XX_KBC3);
+ omap_cfg_reg(P21_24XX_KBC4);
+ omap_cfg_reg(L14_24XX_KBC5);
+ }
+}
+#else
+static inline void omap_init_kp(void) {}
+#endif
+
+/*-------------------------------------------------------------------------*/
#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)
@@ -240,6 +297,55 @@ static void __init omap_init_mmc(void)
static inline void omap_init_mmc(void) {}
#endif
+/*-------------------------------------------------------------------------*/
+
+/* Numbering for the SPI-capable controllers when used for SPI:
+ * spi = 1
+ * uwire = 2
+ * mmc1..2 = 3..4
+ * mcbsp1..3 = 5..7
+ */
+
+#if defined(CONFIG_SPI_OMAP_UWIRE) || defined(CONFIG_SPI_OMAP_UWIRE_MODULE)
+
+#define OMAP_UWIRE_BASE 0xfffb3000
+
+static struct resource uwire_resources[] = {
+ {
+ .start = OMAP_UWIRE_BASE,
+ .end = OMAP_UWIRE_BASE + 0x20,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device omap_uwire_device = {
+ .name = "omap_uwire",
+ .id = -1,
+ .dev = {
+ .release = omap_nop_release,
+ },
+ .num_resources = ARRAY_SIZE(uwire_resources),
+ .resource = uwire_resources,
+};
+
+static void omap_init_uwire(void)
+{
+ /* FIXME define and use a boot tag; not all boards will be hooking
+ * up devices to the microwire controller, and multi-board configs
+ * mean that CONFIG_SPI_OMAP_UWIRE may be configured anyway...
+ */
+
+ /* board-specific code must configure chipselects (only a few
+ * are normally used) and SCLK/SDI/SDO (each has two choices).
+ */
+ (void) platform_device_register(&omap_uwire_device);
+}
+#else
+static inline void omap_init_uwire(void) {}
+#endif
+
+/*-------------------------------------------------------------------------*/
+
#if defined(CONFIG_OMAP_WATCHDOG) || defined(CONFIG_OMAP_WATCHDOG_MODULE)
#ifdef CONFIG_ARCH_OMAP24XX
@@ -310,40 +416,6 @@ static void omap_init_rng(void)
static inline void omap_init_rng(void) {}
#endif
-#if defined(CONFIG_FB_OMAP) || defined(CONFIG_FB_OMAP_MODULE)
-
-static struct omap_lcd_config omap_fb_conf;
-
-static u64 omap_fb_dma_mask = ~(u32)0;
-
-static struct platform_device omap_fb_device = {
- .name = "omapfb",
- .id = -1,
- .dev = {
- .release = omap_nop_release,
- .dma_mask = &omap_fb_dma_mask,
- .coherent_dma_mask = ~(u32)0,
- .platform_data = &omap_fb_conf,
- },
- .num_resources = 0,
-};
-
-static inline void omap_init_fb(void)
-{
- const struct omap_lcd_config *conf;
-
- conf = omap_get_config(OMAP_TAG_LCD, struct omap_lcd_config);
- if (conf != NULL)
- omap_fb_conf = *conf;
- platform_device_register(&omap_fb_device);
-}
-
-#else
-
-static inline void omap_init_fb(void) {}
-
-#endif
-
/*
* This gets called after board-specific INIT_MACHINE, and initializes most
* on-chip peripherals accessible on this board (except for few like USB):
@@ -369,9 +441,10 @@ static int __init omap_init_devices(void)
/* please keep these calls, and their implementations above,
* in alphabetical order so they're easier to sort through.
*/
- omap_init_fb();
omap_init_i2c();
+ omap_init_kp();
omap_init_mmc();
+ omap_init_uwire();
omap_init_wdt();
omap_init_rng();
diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c
index a4e5ac77f6d..5dac4230360 100644
--- a/arch/arm/plat-omap/dma.c
+++ b/arch/arm/plat-omap/dma.c
@@ -1258,6 +1258,11 @@ void omap_stop_lcd_dma(void)
omap_writew(w, OMAP1610_DMA_LCD_CTRL);
}
+int omap_lcd_dma_ext_running(void)
+{
+ return lcd_dma.ext_ctrl && lcd_dma.active;
+}
+
/*----------------------------------------------------------------------------*/
static int __init omap_init_dma(void)
@@ -1389,6 +1394,7 @@ EXPORT_SYMBOL(omap_free_lcd_dma);
EXPORT_SYMBOL(omap_enable_lcd_dma);
EXPORT_SYMBOL(omap_setup_lcd_dma);
EXPORT_SYMBOL(omap_stop_lcd_dma);
+EXPORT_SYMBOL(omap_lcd_dma_ext_running);
EXPORT_SYMBOL(omap_set_lcd_dma_b1);
EXPORT_SYMBOL(omap_set_lcd_dma_single_transfer);
EXPORT_SYMBOL(omap_set_lcd_dma_ext_controller);
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index 38d7ebf8792..eba3cb52ad8 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -97,6 +97,32 @@ int omap_dm_timers_active(void)
}
+/**
+ * omap_dm_timer_modify_idlect_mask - Check if any running timers use ARMXOR
+ * @inputmask: current value of idlect mask
+ */
+__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
+{
+ int n;
+
+ /* If ARMXOR cannot be idled this function call is unnecessary */
+ if (!(inputmask & (1 << 1)))
+ return inputmask;
+
+ /* If any active timer is using ARMXOR return modified mask */
+ for (n = 0; dm_timers[n].base; ++n)
+ if (omap_dm_timer_read_reg(&dm_timers[n], OMAP_TIMER_CTRL_REG)&
+ OMAP_TIMER_CTRL_ST) {
+ if (((omap_readl(MOD_CONF_CTRL_1)>>(n*2)) & 0x03) == 0)
+ inputmask &= ~(1 << 1);
+ else
+ inputmask &= ~(1 << 2);
+ }
+
+ return inputmask;
+}
+
+
void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
{
int n = (timer - dm_timers) << 1;
diff --git a/arch/arm/plat-omap/fb.c b/arch/arm/plat-omap/fb.c
new file mode 100644
index 00000000000..305e9b990b7
--- /dev/null
+++ b/arch/arm/plat-omap/fb.c
@@ -0,0 +1,80 @@
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/bootmem.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+#include <asm/mach/map.h>
+
+#include <asm/arch/board.h>
+#include <asm/arch/sram.h>
+#include <asm/arch/omapfb.h>
+
+#if defined(CONFIG_FB_OMAP) || defined(CONFIG_FB_OMAP_MODULE)
+
+static struct omapfb_platform_data omapfb_config;
+
+static u64 omap_fb_dma_mask = ~(u32)0;
+
+static struct platform_device omap_fb_device = {
+ .name = "omapfb",
+ .id = -1,
+ .dev = {
+ .dma_mask = &omap_fb_dma_mask,
+ .coherent_dma_mask = ~(u32)0,
+ .platform_data = &omapfb_config,
+ },
+ .num_resources = 0,
+};
+
+/* called from map_io */
+void omapfb_reserve_mem(void)
+{
+ const struct omap_fbmem_config *fbmem_conf;
+
+ omapfb_config.fbmem.fb_sram_start = omap_fb_sram_start;
+ omapfb_config.fbmem.fb_sram_size = omap_fb_sram_size;
+
+ fbmem_conf = omap_get_config(OMAP_TAG_FBMEM, struct omap_fbmem_config);
+
+ if (fbmem_conf != NULL) {
+ /* indicate that the bootloader already initialized the
+ * fb device, so we'll skip that part in the fb driver
+ */
+ omapfb_config.fbmem.fb_sdram_start = fbmem_conf->fb_sdram_start;
+ omapfb_config.fbmem.fb_sdram_size = fbmem_conf->fb_sdram_size;
+ if (fbmem_conf->fb_sdram_size) {
+ pr_info("Reserving %u bytes SDRAM for frame buffer\n",
+ fbmem_conf->fb_sdram_size);
+ reserve_bootmem(fbmem_conf->fb_sdram_start,
+ fbmem_conf->fb_sdram_size);
+ }
+ }
+}
+
+static inline int omap_init_fb(void)
+{
+ const struct omap_lcd_config *conf;
+
+ conf = omap_get_config(OMAP_TAG_LCD, struct omap_lcd_config);
+ if (conf == NULL)
+ return 0;
+
+ omapfb_config.lcd = *conf;
+
+ return platform_device_register(&omap_fb_device);
+}
+
+arch_initcall(omap_init_fb);
+
+#else
+
+void omapfb_reserve_mem(void) {}
+
+#endif
+
+
diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c
index b4d5b9e4bfc..d3c8ea7eecf 100644
--- a/arch/arm/plat-omap/gpio.c
+++ b/arch/arm/plat-omap/gpio.c
@@ -174,7 +174,7 @@ static int gpio_bank_count;
static inline struct gpio_bank *get_gpio_bank(int gpio)
{
#ifdef CONFIG_ARCH_OMAP15XX
- if (cpu_is_omap1510()) {
+ if (cpu_is_omap15xx()) {
if (OMAP_GPIO_IS_MPUIO(gpio))
return &gpio_bank[0];
return &gpio_bank[1];
@@ -223,7 +223,7 @@ static inline int gpio_valid(int gpio)
return 0;
}
#ifdef CONFIG_ARCH_OMAP15XX
- if (cpu_is_omap1510() && gpio < 16)
+ if (cpu_is_omap15xx() && gpio < 16)
return 0;
#endif
#if defined(CONFIG_ARCH_OMAP16XX)
@@ -402,13 +402,13 @@ static inline void set_24xx_gpio_triggering(void __iomem *base, int gpio, int tr
u32 gpio_bit = 1 << gpio;
MOD_REG_BIT(OMAP24XX_GPIO_LEVELDETECT0, gpio_bit,
- trigger & IRQT_LOW);
+ trigger & __IRQT_LOWLVL);
MOD_REG_BIT(OMAP24XX_GPIO_LEVELDETECT1, gpio_bit,
- trigger & IRQT_HIGH);
+ trigger & __IRQT_HIGHLVL);
MOD_REG_BIT(OMAP24XX_GPIO_RISINGDETECT, gpio_bit,
- trigger & IRQT_RISING);
+ trigger & __IRQT_RISEDGE);
MOD_REG_BIT(OMAP24XX_GPIO_FALLINGDETECT, gpio_bit,
- trigger & IRQT_FALLING);
+ trigger & __IRQT_FALEDGE);
/* FIXME: Possibly do 'set_irq_handler(j, do_level_IRQ)' if only level
* triggering requested. */
}
@@ -422,9 +422,9 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)
case METHOD_MPUIO:
reg += OMAP_MPUIO_GPIO_INT_EDGE;
l = __raw_readl(reg);
- if (trigger == IRQT_RISING)
+ if (trigger & __IRQT_RISEDGE)
l |= 1 << gpio;
- else if (trigger == IRQT_FALLING)
+ else if (trigger & __IRQT_FALEDGE)
l &= ~(1 << gpio);
else
goto bad;
@@ -432,9 +432,9 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)
case METHOD_GPIO_1510:
reg += OMAP1510_GPIO_INT_CONTROL;
l = __raw_readl(reg);
- if (trigger == IRQT_RISING)
+ if (trigger & __IRQT_RISEDGE)
l |= 1 << gpio;
- else if (trigger == IRQT_FALLING)
+ else if (trigger & __IRQT_FALEDGE)
l &= ~(1 << gpio);
else
goto bad;
@@ -446,20 +446,21 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)
reg += OMAP1610_GPIO_EDGE_CTRL1;
gpio &= 0x07;
/* We allow only edge triggering, i.e. two lowest bits */
- if (trigger & ~IRQT_BOTHEDGE)
+ if (trigger & (__IRQT_LOWLVL | __IRQT_HIGHLVL))
BUG();
- /* NOTE: knows __IRQT_{FAL,RIS}EDGE match OMAP hardware */
- trigger &= 0x03;
l = __raw_readl(reg);
l &= ~(3 << (gpio << 1));
- l |= trigger << (gpio << 1);
+ if (trigger & __IRQT_RISEDGE)
+ l |= 2 << (gpio << 1);
+ if (trigger & __IRQT_FALEDGE)
+ l |= 1 << (gpio << 1);
break;
case METHOD_GPIO_730:
reg += OMAP730_GPIO_INT_CONTROL;
l = __raw_readl(reg);
- if (trigger == IRQT_RISING)
+ if (trigger & __IRQT_RISEDGE)
l |= 1 << gpio;
- else if (trigger == IRQT_FALLING)
+ else if (trigger & __IRQT_FALEDGE)
l &= ~(1 << gpio);
else
goto bad;
@@ -491,7 +492,9 @@ static int gpio_irq_type(unsigned irq, unsigned type)
if (check_gpio(gpio) < 0)
return -EINVAL;
- if (type & (__IRQT_LOWLVL|__IRQT_HIGHLVL|IRQT_PROBE))
+ if (type & IRQT_PROBE)
+ return -EINVAL;
+ if (!cpu_is_omap24xx() && (type & (__IRQT_LOWLVL|__IRQT_HIGHLVL)))
return -EINVAL;
bank = get_gpio_bank(gpio);
@@ -755,13 +758,32 @@ static void gpio_irq_handler(unsigned int irq, struct irqdesc *desc,
if (bank->method == METHOD_GPIO_24XX)
isr_reg = bank->base + OMAP24XX_GPIO_IRQSTATUS1;
#endif
-
while(1) {
- isr = __raw_readl(isr_reg);
- _enable_gpio_irqbank(bank, isr, 0);
- _clear_gpio_irqbank(bank, isr);
- _enable_gpio_irqbank(bank, isr, 1);
- desc->chip->unmask(irq);
+ u32 isr_saved, level_mask = 0;
+
+ isr_saved = isr = __raw_readl(isr_reg);
+
+ if (cpu_is_omap15xx() && (bank->method == METHOD_MPUIO))
+ isr &= 0x0000ffff;
+
+ if (cpu_is_omap24xx())
+ level_mask =
+ __raw_readl(bank->base +
+ OMAP24XX_GPIO_LEVELDETECT0) |
+ __raw_readl(bank->base +
+ OMAP24XX_GPIO_LEVELDETECT1);
+
+ /* clear edge sensitive interrupts before handler(s) are
+ called so that we don't miss any interrupt occurred while
+ executing them */
+ _enable_gpio_irqbank(bank, isr_saved & ~level_mask, 0);
+ _clear_gpio_irqbank(bank, isr_saved & ~level_mask);
+ _enable_gpio_irqbank(bank, isr_saved & ~level_mask, 1);
+
+ /* if there is only edge sensitive GPIO pin interrupts
+ configured, we could unmask GPIO bank interrupt immediately */
+ if (!level_mask)
+ desc->chip->unmask(irq);
if (!isr)
break;
@@ -774,6 +796,20 @@ static void gpio_irq_handler(unsigned int irq, struct irqdesc *desc,
d = irq_desc + gpio_irq;
desc_handle_irq(gpio_irq, d, regs);
}
+
+ if (cpu_is_omap24xx()) {
+ /* clear level sensitive interrupts after handler(s) */
+ _enable_gpio_irqbank(bank, isr_saved & level_mask, 0);
+ _clear_gpio_irqbank(bank, isr_saved & level_mask);
+ _enable_gpio_irqbank(bank, isr_saved & level_mask, 1);
+ }
+
+ /* if bank has any level sensitive GPIO pin interrupt
+ configured, we must unmask the bank interrupt only after
+ handler(s) are executed in order to avoid spurious bank
+ interrupt */
+ if (level_mask)
+ desc->chip->unmask(irq);
}
}
@@ -848,7 +884,7 @@ static int __init _omap_gpio_init(void)
initialized = 1;
- if (cpu_is_omap1510()) {
+ if (cpu_is_omap15xx()) {
gpio_ick = clk_get(NULL, "arm_gpio_ck");
if (IS_ERR(gpio_ick))
printk("Could not get arm_gpio_ck\n");
@@ -869,7 +905,7 @@ static int __init _omap_gpio_init(void)
}
#ifdef CONFIG_ARCH_OMAP15XX
- if (cpu_is_omap1510()) {
+ if (cpu_is_omap15xx()) {
printk(KERN_INFO "OMAP1510 GPIO hardware\n");
gpio_bank_count = 2;
gpio_bank = gpio_bank_1510;
diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c
index 1cd2cace7e1..196aac3ac32 100644
--- a/arch/arm/plat-omap/mcbsp.c
+++ b/arch/arm/plat-omap/mcbsp.c
@@ -34,7 +34,7 @@
#ifdef CONFIG_MCBSP_DEBUG
#define DBG(x...) printk(x)
#else
-#define DBG(x...) do { } while (0)
+#define DBG(x...) do { } while (0)
#endif
struct omap_mcbsp {
@@ -44,6 +44,7 @@ struct omap_mcbsp {
omap_mcbsp_word_length rx_word_length;
omap_mcbsp_word_length tx_word_length;
+ omap_mcbsp_io_type_t io_type; /* IRQ or poll */
/* IRQ based TX/RX */
int rx_irq;
int tx_irq;
@@ -64,10 +65,19 @@ struct omap_mcbsp {
};
static struct omap_mcbsp mcbsp[OMAP_MAX_MCBSP_COUNT];
+#ifdef CONFIG_ARCH_OMAP1
static struct clk *mcbsp_dsp_ck = 0;
static struct clk *mcbsp_api_ck = 0;
static struct clk *mcbsp_dspxor_ck = 0;
-
+#endif
+#ifdef CONFIG_ARCH_OMAP2
+static struct clk *mcbsp1_ick = 0;
+static struct clk *mcbsp1_fck = 0;
+static struct clk *mcbsp2_ick = 0;
+static struct clk *mcbsp2_fck = 0;
+static struct clk *sys_ck = 0;
+static struct clk *sys_clkout = 0;
+#endif
static void omap_mcbsp_dump_reg(u8 id)
{
@@ -88,7 +98,6 @@ static void omap_mcbsp_dump_reg(u8 id)
DBG("***********************\n");
}
-
static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
{
struct omap_mcbsp * mcbsp_tx = (struct omap_mcbsp *)(dev_id);
@@ -109,7 +118,6 @@ static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *dev_id, struct pt_re
return IRQ_HANDLED;
}
-
static void omap_mcbsp_tx_dma_callback(int lch, u16 ch_status, void *data)
{
struct omap_mcbsp * mcbsp_dma_tx = (struct omap_mcbsp *)(data);
@@ -176,7 +184,7 @@ static int omap_mcbsp_check(unsigned int id)
return 0;
}
- if (cpu_is_omap1510() || cpu_is_omap16xx()) {
+ if (cpu_is_omap15xx() || cpu_is_omap16xx() || cpu_is_omap24xx()) {
if (id > OMAP_MAX_MCBSP_COUNT) {
printk(KERN_ERR "OMAP-McBSP: McBSP%d doesn't exist\n", id + 1);
return -1;
@@ -187,9 +195,10 @@ static int omap_mcbsp_check(unsigned int id)
return -1;
}
+#ifdef CONFIG_ARCH_OMAP1
static void omap_mcbsp_dsp_request(void)
{
- if (cpu_is_omap1510() || cpu_is_omap16xx()) {
+ if (cpu_is_omap15xx() || cpu_is_omap16xx()) {
clk_enable(mcbsp_dsp_ck);
clk_enable(mcbsp_api_ck);
@@ -207,12 +216,49 @@ static void omap_mcbsp_dsp_request(void)
static void omap_mcbsp_dsp_free(void)
{
- if (cpu_is_omap1510() || cpu_is_omap16xx()) {
+ if (cpu_is_omap15xx() || cpu_is_omap16xx()) {
clk_disable(mcbsp_dspxor_ck);
clk_disable(mcbsp_dsp_ck);
clk_disable(mcbsp_api_ck);
}
}
+#endif
+
+#ifdef CONFIG_ARCH_OMAP2
+static void omap2_mcbsp2_mux_setup(void)
+{
+ omap_cfg_reg(Y15_24XX_MCBSP2_CLKX);
+ omap_cfg_reg(R14_24XX_MCBSP2_FSX);
+ omap_cfg_reg(W15_24XX_MCBSP2_DR);
+ omap_cfg_reg(V15_24XX_MCBSP2_DX);
+ omap_cfg_reg(V14_24XX_GPIO117);
+ omap_cfg_reg(W14_24XX_SYS_CLKOUT);
+}
+#endif
+
+/*
+ * We can choose between IRQ based or polled IO.
+ * This needs to be called before omap_mcbsp_request().
+ */
+int omap_mcbsp_set_io_type(unsigned int id, omap_mcbsp_io_type_t io_type)
+{
+ if (omap_mcbsp_check(id) < 0)
+ return -EINVAL;
+
+ spin_lock(&mcbsp[id].lock);
+
+ if (!mcbsp[id].free) {
+ printk (KERN_ERR "OMAP-McBSP: McBSP%d is currently in use\n", id + 1);
+ spin_unlock(&mcbsp[id].lock);
+ return -EINVAL;
+ }
+
+ mcbsp[id].io_type = io_type;
+
+ spin_unlock(&mcbsp[id].lock);
+
+ return 0;
+}
int omap_mcbsp_request(unsigned int id)
{
@@ -221,12 +267,26 @@ int omap_mcbsp_request(unsigned int id)
if (omap_mcbsp_check(id) < 0)
return -EINVAL;
+#ifdef CONFIG_ARCH_OMAP1
/*
* On 1510, 1610 and 1710, McBSP1 and McBSP3
* are DSP public peripherals.
*/
if (id == OMAP_MCBSP1 || id == OMAP_MCBSP3)
omap_mcbsp_dsp_request();
+#endif
+
+#ifdef CONFIG_ARCH_OMAP2
+ if (cpu_is_omap24xx()) {
+ if (id == OMAP_MCBSP1) {
+ clk_enable(mcbsp1_ick);
+ clk_enable(mcbsp1_fck);
+ } else {
+ clk_enable(mcbsp2_ick);
+ clk_enable(mcbsp2_fck);
+ }
+ }
+#endif
spin_lock(&mcbsp[id].lock);
if (!mcbsp[id].free) {
@@ -238,30 +298,33 @@ int omap_mcbsp_request(unsigned int id)
mcbsp[id].free = 0;
spin_unlock(&mcbsp[id].lock);
- /* We need to get IRQs here */
- err = request_irq(mcbsp[id].tx_irq, omap_mcbsp_tx_irq_handler, 0,
- "McBSP",
- (void *) (&mcbsp[id]));
- if (err != 0) {
- printk(KERN_ERR "OMAP-McBSP: Unable to request TX IRQ %d for McBSP%d\n",
- mcbsp[id].tx_irq, mcbsp[id].id);
- return err;
- }
+ if (mcbsp[id].io_type == OMAP_MCBSP_IRQ_IO) {
+ /* We need to get IRQs here */
+ err = request_irq(mcbsp[id].tx_irq, omap_mcbsp_tx_irq_handler, 0,
+ "McBSP",
+ (void *) (&mcbsp[id]));
+ if (err != 0) {
+ printk(KERN_ERR "OMAP-McBSP: Unable to request TX IRQ %d for McBSP%d\n",
+ mcbsp[id].tx_irq, mcbsp[id].id);
+ return err;
+ }
- init_completion(&(mcbsp[id].tx_irq_completion));
+ init_completion(&(mcbsp[id].tx_irq_completion));
- err = request_irq(mcbsp[id].rx_irq, omap_mcbsp_rx_irq_handler, 0,
- "McBSP",
- (void *) (&mcbsp[id]));
- if (err != 0) {
- printk(KERN_ERR "OMAP-McBSP: Unable to request RX IRQ %d for McBSP%d\n",
- mcbsp[id].rx_irq, mcbsp[id].id);
- free_irq(mcbsp[id].tx_irq, (void *) (&mcbsp[id]));
- return err;
+ err = request_irq(mcbsp[id].rx_irq, omap_mcbsp_rx_irq_handler, 0,
+ "McBSP",
+ (void *) (&mcbsp[id]));
+ if (err != 0) {
+ printk(KERN_ERR "OMAP-McBSP: Unable to request RX IRQ %d for McBSP%d\n",
+ mcbsp[id].rx_irq, mcbsp[id].id);
+ free_irq(mcbsp[id].tx_irq, (void *) (&mcbsp[id]));
+ return err;
+ }
+
+ init_completion(&(mcbsp[id].rx_irq_completion));
}
- init_completion(&(mcbsp[id].rx_irq_completion));
return 0;
}
@@ -271,8 +334,24 @@ void omap_mcbsp_free(unsigned int id)
if (omap_mcbsp_check(id) < 0)
return;
- if (id == OMAP_MCBSP1 || id == OMAP_MCBSP3)
- omap_mcbsp_dsp_free();
+#ifdef CONFIG_ARCH_OMAP1
+ if (cpu_class_is_omap1()) {
+ if (id == OMAP_MCBSP1 || id == OMAP_MCBSP3)
+ omap_mcbsp_dsp_free();
+ }
+#endif
+
+#ifdef CONFIG_ARCH_OMAP2
+ if (cpu_is_omap24xx()) {
+ if (id == OMAP_MCBSP1) {
+ clk_disable(mcbsp1_ick);
+ clk_disable(mcbsp1_fck);
+ } else {
+ clk_disable(mcbsp2_ick);
+ clk_disable(mcbsp2_fck);
+ }
+ }
+#endif
spin_lock(&mcbsp[id].lock);
if (mcbsp[id].free) {
@@ -284,9 +363,11 @@ void omap_mcbsp_free(unsigned int id)
mcbsp[id].free = 1;
spin_unlock(&mcbsp[id].lock);
- /* Free IRQs */
- free_irq(mcbsp[id].rx_irq, (void *) (&mcbsp[id]));
- free_irq(mcbsp[id].tx_irq, (void *) (&mcbsp[id]));
+ if (mcbsp[id].io_type == OMAP_MCBSP_IRQ_IO) {
+ /* Free IRQs */
+ free_irq(mcbsp[id].rx_irq, (void *) (&mcbsp[id]));
+ free_irq(mcbsp[id].tx_irq, (void *) (&mcbsp[id]));
+ }
}
/*
@@ -461,6 +542,115 @@ u32 omap_mcbsp_recv_word(unsigned int id)
}
+int omap_mcbsp_spi_master_xmit_word_poll(unsigned int id, u32 word)
+{
+ u32 io_base = mcbsp[id].io_base;
+ omap_mcbsp_word_length tx_word_length = mcbsp[id].tx_word_length;
+ omap_mcbsp_word_length rx_word_length = mcbsp[id].rx_word_length;
+ u16 spcr2, spcr1, attempts = 0, word_lsb, word_msb = 0;
+
+ if (tx_word_length != rx_word_length)
+ return -EINVAL;
+
+ /* First we wait for the transmitter to be ready */
+ spcr2 = OMAP_MCBSP_READ(io_base, SPCR2);
+ while (!(spcr2 & XRDY)) {
+ spcr2 = OMAP_MCBSP_READ(io_base, SPCR2);
+ if (attempts++ > 1000) {
+ /* We must reset the transmitter */
+ OMAP_MCBSP_WRITE(io_base, SPCR2, spcr2 & (~XRST));
+ udelay(10);
+ OMAP_MCBSP_WRITE(io_base, SPCR2, spcr2 | XRST);
+ udelay(10);
+ printk("McBSP transmitter not ready\n");
+ return -EAGAIN;
+ }
+ }
+
+ /* Now we can push the data */
+ if (tx_word_length > OMAP_MCBSP_WORD_16)
+ OMAP_MCBSP_WRITE(io_base, DXR2, word >> 16);
+ OMAP_MCBSP_WRITE(io_base, DXR1, word & 0xffff);
+
+ /* We wait for the receiver to be ready */
+ spcr1 = OMAP_MCBSP_READ(io_base, SPCR1);
+ while (!(spcr1 & RRDY)) {
+ spcr1 = OMAP_MCBSP_READ(io_base, SPCR1);
+ if (attempts++ > 1000) {
+ /* We must reset the receiver */
+ OMAP_MCBSP_WRITE(io_base, SPCR1, spcr1 & (~RRST));
+ udelay(10);
+ OMAP_MCBSP_WRITE(io_base, SPCR1, spcr1 | RRST);
+ udelay(10);
+ printk("McBSP receiver not ready\n");
+ return -EAGAIN;
+ }
+ }
+
+ /* Receiver is ready, let's read the dummy data */
+ if (rx_word_length > OMAP_MCBSP_WORD_16)
+ word_msb = OMAP_MCBSP_READ(io_base, DRR2);
+ word_lsb = OMAP_MCBSP_READ(io_base, DRR1);
+
+ return 0;
+}
+
+int omap_mcbsp_spi_master_recv_word_poll(unsigned int id, u32 * word)
+{
+ u32 io_base = mcbsp[id].io_base, clock_word = 0;
+ omap_mcbsp_word_length tx_word_length = mcbsp[id].tx_word_length;
+ omap_mcbsp_word_length rx_word_length = mcbsp[id].rx_word_length;
+ u16 spcr2, spcr1, attempts = 0, word_lsb, word_msb = 0;
+
+ if (tx_word_length != rx_word_length)
+ return -EINVAL;
+
+ /* First we wait for the transmitter to be ready */
+ spcr2 = OMAP_MCBSP_READ(io_base, SPCR2);
+ while (!(spcr2 & XRDY)) {
+ spcr2 = OMAP_MCBSP_READ(io_base, SPCR2);
+ if (attempts++ > 1000) {
+ /* We must reset the transmitter */
+ OMAP_MCBSP_WRITE(io_base, SPCR2, spcr2 & (~XRST));
+ udelay(10);
+ OMAP_MCBSP_WRITE(io_base, SPCR2, spcr2 | XRST);
+ udelay(10);
+ printk("McBSP transmitter not ready\n");
+ return -EAGAIN;
+ }
+ }
+
+ /* We first need to enable the bus clock */
+ if (tx_word_length > OMAP_MCBSP_WORD_16)
+ OMAP_MCBSP_WRITE(io_base, DXR2, clock_word >> 16);
+ OMAP_MCBSP_WRITE(io_base, DXR1, clock_word & 0xffff);
+
+ /* We wait for the receiver to be ready */
+ spcr1 = OMAP_MCBSP_READ(io_base, SPCR1);
+ while (!(spcr1 & RRDY)) {
+ spcr1 = OMAP_MCBSP_READ(io_base, SPCR1);
+ if (attempts++ > 1000) {
+ /* We must reset the receiver */
+ OMAP_MCBSP_WRITE(io_base, SPCR1, spcr1 & (~RRST));
+ udelay(10);
+ OMAP_MCBSP_WRITE(io_base, SPCR1, spcr1 | RRST);
+ udelay(10);
+ printk("McBSP receiver not ready\n");
+ return -EAGAIN;
+ }
+ }
+
+ /* Receiver is ready, there is something for us */
+ if (rx_word_length > OMAP_MCBSP_WORD_16)
+ word_msb = OMAP_MCBSP_READ(io_base, DRR2);
+ word_lsb = OMAP_MCBSP_READ(io_base, DRR1);
+
+ word[0] = (word_lsb | (word_msb << 16));
+
+ return 0;
+}
+
+
/*
* Simple DMA based buffer rx/tx routines.
* Nothing fancy, just a single buffer tx/rx through DMA.
@@ -471,6 +661,9 @@ u32 omap_mcbsp_recv_word(unsigned int id)
int omap_mcbsp_xmit_buffer(unsigned int id, dma_addr_t buffer, unsigned int length)
{
int dma_tx_ch;
+ int src_port = 0;
+ int dest_port = 0;
+ int sync_dev = 0;
if (omap_mcbsp_check(id) < 0)
return -EINVAL;
@@ -487,20 +680,27 @@ int omap_mcbsp_xmit_buffer(unsigned int id, dma_addr_t buffer, unsigned int leng
init_completion(&(mcbsp[id].tx_dma_completion));
+ if (cpu_class_is_omap1()) {
+ src_port = OMAP_DMA_PORT_TIPB;
+ dest_port = OMAP_DMA_PORT_EMIFF;
+ }
+ if (cpu_is_omap24xx())
+ sync_dev = mcbsp[id].dma_tx_sync;
+
omap_set_dma_transfer_params(mcbsp[id].dma_tx_lch,
OMAP_DMA_DATA_TYPE_S16,
length >> 1, 1,
OMAP_DMA_SYNC_ELEMENT,
- 0, 0);
+ sync_dev, 0);
omap_set_dma_dest_params(mcbsp[id].dma_tx_lch,
- OMAP_DMA_PORT_TIPB,
+ src_port,
OMAP_DMA_AMODE_CONSTANT,
mcbsp[id].io_base + OMAP_MCBSP_REG_DXR1,
0, 0);
omap_set_dma_src_params(mcbsp[id].dma_tx_lch,
- OMAP_DMA_PORT_EMIFF,
+ dest_port,
OMAP_DMA_AMODE_POST_INC,
buffer,
0, 0);
@@ -514,6 +714,9 @@ int omap_mcbsp_xmit_buffer(unsigned int id, dma_addr_t buffer, unsigned int leng
int omap_mcbsp_recv_buffer(unsigned int id, dma_addr_t buffer, unsigned int length)
{
int dma_rx_ch;
+ int src_port = 0;
+ int dest_port = 0;
+ int sync_dev = 0;
if (omap_mcbsp_check(id) < 0)
return -EINVAL;
@@ -530,20 +733,27 @@ int omap_mcbsp_recv_buffer(unsigned int id, dma_addr_t buffer, unsigned int leng
init_completion(&(mcbsp[id].rx_dma_completion));
+ if (cpu_class_is_omap1()) {
+ src_port = OMAP_DMA_PORT_TIPB;
+ dest_port = OMAP_DMA_PORT_EMIFF;
+ }
+ if (cpu_is_omap24xx())
+ sync_dev = mcbsp[id].dma_rx_sync;
+
omap_set_dma_transfer_params(mcbsp[id].dma_rx_lch,
OMAP_DMA_DATA_TYPE_S16,
length >> 1, 1,
OMAP_DMA_SYNC_ELEMENT,
- 0, 0);
+ sync_dev, 0);
omap_set_dma_src_params(mcbsp[id].dma_rx_lch,
- OMAP_DMA_PORT_TIPB,
+ src_port,
OMAP_DMA_AMODE_CONSTANT,
mcbsp[id].io_base + OMAP_MCBSP_REG_DRR1,
0, 0);
omap_set_dma_dest_params(mcbsp[id].dma_rx_lch,
- OMAP_DMA_PORT_EMIFF,
+ dest_port,
OMAP_DMA_AMODE_POST_INC,
buffer,
0, 0);
@@ -688,6 +898,23 @@ static const struct omap_mcbsp_info mcbsp_1610[] = {
};
#endif
+#if defined(CONFIG_ARCH_OMAP24XX)
+static const struct omap_mcbsp_info mcbsp_24xx[] = {
+ [0] = { .virt_base = IO_ADDRESS(OMAP24XX_MCBSP1_BASE),
+ .dma_rx_sync = OMAP24XX_DMA_MCBSP1_RX,
+ .dma_tx_sync = OMAP24XX_DMA_MCBSP1_TX,
+ .rx_irq = INT_24XX_MCBSP1_IRQ_RX,
+ .tx_irq = INT_24XX_MCBSP1_IRQ_TX,
+ },
+ [1] = { .virt_base = IO_ADDRESS(OMAP24XX_MCBSP2_BASE),
+ .dma_rx_sync = OMAP24XX_DMA_MCBSP2_RX,
+ .dma_tx_sync = OMAP24XX_DMA_MCBSP2_TX,
+ .rx_irq = INT_24XX_MCBSP2_IRQ_RX,
+ .tx_irq = INT_24XX_MCBSP2_IRQ_TX,
+ },
+};
+#endif
+
static int __init omap_mcbsp_init(void)
{
int mcbsp_count = 0, i;
@@ -695,6 +922,7 @@ static int __init omap_mcbsp_init(void)
printk("Initializing OMAP McBSP system\n");
+#ifdef CONFIG_ARCH_OMAP1
mcbsp_dsp_ck = clk_get(0, "dsp_ck");
if (IS_ERR(mcbsp_dsp_ck)) {
printk(KERN_ERR "mcbsp: could not acquire dsp_ck handle.\n");
@@ -710,6 +938,29 @@ static int __init omap_mcbsp_init(void)
printk(KERN_ERR "mcbsp: could not acquire dspxor_ck handle.\n");
return PTR_ERR(mcbsp_dspxor_ck);
}
+#endif
+#ifdef CONFIG_ARCH_OMAP2
+ mcbsp1_ick = clk_get(0, "mcbsp1_ick");
+ if (IS_ERR(mcbsp1_ick)) {
+ printk(KERN_ERR "mcbsp: could not acquire mcbsp1_ick handle.\n");
+ return PTR_ERR(mcbsp1_ick);
+ }
+ mcbsp1_fck = clk_get(0, "mcbsp1_fck");
+ if (IS_ERR(mcbsp1_fck)) {
+ printk(KERN_ERR "mcbsp: could not acquire mcbsp1_fck handle.\n");
+ return PTR_ERR(mcbsp1_fck);
+ }
+ mcbsp2_ick = clk_get(0, "mcbsp2_ick");
+ if (IS_ERR(mcbsp2_ick)) {
+ printk(KERN_ERR "mcbsp: could not acquire mcbsp2_ick handle.\n");
+ return PTR_ERR(mcbsp2_ick);
+ }
+ mcbsp2_fck = clk_get(0, "mcbsp2_fck");
+ if (IS_ERR(mcbsp2_fck)) {
+ printk(KERN_ERR "mcbsp: could not acquire mcbsp2_fck handle.\n");
+ return PTR_ERR(mcbsp2_fck);
+ }
+#endif
#ifdef CONFIG_ARCH_OMAP730
if (cpu_is_omap730()) {
@@ -718,7 +969,7 @@ static int __init omap_mcbsp_init(void)
}
#endif
#ifdef CONFIG_ARCH_OMAP15XX
- if (cpu_is_omap1510()) {
+ if (cpu_is_omap15xx()) {
mcbsp_info = mcbsp_1510;
mcbsp_count = ARRAY_SIZE(mcbsp_1510);
}
@@ -729,6 +980,19 @@ static int __init omap_mcbsp_init(void)
mcbsp_count = ARRAY_SIZE(mcbsp_1610);
}
#endif
+#if defined(CONFIG_ARCH_OMAP24XX)
+ if (cpu_is_omap24xx()) {
+ mcbsp_info = mcbsp_24xx;
+ mcbsp_count = ARRAY_SIZE(mcbsp_24xx);
+
+ /* REVISIT: where's the right place? */
+ omap2_mcbsp2_mux_setup();
+ sys_ck = clk_get(0, "sys_ck");
+ sys_clkout = clk_get(0, "sys_clkout");
+ clk_set_parent(sys_clkout, sys_ck);
+ clk_enable(sys_clkout);
+ }
+#endif
for (i = 0; i < OMAP_MAX_MCBSP_COUNT ; i++) {
if (i >= mcbsp_count) {
mcbsp[i].io_base = 0;
@@ -741,6 +1005,7 @@ static int __init omap_mcbsp_init(void)
mcbsp[i].dma_rx_lch = -1;
mcbsp[i].io_base = mcbsp_info[i].virt_base;
+ mcbsp[i].io_type = OMAP_MCBSP_IRQ_IO; /* Default I/O is IRQ based */
mcbsp[i].tx_irq = mcbsp_info[i].tx_irq;
mcbsp[i].rx_irq = mcbsp_info[i].rx_irq;
mcbsp[i].dma_rx_sync = mcbsp_info[i].dma_rx_sync;
@@ -751,11 +1016,11 @@ static int __init omap_mcbsp_init(void)
return 0;
}
-
arch_initcall(omap_mcbsp_init);
EXPORT_SYMBOL(omap_mcbsp_config);
EXPORT_SYMBOL(omap_mcbsp_request);
+EXPORT_SYMBOL(omap_mcbsp_set_io_type);
EXPORT_SYMBOL(omap_mcbsp_free);
EXPORT_SYMBOL(omap_mcbsp_start);
EXPORT_SYMBOL(omap_mcbsp_stop);
@@ -763,4 +1028,6 @@ EXPORT_SYMBOL(omap_mcbsp_xmit_word);
EXPORT_SYMBOL(omap_mcbsp_recv_word);
EXPORT_SYMBOL(omap_mcbsp_xmit_buffer);
EXPORT_SYMBOL(omap_mcbsp_recv_buffer);
+EXPORT_SYMBOL(omap_mcbsp_spi_master_xmit_word_poll);
+EXPORT_SYMBOL(omap_mcbsp_spi_master_recv_word_poll);
EXPORT_SYMBOL(omap_mcbsp_set_spi_mode);
diff --git a/arch/arm/plat-omap/ocpi.c b/arch/arm/plat-omap/ocpi.c
index 5cc6775c789..37792d43738 100644
--- a/arch/arm/plat-omap/ocpi.c
+++ b/arch/arm/plat-omap/ocpi.c
@@ -62,9 +62,6 @@ int ocpi_enable(void)
if (!cpu_is_omap16xx())
return -ENODEV;
- /* Make sure there's clock for OCPI */
- clk_enable(ocpi_ck);
-
/* Enable access for OHCI in OCPI */
val = omap_readl(OCPI_PROT);
val &= ~0xff;
diff --git a/arch/arm/plat-omap/pm.c b/arch/arm/plat-omap/pm.c
index 093efd786f2..1a24e2c1071 100644
--- a/arch/arm/plat-omap/pm.c
+++ b/arch/arm/plat-omap/pm.c
@@ -38,6 +38,7 @@
#include <linux/pm.h>
#include <linux/sched.h>
#include <linux/proc_fs.h>
+#include <linux/pm.h>
#include <linux/interrupt.h>
#include <asm/io.h>
diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c
index ee82763b02b..b7bf09b1b41 100644
--- a/arch/arm/plat-omap/sram.c
+++ b/arch/arm/plat-omap/sram.c
@@ -16,24 +16,94 @@
#include <linux/kernel.h>
#include <linux/init.h>
-#include <asm/mach/map.h>
#include <asm/tlb.h>
#include <asm/io.h>
#include <asm/cacheflush.h>
+#include <asm/mach/map.h>
+
#include <asm/arch/sram.h>
+#include <asm/arch/board.h>
#define OMAP1_SRAM_PA 0x20000000
#define OMAP1_SRAM_VA 0xd0000000
#define OMAP2_SRAM_PA 0x40200000
+#define OMAP2_SRAM_PUB_PA 0x4020f800
#define OMAP2_SRAM_VA 0xd0000000
+#define OMAP2_SRAM_PUB_VA 0xd0000800
+#if defined(CONFIG_ARCH_OMAP24XX)
+#define SRAM_BOOTLOADER_SZ 0x00
+#else
#define SRAM_BOOTLOADER_SZ 0x80
+#endif
+
+#define VA_REQINFOPERM0 IO_ADDRESS(0x68005048)
+#define VA_READPERM0 IO_ADDRESS(0x68005050)
+#define VA_WRITEPERM0 IO_ADDRESS(0x68005058)
+#define VA_CONTROL_STAT IO_ADDRESS(0x480002F8)
+#define GP_DEVICE 0x300
+#define TYPE_MASK 0x700
+
+#define ROUND_DOWN(value,boundary) ((value) & (~((boundary)-1)))
static unsigned long omap_sram_base;
static unsigned long omap_sram_size;
static unsigned long omap_sram_ceil;
+unsigned long omap_fb_sram_start;
+unsigned long omap_fb_sram_size;
+
+/* Depending on the target RAMFS firewall setup, the public usable amount of
+ * SRAM varies. The default accessable size for all device types is 2k. A GP
+ * device allows ARM11 but not other initators for full size. This
+ * functionality seems ok until some nice security API happens.
+ */
+static int is_sram_locked(void)
+{
+ int type = 0;
+
+ if (cpu_is_omap242x())
+ type = __raw_readl(VA_CONTROL_STAT) & TYPE_MASK;
+
+ if (type == GP_DEVICE) {
+ /* RAMFW: R/W access to all initators for all qualifier sets */
+ if (cpu_is_omap242x()) {
+ __raw_writel(0xFF, VA_REQINFOPERM0); /* all q-vects */
+ __raw_writel(0xCFDE, VA_READPERM0); /* all i-read */
+ __raw_writel(0xCFDE, VA_WRITEPERM0); /* all i-write */
+ }
+ return 0;
+ } else
+ return 1; /* assume locked with no PPA or security driver */
+}
+
+void get_fb_sram_conf(unsigned long start_avail, unsigned size_avail,
+ unsigned long *start, unsigned long *size)
+{
+ const struct omap_fbmem_config *fbmem_conf;
+
+ fbmem_conf = omap_get_config(OMAP_TAG_FBMEM, struct omap_fbmem_config);
+ if (fbmem_conf != NULL) {
+ *start = fbmem_conf->fb_sram_start;
+ *size = fbmem_conf->fb_sram_size;
+ } else {
+ *size = 0;
+ *start = 0;
+ }
+
+ if (*size && (
+ *start < start_avail ||
+ *start + *size > start_avail + size_avail)) {
+ printk(KERN_ERR "invalid FB SRAM configuration\n");
+ *start = start_avail;
+ *size = size_avail;
+ }
+
+ if (*size)
+ pr_info("Reserving %lu bytes SRAM for frame buffer\n", *size);
+}
+
/*
* The amount of SRAM depends on the core type.
* Note that we cannot try to test for SRAM here because writes
@@ -42,26 +112,45 @@ static unsigned long omap_sram_ceil;
*/
void __init omap_detect_sram(void)
{
- if (!cpu_is_omap24xx())
+ unsigned long sram_start;
+
+ if (cpu_is_omap24xx()) {
+ if (is_sram_locked()) {
+ omap_sram_base = OMAP2_SRAM_PUB_VA;
+ sram_start = OMAP2_SRAM_PUB_PA;
+ omap_sram_size = 0x800; /* 2K */
+ } else {
+ omap_sram_base = OMAP2_SRAM_VA;
+ sram_start = OMAP2_SRAM_PA;
+ if (cpu_is_omap242x())
+ omap_sram_size = 0xa0000; /* 640K */
+ else if (cpu_is_omap243x())
+ omap_sram_size = 0x10000; /* 64K */
+ }
+ } else {
omap_sram_base = OMAP1_SRAM_VA;
- else
- omap_sram_base = OMAP2_SRAM_VA;
-
- if (cpu_is_omap730())
- omap_sram_size = 0x32000; /* 200K */
- else if (cpu_is_omap15xx())
- omap_sram_size = 0x30000; /* 192K */
- else if (cpu_is_omap1610() || cpu_is_omap1621() || cpu_is_omap1710())
- omap_sram_size = 0x4000; /* 16K */
- else if (cpu_is_omap1611())
- omap_sram_size = 0x3e800; /* 250K */
- else if (cpu_is_omap2420())
- omap_sram_size = 0xa0014; /* 640K */
- else {
- printk(KERN_ERR "Could not detect SRAM size\n");
- omap_sram_size = 0x4000;
+ sram_start = OMAP1_SRAM_PA;
+
+ if (cpu_is_omap730())
+ omap_sram_size = 0x32000; /* 200K */
+ else if (cpu_is_omap15xx())
+ omap_sram_size = 0x30000; /* 192K */
+ else if (cpu_is_omap1610() || cpu_is_omap1621() ||
+ cpu_is_omap1710())
+ omap_sram_size = 0x4000; /* 16K */
+ else if (cpu_is_omap1611())
+ omap_sram_size = 0x3e800; /* 250K */
+ else {
+ printk(KERN_ERR "Could not detect SRAM size\n");
+ omap_sram_size = 0x4000;
+ }
}
-
+ get_fb_sram_conf(sram_start + SRAM_BOOTLOADER_SZ,
+ omap_sram_size - SRAM_BOOTLOADER_SZ,
+ &omap_fb_sram_start, &omap_fb_sram_size);
+ if (omap_fb_sram_size)
+ omap_sram_size -= sram_start + omap_sram_size -
+ omap_fb_sram_start;
omap_sram_ceil = omap_sram_base + omap_sram_size;
}
@@ -80,12 +169,20 @@ static struct map_desc omap_sram_io_desc[] __initdata = {
*/
void __init omap_map_sram(void)
{
+ unsigned long base;
+
if (omap_sram_size == 0)
return;
if (cpu_is_omap24xx()) {
omap_sram_io_desc[0].virtual = OMAP2_SRAM_VA;
- omap_sram_io_desc[0].pfn = __phys_to_pfn(OMAP2_SRAM_PA);
+
+ if (is_sram_locked())
+ base = OMAP2_SRAM_PUB_PA;
+ else
+ base = OMAP2_SRAM_PA;
+ base = ROUND_DOWN(base, PAGE_SIZE);
+ omap_sram_io_desc[0].pfn = __phys_to_pfn(base);
}
omap_sram_io_desc[0].length = (omap_sram_size + PAGE_SIZE-1)/PAGE_SIZE;
@@ -93,7 +190,8 @@ void __init omap_map_sram(void)
iotable_init(omap_sram_io_desc, ARRAY_SIZE(omap_sram_io_desc));
printk(KERN_INFO "SRAM: Mapped pa 0x%08lx to va 0x%08lx size: 0x%lx\n",
- omap_sram_io_desc[0].pfn, omap_sram_io_desc[0].virtual,
+ __pfn_to_phys(omap_sram_io_desc[0].pfn),
+ omap_sram_io_desc[0].virtual,
omap_sram_io_desc[0].length);
/*
@@ -118,8 +216,9 @@ void * omap_sram_push(void * start, unsigned long size)
printk(KERN_ERR "Not enough space in SRAM\n");
return NULL;
}
+
omap_sram_ceil -= size;
- omap_sram_ceil &= ~0x3;
+ omap_sram_ceil = ROUND_DOWN(omap_sram_ceil, sizeof(void *));
memcpy((void *)omap_sram_ceil, start, size);
return (void *)omap_sram_ceil;
diff --git a/arch/arm/plat-omap/timer32k.c b/arch/arm/plat-omap/timer32k.c
new file mode 100644
index 00000000000..b2a943bf11e
--- /dev/null
+++ b/arch/arm/plat-omap/timer32k.c
@@ -0,0 +1,325 @@
+/*
+ * linux/arch/arm/plat-omap/timer32k.c
+ *
+ * OMAP 32K Timer
+ *
+ * Copyright (C) 2004 - 2005 Nokia Corporation
+ * Partial timer rewrite and additional dynamic tick timer support by
+ * Tony Lindgen <tony@atomide.com> and
+ * Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
+ *
+ * MPU timer code based on the older MPU timer code for OMAP
+ * Copyright (C) 2000 RidgeRun, Inc.
+ * Author: Greg Lonnon <glonnon@ridgerun.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+
+#include <asm/system.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/leds.h>
+#include <asm/irq.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/time.h>
+
+struct sys_timer omap_timer;
+
+/*
+ * ---------------------------------------------------------------------------
+ * 32KHz OS timer
+ *
+ * This currently works only on 16xx, as 1510 does not have the continuous
+ * 32KHz synchronous timer. The 32KHz synchronous timer is used to keep track
+ * of time in addition to the 32KHz OS timer. Using only the 32KHz OS timer
+ * on 1510 would be possible, but the timer would not be as accurate as
+ * with the 32KHz synchronized timer.
+ * ---------------------------------------------------------------------------
+ */
+
+#if defined(CONFIG_ARCH_OMAP16XX)
+#define TIMER_32K_SYNCHRONIZED 0xfffbc410
+#elif defined(CONFIG_ARCH_OMAP24XX)
+#define TIMER_32K_SYNCHRONIZED 0x48004010
+#else
+#error OMAP 32KHz timer does not currently work on 15XX!
+#endif
+
+/* 16xx specific defines */
+#define OMAP1_32K_TIMER_BASE 0xfffb9000
+#define OMAP1_32K_TIMER_CR 0x08
+#define OMAP1_32K_TIMER_TVR 0x00
+#define OMAP1_32K_TIMER_TCR 0x04
+
+/* 24xx specific defines */
+#define OMAP2_GP_TIMER_BASE 0x48028000
+#define CM_CLKSEL_WKUP 0x48008440
+#define GP_TIMER_TIDR 0x00
+#define GP_TIMER_TISR 0x18
+#define GP_TIMER_TIER 0x1c
+#define GP_TIMER_TCLR 0x24
+#define GP_TIMER_TCRR 0x28
+#define GP_TIMER_TLDR 0x2c
+#define GP_TIMER_TTGR 0x30
+#define GP_TIMER_TSICR 0x40
+
+#define OMAP_32K_TICKS_PER_HZ (32768 / HZ)
+
+/*
+ * TRM says 1 / HZ = ( TVR + 1) / 32768, so TRV = (32768 / HZ) - 1
+ * so with HZ = 128, TVR = 255.
+ */
+#define OMAP_32K_TIMER_TICK_PERIOD ((32768 / HZ) - 1)
+
+#define JIFFIES_TO_HW_TICKS(nr_jiffies, clock_rate) \
+ (((nr_jiffies) * (clock_rate)) / HZ)
+
+static inline void omap_32k_timer_write(int val, int reg)
+{
+ if (cpu_class_is_omap1())
+ omap_writew(val, OMAP1_32K_TIMER_BASE + reg);
+
+ if (cpu_is_omap24xx())
+ omap_writel(val, OMAP2_GP_TIMER_BASE + reg);
+}
+
+static inline unsigned long omap_32k_timer_read(int reg)
+{
+ if (cpu_class_is_omap1())
+ return omap_readl(OMAP1_32K_TIMER_BASE + reg) & 0xffffff;
+
+ if (cpu_is_omap24xx())
+ return omap_readl(OMAP2_GP_TIMER_BASE + reg);
+}
+
+/*
+ * The 32KHz synchronized timer is an additional timer on 16xx.
+ * It is always running.
+ */
+static inline unsigned long omap_32k_sync_timer_read(void)
+{
+ return omap_readl(TIMER_32K_SYNCHRONIZED);
+}
+
+static inline void omap_32k_timer_start(unsigned long load_val)
+{
+ if (cpu_class_is_omap1()) {
+ omap_32k_timer_write(load_val, OMAP1_32K_TIMER_TVR);
+ omap_32k_timer_write(0x0f, OMAP1_32K_TIMER_CR);
+ }
+
+ if (cpu_is_omap24xx()) {
+ omap_32k_timer_write(0xffffffff - load_val, GP_TIMER_TCRR);
+ omap_32k_timer_write((1 << 1), GP_TIMER_TIER);
+ omap_32k_timer_write((1 << 1) | 1, GP_TIMER_TCLR);
+ }
+}
+
+static inline void omap_32k_timer_stop(void)
+{
+ if (cpu_class_is_omap1())
+ omap_32k_timer_write(0x0, OMAP1_32K_TIMER_CR);
+
+ if (cpu_is_omap24xx())
+ omap_32k_timer_write(0x0, GP_TIMER_TCLR);
+}
+
+/*
+ * Rounds down to nearest usec. Note that this will overflow for larger values.
+ */
+static inline unsigned long omap_32k_ticks_to_usecs(unsigned long ticks_32k)
+{
+ return (ticks_32k * 5*5*5*5*5*5) >> 9;
+}
+
+/*
+ * Rounds down to nearest nsec.
+ */
+static inline unsigned long long
+omap_32k_ticks_to_nsecs(unsigned long ticks_32k)
+{
+ return (unsigned long long) ticks_32k * 1000 * 5*5*5*5*5*5 >> 9;
+}
+
+static unsigned long omap_32k_last_tick = 0;
+
+/*
+ * Returns elapsed usecs since last 32k timer interrupt
+ */
+static unsigned long omap_32k_timer_gettimeoffset(void)
+{
+ unsigned long now = omap_32k_sync_timer_read();
+ return omap_32k_ticks_to_usecs(now - omap_32k_last_tick);
+}
+
+/*
+ * Returns current time from boot in nsecs. It's OK for this to wrap
+ * around for now, as it's just a relative time stamp.
+ */
+unsigned long long sched_clock(void)
+{
+ return omap_32k_ticks_to_nsecs(omap_32k_sync_timer_read());
+}
+
+/*
+ * Timer interrupt for 32KHz timer. When dynamic tick is enabled, this
+ * function is also called from other interrupts to remove latency
+ * issues with dynamic tick. In the dynamic tick case, we need to lock
+ * with irqsave.
+ */
+static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id,
+ struct pt_regs *regs)
+{
+ unsigned long flags;
+ unsigned long now;
+
+ write_seqlock_irqsave(&xtime_lock, flags);
+
+ if (cpu_is_omap24xx()) {
+ u32 status = omap_32k_timer_read(GP_TIMER_TISR);
+ omap_32k_timer_write(status, GP_TIMER_TISR);
+ }
+
+ now = omap_32k_sync_timer_read();
+
+ while (now - omap_32k_last_tick >= OMAP_32K_TICKS_PER_HZ) {
+ omap_32k_last_tick += OMAP_32K_TICKS_PER_HZ;
+ timer_tick(regs);
+ }
+
+ /* Restart timer so we don't drift off due to modulo or dynamic tick.
+ * By default we program the next timer to be continuous to avoid
+ * latencies during high system load. During dynamic tick operation the
+ * continuous timer can be overridden from pm_idle to be longer.
+ */
+ omap_32k_timer_start(omap_32k_last_tick + OMAP_32K_TICKS_PER_HZ - now);
+ write_sequnlock_irqrestore(&xtime_lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_NO_IDLE_HZ
+/*
+ * Programs the next timer interrupt needed. Called when dynamic tick is
+ * enabled, and to reprogram the ticks to skip from pm_idle. Note that
+ * we can keep the timer continuous, and don't need to set it to run in
+ * one-shot mode. This is because the timer will get reprogrammed again
+ * after next interrupt.
+ */
+void omap_32k_timer_reprogram(unsigned long next_tick)
+{
+ omap_32k_timer_start(JIFFIES_TO_HW_TICKS(next_tick, 32768) + 1);
+}
+
+static struct irqaction omap_32k_timer_irq;
+extern struct timer_update_handler timer_update;
+
+static int omap_32k_timer_enable_dyn_tick(void)
+{
+ /* No need to reprogram timer, just use the next interrupt */
+ return 0;
+}
+
+static int omap_32k_timer_disable_dyn_tick(void)
+{
+ omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD);
+ return 0;
+}
+
+static struct dyn_tick_timer omap_dyn_tick_timer = {
+ .enable = omap_32k_timer_enable_dyn_tick,
+ .disable = omap_32k_timer_disable_dyn_tick,
+ .reprogram = omap_32k_timer_reprogram,
+ .handler = omap_32k_timer_interrupt,
+};
+#endif /* CONFIG_NO_IDLE_HZ */
+
+static struct irqaction omap_32k_timer_irq = {
+ .name = "32KHz timer",
+ .flags = SA_INTERRUPT | SA_TIMER,
+ .handler = omap_32k_timer_interrupt,
+};
+
+static struct clk * gpt1_ick;
+static struct clk * gpt1_fck;
+
+static __init void omap_init_32k_timer(void)
+{
+#ifdef CONFIG_NO_IDLE_HZ
+ omap_timer.dyn_tick = &omap_dyn_tick_timer;
+#endif
+
+ if (cpu_class_is_omap1())
+ setup_irq(INT_OS_TIMER, &omap_32k_timer_irq);
+ if (cpu_is_omap24xx())
+ setup_irq(37, &omap_32k_timer_irq);
+ omap_timer.offset = omap_32k_timer_gettimeoffset;
+ omap_32k_last_tick = omap_32k_sync_timer_read();
+
+ /* REVISIT: Check 24xx TIOCP_CFG settings after idle works */
+ if (cpu_is_omap24xx()) {
+ omap_32k_timer_write(0, GP_TIMER_TCLR);
+ omap_writel(0, CM_CLKSEL_WKUP); /* 32KHz clock source */
+
+ gpt1_ick = clk_get(NULL, "gpt1_ick");
+ if (IS_ERR(gpt1_ick))
+ printk(KERN_ERR "Could not get gpt1_ick\n");
+ else
+ clk_enable(gpt1_ick);
+
+ gpt1_fck = clk_get(NULL, "gpt1_fck");
+ if (IS_ERR(gpt1_fck))
+ printk(KERN_ERR "Could not get gpt1_fck\n");
+ else
+ clk_enable(gpt1_fck);
+
+ mdelay(100); /* Wait for clocks to stabilize */
+
+ omap_32k_timer_write(0x7, GP_TIMER_TISR);
+ }
+
+ omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD);
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ * Timer initialization
+ * ---------------------------------------------------------------------------
+ */
+static void __init omap_timer_init(void)
+{
+ omap_init_32k_timer();
+}
+
+struct sys_timer omap_timer = {
+ .init = omap_timer_init,
+ .offset = NULL, /* Initialized later */
+};
diff --git a/arch/i386/kernel/crash.c b/arch/i386/kernel/crash.c
index e3c5fca0aa8..2b0cfce24a6 100644
--- a/arch/i386/kernel/crash.c
+++ b/arch/i386/kernel/crash.c
@@ -69,7 +69,7 @@ static void crash_save_this_cpu(struct pt_regs *regs, int cpu)
* for the data I pass, and I need tags
* on the data to indicate what information I have
* squirrelled away. ELF notes happen to provide
- * all of that that no need to invent something new.
+ * all of that, so there is no need to invent something new.
*/
buf = (u32*)per_cpu_ptr(crash_notes, cpu);
if (!buf)
diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c
index 5b26af8597f..e112d1a5dab 100644
--- a/block/ll_rw_blk.c
+++ b/block/ll_rw_blk.c
@@ -1740,7 +1740,7 @@ EXPORT_SYMBOL(blk_run_queue);
/**
* blk_cleanup_queue: - release a &request_queue_t when it is no longer needed
- * @q: the request queue to be released
+ * @kobj: the kobj belonging of the request queue to be released
*
* Description:
* blk_cleanup_queue is the pair to blk_init_queue() or
diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig
index 16e99db2e12..d53f664a4dd 100644
--- a/drivers/char/watchdog/Kconfig
+++ b/drivers/char/watchdog/Kconfig
@@ -60,6 +60,13 @@ config SOFT_WATCHDOG
# ARM Architecture
+config AT91_WATCHDOG
+ tristate "AT91RM9200 watchdog"
+ depends on WATCHDOG && ARCH_AT91RM9200
+ help
+ Watchdog timer embedded into AT91RM9200 chips. This will reboot your
+ system when the timeout is reached.
+
config 21285_WATCHDOG
tristate "DC21285 watchdog"
depends on WATCHDOG && FOOTBRIDGE
diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile
index d6f27fde990..6ab77b61a64 100644
--- a/drivers/char/watchdog/Makefile
+++ b/drivers/char/watchdog/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_WDTPCI) += wdt_pci.o
obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o
# ARM Architecture
+obj-$(CONFIG_AT91_WATCHDOG) += at91_wdt.o
obj-$(CONFIG_21285_WATCHDOG) += wdt285.o
obj-$(CONFIG_977_WATCHDOG) += wdt977.o
obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o
diff --git a/drivers/char/watchdog/at91_wdt.c b/drivers/char/watchdog/at91_wdt.c
new file mode 100644
index 00000000000..ac83bc4b019
--- /dev/null
+++ b/drivers/char/watchdog/at91_wdt.c
@@ -0,0 +1,228 @@
+/*
+ * Watchdog driver for Atmel AT91RM9200 (Thunder)
+ *
+ * Copyright (C) 2003 SAN People (Pty) Ltd
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/watchdog.h>
+#include <asm/bitops.h>
+#include <asm/uaccess.h>
+
+
+#define WDT_DEFAULT_TIME 5 /* 5 seconds */
+#define WDT_MAX_TIME 256 /* 256 seconds */
+
+static int wdt_time = WDT_DEFAULT_TIME;
+static int nowayout = WATCHDOG_NOWAYOUT;
+
+module_param(wdt_time, int, 0);
+MODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default="__MODULE_STRING(WDT_DEFAULT_TIME) ")");
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+
+static unsigned long at91wdt_busy;
+
+/* ......................................................................... */
+
+/*
+ * Disable the watchdog.
+ */
+static void inline at91_wdt_stop(void)
+{
+ at91_sys_write(AT91_ST_WDMR, AT91_ST_EXTEN);
+}
+
+/*
+ * Enable and reset the watchdog.
+ */
+static void inline at91_wdt_start(void)
+{
+ at91_sys_write(AT91_ST_WDMR, AT91_ST_EXTEN | AT91_ST_RSTEN | (((65536 * wdt_time) >> 8) & AT91_ST_WDV));
+ at91_sys_write(AT91_ST_CR, AT91_ST_WDRST);
+}
+
+/*
+ * Reload the watchdog timer. (ie, pat the watchdog)
+ */
+static void inline at91_wdt_reload(void)
+{
+ at91_sys_write(AT91_ST_CR, AT91_ST_WDRST);
+}
+
+/* ......................................................................... */
+
+/*
+ * Watchdog device is opened, and watchdog starts running.
+ */
+static int at91_wdt_open(struct inode *inode, struct file *file)
+{
+ if (test_and_set_bit(0, &at91wdt_busy))
+ return -EBUSY;
+
+ at91_wdt_start();
+ return nonseekable_open(inode, file);
+}
+
+/*
+ * Close the watchdog device.
+ * If CONFIG_WATCHDOG_NOWAYOUT is NOT defined then the watchdog is also
+ * disabled.
+ */
+static int at91_wdt_close(struct inode *inode, struct file *file)
+{
+ if (!nowayout)
+ at91_wdt_stop(); /* Disable the watchdog when file is closed */
+
+ clear_bit(0, &at91wdt_busy);
+ return 0;
+}
+
+/*
+ * Change the watchdog time interval.
+ */
+static int at91_wdt_settimeout(int new_time)
+{
+ /*
+ * All counting occurs at SLOW_CLOCK / 128 = 0.256 Hz
+ *
+ * Since WDV is a 16-bit counter, the maximum period is
+ * 65536 / 0.256 = 256 seconds.
+ */
+ if ((new_time <= 0) || (new_time > WDT_MAX_TIME))
+ return -EINVAL;
+
+ /* Set new watchdog time. It will be used when at91_wdt_start() is called. */
+ wdt_time = new_time;
+ return 0;
+}
+
+static struct watchdog_info at91_wdt_info = {
+ .identity = "at91 watchdog",
+ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+};
+
+/*
+ * Handle commands from user-space.
+ */
+static int at91_wdt_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ int __user *p = argp;
+ int new_value;
+
+ switch(cmd) {
+ case WDIOC_KEEPALIVE:
+ at91_wdt_reload(); /* pat the watchdog */
+ return 0;
+
+ case WDIOC_GETSUPPORT:
+ return copy_to_user(argp, &at91_wdt_info, sizeof(at91_wdt_info)) ? -EFAULT : 0;
+
+ case WDIOC_SETTIMEOUT:
+ if (get_user(new_value, p))
+ return -EFAULT;
+
+ if (at91_wdt_settimeout(new_value))
+ return -EINVAL;
+
+ /* Enable new time value */
+ at91_wdt_start();
+
+ /* Return current value */
+ return put_user(wdt_time, p);
+
+ case WDIOC_GETTIMEOUT:
+ return put_user(wdt_time, p);
+
+ case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
+ return put_user(0, p);
+
+ case WDIOC_SETOPTIONS:
+ if (get_user(new_value, p))
+ return -EFAULT;
+
+ if (new_value & WDIOS_DISABLECARD)
+ at91_wdt_stop();
+ if (new_value & WDIOS_ENABLECARD)
+ at91_wdt_start();
+ return 0;
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
+/*
+ * Pat the watchdog whenever device is written to.
+ */
+static ssize_t at91_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos)
+{
+ at91_wdt_reload(); /* pat the watchdog */
+ return len;
+}
+
+/* ......................................................................... */
+
+static struct file_operations at91wdt_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .ioctl = at91_wdt_ioctl,
+ .open = at91_wdt_open,
+ .release = at91_wdt_close,
+ .write = at91_wdt_write,
+};
+
+static struct miscdevice at91wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &at91wdt_fops,
+};
+
+static int __init at91_wdt_init(void)
+{
+ int res;
+
+ /* Check that the heartbeat value is within range; if not reset to the default */
+ if (at91_wdt_settimeout(wdt_time)) {
+ at91_wdt_settimeout(WDT_DEFAULT_TIME);
+ printk(KERN_INFO "at91_wdt: wdt_time value must be 1 <= wdt_time <= 256, using %d\n", wdt_time);
+ }
+
+ res = misc_register(&at91wdt_miscdev);
+ if (res)
+ return res;
+
+ printk("AT91 Watchdog Timer enabled (%d seconds, nowayout=%d)\n", wdt_time, nowayout);
+ return 0;
+}
+
+static void __exit at91_wdt_exit(void)
+{
+ misc_deregister(&at91wdt_miscdev);
+}
+
+module_init(at91_wdt_init);
+module_exit(at91_wdt_exit);
+
+MODULE_AUTHOR("Andrew Victor");
+MODULE_DESCRIPTION("Watchdog driver for Atmel AT91RM9200");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/pcwd.c b/drivers/char/watchdog/pcwd.c
index 8d6b249ad66..6d44ca68312 100644
--- a/drivers/char/watchdog/pcwd.c
+++ b/drivers/char/watchdog/pcwd.c
@@ -66,15 +66,13 @@
#include <linux/fs.h> /* For file operations */
#include <linux/ioport.h> /* For io-port access */
#include <linux/spinlock.h> /* For spin_lock/spin_unlock/... */
-#include <linux/sched.h> /* TASK_INTERRUPTIBLE, set_current_state() and friends */
-#include <linux/slab.h> /* For kmalloc */
#include <asm/uaccess.h> /* For copy_to_user/put_user/... */
#include <asm/io.h> /* For inb/outb/... */
/* Module and version information */
-#define WATCHDOG_VERSION "1.16"
-#define WATCHDOG_DATE "03 Jan 2006"
+#define WATCHDOG_VERSION "1.17"
+#define WATCHDOG_DATE "12 Feb 2006"
#define WATCHDOG_DRIVER_NAME "ISA-PC Watchdog"
#define WATCHDOG_NAME "pcwd"
#define PFX WATCHDOG_NAME ": "
@@ -96,15 +94,19 @@
* PCI-PC Watchdog card.
*/
/* Port 1 : Control Status #1 for the PC Watchdog card, revision A. */
-#define WD_WDRST 0x01 /* Previously reset state */
-#define WD_T110 0x02 /* Temperature overheat sense */
-#define WD_HRTBT 0x04 /* Heartbeat sense */
-#define WD_RLY2 0x08 /* External relay triggered */
-#define WD_SRLY2 0x80 /* Software external relay triggered */
+#define WD_WDRST 0x01 /* Previously reset state */
+#define WD_T110 0x02 /* Temperature overheat sense */
+#define WD_HRTBT 0x04 /* Heartbeat sense */
+#define WD_RLY2 0x08 /* External relay triggered */
+#define WD_SRLY2 0x80 /* Software external relay triggered */
/* Port 1 : Control Status #1 for the PC Watchdog card, revision C. */
-#define WD_REVC_WTRP 0x01 /* Watchdog Trip status */
-#define WD_REVC_HRBT 0x02 /* Watchdog Heartbeat */
-#define WD_REVC_TTRP 0x04 /* Temperature Trip status */
+#define WD_REVC_WTRP 0x01 /* Watchdog Trip status */
+#define WD_REVC_HRBT 0x02 /* Watchdog Heartbeat */
+#define WD_REVC_TTRP 0x04 /* Temperature Trip status */
+#define WD_REVC_RL2A 0x08 /* Relay 2 activated by on-board processor */
+#define WD_REVC_RL1A 0x10 /* Relay 1 active */
+#define WD_REVC_R2DS 0x40 /* Relay 2 disable */
+#define WD_REVC_RLY2 0x80 /* Relay 2 activated? */
/* Port 2 : Control Status #2 */
#define WD_WDIS 0x10 /* Watchdog Disabled */
#define WD_ENTP 0x20 /* Watchdog Enable Temperature Trip */
@@ -122,9 +124,14 @@
#define CMD_ISA_VERSION_HUNDRETH 0x03
#define CMD_ISA_VERSION_MINOR 0x04
#define CMD_ISA_SWITCH_SETTINGS 0x05
+#define CMD_ISA_RESET_PC 0x06
+#define CMD_ISA_ARM_0 0x07
+#define CMD_ISA_ARM_30 0x08
+#define CMD_ISA_ARM_60 0x09
#define CMD_ISA_DELAY_TIME_2SECS 0x0A
#define CMD_ISA_DELAY_TIME_4SECS 0x0B
#define CMD_ISA_DELAY_TIME_8SECS 0x0C
+#define CMD_ISA_RESET_RELAYS 0x0D
/*
* We are using an kernel timer to do the pinging of the watchdog
@@ -142,6 +149,7 @@ static atomic_t open_allowed = ATOMIC_INIT(1);
static char expect_close;
static int temp_panic;
static struct { /* this is private data for each ISA-PC watchdog card */
+ char fw_ver_str[6]; /* The cards firmware version */
int revision; /* The card's revision */
int supports_temp; /* Wether or not the card has a temperature device */
int command_mode; /* Wether or not the card is in command mode */
@@ -153,6 +161,13 @@ static struct { /* this is private data for each ISA-PC watchdog card */
} pcwd_private;
/* module parameters */
+#define QUIET 0 /* Default */
+#define VERBOSE 1 /* Verbose */
+#define DEBUG 2 /* print fancy stuff too */
+static int debug = QUIET;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug level: 0=Quiet, 1=Verbose, 2=Debug (default=0)");
+
#define WATCHDOG_HEARTBEAT 60 /* 60 sec default heartbeat */
static int heartbeat = WATCHDOG_HEARTBEAT;
module_param(heartbeat, int, 0);
@@ -172,6 +187,10 @@ static int send_isa_command(int cmd)
int control_status;
int port0, last_port0; /* Double read for stabilising */
+ if (debug >= DEBUG)
+ printk(KERN_DEBUG PFX "sending following data cmd=0x%02x\n",
+ cmd);
+
/* The WCMD bit must be 1 and the command is only 4 bits in size */
control_status = (cmd & 0x0F) | WD_WCMD;
outb_p(control_status, pcwd_private.io_addr + 2);
@@ -188,6 +207,10 @@ static int send_isa_command(int cmd)
udelay (250);
}
+ if (debug >= DEBUG)
+ printk(KERN_DEBUG PFX "received following data for cmd=0x%02x: port0=0x%02x last_port0=0x%02x\n",
+ cmd, port0, last_port0);
+
return port0;
}
@@ -214,6 +237,10 @@ static int set_command_mode(void)
spin_unlock(&pcwd_private.io_lock);
pcwd_private.command_mode = found;
+ if (debug >= DEBUG)
+ printk(KERN_DEBUG PFX "command_mode=%d\n",
+ pcwd_private.command_mode);
+
return(found);
}
@@ -226,6 +253,10 @@ static void unset_command_mode(void)
spin_unlock(&pcwd_private.io_lock);
pcwd_private.command_mode = 0;
+
+ if (debug >= DEBUG)
+ printk(KERN_DEBUG PFX "command_mode=%d\n",
+ pcwd_private.command_mode);
}
static inline void pcwd_check_temperature_support(void)
@@ -234,27 +265,22 @@ static inline void pcwd_check_temperature_support(void)
pcwd_private.supports_temp = 1;
}
-static inline char *get_firmware(void)
+static inline void pcwd_get_firmware(void)
{
int one, ten, hund, minor;
- char *ret;
- ret = kmalloc(6, GFP_KERNEL);
- if(ret == NULL)
- return NULL;
+ strcpy(pcwd_private.fw_ver_str, "ERROR");
if (set_command_mode()) {
one = send_isa_command(CMD_ISA_VERSION_INTEGER);
ten = send_isa_command(CMD_ISA_VERSION_TENTH);
hund = send_isa_command(CMD_ISA_VERSION_HUNDRETH);
minor = send_isa_command(CMD_ISA_VERSION_MINOR);
- sprintf(ret, "%c.%c%c%c", one, ten, hund, minor);
+ sprintf(pcwd_private.fw_ver_str, "%c.%c%c%c", one, ten, hund, minor);
}
- else
- sprintf(ret, "ERROR");
-
unset_command_mode();
- return(ret);
+
+ return;
}
static inline int pcwd_get_option_switches(void)
@@ -272,17 +298,15 @@ static inline int pcwd_get_option_switches(void)
static void pcwd_show_card_info(void)
{
- char *firmware;
int option_switches;
/* Get some extra info from the hardware (in command/debug/diag mode) */
if (pcwd_private.revision == PCWD_REVISION_A)
printk(KERN_INFO PFX "ISA-PC Watchdog (REV.A) detected at port 0x%04x\n", pcwd_private.io_addr);
else if (pcwd_private.revision == PCWD_REVISION_C) {
- firmware = get_firmware();
+ pcwd_get_firmware();
printk(KERN_INFO PFX "ISA-PC Watchdog (REV.C) detected at port 0x%04x (Firmware version: %s)\n",
- pcwd_private.io_addr, firmware);
- kfree(firmware);
+ pcwd_private.io_addr, pcwd_private.fw_ver_str);
option_switches = pcwd_get_option_switches();
printk(KERN_INFO PFX "Option switches (0x%02x): Temperature Reset Enable=%s, Power On Delay=%s\n",
option_switches,
@@ -362,6 +386,10 @@ static int pcwd_start(void)
return -EIO;
}
}
+
+ if (debug >= VERBOSE)
+ printk(KERN_DEBUG PFX "Watchdog started\n");
+
return 0;
}
@@ -386,6 +414,10 @@ static int pcwd_stop(void)
return -EIO;
}
}
+
+ if (debug >= VERBOSE)
+ printk(KERN_DEBUG PFX "Watchdog stopped\n");
+
return 0;
}
@@ -393,6 +425,10 @@ static int pcwd_keepalive(void)
{
/* user land ping */
pcwd_private.next_heartbeat = jiffies + (heartbeat * HZ);
+
+ if (debug >= DEBUG)
+ printk(KERN_DEBUG PFX "Watchdog keepalive signal send\n");
+
return 0;
}
@@ -402,12 +438,17 @@ static int pcwd_set_heartbeat(int t)
return -EINVAL;
heartbeat = t;
+
+ if (debug >= VERBOSE)
+ printk(KERN_DEBUG PFX "New heartbeat: %d\n",
+ heartbeat);
+
return 0;
}
static int pcwd_get_status(int *status)
{
- int card_status;
+ int control_status;
*status=0;
spin_lock(&pcwd_private.io_lock);
@@ -415,37 +456,39 @@ static int pcwd_get_status(int *status)
/* Rev A cards return status information from
* the base register, which is used for the
* temperature in other cards. */
- card_status = inb(pcwd_private.io_addr);
+ control_status = inb(pcwd_private.io_addr);
else {
/* Rev C cards return card status in the base
* address + 1 register. And use different bits
* to indicate a card initiated reset, and an
* over-temperature condition. And the reboot
* status can be reset. */
- card_status = inb(pcwd_private.io_addr + 1);
+ control_status = inb(pcwd_private.io_addr + 1);
}
spin_unlock(&pcwd_private.io_lock);
if (pcwd_private.revision == PCWD_REVISION_A) {
- if (card_status & WD_WDRST)
+ if (control_status & WD_WDRST)
*status |= WDIOF_CARDRESET;
- if (card_status & WD_T110) {
+ if (control_status & WD_T110) {
*status |= WDIOF_OVERHEAT;
if (temp_panic) {
printk (KERN_INFO PFX "Temperature overheat trip!\n");
kernel_power_off();
+ /* or should we just do a: panic(PFX "Temperature overheat trip!\n"); */
}
}
} else {
- if (card_status & WD_REVC_WTRP)
+ if (control_status & WD_REVC_WTRP)
*status |= WDIOF_CARDRESET;
- if (card_status & WD_REVC_TTRP) {
+ if (control_status & WD_REVC_TTRP) {
*status |= WDIOF_OVERHEAT;
if (temp_panic) {
printk (KERN_INFO PFX "Temperature overheat trip!\n");
kernel_power_off();
+ /* or should we just do a: panic(PFX "Temperature overheat trip!\n"); */
}
}
}
@@ -455,9 +498,25 @@ static int pcwd_get_status(int *status)
static int pcwd_clear_status(void)
{
+ int control_status;
+
if (pcwd_private.revision == PCWD_REVISION_C) {
spin_lock(&pcwd_private.io_lock);
- outb_p(0x00, pcwd_private.io_addr + 1); /* clear reset status */
+
+ if (debug >= VERBOSE)
+ printk(KERN_INFO PFX "clearing watchdog trip status\n");
+
+ control_status = inb_p(pcwd_private.io_addr + 1);
+
+ if (debug >= DEBUG) {
+ printk(KERN_DEBUG PFX "status was: 0x%02x\n", control_status);
+ printk(KERN_DEBUG PFX "sending: 0x%02x\n",
+ (control_status & WD_REVC_R2DS));
+ }
+
+ /* clear reset status & Keep Relay 2 disable state as it is */
+ outb_p((control_status & WD_REVC_R2DS), pcwd_private.io_addr + 1);
+
spin_unlock(&pcwd_private.io_lock);
}
return 0;
@@ -481,6 +540,11 @@ static int pcwd_get_temperature(int *temperature)
*temperature = ((inb(pcwd_private.io_addr)) * 9 / 5) + 32;
spin_unlock(&pcwd_private.io_lock);
+ if (debug >= DEBUG) {
+ printk(KERN_DEBUG PFX "temperature is: %d F\n",
+ *temperature);
+ }
+
return 0;
}
@@ -599,6 +663,8 @@ static ssize_t pcwd_write(struct file *file, const char __user *buf, size_t len,
static int pcwd_open(struct inode *inode, struct file *file)
{
if (!atomic_dec_and_test(&open_allowed) ) {
+ if (debug >= VERBOSE)
+ printk(KERN_ERR PFX "Attempt to open already opened device.\n");
atomic_inc( &open_allowed );
return -EBUSY;
}
@@ -922,7 +988,8 @@ static void __exit pcwd_cleanup_module(void)
{
if (pcwd_private.io_addr)
pcwatchdog_exit();
- return;
+
+ printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
}
module_init(pcwd_init_module);
diff --git a/drivers/char/watchdog/pcwd_usb.c b/drivers/char/watchdog/pcwd_usb.c
index 2700c5c45b8..3fdfda9324f 100644
--- a/drivers/char/watchdog/pcwd_usb.c
+++ b/drivers/char/watchdog/pcwd_usb.c
@@ -705,7 +705,8 @@ err_out_misc_deregister:
err_out_unregister_reboot:
unregister_reboot_notifier(&usb_pcwd_notifier);
error:
- usb_pcwd_delete (usb_pcwd);
+ if (usb_pcwd)
+ usb_pcwd_delete(usb_pcwd);
usb_pcwd_device = NULL;
return retval;
}
diff --git a/drivers/hwmon/hdaps.c b/drivers/hwmon/hdaps.c
index 7636c1a58f9..23a9e1ea8e3 100644
--- a/drivers/hwmon/hdaps.c
+++ b/drivers/hwmon/hdaps.c
@@ -33,7 +33,6 @@
#include <linux/module.h>
#include <linux/timer.h>
#include <linux/dmi.h>
-#include <linux/mutex.h>
#include <asm/io.h>
#define HDAPS_LOW_PORT 0x1600 /* first port used by hdaps */
@@ -71,10 +70,10 @@ static u8 km_activity;
static int rest_x;
static int rest_y;
-static DEFINE_MUTEX(hdaps_mutex);
+static DECLARE_MUTEX(hdaps_sem);
/*
- * __get_latch - Get the value from a given port. Callers must hold hdaps_mutex.
+ * __get_latch - Get the value from a given port. Callers must hold hdaps_sem.
*/
static inline u8 __get_latch(u16 port)
{
@@ -83,7 +82,7 @@ static inline u8 __get_latch(u16 port)
/*
* __check_latch - Check a port latch for a given value. Returns zero if the
- * port contains the given value. Callers must hold hdaps_mutex.
+ * port contains the given value. Callers must hold hdaps_sem.
*/
static inline int __check_latch(u16 port, u8 val)
{
@@ -94,7 +93,7 @@ static inline int __check_latch(u16 port, u8 val)
/*
* __wait_latch - Wait up to 100us for a port latch to get a certain value,
- * returning zero if the value is obtained. Callers must hold hdaps_mutex.
+ * returning zero if the value is obtained. Callers must hold hdaps_sem.
*/
static int __wait_latch(u16 port, u8 val)
{
@@ -111,7 +110,7 @@ static int __wait_latch(u16 port, u8 val)
/*
* __device_refresh - request a refresh from the accelerometer. Does not wait
- * for refresh to complete. Callers must hold hdaps_mutex.
+ * for refresh to complete. Callers must hold hdaps_sem.
*/
static void __device_refresh(void)
{
@@ -125,7 +124,7 @@ static void __device_refresh(void)
/*
* __device_refresh_sync - request a synchronous refresh from the
* accelerometer. We wait for the refresh to complete. Returns zero if
- * successful and nonzero on error. Callers must hold hdaps_mutex.
+ * successful and nonzero on error. Callers must hold hdaps_sem.
*/
static int __device_refresh_sync(void)
{
@@ -135,7 +134,7 @@ static int __device_refresh_sync(void)
/*
* __device_complete - indicate to the accelerometer that we are done reading
- * data, and then initiate an async refresh. Callers must hold hdaps_mutex.
+ * data, and then initiate an async refresh. Callers must hold hdaps_sem.
*/
static inline void __device_complete(void)
{
@@ -153,7 +152,7 @@ static int hdaps_readb_one(unsigned int port, u8 *val)
{
int ret;
- mutex_lock(&hdaps_mutex);
+ down(&hdaps_sem);
/* do a sync refresh -- we need to be sure that we read fresh data */
ret = __device_refresh_sync();
@@ -164,7 +163,7 @@ static int hdaps_readb_one(unsigned int port, u8 *val)
__device_complete();
out:
- mutex_unlock(&hdaps_mutex);
+ up(&hdaps_sem);
return ret;
}
@@ -199,9 +198,9 @@ static int hdaps_read_pair(unsigned int port1, unsigned int port2,
{
int ret;
- mutex_lock(&hdaps_mutex);
+ down(&hdaps_sem);
ret = __hdaps_read_pair(port1, port2, val1, val2);
- mutex_unlock(&hdaps_mutex);
+ up(&hdaps_sem);
return ret;
}
@@ -214,7 +213,7 @@ static int hdaps_device_init(void)
{
int total, ret = -ENXIO;
- mutex_lock(&hdaps_mutex);
+ down(&hdaps_sem);
outb(0x13, 0x1610);
outb(0x01, 0x161f);
@@ -280,7 +279,7 @@ static int hdaps_device_init(void)
}
out:
- mutex_unlock(&hdaps_mutex);
+ up(&hdaps_sem);
return ret;
}
@@ -314,7 +313,7 @@ static struct platform_driver hdaps_driver = {
};
/*
- * hdaps_calibrate - Set our "resting" values. Callers must hold hdaps_mutex.
+ * hdaps_calibrate - Set our "resting" values. Callers must hold hdaps_sem.
*/
static void hdaps_calibrate(void)
{
@@ -326,7 +325,7 @@ static void hdaps_mousedev_poll(unsigned long unused)
int x, y;
/* Cannot sleep. Try nonblockingly. If we fail, try again later. */
- if (!mutex_trylock(&hdaps_mutex)) {
+ if (down_trylock(&hdaps_sem)) {
mod_timer(&hdaps_timer,jiffies + HDAPS_POLL_PERIOD);
return;
}
@@ -341,7 +340,7 @@ static void hdaps_mousedev_poll(unsigned long unused)
mod_timer(&hdaps_timer, jiffies + HDAPS_POLL_PERIOD);
out:
- mutex_unlock(&hdaps_mutex);
+ up(&hdaps_sem);
}
@@ -421,9 +420,9 @@ static ssize_t hdaps_calibrate_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- mutex_lock(&hdaps_mutex);
+ down(&hdaps_sem);
hdaps_calibrate();
- mutex_unlock(&hdaps_mutex);
+ up(&hdaps_sem);
return count;
}
diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
index 2c765ca5aa5..f4206604db0 100644
--- a/drivers/ieee1394/sbp2.c
+++ b/drivers/ieee1394/sbp2.c
@@ -496,22 +496,17 @@ static struct sbp2_command_info *sbp2util_find_command_for_orb(
/*
* This function finds the sbp2_command for a given outstanding SCpnt.
* Only looks at the inuse list.
+ * Must be called with scsi_id->sbp2_command_orb_lock held.
*/
-static struct sbp2_command_info *sbp2util_find_command_for_SCpnt(struct scsi_id_instance_data *scsi_id, void *SCpnt)
+static struct sbp2_command_info *sbp2util_find_command_for_SCpnt(
+ struct scsi_id_instance_data *scsi_id, void *SCpnt)
{
struct sbp2_command_info *command;
- unsigned long flags;
- spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
- if (!list_empty(&scsi_id->sbp2_command_orb_inuse)) {
- list_for_each_entry(command, &scsi_id->sbp2_command_orb_inuse, list) {
- if (command->Current_SCpnt == SCpnt) {
- spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
+ if (!list_empty(&scsi_id->sbp2_command_orb_inuse))
+ list_for_each_entry(command, &scsi_id->sbp2_command_orb_inuse, list)
+ if (command->Current_SCpnt == SCpnt)
return command;
- }
- }
- }
- spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
return NULL;
}
@@ -580,17 +575,15 @@ static void sbp2util_free_command_dma(struct sbp2_command_info *command)
/*
* This function moves a command to the completed orb list.
+ * Must be called with scsi_id->sbp2_command_orb_lock held.
*/
-static void sbp2util_mark_command_completed(struct scsi_id_instance_data *scsi_id,
- struct sbp2_command_info *command)
+static void sbp2util_mark_command_completed(
+ struct scsi_id_instance_data *scsi_id,
+ struct sbp2_command_info *command)
{
- unsigned long flags;
-
- spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
list_del(&command->list);
sbp2util_free_command_dma(command);
list_add_tail(&command->list, &scsi_id->sbp2_command_orb_completed);
- spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
}
/*
@@ -2148,7 +2141,9 @@ static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int dest
* Matched status with command, now grab scsi command pointers and check status
*/
SCpnt = command->Current_SCpnt;
+ spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
sbp2util_mark_command_completed(scsi_id, command);
+ spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
if (SCpnt) {
@@ -2484,6 +2479,7 @@ static int sbp2scsi_abort(struct scsi_cmnd *SCpnt)
(struct scsi_id_instance_data *)SCpnt->device->host->hostdata[0];
struct sbp2scsi_host_info *hi = scsi_id->hi;
struct sbp2_command_info *command;
+ unsigned long flags;
SBP2_ERR("aborting sbp2 command");
scsi_print_command(SCpnt);
@@ -2494,6 +2490,7 @@ static int sbp2scsi_abort(struct scsi_cmnd *SCpnt)
* Right now, just return any matching command structures
* to the free pool.
*/
+ spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
command = sbp2util_find_command_for_SCpnt(scsi_id, SCpnt);
if (command) {
SBP2_DEBUG("Found command to abort");
@@ -2511,6 +2508,7 @@ static int sbp2scsi_abort(struct scsi_cmnd *SCpnt)
command->Current_done(command->Current_SCpnt);
}
}
+ spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
/*
* Initiate a fetch agent reset.
diff --git a/drivers/md/dm-target.c b/drivers/md/dm-target.c
index aecd9e0c261..64fd8e79ea4 100644
--- a/drivers/md/dm-target.c
+++ b/drivers/md/dm-target.c
@@ -78,8 +78,7 @@ void dm_put_target_type(struct target_type *t)
if (--ti->use == 0)
module_put(ti->tt.module);
- if (ti->use < 0)
- BUG();
+ BUG_ON(ti->use < 0);
up_read(&_lock);
return;
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 9b374c91db6..6081941de1b 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -1558,8 +1558,7 @@ static int init_resync(conf_t *conf)
int buffs;
buffs = RESYNC_WINDOW / RESYNC_BLOCK_SIZE;
- if (conf->r1buf_pool)
- BUG();
+ BUG_ON(conf->r1buf_pool);
conf->r1buf_pool = mempool_create(buffs, r1buf_pool_alloc, r1buf_pool_free,
conf->poolinfo);
if (!conf->r1buf_pool)
@@ -1732,8 +1731,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
!conf->fullsync &&
!test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery))
break;
- if (sync_blocks < (PAGE_SIZE>>9))
- BUG();
+ BUG_ON(sync_blocks < (PAGE_SIZE>>9));
if (len > (sync_blocks<<9))
len = sync_blocks<<9;
}
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index ab90a6d1202..617012bc107 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -1117,8 +1117,7 @@ static int end_sync_read(struct bio *bio, unsigned int bytes_done, int error)
for (i=0; i<conf->copies; i++)
if (r10_bio->devs[i].bio == bio)
break;
- if (i == conf->copies)
- BUG();
+ BUG_ON(i == conf->copies);
update_head_pos(i, r10_bio);
d = r10_bio->devs[i].devnum;
@@ -1518,8 +1517,7 @@ static int init_resync(conf_t *conf)
int buffs;
buffs = RESYNC_WINDOW / RESYNC_BLOCK_SIZE;
- if (conf->r10buf_pool)
- BUG();
+ BUG_ON(conf->r10buf_pool);
conf->r10buf_pool = mempool_create(buffs, r10buf_pool_alloc, r10buf_pool_free, conf);
if (!conf->r10buf_pool)
return -ENOMEM;
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index dae740adaf6..31843604049 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -73,10 +73,8 @@ static void print_raid5_conf (raid5_conf_t *conf);
static void __release_stripe(raid5_conf_t *conf, struct stripe_head *sh)
{
if (atomic_dec_and_test(&sh->count)) {
- if (!list_empty(&sh->lru))
- BUG();
- if (atomic_read(&conf->active_stripes)==0)
- BUG();
+ BUG_ON(!list_empty(&sh->lru));
+ BUG_ON(atomic_read(&conf->active_stripes)==0);
if (test_bit(STRIPE_HANDLE, &sh->state)) {
if (test_bit(STRIPE_DELAYED, &sh->state))
list_add_tail(&sh->lru, &conf->delayed_list);
@@ -184,10 +182,8 @@ static void init_stripe(struct stripe_head *sh, sector_t sector, int pd_idx, int
raid5_conf_t *conf = sh->raid_conf;
int i;
- if (atomic_read(&sh->count) != 0)
- BUG();
- if (test_bit(STRIPE_HANDLE, &sh->state))
- BUG();
+ BUG_ON(atomic_read(&sh->count) != 0);
+ BUG_ON(test_bit(STRIPE_HANDLE, &sh->state));
CHECK_DEVLOCK();
PRINTK("init_stripe called, stripe %llu\n",
@@ -269,8 +265,7 @@ static struct stripe_head *get_active_stripe(raid5_conf_t *conf, sector_t sector
init_stripe(sh, sector, pd_idx, disks);
} else {
if (atomic_read(&sh->count)) {
- if (!list_empty(&sh->lru))
- BUG();
+ BUG_ON(!list_empty(&sh->lru));
} else {
if (!test_bit(STRIPE_HANDLE, &sh->state))
atomic_inc(&conf->active_stripes);
@@ -465,8 +460,7 @@ static int drop_one_stripe(raid5_conf_t *conf)
spin_unlock_irq(&conf->device_lock);
if (!sh)
return 0;
- if (atomic_read(&sh->count))
- BUG();
+ BUG_ON(atomic_read(&sh->count));
shrink_buffers(sh, conf->pool_size);
kmem_cache_free(conf->slab_cache, sh);
atomic_dec(&conf->active_stripes);
@@ -882,8 +876,7 @@ static void compute_parity(struct stripe_head *sh, int method)
ptr[0] = page_address(sh->dev[pd_idx].page);
switch(method) {
case READ_MODIFY_WRITE:
- if (!test_bit(R5_UPTODATE, &sh->dev[pd_idx].flags))
- BUG();
+ BUG_ON(!test_bit(R5_UPTODATE, &sh->dev[pd_idx].flags));
for (i=disks ; i-- ;) {
if (i==pd_idx)
continue;
@@ -896,7 +889,7 @@ static void compute_parity(struct stripe_head *sh, int method)
if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags))
wake_up(&conf->wait_for_overlap);
- if (sh->dev[i].written) BUG();
+ BUG_ON(sh->dev[i].written);
sh->dev[i].written = chosen;
check_xor();
}
@@ -912,7 +905,7 @@ static void compute_parity(struct stripe_head *sh, int method)
if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags))
wake_up(&conf->wait_for_overlap);
- if (sh->dev[i].written) BUG();
+ BUG_ON(sh->dev[i].written);
sh->dev[i].written = chosen;
}
break;
@@ -995,8 +988,7 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in
if (*bip && (*bip)->bi_sector < bi->bi_sector + ((bi->bi_size)>>9))
goto overlap;
- if (*bip && bi->bi_next && (*bip) != bi->bi_next)
- BUG();
+ BUG_ON(*bip && bi->bi_next && (*bip) != bi->bi_next);
if (*bip)
bi->bi_next = *bip;
*bip = bi;
@@ -1430,8 +1422,7 @@ static void handle_stripe(struct stripe_head *sh)
set_bit(STRIPE_HANDLE, &sh->state);
if (failed == 0) {
char *pagea;
- if (uptodate != disks)
- BUG();
+ BUG_ON(uptodate != disks);
compute_parity(sh, CHECK_PARITY);
uptodate--;
pagea = page_address(sh->dev[sh->pd_idx].page);
@@ -2096,8 +2087,7 @@ static void raid5d (mddev_t *mddev)
list_del_init(first);
atomic_inc(&sh->count);
- if (atomic_read(&sh->count)!= 1)
- BUG();
+ BUG_ON(atomic_read(&sh->count)!= 1);
spin_unlock_irq(&conf->device_lock);
handled++;
diff --git a/drivers/md/raid6main.c b/drivers/md/raid6main.c
index ab64b37e499..bc69355e010 100644
--- a/drivers/md/raid6main.c
+++ b/drivers/md/raid6main.c
@@ -91,10 +91,8 @@ static void print_raid6_conf (raid6_conf_t *conf);
static void __release_stripe(raid6_conf_t *conf, struct stripe_head *sh)
{
if (atomic_dec_and_test(&sh->count)) {
- if (!list_empty(&sh->lru))
- BUG();
- if (atomic_read(&conf->active_stripes)==0)
- BUG();
+ BUG_ON(!list_empty(&sh->lru));
+ BUG_ON(atomic_read(&conf->active_stripes)==0);
if (test_bit(STRIPE_HANDLE, &sh->state)) {
if (test_bit(STRIPE_DELAYED, &sh->state))
list_add_tail(&sh->lru, &conf->delayed_list);
@@ -202,10 +200,8 @@ static void init_stripe(struct stripe_head *sh, sector_t sector, int pd_idx)
raid6_conf_t *conf = sh->raid_conf;
int disks = conf->raid_disks, i;
- if (atomic_read(&sh->count) != 0)
- BUG();
- if (test_bit(STRIPE_HANDLE, &sh->state))
- BUG();
+ BUG_ON(atomic_read(&sh->count) != 0);
+ BUG_ON(test_bit(STRIPE_HANDLE, &sh->state));
CHECK_DEVLOCK();
PRINTK("init_stripe called, stripe %llu\n",
@@ -284,13 +280,11 @@ static struct stripe_head *get_active_stripe(raid6_conf_t *conf, sector_t sector
init_stripe(sh, sector, pd_idx);
} else {
if (atomic_read(&sh->count)) {
- if (!list_empty(&sh->lru))
- BUG();
+ BUG_ON(!list_empty(&sh->lru));
} else {
if (!test_bit(STRIPE_HANDLE, &sh->state))
atomic_inc(&conf->active_stripes);
- if (list_empty(&sh->lru))
- BUG();
+ BUG_ON(list_empty(&sh->lru));
list_del_init(&sh->lru);
}
}
@@ -353,8 +347,7 @@ static int drop_one_stripe(raid6_conf_t *conf)
spin_unlock_irq(&conf->device_lock);
if (!sh)
return 0;
- if (atomic_read(&sh->count))
- BUG();
+ BUG_ON(atomic_read(&sh->count));
shrink_buffers(sh, conf->raid_disks);
kmem_cache_free(conf->slab_cache, sh);
atomic_dec(&conf->active_stripes);
@@ -780,7 +773,7 @@ static void compute_parity(struct stripe_head *sh, int method)
if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags))
wake_up(&conf->wait_for_overlap);
- if (sh->dev[i].written) BUG();
+ BUG_ON(sh->dev[i].written);
sh->dev[i].written = chosen;
}
break;
@@ -970,8 +963,7 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in
if (*bip && (*bip)->bi_sector < bi->bi_sector + ((bi->bi_size)>>9))
goto overlap;
- if (*bip && bi->bi_next && (*bip) != bi->bi_next)
- BUG();
+ BUG_ON(*bip && bi->bi_next && (*bip) != bi->bi_next);
if (*bip)
bi->bi_next = *bip;
*bip = bi;
@@ -1906,8 +1898,7 @@ static void raid6d (mddev_t *mddev)
list_del_init(first);
atomic_inc(&sh->count);
- if (atomic_read(&sh->count)!= 1)
- BUG();
+ BUG_ON(atomic_read(&sh->count)!= 1);
spin_unlock_irq(&conf->device_lock);
handled++;
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index 7cc162e8978..003b077c232 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -91,4 +91,22 @@ config MMC_AU1X
If unsure, say N.
+config MMC_AT91RM9200
+ tristate "AT91RM9200 SD/MMC Card Interface support"
+ depends on ARCH_AT91RM9200 && MMC
+ help
+ This selects the AT91RM9200 MCI controller.
+
+ If unsure, say N.
+
+config MMC_IMX
+ tristate "Motorola i.MX Multimedia Card Interface support"
+ depends on ARCH_IMX && MMC
+ help
+ This selects the Motorola i.MX Multimedia card Interface.
+ If you have a i.MX platform with a Multimedia Card slot,
+ say Y or M here.
+
+ If unsure, say N.
+
endmenu
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index c7c34aadfc9..d2957e35cc6 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -17,10 +17,12 @@ obj-$(CONFIG_MMC_BLOCK) += mmc_block.o
#
obj-$(CONFIG_MMC_ARMMMCI) += mmci.o
obj-$(CONFIG_MMC_PXA) += pxamci.o
+obj-$(CONFIG_MMC_IMX) += imxmmc.o
obj-$(CONFIG_MMC_SDHCI) += sdhci.o
obj-$(CONFIG_MMC_WBSD) += wbsd.o
obj-$(CONFIG_MMC_AU1X) += au1xmmc.o
obj-$(CONFIG_MMC_OMAP) += omap.o
+obj-$(CONFIG_MMC_AT91RM9200) += at91_mci.o
mmc_core-y := mmc.o mmc_queue.o mmc_sysfs.o
diff --git a/drivers/mmc/at91_mci.c b/drivers/mmc/at91_mci.c
new file mode 100644
index 00000000000..6061c2d101a
--- /dev/null
+++ b/drivers/mmc/at91_mci.c
@@ -0,0 +1,988 @@
+/*
+ * linux/drivers/mmc/at91_mci.c - ATMEL AT91RM9200 MCI Driver
+ *
+ * Copyright (C) 2005 Cougar Creek Computing Devices Ltd, All Rights Reserved
+ *
+ * Copyright (C) 2006 Malcolm Noyes
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*
+ This is the AT91RM9200 MCI driver that has been tested with both MMC cards
+ and SD-cards. Boards that support write protect are now supported.
+ The CCAT91SBC001 board does not support SD cards.
+
+ The three entry points are at91_mci_request, at91_mci_set_ios
+ and at91_mci_get_ro.
+
+ SET IOS
+ This configures the device to put it into the correct mode and clock speed
+ required.
+
+ MCI REQUEST
+ MCI request processes the commands sent in the mmc_request structure. This
+ can consist of a processing command and a stop command in the case of
+ multiple block transfers.
+
+ There are three main types of request, commands, reads and writes.
+
+ Commands are straight forward. The command is submitted to the controller and
+ the request function returns. When the controller generates an interrupt to indicate
+ the command is finished, the response to the command are read and the mmc_request_done
+ function called to end the request.
+
+ Reads and writes work in a similar manner to normal commands but involve the PDC (DMA)
+ controller to manage the transfers.
+
+ A read is done from the controller directly to the scatterlist passed in from the request.
+ Due to a bug in the controller, when a read is completed, all the words are byte
+ swapped in the scatterlist buffers.
+
+ The sequence of read interrupts is: ENDRX, RXBUFF, CMDRDY
+
+ A write is slightly different in that the bytes to write are read from the scatterlist
+ into a dma memory buffer (this is in case the source buffer should be read only). The
+ entire write buffer is then done from this single dma memory buffer.
+
+ The sequence of write interrupts is: ENDTX, TXBUFE, NOTBUSY, CMDRDY
+
+ GET RO
+ Gets the status of the write protect pin, if available.
+*/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/dma-mapping.h>
+#include <linux/clk.h>
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/protocol.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach/mmc.h>
+#include <asm/arch/board.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/at91rm9200_mci.h>
+#include <asm/arch/at91rm9200_pdc.h>
+
+#define DRIVER_NAME "at91_mci"
+
+#undef SUPPORT_4WIRE
+
+#ifdef CONFIG_MMC_DEBUG
+#define DBG(fmt...) \
+ printk(fmt)
+#else
+#define DBG(fmt...) do { } while (0)
+#endif
+
+static struct clk *mci_clk;
+
+#define FL_SENT_COMMAND (1 << 0)
+#define FL_SENT_STOP (1 << 1)
+
+
+
+/*
+ * Read from a MCI register.
+ */
+static inline unsigned long at91_mci_read(unsigned int reg)
+{
+ void __iomem *mci_base = (void __iomem *)AT91_VA_BASE_MCI;
+
+ return __raw_readl(mci_base + reg);
+}
+
+/*
+ * Write to a MCI register.
+ */
+static inline void at91_mci_write(unsigned int reg, unsigned long value)
+{
+ void __iomem *mci_base = (void __iomem *)AT91_VA_BASE_MCI;
+
+ __raw_writel(value, mci_base + reg);
+}
+
+/*
+ * Low level type for this driver
+ */
+struct at91mci_host
+{
+ struct mmc_host *mmc;
+ struct mmc_command *cmd;
+ struct mmc_request *request;
+
+ struct at91_mmc_data *board;
+ int present;
+
+ /*
+ * Flag indicating when the command has been sent. This is used to
+ * work out whether or not to send the stop
+ */
+ unsigned int flags;
+ /* flag for current bus settings */
+ u32 bus_mode;
+
+ /* DMA buffer used for transmitting */
+ unsigned int* buffer;
+ dma_addr_t physical_address;
+ unsigned int total_length;
+
+ /* Latest in the scatterlist that has been enabled for transfer, but not freed */
+ int in_use_index;
+
+ /* Latest in the scatterlist that has been enabled for transfer */
+ int transfer_index;
+};
+
+/*
+ * Copy from sg to a dma block - used for transfers
+ */
+static inline void at91mci_sg_to_dma(struct at91mci_host *host, struct mmc_data *data)
+{
+ unsigned int len, i, size;
+ unsigned *dmabuf = host->buffer;
+
+ size = host->total_length;
+ len = data->sg_len;
+
+ /*
+ * Just loop through all entries. Size might not
+ * be the entire list though so make sure that
+ * we do not transfer too much.
+ */
+ for (i = 0; i < len; i++) {
+ struct scatterlist *sg;
+ int amount;
+ int index;
+ unsigned int *sgbuffer;
+
+ sg = &data->sg[i];
+
+ sgbuffer = kmap_atomic(sg->page, KM_BIO_SRC_IRQ) + sg->offset;
+ amount = min(size, sg->length);
+ size -= amount;
+ amount /= 4;
+
+ for (index = 0; index < amount; index++)
+ *dmabuf++ = swab32(sgbuffer[index]);
+
+ kunmap_atomic(sgbuffer, KM_BIO_SRC_IRQ);
+
+ if (size == 0)
+ break;
+ }
+
+ /*
+ * Check that we didn't get a request to transfer
+ * more data than can fit into the SG list.
+ */
+ BUG_ON(size != 0);
+}
+
+/*
+ * Prepare a dma read
+ */
+static void at91mci_pre_dma_read(struct at91mci_host *host)
+{
+ int i;
+ struct scatterlist *sg;
+ struct mmc_command *cmd;
+ struct mmc_data *data;
+
+ DBG("pre dma read\n");
+
+ cmd = host->cmd;
+ if (!cmd) {
+ DBG("no command\n");
+ return;
+ }
+
+ data = cmd->data;
+ if (!data) {
+ DBG("no data\n");
+ return;
+ }
+
+ for (i = 0; i < 2; i++) {
+ /* nothing left to transfer */
+ if (host->transfer_index >= data->sg_len) {
+ DBG("Nothing left to transfer (index = %d)\n", host->transfer_index);
+ break;
+ }
+
+ /* Check to see if this needs filling */
+ if (i == 0) {
+ if (at91_mci_read(AT91_PDC_RCR) != 0) {
+ DBG("Transfer active in current\n");
+ continue;
+ }
+ }
+ else {
+ if (at91_mci_read(AT91_PDC_RNCR) != 0) {
+ DBG("Transfer active in next\n");
+ continue;
+ }
+ }
+
+ /* Setup the next transfer */
+ DBG("Using transfer index %d\n", host->transfer_index);
+
+ sg = &data->sg[host->transfer_index++];
+ DBG("sg = %p\n", sg);
+
+ sg->dma_address = dma_map_page(NULL, sg->page, sg->offset, sg->length, DMA_FROM_DEVICE);
+
+ DBG("dma address = %08X, length = %d\n", sg->dma_address, sg->length);
+
+ if (i == 0) {
+ at91_mci_write(AT91_PDC_RPR, sg->dma_address);
+ at91_mci_write(AT91_PDC_RCR, sg->length / 4);
+ }
+ else {
+ at91_mci_write(AT91_PDC_RNPR, sg->dma_address);
+ at91_mci_write(AT91_PDC_RNCR, sg->length / 4);
+ }
+ }
+
+ DBG("pre dma read done\n");
+}
+
+/*
+ * Handle after a dma read
+ */
+static void at91mci_post_dma_read(struct at91mci_host *host)
+{
+ struct mmc_command *cmd;
+ struct mmc_data *data;
+
+ DBG("post dma read\n");
+
+ cmd = host->cmd;
+ if (!cmd) {
+ DBG("no command\n");
+ return;
+ }
+
+ data = cmd->data;
+ if (!data) {
+ DBG("no data\n");
+ return;
+ }
+
+ while (host->in_use_index < host->transfer_index) {
+ unsigned int *buffer;
+ int index;
+ int len;
+
+ struct scatterlist *sg;
+
+ DBG("finishing index %d\n", host->in_use_index);
+
+ sg = &data->sg[host->in_use_index++];
+
+ DBG("Unmapping page %08X\n", sg->dma_address);
+
+ dma_unmap_page(NULL, sg->dma_address, sg->length, DMA_FROM_DEVICE);
+
+ /* Swap the contents of the buffer */
+ buffer = kmap_atomic(sg->page, KM_BIO_SRC_IRQ) + sg->offset;
+ DBG("buffer = %p, length = %d\n", buffer, sg->length);
+
+ data->bytes_xfered += sg->length;
+
+ len = sg->length / 4;
+
+ for (index = 0; index < len; index++) {
+ buffer[index] = swab32(buffer[index]);
+ }
+ kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
+ flush_dcache_page(sg->page);
+ }
+
+ /* Is there another transfer to trigger? */
+ if (host->transfer_index < data->sg_len)
+ at91mci_pre_dma_read(host);
+ else {
+ at91_mci_write(AT91_MCI_IER, AT91_MCI_RXBUFF);
+ at91_mci_write(AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS);
+ }
+
+ DBG("post dma read done\n");
+}
+
+/*
+ * Handle transmitted data
+ */
+static void at91_mci_handle_transmitted(struct at91mci_host *host)
+{
+ struct mmc_command *cmd;
+ struct mmc_data *data;
+
+ DBG("Handling the transmit\n");
+
+ /* Disable the transfer */
+ at91_mci_write(AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS);
+
+ /* Now wait for cmd ready */
+ at91_mci_write(AT91_MCI_IDR, AT91_MCI_TXBUFE);
+ at91_mci_write(AT91_MCI_IER, AT91_MCI_NOTBUSY);
+
+ cmd = host->cmd;
+ if (!cmd) return;
+
+ data = cmd->data;
+ if (!data) return;
+
+ data->bytes_xfered = host->total_length;
+}
+
+/*
+ * Enable the controller
+ */
+static void at91_mci_enable(void)
+{
+ at91_mci_write(AT91_MCI_CR, AT91_MCI_MCIEN);
+ at91_mci_write(AT91_MCI_IDR, 0xFFFFFFFF);
+ at91_mci_write(AT91_MCI_DTOR, AT91_MCI_DTOMUL_1M | AT91_MCI_DTOCYC);
+ at91_mci_write(AT91_MCI_MR, 0x834A);
+ at91_mci_write(AT91_MCI_SDCR, 0x0);
+}
+
+/*
+ * Disable the controller
+ */
+static void at91_mci_disable(void)
+{
+ at91_mci_write(AT91_MCI_CR, AT91_MCI_MCIDIS | AT91_MCI_SWRST);
+}
+
+/*
+ * Send a command
+ * return the interrupts to enable
+ */
+static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_command *cmd)
+{
+ unsigned int cmdr, mr;
+ unsigned int block_length;
+ struct mmc_data *data = cmd->data;
+
+ unsigned int blocks;
+ unsigned int ier = 0;
+
+ host->cmd = cmd;
+
+ /* Not sure if this is needed */
+#if 0
+ if ((at91_mci_read(AT91_MCI_SR) & AT91_MCI_RTOE) && (cmd->opcode == 1)) {
+ DBG("Clearing timeout\n");
+ at91_mci_write(AT91_MCI_ARGR, 0);
+ at91_mci_write(AT91_MCI_CMDR, AT91_MCI_OPDCMD);
+ while (!(at91_mci_read(AT91_MCI_SR) & AT91_MCI_CMDRDY)) {
+ /* spin */
+ DBG("Clearing: SR = %08X\n", at91_mci_read(AT91_MCI_SR));
+ }
+ }
+#endif
+ cmdr = cmd->opcode;
+
+ if (mmc_resp_type(cmd) == MMC_RSP_NONE)
+ cmdr |= AT91_MCI_RSPTYP_NONE;
+ else {
+ /* if a response is expected then allow maximum response latancy */
+ cmdr |= AT91_MCI_MAXLAT;
+ /* set 136 bit response for R2, 48 bit response otherwise */
+ if (mmc_resp_type(cmd) == MMC_RSP_R2)
+ cmdr |= AT91_MCI_RSPTYP_136;
+ else
+ cmdr |= AT91_MCI_RSPTYP_48;
+ }
+
+ if (data) {
+ block_length = 1 << data->blksz_bits;
+ blocks = data->blocks;
+
+ /* always set data start - also set direction flag for read */
+ if (data->flags & MMC_DATA_READ)
+ cmdr |= (AT91_MCI_TRDIR | AT91_MCI_TRCMD_START);
+ else if (data->flags & MMC_DATA_WRITE)
+ cmdr |= AT91_MCI_TRCMD_START;
+
+ if (data->flags & MMC_DATA_STREAM)
+ cmdr |= AT91_MCI_TRTYP_STREAM;
+ if (data->flags & MMC_DATA_MULTI)
+ cmdr |= AT91_MCI_TRTYP_MULTIPLE;
+ }
+ else {
+ block_length = 0;
+ blocks = 0;
+ }
+
+ if (cmd->opcode == MMC_STOP_TRANSMISSION)
+ cmdr |= AT91_MCI_TRCMD_STOP;
+
+ if (host->bus_mode == MMC_BUSMODE_OPENDRAIN)
+ cmdr |= AT91_MCI_OPDCMD;
+
+ /*
+ * Set the arguments and send the command
+ */
+ DBG("Sending command %d as %08X, arg = %08X, blocks = %d, length = %d (MR = %08lX)\n",
+ cmd->opcode, cmdr, cmd->arg, blocks, block_length, at91_mci_read(AT91_MCI_MR));
+
+ if (!data) {
+ at91_mci_write(AT91_PDC_PTCR, AT91_PDC_TXTDIS | AT91_PDC_RXTDIS);
+ at91_mci_write(AT91_PDC_RPR, 0);
+ at91_mci_write(AT91_PDC_RCR, 0);
+ at91_mci_write(AT91_PDC_RNPR, 0);
+ at91_mci_write(AT91_PDC_RNCR, 0);
+ at91_mci_write(AT91_PDC_TPR, 0);
+ at91_mci_write(AT91_PDC_TCR, 0);
+ at91_mci_write(AT91_PDC_TNPR, 0);
+ at91_mci_write(AT91_PDC_TNCR, 0);
+
+ at91_mci_write(AT91_MCI_ARGR, cmd->arg);
+ at91_mci_write(AT91_MCI_CMDR, cmdr);
+ return AT91_MCI_CMDRDY;
+ }
+
+ mr = at91_mci_read(AT91_MCI_MR) & 0x7fff; /* zero block length and PDC mode */
+ at91_mci_write(AT91_MCI_MR, mr | (block_length << 16) | AT91_MCI_PDCMODE);
+
+ /*
+ * Disable the PDC controller
+ */
+ at91_mci_write(AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS);
+
+ if (cmdr & AT91_MCI_TRCMD_START) {
+ data->bytes_xfered = 0;
+ host->transfer_index = 0;
+ host->in_use_index = 0;
+ if (cmdr & AT91_MCI_TRDIR) {
+ /*
+ * Handle a read
+ */
+ host->buffer = NULL;
+ host->total_length = 0;
+
+ at91mci_pre_dma_read(host);
+ ier = AT91_MCI_ENDRX /* | AT91_MCI_RXBUFF */;
+ }
+ else {
+ /*
+ * Handle a write
+ */
+ host->total_length = block_length * blocks;
+ host->buffer = dma_alloc_coherent(NULL,
+ host->total_length,
+ &host->physical_address, GFP_KERNEL);
+
+ at91mci_sg_to_dma(host, data);
+
+ DBG("Transmitting %d bytes\n", host->total_length);
+
+ at91_mci_write(AT91_PDC_TPR, host->physical_address);
+ at91_mci_write(AT91_PDC_TCR, host->total_length / 4);
+ ier = AT91_MCI_TXBUFE;
+ }
+ }
+
+ /*
+ * Send the command and then enable the PDC - not the other way round as
+ * the data sheet says
+ */
+
+ at91_mci_write(AT91_MCI_ARGR, cmd->arg);
+ at91_mci_write(AT91_MCI_CMDR, cmdr);
+
+ if (cmdr & AT91_MCI_TRCMD_START) {
+ if (cmdr & AT91_MCI_TRDIR)
+ at91_mci_write(AT91_PDC_PTCR, AT91_PDC_RXTEN);
+ else
+ at91_mci_write(AT91_PDC_PTCR, AT91_PDC_TXTEN);
+ }
+ return ier;
+}
+
+/*
+ * Wait for a command to complete
+ */
+static void at91mci_process_command(struct at91mci_host *host, struct mmc_command *cmd)
+{
+ unsigned int ier;
+
+ ier = at91_mci_send_command(host, cmd);
+
+ DBG("setting ier to %08X\n", ier);
+
+ /* Stop on errors or the required value */
+ at91_mci_write(AT91_MCI_IER, 0xffff0000 | ier);
+}
+
+/*
+ * Process the next step in the request
+ */
+static void at91mci_process_next(struct at91mci_host *host)
+{
+ if (!(host->flags & FL_SENT_COMMAND)) {
+ host->flags |= FL_SENT_COMMAND;
+ at91mci_process_command(host, host->request->cmd);
+ }
+ else if ((!(host->flags & FL_SENT_STOP)) && host->request->stop) {
+ host->flags |= FL_SENT_STOP;
+ at91mci_process_command(host, host->request->stop);
+ }
+ else
+ mmc_request_done(host->mmc, host->request);
+}
+
+/*
+ * Handle a command that has been completed
+ */
+static void at91mci_completed_command(struct at91mci_host *host)
+{
+ struct mmc_command *cmd = host->cmd;
+ unsigned int status;
+
+ at91_mci_write(AT91_MCI_IDR, 0xffffffff);
+
+ cmd->resp[0] = at91_mci_read(AT91_MCI_RSPR(0));
+ cmd->resp[1] = at91_mci_read(AT91_MCI_RSPR(1));
+ cmd->resp[2] = at91_mci_read(AT91_MCI_RSPR(2));
+ cmd->resp[3] = at91_mci_read(AT91_MCI_RSPR(3));
+
+ if (host->buffer) {
+ dma_free_coherent(NULL, host->total_length, host->buffer, host->physical_address);
+ host->buffer = NULL;
+ }
+
+ status = at91_mci_read(AT91_MCI_SR);
+
+ DBG("Status = %08X [%08X %08X %08X %08X]\n",
+ status, cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
+
+ if (status & (AT91_MCI_RINDE | AT91_MCI_RDIRE | AT91_MCI_RCRCE |
+ AT91_MCI_RENDE | AT91_MCI_RTOE | AT91_MCI_DCRCE |
+ AT91_MCI_DTOE | AT91_MCI_OVRE | AT91_MCI_UNRE)) {
+ if ((status & AT91_MCI_RCRCE) &&
+ ((cmd->opcode == MMC_SEND_OP_COND) || (cmd->opcode == SD_APP_OP_COND))) {
+ cmd->error = MMC_ERR_NONE;
+ }
+ else {
+ if (status & (AT91_MCI_RTOE | AT91_MCI_DTOE))
+ cmd->error = MMC_ERR_TIMEOUT;
+ else if (status & (AT91_MCI_RCRCE | AT91_MCI_DCRCE))
+ cmd->error = MMC_ERR_BADCRC;
+ else if (status & (AT91_MCI_OVRE | AT91_MCI_UNRE))
+ cmd->error = MMC_ERR_FIFO;
+ else
+ cmd->error = MMC_ERR_FAILED;
+
+ DBG("Error detected and set to %d (cmd = %d, retries = %d)\n",
+ cmd->error, cmd->opcode, cmd->retries);
+ }
+ }
+ else
+ cmd->error = MMC_ERR_NONE;
+
+ at91mci_process_next(host);
+}
+
+/*
+ * Handle an MMC request
+ */
+static void at91_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+ struct at91mci_host *host = mmc_priv(mmc);
+ host->request = mrq;
+ host->flags = 0;
+
+ at91mci_process_next(host);
+}
+
+/*
+ * Set the IOS
+ */
+static void at91_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ int clkdiv;
+ struct at91mci_host *host = mmc_priv(mmc);
+ unsigned long at91_master_clock = clk_get_rate(mci_clk);
+
+ DBG("Clock %uHz, busmode %u, powermode %u, Vdd %u\n",
+ ios->clock, ios->bus_mode, ios->power_mode, ios->vdd);
+
+ if (host)
+ host->bus_mode = ios->bus_mode;
+ else
+ printk("MMC: No host for bus_mode\n");
+
+ if (ios->clock == 0) {
+ /* Disable the MCI controller */
+ at91_mci_write(AT91_MCI_CR, AT91_MCI_MCIDIS);
+ clkdiv = 0;
+ }
+ else {
+ /* Enable the MCI controller */
+ at91_mci_write(AT91_MCI_CR, AT91_MCI_MCIEN);
+
+ if ((at91_master_clock % (ios->clock * 2)) == 0)
+ clkdiv = ((at91_master_clock / ios->clock) / 2) - 1;
+ else
+ clkdiv = (at91_master_clock / ios->clock) / 2;
+
+ DBG("clkdiv = %d. mcck = %ld\n", clkdiv,
+ at91_master_clock / (2 * (clkdiv + 1)));
+ }
+ if (ios->bus_width == MMC_BUS_WIDTH_4 && host->board->wire4) {
+ DBG("MMC: Setting controller bus width to 4\n");
+ at91_mci_write(AT91_MCI_SDCR, at91_mci_read(AT91_MCI_SDCR) | AT91_MCI_SDCBUS);
+ }
+ else {
+ DBG("MMC: Setting controller bus width to 1\n");
+ at91_mci_write(AT91_MCI_SDCR, at91_mci_read(AT91_MCI_SDCR) & ~AT91_MCI_SDCBUS);
+ }
+
+ /* Set the clock divider */
+ at91_mci_write(AT91_MCI_MR, (at91_mci_read(AT91_MCI_MR) & ~AT91_MCI_CLKDIV) | clkdiv);
+
+ /* maybe switch power to the card */
+ if (host && host->board->vcc_pin) {
+ switch (ios->power_mode) {
+ case MMC_POWER_OFF:
+ at91_set_gpio_output(host->board->vcc_pin, 0);
+ break;
+ case MMC_POWER_UP:
+ case MMC_POWER_ON:
+ at91_set_gpio_output(host->board->vcc_pin, 1);
+ break;
+ }
+ }
+}
+
+/*
+ * Handle an interrupt
+ */
+static irqreturn_t at91_mci_irq(int irq, void *devid, struct pt_regs *regs)
+{
+ struct at91mci_host *host = devid;
+ int completed = 0;
+
+ unsigned int int_status;
+
+ if (host == NULL)
+ return IRQ_HANDLED;
+
+ int_status = at91_mci_read(AT91_MCI_SR);
+ DBG("MCI irq: status = %08X, %08lX, %08lX\n", int_status, at91_mci_read(AT91_MCI_IMR),
+ int_status & at91_mci_read(AT91_MCI_IMR));
+
+ if ((int_status & at91_mci_read(AT91_MCI_IMR)) & 0xffff0000)
+ completed = 1;
+
+ int_status &= at91_mci_read(AT91_MCI_IMR);
+
+ if (int_status & AT91_MCI_UNRE)
+ DBG("MMC: Underrun error\n");
+ if (int_status & AT91_MCI_OVRE)
+ DBG("MMC: Overrun error\n");
+ if (int_status & AT91_MCI_DTOE)
+ DBG("MMC: Data timeout\n");
+ if (int_status & AT91_MCI_DCRCE)
+ DBG("MMC: CRC error in data\n");
+ if (int_status & AT91_MCI_RTOE)
+ DBG("MMC: Response timeout\n");
+ if (int_status & AT91_MCI_RENDE)
+ DBG("MMC: Response end bit error\n");
+ if (int_status & AT91_MCI_RCRCE)
+ DBG("MMC: Response CRC error\n");
+ if (int_status & AT91_MCI_RDIRE)
+ DBG("MMC: Response direction error\n");
+ if (int_status & AT91_MCI_RINDE)
+ DBG("MMC: Response index error\n");
+
+ /* Only continue processing if no errors */
+ if (!completed) {
+ if (int_status & AT91_MCI_TXBUFE) {
+ DBG("TX buffer empty\n");
+ at91_mci_handle_transmitted(host);
+ }
+
+ if (int_status & AT91_MCI_RXBUFF) {
+ DBG("RX buffer full\n");
+ at91_mci_write(AT91_MCI_IER, AT91_MCI_CMDRDY);
+ }
+
+ if (int_status & AT91_MCI_ENDTX) {
+ DBG("Transmit has ended\n");
+ }
+
+ if (int_status & AT91_MCI_ENDRX) {
+ DBG("Receive has ended\n");
+ at91mci_post_dma_read(host);
+ }
+
+ if (int_status & AT91_MCI_NOTBUSY) {
+ DBG("Card is ready\n");
+ at91_mci_write(AT91_MCI_IER, AT91_MCI_CMDRDY);
+ }
+
+ if (int_status & AT91_MCI_DTIP) {
+ DBG("Data transfer in progress\n");
+ }
+
+ if (int_status & AT91_MCI_BLKE) {
+ DBG("Block transfer has ended\n");
+ }
+
+ if (int_status & AT91_MCI_TXRDY) {
+ DBG("Ready to transmit\n");
+ }
+
+ if (int_status & AT91_MCI_RXRDY) {
+ DBG("Ready to receive\n");
+ }
+
+ if (int_status & AT91_MCI_CMDRDY) {
+ DBG("Command ready\n");
+ completed = 1;
+ }
+ }
+ at91_mci_write(AT91_MCI_IDR, int_status);
+
+ if (completed) {
+ DBG("Completed command\n");
+ at91_mci_write(AT91_MCI_IDR, 0xffffffff);
+ at91mci_completed_command(host);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t at91_mmc_det_irq(int irq, void *_host, struct pt_regs *regs)
+{
+ struct at91mci_host *host = _host;
+ int present = !at91_get_gpio_value(irq);
+
+ /*
+ * we expect this irq on both insert and remove,
+ * and use a short delay to debounce.
+ */
+ if (present != host->present) {
+ host->present = present;
+ DBG("%s: card %s\n", mmc_hostname(host->mmc),
+ present ? "insert" : "remove");
+ if (!present) {
+ DBG("****** Resetting SD-card bus width ******\n");
+ at91_mci_write(AT91_MCI_SDCR, 0);
+ }
+ mmc_detect_change(host->mmc, msecs_to_jiffies(100));
+ }
+ return IRQ_HANDLED;
+}
+
+int at91_mci_get_ro(struct mmc_host *mmc)
+{
+ int read_only = 0;
+ struct at91mci_host *host = mmc_priv(mmc);
+
+ if (host->board->wp_pin) {
+ read_only = at91_get_gpio_value(host->board->wp_pin);
+ printk(KERN_WARNING "%s: card is %s\n", mmc_hostname(mmc),
+ (read_only ? "read-only" : "read-write") );
+ }
+ else {
+ printk(KERN_WARNING "%s: host does not support reading read-only "
+ "switch. Assuming write-enable.\n", mmc_hostname(mmc));
+ }
+ return read_only;
+}
+
+static struct mmc_host_ops at91_mci_ops = {
+ .request = at91_mci_request,
+ .set_ios = at91_mci_set_ios,
+ .get_ro = at91_mci_get_ro,
+};
+
+/*
+ * Probe for the device
+ */
+static int at91_mci_probe(struct platform_device *pdev)
+{
+ struct mmc_host *mmc;
+ struct at91mci_host *host;
+ int ret;
+
+ DBG("Probe MCI devices\n");
+ at91_mci_disable();
+ at91_mci_enable();
+
+ mmc = mmc_alloc_host(sizeof(struct at91mci_host), &pdev->dev);
+ if (!mmc) {
+ DBG("Failed to allocate mmc host\n");
+ return -ENOMEM;
+ }
+
+ mmc->ops = &at91_mci_ops;
+ mmc->f_min = 375000;
+ mmc->f_max = 25000000;
+ mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+
+ host = mmc_priv(mmc);
+ host->mmc = mmc;
+ host->buffer = NULL;
+ host->bus_mode = 0;
+ host->board = pdev->dev.platform_data;
+ if (host->board->wire4) {
+#ifdef SUPPORT_4WIRE
+ mmc->caps |= MMC_CAP_4_BIT_DATA;
+#else
+ printk("MMC: 4 wire bus mode not supported by this driver - using 1 wire\n");
+#endif
+ }
+
+ /*
+ * Get Clock
+ */
+ mci_clk = clk_get(&pdev->dev, "mci_clk");
+ if (!mci_clk) {
+ printk(KERN_ERR "AT91 MMC: no clock defined.\n");
+ return -ENODEV;
+ }
+ clk_enable(mci_clk); /* Enable the peripheral clock */
+
+ /*
+ * Allocate the MCI interrupt
+ */
+ ret = request_irq(AT91_ID_MCI, at91_mci_irq, SA_SHIRQ, DRIVER_NAME, host);
+ if (ret) {
+ DBG("Failed to request MCI interrupt\n");
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, mmc);
+
+ /*
+ * Add host to MMC layer
+ */
+ if (host->board->det_pin)
+ host->present = !at91_get_gpio_value(host->board->det_pin);
+ else
+ host->present = -1;
+
+ mmc_add_host(mmc);
+
+ /*
+ * monitor card insertion/removal if we can
+ */
+ if (host->board->det_pin) {
+ ret = request_irq(host->board->det_pin, at91_mmc_det_irq,
+ SA_SAMPLE_RANDOM, DRIVER_NAME, host);
+ if (ret)
+ DBG("couldn't allocate MMC detect irq\n");
+ }
+
+ DBG(KERN_INFO "Added MCI driver\n");
+
+ return 0;
+}
+
+/*
+ * Remove a device
+ */
+static int at91_mci_remove(struct platform_device *pdev)
+{
+ struct mmc_host *mmc = platform_get_drvdata(pdev);
+ struct at91mci_host *host;
+
+ if (!mmc)
+ return -1;
+
+ host = mmc_priv(mmc);
+
+ if (host->present != -1) {
+ free_irq(host->board->det_pin, host);
+ cancel_delayed_work(&host->mmc->detect);
+ }
+
+ mmc_remove_host(mmc);
+ at91_mci_disable();
+ free_irq(AT91_ID_MCI, host);
+ mmc_free_host(mmc);
+
+ clk_disable(mci_clk); /* Disable the peripheral clock */
+ clk_put(mci_clk);
+
+ platform_set_drvdata(pdev, NULL);
+
+ DBG("Removed\n");
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int at91_mci_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct mmc_host *mmc = platform_get_drvdata(pdev);
+ int ret = 0;
+
+ if (mmc)
+ ret = mmc_suspend_host(mmc, state);
+
+ return ret;
+}
+
+static int at91_mci_resume(struct platform_device *pdev)
+{
+ struct mmc_host *mmc = platform_get_drvdata(pdev);
+ int ret = 0;
+
+ if (mmc)
+ ret = mmc_resume_host(mmc);
+
+ return ret;
+}
+#else
+#define at91_mci_suspend NULL
+#define at91_mci_resume NULL
+#endif
+
+static struct platform_driver at91_mci_driver = {
+ .probe = at91_mci_probe,
+ .remove = at91_mci_remove,
+ .suspend = at91_mci_suspend,
+ .resume = at91_mci_resume,
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init at91_mci_init(void)
+{
+ return platform_driver_register(&at91_mci_driver);
+}
+
+static void __exit at91_mci_exit(void)
+{
+ platform_driver_unregister(&at91_mci_driver);
+}
+
+module_init(at91_mci_init);
+module_exit(at91_mci_exit);
+
+MODULE_DESCRIPTION("AT91 Multimedia Card Interface driver");
+MODULE_AUTHOR("Nick Randell");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/imxmmc.c b/drivers/mmc/imxmmc.c
new file mode 100644
index 00000000000..ffb7f55d346
--- /dev/null
+++ b/drivers/mmc/imxmmc.c
@@ -0,0 +1,1096 @@
+/*
+ * linux/drivers/mmc/imxmmc.c - Motorola i.MX MMCI driver
+ *
+ * Copyright (C) 2004 Sascha Hauer, Pengutronix <sascha@saschahauer.de>
+ * Copyright (C) 2006 Pavel Pisa, PiKRON <ppisa@pikron.com>
+ *
+ * derived from pxamci.c by Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 2005-04-17 Pavel Pisa <pisa@cmp.felk.cvut.cz>
+ * Changed to conform redesigned i.MX scatter gather DMA interface
+ *
+ * 2005-11-04 Pavel Pisa <pisa@cmp.felk.cvut.cz>
+ * Updated for 2.6.14 kernel
+ *
+ * 2005-12-13 Jay Monkman <jtm@smoothsmoothie.com>
+ * Found and corrected problems in the write path
+ *
+ * 2005-12-30 Pavel Pisa <pisa@cmp.felk.cvut.cz>
+ * The event handling rewritten right way in softirq.
+ * Added many ugly hacks and delays to overcome SDHC
+ * deficiencies
+ *
+ */
+#include <linux/config.h>
+
+#ifdef CONFIG_MMC_DEBUG
+#define DEBUG
+#else
+#undef DEBUG
+#endif
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/dma-mapping.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/protocol.h>
+#include <linux/delay.h>
+
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/sizes.h>
+#include <asm/arch/mmc.h>
+#include <asm/arch/imx-dma.h>
+
+#include "imxmmc.h"
+
+#define DRIVER_NAME "imx-mmc"
+
+#define IMXMCI_INT_MASK_DEFAULT (INT_MASK_BUF_READY | INT_MASK_DATA_TRAN | \
+ INT_MASK_WRITE_OP_DONE | INT_MASK_END_CMD_RES | \
+ INT_MASK_AUTO_CARD_DETECT | INT_MASK_DAT0_EN | INT_MASK_SDIO)
+
+struct imxmci_host {
+ struct mmc_host *mmc;
+ spinlock_t lock;
+ struct resource *res;
+ int irq;
+ imx_dmach_t dma;
+ unsigned int clkrt;
+ unsigned int cmdat;
+ volatile unsigned int imask;
+ unsigned int power_mode;
+ unsigned int present;
+ struct imxmmc_platform_data *pdata;
+
+ struct mmc_request *req;
+ struct mmc_command *cmd;
+ struct mmc_data *data;
+
+ struct timer_list timer;
+ struct tasklet_struct tasklet;
+ unsigned int status_reg;
+ unsigned long pending_events;
+ /* Next to fields are there for CPU driven transfers to overcome SDHC deficiencies */
+ u16 *data_ptr;
+ unsigned int data_cnt;
+ atomic_t stuck_timeout;
+
+ unsigned int dma_nents;
+ unsigned int dma_size;
+ unsigned int dma_dir;
+ int dma_allocated;
+
+ unsigned char actual_bus_width;
+};
+
+#define IMXMCI_PEND_IRQ_b 0
+#define IMXMCI_PEND_DMA_END_b 1
+#define IMXMCI_PEND_DMA_ERR_b 2
+#define IMXMCI_PEND_WAIT_RESP_b 3
+#define IMXMCI_PEND_DMA_DATA_b 4
+#define IMXMCI_PEND_CPU_DATA_b 5
+#define IMXMCI_PEND_CARD_XCHG_b 6
+#define IMXMCI_PEND_SET_INIT_b 7
+
+#define IMXMCI_PEND_IRQ_m (1 << IMXMCI_PEND_IRQ_b)
+#define IMXMCI_PEND_DMA_END_m (1 << IMXMCI_PEND_DMA_END_b)
+#define IMXMCI_PEND_DMA_ERR_m (1 << IMXMCI_PEND_DMA_ERR_b)
+#define IMXMCI_PEND_WAIT_RESP_m (1 << IMXMCI_PEND_WAIT_RESP_b)
+#define IMXMCI_PEND_DMA_DATA_m (1 << IMXMCI_PEND_DMA_DATA_b)
+#define IMXMCI_PEND_CPU_DATA_m (1 << IMXMCI_PEND_CPU_DATA_b)
+#define IMXMCI_PEND_CARD_XCHG_m (1 << IMXMCI_PEND_CARD_XCHG_b)
+#define IMXMCI_PEND_SET_INIT_m (1 << IMXMCI_PEND_SET_INIT_b)
+
+static void imxmci_stop_clock(struct imxmci_host *host)
+{
+ int i = 0;
+ MMC_STR_STP_CLK &= ~STR_STP_CLK_START_CLK;
+ while(i < 0x1000) {
+ if(!(i & 0x7f))
+ MMC_STR_STP_CLK |= STR_STP_CLK_STOP_CLK;
+
+ if(!(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN)) {
+ /* Check twice before cut */
+ if(!(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN))
+ return;
+ }
+
+ i++;
+ }
+ dev_dbg(mmc_dev(host->mmc), "imxmci_stop_clock blocked, no luck\n");
+}
+
+static void imxmci_start_clock(struct imxmci_host *host)
+{
+ int i = 0;
+ MMC_STR_STP_CLK &= ~STR_STP_CLK_STOP_CLK;
+ while(i < 0x1000) {
+ if(!(i & 0x7f))
+ MMC_STR_STP_CLK |= STR_STP_CLK_START_CLK;
+
+ if(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN) {
+ /* Check twice before cut */
+ if(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN)
+ return;
+ }
+
+ i++;
+ }
+ dev_dbg(mmc_dev(host->mmc), "imxmci_start_clock blocked, no luck\n");
+}
+
+static void imxmci_softreset(void)
+{
+ /* reset sequence */
+ MMC_STR_STP_CLK = 0x8;
+ MMC_STR_STP_CLK = 0xD;
+ MMC_STR_STP_CLK = 0x5;
+ MMC_STR_STP_CLK = 0x5;
+ MMC_STR_STP_CLK = 0x5;
+ MMC_STR_STP_CLK = 0x5;
+ MMC_STR_STP_CLK = 0x5;
+ MMC_STR_STP_CLK = 0x5;
+ MMC_STR_STP_CLK = 0x5;
+ MMC_STR_STP_CLK = 0x5;
+
+ MMC_RES_TO = 0xff;
+ MMC_BLK_LEN = 512;
+ MMC_NOB = 1;
+}
+
+static int imxmci_busy_wait_for_status(struct imxmci_host *host,
+ unsigned int *pstat, unsigned int stat_mask,
+ int timeout, const char *where)
+{
+ int loops=0;
+ while(!(*pstat & stat_mask)) {
+ loops+=2;
+ if(loops >= timeout) {
+ dev_dbg(mmc_dev(host->mmc), "busy wait timeout in %s, STATUS = 0x%x (0x%x)\n",
+ where, *pstat, stat_mask);
+ return -1;
+ }
+ udelay(2);
+ *pstat |= MMC_STATUS;
+ }
+ if(!loops)
+ return 0;
+
+ dev_info(mmc_dev(host->mmc), "busy wait for %d usec in %s, STATUS = 0x%x (0x%x)\n",
+ loops, where, *pstat, stat_mask);
+ return loops;
+}
+
+static void imxmci_setup_data(struct imxmci_host *host, struct mmc_data *data)
+{
+ unsigned int nob = data->blocks;
+ unsigned int blksz = 1 << data->blksz_bits;
+ unsigned int datasz = nob * blksz;
+ int i;
+
+ if (data->flags & MMC_DATA_STREAM)
+ nob = 0xffff;
+
+ host->data = data;
+ data->bytes_xfered = 0;
+
+ MMC_NOB = nob;
+ MMC_BLK_LEN = blksz;
+
+ /*
+ * DMA cannot be used for small block sizes, we have to use CPU driven transfers otherwise.
+ * We are in big troubles for non-512 byte transfers according to note in the paragraph
+ * 20.6.7 of User Manual anyway, but we need to be able to transfer SCR at least.
+ * The situation is even more complex in reality. The SDHC in not able to handle wll
+ * partial FIFO fills and reads. The length has to be rounded up to burst size multiple.
+ * This is required for SCR read at least.
+ */
+ if (datasz < 64) {
+ host->dma_size = datasz;
+ if (data->flags & MMC_DATA_READ) {
+ host->dma_dir = DMA_FROM_DEVICE;
+
+ /* Hack to enable read SCR */
+ if(datasz < 16) {
+ MMC_NOB = 1;
+ MMC_BLK_LEN = 16;
+ }
+ } else {
+ host->dma_dir = DMA_TO_DEVICE;
+ }
+
+ /* Convert back to virtual address */
+ host->data_ptr = (u16*)(page_address(data->sg->page) + data->sg->offset);
+ host->data_cnt = 0;
+
+ clear_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events);
+ set_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events);
+
+ return;
+ }
+
+ if (data->flags & MMC_DATA_READ) {
+ host->dma_dir = DMA_FROM_DEVICE;
+ host->dma_nents = dma_map_sg(mmc_dev(host->mmc), data->sg,
+ data->sg_len, host->dma_dir);
+
+ imx_dma_setup_sg(host->dma, data->sg, data->sg_len, datasz,
+ host->res->start + MMC_BUFFER_ACCESS_OFS, DMA_MODE_READ);
+
+ /*imx_dma_setup_mem2dev_ccr(host->dma, DMA_MODE_READ, IMX_DMA_WIDTH_16, CCR_REN);*/
+ CCR(host->dma) = CCR_DMOD_LINEAR | CCR_DSIZ_32 | CCR_SMOD_FIFO | CCR_SSIZ_16 | CCR_REN;
+ } else {
+ host->dma_dir = DMA_TO_DEVICE;
+
+ host->dma_nents = dma_map_sg(mmc_dev(host->mmc), data->sg,
+ data->sg_len, host->dma_dir);
+
+ imx_dma_setup_sg(host->dma, data->sg, data->sg_len, datasz,
+ host->res->start + MMC_BUFFER_ACCESS_OFS, DMA_MODE_WRITE);
+
+ /*imx_dma_setup_mem2dev_ccr(host->dma, DMA_MODE_WRITE, IMX_DMA_WIDTH_16, CCR_REN);*/
+ CCR(host->dma) = CCR_SMOD_LINEAR | CCR_SSIZ_32 | CCR_DMOD_FIFO | CCR_DSIZ_16 | CCR_REN;
+ }
+
+#if 1 /* This code is there only for consistency checking and can be disabled in future */
+ host->dma_size = 0;
+ for(i=0; i<host->dma_nents; i++)
+ host->dma_size+=data->sg[i].length;
+
+ if (datasz > host->dma_size) {
+ dev_err(mmc_dev(host->mmc), "imxmci_setup_data datasz 0x%x > 0x%x dm_size\n",
+ datasz, host->dma_size);
+ }
+#endif
+
+ host->dma_size = datasz;
+
+ wmb();
+
+ if(host->actual_bus_width == MMC_BUS_WIDTH_4)
+ BLR(host->dma) = 0; /* burst 64 byte read / 64 bytes write */
+ else
+ BLR(host->dma) = 16; /* burst 16 byte read / 16 bytes write */
+
+ RSSR(host->dma) = DMA_REQ_SDHC;
+
+ set_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events);
+ clear_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events);
+
+ /* start DMA engine for read, write is delayed after initial response */
+ if (host->dma_dir == DMA_FROM_DEVICE) {
+ imx_dma_enable(host->dma);
+ }
+}
+
+static void imxmci_start_cmd(struct imxmci_host *host, struct mmc_command *cmd, unsigned int cmdat)
+{
+ unsigned long flags;
+ u32 imask;
+
+ WARN_ON(host->cmd != NULL);
+ host->cmd = cmd;
+
+ if (cmd->flags & MMC_RSP_BUSY)
+ cmdat |= CMD_DAT_CONT_BUSY;
+
+ switch (mmc_resp_type(cmd)) {
+ case MMC_RSP_R1: /* short CRC, OPCODE */
+ case MMC_RSP_R1B:/* short CRC, OPCODE, BUSY */
+ cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R1;
+ break;
+ case MMC_RSP_R2: /* long 136 bit + CRC */
+ cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R2;
+ break;
+ case MMC_RSP_R3: /* short */
+ cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R3;
+ break;
+ case MMC_RSP_R6: /* short CRC */
+ cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R6;
+ break;
+ default:
+ break;
+ }
+
+ if ( test_and_clear_bit(IMXMCI_PEND_SET_INIT_b, &host->pending_events) )
+ cmdat |= CMD_DAT_CONT_INIT; /* This command needs init */
+
+ if ( host->actual_bus_width == MMC_BUS_WIDTH_4 )
+ cmdat |= CMD_DAT_CONT_BUS_WIDTH_4;
+
+ MMC_CMD = cmd->opcode;
+ MMC_ARGH = cmd->arg >> 16;
+ MMC_ARGL = cmd->arg & 0xffff;
+ MMC_CMD_DAT_CONT = cmdat;
+
+ atomic_set(&host->stuck_timeout, 0);
+ set_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events);
+
+
+ imask = IMXMCI_INT_MASK_DEFAULT;
+ imask &= ~INT_MASK_END_CMD_RES;
+ if ( cmdat & CMD_DAT_CONT_DATA_ENABLE ) {
+ /*imask &= ~INT_MASK_BUF_READY;*/
+ imask &= ~INT_MASK_DATA_TRAN;
+ if ( cmdat & CMD_DAT_CONT_WRITE )
+ imask &= ~INT_MASK_WRITE_OP_DONE;
+ if(test_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events))
+ imask &= ~INT_MASK_BUF_READY;
+ }
+
+ spin_lock_irqsave(&host->lock, flags);
+ host->imask = imask;
+ MMC_INT_MASK = host->imask;
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ dev_dbg(mmc_dev(host->mmc), "CMD%02d (0x%02x) mask set to 0x%04x\n",
+ cmd->opcode, cmd->opcode, imask);
+
+ imxmci_start_clock(host);
+}
+
+static void imxmci_finish_request(struct imxmci_host *host, struct mmc_request *req)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ host->pending_events &= ~(IMXMCI_PEND_WAIT_RESP_m | IMXMCI_PEND_DMA_END_m |
+ IMXMCI_PEND_DMA_DATA_m | IMXMCI_PEND_CPU_DATA_m);
+
+ host->imask = IMXMCI_INT_MASK_DEFAULT;
+ MMC_INT_MASK = host->imask;
+
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ host->req = NULL;
+ host->cmd = NULL;
+ host->data = NULL;
+ mmc_request_done(host->mmc, req);
+}
+
+static int imxmci_finish_data(struct imxmci_host *host, unsigned int stat)
+{
+ struct mmc_data *data = host->data;
+ int data_error;
+
+ if(test_and_clear_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events)){
+ imx_dma_disable(host->dma);
+ dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_nents,
+ host->dma_dir);
+ }
+
+ if ( stat & STATUS_ERR_MASK ) {
+ dev_dbg(mmc_dev(host->mmc), "request failed. status: 0x%08x\n",stat);
+ if(stat & (STATUS_CRC_READ_ERR | STATUS_CRC_WRITE_ERR))
+ data->error = MMC_ERR_BADCRC;
+ else if(stat & STATUS_TIME_OUT_READ)
+ data->error = MMC_ERR_TIMEOUT;
+ else
+ data->error = MMC_ERR_FAILED;
+ } else {
+ data->bytes_xfered = host->dma_size;
+ }
+
+ data_error = data->error;
+
+ host->data = NULL;
+
+ return data_error;
+}
+
+static int imxmci_cmd_done(struct imxmci_host *host, unsigned int stat)
+{
+ struct mmc_command *cmd = host->cmd;
+ int i;
+ u32 a,b,c;
+ struct mmc_data *data = host->data;
+
+ if (!cmd)
+ return 0;
+
+ host->cmd = NULL;
+
+ if (stat & STATUS_TIME_OUT_RESP) {
+ dev_dbg(mmc_dev(host->mmc), "CMD TIMEOUT\n");
+ cmd->error = MMC_ERR_TIMEOUT;
+ } else if (stat & STATUS_RESP_CRC_ERR && cmd->flags & MMC_RSP_CRC) {
+ dev_dbg(mmc_dev(host->mmc), "cmd crc error\n");
+ cmd->error = MMC_ERR_BADCRC;
+ }
+
+ if(cmd->flags & MMC_RSP_PRESENT) {
+ if(cmd->flags & MMC_RSP_136) {
+ for (i = 0; i < 4; i++) {
+ u32 a = MMC_RES_FIFO & 0xffff;
+ u32 b = MMC_RES_FIFO & 0xffff;
+ cmd->resp[i] = a<<16 | b;
+ }
+ } else {
+ a = MMC_RES_FIFO & 0xffff;
+ b = MMC_RES_FIFO & 0xffff;
+ c = MMC_RES_FIFO & 0xffff;
+ cmd->resp[0] = a<<24 | b<<8 | c>>8;
+ }
+ }
+
+ dev_dbg(mmc_dev(host->mmc), "RESP 0x%08x, 0x%08x, 0x%08x, 0x%08x, error %d\n",
+ cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3], cmd->error);
+
+ if (data && (cmd->error == MMC_ERR_NONE) && !(stat & STATUS_ERR_MASK)) {
+ if (host->req->data->flags & MMC_DATA_WRITE) {
+
+ /* Wait for FIFO to be empty before starting DMA write */
+
+ stat = MMC_STATUS;
+ if(imxmci_busy_wait_for_status(host, &stat,
+ STATUS_APPL_BUFF_FE,
+ 40, "imxmci_cmd_done DMA WR") < 0) {
+ cmd->error = MMC_ERR_FIFO;
+ imxmci_finish_data(host, stat);
+ if(host->req)
+ imxmci_finish_request(host, host->req);
+ dev_warn(mmc_dev(host->mmc), "STATUS = 0x%04x\n",
+ stat);
+ return 0;
+ }
+
+ if(test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events)) {
+ imx_dma_enable(host->dma);
+ }
+ }
+ } else {
+ struct mmc_request *req;
+ imxmci_stop_clock(host);
+ req = host->req;
+
+ if(data)
+ imxmci_finish_data(host, stat);
+
+ if( req ) {
+ imxmci_finish_request(host, req);
+ } else {
+ dev_warn(mmc_dev(host->mmc), "imxmci_cmd_done: no request to finish\n");
+ }
+ }
+
+ return 1;
+}
+
+static int imxmci_data_done(struct imxmci_host *host, unsigned int stat)
+{
+ struct mmc_data *data = host->data;
+ int data_error;
+
+ if (!data)
+ return 0;
+
+ data_error = imxmci_finish_data(host, stat);
+
+ if (host->req->stop && (data_error == MMC_ERR_NONE)) {
+ imxmci_stop_clock(host);
+ imxmci_start_cmd(host, host->req->stop, 0);
+ } else {
+ struct mmc_request *req;
+ req = host->req;
+ if( req ) {
+ imxmci_finish_request(host, req);
+ } else {
+ dev_warn(mmc_dev(host->mmc), "imxmci_data_done: no request to finish\n");
+ }
+ }
+
+ return 1;
+}
+
+static int imxmci_cpu_driven_data(struct imxmci_host *host, unsigned int *pstat)
+{
+ int i;
+ int burst_len;
+ int flush_len;
+ int trans_done = 0;
+ unsigned int stat = *pstat;
+
+ if(host->actual_bus_width == MMC_BUS_WIDTH_4)
+ burst_len = 16;
+ else
+ burst_len = 64;
+
+ /* This is unfortunately required */
+ dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data running STATUS = 0x%x\n",
+ stat);
+
+ if(host->dma_dir == DMA_FROM_DEVICE) {
+ imxmci_busy_wait_for_status(host, &stat,
+ STATUS_APPL_BUFF_FF | STATUS_DATA_TRANS_DONE,
+ 20, "imxmci_cpu_driven_data read");
+
+ while((stat & (STATUS_APPL_BUFF_FF | STATUS_DATA_TRANS_DONE)) &&
+ (host->data_cnt < host->dma_size)) {
+ if(burst_len >= host->dma_size - host->data_cnt) {
+ flush_len = burst_len;
+ burst_len = host->dma_size - host->data_cnt;
+ flush_len -= burst_len;
+ host->data_cnt = host->dma_size;
+ trans_done = 1;
+ } else {
+ flush_len = 0;
+ host->data_cnt += burst_len;
+ }
+
+ for(i = burst_len; i>=2 ; i-=2) {
+ *(host->data_ptr++) = MMC_BUFFER_ACCESS;
+ udelay(20); /* required for clocks < 8MHz*/
+ }
+
+ if(i == 1)
+ *(u8*)(host->data_ptr) = MMC_BUFFER_ACCESS;
+
+ stat = MMC_STATUS;
+
+ /* Flush extra bytes from FIFO */
+ while(flush_len >= 2){
+ flush_len -= 2;
+ i = MMC_BUFFER_ACCESS;
+ stat = MMC_STATUS;
+ stat &= ~STATUS_CRC_READ_ERR; /* Stupid but required there */
+ }
+
+ dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data read burst %d STATUS = 0x%x\n",
+ burst_len, stat);
+ }
+ } else {
+ imxmci_busy_wait_for_status(host, &stat,
+ STATUS_APPL_BUFF_FE,
+ 20, "imxmci_cpu_driven_data write");
+
+ while((stat & STATUS_APPL_BUFF_FE) &&
+ (host->data_cnt < host->dma_size)) {
+ if(burst_len >= host->dma_size - host->data_cnt) {
+ burst_len = host->dma_size - host->data_cnt;
+ host->data_cnt = host->dma_size;
+ trans_done = 1;
+ } else {
+ host->data_cnt += burst_len;
+ }
+
+ for(i = burst_len; i>0 ; i-=2)
+ MMC_BUFFER_ACCESS = *(host->data_ptr++);
+
+ stat = MMC_STATUS;
+
+ dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data write burst %d STATUS = 0x%x\n",
+ burst_len, stat);
+ }
+ }
+
+ *pstat = stat;
+
+ return trans_done;
+}
+
+static void imxmci_dma_irq(int dma, void *devid, struct pt_regs *regs)
+{
+ struct imxmci_host *host = devid;
+ uint32_t stat = MMC_STATUS;
+
+ atomic_set(&host->stuck_timeout, 0);
+ host->status_reg = stat;
+ set_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events);
+ tasklet_schedule(&host->tasklet);
+}
+
+static irqreturn_t imxmci_irq(int irq, void *devid, struct pt_regs *regs)
+{
+ struct imxmci_host *host = devid;
+ uint32_t stat = MMC_STATUS;
+ int handled = 1;
+
+ MMC_INT_MASK = host->imask | INT_MASK_SDIO | INT_MASK_AUTO_CARD_DETECT;
+
+ atomic_set(&host->stuck_timeout, 0);
+ host->status_reg = stat;
+ set_bit(IMXMCI_PEND_IRQ_b, &host->pending_events);
+ tasklet_schedule(&host->tasklet);
+
+ return IRQ_RETVAL(handled);;
+}
+
+static void imxmci_tasklet_fnc(unsigned long data)
+{
+ struct imxmci_host *host = (struct imxmci_host *)data;
+ u32 stat;
+ unsigned int data_dir_mask = 0; /* STATUS_WR_CRC_ERROR_CODE_MASK */
+ int timeout = 0;
+
+ if(atomic_read(&host->stuck_timeout) > 4) {
+ char *what;
+ timeout = 1;
+ stat = MMC_STATUS;
+ host->status_reg = stat;
+ if (test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events))
+ if (test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events))
+ what = "RESP+DMA";
+ else
+ what = "RESP";
+ else
+ if (test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events))
+ if(test_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events))
+ what = "DATA";
+ else
+ what = "DMA";
+ else
+ what = "???";
+
+ dev_err(mmc_dev(host->mmc), "%s TIMEOUT, hardware stucked STATUS = 0x%04x IMASK = 0x%04x\n",
+ what, stat, MMC_INT_MASK);
+ dev_err(mmc_dev(host->mmc), "CMD_DAT_CONT = 0x%04x, MMC_BLK_LEN = 0x%04x, MMC_NOB = 0x%04x, DMA_CCR = 0x%08x\n",
+ MMC_CMD_DAT_CONT, MMC_BLK_LEN, MMC_NOB, CCR(host->dma));
+ dev_err(mmc_dev(host->mmc), "CMD%d, bus %d-bit, dma_size = 0x%x\n",
+ host->cmd?host->cmd->opcode:0, 1<<host->actual_bus_width, host->dma_size);
+ }
+
+ if(!host->present || timeout)
+ host->status_reg = STATUS_TIME_OUT_RESP | STATUS_TIME_OUT_READ |
+ STATUS_CRC_READ_ERR | STATUS_CRC_WRITE_ERR;
+
+ if(test_bit(IMXMCI_PEND_IRQ_b, &host->pending_events) || timeout) {
+ clear_bit(IMXMCI_PEND_IRQ_b, &host->pending_events);
+
+ stat = MMC_STATUS;
+ /*
+ * This is not required in theory, but there is chance to miss some flag
+ * which clears automatically by mask write, FreeScale original code keeps
+ * stat from IRQ time so do I
+ */
+ stat |= host->status_reg;
+
+ if(test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events)) {
+ imxmci_busy_wait_for_status(host, &stat,
+ STATUS_END_CMD_RESP | STATUS_ERR_MASK,
+ 20, "imxmci_tasklet_fnc resp (ERRATUM #4)");
+ }
+
+ if(stat & (STATUS_END_CMD_RESP | STATUS_ERR_MASK)) {
+ if(test_and_clear_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events))
+ imxmci_cmd_done(host, stat);
+ if(host->data && (stat & STATUS_ERR_MASK))
+ imxmci_data_done(host, stat);
+ }
+
+ if(test_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events)) {
+ stat |= MMC_STATUS;
+ if(imxmci_cpu_driven_data(host, &stat)){
+ if(test_and_clear_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events))
+ imxmci_cmd_done(host, stat);
+ atomic_clear_mask(IMXMCI_PEND_IRQ_m|IMXMCI_PEND_CPU_DATA_m,
+ &host->pending_events);
+ imxmci_data_done(host, stat);
+ }
+ }
+ }
+
+ if(test_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events) &&
+ !test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events)) {
+
+ stat = MMC_STATUS;
+ /* Same as above */
+ stat |= host->status_reg;
+
+ if(host->dma_dir == DMA_TO_DEVICE) {
+ data_dir_mask = STATUS_WRITE_OP_DONE;
+ } else {
+ data_dir_mask = STATUS_DATA_TRANS_DONE;
+ }
+
+ imxmci_busy_wait_for_status(host, &stat,
+ data_dir_mask,
+ 50, "imxmci_tasklet_fnc data");
+
+ if(stat & data_dir_mask) {
+ clear_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events);
+ imxmci_data_done(host, stat);
+ }
+ }
+
+ if(test_and_clear_bit(IMXMCI_PEND_CARD_XCHG_b, &host->pending_events)) {
+
+ if(host->cmd)
+ imxmci_cmd_done(host, STATUS_TIME_OUT_RESP);
+
+ if(host->data)
+ imxmci_data_done(host, STATUS_TIME_OUT_READ |
+ STATUS_CRC_READ_ERR | STATUS_CRC_WRITE_ERR);
+
+ if(host->req)
+ imxmci_finish_request(host, host->req);
+
+ mmc_detect_change(host->mmc, msecs_to_jiffies(100));
+
+ }
+}
+
+static void imxmci_request(struct mmc_host *mmc, struct mmc_request *req)
+{
+ struct imxmci_host *host = mmc_priv(mmc);
+ unsigned int cmdat;
+
+ WARN_ON(host->req != NULL);
+
+ host->req = req;
+
+ cmdat = 0;
+
+ if (req->data) {
+ imxmci_setup_data(host, req->data);
+
+ cmdat |= CMD_DAT_CONT_DATA_ENABLE;
+
+ if (req->data->flags & MMC_DATA_WRITE)
+ cmdat |= CMD_DAT_CONT_WRITE;
+
+ if (req->data->flags & MMC_DATA_STREAM) {
+ cmdat |= CMD_DAT_CONT_STREAM_BLOCK;
+ }
+ }
+
+ imxmci_start_cmd(host, req->cmd, cmdat);
+}
+
+#define CLK_RATE 19200000
+
+static void imxmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ struct imxmci_host *host = mmc_priv(mmc);
+ int prescaler;
+
+ dev_dbg(mmc_dev(host->mmc), "clock %u power %u vdd %u width %u\n",
+ ios->clock, ios->power_mode, ios->vdd,
+ (ios->bus_width==MMC_BUS_WIDTH_4)?4:1);
+
+ if( ios->bus_width==MMC_BUS_WIDTH_4 ) {
+ host->actual_bus_width = MMC_BUS_WIDTH_4;
+ imx_gpio_mode(PB11_PF_SD_DAT3);
+ }else{
+ host->actual_bus_width = MMC_BUS_WIDTH_1;
+ imx_gpio_mode(GPIO_PORTB | GPIO_IN | GPIO_PUEN | 11);
+ }
+
+ if ( host->power_mode != ios->power_mode ) {
+ switch (ios->power_mode) {
+ case MMC_POWER_OFF:
+ break;
+ case MMC_POWER_UP:
+ set_bit(IMXMCI_PEND_SET_INIT_b, &host->pending_events);
+ break;
+ case MMC_POWER_ON:
+ break;
+ }
+ host->power_mode = ios->power_mode;
+ }
+
+ if ( ios->clock ) {
+ unsigned int clk;
+
+ /* The prescaler is 5 for PERCLK2 equal to 96MHz
+ * then 96MHz / 5 = 19.2 MHz
+ */
+ clk=imx_get_perclk2();
+ prescaler=(clk+(CLK_RATE*7)/8)/CLK_RATE;
+ switch(prescaler) {
+ case 0:
+ case 1: prescaler = 0;
+ break;
+ case 2: prescaler = 1;
+ break;
+ case 3: prescaler = 2;
+ break;
+ case 4: prescaler = 4;
+ break;
+ default:
+ case 5: prescaler = 5;
+ break;
+ }
+
+ dev_dbg(mmc_dev(host->mmc), "PERCLK2 %d MHz -> prescaler %d\n",
+ clk, prescaler);
+
+ for(clk=0; clk<8; clk++) {
+ int x;
+ x = CLK_RATE / (1<<clk);
+ if( x <= ios->clock)
+ break;
+ }
+
+ MMC_STR_STP_CLK |= STR_STP_CLK_ENABLE; /* enable controller */
+
+ imxmci_stop_clock(host);
+ MMC_CLK_RATE = (prescaler<<3) | clk;
+ imxmci_start_clock(host);
+
+ dev_dbg(mmc_dev(host->mmc), "MMC_CLK_RATE: 0x%08x\n", MMC_CLK_RATE);
+ } else {
+ imxmci_stop_clock(host);
+ }
+}
+
+static struct mmc_host_ops imxmci_ops = {
+ .request = imxmci_request,
+ .set_ios = imxmci_set_ios,
+};
+
+static struct resource *platform_device_resource(struct platform_device *dev, unsigned int mask, int nr)
+{
+ int i;
+
+ for (i = 0; i < dev->num_resources; i++)
+ if (dev->resource[i].flags == mask && nr-- == 0)
+ return &dev->resource[i];
+ return NULL;
+}
+
+static int platform_device_irq(struct platform_device *dev, int nr)
+{
+ int i;
+
+ for (i = 0; i < dev->num_resources; i++)
+ if (dev->resource[i].flags == IORESOURCE_IRQ && nr-- == 0)
+ return dev->resource[i].start;
+ return NO_IRQ;
+}
+
+static void imxmci_check_status(unsigned long data)
+{
+ struct imxmci_host *host = (struct imxmci_host *)data;
+
+ if( host->pdata->card_present() != host->present ) {
+ host->present ^= 1;
+ dev_info(mmc_dev(host->mmc), "card %s\n",
+ host->present ? "inserted" : "removed");
+
+ set_bit(IMXMCI_PEND_CARD_XCHG_b, &host->pending_events);
+ tasklet_schedule(&host->tasklet);
+ }
+
+ if(test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events) ||
+ test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events)) {
+ atomic_inc(&host->stuck_timeout);
+ if(atomic_read(&host->stuck_timeout) > 4)
+ tasklet_schedule(&host->tasklet);
+ } else {
+ atomic_set(&host->stuck_timeout, 0);
+
+ }
+
+ mod_timer(&host->timer, jiffies + (HZ>>1));
+}
+
+static int imxmci_probe(struct platform_device *pdev)
+{
+ struct mmc_host *mmc;
+ struct imxmci_host *host = NULL;
+ struct resource *r;
+ int ret = 0, irq;
+
+ printk(KERN_INFO "i.MX mmc driver\n");
+
+ r = platform_device_resource(pdev, IORESOURCE_MEM, 0);
+ irq = platform_device_irq(pdev, 0);
+ if (!r || irq == NO_IRQ)
+ return -ENXIO;
+
+ r = request_mem_region(r->start, 0x100, "IMXMCI");
+ if (!r)
+ return -EBUSY;
+
+ mmc = mmc_alloc_host(sizeof(struct imxmci_host), &pdev->dev);
+ if (!mmc) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ mmc->ops = &imxmci_ops;
+ mmc->f_min = 150000;
+ mmc->f_max = CLK_RATE/2;
+ mmc->ocr_avail = MMC_VDD_32_33;
+ mmc->caps |= MMC_CAP_4_BIT_DATA;
+
+ /* MMC core transfer sizes tunable parameters */
+ mmc->max_hw_segs = 64;
+ mmc->max_phys_segs = 64;
+ mmc->max_sectors = 64; /* default 1 << (PAGE_CACHE_SHIFT - 9) */
+ mmc->max_seg_size = 64*512; /* default PAGE_CACHE_SIZE */
+
+ host = mmc_priv(mmc);
+ host->mmc = mmc;
+ host->dma_allocated = 0;
+ host->pdata = pdev->dev.platform_data;
+
+ spin_lock_init(&host->lock);
+ host->res = r;
+ host->irq = irq;
+
+ imx_gpio_mode(PB8_PF_SD_DAT0);
+ imx_gpio_mode(PB9_PF_SD_DAT1);
+ imx_gpio_mode(PB10_PF_SD_DAT2);
+ /* Configured as GPIO with pull-up to ensure right MCC card mode */
+ /* Switched to PB11_PF_SD_DAT3 if 4 bit bus is configured */
+ imx_gpio_mode(GPIO_PORTB | GPIO_IN | GPIO_PUEN | 11);
+ /* imx_gpio_mode(PB11_PF_SD_DAT3); */
+ imx_gpio_mode(PB12_PF_SD_CLK);
+ imx_gpio_mode(PB13_PF_SD_CMD);
+
+ imxmci_softreset();
+
+ if ( MMC_REV_NO != 0x390 ) {
+ dev_err(mmc_dev(host->mmc), "wrong rev.no. 0x%08x. aborting.\n",
+ MMC_REV_NO);
+ goto out;
+ }
+
+ MMC_READ_TO = 0x2db4; /* recommended in data sheet */
+
+ host->imask = IMXMCI_INT_MASK_DEFAULT;
+ MMC_INT_MASK = host->imask;
+
+
+ if(imx_dma_request_by_prio(&host->dma, DRIVER_NAME, DMA_PRIO_LOW)<0){
+ dev_err(mmc_dev(host->mmc), "imx_dma_request_by_prio failed\n");
+ ret = -EBUSY;
+ goto out;
+ }
+ host->dma_allocated=1;
+ imx_dma_setup_handlers(host->dma, imxmci_dma_irq, NULL, host);
+
+ tasklet_init(&host->tasklet, imxmci_tasklet_fnc, (unsigned long)host);
+ host->status_reg=0;
+ host->pending_events=0;
+
+ ret = request_irq(host->irq, imxmci_irq, 0, DRIVER_NAME, host);
+ if (ret)
+ goto out;
+
+ host->present = host->pdata->card_present();
+ init_timer(&host->timer);
+ host->timer.data = (unsigned long)host;
+ host->timer.function = imxmci_check_status;
+ add_timer(&host->timer);
+ mod_timer(&host->timer, jiffies + (HZ>>1));
+
+ platform_set_drvdata(pdev, mmc);
+
+ mmc_add_host(mmc);
+
+ return 0;
+
+out:
+ if (host) {
+ if(host->dma_allocated){
+ imx_dma_free(host->dma);
+ host->dma_allocated=0;
+ }
+ }
+ if (mmc)
+ mmc_free_host(mmc);
+ release_resource(r);
+ return ret;
+}
+
+static int imxmci_remove(struct platform_device *pdev)
+{
+ struct mmc_host *mmc = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+
+ if (mmc) {
+ struct imxmci_host *host = mmc_priv(mmc);
+
+ tasklet_disable(&host->tasklet);
+
+ del_timer_sync(&host->timer);
+ mmc_remove_host(mmc);
+
+ free_irq(host->irq, host);
+ if(host->dma_allocated){
+ imx_dma_free(host->dma);
+ host->dma_allocated=0;
+ }
+
+ tasklet_kill(&host->tasklet);
+
+ release_resource(host->res);
+
+ mmc_free_host(mmc);
+ }
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int imxmci_suspend(struct platform_device *dev, pm_message_t state)
+{
+ struct mmc_host *mmc = platform_get_drvdata(dev);
+ int ret = 0;
+
+ if (mmc)
+ ret = mmc_suspend_host(mmc, state);
+
+ return ret;
+}
+
+static int imxmci_resume(struct platform_device *dev)
+{
+ struct mmc_host *mmc = platform_get_drvdata(dev);
+ struct imxmci_host *host;
+ int ret = 0;
+
+ if (mmc) {
+ host = mmc_priv(mmc);
+ if(host)
+ set_bit(IMXMCI_PEND_SET_INIT_b, &host->pending_events);
+ ret = mmc_resume_host(mmc);
+ }
+
+ return ret;
+}
+#else
+#define imxmci_suspend NULL
+#define imxmci_resume NULL
+#endif /* CONFIG_PM */
+
+static struct platform_driver imxmci_driver = {
+ .probe = imxmci_probe,
+ .remove = imxmci_remove,
+ .suspend = imxmci_suspend,
+ .resume = imxmci_resume,
+ .driver = {
+ .name = DRIVER_NAME,
+ }
+};
+
+static int __init imxmci_init(void)
+{
+ return platform_driver_register(&imxmci_driver);
+}
+
+static void __exit imxmci_exit(void)
+{
+ platform_driver_unregister(&imxmci_driver);
+}
+
+module_init(imxmci_init);
+module_exit(imxmci_exit);
+
+MODULE_DESCRIPTION("i.MX Multimedia Card Interface Driver");
+MODULE_AUTHOR("Sascha Hauer, Pengutronix");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/imxmmc.h b/drivers/mmc/imxmmc.h
new file mode 100644
index 00000000000..e5339e334db
--- /dev/null
+++ b/drivers/mmc/imxmmc.h
@@ -0,0 +1,67 @@
+
+# define __REG16(x) (*((volatile u16 *)IO_ADDRESS(x)))
+
+#define MMC_STR_STP_CLK __REG16(IMX_MMC_BASE + 0x00)
+#define MMC_STATUS __REG16(IMX_MMC_BASE + 0x04)
+#define MMC_CLK_RATE __REG16(IMX_MMC_BASE + 0x08)
+#define MMC_CMD_DAT_CONT __REG16(IMX_MMC_BASE + 0x0C)
+#define MMC_RES_TO __REG16(IMX_MMC_BASE + 0x10)
+#define MMC_READ_TO __REG16(IMX_MMC_BASE + 0x14)
+#define MMC_BLK_LEN __REG16(IMX_MMC_BASE + 0x18)
+#define MMC_NOB __REG16(IMX_MMC_BASE + 0x1C)
+#define MMC_REV_NO __REG16(IMX_MMC_BASE + 0x20)
+#define MMC_INT_MASK __REG16(IMX_MMC_BASE + 0x24)
+#define MMC_CMD __REG16(IMX_MMC_BASE + 0x28)
+#define MMC_ARGH __REG16(IMX_MMC_BASE + 0x2C)
+#define MMC_ARGL __REG16(IMX_MMC_BASE + 0x30)
+#define MMC_RES_FIFO __REG16(IMX_MMC_BASE + 0x34)
+#define MMC_BUFFER_ACCESS __REG16(IMX_MMC_BASE + 0x38)
+#define MMC_BUFFER_ACCESS_OFS 0x38
+
+
+#define STR_STP_CLK_ENDIAN (1<<5)
+#define STR_STP_CLK_RESET (1<<3)
+#define STR_STP_CLK_ENABLE (1<<2)
+#define STR_STP_CLK_START_CLK (1<<1)
+#define STR_STP_CLK_STOP_CLK (1<<0)
+#define STATUS_CARD_PRESENCE (1<<15)
+#define STATUS_SDIO_INT_ACTIVE (1<<14)
+#define STATUS_END_CMD_RESP (1<<13)
+#define STATUS_WRITE_OP_DONE (1<<12)
+#define STATUS_DATA_TRANS_DONE (1<<11)
+#define STATUS_WR_CRC_ERROR_CODE_MASK (3<<10)
+#define STATUS_CARD_BUS_CLK_RUN (1<<8)
+#define STATUS_APPL_BUFF_FF (1<<7)
+#define STATUS_APPL_BUFF_FE (1<<6)
+#define STATUS_RESP_CRC_ERR (1<<5)
+#define STATUS_CRC_READ_ERR (1<<3)
+#define STATUS_CRC_WRITE_ERR (1<<2)
+#define STATUS_TIME_OUT_RESP (1<<1)
+#define STATUS_TIME_OUT_READ (1<<0)
+#define STATUS_ERR_MASK 0x2f
+#define CLK_RATE_PRESCALER(x) ((x) & 0x7)
+#define CLK_RATE_CLK_RATE(x) (((x) & 0x7) << 3)
+#define CMD_DAT_CONT_CMD_RESP_LONG_OFF (1<<12)
+#define CMD_DAT_CONT_STOP_READWAIT (1<<11)
+#define CMD_DAT_CONT_START_READWAIT (1<<10)
+#define CMD_DAT_CONT_BUS_WIDTH_1 (0<<8)
+#define CMD_DAT_CONT_BUS_WIDTH_4 (2<<8)
+#define CMD_DAT_CONT_INIT (1<<7)
+#define CMD_DAT_CONT_BUSY (1<<6)
+#define CMD_DAT_CONT_STREAM_BLOCK (1<<5)
+#define CMD_DAT_CONT_WRITE (1<<4)
+#define CMD_DAT_CONT_DATA_ENABLE (1<<3)
+#define CMD_DAT_CONT_RESPONSE_FORMAT_R1 (1)
+#define CMD_DAT_CONT_RESPONSE_FORMAT_R2 (2)
+#define CMD_DAT_CONT_RESPONSE_FORMAT_R3 (3)
+#define CMD_DAT_CONT_RESPONSE_FORMAT_R4 (4)
+#define CMD_DAT_CONT_RESPONSE_FORMAT_R5 (5)
+#define CMD_DAT_CONT_RESPONSE_FORMAT_R6 (6)
+#define INT_MASK_AUTO_CARD_DETECT (1<<6)
+#define INT_MASK_DAT0_EN (1<<5)
+#define INT_MASK_SDIO (1<<4)
+#define INT_MASK_BUF_READY (1<<3)
+#define INT_MASK_END_CMD_RES (1<<2)
+#define INT_MASK_WRITE_OP_DONE (1<<1)
+#define INT_MASK_DATA_TRAN (1<<0)
+#define INT_ALL (0x7f)
diff --git a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig
index 0f6bb2e625d..a7ec5954caf 100644
--- a/drivers/mtd/chips/Kconfig
+++ b/drivers/mtd/chips/Kconfig
@@ -200,27 +200,6 @@ config MTD_CFI_AMDSTD
provides support for one of those command sets, used on chips
including the AMD Am29LV320.
-config MTD_CFI_AMDSTD_RETRY
- int "Retry failed commands (erase/program)"
- depends on MTD_CFI_AMDSTD
- default "0"
- help
- Some chips, when attached to a shared bus, don't properly filter
- bus traffic that is destined to other devices. This broken
- behavior causes erase and program sequences to be aborted when
- the sequences are mixed with traffic for other devices.
-
- SST49LF040 (and related) chips are know to be broken.
-
-config MTD_CFI_AMDSTD_RETRY_MAX
- int "Max retries of failed commands (erase/program)"
- depends on MTD_CFI_AMDSTD_RETRY
- default "0"
- help
- If you have an SST49LF040 (or related chip) then this value should
- be set to at least 1. This can also be adjusted at driver load
- time with the retry_cmd_max module parameter.
-
config MTD_CFI_STAA
tristate "Support for ST (Advanced Architecture) flash chips"
depends on MTD_GEN_PROBE
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
index ce99845d826..066e22b01a9 100644
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -539,8 +539,7 @@ rx_status_loop:
unsigned buflen;
skb = cp->rx_skb[rx_tail].skb;
- if (!skb)
- BUG();
+ BUG_ON(!skb);
desc = &cp->rx_ring[rx_tail];
status = le32_to_cpu(desc->opts1);
@@ -723,8 +722,7 @@ static void cp_tx (struct cp_private *cp)
break;
skb = cp->tx_skb[tx_tail].skb;
- if (!skb)
- BUG();
+ BUG_ON(!skb);
pci_unmap_single(cp->pdev, cp->tx_skb[tx_tail].mapping,
cp->tx_skb[tx_tail].len, PCI_DMA_TODEVICE);
@@ -1550,8 +1548,7 @@ static void cp_get_ethtool_stats (struct net_device *dev,
tmp_stats[i++] = le16_to_cpu(nic_stats->tx_abort);
tmp_stats[i++] = le16_to_cpu(nic_stats->tx_underrun);
tmp_stats[i++] = cp->cp_stats.rx_frags;
- if (i != CP_NUM_STATS)
- BUG();
+ BUG_ON(i != CP_NUM_STATS);
pci_free_consistent(cp->pdev, sizeof(*nic_stats), nic_stats, dma);
}
@@ -1856,8 +1853,7 @@ static void cp_remove_one (struct pci_dev *pdev)
struct net_device *dev = pci_get_drvdata(pdev);
struct cp_private *cp = netdev_priv(dev);
- if (!dev)
- BUG();
+ BUG_ON(!dev);
unregister_netdev(dev);
iounmap(cp->regs);
if (cp->wol_enabled) pci_set_power_state (pdev, PCI_D0);
diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c
index 64e2caf3083..fabc0607b0f 100644
--- a/drivers/net/arcnet/arcnet.c
+++ b/drivers/net/arcnet/arcnet.c
@@ -765,8 +765,7 @@ irqreturn_t arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs)
BUGMSG(D_DURING, "in arcnet_interrupt\n");
lp = dev->priv;
- if (!lp)
- BUG();
+ BUG_ON(!lp);
spin_lock(&lp->lock);
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index 15032f2c781..c4e12b5cbb9 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -608,8 +608,7 @@ static void b44_tx(struct b44 *bp)
struct ring_info *rp = &bp->tx_buffers[cons];
struct sk_buff *skb = rp->skb;
- if (unlikely(skb == NULL))
- BUG();
+ BUG_ON(skb == NULL);
pci_unmap_single(bp->pdev,
pci_unmap_addr(rp, mapping),
diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c
index 30ff8ea1a40..4391bf4bf57 100644
--- a/drivers/net/chelsio/sge.c
+++ b/drivers/net/chelsio/sge.c
@@ -1093,8 +1093,7 @@ static int process_responses(struct adapter *adapter, int budget)
if (likely(e->DataValid)) {
struct freelQ *fl = &sge->freelQ[e->FreelistQid];
- if (unlikely(!e->Sop || !e->Eop))
- BUG();
+ BUG_ON(!e->Sop || !e->Eop);
if (unlikely(e->Offload))
unexpected_offload(adapter, fl);
else
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index 49cd096a3c3..add8dc4aa7b 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -3308,8 +3308,7 @@ e1000_clean(struct net_device *poll_dev, int *budget)
while (poll_dev != &adapter->polling_netdev[i]) {
i++;
- if (unlikely(i == adapter->num_rx_queues))
- BUG();
+ BUG_ON(i == adapter->num_rx_queues);
}
if (likely(adapter->num_tx_queues == 1)) {
diff --git a/drivers/net/eql.c b/drivers/net/eql.c
index aa1569182fd..815436c6170 100644
--- a/drivers/net/eql.c
+++ b/drivers/net/eql.c
@@ -203,8 +203,7 @@ static int eql_open(struct net_device *dev)
printk(KERN_INFO "%s: remember to turn off Van-Jacobson compression on "
"your slave devices.\n", dev->name);
- if (!list_empty(&eql->queue.all_slaves))
- BUG();
+ BUG_ON(!list_empty(&eql->queue.all_slaves));
eql->min_slaves = 1;
eql->max_slaves = EQL_DEFAULT_MAX_SLAVES; /* 4 usually... */
diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c
index 63d38fbbd04..f530686bd09 100644
--- a/drivers/net/irda/sa1100_ir.c
+++ b/drivers/net/irda/sa1100_ir.c
@@ -695,8 +695,7 @@ static int sa1100_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
/*
* We must not be transmitting...
*/
- if (si->txskb)
- BUG();
+ BUG_ON(si->txskb);
netif_stop_queue(dev);
diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c
index d11821dd86e..ced9fdb8335 100644
--- a/drivers/net/ne2k-pci.c
+++ b/drivers/net/ne2k-pci.c
@@ -645,9 +645,7 @@ static void __devexit ne2k_pci_remove_one (struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
- if (!dev)
- BUG();
-
+ BUG_ON(!dev);
unregister_netdev(dev);
release_region(dev->base_addr, NE_IO_EXTENT);
free_netdev(dev);
diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c
index 8e9b1a537de..706aed7d717 100644
--- a/drivers/net/ns83820.c
+++ b/drivers/net/ns83820.c
@@ -568,8 +568,7 @@ static inline int ns83820_add_rx_skb(struct ns83820 *dev, struct sk_buff *skb)
#endif
sg = dev->rx_info.descs + (next_empty * DESC_SIZE);
- if (unlikely(NULL != dev->rx_info.skbs[next_empty]))
- BUG();
+ BUG_ON(NULL != dev->rx_info.skbs[next_empty]);
dev->rx_info.skbs[next_empty] = skb;
dev->rx_info.next_empty = (next_empty + 1) % NR_RX_DESC;
diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c
index 35b18057fbd..45ad036733e 100644
--- a/drivers/net/starfire.c
+++ b/drivers/net/starfire.c
@@ -2122,8 +2122,7 @@ static void __devexit starfire_remove_one (struct pci_dev *pdev)
struct net_device *dev = pci_get_drvdata(pdev);
struct netdev_private *np = netdev_priv(dev);
- if (!dev)
- BUG();
+ BUG_ON(!dev);
unregister_netdev(dev);
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 770e6b6cec6..0b535807217 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -2959,9 +2959,7 @@ static void tg3_tx(struct tg3 *tp)
struct sk_buff *skb = ri->skb;
int i;
- if (unlikely(skb == NULL))
- BUG();
-
+ BUG_ON(skb == NULL);
pci_unmap_single(tp->pdev,
pci_unmap_addr(ri, mapping),
skb_headlen(skb),
@@ -2972,12 +2970,10 @@ static void tg3_tx(struct tg3 *tp)
sw_idx = NEXT_TX(sw_idx);
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- if (unlikely(sw_idx == hw_idx))
- BUG();
+ BUG_ON(sw_idx == hw_idx);
ri = &tp->tx_buffers[sw_idx];
- if (unlikely(ri->skb != NULL))
- BUG();
+ BUG_ON(ri->skb != NULL);
pci_unmap_page(tp->pdev,
pci_unmap_addr(ri, mapping),
@@ -4928,9 +4924,8 @@ static int tg3_halt_cpu(struct tg3 *tp, u32 offset)
{
int i;
- if (offset == TX_CPU_BASE &&
- (tp->tg3_flags2 & TG3_FLG2_5705_PLUS))
- BUG();
+ BUG_ON(offset == TX_CPU_BASE &&
+ (tp->tg3_flags2 & TG3_FLG2_5705_PLUS));
if (offset == RX_CPU_BASE) {
for (i = 0; i < 10000; i++) {
diff --git a/drivers/net/tokenring/abyss.c b/drivers/net/tokenring/abyss.c
index 9345e68c451..649d8ea354f 100644
--- a/drivers/net/tokenring/abyss.c
+++ b/drivers/net/tokenring/abyss.c
@@ -438,8 +438,7 @@ static void __devexit abyss_detach (struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
- if (!dev)
- BUG();
+ BUG_ON(!dev);
unregister_netdev(dev);
release_region(dev->base_addr-0x10, ABYSS_IO_EXTENT);
free_irq(dev->irq, dev);
diff --git a/drivers/net/tokenring/madgemc.c b/drivers/net/tokenring/madgemc.c
index 3a25d191ea4..19e6f4dfd69 100644
--- a/drivers/net/tokenring/madgemc.c
+++ b/drivers/net/tokenring/madgemc.c
@@ -735,8 +735,7 @@ static int __devexit madgemc_remove(struct device *device)
struct net_local *tp;
struct card_info *card;
- if (!dev)
- BUG();
+ BUG_ON(!dev);
tp = dev->priv;
card = tp->tmspriv;
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c
index 9dce522526c..bca89cff85a 100644
--- a/drivers/net/wireless/ipw2200.c
+++ b/drivers/net/wireless/ipw2200.c
@@ -5573,8 +5573,7 @@ static void ipw_adhoc_create(struct ipw_priv *priv,
case IEEE80211_52GHZ_BAND:
network->mode = IEEE_A;
i = ieee80211_channel_to_index(priv->ieee, priv->channel);
- if (i == -1)
- BUG();
+ BUG_ON(i == -1);
if (geo->a[i].flags & IEEE80211_CH_PASSIVE_ONLY) {
IPW_WARNING("Overriding invalid channel\n");
priv->channel = geo->a[0].channel;
@@ -5587,8 +5586,7 @@ static void ipw_adhoc_create(struct ipw_priv *priv,
else
network->mode = IEEE_B;
i = ieee80211_channel_to_index(priv->ieee, priv->channel);
- if (i == -1)
- BUG();
+ BUG_ON(i == -1);
if (geo->bg[i].flags & IEEE80211_CH_PASSIVE_ONLY) {
IPW_WARNING("Overriding invalid channel\n");
priv->channel = geo->bg[0].channel;
@@ -6715,8 +6713,7 @@ static int ipw_qos_association(struct ipw_priv *priv,
switch (priv->ieee->iw_mode) {
case IW_MODE_ADHOC:
- if (!(network->capability & WLAN_CAPABILITY_IBSS))
- BUG();
+ BUG_ON(!(network->capability & WLAN_CAPABILITY_IBSS));
qos_data = &ibss_data;
break;
diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c
index 75d56bfef0e..fd0f43b7db5 100644
--- a/drivers/net/yellowfin.c
+++ b/drivers/net/yellowfin.c
@@ -1441,8 +1441,7 @@ static void __devexit yellowfin_remove_one (struct pci_dev *pdev)
struct net_device *dev = pci_get_drvdata(pdev);
struct yellowfin_private *np;
- if (!dev)
- BUG();
+ BUG_ON(!dev);
np = netdev_priv(dev);
pci_free_consistent(pdev, STATUS_TOTAL_SIZE, np->tx_status,
diff --git a/drivers/s390/block/dasd_erp.c b/drivers/s390/block/dasd_erp.c
index 8fd71ab02ef..b842377cb0c 100644
--- a/drivers/s390/block/dasd_erp.c
+++ b/drivers/s390/block/dasd_erp.c
@@ -32,9 +32,8 @@ dasd_alloc_erp_request(char *magic, int cplength, int datasize,
int size;
/* Sanity checks */
- if ( magic == NULL || datasize > PAGE_SIZE ||
- (cplength*sizeof(struct ccw1)) > PAGE_SIZE)
- BUG();
+ BUG_ON( magic == NULL || datasize > PAGE_SIZE ||
+ (cplength*sizeof(struct ccw1)) > PAGE_SIZE);
size = (sizeof(struct dasd_ccw_req) + 7L) & -8L;
if (cplength > 0)
@@ -125,8 +124,7 @@ dasd_default_erp_postaction(struct dasd_ccw_req * cqr)
struct dasd_device *device;
int success;
- if (cqr->refers == NULL || cqr->function == NULL)
- BUG();
+ BUG_ON(cqr->refers == NULL || cqr->function == NULL);
device = cqr->device;
success = cqr->status == DASD_CQR_DONE;
diff --git a/drivers/s390/char/sclp_rw.c b/drivers/s390/char/sclp_rw.c
index ac10dfb20a6..91e93c78f57 100644
--- a/drivers/s390/char/sclp_rw.c
+++ b/drivers/s390/char/sclp_rw.c
@@ -24,7 +24,7 @@
/*
* The room for the SCCB (only for writing) is not equal to a pages size
- * (as it is specified as the maximum size in the the SCLP ducumentation)
+ * (as it is specified as the maximum size in the the SCLP documentation)
* because of the additional data structure described above.
*/
#define MAX_SCCB_ROOM (PAGE_SIZE - sizeof(struct sclp_buffer))
diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c
index 5ced2725d6c..5c65cf3e5cc 100644
--- a/drivers/s390/char/tape_block.c
+++ b/drivers/s390/char/tape_block.c
@@ -198,9 +198,7 @@ tapeblock_request_fn(request_queue_t *queue)
device = (struct tape_device *) queue->queuedata;
DBF_LH(6, "tapeblock_request_fn(device=%p)\n", device);
- if (device == NULL)
- BUG();
-
+ BUG_ON(device == NULL);
tapeblock_trigger_requeue(device);
}
@@ -307,8 +305,7 @@ tapeblock_revalidate_disk(struct gendisk *disk)
int rc;
device = (struct tape_device *) disk->private_data;
- if (!device)
- BUG();
+ BUG_ON(!device);
if (!device->blk_data.medium_changed)
return 0;
@@ -440,11 +437,9 @@ tapeblock_ioctl(
rc = 0;
disk = inode->i_bdev->bd_disk;
- if (!disk)
- BUG();
+ BUG_ON(!disk);
device = disk->private_data;
- if (!device)
- BUG();
+ BUG_ON(!device);
minor = iminor(inode);
DBF_LH(6, "tapeblock_ioctl(0x%0x)\n", command);
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c
index edcf05d5d56..5d6b7a57b02 100644
--- a/drivers/s390/net/lcs.c
+++ b/drivers/s390/net/lcs.c
@@ -675,9 +675,8 @@ lcs_ready_buffer(struct lcs_channel *channel, struct lcs_buffer *buffer)
int index, rc;
LCS_DBF_TEXT(5, trace, "rdybuff");
- if (buffer->state != BUF_STATE_LOCKED &&
- buffer->state != BUF_STATE_PROCESSED)
- BUG();
+ BUG_ON(buffer->state != BUF_STATE_LOCKED &&
+ buffer->state != BUF_STATE_PROCESSED);
spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
buffer->state = BUF_STATE_READY;
index = buffer - channel->iob;
@@ -701,8 +700,7 @@ __lcs_processed_buffer(struct lcs_channel *channel, struct lcs_buffer *buffer)
int index, prev, next;
LCS_DBF_TEXT(5, trace, "prcsbuff");
- if (buffer->state != BUF_STATE_READY)
- BUG();
+ BUG_ON(buffer->state != BUF_STATE_READY);
buffer->state = BUF_STATE_PROCESSED;
index = buffer - channel->iob;
prev = (index - 1) & (LCS_NUM_BUFFS - 1);
@@ -734,9 +732,8 @@ lcs_release_buffer(struct lcs_channel *channel, struct lcs_buffer *buffer)
unsigned long flags;
LCS_DBF_TEXT(5, trace, "relbuff");
- if (buffer->state != BUF_STATE_LOCKED &&
- buffer->state != BUF_STATE_PROCESSED)
- BUG();
+ BUG_ON(buffer->state != BUF_STATE_LOCKED &&
+ buffer->state != BUF_STATE_PROCESSED);
spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
buffer->state = BUF_STATE_EMPTY;
spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
diff --git a/drivers/scsi/aic7xxx/Kconfig.aic7xxx b/drivers/scsi/aic7xxx/Kconfig.aic7xxx
index 6c2c395554f..5517da5855f 100644
--- a/drivers/scsi/aic7xxx/Kconfig.aic7xxx
+++ b/drivers/scsi/aic7xxx/Kconfig.aic7xxx
@@ -86,7 +86,7 @@ config AIC7XXX_DEBUG_MASK
default "0"
help
Bit mask of debug options that is only valid if the
- CONFIG_AIC7XXX_DEBUG_ENBLE option is enabled. The bits in this mask
+ CONFIG_AIC7XXX_DEBUG_ENABLE option is enabled. The bits in this mask
are defined in the drivers/scsi/aic7xxx/aic7xxx.h - search for the
variable ahc_debug in that file to find them.
diff --git a/drivers/serial/jsm/jsm.h b/drivers/serial/jsm/jsm.h
index dfc1e86d3aa..043f50b1d10 100644
--- a/drivers/serial/jsm/jsm.h
+++ b/drivers/serial/jsm/jsm.h
@@ -20,7 +20,7 @@
*
* Contact Information:
* Scott H Kilau <Scott_Kilau@digi.com>
- * Wendy Xiong <wendyx@us.ltcfwd.linux.ibm.com>
+ * Wendy Xiong <wendyx@us.ibm.com>
*
***********************************************************************/
diff --git a/drivers/serial/jsm/jsm_driver.c b/drivers/serial/jsm/jsm_driver.c
index b1b66e71d28..b3e1f71be4d 100644
--- a/drivers/serial/jsm/jsm_driver.c
+++ b/drivers/serial/jsm/jsm_driver.c
@@ -20,7 +20,7 @@
*
* Contact Information:
* Scott H Kilau <Scott_Kilau@digi.com>
- * Wendy Xiong <wendyx@us.ltcfwd.linux.ibm.com>
+ * Wendy Xiong <wendyx@us.ibm.com>
*
*
***********************************************************************/
diff --git a/drivers/serial/jsm/jsm_neo.c b/drivers/serial/jsm/jsm_neo.c
index 87e4e2cf8ce..a5fc589d6ef 100644
--- a/drivers/serial/jsm/jsm_neo.c
+++ b/drivers/serial/jsm/jsm_neo.c
@@ -20,7 +20,7 @@
*
* Contact Information:
* Scott H Kilau <Scott_Kilau@digi.com>
- * Wendy Xiong <wendyx@us.ltcfwd.linux.ibm.com>
+ * Wendy Xiong <wendyx@us.ibm.com>
*
***********************************************************************/
#include <linux/delay.h> /* For udelay */
diff --git a/fs/direct-io.c b/fs/direct-io.c
index 910a8ed74b5..b05d1b21877 100644
--- a/fs/direct-io.c
+++ b/fs/direct-io.c
@@ -929,8 +929,7 @@ do_holes:
block_in_page += this_chunk_blocks;
dio->blocks_available -= this_chunk_blocks;
next_block:
- if (dio->block_in_file > dio->final_block_in_request)
- BUG();
+ BUG_ON(dio->block_in_file > dio->final_block_in_request);
if (dio->block_in_file == dio->final_block_in_request)
break;
}
diff --git a/fs/dquot.c b/fs/dquot.c
index 6b388692093..81d87a413c6 100644
--- a/fs/dquot.c
+++ b/fs/dquot.c
@@ -590,8 +590,7 @@ we_slept:
atomic_dec(&dquot->dq_count);
#ifdef __DQUOT_PARANOIA
/* sanity check */
- if (!list_empty(&dquot->dq_free))
- BUG();
+ BUG_ON(!list_empty(&dquot->dq_free));
#endif
put_dquot_last(dquot);
spin_unlock(&dq_list_lock);
@@ -666,8 +665,7 @@ we_slept:
return NODQUOT;
}
#ifdef __DQUOT_PARANOIA
- if (!dquot->dq_sb) /* Has somebody invalidated entry under us? */
- BUG();
+ BUG_ON(!dquot->dq_sb); /* Has somebody invalidated entry under us? */
#endif
return dquot;
diff --git a/fs/exec.c b/fs/exec.c
index 950ebd43cdc..0291a68a362 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -561,7 +561,7 @@ static int exec_mmap(struct mm_struct *mm)
arch_pick_mmap_layout(mm);
if (old_mm) {
up_read(&old_mm->mmap_sem);
- if (active_mm != old_mm) BUG();
+ BUG_ON(active_mm != old_mm);
mmput(old_mm);
return 0;
}
diff --git a/fs/fcntl.c b/fs/fcntl.c
index 2a2479196f9..d35cbc6bc11 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -453,8 +453,7 @@ static void send_sigio_to_task(struct task_struct *p,
/* Make sure we are called with one of the POLL_*
reasons, otherwise we could leak kernel stack into
userspace. */
- if ((reason & __SI_MASK) != __SI_POLL)
- BUG();
+ BUG_ON((reason & __SI_MASK) != __SI_POLL);
if (reason - POLL_IN >= NSIGPOLL)
si.si_band = ~0L;
else
diff --git a/fs/freevxfs/vxfs_olt.c b/fs/freevxfs/vxfs_olt.c
index 76a0708ae97..04950084790 100644
--- a/fs/freevxfs/vxfs_olt.c
+++ b/fs/freevxfs/vxfs_olt.c
@@ -42,24 +42,21 @@
static inline void
vxfs_get_fshead(struct vxfs_oltfshead *fshp, struct vxfs_sb_info *infp)
{
- if (infp->vsi_fshino)
- BUG();
+ BUG_ON(infp->vsi_fshino);
infp->vsi_fshino = fshp->olt_fsino[0];
}
static inline void
vxfs_get_ilist(struct vxfs_oltilist *ilistp, struct vxfs_sb_info *infp)
{
- if (infp->vsi_iext)
- BUG();
+ BUG_ON(infp->vsi_iext);
infp->vsi_iext = ilistp->olt_iext[0];
}
static inline u_long
vxfs_oblock(struct super_block *sbp, daddr_t block, u_long bsize)
{
- if (sbp->s_blocksize % bsize)
- BUG();
+ BUG_ON(sbp->s_blocksize % bsize);
return (block * (sbp->s_blocksize / bsize));
}
diff --git a/fs/hfsplus/bnode.c b/fs/hfsplus/bnode.c
index 8f07e8fbd03..746abc9ecf7 100644
--- a/fs/hfsplus/bnode.c
+++ b/fs/hfsplus/bnode.c
@@ -466,8 +466,7 @@ void hfs_bnode_unhash(struct hfs_bnode *node)
for (p = &node->tree->node_hash[hfs_bnode_hash(node->this)];
*p && *p != node; p = &(*p)->next_hash)
;
- if (!*p)
- BUG();
+ BUG_ON(!*p);
*p = node->next_hash;
node->tree->node_hash_cnt--;
}
@@ -622,8 +621,7 @@ void hfs_bnode_put(struct hfs_bnode *node)
dprint(DBG_BNODE_REFS, "put_node(%d:%d): %d\n",
node->tree->cnid, node->this, atomic_read(&node->refcnt));
- if (!atomic_read(&node->refcnt))
- BUG();
+ BUG_ON(!atomic_read(&node->refcnt));
if (!atomic_dec_and_lock(&node->refcnt, &tree->hash_lock))
return;
for (i = 0; i < tree->pages_per_bnode; i++) {
diff --git a/fs/hfsplus/btree.c b/fs/hfsplus/btree.c
index a67edfa34e9..effa8991999 100644
--- a/fs/hfsplus/btree.c
+++ b/fs/hfsplus/btree.c
@@ -269,8 +269,7 @@ void hfs_bmap_free(struct hfs_bnode *node)
u8 *data, byte, m;
dprint(DBG_BNODE_MOD, "btree_free_node: %u\n", node->this);
- if (!node->this)
- BUG();
+ BUG_ON(!node->this);
tree = node->tree;
nidx = node->this;
node = hfs_bnode_find(tree, 0);
diff --git a/fs/inode.c b/fs/inode.c
index 32b7c337502..3a2446a27d2 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -172,8 +172,7 @@ static struct inode *alloc_inode(struct super_block *sb)
void destroy_inode(struct inode *inode)
{
- if (inode_has_buffers(inode))
- BUG();
+ BUG_ON(inode_has_buffers(inode));
security_inode_free(inode);
if (inode->i_sb->s_op->destroy_inode)
inode->i_sb->s_op->destroy_inode(inode);
@@ -249,12 +248,9 @@ void clear_inode(struct inode *inode)
might_sleep();
invalidate_inode_buffers(inode);
- if (inode->i_data.nrpages)
- BUG();
- if (!(inode->i_state & I_FREEING))
- BUG();
- if (inode->i_state & I_CLEAR)
- BUG();
+ BUG_ON(inode->i_data.nrpages);
+ BUG_ON(!(inode->i_state & I_FREEING));
+ BUG_ON(inode->i_state & I_CLEAR);
wait_on_inode(inode);
DQUOT_DROP(inode);
if (inode->i_sb && inode->i_sb->s_op->clear_inode)
@@ -1054,8 +1050,7 @@ void generic_delete_inode(struct inode *inode)
hlist_del_init(&inode->i_hash);
spin_unlock(&inode_lock);
wake_up_inode(inode);
- if (inode->i_state != I_CLEAR)
- BUG();
+ BUG_ON(inode->i_state != I_CLEAR);
destroy_inode(inode);
}
diff --git a/fs/jffs2/background.c b/fs/jffs2/background.c
index 7b77a954112..ff2a872e80e 100644
--- a/fs/jffs2/background.c
+++ b/fs/jffs2/background.c
@@ -35,8 +35,7 @@ int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c)
pid_t pid;
int ret = 0;
- if (c->gc_task)
- BUG();
+ BUG_ON(c->gc_task);
init_completion(&c->gc_thread_start);
init_completion(&c->gc_thread_exit);
diff --git a/fs/smbfs/file.c b/fs/smbfs/file.c
index c56bd99a970..ed9a24d19d7 100644
--- a/fs/smbfs/file.c
+++ b/fs/smbfs/file.c
@@ -178,11 +178,9 @@ smb_writepage(struct page *page, struct writeback_control *wbc)
unsigned offset = PAGE_CACHE_SIZE;
int err;
- if (!mapping)
- BUG();
+ BUG_ON(!mapping);
inode = mapping->host;
- if (!inode)
- BUG();
+ BUG_ON(!inode);
end_index = inode->i_size >> PAGE_CACHE_SHIFT;
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index f26880a4785..6cfdc9a8777 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -50,7 +50,7 @@ static struct sysfs_dirent * sysfs_new_dirent(struct sysfs_dirent * parent_sd,
return sd;
}
-/**
+/*
*
* Return -EEXIST if there is already a sysfs element with the same name for
* the same parent.
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index 830f76fa098..f1cb1ddde51 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -183,7 +183,7 @@ fill_write_buffer(struct sysfs_buffer * buffer, const char __user * buf, size_t
return -ENOMEM;
if (count >= PAGE_SIZE)
- count = PAGE_SIZE;
+ count = PAGE_SIZE - 1;
error = copy_from_user(buffer->page,buf,count);
buffer->needs_read_fill = 1;
return error ? -EFAULT : count;
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c
index 4c29ac41ac3..f0b347bd12c 100644
--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -175,8 +175,7 @@ const unsigned char * sysfs_get_name(struct sysfs_dirent *sd)
struct bin_attribute * bin_attr;
struct sysfs_symlink * sl;
- if (!sd || !sd->s_element)
- BUG();
+ BUG_ON(!sd || !sd->s_element);
switch (sd->s_type) {
case SYSFS_DIR:
diff --git a/fs/sysv/dir.c b/fs/sysv/dir.c
index 8c66e9270dd..d7074341ee8 100644
--- a/fs/sysv/dir.c
+++ b/fs/sysv/dir.c
@@ -253,8 +253,7 @@ int sysv_delete_entry(struct sysv_dir_entry *de, struct page *page)
lock_page(page);
err = mapping->a_ops->prepare_write(NULL, page, from, to);
- if (err)
- BUG();
+ BUG_ON(err);
de->inode = 0;
err = dir_commit_chunk(page, from, to);
dir_put_page(page);
@@ -353,8 +352,7 @@ void sysv_set_link(struct sysv_dir_entry *de, struct page *page,
lock_page(page);
err = page->mapping->a_ops->prepare_write(NULL, page, from, to);
- if (err)
- BUG();
+ BUG_ON(err);
de->inode = cpu_to_fs16(SYSV_SB(inode->i_sb), inode->i_ino);
err = dir_commit_chunk(page, from, to);
dir_put_page(page);
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index 81e0e8459af..2983afd5e7f 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -312,12 +312,10 @@ static int udf_get_block(struct inode *inode, sector_t block, struct buffer_head
err = 0;
bh = inode_getblk(inode, block, &err, &phys, &new);
- if (bh)
- BUG();
+ BUG_ON(bh);
if (err)
goto abort;
- if (!phys)
- BUG();
+ BUG_ON(!phys);
if (new)
set_buffer_new(bh_result);
diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c
index 85997b1205f..ae4c4754ed3 100644
--- a/fs/xfs/linux-2.6/xfs_file.c
+++ b/fs/xfs/linux-2.6/xfs_file.c
@@ -69,7 +69,6 @@ __xfs_file_read(
return rval;
}
-
STATIC ssize_t
xfs_file_aio_read(
struct kiocb *iocb,
@@ -90,7 +89,6 @@ xfs_file_aio_read_invis(
return __xfs_file_read(iocb, buf, IO_ISAIO|IO_INVIS, count, pos);
}
-
STATIC inline ssize_t
__xfs_file_write(
struct kiocb *iocb,
@@ -113,7 +111,6 @@ __xfs_file_write(
return rval;
}
-
STATIC ssize_t
xfs_file_aio_write(
struct kiocb *iocb,
@@ -134,7 +131,6 @@ xfs_file_aio_write_invis(
return __xfs_file_write(iocb, buf, IO_ISAIO|IO_INVIS, count, pos);
}
-
STATIC inline ssize_t
__xfs_file_readv(
struct file *file,
@@ -179,7 +175,6 @@ xfs_file_readv_invis(
return __xfs_file_readv(file, iov, IO_INVIS, nr_segs, ppos);
}
-
STATIC inline ssize_t
__xfs_file_writev(
struct file *file,
@@ -204,7 +199,6 @@ __xfs_file_writev(
return rval;
}
-
STATIC ssize_t
xfs_file_writev(
struct file *file,
@@ -228,7 +222,7 @@ xfs_file_writev_invis(
STATIC ssize_t
xfs_file_sendfile(
struct file *filp,
- loff_t *ppos,
+ loff_t *pos,
size_t count,
read_actor_t actor,
void *target)
@@ -236,10 +230,80 @@ xfs_file_sendfile(
vnode_t *vp = vn_from_inode(filp->f_dentry->d_inode);
ssize_t rval;
- VOP_SENDFILE(vp, filp, ppos, 0, count, actor, target, NULL, rval);
+ VOP_SENDFILE(vp, filp, pos, 0, count, actor, target, NULL, rval);
return rval;
}
+STATIC ssize_t
+xfs_file_sendfile_invis(
+ struct file *filp,
+ loff_t *pos,
+ size_t count,
+ read_actor_t actor,
+ void *target)
+{
+ vnode_t *vp = vn_from_inode(filp->f_dentry->d_inode);
+ ssize_t rval;
+
+ VOP_SENDFILE(vp, filp, pos, IO_INVIS, count, actor, target, NULL, rval);
+ return rval;
+}
+
+STATIC ssize_t
+xfs_file_splice_read(
+ struct file *infilp,
+ struct inode *pipe,
+ size_t len,
+ unsigned int flags)
+{
+ vnode_t *vp = vn_from_inode(infilp->f_dentry->d_inode);
+ ssize_t rval;
+
+ VOP_SPLICE_READ(vp, infilp, pipe, len, flags, 0, NULL, rval);
+ return rval;
+}
+
+STATIC ssize_t
+xfs_file_splice_read_invis(
+ struct file *infilp,
+ struct inode *pipe,
+ size_t len,
+ unsigned int flags)
+{
+ vnode_t *vp = vn_from_inode(infilp->f_dentry->d_inode);
+ ssize_t rval;
+
+ VOP_SPLICE_READ(vp, infilp, pipe, len, flags, IO_INVIS, NULL, rval);
+ return rval;
+}
+
+STATIC ssize_t
+xfs_file_splice_write(
+ struct inode *pipe,
+ struct file *outfilp,
+ size_t len,
+ unsigned int flags)
+{
+ vnode_t *vp = vn_from_inode(outfilp->f_dentry->d_inode);
+ ssize_t rval;
+
+ VOP_SPLICE_WRITE(vp, pipe, outfilp, len, flags, 0, NULL, rval);
+ return rval;
+}
+
+STATIC ssize_t
+xfs_file_splice_write_invis(
+ struct inode *pipe,
+ struct file *outfilp,
+ size_t len,
+ unsigned int flags)
+{
+ vnode_t *vp = vn_from_inode(outfilp->f_dentry->d_inode);
+ ssize_t rval;
+
+ VOP_SPLICE_WRITE(vp, pipe, outfilp, len, flags, IO_INVIS, NULL, rval);
+ return rval;
+}
STATIC int
xfs_file_open(
@@ -251,13 +315,10 @@ xfs_file_open(
if (!(filp->f_flags & O_LARGEFILE) && i_size_read(inode) > MAX_NON_LFS)
return -EFBIG;
-
- ASSERT(vp);
VOP_OPEN(vp, NULL, error);
return -error;
}
-
STATIC int
xfs_file_release(
struct inode *inode,
@@ -271,7 +332,6 @@ xfs_file_release(
return -error;
}
-
STATIC int
xfs_file_fsync(
struct file *filp,
@@ -285,21 +345,11 @@ xfs_file_fsync(
if (datasync)
flags |= FSYNC_DATA;
-
- ASSERT(vp);
VOP_FSYNC(vp, flags, NULL, (xfs_off_t)0, (xfs_off_t)-1, error);
return -error;
}
-/*
- * xfs_file_readdir maps to VOP_READDIR().
- * We need to build a uio, cred, ...
- */
-
-#define nextdp(dp) ((struct xfs_dirent *)((char *)(dp) + (dp)->d_reclen))
-
#ifdef CONFIG_XFS_DMAPI
-
STATIC struct page *
xfs_vm_nopage(
struct vm_area_struct *area,
@@ -319,10 +369,8 @@ xfs_vm_nopage(
return filemap_nopage(area, address, type);
}
-
#endif /* CONFIG_XFS_DMAPI */
-
STATIC int
xfs_file_readdir(
struct file *filp,
@@ -330,7 +378,7 @@ xfs_file_readdir(
filldir_t filldir)
{
int error = 0;
- vnode_t *vp;
+ vnode_t *vp = vn_from_inode(filp->f_dentry->d_inode);
uio_t uio;
iovec_t iov;
int eof = 0;
@@ -340,9 +388,6 @@ xfs_file_readdir(
xfs_off_t start_offset, curr_offset;
xfs_dirent_t *dbp = NULL;
- vp = vn_from_inode(filp->f_dentry->d_inode);
- ASSERT(vp);
-
/* Try fairly hard to get memory */
do {
if ((read_buf = (caddr_t)kmalloc(rlen, GFP_KERNEL)))
@@ -387,7 +432,7 @@ xfs_file_readdir(
}
size -= dbp->d_reclen;
curr_offset = (loff_t)dbp->d_off /* & 0x7fffffff */;
- dbp = nextdp(dbp);
+ dbp = (xfs_dirent_t *)((char *)dbp + dbp->d_reclen);
}
}
done:
@@ -402,7 +447,6 @@ done:
return -error;
}
-
STATIC int
xfs_file_mmap(
struct file *filp,
@@ -457,11 +501,10 @@ xfs_file_ioctl_invis(
unsigned int cmd,
unsigned long arg)
{
- int error;
struct inode *inode = filp->f_dentry->d_inode;
vnode_t *vp = vn_from_inode(inode);
+ int error;
- ASSERT(vp);
VOP_IOCTL(vp, inode, filp, IO_INVIS, cmd, (void __user *)arg, error);
VMODIFY(vp);
@@ -537,6 +580,8 @@ const struct file_operations xfs_file_operations = {
.aio_read = xfs_file_aio_read,
.aio_write = xfs_file_aio_write,
.sendfile = xfs_file_sendfile,
+ .splice_read = xfs_file_splice_read,
+ .splice_write = xfs_file_splice_write,
.unlocked_ioctl = xfs_file_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = xfs_file_compat_ioctl,
@@ -558,7 +603,9 @@ const struct file_operations xfs_invis_file_operations = {
.writev = xfs_file_writev_invis,
.aio_read = xfs_file_aio_read_invis,
.aio_write = xfs_file_aio_write_invis,
- .sendfile = xfs_file_sendfile,
+ .sendfile = xfs_file_sendfile_invis,
+ .splice_read = xfs_file_splice_read_invis,
+ .splice_write = xfs_file_splice_write_invis,
.unlocked_ioctl = xfs_file_ioctl_invis,
#ifdef CONFIG_COMPAT
.compat_ioctl = xfs_file_compat_invis_ioctl,
diff --git a/fs/xfs/linux-2.6/xfs_linux.h b/fs/xfs/linux-2.6/xfs_linux.h
index 1fe09f2d651..e9fe43d7476 100644
--- a/fs/xfs/linux-2.6/xfs_linux.h
+++ b/fs/xfs/linux-2.6/xfs_linux.h
@@ -103,6 +103,7 @@
*/
#undef HAVE_REFCACHE /* reference cache not needed for NFS in 2.6 */
#define HAVE_SENDFILE /* sendfile(2) exists in 2.6, but not in 2.4 */
+#define HAVE_SPLICE /* a splice(2) exists in 2.6, but not in 2.4 */
#ifdef CONFIG_SMP
#define HAVE_PERCPU_SB /* per cpu superblock counters are a 2.6 feature */
#else
diff --git a/fs/xfs/linux-2.6/xfs_lrw.c b/fs/xfs/linux-2.6/xfs_lrw.c
index 84ddf189389..90cd314acba 100644
--- a/fs/xfs/linux-2.6/xfs_lrw.c
+++ b/fs/xfs/linux-2.6/xfs_lrw.c
@@ -301,36 +301,23 @@ xfs_sendfile(
void *target,
cred_t *credp)
{
+ xfs_inode_t *ip = XFS_BHVTOI(bdp);
+ xfs_mount_t *mp = ip->i_mount;
ssize_t ret;
- xfs_fsize_t n;
- xfs_inode_t *ip;
- xfs_mount_t *mp;
- vnode_t *vp;
-
- ip = XFS_BHVTOI(bdp);
- vp = BHV_TO_VNODE(bdp);
- mp = ip->i_mount;
XFS_STATS_INC(xs_read_calls);
-
- n = XFS_MAXIOFFSET(mp) - *offset;
- if ((n <= 0) || (count == 0))
- return 0;
-
- if (n < count)
- count = n;
-
- if (XFS_FORCED_SHUTDOWN(ip->i_mount))
+ if (XFS_FORCED_SHUTDOWN(mp))
return -EIO;
xfs_ilock(ip, XFS_IOLOCK_SHARED);
- if (DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_READ) &&
+ if (DM_EVENT_ENABLED(BHV_TO_VNODE(bdp)->v_vfsp, ip, DM_EVENT_READ) &&
(!(ioflags & IO_INVIS))) {
vrwlock_t locktype = VRWLOCK_READ;
int error;
- error = XFS_SEND_DATA(mp, DM_EVENT_READ, BHV_TO_VNODE(bdp), *offset, count,
+ error = XFS_SEND_DATA(mp, DM_EVENT_READ, BHV_TO_VNODE(bdp),
+ *offset, count,
FILP_DELAY_FLAG(filp), &locktype);
if (error) {
xfs_iunlock(ip, XFS_IOLOCK_SHARED);
@@ -340,12 +327,96 @@ xfs_sendfile(
xfs_rw_enter_trace(XFS_SENDFILE_ENTER, &ip->i_iocore,
(void *)(unsigned long)target, count, *offset, ioflags);
ret = generic_file_sendfile(filp, offset, count, actor, target);
+ if (ret > 0)
+ XFS_STATS_ADD(xs_read_bytes, ret);
xfs_iunlock(ip, XFS_IOLOCK_SHARED);
+ return ret;
+}
+ssize_t
+xfs_splice_read(
+ bhv_desc_t *bdp,
+ struct file *infilp,
+ struct inode *pipe,
+ size_t count,
+ int flags,
+ int ioflags,
+ cred_t *credp)
+{
+ xfs_inode_t *ip = XFS_BHVTOI(bdp);
+ xfs_mount_t *mp = ip->i_mount;
+ ssize_t ret;
+
+ XFS_STATS_INC(xs_read_calls);
+ if (XFS_FORCED_SHUTDOWN(ip->i_mount))
+ return -EIO;
+
+ xfs_ilock(ip, XFS_IOLOCK_SHARED);
+
+ if (DM_EVENT_ENABLED(BHV_TO_VNODE(bdp)->v_vfsp, ip, DM_EVENT_READ) &&
+ (!(ioflags & IO_INVIS))) {
+ vrwlock_t locktype = VRWLOCK_READ;
+ int error;
+
+ error = XFS_SEND_DATA(mp, DM_EVENT_READ, BHV_TO_VNODE(bdp),
+ infilp->f_pos, count,
+ FILP_DELAY_FLAG(infilp), &locktype);
+ if (error) {
+ xfs_iunlock(ip, XFS_IOLOCK_SHARED);
+ return -error;
+ }
+ }
+ xfs_rw_enter_trace(XFS_SPLICE_READ_ENTER, &ip->i_iocore,
+ pipe, count, infilp->f_pos, ioflags);
+ ret = generic_file_splice_read(infilp, pipe, count, flags);
if (ret > 0)
XFS_STATS_ADD(xs_read_bytes, ret);
+ xfs_iunlock(ip, XFS_IOLOCK_SHARED);
+ return ret;
+}
+
+ssize_t
+xfs_splice_write(
+ bhv_desc_t *bdp,
+ struct inode *pipe,
+ struct file *outfilp,
+ size_t count,
+ int flags,
+ int ioflags,
+ cred_t *credp)
+{
+ xfs_inode_t *ip = XFS_BHVTOI(bdp);
+ xfs_mount_t *mp = ip->i_mount;
+ ssize_t ret;
+
+ XFS_STATS_INC(xs_write_calls);
+ if (XFS_FORCED_SHUTDOWN(ip->i_mount))
+ return -EIO;
+
+ xfs_ilock(ip, XFS_IOLOCK_EXCL);
+
+ if (DM_EVENT_ENABLED(BHV_TO_VNODE(bdp)->v_vfsp, ip, DM_EVENT_WRITE) &&
+ (!(ioflags & IO_INVIS))) {
+ vrwlock_t locktype = VRWLOCK_WRITE;
+ int error;
+
+ error = XFS_SEND_DATA(mp, DM_EVENT_WRITE, BHV_TO_VNODE(bdp),
+ outfilp->f_pos, count,
+ FILP_DELAY_FLAG(outfilp), &locktype);
+ if (error) {
+ xfs_iunlock(ip, XFS_IOLOCK_EXCL);
+ return -error;
+ }
+ }
+ xfs_rw_enter_trace(XFS_SPLICE_WRITE_ENTER, &ip->i_iocore,
+ pipe, count, outfilp->f_pos, ioflags);
+ ret = generic_file_splice_write(pipe, outfilp, count, flags);
+ if (ret > 0)
+ XFS_STATS_ADD(xs_write_bytes, ret);
+
+ xfs_iunlock(ip, XFS_IOLOCK_EXCL);
return ret;
}
@@ -363,7 +434,7 @@ xfs_zero_last_block(
xfs_fsize_t end_size)
{
xfs_fileoff_t last_fsb;
- xfs_mount_t *mp;
+ xfs_mount_t *mp = io->io_mount;
int nimaps;
int zero_offset;
int zero_len;
@@ -373,8 +444,6 @@ xfs_zero_last_block(
ASSERT(ismrlocked(io->io_lock, MR_UPDATE) != 0);
- mp = io->io_mount;
-
zero_offset = XFS_B_FSB_OFFSET(mp, isize);
if (zero_offset == 0) {
/*
@@ -405,10 +474,9 @@ xfs_zero_last_block(
* don't deadlock when the buffer cache calls back to us.
*/
XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL| XFS_EXTSIZE_RD);
- loff = XFS_FSB_TO_B(mp, last_fsb);
+ loff = XFS_FSB_TO_B(mp, last_fsb);
zero_len = mp->m_sb.sb_blocksize - zero_offset;
-
error = xfs_iozero(ip, loff + zero_offset, zero_len, end_size);
XFS_ILOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD);
@@ -441,7 +509,7 @@ xfs_zero_eof(
xfs_fileoff_t zero_count_fsb;
xfs_fileoff_t last_fsb;
xfs_extlen_t buf_len_fsb;
- xfs_mount_t *mp;
+ xfs_mount_t *mp = io->io_mount;
int nimaps;
int error = 0;
xfs_bmbt_irec_t imap;
@@ -450,8 +518,6 @@ xfs_zero_eof(
ASSERT(ismrlocked(io->io_iolock, MR_UPDATE));
ASSERT(offset > isize);
- mp = io->io_mount;
-
/*
* First handle zeroing the block on which isize resides.
* We only zero a part of that block so it is handled specially.
diff --git a/fs/xfs/linux-2.6/xfs_lrw.h b/fs/xfs/linux-2.6/xfs_lrw.h
index 38864a88d42..eaa5659713f 100644
--- a/fs/xfs/linux-2.6/xfs_lrw.h
+++ b/fs/xfs/linux-2.6/xfs_lrw.h
@@ -60,6 +60,8 @@ struct xfs_iomap;
#define XFS_IOMAP_ALLOC_ENTER 25
#define XFS_IOMAP_ALLOC_MAP 26
#define XFS_IOMAP_UNWRITTEN 27
+#define XFS_SPLICE_READ_ENTER 28
+#define XFS_SPLICE_WRITE_ENTER 29
extern void xfs_rw_enter_trace(int, struct xfs_iocore *,
void *, size_t, loff_t, int);
extern void xfs_inval_cached_trace(struct xfs_iocore *,
@@ -78,6 +80,7 @@ extern int xfs_bmap(struct bhv_desc *, xfs_off_t, ssize_t, int,
struct xfs_iomap *, int *);
extern int xfsbdstrat(struct xfs_mount *, struct xfs_buf *);
extern int xfs_bdstrat_cb(struct xfs_buf *);
+extern int xfs_dev_is_read_only(struct xfs_mount *, char *);
extern int xfs_zero_eof(struct vnode *, struct xfs_iocore *, xfs_off_t,
xfs_fsize_t, xfs_fsize_t);
@@ -90,7 +93,11 @@ extern ssize_t xfs_write(struct bhv_desc *, struct kiocb *,
extern ssize_t xfs_sendfile(struct bhv_desc *, struct file *,
loff_t *, int, size_t, read_actor_t,
void *, struct cred *);
-
-extern int xfs_dev_is_read_only(struct xfs_mount *, char *);
+extern ssize_t xfs_splice_read(struct bhv_desc *, struct file *,
+ struct inode *, size_t, int, int,
+ struct cred *);
+extern ssize_t xfs_splice_write(struct bhv_desc *, struct inode *,
+ struct file *, size_t, int, int,
+ struct cred *);
#endif /* __XFS_LRW_H__ */
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c
index 1884300417e..68f4793e8a1 100644
--- a/fs/xfs/linux-2.6/xfs_super.c
+++ b/fs/xfs/linux-2.6/xfs_super.c
@@ -67,7 +67,8 @@ mempool_t *xfs_ioend_pool;
STATIC struct xfs_mount_args *
xfs_args_allocate(
- struct super_block *sb)
+ struct super_block *sb,
+ int silent)
{
struct xfs_mount_args *args;
@@ -80,8 +81,8 @@ xfs_args_allocate(
args->flags |= XFSMNT_DIRSYNC;
if (sb->s_flags & MS_SYNCHRONOUS)
args->flags |= XFSMNT_WSYNC;
-
- /* Default to 32 bit inodes on Linux all the time */
+ if (silent)
+ args->flags |= XFSMNT_QUIET;
args->flags |= XFSMNT_32BITINODES;
return args;
@@ -719,7 +720,7 @@ xfs_fs_remount(
char *options)
{
vfs_t *vfsp = vfs_from_sb(sb);
- struct xfs_mount_args *args = xfs_args_allocate(sb);
+ struct xfs_mount_args *args = xfs_args_allocate(sb, 0);
int error;
VFS_PARSEARGS(vfsp, options, args, 1, error);
@@ -825,7 +826,7 @@ xfs_fs_fill_super(
{
vnode_t *rootvp;
struct vfs *vfsp = vfs_allocate(sb);
- struct xfs_mount_args *args = xfs_args_allocate(sb);
+ struct xfs_mount_args *args = xfs_args_allocate(sb, silent);
struct kstatfs statvfs;
int error, error2;
diff --git a/fs/xfs/linux-2.6/xfs_vnode.h b/fs/xfs/linux-2.6/xfs_vnode.h
index 06f5845e956..6f1c79a28f8 100644
--- a/fs/xfs/linux-2.6/xfs_vnode.h
+++ b/fs/xfs/linux-2.6/xfs_vnode.h
@@ -173,6 +173,12 @@ typedef ssize_t (*vop_write_t)(bhv_desc_t *, struct kiocb *,
typedef ssize_t (*vop_sendfile_t)(bhv_desc_t *, struct file *,
loff_t *, int, size_t, read_actor_t,
void *, struct cred *);
+typedef ssize_t (*vop_splice_read_t)(bhv_desc_t *, struct file *,
+ struct inode *, size_t, int, int,
+ struct cred *);
+typedef ssize_t (*vop_splice_write_t)(bhv_desc_t *, struct inode *,
+ struct file *, size_t, int, int,
+ struct cred *);
typedef int (*vop_ioctl_t)(bhv_desc_t *, struct inode *, struct file *,
int, unsigned int, void __user *);
typedef int (*vop_getattr_t)(bhv_desc_t *, struct vattr *, int,
@@ -231,6 +237,8 @@ typedef struct vnodeops {
vop_read_t vop_read;
vop_write_t vop_write;
vop_sendfile_t vop_sendfile;
+ vop_splice_read_t vop_splice_read;
+ vop_splice_write_t vop_splice_write;
vop_ioctl_t vop_ioctl;
vop_getattr_t vop_getattr;
vop_setattr_t vop_setattr;
@@ -276,6 +284,10 @@ typedef struct vnodeops {
rv = _VOP_(vop_write, vp)((vp)->v_fbhv,file,iov,segs,offset,ioflags,cr)
#define VOP_SENDFILE(vp,f,off,ioflags,cnt,act,targ,cr,rv) \
rv = _VOP_(vop_sendfile, vp)((vp)->v_fbhv,f,off,ioflags,cnt,act,targ,cr)
+#define VOP_SPLICE_READ(vp,f,pipe,cnt,fl,iofl,cr,rv) \
+ rv = _VOP_(vop_splice_read, vp)((vp)->v_fbhv,f,pipe,cnt,fl,iofl,cr)
+#define VOP_SPLICE_WRITE(vp,f,pipe,cnt,fl,iofl,cr,rv) \
+ rv = _VOP_(vop_splice_write, vp)((vp)->v_fbhv,f,pipe,cnt,fl,iofl,cr)
#define VOP_BMAP(vp,of,sz,rw,b,n,rv) \
rv = _VOP_(vop_bmap, vp)((vp)->v_fbhv,of,sz,rw,b,n)
#define VOP_OPEN(vp, cr, rv) \
diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c
index 73c1e5e80c0..7fb5eca9bd5 100644
--- a/fs/xfs/quota/xfs_qm.c
+++ b/fs/xfs/quota/xfs_qm.c
@@ -2624,7 +2624,7 @@ xfs_qm_vop_chown_reserve(
{
int error;
xfs_mount_t *mp;
- uint delblks, blkflags;
+ uint delblks, blkflags, prjflags = 0;
xfs_dquot_t *unresudq, *unresgdq, *delblksudq, *delblksgdq;
ASSERT(XFS_ISLOCKED_INODE(ip));
@@ -2650,10 +2650,13 @@ xfs_qm_vop_chown_reserve(
}
}
if (XFS_IS_OQUOTA_ON(ip->i_mount) && gdqp) {
- if ((XFS_IS_GQUOTA_ON(ip->i_mount) &&
- ip->i_d.di_gid != be32_to_cpu(gdqp->q_core.d_id)) ||
- (XFS_IS_PQUOTA_ON(ip->i_mount) &&
- ip->i_d.di_projid != be32_to_cpu(gdqp->q_core.d_id))) {
+ if (XFS_IS_PQUOTA_ON(ip->i_mount) &&
+ ip->i_d.di_projid != be32_to_cpu(gdqp->q_core.d_id))
+ prjflags = XFS_QMOPT_ENOSPC;
+
+ if (prjflags ||
+ (XFS_IS_GQUOTA_ON(ip->i_mount) &&
+ ip->i_d.di_gid != be32_to_cpu(gdqp->q_core.d_id))) {
delblksgdq = gdqp;
if (delblks) {
ASSERT(ip->i_gdquot);
@@ -2664,7 +2667,7 @@ xfs_qm_vop_chown_reserve(
if ((error = xfs_trans_reserve_quota_bydquots(tp, ip->i_mount,
delblksudq, delblksgdq, ip->i_d.di_nblocks, 1,
- flags | blkflags)))
+ flags | blkflags | prjflags)))
return (error);
/*
@@ -2681,7 +2684,7 @@ xfs_qm_vop_chown_reserve(
ASSERT(unresudq || unresgdq);
if ((error = xfs_trans_reserve_quota_bydquots(NULL, ip->i_mount,
delblksudq, delblksgdq, (xfs_qcnt_t)delblks, 0,
- flags | blkflags)))
+ flags | blkflags | prjflags)))
return (error);
xfs_trans_reserve_quota_bydquots(NULL, ip->i_mount,
unresudq, unresgdq, -((xfs_qcnt_t)delblks), 0,
diff --git a/fs/xfs/quota/xfs_trans_dquot.c b/fs/xfs/quota/xfs_trans_dquot.c
index d8e131ec0aa..9168918db25 100644
--- a/fs/xfs/quota/xfs_trans_dquot.c
+++ b/fs/xfs/quota/xfs_trans_dquot.c
@@ -595,12 +595,19 @@ xfs_trans_unreserve_and_mod_dquots(
}
}
+STATIC int
+xfs_quota_error(uint flags)
+{
+ if (flags & XFS_QMOPT_ENOSPC)
+ return ENOSPC;
+ return EDQUOT;
+}
+
/*
* This reserves disk blocks and inodes against a dquot.
* Flags indicate if the dquot is to be locked here and also
* if the blk reservation is for RT or regular blocks.
* Sending in XFS_QMOPT_FORCE_RES flag skips the quota check.
- * Returns EDQUOT if quota is exceeded.
*/
STATIC int
xfs_trans_dqresv(
@@ -666,19 +673,15 @@ xfs_trans_dqresv(
*/
if (hardlimit > 0ULL &&
(hardlimit <= nblks + *resbcountp)) {
- error = EDQUOT;
+ error = xfs_quota_error(flags);
goto error_return;
}
if (softlimit > 0ULL &&
(softlimit <= nblks + *resbcountp)) {
- /*
- * If timer or warnings has expired,
- * return EDQUOT
- */
if ((timer != 0 && get_seconds() > timer) ||
(warns != 0 && warns >= warnlimit)) {
- error = EDQUOT;
+ error = xfs_quota_error(flags);
goto error_return;
}
}
@@ -695,16 +698,12 @@ xfs_trans_dqresv(
if (!softlimit)
softlimit = q->qi_isoftlimit;
if (hardlimit > 0ULL && count >= hardlimit) {
- error = EDQUOT;
+ error = xfs_quota_error(flags);
goto error_return;
} else if (softlimit > 0ULL && count >= softlimit) {
- /*
- * If timer or warnings has expired,
- * return EDQUOT
- */
if ((timer != 0 && get_seconds() > timer) ||
(warns != 0 && warns >= warnlimit)) {
- error = EDQUOT;
+ error = xfs_quota_error(flags);
goto error_return;
}
}
@@ -751,13 +750,14 @@ error_return:
/*
- * Given a dquot(s), make disk block and/or inode reservations against them.
+ * Given dquot(s), make disk block and/or inode reservations against them.
* The fact that this does the reservation against both the usr and
- * grp quotas is important, because this follows a both-or-nothing
+ * grp/prj quotas is important, because this follows a both-or-nothing
* approach.
*
* flags = XFS_QMOPT_DQLOCK indicate if dquot(s) need to be locked.
* XFS_QMOPT_FORCE_RES evades limit enforcement. Used by chown.
+ * XFS_QMOPT_ENOSPC returns ENOSPC not EDQUOT. Used by pquota.
* XFS_TRANS_DQ_RES_BLKS reserves regular disk blocks
* XFS_TRANS_DQ_RES_RTBLKS reserves realtime disk blocks
* dquots are unlocked on return, if they were not locked by caller.
@@ -772,25 +772,27 @@ xfs_trans_reserve_quota_bydquots(
long ninos,
uint flags)
{
- int resvd;
+ int resvd = 0, error;
- if (! XFS_IS_QUOTA_ON(mp))
- return (0);
+ if (!XFS_IS_QUOTA_ON(mp))
+ return 0;
if (tp && tp->t_dqinfo == NULL)
xfs_trans_alloc_dqinfo(tp);
ASSERT(flags & XFS_QMOPT_RESBLK_MASK);
- resvd = 0;
if (udqp) {
- if (xfs_trans_dqresv(tp, mp, udqp, nblks, ninos, flags))
- return (EDQUOT);
+ error = xfs_trans_dqresv(tp, mp, udqp, nblks, ninos,
+ (flags & ~XFS_QMOPT_ENOSPC));
+ if (error)
+ return error;
resvd = 1;
}
if (gdqp) {
- if (xfs_trans_dqresv(tp, mp, gdqp, nblks, ninos, flags)) {
+ error = xfs_trans_dqresv(tp, mp, gdqp, nblks, ninos, flags);
+ if (error) {
/*
* can't do it, so backout previous reservation
*/
@@ -799,14 +801,14 @@ xfs_trans_reserve_quota_bydquots(
xfs_trans_dqresv(tp, mp, udqp,
-nblks, -ninos, flags);
}
- return (EDQUOT);
+ return error;
}
}
/*
* Didn't change anything critical, so, no need to log
*/
- return (0);
+ return 0;
}
@@ -814,8 +816,6 @@ xfs_trans_reserve_quota_bydquots(
* Lock the dquot and change the reservation if we can.
* This doesn't change the actual usage, just the reservation.
* The inode sent in is locked.
- *
- * Returns 0 on success, EDQUOT or other errors otherwise
*/
STATIC int
xfs_trans_reserve_quota_nblks(
@@ -824,20 +824,24 @@ xfs_trans_reserve_quota_nblks(
xfs_inode_t *ip,
long nblks,
long ninos,
- uint type)
+ uint flags)
{
int error;
if (!XFS_IS_QUOTA_ON(mp))
- return (0);
+ return 0;
+ if (XFS_IS_PQUOTA_ON(mp))
+ flags |= XFS_QMOPT_ENOSPC;
ASSERT(ip->i_ino != mp->m_sb.sb_uquotino);
ASSERT(ip->i_ino != mp->m_sb.sb_gquotino);
ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
ASSERT(XFS_IS_QUOTA_RUNNING(ip->i_mount));
- ASSERT((type & ~XFS_QMOPT_FORCE_RES) == XFS_TRANS_DQ_RES_RTBLKS ||
- (type & ~XFS_QMOPT_FORCE_RES) == XFS_TRANS_DQ_RES_BLKS);
+ ASSERT((flags & ~(XFS_QMOPT_FORCE_RES | XFS_QMOPT_ENOSPC)) ==
+ XFS_TRANS_DQ_RES_RTBLKS ||
+ (flags & ~(XFS_QMOPT_FORCE_RES | XFS_QMOPT_ENOSPC)) ==
+ XFS_TRANS_DQ_RES_BLKS);
/*
* Reserve nblks against these dquots, with trans as the mediator.
@@ -845,8 +849,8 @@ xfs_trans_reserve_quota_nblks(
error = xfs_trans_reserve_quota_bydquots(tp, mp,
ip->i_udquot, ip->i_gdquot,
nblks, ninos,
- type);
- return (error);
+ flags);
+ return error;
}
/*
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c
index d384e489705..26939d364bc 100644
--- a/fs/xfs/xfs_bmap.c
+++ b/fs/xfs/xfs_bmap.c
@@ -4719,18 +4719,17 @@ xfs_bmapi(
/*
* Make a transaction-less quota reservation for
* delayed allocation blocks. This number gets
- * adjusted later.
- * We return EDQUOT if we haven't allocated
- * blks already inside this loop;
+ * adjusted later. We return if we haven't
+ * allocated blocks already inside this loop.
*/
- if (XFS_TRANS_RESERVE_QUOTA_NBLKS(
+ if ((error = XFS_TRANS_RESERVE_QUOTA_NBLKS(
mp, NULL, ip, (long)alen, 0,
rt ? XFS_QMOPT_RES_RTBLKS :
- XFS_QMOPT_RES_REGBLKS)) {
+ XFS_QMOPT_RES_REGBLKS))) {
if (n == 0) {
*nmap = 0;
ASSERT(cur == NULL);
- return XFS_ERROR(EDQUOT);
+ return error;
}
break;
}
diff --git a/fs/xfs/xfs_bmap.h b/fs/xfs/xfs_bmap.h
index f83399c89ce..8e0d73d9ccc 100644
--- a/fs/xfs/xfs_bmap.h
+++ b/fs/xfs/xfs_bmap.h
@@ -353,10 +353,11 @@ xfs_check_nostate_extents(
xfs_extnum_t num);
/*
- * Call xfs_bmap_do_search_extents() to search for the extent
- * record containing block bno. If in multi-level in-core extent
- * allocation mode, find and extract the target extent buffer,
- * otherwise just use the direct extent list.
+ * Search the extent records for the entry containing block bno.
+ * If bno lies in a hole, point to the next entry. If bno lies
+ * past eof, *eofp will be set, and *prevp will contain the last
+ * entry (null if none). Else, *lastxp will be set to the index
+ * of the found entry; *gotp will contain the entry.
*/
xfs_bmbt_rec_t *
xfs_bmap_search_multi_extents(struct xfs_ifork *, xfs_fileoff_t, int *,
diff --git a/fs/xfs/xfs_clnt.h b/fs/xfs/xfs_clnt.h
index 022fff62085..5b7eb81453b 100644
--- a/fs/xfs/xfs_clnt.h
+++ b/fs/xfs/xfs_clnt.h
@@ -68,6 +68,7 @@ struct xfs_mount_args {
* enforcement */
#define XFSMNT_PQUOTAENF 0x00000040 /* IRIX project quota limit
* enforcement */
+#define XFSMNT_QUIET 0x00000080 /* don't report mount errors */
#define XFSMNT_NOALIGN 0x00000200 /* don't allocate at
* stripe boundaries*/
#define XFSMNT_RETERR 0x00000400 /* return error to user */
diff --git a/fs/xfs/xfs_error.h b/fs/xfs/xfs_error.h
index 26b8e709a56..bc43163456e 100644
--- a/fs/xfs/xfs_error.h
+++ b/fs/xfs/xfs_error.h
@@ -186,4 +186,7 @@ extern void xfs_fs_cmn_err(int level, struct xfs_mount *mp, char *fmt, ...);
#define xfs_fs_repair_cmn_err(level, mp, fmt, args...) \
xfs_fs_cmn_err(level, mp, fmt " Unmount and run xfs_repair.", ## args)
+#define xfs_fs_mount_cmn_err(f, fmt, args...) \
+ ((f & XFS_MFSI_QUIET)? cmn_err(CE_WARN, "XFS: " fmt, ## args) : (void)0)
+
#endif /* __XFS_ERROR_H__ */
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index 72e7e78bfff..049fabb7f7e 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -213,7 +213,8 @@ xfs_mount_free(
STATIC int
xfs_mount_validate_sb(
xfs_mount_t *mp,
- xfs_sb_t *sbp)
+ xfs_sb_t *sbp,
+ int flags)
{
/*
* If the log device and data device have the
@@ -223,33 +224,29 @@ xfs_mount_validate_sb(
* a volume filesystem in a non-volume manner.
*/
if (sbp->sb_magicnum != XFS_SB_MAGIC) {
- cmn_err(CE_WARN, "XFS: bad magic number");
+ xfs_fs_mount_cmn_err(flags, "bad magic number");
return XFS_ERROR(EWRONGFS);
}
if (!XFS_SB_GOOD_VERSION(sbp)) {
- cmn_err(CE_WARN, "XFS: bad version");
+ xfs_fs_mount_cmn_err(flags, "bad version");
return XFS_ERROR(EWRONGFS);
}
if (unlikely(
sbp->sb_logstart == 0 && mp->m_logdev_targp == mp->m_ddev_targp)) {
- cmn_err(CE_WARN,
- "XFS: filesystem is marked as having an external log; "
- "specify logdev on the\nmount command line.");
- XFS_CORRUPTION_ERROR("xfs_mount_validate_sb(1)",
- XFS_ERRLEVEL_HIGH, mp, sbp);
- return XFS_ERROR(EFSCORRUPTED);
+ xfs_fs_mount_cmn_err(flags,
+ "filesystem is marked as having an external log; "
+ "specify logdev on the\nmount command line.");
+ return XFS_ERROR(EINVAL);
}
if (unlikely(
sbp->sb_logstart != 0 && mp->m_logdev_targp != mp->m_ddev_targp)) {
- cmn_err(CE_WARN,
- "XFS: filesystem is marked as having an internal log; "
- "don't specify logdev on\nthe mount command line.");
- XFS_CORRUPTION_ERROR("xfs_mount_validate_sb(2)",
- XFS_ERRLEVEL_HIGH, mp, sbp);
- return XFS_ERROR(EFSCORRUPTED);
+ xfs_fs_mount_cmn_err(flags,
+ "filesystem is marked as having an internal log; "
+ "do not specify logdev on\nthe mount command line.");
+ return XFS_ERROR(EINVAL);
}
/*
@@ -274,9 +271,7 @@ xfs_mount_validate_sb(
(sbp->sb_rextsize * sbp->sb_blocksize > XFS_MAX_RTEXTSIZE) ||
(sbp->sb_rextsize * sbp->sb_blocksize < XFS_MIN_RTEXTSIZE) ||
(sbp->sb_imax_pct > 100 || sbp->sb_imax_pct < 1))) {
- cmn_err(CE_WARN, "XFS: SB sanity check 1 failed");
- XFS_CORRUPTION_ERROR("xfs_mount_validate_sb(3)",
- XFS_ERRLEVEL_LOW, mp, sbp);
+ xfs_fs_mount_cmn_err(flags, "SB sanity check 1 failed");
return XFS_ERROR(EFSCORRUPTED);
}
@@ -289,9 +284,7 @@ xfs_mount_validate_sb(
(xfs_drfsbno_t)sbp->sb_agcount * sbp->sb_agblocks ||
sbp->sb_dblocks < (xfs_drfsbno_t)(sbp->sb_agcount - 1) *
sbp->sb_agblocks + XFS_MIN_AG_BLOCKS)) {
- cmn_err(CE_WARN, "XFS: SB sanity check 2 failed");
- XFS_ERROR_REPORT("xfs_mount_validate_sb(4)",
- XFS_ERRLEVEL_LOW, mp);
+ xfs_fs_mount_cmn_err(flags, "SB sanity check 2 failed");
return XFS_ERROR(EFSCORRUPTED);
}
@@ -307,15 +300,13 @@ xfs_mount_validate_sb(
(sbp->sb_dblocks << (sbp->sb_blocklog - BBSHIFT)) > UINT_MAX ||
(sbp->sb_rblocks << (sbp->sb_blocklog - BBSHIFT)) > UINT_MAX)) {
#endif
- cmn_err(CE_WARN,
- "XFS: File system is too large to be mounted on this system.");
+ xfs_fs_mount_cmn_err(flags,
+ "file system too large to be mounted on this system.");
return XFS_ERROR(E2BIG);
}
if (unlikely(sbp->sb_inprogress)) {
- cmn_err(CE_WARN, "XFS: file system busy");
- XFS_ERROR_REPORT("xfs_mount_validate_sb(5)",
- XFS_ERRLEVEL_LOW, mp);
+ xfs_fs_mount_cmn_err(flags, "file system busy");
return XFS_ERROR(EFSCORRUPTED);
}
@@ -323,8 +314,8 @@ xfs_mount_validate_sb(
* Version 1 directory format has never worked on Linux.
*/
if (unlikely(!XFS_SB_VERSION_HASDIRV2(sbp))) {
- cmn_err(CE_WARN,
- "XFS: Attempted to mount file system using version 1 directory format");
+ xfs_fs_mount_cmn_err(flags,
+ "file system using version 1 directory format");
return XFS_ERROR(ENOSYS);
}
@@ -332,11 +323,11 @@ xfs_mount_validate_sb(
* Until this is fixed only page-sized or smaller data blocks work.
*/
if (unlikely(sbp->sb_blocksize > PAGE_SIZE)) {
- cmn_err(CE_WARN,
- "XFS: Attempted to mount file system with blocksize %d bytes",
+ xfs_fs_mount_cmn_err(flags,
+ "file system with blocksize %d bytes",
sbp->sb_blocksize);
- cmn_err(CE_WARN,
- "XFS: Only page-sized (%ld) or less blocksizes currently work.",
+ xfs_fs_mount_cmn_err(flags,
+ "only pagesize (%ld) or less will currently work.",
PAGE_SIZE);
return XFS_ERROR(ENOSYS);
}
@@ -484,7 +475,7 @@ xfs_xlatesb(
* Does the initial read of the superblock.
*/
int
-xfs_readsb(xfs_mount_t *mp)
+xfs_readsb(xfs_mount_t *mp, int flags)
{
unsigned int sector_size;
unsigned int extra_flags;
@@ -506,7 +497,7 @@ xfs_readsb(xfs_mount_t *mp)
bp = xfs_buf_read_flags(mp->m_ddev_targp, XFS_SB_DADDR,
BTOBB(sector_size), extra_flags);
if (!bp || XFS_BUF_ISERROR(bp)) {
- cmn_err(CE_WARN, "XFS: SB read failed");
+ xfs_fs_mount_cmn_err(flags, "SB read failed");
error = bp ? XFS_BUF_GETERROR(bp) : ENOMEM;
goto fail;
}
@@ -520,9 +511,9 @@ xfs_readsb(xfs_mount_t *mp)
sbp = XFS_BUF_TO_SBP(bp);
xfs_xlatesb(XFS_BUF_PTR(bp), &(mp->m_sb), 1, XFS_SB_ALL_BITS);
- error = xfs_mount_validate_sb(mp, &(mp->m_sb));
+ error = xfs_mount_validate_sb(mp, &(mp->m_sb), flags);
if (error) {
- cmn_err(CE_WARN, "XFS: SB validate failed");
+ xfs_fs_mount_cmn_err(flags, "SB validate failed");
goto fail;
}
@@ -530,8 +521,8 @@ xfs_readsb(xfs_mount_t *mp)
* We must be able to do sector-sized and sector-aligned IO.
*/
if (sector_size > mp->m_sb.sb_sectsize) {
- cmn_err(CE_WARN,
- "XFS: device supports only %u byte sectors (not %u)",
+ xfs_fs_mount_cmn_err(flags,
+ "device supports only %u byte sectors (not %u)",
sector_size, mp->m_sb.sb_sectsize);
error = ENOSYS;
goto fail;
@@ -548,7 +539,7 @@ xfs_readsb(xfs_mount_t *mp)
bp = xfs_buf_read_flags(mp->m_ddev_targp, XFS_SB_DADDR,
BTOBB(sector_size), extra_flags);
if (!bp || XFS_BUF_ISERROR(bp)) {
- cmn_err(CE_WARN, "XFS: SB re-read failed");
+ xfs_fs_mount_cmn_err(flags, "SB re-read failed");
error = bp ? XFS_BUF_GETERROR(bp) : ENOMEM;
goto fail;
}
@@ -678,7 +669,7 @@ xfs_mountfs(
int error = 0;
if (mp->m_sb_bp == NULL) {
- if ((error = xfs_readsb(mp))) {
+ if ((error = xfs_readsb(mp, mfsi_flags))) {
return error;
}
}
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
index 66cbee79864..668ad23fd37 100644
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -510,9 +510,12 @@ xfs_preferred_iosize(xfs_mount_t *mp)
*/
#define XFS_MFSI_SECOND 0x01 /* Secondary mount -- skip stuff */
#define XFS_MFSI_CLIENT 0x02 /* Is a client -- skip lots of stuff */
+/* XFS_MFSI_RRINODES */
#define XFS_MFSI_NOUNLINK 0x08 /* Skip unlinked inode processing in */
/* log recovery */
#define XFS_MFSI_NO_QUOTACHECK 0x10 /* Skip quotacheck processing */
+/* XFS_MFSI_CONVERT_SUNIT */
+#define XFS_MFSI_QUIET 0x40 /* Be silent if mount errors found */
/*
* Macros for getting from mount to vfs and back.
@@ -581,7 +584,7 @@ extern int xfs_mod_incore_sb_unlocked(xfs_mount_t *, xfs_sb_field_t,
extern int xfs_mod_incore_sb_batch(xfs_mount_t *, xfs_mod_sb_t *,
uint, int);
extern struct xfs_buf *xfs_getsb(xfs_mount_t *, int);
-extern int xfs_readsb(xfs_mount_t *mp);
+extern int xfs_readsb(xfs_mount_t *, int);
extern void xfs_freesb(xfs_mount_t *);
extern void xfs_do_force_shutdown(bhv_desc_t *, int, char *, int);
extern int xfs_syncsub(xfs_mount_t *, int, int, int *);
diff --git a/fs/xfs/xfs_quota.h b/fs/xfs/xfs_quota.h
index 4f6a034de7f..7fbef974bce 100644
--- a/fs/xfs/xfs_quota.h
+++ b/fs/xfs/xfs_quota.h
@@ -196,10 +196,11 @@ typedef struct xfs_qoff_logformat {
#define XFS_QMOPT_QUOTAOFF 0x0000080 /* quotas are being turned off */
#define XFS_QMOPT_UMOUNTING 0x0000100 /* filesys is being unmounted */
#define XFS_QMOPT_DOLOG 0x0000200 /* log buf changes (in quotacheck) */
-#define XFS_QMOPT_DOWARN 0x0000400 /* increase warning cnt if necessary */
+#define XFS_QMOPT_DOWARN 0x0000400 /* increase warning cnt if needed */
#define XFS_QMOPT_ILOCKED 0x0000800 /* inode is already locked (excl) */
-#define XFS_QMOPT_DQREPAIR 0x0001000 /* repair dquot, if damaged. */
+#define XFS_QMOPT_DQREPAIR 0x0001000 /* repair dquot if damaged */
#define XFS_QMOPT_GQUOTA 0x0002000 /* group dquot requested */
+#define XFS_QMOPT_ENOSPC 0x0004000 /* enospc instead of edquot (prj) */
/*
* flags to xfs_trans_mod_dquot to indicate which field needs to be
diff --git a/fs/xfs/xfs_vfsops.c b/fs/xfs/xfs_vfsops.c
index 504d2a80747..f0e09ca1413 100644
--- a/fs/xfs/xfs_vfsops.c
+++ b/fs/xfs/xfs_vfsops.c
@@ -442,6 +442,9 @@ xfs_mount(
p = vfs_bhv_lookup(vfsp, VFS_POSITION_IO);
mp->m_io_ops = p ? *(xfs_ioops_t *) vfs_bhv_custom(p) : xfs_iocore_xfs;
+ if (args->flags & XFSMNT_QUIET)
+ flags |= XFS_MFSI_QUIET;
+
/*
* Open real time and log devices - order is important.
*/
@@ -492,7 +495,7 @@ xfs_mount(
error = xfs_start_flags(vfsp, args, mp);
if (error)
goto error1;
- error = xfs_readsb(mp);
+ error = xfs_readsb(mp, flags);
if (error)
goto error1;
error = xfs_finish_flags(vfsp, args, mp);
@@ -1697,8 +1700,9 @@ xfs_parseargs(
int dsunit, dswidth, vol_dsunit, vol_dswidth;
int iosize;
- args->flags2 |= XFSMNT2_COMPAT_IOSIZE;
args->flags |= XFSMNT_IDELETE;
+ args->flags |= XFSMNT_BARRIER;
+ args->flags2 |= XFSMNT2_COMPAT_IOSIZE;
if (!options)
goto done;
@@ -1947,8 +1951,6 @@ xfs_showargs(
seq_printf(m, "," MNTOPT_IKEEP);
if (!(mp->m_flags & XFS_MOUNT_COMPAT_IOSIZE))
seq_printf(m, "," MNTOPT_LARGEIO);
- if (mp->m_flags & XFS_MOUNT_BARRIER)
- seq_printf(m, "," MNTOPT_BARRIER);
if (!(vfsp->vfs_flag & VFS_32BITINODES))
seq_printf(m, "," MNTOPT_64BITINODE);
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
index de49601919c..fa71b305ba5 100644
--- a/fs/xfs/xfs_vnodeops.c
+++ b/fs/xfs/xfs_vnodeops.c
@@ -4649,6 +4649,10 @@ vnodeops_t xfs_vnodeops = {
#ifdef HAVE_SENDFILE
.vop_sendfile = xfs_sendfile,
#endif
+#ifdef HAVE_SPLICE
+ .vop_splice_read = xfs_splice_read,
+ .vop_splice_write = xfs_splice_write,
+#endif
.vop_write = xfs_write,
.vop_ioctl = xfs_ioctl,
.vop_getattr = xfs_getattr,
diff --git a/include/asm-arm/arch-at91rm9200/at91rm9200_mci.h b/include/asm-arm/arch-at91rm9200/at91rm9200_mci.h
new file mode 100644
index 00000000000..f28636d61e3
--- /dev/null
+++ b/include/asm-arm/arch-at91rm9200/at91rm9200_mci.h
@@ -0,0 +1,104 @@
+/*
+ * include/asm-arm/arch-at91rm9200/at91rm9200_mci.h
+ *
+ * Copyright (C) 2005 Ivan Kokshaysky
+ * Copyright (C) SAN People
+ *
+ * MultiMedia Card Interface (MCI) registers.
+ * Based on AT91RM9200 datasheet revision E.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef AT91RM9200_MCI_H
+#define AT91RM9200_MCI_H
+
+#define AT91_MCI_CR 0x00 /* Control Register */
+#define AT91_MCI_MCIEN (1 << 0) /* Multi-Media Interface Enable */
+#define AT91_MCI_MCIDIS (1 << 1) /* Multi-Media Interface Disable */
+#define AT91_MCI_PWSEN (1 << 2) /* Power Save Mode Enable */
+#define AT91_MCI_PWSDIS (1 << 3) /* Power Save Mode Disable */
+#define AT91_MCI_SWRST (1 << 7) /* Software Reset */
+
+#define AT91_MCI_MR 0x04 /* Mode Register */
+#define AT91_MCI_CLKDIV (0xff << 0) /* Clock Divider */
+#define AT91_MCI_PWSDIV (3 << 8) /* Power Saving Divider */
+#define AT91_MCI_PDCPADV (1 << 14) /* PDC Padding Value */
+#define AT91_MCI_PDCMODE (1 << 15) /* PDC-orientated Mode */
+#define AT91_MCI_BLKLEN (0xfff << 18) /* Data Block Length */
+
+#define AT91_MCI_DTOR 0x08 /* Data Timeout Register */
+#define AT91_MCI_DTOCYC (0xf << 0) /* Data Timeout Cycle Number */
+#define AT91_MCI_DTOMUL (7 << 4) /* Data Timeout Multiplier */
+#define AT91_MCI_DTOMUL_1 (0 << 4)
+#define AT91_MCI_DTOMUL_16 (1 << 4)
+#define AT91_MCI_DTOMUL_128 (2 << 4)
+#define AT91_MCI_DTOMUL_256 (3 << 4)
+#define AT91_MCI_DTOMUL_1K (4 << 4)
+#define AT91_MCI_DTOMUL_4K (5 << 4)
+#define AT91_MCI_DTOMUL_64K (6 << 4)
+#define AT91_MCI_DTOMUL_1M (7 << 4)
+
+#define AT91_MCI_SDCR 0x0c /* SD Card Register */
+#define AT91_MCI_SDCSEL (0xf << 0) /* SD Card Selector */
+#define AT91_MCI_SDCBUS (1 << 7) /* 1-bit or 4-bit bus */
+
+#define AT91_MCI_ARGR 0x10 /* Argument Register */
+
+#define AT91_MCI_CMDR 0x14 /* Command Register */
+#define AT91_MCI_CMDNB (0x3f << 0) /* Command Number */
+#define AT91_MCI_RSPTYP (3 << 6) /* Response Type */
+#define AT91_MCI_RSPTYP_NONE (0 << 6)
+#define AT91_MCI_RSPTYP_48 (1 << 6)
+#define AT91_MCI_RSPTYP_136 (2 << 6)
+#define AT91_MCI_SPCMD (7 << 8) /* Special Command */
+#define AT91_MCI_SPCMD_NONE (0 << 8)
+#define AT91_MCI_SPCMD_INIT (1 << 8)
+#define AT91_MCI_SPCMD_SYNC (2 << 8)
+#define AT91_MCI_SPCMD_ICMD (4 << 8)
+#define AT91_MCI_SPCMD_IRESP (5 << 8)
+#define AT91_MCI_OPDCMD (1 << 11) /* Open Drain Command */
+#define AT91_MCI_MAXLAT (1 << 12) /* Max Latency for Command to Response */
+#define AT91_MCI_TRCMD (3 << 16) /* Transfer Command */
+#define AT91_MCI_TRCMD_NONE (0 << 16)
+#define AT91_MCI_TRCMD_START (1 << 16)
+#define AT91_MCI_TRCMD_STOP (2 << 16)
+#define AT91_MCI_TRDIR (1 << 18) /* Transfer Direction */
+#define AT91_MCI_TRTYP (3 << 19) /* Transfer Type */
+#define AT91_MCI_TRTYP_BLOCK (0 << 19)
+#define AT91_MCI_TRTYP_MULTIPLE (1 << 19)
+#define AT91_MCI_TRTYP_STREAM (2 << 19)
+
+#define AT91_MCI_RSPR(n) (0x20 + ((n) * 4)) /* Response Registers 0-3 */
+#define AT91_MCR_RDR 0x30 /* Receive Data Register */
+#define AT91_MCR_TDR 0x34 /* Transmit Data Register */
+
+#define AT91_MCI_SR 0x40 /* Status Register */
+#define AT91_MCI_CMDRDY (1 << 0) /* Command Ready */
+#define AT91_MCI_RXRDY (1 << 1) /* Receiver Ready */
+#define AT91_MCI_TXRDY (1 << 2) /* Transmit Ready */
+#define AT91_MCI_BLKE (1 << 3) /* Data Block Ended */
+#define AT91_MCI_DTIP (1 << 4) /* Data Transfer in Progress */
+#define AT91_MCI_NOTBUSY (1 << 5) /* Data Not Busy */
+#define AT91_MCI_ENDRX (1 << 6) /* End of RX Buffer */
+#define AT91_MCI_ENDTX (1 << 7) /* End fo TX Buffer */
+#define AT91_MCI_RXBUFF (1 << 14) /* RX Buffer Full */
+#define AT91_MCI_TXBUFE (1 << 15) /* TX Buffer Empty */
+#define AT91_MCI_RINDE (1 << 16) /* Response Index Error */
+#define AT91_MCI_RDIRE (1 << 17) /* Response Direction Error */
+#define AT91_MCI_RCRCE (1 << 18) /* Response CRC Error */
+#define AT91_MCI_RENDE (1 << 19) /* Response End Bit Error */
+#define AT91_MCI_RTOE (1 << 20) /* Reponse Time-out Error */
+#define AT91_MCI_DCRCE (1 << 21) /* Data CRC Error */
+#define AT91_MCI_DTOE (1 << 22) /* Data Time-out Error */
+#define AT91_MCI_OVRE (1 << 30) /* Overrun */
+#define AT91_MCI_UNRE (1 << 31) /* Underrun */
+
+#define AT91_MCI_IER 0x44 /* Interrupt Enable Register */
+#define AT91_MCI_IDR 0x48 /* Interrupt Disable Register */
+#define AT91_MCI_IMR 0x4c /* Interrupt Mask Register */
+
+#endif
diff --git a/include/asm-arm/arch-at91rm9200/board.h b/include/asm-arm/arch-at91rm9200/board.h
index 2e7d1139a79..4fdef13d01d 100644
--- a/include/asm-arm/arch-at91rm9200/board.h
+++ b/include/asm-arm/arch-at91rm9200/board.h
@@ -38,6 +38,8 @@ extern unsigned long at91_master_clock;
extern int at91_serial_map[AT91_NR_UART];
extern int at91_console_port;
+#include <linux/mtd/partitions.h>
+
/* USB Device */
struct at91_udc_data {
u8 vbus_pin; /* high == host powering us */
@@ -77,4 +79,26 @@ struct at91_usbh_data {
};
extern void __init at91_add_device_usbh(struct at91_usbh_data *data);
+ /* NAND / SmartMedia */
+struct at91_nand_data {
+ u8 enable_pin; /* chip enable */
+ u8 det_pin; /* card detect */
+ u8 rdy_pin; /* ready/busy */
+ u8 ale; /* address line number connected to ALE */
+ u8 cle; /* address line number connected to CLE */
+ struct mtd_partition* (*partition_info)(int, int*);
+};
+extern void __init at91_add_device_nand(struct at91_nand_data *data);
+
+ /* I2C*/
+void __init at91_add_device_i2c(void);
+
+ /* RTC */
+void __init at91_add_device_rtc(void);
+
+ /* LEDs */
+extern u8 at91_leds_cpu;
+extern u8 at91_leds_timer;
+extern void __init at91_init_leds(u8 cpu_led, u8 timer_led);
+
#endif
diff --git a/include/asm-arm/arch-ep93xx/ts72xx.h b/include/asm-arm/arch-ep93xx/ts72xx.h
index 412215e77f4..a94f63ff053 100644
--- a/include/asm-arm/arch-ep93xx/ts72xx.h
+++ b/include/asm-arm/arch-ep93xx/ts72xx.h
@@ -12,6 +12,8 @@
* febfc000 [67]0000000 4K NAND data register
* febfb000 [67]0400000 4K NAND control register
* febfa000 [67]0800000 4K NAND busy register
+ * febf9000 10800000 4K TS-5620 RTC index register
+ * febf8000 11700000 4K TS-5620 RTC data register
*/
#define TS72XX_MODEL_PHYS_BASE 0x22000000
@@ -58,6 +60,15 @@
#define TS72XX_NAND_BUSY_SIZE 0x00001000
+#define TS72XX_RTC_INDEX_VIRT_BASE 0xfebf9000
+#define TS72XX_RTC_INDEX_PHYS_BASE 0x10800000
+#define TS72XX_RTC_INDEX_SIZE 0x00001000
+
+#define TS72XX_RTC_DATA_VIRT_BASE 0xfebf8000
+#define TS72XX_RTC_DATA_PHYS_BASE 0x11700000
+#define TS72XX_RTC_DATA_SIZE 0x00001000
+
+
#ifndef __ASSEMBLY__
#include <asm/io.h>
diff --git a/include/asm-arm/arch-imx/dma.h b/include/asm-arm/arch-imx/dma.h
index b45fa367d71..621ff2c730f 100644
--- a/include/asm-arm/arch-imx/dma.h
+++ b/include/asm-arm/arch-imx/dma.h
@@ -17,27 +17,16 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+
#ifndef __ASM_ARCH_DMA_H
#define __ASM_ARCH_DMA_H
-/*
- * DMA registration
- */
-
typedef enum {
DMA_PRIO_HIGH = 0,
- DMA_PRIO_MEDIUM = 3,
- DMA_PRIO_LOW = 6
+ DMA_PRIO_MEDIUM = 1,
+ DMA_PRIO_LOW = 2
} imx_dma_prio;
-int imx_request_dma(char *name, imx_dma_prio prio,
- void (*irq_handler) (int, void *, struct pt_regs *),
- void (*err_handler) (int, void *, struct pt_regs *),
- void *data);
-
-void imx_free_dma(int dma_ch);
-
-
#define DMA_REQ_UART3_T 2
#define DMA_REQ_UART3_R 3
#define DMA_REQ_SSI2_T 4
diff --git a/include/asm-arm/arch-imx/imx-dma.h b/include/asm-arm/arch-imx/imx-dma.h
new file mode 100644
index 00000000000..f2063c1d610
--- /dev/null
+++ b/include/asm-arm/arch-imx/imx-dma.h
@@ -0,0 +1,90 @@
+/*
+ * linux/include/asm-arm/imxads/dma.h
+ *
+ * Copyright (C) 1997,1998 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <asm/dma.h>
+
+#ifndef __ASM_ARCH_IMX_DMA_H
+#define __ASM_ARCH_IMX_DMA_H
+
+#define IMX_DMA_CHANNELS 11
+
+/*
+ * struct imx_dma_channel - i.MX specific DMA extension
+ * @name: name specified by DMA client
+ * @irq_handler: client callback for end of transfer
+ * @err_handler: client callback for error condition
+ * @data: clients context data for callbacks
+ * @dma_mode: direction of the transfer %DMA_MODE_READ or %DMA_MODE_WRITE
+ * @sg: pointer to the actual read/written chunk for scatter-gather emulation
+ * @sgbc: counter of processed bytes in the actual read/written chunk
+ * @resbytes: total residual number of bytes to transfer
+ * (it can be lower or same as sum of SG mapped chunk sizes)
+ * @sgcount: number of chunks to be read/written
+ *
+ * Structure is used for IMX DMA processing. It would be probably good
+ * @struct dma_struct in the future for external interfacing and use
+ * @struct imx_dma_channel only as extension to it.
+ */
+
+struct imx_dma_channel {
+ const char *name;
+ void (*irq_handler) (int, void *, struct pt_regs *);
+ void (*err_handler) (int, void *, struct pt_regs *);
+ void *data;
+ dmamode_t dma_mode;
+ struct scatterlist *sg;
+ unsigned int sgbc;
+ unsigned int sgcount;
+ unsigned int resbytes;
+ int dma_num;
+};
+
+extern struct imx_dma_channel imx_dma_channels[IMX_DMA_CHANNELS];
+
+
+/* The type to distinguish channel numbers parameter from ordinal int type */
+typedef int imx_dmach_t;
+
+int
+imx_dma_setup_single(imx_dmach_t dma_ch, dma_addr_t dma_address,
+ unsigned int dma_length, unsigned int dev_addr, dmamode_t dmamode);
+
+int
+imx_dma_setup_sg(imx_dmach_t dma_ch,
+ struct scatterlist *sg, unsigned int sgcount, unsigned int dma_length,
+ unsigned int dev_addr, dmamode_t dmamode);
+
+int
+imx_dma_setup_handlers(imx_dmach_t dma_ch,
+ void (*irq_handler) (int, void *, struct pt_regs *),
+ void (*err_handler) (int, void *, struct pt_regs *), void *data);
+
+void imx_dma_enable(imx_dmach_t dma_ch);
+
+void imx_dma_disable(imx_dmach_t dma_ch);
+
+int imx_dma_request(imx_dmach_t dma_ch, const char *name);
+
+void imx_dma_free(imx_dmach_t dma_ch);
+
+int imx_dma_request_by_prio(imx_dmach_t *pdma_ch, const char *name, imx_dma_prio prio);
+
+
+#endif /* _ASM_ARCH_IMX_DMA_H */
diff --git a/include/asm-arm/arch-imx/mmc.h b/include/asm-arm/arch-imx/mmc.h
new file mode 100644
index 00000000000..1937151665c
--- /dev/null
+++ b/include/asm-arm/arch-imx/mmc.h
@@ -0,0 +1,12 @@
+#ifndef ASMARM_ARCH_MMC_H
+#define ASMARM_ARCH_MMC_H
+
+#include <linux/mmc/protocol.h>
+
+struct imxmmc_platform_data {
+ int (*card_present)(void);
+};
+
+extern void imx_set_mmc_info(struct imxmmc_platform_data *info);
+
+#endif
diff --git a/include/asm-arm/arch-ixp23xx/memory.h b/include/asm-arm/arch-ixp23xx/memory.h
index bebcf0aa0d7..6e19f46d54d 100644
--- a/include/asm-arm/arch-ixp23xx/memory.h
+++ b/include/asm-arm/arch-ixp23xx/memory.h
@@ -28,6 +28,7 @@
* to an address that the kernel can use.
*/
#ifndef __ASSEMBLY__
+#include <asm/mach-types.h>
#define __virt_to_bus(v) \
({ unsigned int ret; \
@@ -40,6 +41,22 @@
data = *((volatile int *)IXP23XX_PCI_SDRAM_BAR); \
__phys_to_virt((((b - (data & 0xfffffff0)) + 0x00000000))); })
+/*
+ * Coherency support. Only supported on A2 CPUs or on A1
+ * systems that have the cache coherency workaround.
+ */
+static inline int __ixp23xx_arch_is_coherent(void)
+{
+ extern unsigned int processor_id;
+
+ if (((processor_id & 15) >= 2) || machine_is_roadrunner())
+ return 1;
+
+ return 0;
+}
+
+#define arch_is_coherent() __ixp23xx_arch_is_coherent()
+
#endif
diff --git a/include/asm-arm/arch-ixp23xx/platform.h b/include/asm-arm/arch-ixp23xx/platform.h
index f85b4685a49..e4d99060a04 100644
--- a/include/asm-arm/arch-ixp23xx/platform.h
+++ b/include/asm-arm/arch-ixp23xx/platform.h
@@ -22,6 +22,7 @@ void ixp23xx_sys_init(void);
int ixp23xx_pci_setup(int, struct pci_sys_data *);
void ixp23xx_pci_preinit(void);
struct pci_bus *ixp23xx_pci_scan_bus(int, struct pci_sys_data*);
+void ixp23xx_pci_slave_init(void);
extern struct sys_timer ixp23xx_timer;
diff --git a/include/asm-arm/arch-omap/aic23.h b/include/asm-arm/arch-omap/aic23.h
index 590bac25b7c..6513065941d 100644
--- a/include/asm-arm/arch-omap/aic23.h
+++ b/include/asm-arm/arch-omap/aic23.h
@@ -57,6 +57,7 @@
#define LHV_MIN 0x0000
// Analog audio path control register
+#define STA_REG(x) ((x)<<6)
#define STE_ENABLED 0x0020
#define DAC_SELECTED 0x0010
#define BYPASS_ON 0x0008
@@ -109,4 +110,7 @@
#define TLV320AIC23ID1 (0x1a) // cs low
#define TLV320AIC23ID2 (0x1b) // cs high
+void tlv320aic23_power_up(void);
+void tlv320aic23_power_down(void);
+
#endif /* __ASM_ARCH_AIC23_H */
diff --git a/include/asm-arm/arch-omap/board-ams-delta.h b/include/asm-arm/arch-omap/board-ams-delta.h
new file mode 100644
index 00000000000..0070f6d3b75
--- /dev/null
+++ b/include/asm-arm/arch-omap/board-ams-delta.h
@@ -0,0 +1,65 @@
+/*
+ * linux/include/asm-arm/arch-omap/board-ams-delta.h
+ *
+ * Copyright (C) 2006 Jonathan McDowell <noodles@earth.li>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef __ASM_ARCH_OMAP_AMS_DELTA_H
+#define __ASM_ARCH_OMAP_AMS_DELTA_H
+
+#if defined (CONFIG_MACH_AMS_DELTA)
+
+#define AMS_DELTA_LATCH1_PHYS 0x01000000
+#define AMS_DELTA_LATCH1_VIRT 0xEA000000
+#define AMS_DELTA_MODEM_PHYS 0x04000000
+#define AMS_DELTA_MODEM_VIRT 0xEB000000
+#define AMS_DELTA_LATCH2_PHYS 0x08000000
+#define AMS_DELTA_LATCH2_VIRT 0xEC000000
+
+#define AMS_DELTA_LATCH1_LED_CAMERA 0x01
+#define AMS_DELTA_LATCH1_LED_ADVERT 0x02
+#define AMS_DELTA_LATCH1_LED_EMAIL 0x04
+#define AMS_DELTA_LATCH1_LED_HANDSFREE 0x08
+#define AMS_DELTA_LATCH1_LED_VOICEMAIL 0x10
+#define AMS_DELTA_LATCH1_LED_VOICE 0x20
+
+#define AMS_DELTA_LATCH2_LCD_VBLEN 0x0001
+#define AMS_DELTA_LATCH2_LCD_NDISP 0x0002
+#define AMS_DELTA_LATCH2_NAND_NCE 0x0004
+#define AMS_DELTA_LATCH2_NAND_NRE 0x0008
+#define AMS_DELTA_LATCH2_NAND_NWP 0x0010
+#define AMS_DELTA_LATCH2_NAND_NWE 0x0020
+#define AMS_DELTA_LATCH2_NAND_ALE 0x0040
+#define AMS_DELTA_LATCH2_NAND_CLE 0x0080
+#define AMS_DELTA_LATCH2_MODEM_NRESET 0x1000
+#define AMS_DELTA_LATCH2_MODEM_CODEC 0x2000
+
+#define AMS_DELTA_GPIO_PIN_NAND_RB 12
+
+#ifndef __ASSEMBLY__
+void ams_delta_latch1_write(u8 mask, u8 value);
+void ams_delta_latch2_write(u16 mask, u16 value);
+#endif
+
+#endif /* CONFIG_MACH_AMS_DELTA */
+
+#endif /* __ASM_ARCH_OMAP_AMS_DELTA_H */
diff --git a/include/asm-arm/arch-omap/board-apollon.h b/include/asm-arm/arch-omap/board-apollon.h
new file mode 100644
index 00000000000..de0c5b792c5
--- /dev/null
+++ b/include/asm-arm/arch-omap/board-apollon.h
@@ -0,0 +1,45 @@
+/*
+ * linux/include/asm-arm/arch-omap/board-apollon.h
+ *
+ * Hardware definitions for Samsung OMAP24XX Apollon board.
+ *
+ * Initial creation by Kyungmin Park <kyungmin.park@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __ASM_ARCH_OMAP_APOLLON_H
+#define __ASM_ARCH_OMAP_APOLLON_H
+
+/* Placeholder for APOLLON specific defines */
+/* GPMC CS0 */
+#define APOLLON_CS0_BASE 0x00000000
+/* GPMC CS1 */
+#define APOLLON_CS1_BASE 0x08000000
+#define APOLLON_ETHR_START (APOLLON_CS1_BASE + 0x300)
+#define APOLLON_ETHR_GPIO_IRQ 74
+/* GPMC CS2 - reserved for OneNAND */
+#define APOLLON_CS2_BASE 0x10000000
+/* GPMC CS3 - reserved for NOR or NAND */
+#define APOLLON_CS3_BASE 0x18000000
+
+#endif /* __ASM_ARCH_OMAP_APOLLON_H */
+
diff --git a/include/asm-arm/arch-omap/board-h2.h b/include/asm-arm/arch-omap/board-h2.h
index 39ca5a31aee..b2888ef9e9b 100644
--- a/include/asm-arm/arch-omap/board-h2.h
+++ b/include/asm-arm/arch-omap/board-h2.h
@@ -34,9 +34,5 @@
/* At OMAP1610 Innovator the Ethernet is directly connected to CS1 */
#define OMAP1610_ETHR_START 0x04000300
-/* Samsung NAND flash at CS2B or CS3(NAND Boot) */
-#define OMAP_NAND_FLASH_START1 0x0A000000 /* CS2B */
-#define OMAP_NAND_FLASH_START2 0x0C000000 /* CS3 */
-
#endif /* __ASM_ARCH_OMAP_H2_H */
diff --git a/include/asm-arm/arch-omap/board-h3.h b/include/asm-arm/arch-omap/board-h3.h
index 1b12c1dcc2f..761ea0a1789 100644
--- a/include/asm-arm/arch-omap/board-h3.h
+++ b/include/asm-arm/arch-omap/board-h3.h
@@ -30,10 +30,6 @@
/* In OMAP1710 H3 the Ethernet is directly connected to CS1 */
#define OMAP1710_ETHR_START 0x04000300
-/* Samsung NAND flash at CS2B or CS3(NAND Boot) */
-#define OMAP_NAND_FLASH_START1 0x0A000000 /* CS2B */
-#define OMAP_NAND_FLASH_START2 0x0C000000 /* CS3 */
-
#define MAXIRQNUM (IH_BOARD_BASE)
#define MAXFIQNUM MAXIRQNUM
#define MAXSWINUM MAXIRQNUM
diff --git a/include/asm-arm/arch-omap/board-h4.h b/include/asm-arm/arch-omap/board-h4.h
index 33ea29a4165..7ef664bc9e3 100644
--- a/include/asm-arm/arch-omap/board-h4.h
+++ b/include/asm-arm/arch-omap/board-h4.h
@@ -33,12 +33,6 @@
/* GPMC CS1 */
#define OMAP24XX_ETHR_START 0x08000300
#define OMAP24XX_ETHR_GPIO_IRQ 92
-
-#define H4_CS0_BASE 0x04000000
-
-#define H4_CS0_BASE 0x04000000
-
-#define H4_CS0_BASE 0x04000000
-
+#define H4_CS0_BASE 0x04000000
#endif /* __ASM_ARCH_OMAP_H4_H */
diff --git a/include/asm-arm/arch-omap/board-netstar.h b/include/asm-arm/arch-omap/board-netstar.h
deleted file mode 100644
index 77cc0fb54d5..00000000000
--- a/include/asm-arm/arch-omap/board-netstar.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2004 2N Telekomunikace, Ladislav Michl <michl@2n.cz>
- *
- * Hardware definitions for OMAP5910 based NetStar board.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __ASM_ARCH_NETSTAR_H
-#define __ASM_ARCH_NETSTAR_H
-
-#include <asm/arch/tc.h>
-
-#define OMAP_NAND_FLASH_START1 OMAP_CS1_PHYS + (1 << 23)
-#define OMAP_NAND_FLASH_START2 OMAP_CS1_PHYS + (2 << 23)
-
-#endif /* __ASM_ARCH_NETSTAR_H */
diff --git a/include/asm-arm/arch-omap/board-nokia.h b/include/asm-arm/arch-omap/board-nokia.h
new file mode 100644
index 00000000000..72deea20349
--- /dev/null
+++ b/include/asm-arm/arch-omap/board-nokia.h
@@ -0,0 +1,54 @@
+/*
+ * linux/include/asm-arm/arch-omap/board-nokia.h
+ *
+ * Information structures for Nokia-specific board config data
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ */
+
+#ifndef _OMAP_BOARD_NOKIA_H
+#define _OMAP_BOARD_NOKIA_H
+
+#include <linux/types.h>
+
+#define OMAP_TAG_NOKIA_BT 0x4e01
+#define OMAP_TAG_WLAN_CX3110X 0x4e02
+#define OMAP_TAG_CBUS 0x4e03
+#define OMAP_TAG_EM_ASIC_BB5 0x4e04
+
+
+#define BT_CHIP_CSR 1
+#define BT_CHIP_TI 2
+
+#define BT_SYSCLK_12 1
+#define BT_SYSCLK_38_4 2
+
+struct omap_bluetooth_config {
+ u8 chip_type;
+ u8 bt_wakeup_gpio;
+ u8 host_wakeup_gpio;
+ u8 reset_gpio;
+ u8 bt_uart;
+ u8 bd_addr[6];
+ u8 bt_sysclk;
+};
+
+struct omap_wlan_cx3110x_config {
+ u8 chip_type;
+ s16 power_gpio;
+ s16 irq_gpio;
+ s16 spi_cs_gpio;
+};
+
+struct omap_cbus_config {
+ s16 clk_gpio;
+ s16 dat_gpio;
+ s16 sel_gpio;
+};
+
+struct omap_em_asic_bb5_config {
+ s16 retu_irq_gpio;
+ s16 tahvo_irq_gpio;
+};
+
+#endif
diff --git a/include/asm-arm/arch-omap/board-perseus2.h b/include/asm-arm/arch-omap/board-perseus2.h
index 691e52a52b4..eb74420cb43 100644
--- a/include/asm-arm/arch-omap/board-perseus2.h
+++ b/include/asm-arm/arch-omap/board-perseus2.h
@@ -42,8 +42,4 @@
#define NR_IRQS (MAXIRQNUM + 1)
-/* Samsung NAND flash at CS2B or CS3(NAND Boot) */
-#define OMAP_NAND_FLASH_START1 0x0A000000 /* CS2B */
-#define OMAP_NAND_FLASH_START2 0x0C000000 /* CS3 */
-
#endif
diff --git a/include/asm-arm/arch-omap/board.h b/include/asm-arm/arch-omap/board.h
index a0040cd8663..6d6240a4681 100644
--- a/include/asm-arm/arch-omap/board.h
+++ b/include/asm-arm/arch-omap/board.h
@@ -21,9 +21,12 @@
#define OMAP_TAG_LCD 0x4f05
#define OMAP_TAG_GPIO_SWITCH 0x4f06
#define OMAP_TAG_UART 0x4f07
+#define OMAP_TAG_FBMEM 0x4f08
+#define OMAP_TAG_STI_CONSOLE 0x4f09
#define OMAP_TAG_BOOT_REASON 0x4f80
#define OMAP_TAG_FLASH_PART 0x4f81
+#define OMAP_TAG_VERSION_STR 0x4f82
struct omap_clock_config {
/* 0 for 12 MHz, 1 for 13 MHz and 2 for 19.2 MHz */
@@ -54,6 +57,11 @@ struct omap_serial_console_config {
u32 console_speed;
};
+struct omap_sti_console_config {
+ unsigned enable:1;
+ u8 channel;
+};
+
struct omap_usb_config {
/* Configure drivers according to the connectors on your board:
* - "A" connector (rectagular)
@@ -87,6 +95,13 @@ struct omap_lcd_config {
char ctrl_name[16];
};
+struct omap_fbmem_config {
+ u32 fb_sram_start;
+ u32 fb_sram_size;
+ u32 fb_sdram_start;
+ u32 fb_sdram_size;
+};
+
/* Cover:
* high -> closed
* low -> open
@@ -106,6 +121,12 @@ struct omap_gpio_switch_config {
int key_code:24; /* Linux key code */
};
+struct omap_uart_config {
+ /* Bit field of UARTs present; bit 0 --> UART1 */
+ unsigned int enabled_uarts;
+};
+
+
struct omap_flash_part_config {
char part_table[0];
};
@@ -114,11 +135,14 @@ struct omap_boot_reason_config {
char reason_str[12];
};
-struct omap_uart_config {
- /* Bit field of UARTs present; bit 0 --> UART1 */
- unsigned int enabled_uarts;
+struct omap_version_config {
+ char component[12];
+ char version[12];
};
+
+#include <asm-arm/arch-omap/board-nokia.h>
+
struct omap_board_config_entry {
u16 tag;
u16 len;
diff --git a/include/asm-arm/arch-omap/clock.h b/include/asm-arm/arch-omap/clock.h
index 46a0402696d..3c4eb9fbe48 100644
--- a/include/asm-arm/arch-omap/clock.h
+++ b/include/asm-arm/arch-omap/clock.h
@@ -19,6 +19,7 @@ struct clk {
struct list_head node;
struct module *owner;
const char *name;
+ int id;
struct clk *parent;
unsigned long rate;
__u32 flags;
@@ -57,6 +58,7 @@ extern void propagate_rate(struct clk *clk);
extern void followparent_recalc(struct clk * clk);
extern void clk_allow_idle(struct clk *clk);
extern void clk_deny_idle(struct clk *clk);
+extern int clk_get_usecount(struct clk *clk);
/* Clock flags */
#define RATE_CKCTL (1 << 0) /* Main fixed ratio clocks */
@@ -80,10 +82,11 @@ extern void clk_deny_idle(struct clk *clk);
#define CM_PLL_SEL1 (1 << 18)
#define CM_PLL_SEL2 (1 << 19)
#define CM_SYSCLKOUT_SEL1 (1 << 20)
-#define CLOCK_IN_OMAP730 (1 << 21)
-#define CLOCK_IN_OMAP1510 (1 << 22)
-#define CLOCK_IN_OMAP16XX (1 << 23)
-#define CLOCK_IN_OMAP242X (1 << 24)
-#define CLOCK_IN_OMAP243X (1 << 25)
+#define CLOCK_IN_OMAP310 (1 << 21)
+#define CLOCK_IN_OMAP730 (1 << 22)
+#define CLOCK_IN_OMAP1510 (1 << 23)
+#define CLOCK_IN_OMAP16XX (1 << 24)
+#define CLOCK_IN_OMAP242X (1 << 25)
+#define CLOCK_IN_OMAP243X (1 << 26)
#endif
diff --git a/include/asm-arm/arch-omap/dma.h b/include/asm-arm/arch-omap/dma.h
index d4e73efcb81..ca1202312a4 100644
--- a/include/asm-arm/arch-omap/dma.h
+++ b/include/asm-arm/arch-omap/dma.h
@@ -404,6 +404,7 @@ extern void omap_free_lcd_dma(void);
extern void omap_setup_lcd_dma(void);
extern void omap_enable_lcd_dma(void);
extern void omap_stop_lcd_dma(void);
+extern int omap_lcd_dma_ext_running(void);
extern void omap_set_lcd_dma_ext_controller(int external);
extern void omap_set_lcd_dma_single_transfer(int single);
extern void omap_set_lcd_dma_b1(unsigned long addr, u16 fb_xres, u16 fb_yres,
diff --git a/include/asm-arm/arch-omap/dmtimer.h b/include/asm-arm/arch-omap/dmtimer.h
index 11772c792f3..e6522e6a383 100644
--- a/include/asm-arm/arch-omap/dmtimer.h
+++ b/include/asm-arm/arch-omap/dmtimer.h
@@ -88,5 +88,6 @@ unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer);
void omap_dm_timer_reset_counter(struct omap_dm_timer *timer);
int omap_dm_timers_active(void);
+u32 omap_dm_timer_modify_idlect_mask(u32 inputmask);
#endif /* __ASM_ARCH_TIMER_H */
diff --git a/include/asm-arm/arch-omap/dsp.h b/include/asm-arm/arch-omap/dsp.h
index 57bf4f39ca5..06dad83dd41 100644
--- a/include/asm-arm/arch-omap/dsp.h
+++ b/include/asm-arm/arch-omap/dsp.h
@@ -181,10 +181,16 @@ struct omap_dsp_varinfo {
#define OMAP_DSP_MBCMD_PM_ENABLE 0x01
#define OMAP_DSP_MBCMD_KFUNC_FBCTL 0x00
+#define OMAP_DSP_MBCMD_KFUNC_AUDIO_PWR 0x01
+#define OMAP_DSP_MBCMD_FBCTL_UPD 0x0000
#define OMAP_DSP_MBCMD_FBCTL_ENABLE 0x0002
#define OMAP_DSP_MBCMD_FBCTL_DISABLE 0x0003
+#define OMAP_DSP_MBCMD_AUDIO_PWR_UP 0x0000
+#define OMAP_DSP_MBCMD_AUDIO_PWR_DOWN1 0x0001
+#define OMAP_DSP_MBCMD_AUDIO_PWR_DOWN2 0x0002
+
#define OMAP_DSP_MBCMD_TDEL_SAFE 0x0000
#define OMAP_DSP_MBCMD_TDEL_KILL 0x0001
diff --git a/include/asm-arm/arch-omap/dsp_common.h b/include/asm-arm/arch-omap/dsp_common.h
index 4fcce694405..16a459dfa71 100644
--- a/include/asm-arm/arch-omap/dsp_common.h
+++ b/include/asm-arm/arch-omap/dsp_common.h
@@ -27,11 +27,12 @@
#ifndef ASM_ARCH_DSP_COMMON_H
#define ASM_ARCH_DSP_COMMON_H
-void omap_dsp_pm_suspend(void);
-void omap_dsp_pm_resume(void);
-void omap_dsp_request_mpui(void);
-void omap_dsp_release_mpui(void);
-int omap_dsp_request_mem(void);
-int omap_dsp_release_mem(void);
+extern void omap_dsp_request_mpui(void);
+extern void omap_dsp_release_mpui(void);
+extern int omap_dsp_request_mem(void);
+extern int omap_dsp_release_mem(void);
+
+extern void (*omap_dsp_audio_pwr_up_request)(int stage);
+extern void (*omap_dsp_audio_pwr_down_request)(int stage);
#endif /* ASM_ARCH_DSP_COMMON_H */
diff --git a/include/asm-arm/arch-omap/gpioexpander.h b/include/asm-arm/arch-omap/gpioexpander.h
new file mode 100644
index 00000000000..7a43b0a912e
--- /dev/null
+++ b/include/asm-arm/arch-omap/gpioexpander.h
@@ -0,0 +1,24 @@
+/*
+ * linux/include/asm-arm/arch-omap/gpioexpander.h
+ *
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef __ASM_ARCH_OMAP_GPIOEXPANDER_H
+#define __ASM_ARCH_OMAP_GPIOEXPANDER_H
+
+/* Function Prototypes for GPIO Expander functions */
+
+int read_gpio_expa(u8 *, int);
+int write_gpio_expa(u8 , int);
+
+#endif /* __ASM_ARCH_OMAP_GPIOEXPANDER_H */
diff --git a/include/asm-arm/arch-omap/hardware.h b/include/asm-arm/arch-omap/hardware.h
index 5406b875c42..7909b729826 100644
--- a/include/asm-arm/arch-omap/hardware.h
+++ b/include/asm-arm/arch-omap/hardware.h
@@ -306,6 +306,10 @@
#include "board-h4.h"
#endif
+#ifdef CONFIG_MACH_OMAP_APOLLON
+#include "board-apollon.h"
+#endif
+
#ifdef CONFIG_MACH_OMAP_OSK
#include "board-osk.h"
#endif
@@ -314,10 +318,6 @@
#include "board-voiceblue.h"
#endif
-#ifdef CONFIG_MACH_NETSTAR
-#include "board-netstar.h"
-#endif
-
#endif /* !__ASSEMBLER__ */
#endif /* __ASM_ARCH_OMAP_HARDWARE_H */
diff --git a/include/asm-arm/arch-omap/irda.h b/include/asm-arm/arch-omap/irda.h
new file mode 100644
index 00000000000..805ae3575e4
--- /dev/null
+++ b/include/asm-arm/arch-omap/irda.h
@@ -0,0 +1,36 @@
+/*
+ * linux/include/asm-arm/arch-omap/irda.h
+ *
+ * Copyright (C) 2005-2006 Komal Shah <komal_shah802003@yahoo.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef ASMARM_ARCH_IRDA_H
+#define ASMARM_ARCH_IRDA_H
+
+/* board specific transceiver capabilities */
+
+#define IR_SEL 1 /* Selects IrDA */
+#define IR_SIRMODE 2
+#define IR_FIRMODE 4
+#define IR_MIRMODE 8
+
+struct omap_irda_config {
+ int transceiver_cap;
+ int (*transceiver_mode)(struct device *dev, int mode);
+ int (*select_irda)(struct device *dev, int state);
+ /* Very specific to the needs of some platforms (h3,h4)
+ * having calls which can sleep in irda_set_speed.
+ */
+ struct work_struct gpio_expa;
+ int rx_channel;
+ int tx_channel;
+ unsigned long dest_start;
+ unsigned long src_start;
+ int tx_trigger;
+ int rx_trigger;
+};
+
+#endif
diff --git a/include/asm-arm/arch-omap/irqs.h b/include/asm-arm/arch-omap/irqs.h
index 4ffce1d7775..42098d99f30 100644
--- a/include/asm-arm/arch-omap/irqs.h
+++ b/include/asm-arm/arch-omap/irqs.h
@@ -242,6 +242,11 @@
#define INT_24XX_GPIO_BANK2 30
#define INT_24XX_GPIO_BANK3 31
#define INT_24XX_GPIO_BANK4 32
+#define INT_24XX_MCBSP1_IRQ_TX 59
+#define INT_24XX_MCBSP1_IRQ_RX 60
+#define INT_24XX_MCBSP2_IRQ_TX 62
+#define INT_24XX_MCBSP2_IRQ_RX 63
+#define INT_24XX_UART3_IRQ 74
/* Max. 128 level 2 IRQs (OMAP1610), 192 GPIOs (OMAP730) and
* 16 MPUIO lines */
diff --git a/include/asm-arm/arch-omap/keypad.h b/include/asm-arm/arch-omap/keypad.h
new file mode 100644
index 00000000000..8a023a984ac
--- /dev/null
+++ b/include/asm-arm/arch-omap/keypad.h
@@ -0,0 +1,36 @@
+/*
+ * linux/include/asm-arm/arch-omap/keypad.h
+ *
+ * Copyright (C) 2006 Komal Shah <komal_shah802003@yahoo.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef ASMARM_ARCH_KEYPAD_H
+#define ASMARM_ARCH_KEYPAD_H
+
+struct omap_kp_platform_data {
+ int rows;
+ int cols;
+ int *keymap;
+ unsigned int rep:1;
+ /* specific to OMAP242x*/
+ unsigned int *row_gpios;
+ unsigned int *col_gpios;
+};
+
+/* Group (0..3) -- when multiple keys are pressed, only the
+ * keys pressed in the same group are considered as pressed. This is
+ * in order to workaround certain crappy HW designs that produce ghost
+ * keypresses. */
+#define GROUP_0 (0 << 16)
+#define GROUP_1 (1 << 16)
+#define GROUP_2 (2 << 16)
+#define GROUP_3 (3 << 16)
+#define GROUP_MASK GROUP_3
+
+#define KEY(col, row, val) (((col) << 28) | ((row) << 24) | (val))
+
+#endif
+
diff --git a/include/asm-arm/arch-omap/lcd_lph8923.h b/include/asm-arm/arch-omap/lcd_lph8923.h
new file mode 100644
index 00000000000..004e67e22ca
--- /dev/null
+++ b/include/asm-arm/arch-omap/lcd_lph8923.h
@@ -0,0 +1,14 @@
+#ifndef __LCD_LPH8923_H
+#define __LCD_LPH8923_H
+
+enum lcd_lph8923_test_num {
+ LCD_LPH8923_TEST_RGB_LINES,
+};
+
+enum lcd_lph8923_test_result {
+ LCD_LPH8923_TEST_SUCCESS,
+ LCD_LPH8923_TEST_INVALID,
+ LCD_LPH8923_TEST_FAILED,
+};
+
+#endif
diff --git a/include/asm-arm/arch-omap/mcbsp.h b/include/asm-arm/arch-omap/mcbsp.h
index e79d98ab2ab..ed0dde4f721 100644
--- a/include/asm-arm/arch-omap/mcbsp.h
+++ b/include/asm-arm/arch-omap/mcbsp.h
@@ -37,6 +37,11 @@
#define OMAP1610_MCBSP2_BASE 0xfffb1000
#define OMAP1610_MCBSP3_BASE 0xe1017000
+#define OMAP24XX_MCBSP1_BASE 0x48074000
+#define OMAP24XX_MCBSP2_BASE 0x48076000
+
+#if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP730)
+
#define OMAP_MCBSP_REG_DRR2 0x00
#define OMAP_MCBSP_REG_DRR1 0x02
#define OMAP_MCBSP_REG_DXR2 0x04
@@ -71,9 +76,62 @@
#define OMAP_MAX_MCBSP_COUNT 3
+#define AUDIO_MCBSP_DATAWRITE (OMAP1510_MCBSP1_BASE + OMAP_MCBSP_REG_DXR1)
+#define AUDIO_MCBSP_DATAREAD (OMAP1510_MCBSP1_BASE + OMAP_MCBSP_REG_DRR1)
+
+#define AUDIO_MCBSP OMAP_MCBSP1
+#define AUDIO_DMA_TX OMAP_DMA_MCBSP1_TX
+#define AUDIO_DMA_RX OMAP_DMA_MCBSP1_RX
+
+#elif defined(CONFIG_ARCH_OMAP24XX)
+
+#define OMAP_MCBSP_REG_DRR2 0x00
+#define OMAP_MCBSP_REG_DRR1 0x04
+#define OMAP_MCBSP_REG_DXR2 0x08
+#define OMAP_MCBSP_REG_DXR1 0x0C
+#define OMAP_MCBSP_REG_SPCR2 0x10
+#define OMAP_MCBSP_REG_SPCR1 0x14
+#define OMAP_MCBSP_REG_RCR2 0x18
+#define OMAP_MCBSP_REG_RCR1 0x1C
+#define OMAP_MCBSP_REG_XCR2 0x20
+#define OMAP_MCBSP_REG_XCR1 0x24
+#define OMAP_MCBSP_REG_SRGR2 0x28
+#define OMAP_MCBSP_REG_SRGR1 0x2C
+#define OMAP_MCBSP_REG_MCR2 0x30
+#define OMAP_MCBSP_REG_MCR1 0x34
+#define OMAP_MCBSP_REG_RCERA 0x38
+#define OMAP_MCBSP_REG_RCERB 0x3C
+#define OMAP_MCBSP_REG_XCERA 0x40
+#define OMAP_MCBSP_REG_XCERB 0x44
+#define OMAP_MCBSP_REG_PCR0 0x48
+#define OMAP_MCBSP_REG_RCERC 0x4C
+#define OMAP_MCBSP_REG_RCERD 0x50
+#define OMAP_MCBSP_REG_XCERC 0x54
+#define OMAP_MCBSP_REG_XCERD 0x58
+#define OMAP_MCBSP_REG_RCERE 0x5C
+#define OMAP_MCBSP_REG_RCERF 0x60
+#define OMAP_MCBSP_REG_XCERE 0x64
+#define OMAP_MCBSP_REG_XCERF 0x68
+#define OMAP_MCBSP_REG_RCERG 0x6C
+#define OMAP_MCBSP_REG_RCERH 0x70
+#define OMAP_MCBSP_REG_XCERG 0x74
+#define OMAP_MCBSP_REG_XCERH 0x78
+
+#define OMAP_MAX_MCBSP_COUNT 2
+
+#define AUDIO_MCBSP_DATAWRITE (OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DXR1)
+#define AUDIO_MCBSP_DATAREAD (OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR1)
+
+#define AUDIO_MCBSP OMAP_MCBSP2
+#define AUDIO_DMA_TX OMAP24XX_DMA_MCBSP2_TX
+#define AUDIO_DMA_RX OMAP24XX_DMA_MCBSP2_RX
+
+#endif
+
#define OMAP_MCBSP_READ(base, reg) __raw_readw((base) + OMAP_MCBSP_REG_##reg)
#define OMAP_MCBSP_WRITE(base, reg, val) __raw_writew((val), (base) + OMAP_MCBSP_REG_##reg)
+
/************************** McBSP SPCR1 bit definitions ***********************/
#define RRST 0x0001
#define RRDY 0x0002
@@ -195,6 +253,10 @@ typedef enum {
OMAP_MCBSP3,
} omap_mcbsp_id;
+typedef int __bitwise omap_mcbsp_io_type_t;
+#define OMAP_MCBSP_IRQ_IO ((__force omap_mcbsp_io_type_t) 1)
+#define OMAP_MCBSP_POLL_IO ((__force omap_mcbsp_io_type_t) 2)
+
typedef enum {
OMAP_MCBSP_WORD_8 = 0,
OMAP_MCBSP_WORD_12,
@@ -246,6 +308,9 @@ u32 omap_mcbsp_recv_word(unsigned int id);
int omap_mcbsp_xmit_buffer(unsigned int id, dma_addr_t buffer, unsigned int length);
int omap_mcbsp_recv_buffer(unsigned int id, dma_addr_t buffer, unsigned int length);
+int omap_mcbsp_spi_master_xmit_word_poll(unsigned int id, u32 word);
+int omap_mcbsp_spi_master_recv_word_poll(unsigned int id, u32 * word);
+
/* SPI specific API */
void omap_mcbsp_set_spi_mode(unsigned int id, const struct omap_mcbsp_spi_cfg * spi_cfg);
diff --git a/include/asm-arm/arch-omap/mcspi.h b/include/asm-arm/arch-omap/mcspi.h
new file mode 100644
index 00000000000..9e7f40a88e1
--- /dev/null
+++ b/include/asm-arm/arch-omap/mcspi.h
@@ -0,0 +1,16 @@
+#ifndef _OMAP2_MCSPI_H
+#define _OMAP2_MCSPI_H
+
+struct omap2_mcspi_platform_config {
+ unsigned long base;
+ unsigned short num_cs;
+};
+
+struct omap2_mcspi_device_config {
+ unsigned turbo_mode:1;
+
+ /* Do we want one channel enabled at the same time? */
+ unsigned single_channel:1;
+};
+
+#endif
diff --git a/include/asm-arm/arch-omap/menelaus.h b/include/asm-arm/arch-omap/menelaus.h
index 46be8b8d634..88cd4c87f0d 100644
--- a/include/asm-arm/arch-omap/menelaus.h
+++ b/include/asm-arm/arch-omap/menelaus.h
@@ -7,7 +7,7 @@
#ifndef __ASM_ARCH_MENELAUS_H
#define __ASM_ARCH_MENELAUS_H
-extern void menelaus_mmc_register(void (*callback)(u8 card_mask),
+extern void menelaus_mmc_register(void (*callback)(unsigned long data, u8 card_mask),
unsigned long data);
extern void menelaus_mmc_remove(void);
extern void menelaus_mmc_opendrain(int enable);
diff --git a/include/asm-arm/arch-omap/mux.h b/include/asm-arm/arch-omap/mux.h
index 13415a9aab0..0dc24d4ba59 100644
--- a/include/asm-arm/arch-omap/mux.h
+++ b/include/asm-arm/arch-omap/mux.h
@@ -112,14 +112,13 @@
* as mux config
*/
#define MUX_CFG_730(desc, mux_reg, mode_offset, mode, \
- pull_reg, pull_bit, pull_status, \
- pu_pd_reg, pu_pd_status, debug_status)\
+ pull_bit, pull_status, debug_status)\
{ \
.name = desc, \
.debug = debug_status, \
MUX_REG_730(mux_reg, mode_offset, mode) \
PULL_REG_730(mux_reg, pull_bit, pull_status) \
- PU_PD_REG(pu_pd_reg, pu_pd_status) \
+ PU_PD_REG(NA, 0) \
},
#define MUX_CFG_24XX(desc, reg_offset, mode, \
@@ -172,6 +171,11 @@ enum omap730_index {
E4_730_KBC2,
F4_730_KBC3,
E3_730_KBC4,
+
+ /* USB */
+ AA17_730_USB_DM,
+ W16_730_USB_PU_EN,
+ W17_730_USB_VBUSI,
};
enum omap1xxx_index {
@@ -403,9 +407,53 @@ enum omap24xx_index {
/* 24xx Menelaus interrupt */
W19_24XX_SYS_NIRQ,
+ /* 24xx clock */
+ W14_24XX_SYS_CLKOUT,
+
+ /* 242X McBSP */
+ Y15_24XX_MCBSP2_CLKX,
+ R14_24XX_MCBSP2_FSX,
+ W15_24XX_MCBSP2_DR,
+ V15_24XX_MCBSP2_DX,
+
/* 24xx GPIO */
+ M21_242X_GPIO11,
+ AA10_242X_GPIO13,
+ AA6_242X_GPIO14,
+ AA4_242X_GPIO15,
+ Y11_242X_GPIO16,
+ AA12_242X_GPIO17,
+ AA8_242X_GPIO58,
Y20_24XX_GPIO60,
+ W4__24XX_GPIO74,
M15_24XX_GPIO92,
+ V14_24XX_GPIO117,
+
+ P20_24XX_TSC_IRQ,
+
+ /* UART3 */
+ K15_24XX_UART3_TX,
+ K14_24XX_UART3_RX,
+
+ /* Keypad GPIO*/
+ T19_24XX_KBR0,
+ R19_24XX_KBR1,
+ V18_24XX_KBR2,
+ M21_24XX_KBR3,
+ E5__24XX_KBR4,
+ M18_24XX_KBR5,
+ R20_24XX_KBC0,
+ M14_24XX_KBC1,
+ H19_24XX_KBC2,
+ V17_24XX_KBC3,
+ P21_24XX_KBC4,
+ L14_24XX_KBC5,
+ N19_24XX_KBC6,
+
+ /* 24xx Menelaus Keypad GPIO */
+ B3__24XX_KBR5,
+ AA4_24XX_KBC2,
+ B13_24XX_KBC6,
};
#ifdef CONFIG_OMAP_MUX
diff --git a/include/asm-arm/arch-omap/omap-alsa.h b/include/asm-arm/arch-omap/omap-alsa.h
new file mode 100644
index 00000000000..df4695474e3
--- /dev/null
+++ b/include/asm-arm/arch-omap/omap-alsa.h
@@ -0,0 +1,124 @@
+/*
+ * linux/include/asm-arm/arch-omap/omap-alsa.h
+ *
+ * Alsa Driver for AIC23 and TSC2101 codecs on OMAP platform boards.
+ *
+ * Copyright (C) 2006 Mika Laitio <lamikr@cc.jyu.fi>
+ *
+ * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ * Written by Daniel Petrini, David Cohen, Anderson Briglia
+ * {daniel.petrini, david.cohen, anderson.briglia}@indt.org.br
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * History
+ * -------
+ *
+ * 2005/07/25 INdT-10LE Kernel Team - Alsa driver for omap osk,
+ * original version based in sa1100 driver
+ * and omap oss driver.
+ */
+
+#ifndef __OMAP_ALSA_H
+#define __OMAP_ALSA_H
+
+#include <sound/driver.h>
+#include <asm/arch/dma.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <asm/arch/mcbsp.h>
+#include <linux/platform_device.h>
+
+#define DMA_BUF_SIZE (1024 * 8)
+
+/*
+ * Buffer management for alsa and dma
+ */
+struct audio_stream {
+ char *id; /* identification string */
+ int stream_id; /* numeric identification */
+ int dma_dev; /* dma number of that device */
+ int *lch; /* Chain of channels this stream is linked to */
+ char started; /* to store if the chain was started or not */
+ int dma_q_head; /* DMA Channel Q Head */
+ int dma_q_tail; /* DMA Channel Q Tail */
+ char dma_q_count; /* DMA Channel Q Count */
+ int active:1; /* we are using this stream for transfer now */
+ int period; /* current transfer period */
+ int periods; /* current count of periods registerd in the DMA engine */
+ spinlock_t dma_lock; /* for locking in DMA operations */
+ snd_pcm_substream_t *stream; /* the pcm stream */
+ unsigned linked:1; /* dma channels linked */
+ int offset; /* store start position of the last period in the alsa buffer */
+ int (*hw_start)(void); /* interface to start HW interface, e.g. McBSP */
+ int (*hw_stop)(void); /* interface to stop HW interface, e.g. McBSP */
+};
+
+/*
+ * Alsa card structure for aic23
+ */
+struct snd_card_omap_codec {
+ snd_card_t *card;
+ snd_pcm_t *pcm;
+ long samplerate;
+ struct audio_stream s[2]; /* playback & capture */
+};
+
+/* Codec specific information and function pointers.
+ * Codec (omap-alsa-aic23.c and omap-alsa-tsc2101.c)
+ * are responsible for defining the function pointers.
+ */
+struct omap_alsa_codec_config {
+ char *name;
+ struct omap_mcbsp_reg_cfg *mcbsp_regs_alsa;
+ snd_pcm_hw_constraint_list_t *hw_constraints_rates;
+ snd_pcm_hardware_t *snd_omap_alsa_playback;
+ snd_pcm_hardware_t *snd_omap_alsa_capture;
+ void (*codec_configure_dev)(void);
+ void (*codec_set_samplerate)(long);
+ void (*codec_clock_setup)(void);
+ int (*codec_clock_on)(void);
+ int (*codec_clock_off)(void);
+ int (*get_default_samplerate)(void);
+};
+
+/*********** Mixer function prototypes *************************/
+int snd_omap_mixer(struct snd_card_omap_codec *);
+void snd_omap_init_mixer(void);
+
+#ifdef CONFIG_PM
+void snd_omap_suspend_mixer(void);
+void snd_omap_resume_mixer(void);
+#endif
+
+int snd_omap_alsa_post_probe(struct platform_device *pdev, struct omap_alsa_codec_config *config);
+int snd_omap_alsa_remove(struct platform_device *pdev);
+#ifdef CONFIG_PM
+int snd_omap_alsa_suspend(struct platform_device *pdev, pm_message_t state);
+int snd_omap_alsa_resume(struct platform_device *pdev);
+#else
+#define snd_omap_alsa_suspend NULL
+#define snd_omap_alsa_resume NULL
+#endif
+
+void callback_omap_alsa_sound_dma(void *);
+
+#endif
diff --git a/include/asm-arm/arch-omap/omapfb.h b/include/asm-arm/arch-omap/omapfb.h
index 4ba2622cc14..fccdb3db025 100644
--- a/include/asm-arm/arch-omap/omapfb.h
+++ b/include/asm-arm/arch-omap/omapfb.h
@@ -34,9 +34,10 @@
#define OMAPFB_MIRROR OMAP_IOW(31, int)
#define OMAPFB_SYNC_GFX OMAP_IO(37)
#define OMAPFB_VSYNC OMAP_IO(38)
-#define OMAPFB_SET_UPDATE_MODE OMAP_IOW(40, enum omapfb_update_mode)
+#define OMAPFB_SET_UPDATE_MODE OMAP_IOW(40, int)
+#define OMAPFB_UPDATE_WINDOW_OLD OMAP_IOW(41, struct omapfb_update_window_old)
#define OMAPFB_GET_CAPS OMAP_IOR(42, unsigned long)
-#define OMAPFB_GET_UPDATE_MODE OMAP_IOW(43, enum omapfb_update_mode)
+#define OMAPFB_GET_UPDATE_MODE OMAP_IOW(43, int)
#define OMAPFB_LCD_TEST OMAP_IOW(45, int)
#define OMAPFB_CTRL_TEST OMAP_IOW(46, int)
#define OMAPFB_UPDATE_WINDOW OMAP_IOW(47, struct omapfb_update_window)
@@ -66,9 +67,14 @@ enum omapfb_color_format {
};
struct omapfb_update_window {
- u32 x, y;
- u32 width, height;
- u32 format;
+ __u32 x, y;
+ __u32 width, height;
+ __u32 format;
+};
+
+struct omapfb_update_window_old {
+ __u32 x, y;
+ __u32 width, height;
};
enum omapfb_plane {
@@ -83,17 +89,17 @@ enum omapfb_channel_out {
};
struct omapfb_setup_plane {
- u8 plane;
- u8 channel_out;
- u32 offset;
- u32 pos_x, pos_y;
- u32 width, height;
- u32 color_mode;
+ __u8 plane;
+ __u8 channel_out;
+ __u32 offset;
+ __u32 pos_x, pos_y;
+ __u32 width, height;
+ __u32 color_mode;
};
struct omapfb_enable_plane {
- u8 plane;
- u8 enable;
+ __u8 plane;
+ __u8 enable;
};
enum omapfb_color_key_type {
@@ -103,10 +109,10 @@ enum omapfb_color_key_type {
};
struct omapfb_color_key {
- u8 channel_out;
- u32 background;
- u32 trans_key;
- u8 key_type;
+ __u8 channel_out;
+ __u32 background;
+ __u32 trans_key;
+ __u8 key_type;
};
enum omapfb_update_mode {
@@ -120,6 +126,9 @@ enum omapfb_update_mode {
#include <linux/completion.h>
#include <linux/interrupt.h>
#include <linux/fb.h>
+#include <linux/mutex.h>
+
+#include <asm/arch/board.h>
#define OMAP_LCDC_INV_VSYNC 0x0001
#define OMAP_LCDC_INV_HSYNC 0x0002
@@ -184,19 +193,38 @@ struct extif_timings {
int re_cycle_time;
int cs_pulse_width;
int access_time;
+
+ int clk_div;
+
+ u32 tim[5]; /* set by extif->convert_timings */
+
+ int converted;
};
struct lcd_ctrl_extif {
int (*init) (void);
void (*cleanup) (void);
+ void (*get_clk_info) (u32 *clk_period, u32 *max_clk_div);
+ int (*convert_timings) (struct extif_timings *timings);
void (*set_timings) (const struct extif_timings *timings);
- void (*write_command) (u32 cmd);
- u32 (*read_data) (void);
- void (*write_data) (u32 data);
+ void (*set_bits_per_cycle)(int bpc);
+ void (*write_command) (const void *buf, unsigned int len);
+ void (*read_data) (void *buf, unsigned int len);
+ void (*write_data) (const void *buf, unsigned int len);
void (*transfer_area) (int width, int height,
void (callback)(void * data), void *data);
+ unsigned long max_transmit_size;
};
+struct omapfb_notifier_block {
+ struct notifier_block nb;
+ void *data;
+};
+
+typedef int (*omapfb_notifier_callback_t)(struct omapfb_notifier_block *,
+ unsigned long event,
+ struct omapfb_device *fbdev);
+
struct lcd_ctrl {
const char *name;
void *data;
@@ -204,9 +232,11 @@ struct lcd_ctrl {
int (*init) (struct omapfb_device *fbdev,
int ext_mode, int req_vram_size);
void (*cleanup) (void);
+ void (*bind_client) (struct omapfb_notifier_block *nb);
void (*get_vram_layout)(unsigned long *size,
void **virt_base,
dma_addr_t *phys_base);
+ int (*mmap) (struct vm_area_struct *vma);
unsigned long (*get_caps) (void);
int (*set_update_mode)(enum omapfb_update_mode mode);
enum omapfb_update_mode (*get_update_mode)(void);
@@ -240,7 +270,7 @@ struct omapfb_device {
int state;
int ext_lcdc; /* Using external
LCD controller */
- struct semaphore rqueue_sema;
+ struct mutex rqueue_mutex;
void *vram_virt_base;
dma_addr_t vram_phys_base;
@@ -261,12 +291,13 @@ struct omapfb_device {
struct device *dev;
};
-extern struct lcd_panel h3_panel;
-extern struct lcd_panel h2_panel;
-extern struct lcd_panel p2_panel;
-extern struct lcd_panel osk_panel;
-extern struct lcd_panel innovator1610_panel;
-extern struct lcd_panel innovator1510_panel;
+struct omapfb_platform_data {
+ struct omap_lcd_config lcd;
+ struct omap_fbmem_config fbmem;
+};
+
+#define OMAPFB_EVENT_READY 1
+#define OMAPFB_EVENT_DISABLED 2
#ifdef CONFIG_ARCH_OMAP1
extern struct lcd_ctrl omap1_lcd_ctrl;
@@ -274,7 +305,20 @@ extern struct lcd_ctrl omap1_lcd_ctrl;
extern struct lcd_ctrl omap2_disp_ctrl;
#endif
+extern void omapfb_register_panel(struct lcd_panel *panel);
extern void omapfb_write_first_pixel(struct omapfb_device *fbdev, u16 pixval);
+extern void omapfb_notify_clients(struct omapfb_device *fbdev,
+ unsigned long event);
+extern int omapfb_register_client(struct omapfb_notifier_block *nb,
+ omapfb_notifier_callback_t callback,
+ void *callback_data);
+extern int omapfb_unregister_client(struct omapfb_notifier_block *nb);
+extern int omapfb_update_window_async(struct omapfb_update_window *win,
+ void (*callback)(void *),
+ void *callback_data);
+
+/* in arch/arm/plat-omap/devices.c */
+extern void omapfb_reserve_mem(void);
#endif /* __KERNEL__ */
diff --git a/include/asm-arm/arch-omap/param.h b/include/asm-arm/arch-omap/param.h
new file mode 100644
index 00000000000..face9ad41e9
--- /dev/null
+++ b/include/asm-arm/arch-omap/param.h
@@ -0,0 +1,8 @@
+/*
+ * linux/include/asm-arm/arch-omap/param.h
+ *
+ */
+
+#ifdef CONFIG_OMAP_32K_TIMER_HZ
+#define HZ CONFIG_OMAP_32K_TIMER_HZ
+#endif
diff --git a/include/asm-arm/arch-omap/pm.h b/include/asm-arm/arch-omap/pm.h
index 7c790425e36..05b003f3a94 100644
--- a/include/asm-arm/arch-omap/pm.h
+++ b/include/asm-arm/arch-omap/pm.h
@@ -49,7 +49,7 @@
/*
* ----------------------------------------------------------------------------
- * Powermanagement bitmasks
+ * Power management bitmasks
* ----------------------------------------------------------------------------
*/
#define IDLE_WAIT_CYCLES 0x00000fff
@@ -112,32 +112,59 @@
#endif
#ifndef __ASSEMBLER__
+
+#include <linux/clk.h>
+
+extern void prevent_idle_sleep(void);
+extern void allow_idle_sleep(void);
+
+/**
+ * clk_deny_idle - Prevents the clock from being idled during MPU idle
+ * @clk: clock signal handle
+ */
+void clk_deny_idle(struct clk *clk);
+
+/**
+ * clk_allow_idle - Counters previous clk_deny_idle
+ * @clk: clock signal handle
+ */
+void clk_deny_idle(struct clk *clk);
+
extern void omap_pm_idle(void);
extern void omap_pm_suspend(void);
extern void omap730_cpu_suspend(unsigned short, unsigned short);
extern void omap1510_cpu_suspend(unsigned short, unsigned short);
extern void omap1610_cpu_suspend(unsigned short, unsigned short);
+extern void omap24xx_cpu_suspend(u32 dll_ctrl, u32 cpu_revision);
extern void omap730_idle_loop_suspend(void);
extern void omap1510_idle_loop_suspend(void);
extern void omap1610_idle_loop_suspend(void);
+extern void omap24xx_idle_loop_suspend(void);
+
+extern unsigned int omap730_cpu_suspend_sz;
+extern unsigned int omap1510_cpu_suspend_sz;
+extern unsigned int omap1610_cpu_suspend_sz;
+extern unsigned int omap24xx_cpu_suspend_sz;
+extern unsigned int omap730_idle_loop_suspend_sz;
+extern unsigned int omap1510_idle_loop_suspend_sz;
+extern unsigned int omap1610_idle_loop_suspend_sz;
+extern unsigned int omap24xx_idle_loop_suspend_sz;
#ifdef CONFIG_OMAP_SERIAL_WAKE
extern void omap_serial_wake_trigger(int enable);
#else
+#define omap_serial_wakeup_init() {}
#define omap_serial_wake_trigger(x) {}
#endif /* CONFIG_OMAP_SERIAL_WAKE */
-extern unsigned int omap730_cpu_suspend_sz;
-extern unsigned int omap730_idle_loop_suspend_sz;
-extern unsigned int omap1510_cpu_suspend_sz;
-extern unsigned int omap1510_idle_loop_suspend_sz;
-extern unsigned int omap1610_cpu_suspend_sz;
-extern unsigned int omap1610_idle_loop_suspend_sz;
-
#define ARM_SAVE(x) arm_sleep_save[ARM_SLEEP_SAVE_##x] = omap_readl(x)
#define ARM_RESTORE(x) omap_writel((arm_sleep_save[ARM_SLEEP_SAVE_##x]), (x))
#define ARM_SHOW(x) arm_sleep_save[ARM_SLEEP_SAVE_##x]
+#define DSP_SAVE(x) dsp_sleep_save[DSP_SLEEP_SAVE_##x] = __raw_readw(x)
+#define DSP_RESTORE(x) __raw_writew((dsp_sleep_save[DSP_SLEEP_SAVE_##x]), (x))
+#define DSP_SHOW(x) dsp_sleep_save[DSP_SLEEP_SAVE_##x]
+
#define ULPD_SAVE(x) ulpd_sleep_save[ULPD_SLEEP_SAVE_##x] = omap_readw(x)
#define ULPD_RESTORE(x) omap_writew((ulpd_sleep_save[ULPD_SLEEP_SAVE_##x]), (x))
#define ULPD_SHOW(x) ulpd_sleep_save[ULPD_SLEEP_SAVE_##x]
@@ -154,6 +181,10 @@ extern unsigned int omap1610_idle_loop_suspend_sz;
#define MPUI1610_RESTORE(x) omap_writel((mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_##x]), (x))
#define MPUI1610_SHOW(x) mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_##x]
+#define OMAP24XX_SAVE(x) omap24xx_sleep_save[OMAP24XX_SLEEP_SAVE_##x] = x
+#define OMAP24XX_RESTORE(x) x = omap24xx_sleep_save[OMAP24XX_SLEEP_SAVE_##x]
+#define OMAP24XX_SHOW(x) omap24xx_sleep_save[OMAP24XX_SLEEP_SAVE_##x]
+
/*
* List of global OMAP registers to preserve.
* More ones like CP and general purpose register values are preserved
@@ -176,6 +207,15 @@ enum arm_save_state {
ARM_SLEEP_SAVE_SIZE
};
+enum dsp_save_state {
+ DSP_SLEEP_SAVE_START = 0,
+ /*
+ * DSP registers 16 bits
+ */
+ DSP_SLEEP_SAVE_DSP_IDLECT2,
+ DSP_SLEEP_SAVE_SIZE
+};
+
enum ulpd_save_state {
ULPD_SLEEP_SAVE_START = 0,
/*
@@ -254,5 +294,30 @@ enum mpui1610_save_state {
#endif
};
+enum omap24xx_save_state {
+ OMAP24XX_SLEEP_SAVE_START = 0,
+ OMAP24XX_SLEEP_SAVE_INTC_MIR0,
+ OMAP24XX_SLEEP_SAVE_INTC_MIR1,
+ OMAP24XX_SLEEP_SAVE_INTC_MIR2,
+ OMAP24XX_SLEEP_SAVE_CM_FCLKEN1_CORE,
+ OMAP24XX_SLEEP_SAVE_CM_FCLKEN2_CORE,
+ OMAP24XX_SLEEP_SAVE_CM_ICLKEN1_CORE,
+ OMAP24XX_SLEEP_SAVE_CM_ICLKEN2_CORE,
+ OMAP24XX_SLEEP_SAVE_CM_ICLKEN4_CORE,
+ OMAP24XX_SLEEP_SAVE_GPIO1_IRQENABLE1,
+ OMAP24XX_SLEEP_SAVE_GPIO2_IRQENABLE1,
+ OMAP24XX_SLEEP_SAVE_GPIO3_IRQENABLE1,
+ OMAP24XX_SLEEP_SAVE_GPIO4_IRQENABLE1,
+ OMAP24XX_SLEEP_SAVE_GPIO3_OE,
+ OMAP24XX_SLEEP_SAVE_GPIO4_OE,
+ OMAP24XX_SLEEP_SAVE_GPIO3_RISINGDETECT,
+ OMAP24XX_SLEEP_SAVE_GPIO3_FALLINGDETECT,
+ OMAP24XX_SLEEP_SAVE_CONTROL_PADCONF_SPI1_NCS2,
+ OMAP24XX_SLEEP_SAVE_CONTROL_PADCONF_MCBSP1_DX,
+ OMAP24XX_SLEEP_SAVE_CONTROL_PADCONF_SSI1_FLAG_TX,
+ OMAP24XX_SLEEP_SAVE_CONTROL_PADCONF_SYS_NIRQW0,
+ OMAP24XX_SLEEP_SAVE_SIZE
+};
+
#endif /* ASSEMBLER */
#endif /* __ASM_ARCH_OMAP_PM_H */
diff --git a/include/asm-arm/arch-omap/prcm.h b/include/asm-arm/arch-omap/prcm.h
index 7b48a5cbb15..7bcaf94bde9 100644
--- a/include/asm-arm/arch-omap/prcm.h
+++ b/include/asm-arm/arch-omap/prcm.h
@@ -1,5 +1,7 @@
/*
- * prcm.h - Access definations for use in OMAP24XX clock and power management
+ * linux/include/asm-arm/arch-omap/prcm.h
+ *
+ * Access definations for use in OMAP24XX clock and power management
*
* Copyright (C) 2005 Texas Instruments, Inc.
*
@@ -21,405 +23,7 @@
#ifndef __ASM_ARM_ARCH_DPM_PRCM_H
#define __ASM_ARM_ARCH_DPM_PRCM_H
-/* SET_PERFORMANCE_LEVEL PARAMETERS */
-#define PRCM_HALF_SPEED 1
-#define PRCM_FULL_SPEED 2
-
-#ifndef __ASSEMBLER__
-
-#define PRCM_REG32(offset) __REG32(OMAP24XX_PRCM_BASE + (offset))
-
-#define PRCM_REVISION PRCM_REG32(0x000)
-#define PRCM_SYSCONFIG PRCM_REG32(0x010)
-#define PRCM_IRQSTATUS_MPU PRCM_REG32(0x018)
-#define PRCM_IRQENABLE_MPU PRCM_REG32(0x01C)
-#define PRCM_VOLTCTRL PRCM_REG32(0x050)
-#define PRCM_VOLTST PRCM_REG32(0x054)
-#define PRCM_CLKSRC_CTRL PRCM_REG32(0x060)
-#define PRCM_CLKOUT_CTRL PRCM_REG32(0x070)
-#define PRCM_CLKEMUL_CTRL PRCM_REG32(0x078)
-#define PRCM_CLKCFG_CTRL PRCM_REG32(0x080)
-#define PRCM_CLKCFG_STATUS PRCM_REG32(0x084)
-#define PRCM_VOLTSETUP PRCM_REG32(0x090)
-#define PRCM_CLKSSETUP PRCM_REG32(0x094)
-#define PRCM_POLCTRL PRCM_REG32(0x098)
-
-/* GENERAL PURPOSE */
-#define GENERAL_PURPOSE1 PRCM_REG32(0x0B0)
-#define GENERAL_PURPOSE2 PRCM_REG32(0x0B4)
-#define GENERAL_PURPOSE3 PRCM_REG32(0x0B8)
-#define GENERAL_PURPOSE4 PRCM_REG32(0x0BC)
-#define GENERAL_PURPOSE5 PRCM_REG32(0x0C0)
-#define GENERAL_PURPOSE6 PRCM_REG32(0x0C4)
-#define GENERAL_PURPOSE7 PRCM_REG32(0x0C8)
-#define GENERAL_PURPOSE8 PRCM_REG32(0x0CC)
-#define GENERAL_PURPOSE9 PRCM_REG32(0x0D0)
-#define GENERAL_PURPOSE10 PRCM_REG32(0x0D4)
-#define GENERAL_PURPOSE11 PRCM_REG32(0x0D8)
-#define GENERAL_PURPOSE12 PRCM_REG32(0x0DC)
-#define GENERAL_PURPOSE13 PRCM_REG32(0x0E0)
-#define GENERAL_PURPOSE14 PRCM_REG32(0x0E4)
-#define GENERAL_PURPOSE15 PRCM_REG32(0x0E8)
-#define GENERAL_PURPOSE16 PRCM_REG32(0x0EC)
-#define GENERAL_PURPOSE17 PRCM_REG32(0x0F0)
-#define GENERAL_PURPOSE18 PRCM_REG32(0x0F4)
-#define GENERAL_PURPOSE19 PRCM_REG32(0x0F8)
-#define GENERAL_PURPOSE20 PRCM_REG32(0x0FC)
-
-/* MPU */
-#define CM_CLKSEL_MPU PRCM_REG32(0x140)
-#define CM_CLKSTCTRL_MPU PRCM_REG32(0x148)
-#define RM_RSTST_MPU PRCM_REG32(0x158)
-#define PM_WKDEP_MPU PRCM_REG32(0x1C8)
-#define PM_EVGENCTRL_MPU PRCM_REG32(0x1D4)
-#define PM_EVEGENONTIM_MPU PRCM_REG32(0x1D8)
-#define PM_EVEGENOFFTIM_MPU PRCM_REG32(0x1DC)
-#define PM_PWSTCTRL_MPU PRCM_REG32(0x1E0)
-#define PM_PWSTST_MPU PRCM_REG32(0x1E4)
-
-/* CORE */
-#define CM_FCLKEN1_CORE PRCM_REG32(0x200)
-#define CM_FCLKEN2_CORE PRCM_REG32(0x204)
-#define CM_FCLKEN3_CORE PRCM_REG32(0x208)
-#define CM_ICLKEN1_CORE PRCM_REG32(0x210)
-#define CM_ICLKEN2_CORE PRCM_REG32(0x214)
-#define CM_ICLKEN3_CORE PRCM_REG32(0x218)
-#define CM_ICLKEN4_CORE PRCM_REG32(0x21C)
-#define CM_IDLEST1_CORE PRCM_REG32(0x220)
-#define CM_IDLEST2_CORE PRCM_REG32(0x224)
-#define CM_IDLEST3_CORE PRCM_REG32(0x228)
-#define CM_IDLEST4_CORE PRCM_REG32(0x22C)
-#define CM_AUTOIDLE1_CORE PRCM_REG32(0x230)
-#define CM_AUTOIDLE2_CORE PRCM_REG32(0x234)
-#define CM_AUTOIDLE3_CORE PRCM_REG32(0x238)
-#define CM_AUTOIDLE4_CORE PRCM_REG32(0x23C)
-#define CM_CLKSEL1_CORE PRCM_REG32(0x240)
-#define CM_CLKSEL2_CORE PRCM_REG32(0x244)
-#define CM_CLKSTCTRL_CORE PRCM_REG32(0x248)
-#define PM_WKEN1_CORE PRCM_REG32(0x2A0)
-#define PM_WKEN2_CORE PRCM_REG32(0x2A4)
-#define PM_WKST1_CORE PRCM_REG32(0x2B0)
-#define PM_WKST2_CORE PRCM_REG32(0x2B4)
-#define PM_WKDEP_CORE PRCM_REG32(0x2C8)
-#define PM_PWSTCTRL_CORE PRCM_REG32(0x2E0)
-#define PM_PWSTST_CORE PRCM_REG32(0x2E4)
-
-/* GFX */
-#define CM_FCLKEN_GFX PRCM_REG32(0x300)
-#define CM_ICLKEN_GFX PRCM_REG32(0x310)
-#define CM_IDLEST_GFX PRCM_REG32(0x320)
-#define CM_CLKSEL_GFX PRCM_REG32(0x340)
-#define CM_CLKSTCTRL_GFX PRCM_REG32(0x348)
-#define RM_RSTCTRL_GFX PRCM_REG32(0x350)
-#define RM_RSTST_GFX PRCM_REG32(0x358)
-#define PM_WKDEP_GFX PRCM_REG32(0x3C8)
-#define PM_PWSTCTRL_GFX PRCM_REG32(0x3E0)
-#define PM_PWSTST_GFX PRCM_REG32(0x3E4)
-
-/* WAKE-UP */
-#define CM_FCLKEN_WKUP PRCM_REG32(0x400)
-#define CM_ICLKEN_WKUP PRCM_REG32(0x410)
-#define CM_IDLEST_WKUP PRCM_REG32(0x420)
-#define CM_AUTOIDLE_WKUP PRCM_REG32(0x430)
-#define CM_CLKSEL_WKUP PRCM_REG32(0x440)
-#define RM_RSTCTRL_WKUP PRCM_REG32(0x450)
-#define RM_RSTTIME_WKUP PRCM_REG32(0x454)
-#define RM_RSTST_WKUP PRCM_REG32(0x458)
-#define PM_WKEN_WKUP PRCM_REG32(0x4A0)
-#define PM_WKST_WKUP PRCM_REG32(0x4B0)
-
-/* CLOCKS */
-#define CM_CLKEN_PLL PRCM_REG32(0x500)
-#define CM_IDLEST_CKGEN PRCM_REG32(0x520)
-#define CM_AUTOIDLE_PLL PRCM_REG32(0x530)
-#define CM_CLKSEL1_PLL PRCM_REG32(0x540)
-#define CM_CLKSEL2_PLL PRCM_REG32(0x544)
-
-/* DSP */
-#define CM_FCLKEN_DSP PRCM_REG32(0x800)
-#define CM_ICLKEN_DSP PRCM_REG32(0x810)
-#define CM_IDLEST_DSP PRCM_REG32(0x820)
-#define CM_AUTOIDLE_DSP PRCM_REG32(0x830)
-#define CM_CLKSEL_DSP PRCM_REG32(0x840)
-#define CM_CLKSTCTRL_DSP PRCM_REG32(0x848)
-#define RM_RSTCTRL_DSP PRCM_REG32(0x850)
-#define RM_RSTST_DSP PRCM_REG32(0x858)
-#define PM_WKEN_DSP PRCM_REG32(0x8A0)
-#define PM_WKDEP_DSP PRCM_REG32(0x8C8)
-#define PM_PWSTCTRL_DSP PRCM_REG32(0x8E0)
-#define PM_PWSTST_DSP PRCM_REG32(0x8E4)
-#define PRCM_IRQSTATUS_DSP PRCM_REG32(0x8F0)
-#define PRCM_IRQENABLE_DSP PRCM_REG32(0x8F4)
-
-/* IVA */
-#define PRCM_IRQSTATUS_IVA PRCM_REG32(0x8F8)
-#define PRCM_IRQENABLE_IVA PRCM_REG32(0x8FC)
-
-/* Modem on 2430 */
-#define CM_FCLKEN_MDM PRCM_REG32(0xC00)
-#define CM_ICLKEN_MDM PRCM_REG32(0xC10)
-#define CM_IDLEST_MDM PRCM_REG32(0xC20)
-#define CM_CLKSEL_MDM PRCM_REG32(0xC40)
-
-/* FIXME: Move to header for 2430 */
-#define DISP_BASE (OMAP24XX_L4_IO_BASE+0x50000)
-#define DISP_REG32(offset) __REG32(DISP_BASE + (offset))
-
-#define OMAP24XX_GPMC_BASE (L3_24XX_BASE + 0xa000)
-#define GPMC_BASE (OMAP24XX_GPMC_BASE)
-#define GPMC_REG32(offset) __REG32(GPMC_BASE + (offset))
-
-#define GPT1_BASE (OMAP24XX_GPT1)
-#define GPT1_REG32(offset) __REG32(GPT1_BASE + (offset))
-
-/* Misc sysconfig */
-#define DISPC_SYSCONFIG DISP_REG32(0x410)
-#define SPI_BASE (OMAP24XX_L4_IO_BASE+0x98000)
-#define MCSPI1_SYSCONFIG __REG32(SPI_BASE + 0x10)
-#define MCSPI2_SYSCONFIG __REG32(SPI_BASE+0x2000 + 0x10)
-
-//#define DSP_MMU_SYSCONFIG 0x5A000010
-#define CAMERA_MMU_SYSCONFIG __REG32(DISP_BASE+0x2C10)
-//#define IVA_MMU_SYSCONFIG 0x5D000010
-//#define DSP_DMA_SYSCONFIG 0x00FCC02C
-#define CAMERA_DMA_SYSCONFIG __REG32(DISP_BASE+0x282C)
-#define SYSTEM_DMA_SYSCONFIG __REG32(DISP_BASE+0x602C)
-#define GPMC_SYSCONFIG GPMC_REG32(0x010)
-#define MAILBOXES_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE+0x94010)
-#define UART1_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE+0x6A054)
-#define UART2_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE+0x6C054)
-#define UART3_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE+0x6E054)
-//#define IVA_SYSCONFIG 0x5C060010
-#define SDRC_SYSCONFIG __REG32(OMAP24XX_SDRC_BASE+0x10)
-#define SMS_SYSCONFIG __REG32(OMAP24XX_SMS_BASE+0x10)
-#define SSI_SYSCONFIG __REG32(DISP_BASE+0x8010)
-//#define VLYNQ_SYSCONFIG 0x67FFFE10
-
-/* rkw - good cannidates for PM_ to start what nm was trying */
-#define OMAP24XX_GPT2 (OMAP24XX_L4_IO_BASE+0x2A000)
-#define OMAP24XX_GPT3 (OMAP24XX_L4_IO_BASE+0x78000)
-#define OMAP24XX_GPT4 (OMAP24XX_L4_IO_BASE+0x7A000)
-#define OMAP24XX_GPT5 (OMAP24XX_L4_IO_BASE+0x7C000)
-#define OMAP24XX_GPT6 (OMAP24XX_L4_IO_BASE+0x7E000)
-#define OMAP24XX_GPT7 (OMAP24XX_L4_IO_BASE+0x80000)
-#define OMAP24XX_GPT8 (OMAP24XX_L4_IO_BASE+0x82000)
-#define OMAP24XX_GPT9 (OMAP24XX_L4_IO_BASE+0x84000)
-#define OMAP24XX_GPT10 (OMAP24XX_L4_IO_BASE+0x86000)
-#define OMAP24XX_GPT11 (OMAP24XX_L4_IO_BASE+0x88000)
-#define OMAP24XX_GPT12 (OMAP24XX_L4_IO_BASE+0x8A000)
-
-#define GPTIMER1_SYSCONFIG GPT1_REG32(0x010)
-#define GPTIMER2_SYSCONFIG __REG32(OMAP24XX_GPT2 + 0x10)
-#define GPTIMER3_SYSCONFIG __REG32(OMAP24XX_GPT3 + 0x10)
-#define GPTIMER4_SYSCONFIG __REG32(OMAP24XX_GPT4 + 0x10)
-#define GPTIMER5_SYSCONFIG __REG32(OMAP24XX_GPT5 + 0x10)
-#define GPTIMER6_SYSCONFIG __REG32(OMAP24XX_GPT6 + 0x10)
-#define GPTIMER7_SYSCONFIG __REG32(OMAP24XX_GPT7 + 0x10)
-#define GPTIMER8_SYSCONFIG __REG32(OMAP24XX_GPT8 + 0x10)
-#define GPTIMER9_SYSCONFIG __REG32(OMAP24XX_GPT9 + 0x10)
-#define GPTIMER10_SYSCONFIG __REG32(OMAP24XX_GPT10 + 0x10)
-#define GPTIMER11_SYSCONFIG __REG32(OMAP24XX_GPT11 + 0x10)
-#define GPTIMER12_SYSCONFIG __REG32(OMAP24XX_GPT12 + 0x10)
-
-#define GPIOX_BASE(X) (OMAP24XX_GPIO_BASE+(0x2000*((X)-1)))
-
-#define GPIO1_SYSCONFIG __REG32((GPIOX_BASE(1)+0x10))
-#define GPIO2_SYSCONFIG __REG32((GPIOX_BASE(2)+0x10))
-#define GPIO3_SYSCONFIG __REG32((GPIOX_BASE(3)+0x10))
-#define GPIO4_SYSCONFIG __REG32((GPIOX_BASE(4)+0x10))
-
-/* GP TIMER 1 */
-#define GPTIMER1_TISTAT GPT1_REG32(0x014)
-#define GPTIMER1_TISR GPT1_REG32(0x018)
-#define GPTIMER1_TIER GPT1_REG32(0x01C)
-#define GPTIMER1_TWER GPT1_REG32(0x020)
-#define GPTIMER1_TCLR GPT1_REG32(0x024)
-#define GPTIMER1_TCRR GPT1_REG32(0x028)
-#define GPTIMER1_TLDR GPT1_REG32(0x02C)
-#define GPTIMER1_TTGR GPT1_REG32(0x030)
-#define GPTIMER1_TWPS GPT1_REG32(0x034)
-#define GPTIMER1_TMAR GPT1_REG32(0x038)
-#define GPTIMER1_TCAR1 GPT1_REG32(0x03C)
-#define GPTIMER1_TSICR GPT1_REG32(0x040)
-#define GPTIMER1_TCAR2 GPT1_REG32(0x044)
-
-/* rkw -- base fix up please... */
-#define GPTIMER3_TISR __REG32(OMAP24XX_L4_IO_BASE+0x78018)
-
-/* SDRC */
-#define SDRC_DLLA_CTRL __REG32(OMAP24XX_SDRC_BASE+0x060)
-#define SDRC_DLLA_STATUS __REG32(OMAP24XX_SDRC_BASE+0x064)
-#define SDRC_DLLB_CTRL __REG32(OMAP24XX_SDRC_BASE+0x068)
-#define SDRC_DLLB_STATUS __REG32(OMAP24XX_SDRC_BASE+0x06C)
-#define SDRC_POWER __REG32(OMAP24XX_SDRC_BASE+0x070)
-#define SDRC_MR_0 __REG32(OMAP24XX_SDRC_BASE+0x084)
-
-/* GPIO 1 */
-#define GPIO1_BASE GPIOX_BASE(1)
-#define GPIO1_REG32(offset) __REG32(GPIO1_BASE + (offset))
-#define GPIO1_IRQENABLE1 GPIO1_REG32(0x01C)
-#define GPIO1_IRQSTATUS1 GPIO1_REG32(0x018)
-#define GPIO1_IRQENABLE2 GPIO1_REG32(0x02C)
-#define GPIO1_IRQSTATUS2 GPIO1_REG32(0x028)
-#define GPIO1_WAKEUPENABLE GPIO1_REG32(0x020)
-#define GPIO1_RISINGDETECT GPIO1_REG32(0x048)
-#define GPIO1_DATAIN GPIO1_REG32(0x038)
-#define GPIO1_OE GPIO1_REG32(0x034)
-#define GPIO1_DATAOUT GPIO1_REG32(0x03C)
-
-/* GPIO2 */
-#define GPIO2_BASE GPIOX_BASE(2)
-#define GPIO2_REG32(offset) __REG32(GPIO2_BASE + (offset))
-#define GPIO2_IRQENABLE1 GPIO2_REG32(0x01C)
-#define GPIO2_IRQSTATUS1 GPIO2_REG32(0x018)
-#define GPIO2_IRQENABLE2 GPIO2_REG32(0x02C)
-#define GPIO2_IRQSTATUS2 GPIO2_REG32(0x028)
-#define GPIO2_WAKEUPENABLE GPIO2_REG32(0x020)
-#define GPIO2_RISINGDETECT GPIO2_REG32(0x048)
-#define GPIO2_DATAIN GPIO2_REG32(0x038)
-#define GPIO2_OE GPIO2_REG32(0x034)
-#define GPIO2_DATAOUT GPIO2_REG32(0x03C)
-
-/* GPIO 3 */
-#define GPIO3_BASE GPIOX_BASE(3)
-#define GPIO3_REG32(offset) __REG32(GPIO3_BASE + (offset))
-#define GPIO3_IRQENABLE1 GPIO3_REG32(0x01C)
-#define GPIO3_IRQSTATUS1 GPIO3_REG32(0x018)
-#define GPIO3_IRQENABLE2 GPIO3_REG32(0x02C)
-#define GPIO3_IRQSTATUS2 GPIO3_REG32(0x028)
-#define GPIO3_WAKEUPENABLE GPIO3_REG32(0x020)
-#define GPIO3_RISINGDETECT GPIO3_REG32(0x048)
-#define GPIO3_FALLINGDETECT GPIO3_REG32(0x04C)
-#define GPIO3_DATAIN GPIO3_REG32(0x038)
-#define GPIO3_OE GPIO3_REG32(0x034)
-#define GPIO3_DATAOUT GPIO3_REG32(0x03C)
-#define GPIO3_DEBOUNCENABLE GPIO3_REG32(0x050)
-#define GPIO3_DEBOUNCINGTIME GPIO3_REG32(0x054)
-
-/* GPIO 4 */
-#define GPIO4_BASE GPIOX_BASE(4)
-#define GPIO4_REG32(offset) __REG32(GPIO4_BASE + (offset))
-#define GPIO4_IRQENABLE1 GPIO4_REG32(0x01C)
-#define GPIO4_IRQSTATUS1 GPIO4_REG32(0x018)
-#define GPIO4_IRQENABLE2 GPIO4_REG32(0x02C)
-#define GPIO4_IRQSTATUS2 GPIO4_REG32(0x028)
-#define GPIO4_WAKEUPENABLE GPIO4_REG32(0x020)
-#define GPIO4_RISINGDETECT GPIO4_REG32(0x048)
-#define GPIO4_FALLINGDETECT GPIO4_REG32(0x04C)
-#define GPIO4_DATAIN GPIO4_REG32(0x038)
-#define GPIO4_OE GPIO4_REG32(0x034)
-#define GPIO4_DATAOUT GPIO4_REG32(0x03C)
-#define GPIO4_DEBOUNCENABLE GPIO4_REG32(0x050)
-#define GPIO4_DEBOUNCINGTIME GPIO4_REG32(0x054)
-
-
-/* IO CONFIG */
-#define CONTROL_BASE (OMAP24XX_CTRL_BASE)
-#define CONTROL_REG32(offset) __REG32(CONTROL_BASE + (offset))
-
-#define CONTROL_PADCONF_SPI1_NCS2 CONTROL_REG32(0x104)
-#define CONTROL_PADCONF_SYS_XTALOUT CONTROL_REG32(0x134)
-#define CONTROL_PADCONF_UART1_RX CONTROL_REG32(0x0C8)
-#define CONTROL_PADCONF_MCBSP1_DX CONTROL_REG32(0x10C)
-#define CONTROL_PADCONF_GPMC_NCS4 CONTROL_REG32(0x090)
-#define CONTROL_PADCONF_DSS_D5 CONTROL_REG32(0x0B8)
-#define CONTROL_PADCONF_DSS_D9 CONTROL_REG32(0x0BC)
-#define CONTROL_PADCONF_DSS_D13 CONTROL_REG32(0x0C0)
-#define CONTROL_PADCONF_DSS_VSYNC CONTROL_REG32(0x0CC)
-
-/* CONTROL */
-#define CONTROL_DEVCONF CONTROL_REG32(0x274)
-
-/* INTERRUPT CONTROLLER */
-#define INTC_BASE (OMAP24XX_L4_IO_BASE+0xfe000)
-#define INTC_REG32(offset) __REG32(INTC_BASE + (offset))
-
-#define INTC1_U_BASE INTC_REG32(0x000)
-#define INTC_MIR0 INTC_REG32(0x084)
-#define INTC_MIR_SET0 INTC_REG32(0x08C)
-#define INTC_MIR_CLEAR0 INTC_REG32(0x088)
-#define INTC_ISR_CLEAR0 INTC_REG32(0x094)
-#define INTC_MIR1 INTC_REG32(0x0A4)
-#define INTC_MIR_SET1 INTC_REG32(0x0AC)
-#define INTC_MIR_CLEAR1 INTC_REG32(0x0A8)
-#define INTC_ISR_CLEAR1 INTC_REG32(0x0B4)
-#define INTC_MIR2 INTC_REG32(0x0C4)
-#define INTC_MIR_SET2 INTC_REG32(0x0CC)
-#define INTC_MIR_CLEAR2 INTC_REG32(0x0C8)
-#define INTC_ISR_CLEAR2 INTC_REG32(0x0D4)
-#define INTC_SIR_IRQ INTC_REG32(0x040)
-#define INTC_CONTROL INTC_REG32(0x048)
-#define INTC_ILR11 INTC_REG32(0x12C)
-#define INTC_ILR32 INTC_REG32(0x180)
-#define INTC_ILR37 INTC_REG32(0x194)
-#define INTC_SYSCONFIG INTC_REG32(0x010)
-
-/* RAM FIREWALL */
-#define RAMFW_BASE (0x68005000)
-#define RAMFW_REG32(offset) __REG32(RAMFW_BASE + (offset))
-
-#define RAMFW_REQINFOPERM0 RAMFW_REG32(0x048)
-#define RAMFW_READPERM0 RAMFW_REG32(0x050)
-#define RAMFW_WRITEPERM0 RAMFW_REG32(0x058)
-
-/* GPMC CS1 FPGA ON USER INTERFACE MODULE */
-//#define DEBUG_BOARD_LED_REGISTER 0x04000014
-
-/* GPMC CS0 */
-#define GPMC_CONFIG1_0 GPMC_REG32(0x060)
-#define GPMC_CONFIG2_0 GPMC_REG32(0x064)
-#define GPMC_CONFIG3_0 GPMC_REG32(0x068)
-#define GPMC_CONFIG4_0 GPMC_REG32(0x06C)
-#define GPMC_CONFIG5_0 GPMC_REG32(0x070)
-#define GPMC_CONFIG6_0 GPMC_REG32(0x074)
-#define GPMC_CONFIG7_0 GPMC_REG32(0x078)
-
-/* GPMC CS1 */
-#define GPMC_CONFIG1_1 GPMC_REG32(0x090)
-#define GPMC_CONFIG2_1 GPMC_REG32(0x094)
-#define GPMC_CONFIG3_1 GPMC_REG32(0x098)
-#define GPMC_CONFIG4_1 GPMC_REG32(0x09C)
-#define GPMC_CONFIG5_1 GPMC_REG32(0x0a0)
-#define GPMC_CONFIG6_1 GPMC_REG32(0x0a4)
-#define GPMC_CONFIG7_1 GPMC_REG32(0x0a8)
-
-/* DSS */
-#define DSS_CONTROL DISP_REG32(0x040)
-#define DISPC_CONTROL DISP_REG32(0x440)
-#define DISPC_SYSSTATUS DISP_REG32(0x414)
-#define DISPC_IRQSTATUS DISP_REG32(0x418)
-#define DISPC_IRQENABLE DISP_REG32(0x41C)
-#define DISPC_CONFIG DISP_REG32(0x444)
-#define DISPC_DEFAULT_COLOR0 DISP_REG32(0x44C)
-#define DISPC_DEFAULT_COLOR1 DISP_REG32(0x450)
-#define DISPC_TRANS_COLOR0 DISP_REG32(0x454)
-#define DISPC_TRANS_COLOR1 DISP_REG32(0x458)
-#define DISPC_LINE_NUMBER DISP_REG32(0x460)
-#define DISPC_TIMING_H DISP_REG32(0x464)
-#define DISPC_TIMING_V DISP_REG32(0x468)
-#define DISPC_POL_FREQ DISP_REG32(0x46C)
-#define DISPC_DIVISOR DISP_REG32(0x470)
-#define DISPC_SIZE_DIG DISP_REG32(0x478)
-#define DISPC_SIZE_LCD DISP_REG32(0x47C)
-#define DISPC_GFX_BA0 DISP_REG32(0x480)
-#define DISPC_GFX_BA1 DISP_REG32(0x484)
-#define DISPC_GFX_POSITION DISP_REG32(0x488)
-#define DISPC_GFX_SIZE DISP_REG32(0x48C)
-#define DISPC_GFX_ATTRIBUTES DISP_REG32(0x4A0)
-#define DISPC_GFX_FIFO_THRESHOLD DISP_REG32(0x4A4)
-#define DISPC_GFX_ROW_INC DISP_REG32(0x4AC)
-#define DISPC_GFX_PIXEL_INC DISP_REG32(0x4B0)
-#define DISPC_GFX_WINDOW_SKIP DISP_REG32(0x4B4)
-#define DISPC_GFX_TABLE_BA DISP_REG32(0x4B8)
-#define DISPC_DATA_CYCLE1 DISP_REG32(0x5D4)
-#define DISPC_DATA_CYCLE2 DISP_REG32(0x5D8)
-#define DISPC_DATA_CYCLE3 DISP_REG32(0x5DC)
-
-/* Wake up define for board */
-#define GPIO97 (1 << 1)
-#define GPIO88 (1 << 24)
-
-#endif /* __ASSEMBLER__ */
+u32 omap_prcm_get_reset_sources(void);
#endif
diff --git a/include/asm-arm/arch-omap/sram.h b/include/asm-arm/arch-omap/sram.h
index e72ccbf0fe0..6fc0dd57b7c 100644
--- a/include/asm-arm/arch-omap/sram.h
+++ b/include/asm-arm/arch-omap/sram.h
@@ -20,6 +20,8 @@ extern void omap2_sram_reprogram_sdrc(u32 perf_level, u32 dll_val,
u32 mem_type);
extern u32 omap2_set_prcm(u32 dpll_ctrl_val, u32 sdrc_rfr_val, int bypass);
+extern unsigned long omap_fb_sram_start;
+extern unsigned long omap_fb_sram_size;
/* Do not use these */
extern void sram_reprogram_clock(u32 ckctl, u32 dpllctl);
diff --git a/include/asm-arm/arch-omap/system.h b/include/asm-arm/arch-omap/system.h
index 6724a81bd10..67970d1a202 100644
--- a/include/asm-arm/arch-omap/system.h
+++ b/include/asm-arm/arch-omap/system.h
@@ -9,12 +9,13 @@
#include <asm/mach-types.h>
#include <asm/hardware.h>
-#include <asm/arch/prcm.h>
#ifndef CONFIG_MACH_VOICEBLUE
#define voiceblue_reset() do {} while (0)
#endif
+extern void omap_prcm_arch_reset(char mode);
+
static inline void arch_idle(void)
{
cpu_do_idle();
@@ -38,24 +39,12 @@ static inline void omap1_arch_reset(char mode)
omap_writew(1, ARM_RSTCT1);
}
-static inline void omap2_arch_reset(char mode)
-{
- u32 rate;
- struct clk *vclk, *sclk;
-
- vclk = clk_get(NULL, "virt_prcm_set");
- sclk = clk_get(NULL, "sys_ck");
- rate = clk_get_rate(sclk);
- clk_set_rate(vclk, rate); /* go to bypass for OMAP limitation */
- RM_RSTCTRL_WKUP |= 2;
-}
-
static inline void arch_reset(char mode)
{
if (!cpu_is_omap24xx())
omap1_arch_reset(mode);
else
- omap2_arch_reset(mode);
+ omap_prcm_arch_reset(mode);
}
#endif
diff --git a/include/asm-arm/arch-s3c2410/entry-macro.S b/include/asm-arm/arch-s3c2410/entry-macro.S
index cc06b1bd37b..894c35cf3b1 100644
--- a/include/asm-arm/arch-s3c2410/entry-macro.S
+++ b/include/asm-arm/arch-s3c2410/entry-macro.S
@@ -6,116 +6,83 @@
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
+*/
+
+/* We have a problem that the INTOFFSET register does not always
+ * show one interrupt. Occasionally we get two interrupts through
+ * the prioritiser, and this causes the INTOFFSET register to show
+ * what looks like the logical-or of the two interrupt numbers.
+ *
+ * Thanks to Klaus, Shannon, et al for helping to debug this problem
+*/
+
+#define INTPND (0x10)
+#define INTOFFSET (0x14)
+#define EXTINTPEND (0xa8)
+#define EXTINTMASK (0xa4)
- * Modifications:
- * 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA
- */
#include <asm/hardware.h>
#include <asm/arch/irqs.h>
-
.macro get_irqnr_and_base, irqnr, irqstat, base, tmp
- mov \tmp, #S3C24XX_VA_IRQ
- ldr \irqnr, [ \tmp, #0x14 ] @ get irq no
-30000:
- teq \irqnr, #4
- teqne \irqnr, #5
- beq 1002f @ external irq reg
-
- @ debug check to see if interrupt reported is the same
- @ as the offset....
-
- teq \irqnr, #0
- beq 20002f
- ldr \irqstat, [ \tmp, #0x10 ] @ INTPND
- mov \irqstat, \irqstat, lsr \irqnr
- tst \irqstat, #1
- bne 20002f
-
- /* debug/warning if we get an invalud response from the
- * INTOFFSET register */
-#if 1
- stmfd r13!, { r0 - r4 , r8-r12, r14 }
- ldr r1, [ \tmp, #0x14 ] @ INTOFFSET
- ldr r2, [ \tmp, #0x10 ] @ INTPND
- ldr r3, [ \tmp, #0x00 ] @ SRCPND
- adr r0, 20003f
- bl printk
- b 20004f
-
-20003:
- .ascii "<7>irq: err - bad offset %d, intpnd=%08x, srcpnd=%08x\n"
- .byte 0
- .align 4
-20004:
- mov r1, #1
- mov \tmp, #S3C24XX_VA_IRQ
- ldmfd r13!, { r0 - r4 , r8-r12, r14 }
-#endif
-
- @ try working out interrupt number for ourselves
- mov \irqnr, #0
- ldr \irqstat, [ \tmp, #0x10 ] @ INTPND
-10021:
- movs \irqstat, \irqstat, lsr#1
- bcs 30000b @ try and re-start the proccess
- add \irqnr, \irqnr, #1
- cmp \irqnr, #32
- ble 10021b
-
- @ found no interrupt, set Z flag and leave
- movs \irqnr, #0
- b 1001f
-
-20005:
-20002: @ exit
- @ we base the s3c2410x interrupts at 16 and above to allow
- @ isa peripherals to have their standard interrupts, also
- @ ensure that Z flag is un-set on exit
-
- @ note, we cannot be sure if we get IRQ_EINT0 (0) that
- @ there is simply no interrupt pending, so in all other
- @ cases we jump to say we have found something, otherwise
- @ we check to see if the interrupt really is assrted
- adds \irqnr, \irqnr, #IRQ_EINT0
- teq \irqnr, #IRQ_EINT0
- bne 1001f @ exit
- ldr \irqstat, [ \tmp, #0x10 ] @ INTPND
- teq \irqstat, #0
- moveq \irqnr, #0
- b 1001f
-
- @ we get here from no main or external interrupts pending
-1002:
- add \tmp, \tmp, #S3C24XX_VA_GPIO - S3C24XX_VA_IRQ
- ldr \irqstat, [ \tmp, # 0xa8 ] @ EXTINTPEND
- ldr \irqnr, [ \tmp, # 0xa4 ] @ EXTINTMASK
-
- bic \irqstat, \irqstat, \irqnr @ clear masked irqs
-
- mov \irqnr, #IRQ_EINT4 @ start extint nos
- mov \irqstat, \irqstat, lsr#4 @ ignore bottom 4 bits
-10021:
- movs \irqstat, \irqstat, lsr#1
- bcs 1004f
- add \irqnr, \irqnr, #1
- cmp \irqnr, #IRQ_EINT23
- ble 10021b
-
- @ found no interrupt, set Z flag and leave
- movs \irqnr, #0
-
-1004: @ ensure Z flag clear in case our MOVS shifted out the last bit
- teq \irqnr, #0
+ mov \base, #S3C24XX_VA_IRQ
+
+ ldr \irqstat, [ \base, #INTPND]
+ bics \irqnr, \irqstat, #3<<4 @@ only an GPIO IRQ
+ beq 2000f
+
+ @@ try the interrupt offset register, since it is there
+
+ ldr \irqnr, [ \base, #INTOFFSET ]
+ mov \tmp, #1
+ tst \irqstat, \tmp, lsl \irqnr
+ addne \irqnr, \irqnr, #IRQ_EINT0
+ bne 1001f
+
+ @@ the number specified is not a valid irq, so try
+ @@ and work it out for ourselves
+
+ mov \irqnr, #IRQ_EINT0 @@ start here
+ b 3000f
+
+2000:
+ @@ load the GPIO interrupt register, and check it
+
+ add \tmp, \base, #S3C24XX_VA_GPIO - S3C24XX_VA_IRQ
+ ldr \irqstat, [ \tmp, # EXTINTPEND ]
+ ldr \irqnr, [ \tmp, # EXTINTMASK ]
+ bics \irqstat, \irqstat, \irqnr
+ beq 1001f
+
+ mov \irqnr, #(IRQ_EINT4 - 4)
+
+ @@ work out which irq (if any) we got
+3000:
+ movs \tmp, \irqstat, lsl#16
+ addeq \irqnr, \irqnr, #16
+ moveq \irqstat, \irqstat, lsr#16
+ tst \irqstat, #0xff
+ addeq \irqnr, \irqnr, #8
+ moveq \irqstat, \irqstat, lsr#8
+ tst \irqstat, #0xf
+ addeq \irqnr, \irqnr, #4
+ moveq \irqstat, \irqstat, lsr#4
+ tst \irqstat, #0x3
+ addeq \irqnr, \irqnr, #2
+ moveq \irqstat, \irqstat, lsr#2
+ tst \irqstat, #0x1
+ addeq \irqnr, \irqnr, #1
+
+ @@ we have the value
+ movs \irqnr, \irqnr
+
1001:
- @ exit irq routine
- .endm
+ @@ exit here, Z flag unset if IRQ
+ .endm
/* currently don't need an disable_fiq macro */
.macro disable_fiq
.endm
-
-
diff --git a/include/asm-arm/dma-mapping.h b/include/asm-arm/dma-mapping.h
index e3e8541ee63..63ca7412a46 100644
--- a/include/asm-arm/dma-mapping.h
+++ b/include/asm-arm/dma-mapping.h
@@ -47,7 +47,7 @@ static inline int dma_get_cache_alignment(void)
static inline int dma_is_consistent(dma_addr_t handle)
{
- return 0;
+ return !!arch_is_coherent();
}
/*
@@ -145,7 +145,9 @@ static inline dma_addr_t
dma_map_single(struct device *dev, void *cpu_addr, size_t size,
enum dma_data_direction dir)
{
- consistent_sync(cpu_addr, size, dir);
+ if (!arch_is_coherent())
+ consistent_sync(cpu_addr, size, dir);
+
return virt_to_dma(dev, (unsigned long)cpu_addr);
}
#else
@@ -255,7 +257,9 @@ dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
sg->dma_address = page_to_dma(dev, sg->page) + sg->offset;
virt = page_address(sg->page) + sg->offset;
- consistent_sync(virt, sg->length, dir);
+
+ if (!arch_is_coherent())
+ consistent_sync(virt, sg->length, dir);
}
return nents;
@@ -310,14 +314,16 @@ static inline void
dma_sync_single_for_cpu(struct device *dev, dma_addr_t handle, size_t size,
enum dma_data_direction dir)
{
- consistent_sync((void *)dma_to_virt(dev, handle), size, dir);
+ if (!arch_is_coherent())
+ consistent_sync((void *)dma_to_virt(dev, handle), size, dir);
}
static inline void
dma_sync_single_for_device(struct device *dev, dma_addr_t handle, size_t size,
enum dma_data_direction dir)
{
- consistent_sync((void *)dma_to_virt(dev, handle), size, dir);
+ if (!arch_is_coherent())
+ consistent_sync((void *)dma_to_virt(dev, handle), size, dir);
}
#else
extern void dma_sync_single_for_cpu(struct device*, dma_addr_t, size_t, enum dma_data_direction);
@@ -347,7 +353,8 @@ dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nents,
for (i = 0; i < nents; i++, sg++) {
char *virt = page_address(sg->page) + sg->offset;
- consistent_sync(virt, sg->length, dir);
+ if (!arch_is_coherent())
+ consistent_sync(virt, sg->length, dir);
}
}
@@ -359,7 +366,8 @@ dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nents,
for (i = 0; i < nents; i++, sg++) {
char *virt = page_address(sg->page) + sg->offset;
- consistent_sync(virt, sg->length, dir);
+ if (!arch_is_coherent())
+ consistent_sync(virt, sg->length, dir);
}
}
#else
diff --git a/include/asm-arm/memory.h b/include/asm-arm/memory.h
index afa5c3ea077..2b3cf69b3ed 100644
--- a/include/asm-arm/memory.h
+++ b/include/asm-arm/memory.h
@@ -234,6 +234,14 @@ static inline __deprecated void *bus_to_virt(unsigned long x)
#define virt_to_dma(dev, addr) (__arch_virt_to_dma(dev, addr))
#endif
+/*
+ * Optional coherency support. Currently used only by selected
+ * Intel XSC3-based systems.
+ */
+#ifndef arch_is_coherent
+#define arch_is_coherent() 0
+#endif
+
#endif
#include <asm-generic/memory_model.h>
diff --git a/include/asm-arm/pgtable-hwdef.h b/include/asm-arm/pgtable-hwdef.h
index 1d033495cc7..1bc1f997bda 100644
--- a/include/asm-arm/pgtable-hwdef.h
+++ b/include/asm-arm/pgtable-hwdef.h
@@ -73,6 +73,7 @@
#define PTE_EXT_AP_URW_SRW (PTE_EXT_AP1|PTE_EXT_AP0)
#define PTE_EXT_TEX(x) ((x) << 6) /* v5 */
#define PTE_EXT_APX (1 << 9) /* v6 */
+#define PTE_EXT_COHERENT (1 << 9) /* XScale3 */
#define PTE_EXT_SHARED (1 << 10) /* v6 */
#define PTE_EXT_NG (1 << 11) /* v6 */
diff --git a/include/asm-arm/pgtable.h b/include/asm-arm/pgtable.h
index e595ae24efe..e85c08d78dd 100644
--- a/include/asm-arm/pgtable.h
+++ b/include/asm-arm/pgtable.h
@@ -156,6 +156,7 @@ extern void __pgd_error(const char *file, int line, unsigned long val);
#define L_PTE_WRITE (1 << 5)
#define L_PTE_EXEC (1 << 6)
#define L_PTE_DIRTY (1 << 7)
+#define L_PTE_COHERENT (1 << 9) /* I/O coherent (xsc3) */
#define L_PTE_SHARED (1 << 10) /* shared between CPUs (v6) */
#define L_PTE_ASID (1 << 11) /* non-global (use ASID, v6) */
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 4ed7e602d70..1e9ebaba07b 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -864,7 +864,7 @@ struct super_block {
*/
struct mutex s_vfs_rename_mutex; /* Kludge */
- /* Granuality of c/m/atime in ns.
+ /* Granularity of c/m/atime in ns.
Cannot be worse than a second */
u32 s_time_gran;
};
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h
index b2093928761..306acf1dc6d 100644
--- a/include/linux/hrtimer.h
+++ b/include/linux/hrtimer.h
@@ -80,7 +80,7 @@ struct hrtimer_sleeper {
* @first: pointer to the timer node which expires first
* @resolution: the resolution of the clock, in nanoseconds
* @get_time: function to retrieve the current time of the clock
- * @get_sofirq_time: function to retrieve the current time from the softirq
+ * @get_softirq_time: function to retrieve the current time from the softirq
* @curr_timer: the timer which is executing a callback right now
* @softirq_time: the time when running the hrtimer queue in the softirq
*/
diff --git a/include/sound/core.h b/include/sound/core.h
index 7f32c12b4a0..d1d043f6cb8 100644
--- a/include/sound/core.h
+++ b/include/sound/core.h
@@ -170,7 +170,7 @@ static inline void snd_power_change_state(struct snd_card *card, unsigned int st
}
/* init.c */
-int snd_power_wait(struct snd_card *card, unsigned int power_state, struct file *file);
+int snd_power_wait(struct snd_card *card, unsigned int power_state);
#else /* ! CONFIG_PM */
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 15b885660bf..66b1f08b42b 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -369,6 +369,7 @@ struct snd_pcm_substream {
/* -- assigned files -- */
struct snd_pcm_file *file;
struct file *ffile;
+ void (*pcm_release)(struct snd_pcm_substream *);
#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
/* -- OSS things -- */
struct snd_pcm_oss_substream oss;
@@ -381,13 +382,10 @@ struct snd_pcm_substream {
struct snd_info_entry *proc_prealloc_entry;
/* misc flags */
unsigned int no_mmap_ctrl: 1;
+ unsigned int hw_opened: 1;
};
-#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
-#define SUBSTREAM_BUSY(substream) ((substream)->file != NULL || ((substream)->oss.file != NULL))
-#else
#define SUBSTREAM_BUSY(substream) ((substream)->file != NULL)
-#endif
struct snd_pcm_str {
@@ -460,7 +458,6 @@ int snd_pcm_info_user(struct snd_pcm_substream *substream,
struct snd_pcm_info __user *info);
int snd_pcm_status(struct snd_pcm_substream *substream,
struct snd_pcm_status *status);
-int snd_pcm_prepare(struct snd_pcm_substream *substream);
int snd_pcm_start(struct snd_pcm_substream *substream);
int snd_pcm_stop(struct snd_pcm_substream *substream, int status);
int snd_pcm_drain_done(struct snd_pcm_substream *substream);
@@ -468,11 +465,13 @@ int snd_pcm_drain_done(struct snd_pcm_substream *substream);
int snd_pcm_suspend(struct snd_pcm_substream *substream);
int snd_pcm_suspend_all(struct snd_pcm *pcm);
#endif
-int snd_pcm_kernel_playback_ioctl(struct snd_pcm_substream *substream, unsigned int cmd, void *arg);
-int snd_pcm_kernel_capture_ioctl(struct snd_pcm_substream *substream, unsigned int cmd, void *arg);
int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream, unsigned int cmd, void *arg);
-int snd_pcm_open_substream(struct snd_pcm *pcm, int stream, struct snd_pcm_substream **rsubstream);
+int snd_pcm_open_substream(struct snd_pcm *pcm, int stream, struct file *file,
+ struct snd_pcm_substream **rsubstream);
void snd_pcm_release_substream(struct snd_pcm_substream *substream);
+int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, struct file *file,
+ struct snd_pcm_substream **rsubstream);
+void snd_pcm_detach_substream(struct snd_pcm_substream *substream);
void snd_pcm_vma_notify_data(void *client, void *data);
int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file, struct vm_area_struct *area);
diff --git a/include/sound/pcm_oss.h b/include/sound/pcm_oss.h
index bff0778e196..39df2baca18 100644
--- a/include/sound/pcm_oss.h
+++ b/include/sound/pcm_oss.h
@@ -69,8 +69,7 @@ struct snd_pcm_oss_file {
struct snd_pcm_oss_substream {
unsigned oss: 1; /* oss mode */
- struct snd_pcm_oss_setup *setup; /* active setup */
- struct snd_pcm_oss_file *file;
+ struct snd_pcm_oss_setup setup; /* active setup */
};
struct snd_pcm_oss_stream {
diff --git a/ipc/shm.c b/ipc/shm.c
index f806a2e314e..6b0c9af5bbf 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -91,8 +91,8 @@ static inline int shm_addid(struct shmid_kernel *shp)
static inline void shm_inc (int id) {
struct shmid_kernel *shp;
- if(!(shp = shm_lock(id)))
- BUG();
+ shp = shm_lock(id);
+ BUG_ON(!shp);
shp->shm_atim = get_seconds();
shp->shm_lprid = current->tgid;
shp->shm_nattch++;
@@ -142,8 +142,8 @@ static void shm_close (struct vm_area_struct *shmd)
mutex_lock(&shm_ids.mutex);
/* remove from the list of attaches of the shm segment */
- if(!(shp = shm_lock(id)))
- BUG();
+ shp = shm_lock(id);
+ BUG_ON(!shp);
shp->shm_lprid = current->tgid;
shp->shm_dtim = get_seconds();
shp->shm_nattch--;
@@ -283,8 +283,7 @@ asmlinkage long sys_shmget (key_t key, size_t size, int shmflg)
err = -EEXIST;
} else {
shp = shm_lock(id);
- if(shp==NULL)
- BUG();
+ BUG_ON(shp==NULL);
if (shp->shm_segsz < size)
err = -EINVAL;
else if (ipcperms(&shp->shm_perm, shmflg))
@@ -774,8 +773,8 @@ invalid:
up_write(&current->mm->mmap_sem);
mutex_lock(&shm_ids.mutex);
- if(!(shp = shm_lock(shmid)))
- BUG();
+ shp = shm_lock(shmid);
+ BUG_ON(!shp);
shp->shm_nattch--;
if(shp->shm_nattch == 0 &&
shp->shm_perm.mode & SHM_DEST)
diff --git a/ipc/util.c b/ipc/util.c
index 23151ef3259..5e785a29e1e 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -266,8 +266,7 @@ struct kern_ipc_perm* ipc_rmid(struct ipc_ids* ids, int id)
{
struct kern_ipc_perm* p;
int lid = id % SEQ_MULTIPLIER;
- if(lid >= ids->entries->size)
- BUG();
+ BUG_ON(lid >= ids->entries->size);
/*
* do not need a rcu_dereference()() here to force ordering
@@ -275,8 +274,7 @@ struct kern_ipc_perm* ipc_rmid(struct ipc_ids* ids, int id)
*/
p = ids->entries->p[lid];
ids->entries->p[lid] = NULL;
- if(p==NULL)
- BUG();
+ BUG_ON(p==NULL);
ids->in_use--;
if (lid == ids->max_id) {
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index 9fd8d4f0359..ce0dfb8f4a4 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -41,7 +41,7 @@ config SOFTWARE_SUSPEND
depends on PM && SWAP && (X86 && (!SMP || SUSPEND_SMP)) || ((FRV || PPC32) && !SMP)
---help---
Enable the possibility of suspending the machine.
- It doesn't need APM.
+ It doesn't need ACPI or APM.
You may suspend your machine by 'swsusp' or 'shutdown -z <time>'
(patch for sysvinit needed).
diff --git a/kernel/printk.c b/kernel/printk.c
index 8cc19431e74..c056f332443 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -360,8 +360,7 @@ static void call_console_drivers(unsigned long start, unsigned long end)
unsigned long cur_index, start_print;
static int msg_level = -1;
- if (((long)(start - end)) > 0)
- BUG();
+ BUG_ON(((long)(start - end)) > 0);
cur_index = start;
start_print = start;
@@ -708,8 +707,7 @@ int __init add_preferred_console(char *name, int idx, char *options)
*/
void acquire_console_sem(void)
{
- if (in_interrupt())
- BUG();
+ BUG_ON(in_interrupt());
down(&console_sem);
console_locked = 1;
console_may_schedule = 1;
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 86a7f6c60cb..0eeb7e66722 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -30,8 +30,7 @@
*/
void __ptrace_link(task_t *child, task_t *new_parent)
{
- if (!list_empty(&child->ptrace_list))
- BUG();
+ BUG_ON(!list_empty(&child->ptrace_list));
if (child->parent == new_parent)
return;
list_add(&child->ptrace_list, &child->parent->ptrace_children);
diff --git a/kernel/signal.c b/kernel/signal.c
index 92025b10879..5ccaac505e8 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -769,8 +769,7 @@ specific_send_sig_info(int sig, struct siginfo *info, struct task_struct *t)
{
int ret = 0;
- if (!irqs_disabled())
- BUG();
+ BUG_ON(!irqs_disabled());
assert_spin_locked(&t->sighand->siglock);
/* Short-circuit ignored signals. */
@@ -1384,8 +1383,7 @@ send_group_sigqueue(int sig, struct sigqueue *q, struct task_struct *p)
* the overrun count. Other uses should not try to
* send the signal multiple times.
*/
- if (q->info.si_code != SI_TIMER)
- BUG();
+ BUG_ON(q->info.si_code != SI_TIMER);
q->info.si_overrun++;
goto out;
}
diff --git a/kernel/time.c b/kernel/time.c
index ff8e7019c4c..b00ddc71ced 100644
--- a/kernel/time.c
+++ b/kernel/time.c
@@ -410,7 +410,7 @@ EXPORT_SYMBOL(current_kernel_time);
* current_fs_time - Return FS time
* @sb: Superblock.
*
- * Return the current time truncated to the time granuality supported by
+ * Return the current time truncated to the time granularity supported by
* the fs.
*/
struct timespec current_fs_time(struct super_block *sb)
@@ -421,11 +421,11 @@ struct timespec current_fs_time(struct super_block *sb)
EXPORT_SYMBOL(current_fs_time);
/**
- * timespec_trunc - Truncate timespec to a granuality
+ * timespec_trunc - Truncate timespec to a granularity
* @t: Timespec
- * @gran: Granuality in ns.
+ * @gran: Granularity in ns.
*
- * Truncate a timespec to a granuality. gran must be smaller than a second.
+ * Truncate a timespec to a granularity. gran must be smaller than a second.
* Always rounds down.
*
* This function should be only used for timestamps returned by
diff --git a/kernel/timer.c b/kernel/timer.c
index 6b812c04737..c3a874f1393 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -1479,8 +1479,7 @@ register_time_interpolator(struct time_interpolator *ti)
unsigned long flags;
/* Sanity check */
- if (ti->frequency == 0 || ti->mask == 0)
- BUG();
+ BUG_ON(ti->frequency == 0 || ti->mask == 0);
ti->nsec_per_cyc = ((u64)NSEC_PER_SEC << ti->shift) / ti->frequency;
spin_lock(&time_interpolator_lock);
diff --git a/mm/highmem.c b/mm/highmem.c
index 55885f64af4..9b274fdf9d0 100644
--- a/mm/highmem.c
+++ b/mm/highmem.c
@@ -74,8 +74,7 @@ static void flush_all_zero_pkmaps(void)
pkmap_count[i] = 0;
/* sanity check */
- if (pte_none(pkmap_page_table[i]))
- BUG();
+ BUG_ON(pte_none(pkmap_page_table[i]));
/*
* Don't need an atomic fetch-and-clear op here;
@@ -158,8 +157,7 @@ void fastcall *kmap_high(struct page *page)
if (!vaddr)
vaddr = map_new_virtual(page);
pkmap_count[PKMAP_NR(vaddr)]++;
- if (pkmap_count[PKMAP_NR(vaddr)] < 2)
- BUG();
+ BUG_ON(pkmap_count[PKMAP_NR(vaddr)] < 2);
spin_unlock(&kmap_lock);
return (void*) vaddr;
}
@@ -174,8 +172,7 @@ void fastcall kunmap_high(struct page *page)
spin_lock(&kmap_lock);
vaddr = (unsigned long)page_address(page);
- if (!vaddr)
- BUG();
+ BUG_ON(!vaddr);
nr = PKMAP_NR(vaddr);
/*
@@ -220,8 +217,7 @@ static __init int init_emergency_pool(void)
return 0;
page_pool = mempool_create_page_pool(POOL_SIZE, 0);
- if (!page_pool)
- BUG();
+ BUG_ON(!page_pool);
printk("highmem bounce pool size: %d pages\n", POOL_SIZE);
return 0;
@@ -264,8 +260,7 @@ int init_emergency_isa_pool(void)
isa_page_pool = mempool_create(ISA_POOL_SIZE, mempool_alloc_pages_isa,
mempool_free_pages, (void *) 0);
- if (!isa_page_pool)
- BUG();
+ BUG_ON(!isa_page_pool);
printk("isa bounce pool size: %d pages\n", ISA_POOL_SIZE);
return 0;
diff --git a/mm/mmap.c b/mm/mmap.c
index 4f5b5709136..e780d19aa21 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -294,8 +294,7 @@ void validate_mm(struct mm_struct *mm)
i = browse_rb(&mm->mm_rb);
if (i != mm->map_count)
printk("map_count %d rb %d\n", mm->map_count, i), bug = 1;
- if (bug)
- BUG();
+ BUG_ON(bug);
}
#else
#define validate_mm(mm) do { } while (0)
@@ -432,8 +431,7 @@ __insert_vm_struct(struct mm_struct * mm, struct vm_area_struct * vma)
struct rb_node ** rb_link, * rb_parent;
__vma = find_vma_prepare(mm, vma->vm_start,&prev, &rb_link, &rb_parent);
- if (__vma && __vma->vm_start < vma->vm_end)
- BUG();
+ BUG_ON(__vma && __vma->vm_start < vma->vm_end);
__vma_link(mm, vma, prev, rb_link, rb_parent);
mm->map_count++;
}
@@ -813,8 +811,7 @@ try_prev:
* (e.g. stash info in next's anon_vma_node when assigning
* an anon_vma, or when trying vma_merge). Another time.
*/
- if (find_vma_prev(vma->vm_mm, vma->vm_start, &near) != vma)
- BUG();
+ BUG_ON(find_vma_prev(vma->vm_mm, vma->vm_start, &near) != vma);
if (!near)
goto none;
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index 893d7677579..6dcce3a4bbd 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -258,7 +258,7 @@ static void balance_dirty_pages(struct address_space *mapping)
/**
* balance_dirty_pages_ratelimited_nr - balance dirty memory state
* @mapping: address_space which was dirtied
- * @nr_pages: number of pages which the caller has just dirtied
+ * @nr_pages_dirtied: number of pages which the caller has just dirtied
*
* Processes which are dirtying memory should call in here once for each page
* which was newly dirtied. The function will periodically check the system's
diff --git a/mm/slab.c b/mm/slab.c
index 4cbf8bb1355..f055c142021 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -1297,8 +1297,7 @@ void __init kmem_cache_init(void)
if (cache_cache.num)
break;
}
- if (!cache_cache.num)
- BUG();
+ BUG_ON(!cache_cache.num);
cache_cache.gfporder = order;
cache_cache.colour = left_over / cache_cache.colour_off;
cache_cache.slab_size = ALIGN(cache_cache.num * sizeof(kmem_bufctl_t) +
@@ -1974,8 +1973,7 @@ kmem_cache_create (const char *name, size_t size, size_t align,
* Always checks flags, a caller might be expecting debug support which
* isn't available.
*/
- if (flags & ~CREATE_MASK)
- BUG();
+ BUG_ON(flags & ~CREATE_MASK);
/*
* Check that size is in terms of words. This is needed to avoid
@@ -2206,8 +2204,7 @@ static int __node_shrink(struct kmem_cache *cachep, int node)
slabp = list_entry(l3->slabs_free.prev, struct slab, list);
#if DEBUG
- if (slabp->inuse)
- BUG();
+ BUG_ON(slabp->inuse);
#endif
list_del(&slabp->list);
@@ -2248,8 +2245,7 @@ static int __cache_shrink(struct kmem_cache *cachep)
*/
int kmem_cache_shrink(struct kmem_cache *cachep)
{
- if (!cachep || in_interrupt())
- BUG();
+ BUG_ON(!cachep || in_interrupt());
return __cache_shrink(cachep);
}
@@ -2277,8 +2273,7 @@ int kmem_cache_destroy(struct kmem_cache *cachep)
int i;
struct kmem_list3 *l3;
- if (!cachep || in_interrupt())
- BUG();
+ BUG_ON(!cachep || in_interrupt());
/* Don't let CPUs to come and go */
lock_cpu_hotplug();
@@ -2477,8 +2472,7 @@ static int cache_grow(struct kmem_cache *cachep, gfp_t flags, int nodeid)
* Be lazy and only check for valid flags here, keeping it out of the
* critical path in kmem_cache_alloc().
*/
- if (flags & ~(SLAB_DMA | SLAB_LEVEL_MASK | SLAB_NO_GROW))
- BUG();
+ BUG_ON(flags & ~(SLAB_DMA | SLAB_LEVEL_MASK | SLAB_NO_GROW));
if (flags & SLAB_NO_GROW)
return 0;
diff --git a/mm/swap_state.c b/mm/swap_state.c
index d7af296833f..e0e1583f32c 100644
--- a/mm/swap_state.c
+++ b/mm/swap_state.c
@@ -148,8 +148,7 @@ int add_to_swap(struct page * page, gfp_t gfp_mask)
swp_entry_t entry;
int err;
- if (!PageLocked(page))
- BUG();
+ BUG_ON(!PageLocked(page));
for (;;) {
entry = get_swap_page();
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 729eb3eec75..c0504f1e34e 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -321,8 +321,7 @@ void __vunmap(void *addr, int deallocate_pages)
int i;
for (i = 0; i < area->nr_pages; i++) {
- if (unlikely(!area->pages[i]))
- BUG();
+ BUG_ON(!area->pages[i]);
__free_page(area->pages[i]);
}
diff --git a/sound/core/Kconfig b/sound/core/Kconfig
index 9dd121bb563..8efc1b12f3a 100644
--- a/sound/core/Kconfig
+++ b/sound/core/Kconfig
@@ -92,8 +92,9 @@ config SND_SEQUENCER_OSS
Many programs still use the OSS API, so say Y.
- To compile this driver as a module, choose M here: the module
- will be called snd-seq-oss.
+ If you choose M in "Sequencer support" (SND_SEQUENCER),
+ this will be compiled as a module. The module will be called
+ snd-seq-oss.
config SND_RTCTIMER
tristate "RTC Timer support"
diff --git a/sound/core/control.c b/sound/core/control.c
index 574745314e7..22565c9b960 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -664,7 +664,7 @@ static int snd_ctl_elem_info_user(struct snd_ctl_file *ctl,
if (copy_from_user(&info, _info, sizeof(info)))
return -EFAULT;
snd_power_lock(ctl->card);
- result = snd_power_wait(ctl->card, SNDRV_CTL_POWER_D0, NULL);
+ result = snd_power_wait(ctl->card, SNDRV_CTL_POWER_D0);
if (result >= 0)
result = snd_ctl_elem_info(ctl, &info);
snd_power_unlock(ctl->card);
@@ -718,7 +718,7 @@ static int snd_ctl_elem_read_user(struct snd_card *card,
return -EFAULT;
}
snd_power_lock(card);
- result = snd_power_wait(card, SNDRV_CTL_POWER_D0, NULL);
+ result = snd_power_wait(card, SNDRV_CTL_POWER_D0);
if (result >= 0)
result = snd_ctl_elem_read(card, control);
snd_power_unlock(card);
@@ -783,7 +783,7 @@ static int snd_ctl_elem_write_user(struct snd_ctl_file *file,
}
card = file->card;
snd_power_lock(card);
- result = snd_power_wait(card, SNDRV_CTL_POWER_D0, NULL);
+ result = snd_power_wait(card, SNDRV_CTL_POWER_D0);
if (result >= 0)
result = snd_ctl_elem_write(card, file, control);
snd_power_unlock(card);
diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c
index 84fef5084e1..3c0161bb5ba 100644
--- a/sound/core/control_compat.c
+++ b/sound/core/control_compat.c
@@ -109,7 +109,7 @@ static int snd_ctl_elem_info_compat(struct snd_ctl_file *ctl,
goto error;
snd_power_lock(ctl->card);
- err = snd_power_wait(ctl->card, SNDRV_CTL_POWER_D0, NULL);
+ err = snd_power_wait(ctl->card, SNDRV_CTL_POWER_D0);
if (err >= 0)
err = snd_ctl_elem_info(ctl, data);
snd_power_unlock(ctl->card);
@@ -294,7 +294,7 @@ static int snd_ctl_elem_read_user_compat(struct snd_card *card,
goto error;
snd_power_lock(card);
- err = snd_power_wait(card, SNDRV_CTL_POWER_D0, NULL);
+ err = snd_power_wait(card, SNDRV_CTL_POWER_D0);
if (err >= 0)
err = snd_ctl_elem_read(card, data);
snd_power_unlock(card);
@@ -320,7 +320,7 @@ static int snd_ctl_elem_write_user_compat(struct snd_ctl_file *file,
goto error;
snd_power_lock(card);
- err = snd_power_wait(card, SNDRV_CTL_POWER_D0, NULL);
+ err = snd_power_wait(card, SNDRV_CTL_POWER_D0);
if (err >= 0)
err = snd_ctl_elem_write(card, file, data);
snd_power_unlock(card);
diff --git a/sound/core/init.c b/sound/core/init.c
index 5bb8a8b23d5..39ed2e5bb0a 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -722,13 +722,12 @@ int snd_card_file_remove(struct snd_card *card, struct file *file)
* snd_power_wait - wait until the power-state is changed.
* @card: soundcard structure
* @power_state: expected power state
- * @file: file structure for the O_NONBLOCK check (optional)
*
* Waits until the power-state is changed.
*
* Note: the power lock must be active before call.
*/
-int snd_power_wait(struct snd_card *card, unsigned int power_state, struct file *file)
+int snd_power_wait(struct snd_card *card, unsigned int power_state)
{
wait_queue_t wait;
int result = 0;
@@ -745,12 +744,6 @@ int snd_power_wait(struct snd_card *card, unsigned int power_state, struct file
}
if (snd_power_get_state(card) == power_state)
break;
-#if 0 /* block all devices */
- if (file && (file->f_flags & O_NONBLOCK)) {
- result = -EAGAIN;
- break;
- }
-#endif
set_current_state(TASK_UNINTERRUPTIBLE);
snd_power_unlock(card);
schedule_timeout(30 * HZ);
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index f8302b703a3..91114c7aeff 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -208,9 +208,8 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream,
oss_buffer_size = runtime->oss.mmap_bytes;
}
- if (substream->oss.setup &&
- substream->oss.setup->period_size > 16)
- oss_period_size = substream->oss.setup->period_size;
+ if (substream->oss.setup.period_size > 16)
+ oss_period_size = substream->oss.setup.period_size;
else if (runtime->oss.fragshift) {
oss_period_size = 1 << runtime->oss.fragshift;
if (oss_period_size > oss_buffer_size / 2)
@@ -252,10 +251,8 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream,
oss_periods = oss_buffer_size / oss_period_size;
- if (substream->oss.setup) {
- if (substream->oss.setup->periods > 1)
- oss_periods = substream->oss.setup->periods;
- }
+ if (substream->oss.setup.periods > 1)
+ oss_periods = substream->oss.setup.periods;
s = snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_PERIODS, NULL);
if (runtime->oss.maxfrags && s > runtime->oss.maxfrags)
@@ -341,12 +338,10 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
goto failure;
}
- if (atomic_read(&runtime->mmap_count)) {
+ if (atomic_read(&runtime->mmap_count))
direct = 1;
- } else {
- struct snd_pcm_oss_setup *setup = substream->oss.setup;
- direct = (setup != NULL && setup->direct);
- }
+ else
+ direct = substream->oss.setup.direct;
_snd_pcm_hw_params_any(sparams);
_snd_pcm_hw_param_setinteger(sparams, SNDRV_PCM_HW_PARAM_PERIODS);
@@ -482,7 +477,7 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
1 : runtime->period_size;
sw_params->xfer_align = 1;
if (atomic_read(&runtime->mmap_count) ||
- (substream->oss.setup && substream->oss.setup->nosilence)) {
+ substream->oss.setup.nosilence) {
sw_params->silence_threshold = 0;
sw_params->silence_size = 0;
} else {
@@ -843,7 +838,7 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha
buf += tmp;
bytes -= tmp;
xfer += tmp;
- if ((substream->oss.setup != NULL && substream->oss.setup->partialfrag) ||
+ if (substream->oss.setup.partialfrag ||
runtime->oss.buffer_used == runtime->oss.period_bytes) {
tmp = snd_pcm_oss_write2(substream, runtime->oss.buffer + runtime->oss.period_ptr,
runtime->oss.buffer_used - runtime->oss.period_ptr, 1);
@@ -959,12 +954,12 @@ static int snd_pcm_oss_reset(struct snd_pcm_oss_file *pcm_oss_file)
substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
if (substream != NULL) {
- snd_pcm_kernel_playback_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
+ snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
substream->runtime->oss.prepare = 1;
}
substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
if (substream != NULL) {
- snd_pcm_kernel_capture_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
+ snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
substream->runtime->oss.prepare = 1;
}
return 0;
@@ -979,7 +974,7 @@ static int snd_pcm_oss_post(struct snd_pcm_oss_file *pcm_oss_file)
if (substream != NULL) {
if ((err = snd_pcm_oss_make_ready(substream)) < 0)
return err;
- snd_pcm_kernel_playback_ioctl(substream, SNDRV_PCM_IOCTL_START, NULL);
+ snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_START, NULL);
}
/* note: all errors from the start action are ignored */
/* OSS apps do not know, how to handle them */
@@ -1108,7 +1103,7 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file)
__direct:
saved_f_flags = substream->ffile->f_flags;
substream->ffile->f_flags &= ~O_NONBLOCK;
- err = snd_pcm_kernel_playback_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL);
+ err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL);
substream->ffile->f_flags = saved_f_flags;
if (err < 0)
return err;
@@ -1120,7 +1115,7 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file)
if ((err = snd_pcm_oss_make_ready(substream)) < 0)
return err;
runtime = substream->runtime;
- err = snd_pcm_kernel_capture_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
+ err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
if (err < 0)
return err;
runtime->oss.buffer_used = 0;
@@ -1214,12 +1209,10 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)
if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)
return err;
- if (atomic_read(&substream->runtime->mmap_count)) {
+ if (atomic_read(&substream->runtime->mmap_count))
direct = 1;
- } else {
- struct snd_pcm_oss_setup *setup = substream->oss.setup;
- direct = (setup != NULL && setup->direct);
- }
+ else
+ direct = substream->oss.setup.direct;
if (!direct)
return AFMT_MU_LAW | AFMT_U8 |
AFMT_S16_LE | AFMT_S16_BE |
@@ -1437,7 +1430,7 @@ static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int tr
cmd = SNDRV_PCM_IOCTL_DROP;
runtime->oss.prepare = 1;
}
- err = snd_pcm_kernel_playback_ioctl(psubstream, cmd, NULL);
+ err = snd_pcm_kernel_ioctl(psubstream, cmd, NULL);
if (err < 0)
return err;
}
@@ -1458,7 +1451,7 @@ static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int tr
cmd = SNDRV_PCM_IOCTL_DROP;
runtime->oss.prepare = 1;
}
- err = snd_pcm_kernel_capture_ioctl(csubstream, cmd, NULL);
+ err = snd_pcm_kernel_ioctl(csubstream, cmd, NULL);
if (err < 0)
return err;
}
@@ -1495,7 +1488,7 @@ static int snd_pcm_oss_get_odelay(struct snd_pcm_oss_file *pcm_oss_file)
runtime = substream->runtime;
if (runtime->oss.params || runtime->oss.prepare)
return 0;
- err = snd_pcm_kernel_playback_ioctl(substream, SNDRV_PCM_IOCTL_DELAY, &delay);
+ err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DELAY, &delay);
if (err == -EPIPE)
delay = 0; /* hack for broken OSS applications */
else if (err < 0)
@@ -1555,8 +1548,7 @@ static int snd_pcm_oss_get_ptr(struct snd_pcm_oss_file *pcm_oss_file, int stream
} else {
delay = snd_pcm_oss_bytes(substream, delay);
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
- struct snd_pcm_oss_setup *setup = substream->oss.setup;
- if (setup && setup->buggyptr)
+ if (substream->oss.setup.buggyptr)
info.blocks = (runtime->oss.buffer_bytes - delay - fixup) / runtime->oss.period_bytes;
else
info.blocks = (delay + fixup) / runtime->oss.period_bytes;
@@ -1638,37 +1630,46 @@ static int snd_pcm_oss_get_mapbuf(struct snd_pcm_oss_file *pcm_oss_file, int str
return -EINVAL;
}
-static struct snd_pcm_oss_setup *snd_pcm_oss_look_for_setup(struct snd_pcm *pcm, int stream, const char *task_name)
+static const char *strip_task_path(const char *path)
{
- const char *ptr, *ptrl;
- struct snd_pcm_oss_setup *setup;
-
- mutex_lock(&pcm->streams[stream].oss.setup_mutex);
- for (setup = pcm->streams[stream].oss.setup_list; setup; setup = setup->next) {
- if (!strcmp(setup->task_name, task_name)) {
- mutex_unlock(&pcm->streams[stream].oss.setup_mutex);
- return setup;
- }
- }
- ptr = ptrl = task_name;
- while (*ptr) {
+ const char *ptr, *ptrl = NULL;
+ for (ptr = path; *ptr; ptr++) {
if (*ptr == '/')
ptrl = ptr + 1;
- ptr++;
}
- if (ptrl == task_name) {
- goto __not_found;
- return NULL;
- }
- for (setup = pcm->streams[stream].oss.setup_list; setup; setup = setup->next) {
- if (!strcmp(setup->task_name, ptrl)) {
- mutex_unlock(&pcm->streams[stream].oss.setup_mutex);
- return setup;
+ return ptrl;
+}
+
+static void snd_pcm_oss_look_for_setup(struct snd_pcm *pcm, int stream,
+ const char *task_name,
+ struct snd_pcm_oss_setup *rsetup)
+{
+ struct snd_pcm_oss_setup *setup;
+
+ mutex_lock(&pcm->streams[stream].oss.setup_mutex);
+ do {
+ for (setup = pcm->streams[stream].oss.setup_list; setup;
+ setup = setup->next) {
+ if (!strcmp(setup->task_name, task_name))
+ goto out;
}
- }
- __not_found:
+ } while ((task_name = strip_task_path(task_name)) != NULL);
+ out:
+ if (setup)
+ *rsetup = *setup;
mutex_unlock(&pcm->streams[stream].oss.setup_mutex);
- return NULL;
+}
+
+static void snd_pcm_oss_release_substream(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime;
+ runtime = substream->runtime;
+ vfree(runtime->oss.buffer);
+ runtime->oss.buffer = NULL;
+#ifdef CONFIG_SND_PCM_OSS_PLUGINS
+ snd_pcm_oss_plugin_clear(substream);
+#endif
+ substream->oss.oss = 0;
}
static void snd_pcm_oss_init_substream(struct snd_pcm_substream *substream,
@@ -1678,7 +1679,11 @@ static void snd_pcm_oss_init_substream(struct snd_pcm_substream *substream,
struct snd_pcm_runtime *runtime;
substream->oss.oss = 1;
- substream->oss.setup = setup;
+ substream->oss.setup = *setup;
+ if (setup->nonblock)
+ substream->ffile->f_flags |= O_NONBLOCK;
+ else
+ substream->ffile->f_flags &= ~O_NONBLOCK;
runtime = substream->runtime;
runtime->oss.params = 1;
runtime->oss.trigger = 1;
@@ -1697,18 +1702,7 @@ static void snd_pcm_oss_init_substream(struct snd_pcm_substream *substream,
runtime->oss.fragshift = 0;
runtime->oss.maxfrags = 0;
runtime->oss.subdivision = 0;
-}
-
-static void snd_pcm_oss_release_substream(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime;
- runtime = substream->runtime;
- vfree(runtime->oss.buffer);
-#ifdef CONFIG_SND_PCM_OSS_PLUGINS
- snd_pcm_oss_plugin_clear(substream);
-#endif
- substream->oss.file = NULL;
- substream->oss.oss = 0;
+ substream->pcm_release = snd_pcm_oss_release_substream;
}
static int snd_pcm_oss_release_file(struct snd_pcm_oss_file *pcm_oss_file)
@@ -1717,23 +1711,8 @@ static int snd_pcm_oss_release_file(struct snd_pcm_oss_file *pcm_oss_file)
snd_assert(pcm_oss_file != NULL, return -ENXIO);
for (cidx = 0; cidx < 2; ++cidx) {
struct snd_pcm_substream *substream = pcm_oss_file->streams[cidx];
- struct snd_pcm_runtime *runtime;
- if (substream == NULL)
- continue;
- runtime = substream->runtime;
-
- snd_pcm_stream_lock_irq(substream);
- if (snd_pcm_running(substream))
- snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
- snd_pcm_stream_unlock_irq(substream);
- if (substream->ffile != NULL) {
- if (substream->ops->hw_free != NULL)
- substream->ops->hw_free(substream);
- substream->ops->close(substream);
- substream->ffile = NULL;
- }
- snd_pcm_oss_release_substream(substream);
- snd_pcm_release_substream(substream);
+ if (substream)
+ snd_pcm_release_substream(substream);
}
kfree(pcm_oss_file);
return 0;
@@ -1743,12 +1722,11 @@ static int snd_pcm_oss_open_file(struct file *file,
struct snd_pcm *pcm,
struct snd_pcm_oss_file **rpcm_oss_file,
int minor,
- struct snd_pcm_oss_setup *psetup,
- struct snd_pcm_oss_setup *csetup)
+ struct snd_pcm_oss_setup *setup)
{
- int err = 0;
+ int idx, err;
struct snd_pcm_oss_file *pcm_oss_file;
- struct snd_pcm_substream *psubstream = NULL, *csubstream = NULL;
+ struct snd_pcm_substream *substream;
unsigned int f_mode = file->f_mode;
snd_assert(rpcm_oss_file != NULL, return -EINVAL);
@@ -1761,73 +1739,31 @@ static int snd_pcm_oss_open_file(struct file *file,
if ((f_mode & (FMODE_WRITE|FMODE_READ)) == (FMODE_WRITE|FMODE_READ) &&
(pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX))
f_mode = FMODE_WRITE;
- if ((f_mode & FMODE_WRITE) && !(psetup && psetup->disable)) {
- if ((err = snd_pcm_open_substream(pcm, SNDRV_PCM_STREAM_PLAYBACK,
- &psubstream)) < 0) {
+
+ for (idx = 0; idx < 2; idx++) {
+ if (setup[idx].disable)
+ continue;
+ if (idx == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (! (f_mode & FMODE_WRITE))
+ continue;
+ } else {
+ if (! (f_mode & FMODE_READ))
+ continue;
+ }
+ err = snd_pcm_open_substream(pcm, idx, file, &substream);
+ if (err < 0) {
snd_pcm_oss_release_file(pcm_oss_file);
return err;
}
- pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK] = psubstream;
- }
- if ((f_mode & FMODE_READ) && !(csetup && csetup->disable)) {
- if ((err = snd_pcm_open_substream(pcm, SNDRV_PCM_STREAM_CAPTURE,
- &csubstream)) < 0) {
- if (!(f_mode & FMODE_WRITE) || err != -ENODEV) {
- snd_pcm_oss_release_file(pcm_oss_file);
- return err;
- } else {
- csubstream = NULL;
- }
- }
- pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE] = csubstream;
+
+ pcm_oss_file->streams[idx] = substream;
+ snd_pcm_oss_init_substream(substream, &setup[idx], minor);
}
- if (psubstream == NULL && csubstream == NULL) {
+ if (! pcm_oss_file->streams[0] && pcm_oss_file->streams[1]) {
snd_pcm_oss_release_file(pcm_oss_file);
return -EINVAL;
}
- if (psubstream != NULL) {
- psubstream->oss.file = pcm_oss_file;
- err = snd_pcm_hw_constraints_init(psubstream);
- if (err < 0) {
- snd_printd("snd_pcm_hw_constraint_init failed\n");
- snd_pcm_oss_release_file(pcm_oss_file);
- return err;
- }
- if ((err = psubstream->ops->open(psubstream)) < 0) {
- snd_pcm_oss_release_file(pcm_oss_file);
- return err;
- }
- psubstream->ffile = file;
- err = snd_pcm_hw_constraints_complete(psubstream);
- if (err < 0) {
- snd_printd("snd_pcm_hw_constraint_complete failed\n");
- snd_pcm_oss_release_file(pcm_oss_file);
- return err;
- }
- snd_pcm_oss_init_substream(psubstream, psetup, minor);
- }
- if (csubstream != NULL) {
- csubstream->oss.file = pcm_oss_file;
- err = snd_pcm_hw_constraints_init(csubstream);
- if (err < 0) {
- snd_printd("snd_pcm_hw_constraint_init failed\n");
- snd_pcm_oss_release_file(pcm_oss_file);
- return err;
- }
- if ((err = csubstream->ops->open(csubstream)) < 0) {
- snd_pcm_oss_release_file(pcm_oss_file);
- return err;
- }
- csubstream->ffile = file;
- err = snd_pcm_hw_constraints_complete(csubstream);
- if (err < 0) {
- snd_printd("snd_pcm_hw_constraint_complete failed\n");
- snd_pcm_oss_release_file(pcm_oss_file);
- return err;
- }
- snd_pcm_oss_init_substream(csubstream, csetup, minor);
- }
file->private_data = pcm_oss_file;
*rpcm_oss_file = pcm_oss_file;
@@ -1852,7 +1788,7 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file)
char task_name[32];
struct snd_pcm *pcm;
struct snd_pcm_oss_file *pcm_oss_file;
- struct snd_pcm_oss_setup *psetup = NULL, *csetup = NULL;
+ struct snd_pcm_oss_setup setup[2];
int nonblock;
wait_queue_t wait;
@@ -1873,23 +1809,15 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file)
err = -EFAULT;
goto __error;
}
+ memset(setup, 0, sizeof(*setup));
if (file->f_mode & FMODE_WRITE)
- psetup = snd_pcm_oss_look_for_setup(pcm, SNDRV_PCM_STREAM_PLAYBACK, task_name);
+ snd_pcm_oss_look_for_setup(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ task_name, &setup[0]);
if (file->f_mode & FMODE_READ)
- csetup = snd_pcm_oss_look_for_setup(pcm, SNDRV_PCM_STREAM_CAPTURE, task_name);
+ snd_pcm_oss_look_for_setup(pcm, SNDRV_PCM_STREAM_CAPTURE,
+ task_name, &setup[1]);
nonblock = !!(file->f_flags & O_NONBLOCK);
- if (psetup && !psetup->disable) {
- if (psetup->nonblock)
- nonblock = 1;
- else if (psetup->block)
- nonblock = 0;
- } else if (csetup && !csetup->disable) {
- if (csetup->nonblock)
- nonblock = 1;
- else if (csetup->block)
- nonblock = 0;
- }
if (!nonblock)
nonblock = nonblock_open;
@@ -1898,7 +1826,7 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file)
mutex_lock(&pcm->open_mutex);
while (1) {
err = snd_pcm_oss_open_file(file, pcm, &pcm_oss_file,
- iminor(inode), psetup, csetup);
+ iminor(inode), setup);
if (err >= 0)
break;
if (err == -EAGAIN) {
@@ -2312,13 +2240,8 @@ static void snd_pcm_oss_proc_read(struct snd_info_entry *entry,
static void snd_pcm_oss_proc_free_setup_list(struct snd_pcm_str * pstr)
{
- unsigned int idx;
- struct snd_pcm_substream *substream;
struct snd_pcm_oss_setup *setup, *setupn;
- for (idx = 0, substream = pstr->substream;
- idx < pstr->substream_count; idx++, substream = substream->next)
- substream->oss.setup = NULL;
for (setup = pstr->oss.setup_list, pstr->oss.setup_list = NULL;
setup; setup = setupn) {
setupn = setup->next;
@@ -2379,21 +2302,28 @@ static void snd_pcm_oss_proc_write(struct snd_info_entry *entry,
}
} while (*str);
if (setup == NULL) {
- setup = kmalloc(sizeof(struct snd_pcm_oss_setup), GFP_KERNEL);
- if (setup) {
- if (pstr->oss.setup_list == NULL) {
- pstr->oss.setup_list = setup;
- } else {
- for (setup1 = pstr->oss.setup_list; setup1->next; setup1 = setup1->next);
- setup1->next = setup;
- }
- template.task_name = kstrdup(task_name, GFP_KERNEL);
- } else {
+ setup = kmalloc(sizeof(*setup), GFP_KERNEL);
+ if (! setup) {
+ buffer->error = -ENOMEM;
+ mutex_lock(&pstr->oss.setup_mutex);
+ return;
+ }
+ if (pstr->oss.setup_list == NULL)
+ pstr->oss.setup_list = setup;
+ else {
+ for (setup1 = pstr->oss.setup_list;
+ setup1->next; setup1 = setup1->next);
+ setup1->next = setup;
+ }
+ template.task_name = kstrdup(task_name, GFP_KERNEL);
+ if (! template.task_name) {
+ kfree(setup);
buffer->error = -ENOMEM;
+ mutex_lock(&pstr->oss.setup_mutex);
+ return;
}
}
- if (setup)
- *setup = template;
+ *setup = template;
mutex_unlock(&pstr->oss.setup_mutex);
}
}
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index 3da6a38c2d0..5d7eb123b99 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -777,8 +777,9 @@ static void snd_pcm_tick_timer_func(unsigned long data)
snd_pcm_tick_elapsed(substream);
}
-int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
- struct snd_pcm_substream **rsubstream)
+int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
+ struct file *file,
+ struct snd_pcm_substream **rsubstream)
{
struct snd_pcm_str * pstr;
struct snd_pcm_substream *substream;
@@ -793,7 +794,7 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
*rsubstream = NULL;
snd_assert(pcm != NULL, return -ENXIO);
pstr = &pcm->streams[stream];
- if (pstr->substream == NULL)
+ if (pstr->substream == NULL || pstr->substream_count == 0)
return -ENODEV;
card = pcm->card;
@@ -807,8 +808,6 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
}
up_read(&card->controls_rwsem);
- if (pstr->substream_count == 0)
- return -ENODEV;
switch (stream) {
case SNDRV_PCM_STREAM_PLAYBACK:
if (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX) {
@@ -874,12 +873,13 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
substream->runtime = runtime;
substream->private_data = pcm->private_data;
+ substream->ffile = file;
pstr->substream_opened++;
*rsubstream = substream;
return 0;
}
-void snd_pcm_release_substream(struct snd_pcm_substream *substream)
+void snd_pcm_detach_substream(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime;
substream->file = NULL;
@@ -1111,8 +1111,6 @@ EXPORT_SYMBOL(snd_pcm_link_rwlock);
EXPORT_SYMBOL(snd_pcm_suspend);
EXPORT_SYMBOL(snd_pcm_suspend_all);
#endif
-EXPORT_SYMBOL(snd_pcm_kernel_playback_ioctl);
-EXPORT_SYMBOL(snd_pcm_kernel_capture_ioctl);
EXPORT_SYMBOL(snd_pcm_kernel_ioctl);
EXPORT_SYMBOL(snd_pcm_mmap_data);
#if SNDRV_PCM_INFO_MMAP_IOMEM
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index eeba2f06095..230a940d00b 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -2299,19 +2299,7 @@ snd_pcm_sframes_t snd_pcm_lib_write(struct snd_pcm_substream *substream, const v
if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
return -EBADFD;
- snd_assert(substream->ffile != NULL, return -ENXIO);
nonblock = !!(substream->ffile->f_flags & O_NONBLOCK);
-#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
- if (substream->oss.oss) {
- struct snd_pcm_oss_setup *setup = substream->oss.setup;
- if (setup != NULL) {
- if (setup->nonblock)
- nonblock = 1;
- else if (setup->block)
- nonblock = 0;
- }
- }
-#endif
if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED &&
runtime->channels > 1)
@@ -2374,19 +2362,7 @@ snd_pcm_sframes_t snd_pcm_lib_writev(struct snd_pcm_substream *substream,
if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
return -EBADFD;
- snd_assert(substream->ffile != NULL, return -ENXIO);
nonblock = !!(substream->ffile->f_flags & O_NONBLOCK);
-#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
- if (substream->oss.oss) {
- struct snd_pcm_oss_setup *setup = substream->oss.setup;
- if (setup != NULL) {
- if (setup->nonblock)
- nonblock = 1;
- else if (setup->block)
- nonblock = 0;
- }
- }
-#endif
if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED)
return -EINVAL;
@@ -2596,19 +2572,7 @@ snd_pcm_sframes_t snd_pcm_lib_read(struct snd_pcm_substream *substream, void __u
if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
return -EBADFD;
- snd_assert(substream->ffile != NULL, return -ENXIO);
nonblock = !!(substream->ffile->f_flags & O_NONBLOCK);
-#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
- if (substream->oss.oss) {
- struct snd_pcm_oss_setup *setup = substream->oss.setup;
- if (setup != NULL) {
- if (setup->nonblock)
- nonblock = 1;
- else if (setup->block)
- nonblock = 0;
- }
- }
-#endif
if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED)
return -EINVAL;
return snd_pcm_lib_read1(substream, (unsigned long)buf, size, nonblock, snd_pcm_lib_read_transfer);
@@ -2665,20 +2629,7 @@ snd_pcm_sframes_t snd_pcm_lib_readv(struct snd_pcm_substream *substream,
if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
return -EBADFD;
- snd_assert(substream->ffile != NULL, return -ENXIO);
nonblock = !!(substream->ffile->f_flags & O_NONBLOCK);
-#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
- if (substream->oss.oss) {
- struct snd_pcm_oss_setup *setup = substream->oss.setup;
- if (setup != NULL) {
- if (setup->nonblock)
- nonblock = 1;
- else if (setup->block)
- nonblock = 0;
- }
- }
-#endif
-
if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED)
return -EINVAL;
return snd_pcm_lib_read1(substream, (unsigned long)bufs, frames, nonblock, snd_pcm_lib_readv_transfer);
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 01f150f0990..964e4c47a7f 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -1170,7 +1170,7 @@ static int snd_pcm_resume(struct snd_pcm_substream *substream)
int res;
snd_power_lock(card);
- if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile)) >= 0)
+ if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0)) >= 0)
res = snd_pcm_action_lock_irq(&snd_pcm_action_resume, substream, 0);
snd_power_unlock(card);
return res;
@@ -1198,7 +1198,7 @@ static int snd_pcm_xrun(struct snd_pcm_substream *substream)
snd_power_lock(card);
if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
- result = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile);
+ result = snd_power_wait(card, SNDRV_CTL_POWER_D0);
if (result < 0)
goto _unlock;
}
@@ -1313,13 +1313,13 @@ static struct action_ops snd_pcm_action_prepare = {
*
* Prepare the PCM substream to be triggerable.
*/
-int snd_pcm_prepare(struct snd_pcm_substream *substream)
+static int snd_pcm_prepare(struct snd_pcm_substream *substream)
{
int res;
struct snd_card *card = substream->pcm->card;
snd_power_lock(card);
- if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile)) >= 0)
+ if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0)) >= 0)
res = snd_pcm_action_nonatomic(&snd_pcm_action_prepare, substream, 0);
snd_power_unlock(card);
return res;
@@ -1410,7 +1410,7 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream)
snd_power_lock(card);
if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
- result = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile);
+ result = snd_power_wait(card, SNDRV_CTL_POWER_D0);
if (result < 0) {
snd_power_unlock(card);
return result;
@@ -1533,7 +1533,7 @@ static int snd_pcm_drop(struct snd_pcm_substream *substream)
snd_power_lock(card);
if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
- result = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile);
+ result = snd_power_wait(card, SNDRV_CTL_POWER_D0);
if (result < 0)
goto _unlock;
}
@@ -1995,28 +1995,63 @@ static void snd_pcm_remove_file(struct snd_pcm_str *str,
}
}
-static int snd_pcm_release_file(struct snd_pcm_file * pcm_file)
+static void pcm_release_private(struct snd_pcm_substream *substream)
{
- struct snd_pcm_substream *substream;
- struct snd_pcm_runtime *runtime;
- struct snd_pcm_str * str;
+ struct snd_pcm_file *pcm_file = substream->file;
- snd_assert(pcm_file != NULL, return -ENXIO);
- substream = pcm_file->substream;
- snd_assert(substream != NULL, return -ENXIO);
- runtime = substream->runtime;
- str = substream->pstr;
snd_pcm_unlink(substream);
- if (substream->ffile != NULL) {
+ snd_pcm_remove_file(substream->pstr, pcm_file);
+ kfree(pcm_file);
+}
+
+void snd_pcm_release_substream(struct snd_pcm_substream *substream)
+{
+ snd_pcm_drop(substream);
+ if (substream->pcm_release)
+ substream->pcm_release(substream);
+ if (substream->hw_opened) {
if (substream->ops->hw_free != NULL)
substream->ops->hw_free(substream);
substream->ops->close(substream);
- substream->ffile = NULL;
+ substream->hw_opened = 0;
}
- snd_pcm_remove_file(str, pcm_file);
- snd_pcm_release_substream(substream);
- kfree(pcm_file);
+ snd_pcm_detach_substream(substream);
+}
+
+int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
+ struct file *file,
+ struct snd_pcm_substream **rsubstream)
+{
+ struct snd_pcm_substream *substream;
+ int err;
+
+ err = snd_pcm_attach_substream(pcm, stream, file, &substream);
+ if (err < 0)
+ return err;
+ substream->no_mmap_ctrl = 0;
+ err = snd_pcm_hw_constraints_init(substream);
+ if (err < 0) {
+ snd_printd("snd_pcm_hw_constraints_init failed\n");
+ goto error;
+ }
+
+ if ((err = substream->ops->open(substream)) < 0)
+ goto error;
+
+ substream->hw_opened = 1;
+
+ err = snd_pcm_hw_constraints_complete(substream);
+ if (err < 0) {
+ snd_printd("snd_pcm_hw_constraints_complete failed\n");
+ goto error;
+ }
+
+ *rsubstream = substream;
return 0;
+
+ error:
+ snd_pcm_release_substream(substream);
+ return err;
}
static int snd_pcm_open_file(struct file *file,
@@ -2024,52 +2059,29 @@ static int snd_pcm_open_file(struct file *file,
int stream,
struct snd_pcm_file **rpcm_file)
{
- int err = 0;
struct snd_pcm_file *pcm_file;
struct snd_pcm_substream *substream;
struct snd_pcm_str *str;
+ int err;
snd_assert(rpcm_file != NULL, return -EINVAL);
*rpcm_file = NULL;
+ err = snd_pcm_open_substream(pcm, stream, file, &substream);
+ if (err < 0)
+ return err;
+
pcm_file = kzalloc(sizeof(*pcm_file), GFP_KERNEL);
if (pcm_file == NULL) {
+ snd_pcm_release_substream(substream);
return -ENOMEM;
}
-
- if ((err = snd_pcm_open_substream(pcm, stream, &substream)) < 0) {
- kfree(pcm_file);
- return err;
- }
-
str = substream->pstr;
substream->file = pcm_file;
- substream->no_mmap_ctrl = 0;
-
+ substream->pcm_release = pcm_release_private;
pcm_file->substream = substream;
-
snd_pcm_add_file(str, pcm_file);
- err = snd_pcm_hw_constraints_init(substream);
- if (err < 0) {
- snd_printd("snd_pcm_hw_constraints_init failed\n");
- snd_pcm_release_file(pcm_file);
- return err;
- }
-
- if ((err = substream->ops->open(substream)) < 0) {
- snd_pcm_release_file(pcm_file);
- return err;
- }
- substream->ffile = file;
-
- err = snd_pcm_hw_constraints_complete(substream);
- if (err < 0) {
- snd_printd("snd_pcm_hw_constraints_complete failed\n");
- snd_pcm_release_file(pcm_file);
- return err;
- }
-
file->private_data = pcm_file;
*rpcm_file = pcm_file;
return 0;
@@ -2158,10 +2170,9 @@ static int snd_pcm_release(struct inode *inode, struct file *file)
snd_assert(substream != NULL, return -ENXIO);
snd_assert(!atomic_read(&substream->runtime->mmap_count), );
pcm = substream->pcm;
- snd_pcm_drop(substream);
fasync_helper(-1, file, 0, &substream->runtime->fasync);
mutex_lock(&pcm->open_mutex);
- snd_pcm_release_file(pcm_file);
+ snd_pcm_release_substream(substream);
mutex_unlock(&pcm->open_mutex);
wake_up(&pcm->open_wait);
module_put(pcm->card->module);
@@ -2480,11 +2491,6 @@ static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream,
return 0;
}
-static int snd_pcm_playback_ioctl1(struct snd_pcm_substream *substream,
- unsigned int cmd, void __user *arg);
-static int snd_pcm_capture_ioctl1(struct snd_pcm_substream *substream,
- unsigned int cmd, void __user *arg);
-
static int snd_pcm_common_ioctl1(struct snd_pcm_substream *substream,
unsigned int cmd, void __user *arg)
{
@@ -2736,41 +2742,28 @@ static long snd_pcm_capture_ioctl(struct file *file, unsigned int cmd,
return snd_pcm_capture_ioctl1(pcm_file->substream, cmd, (void __user *)arg);
}
-int snd_pcm_kernel_playback_ioctl(struct snd_pcm_substream *substream,
- unsigned int cmd, void *arg)
-{
- mm_segment_t fs;
- int result;
-
- fs = snd_enter_user();
- result = snd_pcm_playback_ioctl1(substream, cmd, (void __user *)arg);
- snd_leave_user(fs);
- return result;
-}
-
-int snd_pcm_kernel_capture_ioctl(struct snd_pcm_substream *substream,
- unsigned int cmd, void *arg)
+int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream,
+ unsigned int cmd, void *arg)
{
mm_segment_t fs;
int result;
fs = snd_enter_user();
- result = snd_pcm_capture_ioctl1(substream, cmd, (void __user *)arg);
- snd_leave_user(fs);
- return result;
-}
-
-int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream,
- unsigned int cmd, void *arg)
-{
switch (substream->stream) {
case SNDRV_PCM_STREAM_PLAYBACK:
- return snd_pcm_kernel_playback_ioctl(substream, cmd, arg);
+ result = snd_pcm_playback_ioctl1(substream,
+ cmd, (void __user *)arg);
+ break;
case SNDRV_PCM_STREAM_CAPTURE:
- return snd_pcm_kernel_capture_ioctl(substream, cmd, arg);
+ result = snd_pcm_capture_ioctl1(substream,
+ cmd, (void __user *)arg);
+ break;
default:
- return -EINVAL;
+ result = -EINVAL;
+ break;
}
+ snd_leave_user(fs);
+ return result;
}
static ssize_t snd_pcm_read(struct file *file, char __user *buf, size_t count,
diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig
index ff8fef93278..557c4de2296 100644
--- a/sound/isa/Kconfig
+++ b/sound/isa/Kconfig
@@ -11,6 +11,15 @@ config SND_CS4231_LIB
tristate
select SND_PCM
+config SND_ADLIB
+ tristate "AdLib FM card"
+ select SND_OPL3_LIB
+ help
+ Say Y here to include support for AdLib FM cards.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-adlib.
+
config SND_AD1816A
tristate "Analog Devices SoundPort AD1816A"
depends on SND && PNP && ISA
@@ -292,6 +301,20 @@ config SND_OPTI93X
To compile this driver as a module, choose M here: the module
will be called snd-opti93x.
+config SND_MIRO
+ tristate "Miro miroSOUND PCM1pro/PCM12/PCM20radio driver"
+ depends on SND
+ select SND_OPL4_LIB
+ select SND_CS4231_LIB
+ select SND_MPU401_UART
+ select SND_PCM
+ help
+ Say 'Y' or 'M' to include support for Miro miroSOUND PCM1 pro,
+ miroSOUND PCM12 and miroSOUND PCM20 Radio soundcards.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-miro.
+
config SND_SB8
tristate "Sound Blaster 1.0/2.0/Pro (8-bit)"
depends on SND
diff --git a/sound/isa/Makefile b/sound/isa/Makefile
index 05724eb7bfe..bb317ccc170 100644
--- a/sound/isa/Makefile
+++ b/sound/isa/Makefile
@@ -3,6 +3,7 @@
# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
#
+snd-adlib-objs := adlib.o
snd-als100-objs := als100.o
snd-azt2320-objs := azt2320.o
snd-cmi8330-objs := cmi8330.o
@@ -13,6 +14,7 @@ snd-sgalaxy-objs := sgalaxy.o
snd-sscape-objs := sscape.o
# Toplevel Module Dependency
+obj-$(CONFIG_SND_ADLIB) += snd-adlib.o
obj-$(CONFIG_SND_ALS100) += snd-als100.o
obj-$(CONFIG_SND_AZT2320) += snd-azt2320.o
obj-$(CONFIG_SND_CMI8330) += snd-cmi8330.o
diff --git a/sound/isa/adlib.c b/sound/isa/adlib.c
new file mode 100644
index 00000000000..a253a14e6a4
--- /dev/null
+++ b/sound/isa/adlib.c
@@ -0,0 +1,161 @@
+/*
+ * AdLib FM card driver.
+ */
+
+#include <sound/driver.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/opl3.h>
+
+#define CRD_NAME "AdLib FM"
+#define DRV_NAME "snd_adlib"
+
+MODULE_DESCRIPTION(CRD_NAME);
+MODULE_AUTHOR("Rene Herman");
+MODULE_LICENSE("GPL");
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;
+static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for " CRD_NAME " soundcard.");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for " CRD_NAME " soundcard.");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable " CRD_NAME " soundcard.");
+module_param_array(port, long, NULL, 0444);
+MODULE_PARM_DESC(port, "Port # for " CRD_NAME " driver.");
+
+static struct platform_device *devices[SNDRV_CARDS];
+
+static void snd_adlib_free(struct snd_card *card)
+{
+ release_and_free_resource(card->private_data);
+}
+
+static int __devinit snd_adlib_probe(struct platform_device *device)
+{
+ struct snd_card *card;
+ struct snd_opl3 *opl3;
+
+ int error;
+ int i = device->id;
+
+ if (port[i] == SNDRV_AUTO_PORT) {
+ snd_printk(KERN_ERR DRV_NAME ": please specify port\n");
+ error = -EINVAL;
+ goto out0;
+ }
+
+ card = snd_card_new(index[i], id[i], THIS_MODULE, 0);
+ if (!card) {
+ snd_printk(KERN_ERR DRV_NAME ": could not create card\n");
+ error = -EINVAL;
+ goto out0;
+ }
+
+ card->private_data = request_region(port[i], 4, CRD_NAME);
+ if (!card->private_data) {
+ snd_printk(KERN_ERR DRV_NAME ": could not grab ports\n");
+ error = -EBUSY;
+ goto out1;
+ }
+ card->private_free = snd_adlib_free;
+
+ error = snd_opl3_create(card, port[i], port[i] + 2, OPL3_HW_AUTO, 1, &opl3);
+ if (error < 0) {
+ snd_printk(KERN_ERR DRV_NAME ": could not create OPL\n");
+ goto out1;
+ }
+
+ error = snd_opl3_hwdep_new(opl3, 0, 0, NULL);
+ if (error < 0) {
+ snd_printk(KERN_ERR DRV_NAME ": could not create FM\n");
+ goto out1;
+ }
+
+ strcpy(card->driver, DRV_NAME);
+ strcpy(card->shortname, CRD_NAME);
+ sprintf(card->longname, CRD_NAME " at %#lx", port[i]);
+
+ snd_card_set_dev(card, &device->dev);
+
+ error = snd_card_register(card);
+ if (error < 0) {
+ snd_printk(KERN_ERR DRV_NAME ": could not register card\n");
+ goto out1;
+ }
+
+ platform_set_drvdata(device, card);
+ return 0;
+
+out1: snd_card_free(card);
+ out0: error = -EINVAL; /* FIXME: should be the original error code */
+ return error;
+}
+
+static int __devexit snd_adlib_remove(struct platform_device *device)
+{
+ snd_card_free(platform_get_drvdata(device));
+ platform_set_drvdata(device, NULL);
+ return 0;
+}
+
+static struct platform_driver snd_adlib_driver = {
+ .probe = snd_adlib_probe,
+ .remove = __devexit_p(snd_adlib_remove),
+
+ .driver = {
+ .name = DRV_NAME
+ }
+};
+
+static int __init alsa_card_adlib_init(void)
+{
+ int i, cards;
+
+ if (platform_driver_register(&snd_adlib_driver) < 0) {
+ snd_printk(KERN_ERR DRV_NAME ": could not register driver\n");
+ return -ENODEV;
+ }
+
+ for (cards = 0, i = 0; i < SNDRV_CARDS; i++) {
+ struct platform_device *device;
+
+ if (!enable[i])
+ continue;
+
+ device = platform_device_register_simple(DRV_NAME, i, NULL, 0);
+ if (IS_ERR(device))
+ continue;
+
+ devices[i] = device;
+ cards++;
+ }
+
+ if (!cards) {
+#ifdef MODULE
+ printk(KERN_ERR CRD_NAME " soundcard not found or device busy\n");
+#endif
+ platform_driver_unregister(&snd_adlib_driver);
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static void __exit alsa_card_adlib_exit(void)
+{
+ int i;
+
+ for (i = 0; i < SNDRV_CARDS; i++)
+ platform_device_unregister(devices[i]);
+ platform_driver_unregister(&snd_adlib_driver);
+}
+
+module_init(alsa_card_adlib_init);
+module_exit(alsa_card_adlib_exit);
diff --git a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c
index fa63048a8b9..bc0f5ebf5d3 100644
--- a/sound/isa/cmi8330.c
+++ b/sound/isa/cmi8330.c
@@ -693,9 +693,9 @@ static int __init alsa_card_cmi8330_init(void)
if ((err = platform_driver_register(&snd_cmi8330_driver)) < 0)
return err;
- for (i = 0; i < SNDRV_CARDS && enable[i]; i++) {
+ for (i = 0; i < SNDRV_CARDS; i++) {
struct platform_device *device;
- if (is_isapnp_selected(i))
+ if (! enable[i] || is_isapnp_selected(i))
continue;
device = platform_device_register_simple(CMI8330_DRIVER,
i, NULL, 0);
diff --git a/sound/isa/opti9xx/Makefile b/sound/isa/opti9xx/Makefile
index 28c64070cd5..0e41bfd5a40 100644
--- a/sound/isa/opti9xx/Makefile
+++ b/sound/isa/opti9xx/Makefile
@@ -6,8 +6,10 @@
snd-opti92x-ad1848-objs := opti92x-ad1848.o
snd-opti92x-cs4231-objs := opti92x-cs4231.o
snd-opti93x-objs := opti93x.o
+snd-miro-objs := miro.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_OPTI92X_AD1848) += snd-opti92x-ad1848.o
obj-$(CONFIG_SND_OPTI92X_CS4231) += snd-opti92x-cs4231.o
obj-$(CONFIG_SND_OPTI93X) += snd-opti93x.o
+obj-$(CONFIG_SND_MIRO) += snd-miro.o
diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c
new file mode 100644
index 00000000000..09384d03dc3
--- /dev/null
+++ b/sound/isa/opti9xx/miro.c
@@ -0,0 +1,1455 @@
+/*
+ * ALSA soundcard driver for Miro miroSOUND PCM1 pro
+ * miroSOUND PCM12
+ * miroSOUND PCM20 Radio
+ *
+ * Copyright (C) 2004-2005 Martin Langer <martin-langer@gmx.de>
+ *
+ * Based on OSS ACI and ALSA OPTi9xx drivers
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <sound/driver.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/moduleparam.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <sound/core.h>
+#include <sound/cs4231.h>
+#include <sound/mpu401.h>
+#include <sound/opl4.h>
+#include <sound/control.h>
+#include <sound/info.h>
+#define SNDRV_LEGACY_FIND_FREE_IRQ
+#define SNDRV_LEGACY_FIND_FREE_DMA
+#include <sound/initval.h>
+#include "miro.h"
+
+MODULE_AUTHOR("Martin Langer <martin-langer@gmx.de>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Miro miroSOUND PCM1 pro, PCM12, PCM20 Radio");
+MODULE_SUPPORTED_DEVICE("{{Miro,miroSOUND PCM1 pro}, "
+ "{Miro,miroSOUND PCM12}, "
+ "{Miro,miroSOUND PCM20 Radio}}");
+
+static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */
+static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */
+static long port = SNDRV_DEFAULT_PORT1; /* 0x530,0xe80,0xf40,0x604 */
+static long mpu_port = SNDRV_DEFAULT_PORT1; /* 0x300,0x310,0x320,0x330 */
+static long fm_port = SNDRV_DEFAULT_PORT1; /* 0x388 */
+static int irq = SNDRV_DEFAULT_IRQ1; /* 5,7,9,10,11 */
+static int mpu_irq = SNDRV_DEFAULT_IRQ1; /* 5,7,9,10 */
+static int dma1 = SNDRV_DEFAULT_DMA1; /* 0,1,3 */
+static int dma2 = SNDRV_DEFAULT_DMA1; /* 0,1,3 */
+static int wss;
+static int ide;
+
+module_param(index, int, 0444);
+MODULE_PARM_DESC(index, "Index value for miro soundcard.");
+module_param(id, charp, 0444);
+MODULE_PARM_DESC(id, "ID string for miro soundcard.");
+module_param(port, long, 0444);
+MODULE_PARM_DESC(port, "WSS port # for miro driver.");
+module_param(mpu_port, long, 0444);
+MODULE_PARM_DESC(mpu_port, "MPU-401 port # for miro driver.");
+module_param(fm_port, long, 0444);
+MODULE_PARM_DESC(fm_port, "FM Port # for miro driver.");
+module_param(irq, int, 0444);
+MODULE_PARM_DESC(irq, "WSS irq # for miro driver.");
+module_param(mpu_irq, int, 0444);
+MODULE_PARM_DESC(mpu_irq, "MPU-401 irq # for miro driver.");
+module_param(dma1, int, 0444);
+MODULE_PARM_DESC(dma1, "1st dma # for miro driver.");
+module_param(dma2, int, 0444);
+MODULE_PARM_DESC(dma2, "2nd dma # for miro driver.");
+module_param(wss, int, 0444);
+MODULE_PARM_DESC(wss, "wss mode");
+module_param(ide, int, 0444);
+MODULE_PARM_DESC(ide, "enable ide port");
+
+#define OPTi9XX_HW_DETECT 0
+#define OPTi9XX_HW_82C928 1
+#define OPTi9XX_HW_82C929 2
+#define OPTi9XX_HW_82C924 3
+#define OPTi9XX_HW_82C925 4
+#define OPTi9XX_HW_82C930 5
+#define OPTi9XX_HW_82C931 6
+#define OPTi9XX_HW_82C933 7
+#define OPTi9XX_HW_LAST OPTi9XX_HW_82C933
+
+#define OPTi9XX_MC_REG(n) n
+
+
+struct snd_miro {
+ unsigned short hardware;
+ unsigned char password;
+ char name[7];
+
+ struct resource *res_mc_base;
+ struct resource *res_aci_port;
+
+ unsigned long mc_base;
+ unsigned long mc_base_size;
+ unsigned long pwd_reg;
+
+ spinlock_t lock;
+ struct snd_card *card;
+ struct snd_pcm *pcm;
+
+ long wss_base;
+ int irq;
+ int dma1;
+ int dma2;
+
+ long fm_port;
+
+ long mpu_port;
+ int mpu_irq;
+
+ unsigned long aci_port;
+ int aci_vendor;
+ int aci_product;
+ int aci_version;
+ int aci_amp;
+ int aci_preamp;
+ int aci_solomode;
+
+ struct mutex aci_mutex;
+};
+
+static void snd_miro_proc_init(struct snd_miro * miro);
+
+#define DRIVER_NAME "snd-miro"
+
+static struct platform_device *device;
+
+static char * snd_opti9xx_names[] = {
+ "unkown",
+ "82C928", "82C929",
+ "82C924", "82C925",
+ "82C930", "82C931", "82C933"
+};
+
+/*
+ * ACI control
+ */
+
+static int aci_busy_wait(struct snd_miro * miro)
+{
+ long timeout;
+ unsigned char byte;
+
+ for (timeout = 1; timeout <= ACI_MINTIME+30; timeout++) {
+ if (((byte=inb(miro->aci_port + ACI_REG_BUSY)) & 1) == 0) {
+ if (timeout >= ACI_MINTIME)
+ snd_printd("aci ready in round %ld.\n",
+ timeout-ACI_MINTIME);
+ return byte;
+ }
+ if (timeout >= ACI_MINTIME) {
+ long out=10*HZ;
+ switch (timeout-ACI_MINTIME) {
+ case 0 ... 9:
+ out /= 10;
+ case 10 ... 19:
+ out /= 10;
+ case 20 ... 30:
+ out /= 10;
+ default:
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(out);
+ break;
+ }
+ }
+ }
+ snd_printk(KERN_ERR "aci_busy_wait() time out\n");
+ return -EBUSY;
+}
+
+static inline int aci_write(struct snd_miro * miro, unsigned char byte)
+{
+ if (aci_busy_wait(miro) >= 0) {
+ outb(byte, miro->aci_port + ACI_REG_COMMAND);
+ return 0;
+ } else {
+ snd_printk(KERN_ERR "aci busy, aci_write(0x%x) stopped.\n", byte);
+ return -EBUSY;
+ }
+}
+
+static inline int aci_read(struct snd_miro * miro)
+{
+ unsigned char byte;
+
+ if (aci_busy_wait(miro) >= 0) {
+ byte=inb(miro->aci_port + ACI_REG_STATUS);
+ return byte;
+ } else {
+ snd_printk(KERN_ERR "aci busy, aci_read() stopped.\n");
+ return -EBUSY;
+ }
+}
+
+static int aci_cmd(struct snd_miro * miro, int write1, int write2, int write3)
+{
+ int write[] = {write1, write2, write3};
+ int value, i;
+
+ if (mutex_lock_interruptible(&miro->aci_mutex))
+ return -EINTR;
+
+ for (i=0; i<3; i++) {
+ if (write[i]< 0 || write[i] > 255)
+ break;
+ else {
+ value = aci_write(miro, write[i]);
+ if (value < 0)
+ goto out;
+ }
+ }
+
+ value = aci_read(miro);
+
+out: mutex_unlock(&miro->aci_mutex);
+ return value;
+}
+
+static int aci_getvalue(struct snd_miro * miro, unsigned char index)
+{
+ return aci_cmd(miro, ACI_STATUS, index, -1);
+}
+
+static int aci_setvalue(struct snd_miro * miro, unsigned char index, int value)
+{
+ return aci_cmd(miro, index, value, -1);
+}
+
+/*
+ * MIXER part
+ */
+
+static int snd_miro_info_capture(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+
+ return 0;
+}
+
+static int snd_miro_get_capture(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_miro *miro = snd_kcontrol_chip(kcontrol);
+ int value;
+
+ if ((value = aci_getvalue(miro, ACI_S_GENERAL)) < 0) {
+ snd_printk(KERN_ERR "snd_miro_get_capture() failed: %d\n", value);
+ return value;
+ }
+
+ ucontrol->value.integer.value[0] = value & 0x20;
+
+ return 0;
+}
+
+static int snd_miro_put_capture(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_miro *miro = snd_kcontrol_chip(kcontrol);
+ int change, value, error;
+
+ value = !(ucontrol->value.integer.value[0]);
+
+ if ((error = aci_setvalue(miro, ACI_SET_SOLOMODE, value)) < 0) {
+ snd_printk(KERN_ERR "snd_miro_put_capture() failed: %d\n", error);
+ return error;
+ }
+
+ change = (value != miro->aci_solomode);
+ miro->aci_solomode = value;
+
+ return change;
+}
+
+static int snd_miro_info_preamp(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 3;
+
+ return 0;
+}
+
+static int snd_miro_get_preamp(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_miro *miro = snd_kcontrol_chip(kcontrol);
+ int value;
+
+ if (miro->aci_version <= 176) {
+
+ /*
+ OSS says it's not readable with versions < 176.
+ But it doesn't work on my card,
+ which is a PCM12 with aci_version = 176.
+ */
+
+ ucontrol->value.integer.value[0] = miro->aci_preamp;
+ return 0;
+ }
+
+ if ((value = aci_getvalue(miro, ACI_GET_PREAMP)) < 0) {
+ snd_printk(KERN_ERR "snd_miro_get_preamp() failed: %d\n", value);
+ return value;
+ }
+
+ ucontrol->value.integer.value[0] = value;
+
+ return 0;
+}
+
+static int snd_miro_put_preamp(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_miro *miro = snd_kcontrol_chip(kcontrol);
+ int error, value, change;
+
+ value = ucontrol->value.integer.value[0];
+
+ if ((error = aci_setvalue(miro, ACI_SET_PREAMP, value)) < 0) {
+ snd_printk(KERN_ERR "snd_miro_put_preamp() failed: %d\n", error);
+ return error;
+ }
+
+ change = (value != miro->aci_preamp);
+ miro->aci_preamp = value;
+
+ return change;
+}
+
+static int snd_miro_info_amp(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+
+ return 0;
+}
+
+static int snd_miro_get_amp(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_miro *miro = snd_kcontrol_chip(kcontrol);
+ ucontrol->value.integer.value[0] = miro->aci_amp;
+
+ return 0;
+}
+
+static int snd_miro_put_amp(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_miro *miro = snd_kcontrol_chip(kcontrol);
+ int error, value, change;
+
+ value = ucontrol->value.integer.value[0];
+
+ if ((error = aci_setvalue(miro, ACI_SET_POWERAMP, value)) < 0) {
+ snd_printk(KERN_ERR "snd_miro_put_amp() to %d failed: %d\n", value, error);
+ return error;
+ }
+
+ change = (value != miro->aci_amp);
+ miro->aci_amp = value;
+
+ return change;
+}
+
+#define MIRO_DOUBLE(ctl_name, ctl_index, get_right_reg, set_right_reg) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = ctl_name, \
+ .index = ctl_index, \
+ .info = snd_miro_info_double, \
+ .get = snd_miro_get_double, \
+ .put = snd_miro_put_double, \
+ .private_value = get_right_reg | (set_right_reg << 8) \
+}
+
+static int snd_miro_info_double(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ int reg = kcontrol->private_value & 0xff;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 2;
+
+ if ((reg >= ACI_GET_EQ1) && (reg <= ACI_GET_EQ7)) {
+
+ /* equalizer elements */
+
+ uinfo->value.integer.min = - 0x7f;
+ uinfo->value.integer.max = 0x7f;
+ } else {
+
+ /* non-equalizer elements */
+
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 0x20;
+ }
+
+ return 0;
+}
+
+static int snd_miro_get_double(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo)
+{
+ struct snd_miro *miro = snd_kcontrol_chip(kcontrol);
+ int left_val, right_val;
+
+ int right_reg = kcontrol->private_value & 0xff;
+ int left_reg = right_reg + 1;
+
+ if ((right_val = aci_getvalue(miro, right_reg)) < 0) {
+ snd_printk(KERN_ERR "aci_getvalue(%d) failed: %d\n", right_reg, right_val);
+ return right_val;
+ }
+
+ if ((left_val = aci_getvalue(miro, left_reg)) < 0) {
+ snd_printk(KERN_ERR "aci_getvalue(%d) failed: %d\n", left_reg, left_val);
+ return left_val;
+ }
+
+ if ((right_reg >= ACI_GET_EQ1) && (right_reg <= ACI_GET_EQ7)) {
+
+ /* equalizer elements */
+
+ if (left_val < 0x80) {
+ uinfo->value.integer.value[0] = left_val;
+ } else {
+ uinfo->value.integer.value[0] = 0x80 - left_val;
+ }
+
+ if (right_val < 0x80) {
+ uinfo->value.integer.value[1] = right_val;
+ } else {
+ uinfo->value.integer.value[1] = 0x80 - right_val;
+ }
+
+ } else {
+
+ /* non-equalizer elements */
+
+ uinfo->value.integer.value[0] = 0x20 - left_val;
+ uinfo->value.integer.value[1] = 0x20 - right_val;
+ }
+
+ return 0;
+}
+
+static int snd_miro_put_double(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_miro *miro = snd_kcontrol_chip(kcontrol);
+ int left, right, left_old, right_old;
+ int setreg_left, setreg_right, getreg_left, getreg_right;
+ int change, error;
+
+ left = ucontrol->value.integer.value[0];
+ right = ucontrol->value.integer.value[1];
+
+ setreg_right = (kcontrol->private_value >> 8) & 0xff;
+ if (setreg_right == ACI_SET_MASTER) {
+ setreg_left = setreg_right + 1;
+ } else {
+ setreg_left = setreg_right + 8;
+ }
+
+ getreg_right = kcontrol->private_value & 0xff;
+ getreg_left = getreg_right + 1;
+
+ if ((left_old = aci_getvalue(miro, getreg_left)) < 0) {
+ snd_printk(KERN_ERR "aci_getvalue(%d) failed: %d\n", getreg_left, left_old);
+ return left_old;
+ }
+
+ if ((right_old = aci_getvalue(miro, getreg_right)) < 0) {
+ snd_printk(KERN_ERR "aci_getvalue(%d) failed: %d\n", getreg_right, right_old);
+ return right_old;
+ }
+
+ if ((getreg_right >= ACI_GET_EQ1) && (getreg_right <= ACI_GET_EQ7)) {
+
+ /* equalizer elements */
+
+ if (left_old > 0x80)
+ left_old = 0x80 - left_old;
+ if (right_old > 0x80)
+ right_old = 0x80 - right_old;
+
+ if (left >= 0) {
+ if ((error = aci_setvalue(miro, setreg_left, left)) < 0) {
+ snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n",
+ left, error);
+ return error;
+ }
+ } else {
+ if ((error = aci_setvalue(miro, setreg_left, 0x80 - left)) < 0) {
+ snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n",
+ 0x80 - left, error);
+ return error;
+ }
+ }
+
+ if (right >= 0) {
+ if ((error = aci_setvalue(miro, setreg_right, right)) < 0) {
+ snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n",
+ right, error);
+ return error;
+ }
+ } else {
+ if ((error = aci_setvalue(miro, setreg_right, 0x80 - right)) < 0) {
+ snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n",
+ 0x80 - right, error);
+ return error;
+ }
+ }
+
+ } else {
+
+ /* non-equalizer elements */
+
+ left_old = 0x20 - left_old;
+ right_old = 0x20 - right_old;
+
+ if ((error = aci_setvalue(miro, setreg_left, 0x20 - left)) < 0) {
+ snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n",
+ 0x20 - left, error);
+ return error;
+ }
+ if ((error = aci_setvalue(miro, setreg_right, 0x20 - right)) < 0) {
+ snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n",
+ 0x20 - right, error);
+ return error;
+ }
+ }
+
+ change = (left != left_old) || (right != right_old);
+
+ return change;
+}
+
+static struct snd_kcontrol_new snd_miro_controls[] = {
+MIRO_DOUBLE("Master Playback Volume", 0, ACI_GET_MASTER, ACI_SET_MASTER),
+MIRO_DOUBLE("Mic Playback Volume", 1, ACI_GET_MIC, ACI_SET_MIC),
+MIRO_DOUBLE("Line Playback Volume", 1, ACI_GET_LINE, ACI_SET_LINE),
+MIRO_DOUBLE("CD Playback Volume", 0, ACI_GET_CD, ACI_SET_CD),
+MIRO_DOUBLE("Synth Playback Volume", 0, ACI_GET_SYNTH, ACI_SET_SYNTH),
+MIRO_DOUBLE("PCM Playback Volume", 1, ACI_GET_PCM, ACI_SET_PCM),
+MIRO_DOUBLE("Aux Playback Volume", 2, ACI_GET_LINE2, ACI_SET_LINE2),
+};
+
+/* Equalizer with seven bands (only PCM20)
+ from -12dB up to +12dB on each band */
+static struct snd_kcontrol_new snd_miro_eq_controls[] = {
+MIRO_DOUBLE("Tone Control - 28 Hz", 0, ACI_GET_EQ1, ACI_SET_EQ1),
+MIRO_DOUBLE("Tone Control - 160 Hz", 0, ACI_GET_EQ2, ACI_SET_EQ2),
+MIRO_DOUBLE("Tone Control - 400 Hz", 0, ACI_GET_EQ3, ACI_SET_EQ3),
+MIRO_DOUBLE("Tone Control - 1 kHz", 0, ACI_GET_EQ4, ACI_SET_EQ4),
+MIRO_DOUBLE("Tone Control - 2.5 kHz", 0, ACI_GET_EQ5, ACI_SET_EQ5),
+MIRO_DOUBLE("Tone Control - 6.3 kHz", 0, ACI_GET_EQ6, ACI_SET_EQ6),
+MIRO_DOUBLE("Tone Control - 16 kHz", 0, ACI_GET_EQ7, ACI_SET_EQ7),
+};
+
+static struct snd_kcontrol_new snd_miro_radio_control[] = {
+MIRO_DOUBLE("Radio Playback Volume", 0, ACI_GET_LINE1, ACI_SET_LINE1),
+};
+
+static struct snd_kcontrol_new snd_miro_line_control[] = {
+MIRO_DOUBLE("Line Playback Volume", 2, ACI_GET_LINE1, ACI_SET_LINE1),
+};
+
+static struct snd_kcontrol_new snd_miro_preamp_control[] = {
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Mic Boost",
+ .index = 1,
+ .info = snd_miro_info_preamp,
+ .get = snd_miro_get_preamp,
+ .put = snd_miro_put_preamp,
+}};
+
+static struct snd_kcontrol_new snd_miro_amp_control[] = {
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Line Boost",
+ .index = 0,
+ .info = snd_miro_info_amp,
+ .get = snd_miro_get_amp,
+ .put = snd_miro_put_amp,
+}};
+
+static struct snd_kcontrol_new snd_miro_capture_control[] = {
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "PCM Capture Switch",
+ .index = 0,
+ .info = snd_miro_info_capture,
+ .get = snd_miro_get_capture,
+ .put = snd_miro_put_capture,
+}};
+
+static unsigned char aci_init_values[][2] __initdata = {
+ { ACI_SET_MUTE, 0x00 },
+ { ACI_SET_POWERAMP, 0x00 },
+ { ACI_SET_PREAMP, 0x00 },
+ { ACI_SET_SOLOMODE, 0x00 },
+ { ACI_SET_MIC + 0, 0x20 },
+ { ACI_SET_MIC + 8, 0x20 },
+ { ACI_SET_LINE + 0, 0x20 },
+ { ACI_SET_LINE + 8, 0x20 },
+ { ACI_SET_CD + 0, 0x20 },
+ { ACI_SET_CD + 8, 0x20 },
+ { ACI_SET_PCM + 0, 0x20 },
+ { ACI_SET_PCM + 8, 0x20 },
+ { ACI_SET_LINE1 + 0, 0x20 },
+ { ACI_SET_LINE1 + 8, 0x20 },
+ { ACI_SET_LINE2 + 0, 0x20 },
+ { ACI_SET_LINE2 + 8, 0x20 },
+ { ACI_SET_SYNTH + 0, 0x20 },
+ { ACI_SET_SYNTH + 8, 0x20 },
+ { ACI_SET_MASTER + 0, 0x20 },
+ { ACI_SET_MASTER + 1, 0x20 },
+};
+
+static int __init snd_set_aci_init_values(struct snd_miro *miro)
+{
+ int idx, error;
+
+ /* enable WSS on PCM1 */
+
+ if ((miro->aci_product == 'A') && wss) {
+ if ((error = aci_setvalue(miro, ACI_SET_WSS, wss)) < 0) {
+ snd_printk(KERN_ERR "enabling WSS mode failed\n");
+ return error;
+ }
+ }
+
+ /* enable IDE port */
+
+ if (ide) {
+ if ((error = aci_setvalue(miro, ACI_SET_IDE, ide)) < 0) {
+ snd_printk(KERN_ERR "enabling IDE port failed\n");
+ return error;
+ }
+ }
+
+ /* set common aci values */
+
+ for (idx = 0; idx < ARRAY_SIZE(aci_init_values); idx++)
+ if ((error = aci_setvalue(miro, aci_init_values[idx][0],
+ aci_init_values[idx][1])) < 0) {
+ snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n",
+ aci_init_values[idx][0], error);
+ return error;
+ }
+
+ miro->aci_amp = 0;
+ miro->aci_preamp = 0;
+ miro->aci_solomode = 1;
+
+ return 0;
+}
+
+static int snd_miro_mixer(struct snd_miro *miro)
+{
+ struct snd_card *card;
+ unsigned int idx;
+ int err;
+
+ snd_assert(miro != NULL && miro->card != NULL, return -EINVAL);
+
+ card = miro->card;
+
+ switch (miro->hardware) {
+ case OPTi9XX_HW_82C924:
+ strcpy(card->mixername, "ACI & OPTi924");
+ break;
+ case OPTi9XX_HW_82C929:
+ strcpy(card->mixername, "ACI & OPTi929");
+ break;
+ default:
+ snd_BUG();
+ break;
+ }
+
+ for (idx = 0; idx < ARRAY_SIZE(snd_miro_controls); idx++) {
+ if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_controls[idx], miro))) < 0)
+ return err;
+ }
+
+ if ((miro->aci_product == 'A') || (miro->aci_product == 'B')) {
+ /* PCM1/PCM12 with power-amp and Line 2 */
+ if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_line_control[0], miro))) < 0)
+ return err;
+ if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_amp_control[0], miro))) < 0)
+ return err;
+ }
+
+ if ((miro->aci_product == 'B') || (miro->aci_product == 'C')) {
+ /* PCM12/PCM20 with mic-preamp */
+ if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_preamp_control[0], miro))) < 0)
+ return err;
+ if (miro->aci_version >= 176)
+ if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_capture_control[0], miro))) < 0)
+ return err;
+ }
+
+ if (miro->aci_product == 'C') {
+ /* PCM20 with radio and 7 band equalizer */
+ if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_radio_control[0], miro))) < 0)
+ return err;
+ for (idx = 0; idx < ARRAY_SIZE(snd_miro_eq_controls); idx++) {
+ if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_eq_controls[idx], miro))) < 0)
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+static long snd_legacy_find_free_ioport(long *port_table, long size)
+{
+ while (*port_table != -1) {
+ struct resource *res;
+ if ((res = request_region(*port_table, size,
+ "ALSA test")) != NULL) {
+ release_and_free_resource(res);
+ return *port_table;
+ }
+ port_table++;
+ }
+ return -1;
+}
+
+static int __init snd_miro_init(struct snd_miro *chip, unsigned short hardware)
+{
+ static int opti9xx_mc_size[] = {7, 7, 10, 10, 2, 2, 2};
+
+ chip->hardware = hardware;
+ strcpy(chip->name, snd_opti9xx_names[hardware]);
+
+ chip->mc_base_size = opti9xx_mc_size[hardware];
+
+ spin_lock_init(&chip->lock);
+
+ chip->wss_base = -1;
+ chip->irq = -1;
+ chip->dma1 = -1;
+ chip->dma2 = -1;
+ chip->fm_port = -1;
+ chip->mpu_port = -1;
+ chip->mpu_irq = -1;
+
+ switch (hardware) {
+ case OPTi9XX_HW_82C929:
+ chip->mc_base = 0xf8c;
+ chip->password = 0xe3;
+ chip->pwd_reg = 3;
+ break;
+
+ case OPTi9XX_HW_82C924:
+ chip->mc_base = 0xf8c;
+ chip->password = 0xe5;
+ chip->pwd_reg = 3;
+ break;
+
+ default:
+ snd_printk(KERN_ERR "sorry, no support for %d\n", hardware);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static unsigned char snd_miro_read(struct snd_miro *chip,
+ unsigned char reg)
+{
+ unsigned long flags;
+ unsigned char retval = 0xff;
+
+ spin_lock_irqsave(&chip->lock, flags);
+ outb(chip->password, chip->mc_base + chip->pwd_reg);
+
+ switch (chip->hardware) {
+ case OPTi9XX_HW_82C924:
+ if (reg > 7) {
+ outb(reg, chip->mc_base + 8);
+ outb(chip->password, chip->mc_base + chip->pwd_reg);
+ retval = inb(chip->mc_base + 9);
+ break;
+ }
+
+ case OPTi9XX_HW_82C929:
+ retval = inb(chip->mc_base + reg);
+ break;
+
+ default:
+ snd_printk(KERN_ERR "sorry, no support for %d\n", chip->hardware);
+ }
+
+ spin_unlock_irqrestore(&chip->lock, flags);
+ return retval;
+}
+
+static void snd_miro_write(struct snd_miro *chip, unsigned char reg,
+ unsigned char value)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&chip->lock, flags);
+ outb(chip->password, chip->mc_base + chip->pwd_reg);
+
+ switch (chip->hardware) {
+ case OPTi9XX_HW_82C924:
+ if (reg > 7) {
+ outb(reg, chip->mc_base + 8);
+ outb(chip->password, chip->mc_base + chip->pwd_reg);
+ outb(value, chip->mc_base + 9);
+ break;
+ }
+
+ case OPTi9XX_HW_82C929:
+ outb(value, chip->mc_base + reg);
+ break;
+
+ default:
+ snd_printk(KERN_ERR "sorry, no support for %d\n", chip->hardware);
+ }
+
+ spin_unlock_irqrestore(&chip->lock, flags);
+}
+
+
+#define snd_miro_write_mask(chip, reg, value, mask) \
+ snd_miro_write(chip, reg, \
+ (snd_miro_read(chip, reg) & ~(mask)) | ((value) & (mask)))
+
+/*
+ * Proc Interface
+ */
+
+static void snd_miro_proc_read(struct snd_info_entry * entry,
+ struct snd_info_buffer *buffer)
+{
+ struct snd_miro *miro = (struct snd_miro *) entry->private_data;
+ char* model = "unknown";
+
+ /* miroSOUND PCM1 pro, early PCM12 */
+
+ if ((miro->hardware == OPTi9XX_HW_82C929) &&
+ (miro->aci_vendor == 'm') &&
+ (miro->aci_product == 'A')) {
+ switch(miro->aci_version) {
+ case 3:
+ model = "miroSOUND PCM1 pro";
+ break;
+ default:
+ model = "miroSOUND PCM1 pro / (early) PCM12";
+ break;
+ }
+ }
+
+ /* miroSOUND PCM12, PCM12 (Rev. E), PCM12 pnp */
+
+ if ((miro->hardware == OPTi9XX_HW_82C924) &&
+ (miro->aci_vendor == 'm') &&
+ (miro->aci_product == 'B')) {
+ switch(miro->aci_version) {
+ case 4:
+ model = "miroSOUND PCM12";
+ break;
+ case 176:
+ model = "miroSOUND PCM12 (Rev. E)";
+ break;
+ default:
+ model = "miroSOUND PCM12 / PCM12 pnp";
+ break;
+ }
+ }
+
+ /* miroSOUND PCM20 radio */
+
+ if ((miro->hardware == OPTi9XX_HW_82C924) &&
+ (miro->aci_vendor == 'm') &&
+ (miro->aci_product == 'C')) {
+ switch(miro->aci_version) {
+ case 7:
+ model = "miroSOUND PCM20 radio (Rev. E)";
+ break;
+ default:
+ model = "miroSOUND PCM20 radio";
+ break;
+ }
+ }
+
+ snd_iprintf(buffer, "\nGeneral information:\n");
+ snd_iprintf(buffer, " model : %s\n", model);
+ snd_iprintf(buffer, " opti : %s\n", miro->name);
+ snd_iprintf(buffer, " codec : %s\n", miro->pcm->name);
+ snd_iprintf(buffer, " port : 0x%lx\n", miro->wss_base);
+ snd_iprintf(buffer, " irq : %d\n", miro->irq);
+ snd_iprintf(buffer, " dma : %d,%d\n\n", miro->dma1, miro->dma2);
+
+ snd_iprintf(buffer, "MPU-401:\n");
+ snd_iprintf(buffer, " port : 0x%lx\n", miro->mpu_port);
+ snd_iprintf(buffer, " irq : %d\n\n", miro->mpu_irq);
+
+ snd_iprintf(buffer, "ACI information:\n");
+ snd_iprintf(buffer, " vendor : ");
+ switch(miro->aci_vendor) {
+ case 'm':
+ snd_iprintf(buffer, "Miro\n");
+ break;
+ default:
+ snd_iprintf(buffer, "unknown (0x%x)\n", miro->aci_vendor);
+ break;
+ }
+
+ snd_iprintf(buffer, " product : ");
+ switch(miro->aci_product) {
+ case 'A':
+ snd_iprintf(buffer, "miroSOUND PCM1 pro / (early) PCM12\n");
+ break;
+ case 'B':
+ snd_iprintf(buffer, "miroSOUND PCM12\n");
+ break;
+ case 'C':
+ snd_iprintf(buffer, "miroSOUND PCM20 radio\n");
+ break;
+ default:
+ snd_iprintf(buffer, "unknown (0x%x)\n", miro->aci_product);
+ break;
+ }
+
+ snd_iprintf(buffer, " firmware: %d (0x%x)\n",
+ miro->aci_version, miro->aci_version);
+ snd_iprintf(buffer, " port : 0x%lx-0x%lx\n",
+ miro->aci_port, miro->aci_port+2);
+ snd_iprintf(buffer, " wss : 0x%x\n", wss);
+ snd_iprintf(buffer, " ide : 0x%x\n", ide);
+ snd_iprintf(buffer, " solomode: 0x%x\n", miro->aci_solomode);
+ snd_iprintf(buffer, " amp : 0x%x\n", miro->aci_amp);
+ snd_iprintf(buffer, " preamp : 0x%x\n", miro->aci_preamp);
+}
+
+static void __init snd_miro_proc_init(struct snd_miro * miro)
+{
+ struct snd_info_entry *entry;
+
+ if (! snd_card_proc_new(miro->card, "miro", &entry))
+ snd_info_set_text_ops(entry, miro, 1024, snd_miro_proc_read);
+}
+
+/*
+ * Init
+ */
+
+static int __init snd_miro_configure(struct snd_miro *chip)
+{
+ unsigned char wss_base_bits;
+ unsigned char irq_bits;
+ unsigned char dma_bits;
+ unsigned char mpu_port_bits = 0;
+ unsigned char mpu_irq_bits;
+ unsigned long flags;
+
+ switch (chip->hardware) {
+ case OPTi9XX_HW_82C924:
+ snd_miro_write_mask(chip, OPTi9XX_MC_REG(6), 0x02, 0x02);
+ snd_miro_write_mask(chip, OPTi9XX_MC_REG(1), 0x80, 0x80);
+ snd_miro_write_mask(chip, OPTi9XX_MC_REG(2), 0x20, 0x20); /* OPL4 */
+ snd_miro_write_mask(chip, OPTi9XX_MC_REG(3), 0xf0, 0xff);
+ snd_miro_write_mask(chip, OPTi9XX_MC_REG(5), 0x02, 0x02);
+ break;
+ case OPTi9XX_HW_82C929:
+ /* untested init commands for OPTi929 */
+ snd_miro_write_mask(chip, OPTi9XX_MC_REG(1), 0x80, 0x80);
+ snd_miro_write_mask(chip, OPTi9XX_MC_REG(2), 0x20, 0x20); /* OPL4 */
+ snd_miro_write_mask(chip, OPTi9XX_MC_REG(4), 0x00, 0x0c);
+ snd_miro_write_mask(chip, OPTi9XX_MC_REG(5), 0x02, 0x02);
+ break;
+ default:
+ snd_printk(KERN_ERR "chip %d not supported\n", chip->hardware);
+ return -EINVAL;
+ }
+
+ switch (chip->wss_base) {
+ case 0x530:
+ wss_base_bits = 0x00;
+ break;
+ case 0x604:
+ wss_base_bits = 0x03;
+ break;
+ case 0xe80:
+ wss_base_bits = 0x01;
+ break;
+ case 0xf40:
+ wss_base_bits = 0x02;
+ break;
+ default:
+ snd_printk(KERN_ERR "WSS port 0x%lx not valid\n", chip->wss_base);
+ goto __skip_base;
+ }
+ snd_miro_write_mask(chip, OPTi9XX_MC_REG(1), wss_base_bits << 4, 0x30);
+
+__skip_base:
+ switch (chip->irq) {
+ case 5:
+ irq_bits = 0x05;
+ break;
+ case 7:
+ irq_bits = 0x01;
+ break;
+ case 9:
+ irq_bits = 0x02;
+ break;
+ case 10:
+ irq_bits = 0x03;
+ break;
+ case 11:
+ irq_bits = 0x04;
+ break;
+ default:
+ snd_printk(KERN_ERR "WSS irq # %d not valid\n", chip->irq);
+ goto __skip_resources;
+ }
+
+ switch (chip->dma1) {
+ case 0:
+ dma_bits = 0x01;
+ break;
+ case 1:
+ dma_bits = 0x02;
+ break;
+ case 3:
+ dma_bits = 0x03;
+ break;
+ default:
+ snd_printk(KERN_ERR "WSS dma1 # %d not valid\n", chip->dma1);
+ goto __skip_resources;
+ }
+
+ if (chip->dma1 == chip->dma2) {
+ snd_printk(KERN_ERR "don't want to share dmas\n");
+ return -EBUSY;
+ }
+
+ switch (chip->dma2) {
+ case 0:
+ case 1:
+ break;
+ default:
+ snd_printk(KERN_ERR "WSS dma2 # %d not valid\n", chip->dma2);
+ goto __skip_resources;
+ }
+ dma_bits |= 0x04;
+
+ spin_lock_irqsave(&chip->lock, flags);
+ outb(irq_bits << 3 | dma_bits, chip->wss_base);
+ spin_unlock_irqrestore(&chip->lock, flags);
+
+__skip_resources:
+ if (chip->hardware > OPTi9XX_HW_82C928) {
+ switch (chip->mpu_port) {
+ case 0:
+ case -1:
+ break;
+ case 0x300:
+ mpu_port_bits = 0x03;
+ break;
+ case 0x310:
+ mpu_port_bits = 0x02;
+ break;
+ case 0x320:
+ mpu_port_bits = 0x01;
+ break;
+ case 0x330:
+ mpu_port_bits = 0x00;
+ break;
+ default:
+ snd_printk(KERN_ERR "MPU-401 port 0x%lx not valid\n",
+ chip->mpu_port);
+ goto __skip_mpu;
+ }
+
+ switch (chip->mpu_irq) {
+ case 5:
+ mpu_irq_bits = 0x02;
+ break;
+ case 7:
+ mpu_irq_bits = 0x03;
+ break;
+ case 9:
+ mpu_irq_bits = 0x00;
+ break;
+ case 10:
+ mpu_irq_bits = 0x01;
+ break;
+ default:
+ snd_printk(KERN_ERR "MPU-401 irq # %d not valid\n",
+ chip->mpu_irq);
+ goto __skip_mpu;
+ }
+
+ snd_miro_write_mask(chip, OPTi9XX_MC_REG(6),
+ (chip->mpu_port <= 0) ? 0x00 :
+ 0x80 | mpu_port_bits << 5 | mpu_irq_bits << 3,
+ 0xf8);
+ }
+__skip_mpu:
+
+ return 0;
+}
+
+static int __init snd_card_miro_detect(struct snd_card *card, struct snd_miro *chip)
+{
+ int i, err;
+ unsigned char value;
+
+ for (i = OPTi9XX_HW_82C929; i <= OPTi9XX_HW_82C924; i++) {
+
+ if ((err = snd_miro_init(chip, i)) < 0)
+ return err;
+
+ if ((chip->res_mc_base = request_region(chip->mc_base, chip->mc_base_size, "OPTi9xx MC")) == NULL)
+ continue;
+
+ value = snd_miro_read(chip, OPTi9XX_MC_REG(1));
+ if ((value != 0xff) && (value != inb(chip->mc_base + 1)))
+ if (value == snd_miro_read(chip, OPTi9XX_MC_REG(1)))
+ return 1;
+
+ release_and_free_resource(chip->res_mc_base);
+ chip->res_mc_base = NULL;
+
+ }
+
+ return -ENODEV;
+}
+
+static int __init snd_card_miro_aci_detect(struct snd_card *card, struct snd_miro * miro)
+{
+ unsigned char regval;
+ int i;
+
+ mutex_init(&miro->aci_mutex);
+
+ /* get ACI port from OPTi9xx MC 4 */
+
+ miro->mc_base = 0xf8c;
+ regval=inb(miro->mc_base + 4);
+ miro->aci_port = (regval & 0x10) ? 0x344: 0x354;
+
+ if ((miro->res_aci_port = request_region(miro->aci_port, 3, "miro aci")) == NULL) {
+ snd_printk(KERN_ERR "aci i/o area 0x%lx-0x%lx already used.\n",
+ miro->aci_port, miro->aci_port+2);
+ return -ENOMEM;
+ }
+
+ /* force ACI into a known state */
+ for (i = 0; i < 3; i++)
+ if (aci_cmd(miro, ACI_ERROR_OP, -1, -1) < 0) {
+ snd_card_free(card);
+ snd_printk(KERN_ERR "can't force aci into known state.\n");
+ return -ENXIO;
+ }
+
+ if ((miro->aci_vendor=aci_cmd(miro, ACI_READ_IDCODE, -1, -1)) < 0 ||
+ (miro->aci_product=aci_cmd(miro, ACI_READ_IDCODE, -1, -1)) < 0) {
+ snd_card_free(card);
+ snd_printk(KERN_ERR "can't read aci id on 0x%lx.\n", miro->aci_port);
+ return -ENXIO;
+ }
+
+ if ((miro->aci_version=aci_cmd(miro, ACI_READ_VERSION, -1, -1)) < 0) {
+ snd_card_free(card);
+ snd_printk(KERN_ERR "can't read aci version on 0x%lx.\n",
+ miro->aci_port);
+ return -ENXIO;
+ }
+
+ if (aci_cmd(miro, ACI_INIT, -1, -1) < 0 ||
+ aci_cmd(miro, ACI_ERROR_OP, ACI_ERROR_OP, ACI_ERROR_OP) < 0 ||
+ aci_cmd(miro, ACI_ERROR_OP, ACI_ERROR_OP, ACI_ERROR_OP) < 0) {
+ snd_printk(KERN_ERR "can't initialize aci.\n");
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+static void snd_card_miro_free(struct snd_card *card)
+{
+ struct snd_miro *miro = card->private_data;
+
+ release_and_free_resource(miro->res_aci_port);
+ release_and_free_resource(miro->res_mc_base);
+}
+
+static int __init snd_miro_probe(struct platform_device *devptr)
+{
+ static long possible_ports[] = {0x530, 0xe80, 0xf40, 0x604, -1};
+ static long possible_mpu_ports[] = {0x330, 0x300, 0x310, 0x320, -1};
+ static int possible_irqs[] = {11, 9, 10, 7, -1};
+ static int possible_mpu_irqs[] = {10, 5, 9, 7, -1};
+ static int possible_dma1s[] = {3, 1, 0, -1};
+ static int possible_dma2s[][2] = {{1,-1}, {0,-1}, {-1,-1}, {0,-1}};
+
+ int error;
+ struct snd_miro *miro;
+ struct snd_cs4231 *codec;
+ struct snd_timer *timer;
+ struct snd_card *card;
+ struct snd_pcm *pcm;
+ struct snd_rawmidi *rmidi;
+
+ if (!(card = snd_card_new(index, id, THIS_MODULE,
+ sizeof(struct snd_miro))))
+ return -ENOMEM;
+
+ card->private_free = snd_card_miro_free;
+ miro = card->private_data;
+ miro->card = card;
+
+ if ((error = snd_card_miro_aci_detect(card, miro)) < 0) {
+ snd_card_free(card);
+ snd_printk(KERN_ERR "unable to detect aci chip\n");
+ return -ENODEV;
+ }
+
+ /* init proc interface */
+ snd_miro_proc_init(miro);
+
+ if ((error = snd_card_miro_detect(card, miro)) < 0) {
+ snd_card_free(card);
+ snd_printk(KERN_ERR "unable to detect OPTi9xx chip\n");
+ return -ENODEV;
+ }
+
+ if (! miro->res_mc_base &&
+ (miro->res_mc_base = request_region(miro->mc_base, miro->mc_base_size,
+ "miro (OPTi9xx MC)")) == NULL) {
+ snd_card_free(card);
+ snd_printk(KERN_ERR "request for OPTI9xx MC failed\n");
+ return -ENOMEM;
+ }
+
+ miro->wss_base = port;
+ miro->fm_port = fm_port;
+ miro->mpu_port = mpu_port;
+ miro->irq = irq;
+ miro->mpu_irq = mpu_irq;
+ miro->dma1 = dma1;
+ miro->dma2 = dma2;
+
+ if (miro->wss_base == SNDRV_AUTO_PORT) {
+ if ((miro->wss_base = snd_legacy_find_free_ioport(possible_ports, 4)) < 0) {
+ snd_card_free(card);
+ snd_printk(KERN_ERR "unable to find a free WSS port\n");
+ return -EBUSY;
+ }
+ }
+
+ if (miro->mpu_port == SNDRV_AUTO_PORT) {
+ if ((miro->mpu_port = snd_legacy_find_free_ioport(possible_mpu_ports, 2)) < 0) {
+ snd_card_free(card);
+ snd_printk(KERN_ERR "unable to find a free MPU401 port\n");
+ return -EBUSY;
+ }
+ }
+ if (miro->irq == SNDRV_AUTO_IRQ) {
+ if ((miro->irq = snd_legacy_find_free_irq(possible_irqs)) < 0) {
+ snd_card_free(card);
+ snd_printk(KERN_ERR "unable to find a free IRQ\n");
+ return -EBUSY;
+ }
+ }
+ if (miro->mpu_irq == SNDRV_AUTO_IRQ) {
+ if ((miro->mpu_irq = snd_legacy_find_free_irq(possible_mpu_irqs)) < 0) {
+ snd_card_free(card);
+ snd_printk(KERN_ERR "unable to find a free MPU401 IRQ\n");
+ return -EBUSY;
+ }
+ }
+ if (miro->dma1 == SNDRV_AUTO_DMA) {
+ if ((miro->dma1 = snd_legacy_find_free_dma(possible_dma1s)) < 0) {
+ snd_card_free(card);
+ snd_printk(KERN_ERR "unable to find a free DMA1\n");
+ return -EBUSY;
+ }
+ }
+ if (miro->dma2 == SNDRV_AUTO_DMA) {
+ if ((miro->dma2 = snd_legacy_find_free_dma(possible_dma2s[miro->dma1 % 4])) < 0) {
+ snd_card_free(card);
+ snd_printk(KERN_ERR "unable to find a free DMA2\n");
+ return -EBUSY;
+ }
+ }
+
+ if ((error = snd_miro_configure(miro))) {
+ snd_card_free(card);
+ return error;
+ }
+
+ if ((error = snd_cs4231_create(card, miro->wss_base + 4, -1,
+ miro->irq, miro->dma1, miro->dma2,
+ CS4231_HW_AD1845,
+ 0,
+ &codec)) < 0) {
+ snd_card_free(card);
+ return error;
+ }
+
+ if ((error = snd_cs4231_pcm(codec, 0, &pcm)) < 0) {
+ snd_card_free(card);
+ return error;
+ }
+ if ((error = snd_cs4231_mixer(codec)) < 0) {
+ snd_card_free(card);
+ return error;
+ }
+ if ((error = snd_cs4231_timer(codec, 0, &timer)) < 0) {
+ snd_card_free(card);
+ return error;
+ }
+
+ miro->pcm = pcm;
+
+ if ((error = snd_miro_mixer(miro)) < 0) {
+ snd_card_free(card);
+ return error;
+ }
+
+ if (miro->aci_vendor == 'm') {
+ /* It looks like a miro sound card. */
+ switch (miro->aci_product) {
+ case 'A':
+ sprintf(card->shortname,
+ "miroSOUND PCM1 pro / PCM12");
+ break;
+ case 'B':
+ sprintf(card->shortname,
+ "miroSOUND PCM12");
+ break;
+ case 'C':
+ sprintf(card->shortname,
+ "miroSOUND PCM20 radio");
+ break;
+ default:
+ sprintf(card->shortname,
+ "unknown miro");
+ snd_printk(KERN_INFO "unknown miro aci id\n");
+ break;
+ }
+ } else {
+ snd_printk(KERN_INFO "found unsupported aci card\n");
+ sprintf(card->shortname, "unknown Cardinal Technologies");
+ }
+
+ strcpy(card->driver, "miro");
+ sprintf(card->longname, "%s: OPTi%s, %s at 0x%lx, irq %d, dma %d&%d",
+ card->shortname, miro->name, pcm->name, miro->wss_base + 4,
+ miro->irq, miro->dma1, miro->dma2);
+
+ if (miro->mpu_port <= 0 || miro->mpu_port == SNDRV_AUTO_PORT)
+ rmidi = NULL;
+ else
+ if ((error = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
+ miro->mpu_port, 0, miro->mpu_irq, SA_INTERRUPT,
+ &rmidi)))
+ snd_printk(KERN_WARNING "no MPU-401 device at 0x%lx?\n", miro->mpu_port);
+
+ if (miro->fm_port > 0 && miro->fm_port != SNDRV_AUTO_PORT) {
+ struct snd_opl3 *opl3 = NULL;
+ struct snd_opl4 *opl4;
+ if (snd_opl4_create(card, miro->fm_port, miro->fm_port - 8,
+ 2, &opl3, &opl4) < 0)
+ snd_printk(KERN_WARNING "no OPL4 device at 0x%lx\n", miro->fm_port);
+ }
+
+ if ((error = snd_set_aci_init_values(miro)) < 0) {
+ snd_card_free(card);
+ return error;
+ }
+
+ snd_card_set_dev(card, &devptr->dev);
+
+ if ((error = snd_card_register(card))) {
+ snd_card_free(card);
+ return error;
+ }
+
+ platform_set_drvdata(devptr, card);
+ return 0;
+}
+
+static int __devexit snd_miro_remove(struct platform_device *devptr)
+{
+ snd_card_free(platform_get_drvdata(devptr));
+ platform_set_drvdata(devptr, NULL);
+ return 0;
+}
+
+static struct platform_driver snd_miro_driver = {
+ .probe = snd_miro_probe,
+ .remove = __devexit_p(snd_miro_remove),
+ /* FIXME: suspend/resume */
+ .driver = {
+ .name = DRIVER_NAME
+ },
+};
+
+static int __init alsa_card_miro_init(void)
+{
+ int error;
+
+ if ((error = platform_driver_register(&snd_miro_driver)) < 0)
+ return error;
+ device = platform_device_register_simple(DRIVER_NAME, -1, NULL, 0);
+ if (! IS_ERR(device))
+ return 0;
+#ifdef MODULE
+ printk(KERN_ERR "no miro soundcard found\n");
+#endif
+ platform_driver_unregister(&snd_miro_driver);
+ return PTR_ERR(device);
+}
+
+static void __exit alsa_card_miro_exit(void)
+{
+ platform_device_unregister(device);
+ platform_driver_unregister(&snd_miro_driver);
+}
+
+module_init(alsa_card_miro_init)
+module_exit(alsa_card_miro_exit)
diff --git a/sound/isa/opti9xx/miro.h b/sound/isa/opti9xx/miro.h
new file mode 100644
index 00000000000..6e1385b8e07
--- /dev/null
+++ b/sound/isa/opti9xx/miro.h
@@ -0,0 +1,73 @@
+#ifndef _MIRO_H_
+#define _MIRO_H_
+
+#define ACI_REG_COMMAND 0 /* write register offset */
+#define ACI_REG_STATUS 1 /* read register offset */
+#define ACI_REG_BUSY 2 /* busy register offset */
+#define ACI_REG_RDS 2 /* PCM20: RDS register offset */
+#define ACI_MINTIME 500 /* ACI time out limit */
+
+#define ACI_SET_MUTE 0x0d
+#define ACI_SET_POWERAMP 0x0f
+#define ACI_SET_TUNERMUTE 0xa3
+#define ACI_SET_TUNERMONO 0xa4
+#define ACI_SET_IDE 0xd0
+#define ACI_SET_WSS 0xd1
+#define ACI_SET_SOLOMODE 0xd2
+#define ACI_SET_PREAMP 0x03
+#define ACI_GET_PREAMP 0x21
+#define ACI_WRITE_TUNE 0xa7
+#define ACI_READ_TUNERSTEREO 0xa8
+#define ACI_READ_TUNERSTATION 0xa9
+#define ACI_READ_VERSION 0xf1
+#define ACI_READ_IDCODE 0xf2
+#define ACI_INIT 0xff
+#define ACI_STATUS 0xf0
+#define ACI_S_GENERAL 0x00
+#define ACI_ERROR_OP 0xdf
+
+/* ACI Mixer */
+
+/* These are the values for the right channel GET registers.
+ Add an offset of 0x01 for the left channel register.
+ (left=right+0x01) */
+
+#define ACI_GET_MASTER 0x03
+#define ACI_GET_MIC 0x05
+#define ACI_GET_LINE 0x07
+#define ACI_GET_CD 0x09
+#define ACI_GET_SYNTH 0x0b
+#define ACI_GET_PCM 0x0d
+#define ACI_GET_LINE1 0x10 /* Radio on PCM20 */
+#define ACI_GET_LINE2 0x12
+
+#define ACI_GET_EQ1 0x22 /* from Bass ... */
+#define ACI_GET_EQ2 0x24
+#define ACI_GET_EQ3 0x26
+#define ACI_GET_EQ4 0x28
+#define ACI_GET_EQ5 0x2a
+#define ACI_GET_EQ6 0x2c
+#define ACI_GET_EQ7 0x2e /* ... to Treble */
+
+/* And these are the values for the right channel SET registers.
+ For left channel access you have to add an offset of 0x08.
+ MASTER is an exception, which needs an offset of 0x01 */
+
+#define ACI_SET_MASTER 0x00
+#define ACI_SET_MIC 0x30
+#define ACI_SET_LINE 0x31
+#define ACI_SET_CD 0x34
+#define ACI_SET_SYNTH 0x33
+#define ACI_SET_PCM 0x32
+#define ACI_SET_LINE1 0x35 /* Radio on PCM20 */
+#define ACI_SET_LINE2 0x36
+
+#define ACI_SET_EQ1 0x40 /* from Bass ... */
+#define ACI_SET_EQ2 0x41
+#define ACI_SET_EQ3 0x42
+#define ACI_SET_EQ4 0x43
+#define ACI_SET_EQ5 0x44
+#define ACI_SET_EQ6 0x45
+#define ACI_SET_EQ7 0x46 /* ... to Treble */
+
+#endif /* _MIRO_H_ */
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
index 1e2e19305e3..a2081803a82 100644
--- a/sound/pci/Kconfig
+++ b/sound/pci/Kconfig
@@ -15,6 +15,18 @@ config SND_AD1889
To compile this as a module, choose M here: the module
will be called snd-ad1889.
+config SND_ALS300
+ tristate "Avance Logic ALS300/ALS300+"
+ depends on SND
+ select SND_PCM
+ select SND_AC97_CODEC
+ select SND_OPL3_LIB
+ help
+ Say 'Y' or 'M' to include support for Avance Logic ALS300/ALS300+
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-als300
+
config SND_ALS4000
tristate "Avance Logic ALS4000"
depends on SND && ISA_DMA_API
@@ -195,8 +207,9 @@ config SND_CS46XX
will be called snd-cs46xx.
config SND_CS46XX_NEW_DSP
- bool "Cirrus Logic (Sound Fusion) New DSP support (EXPERIMENTAL)"
- depends on SND_CS46XX && EXPERIMENTAL
+ bool "Cirrus Logic (Sound Fusion) New DSP support"
+ depends on SND_CS46XX
+ default y
help
Say Y here to use a new DSP image for SPDIF and dual codecs.
@@ -466,6 +479,19 @@ config SND_PCXHR
To compile this driver as a module, choose M here: the module
will be called snd-pcxhr.
+config SND_RIPTIDE
+ tristate "Conexant Riptide"
+ depends on SND
+ depends on FW_LOADER
+ select SND_OPL3_LIB
+ select SND_MPU401_UART
+ select SND_AC97_CODEC
+ help
+ Say 'Y' or 'M' to include support for Conexant Riptide chip.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-riptide
+
config SND_RME32
tristate "RME Digi32, 32/8, 32 PRO"
depends on SND
diff --git a/sound/pci/Makefile b/sound/pci/Makefile
index a6c3cd58fe9..cba5105aafe 100644
--- a/sound/pci/Makefile
+++ b/sound/pci/Makefile
@@ -4,6 +4,7 @@
#
snd-ad1889-objs := ad1889.o
+snd-als300-objs := als300.o
snd-als4000-objs := als4000.o
snd-atiixp-objs := atiixp.o
snd-atiixp-modem-objs := atiixp_modem.o
@@ -27,6 +28,7 @@ snd-via82xx-modem-objs := via82xx_modem.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_AD1889) += snd-ad1889.o
+obj-$(CONFIG_SND_ALS300) += snd-als300.o
obj-$(CONFIG_SND_ALS4000) += snd-als4000.o
obj-$(CONFIG_SND_ATIIXP) += snd-atiixp.o
obj-$(CONFIG_SND_ATIIXP_MODEM) += snd-atiixp-modem.o
@@ -62,6 +64,7 @@ obj-$(CONFIG_SND) += \
mixart/ \
nm256/ \
pcxhr/ \
+ riptide/ \
rme9652/ \
trident/ \
ymfpci/ \
diff --git a/sound/pci/als300.c b/sound/pci/als300.c
new file mode 100644
index 00000000000..37b80570a5c
--- /dev/null
+++ b/sound/pci/als300.c
@@ -0,0 +1,866 @@
+/*
+ * als300.c - driver for Avance Logic ALS300/ALS300+ soundcards.
+ * Copyright (C) 2005 by Ash Willis <ashwillis@programmer.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * TODO
+ * 4 channel playback for ALS300+
+ * gameport
+ * mpu401
+ * opl3
+ *
+ * NOTES
+ * The BLOCK_COUNTER registers for the ALS300(+) return a figure related to
+ * the position in the current period, NOT the whole buffer. It is important
+ * to know which period we are in so we can calculate the correct pointer.
+ * This is why we always use 2 periods. We can then use a flip-flop variable
+ * to keep track of what period we are in.
+ */
+
+#include <sound/driver.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+
+#include <asm/io.h>
+
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/ac97_codec.h>
+#include <sound/opl3.h>
+
+/* snd_als300_set_irq_flag */
+#define IRQ_DISABLE 0
+#define IRQ_ENABLE 1
+
+/* I/O port layout */
+#define AC97_ACCESS 0x00
+#define AC97_READ 0x04
+#define AC97_STATUS 0x06
+#define AC97_DATA_AVAIL (1<<6)
+#define AC97_BUSY (1<<7)
+#define ALS300_IRQ_STATUS 0x07 /* ALS300 Only */
+#define IRQ_PLAYBACK (1<<3)
+#define IRQ_CAPTURE (1<<2)
+#define GCR_DATA 0x08
+#define GCR_INDEX 0x0C
+#define ALS300P_DRAM_IRQ_STATUS 0x0D /* ALS300+ Only */
+#define MPU_IRQ_STATUS 0x0E /* ALS300 Rev. E+, ALS300+ */
+#define ALS300P_IRQ_STATUS 0x0F /* ALS300+ Only */
+
+/* General Control Registers */
+#define PLAYBACK_START 0x80
+#define PLAYBACK_END 0x81
+#define PLAYBACK_CONTROL 0x82
+#define TRANSFER_START (1<<16)
+#define FIFO_PAUSE (1<<17)
+#define RECORD_START 0x83
+#define RECORD_END 0x84
+#define RECORD_CONTROL 0x85
+#define DRAM_WRITE_CONTROL 0x8B
+#define WRITE_TRANS_START (1<<16)
+#define DRAM_MODE_2 (1<<17)
+#define MISC_CONTROL 0x8C
+#define IRQ_SET_BIT (1<<15)
+#define VMUTE_NORMAL (1<<20)
+#define MMUTE_NORMAL (1<<21)
+#define MUS_VOC_VOL 0x8E
+#define PLAYBACK_BLOCK_COUNTER 0x9A
+#define RECORD_BLOCK_COUNTER 0x9B
+
+#define DEBUG_CALLS 1
+#define DEBUG_PLAY_REC 1
+
+#if DEBUG_CALLS
+#define snd_als300_dbgcalls(format, args...) printk(format, ##args)
+#define snd_als300_dbgcallenter() printk(KERN_ERR "--> %s\n", __FUNCTION__)
+#define snd_als300_dbgcallleave() printk(KERN_ERR "<-- %s\n", __FUNCTION__)
+#else
+#define snd_als300_dbgcalls(format, args...)
+#define snd_als300_dbgcallenter()
+#define snd_als300_dbgcallleave()
+#endif
+
+#if DEBUG_PLAY_REC
+#define snd_als300_dbgplay(format, args...) printk(KERN_ERR format, ##args)
+#else
+#define snd_als300_dbgplay(format, args...)
+#endif
+
+enum {DEVICE_ALS300, DEVICE_ALS300_PLUS};
+
+MODULE_AUTHOR("Ash Willis <ashwillis@programmer.net>");
+MODULE_DESCRIPTION("Avance Logic ALS300");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("{{Avance Logic,ALS300},{Avance Logic,ALS300+}}");
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+
+struct snd_als300 {
+ unsigned long port;
+ spinlock_t reg_lock;
+ struct snd_card *card;
+ struct pci_dev *pci;
+
+ struct snd_pcm *pcm;
+ struct snd_pcm_substream *playback_substream;
+ struct snd_pcm_substream *capture_substream;
+
+ struct snd_ac97 *ac97;
+ struct snd_opl3 *opl3;
+
+ struct resource *res_port;
+
+ int irq;
+
+ int chip_type; /* ALS300 or ALS300+ */
+
+ char revision;
+};
+
+struct snd_als300_substream_data {
+ int period_flipflop;
+ int control_register;
+ int block_counter_register;
+};
+
+static struct pci_device_id snd_als300_ids[] = {
+ { 0x4005, 0x0300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_ALS300 },
+ { 0x4005, 0x0308, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_ALS300_PLUS },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, snd_als300_ids);
+
+static inline u32 snd_als300_gcr_read(unsigned long port, unsigned short reg)
+{
+ outb(reg, port+GCR_INDEX);
+ return inl(port+GCR_DATA);
+}
+
+static inline void snd_als300_gcr_write(unsigned long port,
+ unsigned short reg, u32 val)
+{
+ outb(reg, port+GCR_INDEX);
+ outl(val, port+GCR_DATA);
+}
+
+/* Enable/Disable Interrupts */
+static void snd_als300_set_irq_flag(struct snd_als300 *chip, int cmd)
+{
+ u32 tmp = snd_als300_gcr_read(chip->port, MISC_CONTROL);
+ snd_als300_dbgcallenter();
+
+ /* boolean XOR check, since old vs. new hardware have
+ directly reversed bit setting for ENABLE and DISABLE.
+ ALS300+ acts like newer versions of ALS300 */
+ if (((chip->revision > 5 || chip->chip_type == DEVICE_ALS300_PLUS) ^
+ (cmd == IRQ_ENABLE)) == 0)
+ tmp |= IRQ_SET_BIT;
+ else
+ tmp &= ~IRQ_SET_BIT;
+ snd_als300_gcr_write(chip->port, MISC_CONTROL, tmp);
+ snd_als300_dbgcallleave();
+}
+
+static int snd_als300_free(struct snd_als300 *chip)
+{
+ snd_als300_dbgcallenter();
+ snd_als300_set_irq_flag(chip, IRQ_DISABLE);
+ if (chip->irq >= 0)
+ free_irq(chip->irq, (void *)chip);
+ pci_release_regions(chip->pci);
+ pci_disable_device(chip->pci);
+ kfree(chip);
+ snd_als300_dbgcallleave();
+ return 0;
+}
+
+static int snd_als300_dev_free(struct snd_device *device)
+{
+ struct snd_als300 *chip = device->device_data;
+ return snd_als300_free(chip);
+}
+
+static irqreturn_t snd_als300_interrupt(int irq, void *dev_id,
+ struct pt_regs *regs)
+{
+ u8 status;
+ struct snd_als300 *chip = dev_id;
+ struct snd_als300_substream_data *data;
+
+ status = inb(chip->port+ALS300_IRQ_STATUS);
+ if (!status) /* shared IRQ, for different device?? Exit ASAP! */
+ return IRQ_NONE;
+
+ /* ACK everything ASAP */
+ outb(status, chip->port+ALS300_IRQ_STATUS);
+ if (status & IRQ_PLAYBACK) {
+ if (chip->pcm && chip->playback_substream) {
+ data = chip->playback_substream->runtime->private_data;
+ data->period_flipflop ^= 1;
+ snd_pcm_period_elapsed(chip->playback_substream);
+ snd_als300_dbgplay("IRQ_PLAYBACK\n");
+ }
+ }
+ if (status & IRQ_CAPTURE) {
+ if (chip->pcm && chip->capture_substream) {
+ data = chip->capture_substream->runtime->private_data;
+ data->period_flipflop ^= 1;
+ snd_pcm_period_elapsed(chip->capture_substream);
+ snd_als300_dbgplay("IRQ_CAPTURE\n");
+ }
+ }
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t snd_als300plus_interrupt(int irq, void *dev_id,
+ struct pt_regs *regs)
+{
+ u8 general, mpu, dram;
+ struct snd_als300 *chip = dev_id;
+ struct snd_als300_substream_data *data;
+
+ general = inb(chip->port+ALS300P_IRQ_STATUS);
+ mpu = inb(chip->port+MPU_IRQ_STATUS);
+ dram = inb(chip->port+ALS300P_DRAM_IRQ_STATUS);
+
+ /* shared IRQ, for different device?? Exit ASAP! */
+ if ((general == 0) && ((mpu & 0x80) == 0) && ((dram & 0x01) == 0))
+ return IRQ_NONE;
+
+ if (general & IRQ_PLAYBACK) {
+ if (chip->pcm && chip->playback_substream) {
+ outb(IRQ_PLAYBACK, chip->port+ALS300P_IRQ_STATUS);
+ data = chip->playback_substream->runtime->private_data;
+ data->period_flipflop ^= 1;
+ snd_pcm_period_elapsed(chip->playback_substream);
+ snd_als300_dbgplay("IRQ_PLAYBACK\n");
+ }
+ }
+ if (general & IRQ_CAPTURE) {
+ if (chip->pcm && chip->capture_substream) {
+ outb(IRQ_CAPTURE, chip->port+ALS300P_IRQ_STATUS);
+ data = chip->capture_substream->runtime->private_data;
+ data->period_flipflop ^= 1;
+ snd_pcm_period_elapsed(chip->capture_substream);
+ snd_als300_dbgplay("IRQ_CAPTURE\n");
+ }
+ }
+ /* FIXME: Ack other interrupt types. Not important right now as
+ * those other devices aren't enabled. */
+ return IRQ_HANDLED;
+}
+
+static void __devexit snd_als300_remove(struct pci_dev *pci)
+{
+ snd_als300_dbgcallenter();
+ snd_card_free(pci_get_drvdata(pci));
+ pci_set_drvdata(pci, NULL);
+ snd_als300_dbgcallleave();
+}
+
+static unsigned short snd_als300_ac97_read(struct snd_ac97 *ac97,
+ unsigned short reg)
+{
+ int i;
+ struct snd_als300 *chip = ac97->private_data;
+
+ for (i = 0; i < 1000; i++) {
+ if ((inb(chip->port+AC97_STATUS) & (AC97_BUSY)) == 0)
+ break;
+ udelay(10);
+ }
+ outl((reg << 24) | (1 << 31), chip->port+AC97_ACCESS);
+
+ for (i = 0; i < 1000; i++) {
+ if ((inb(chip->port+AC97_STATUS) & (AC97_DATA_AVAIL)) != 0)
+ break;
+ udelay(10);
+ }
+ return inw(chip->port+AC97_READ);
+}
+
+static void snd_als300_ac97_write(struct snd_ac97 *ac97,
+ unsigned short reg, unsigned short val)
+{
+ int i;
+ struct snd_als300 *chip = ac97->private_data;
+
+ for (i = 0; i < 1000; i++) {
+ if ((inb(chip->port+AC97_STATUS) & (AC97_BUSY)) == 0)
+ break;
+ udelay(10);
+ }
+ outl((reg << 24) | val, chip->port+AC97_ACCESS);
+}
+
+static int snd_als300_ac97(struct snd_als300 *chip)
+{
+ struct snd_ac97_bus *bus;
+ struct snd_ac97_template ac97;
+ int err;
+ static struct snd_ac97_bus_ops ops = {
+ .write = snd_als300_ac97_write,
+ .read = snd_als300_ac97_read,
+ };
+
+ snd_als300_dbgcallenter();
+ if ((err = snd_ac97_bus(chip->card, 0, &ops, NULL, &bus)) < 0)
+ return err;
+
+ memset(&ac97, 0, sizeof(ac97));
+ ac97.private_data = chip;
+
+ snd_als300_dbgcallleave();
+ return snd_ac97_mixer(bus, &ac97, &chip->ac97);
+}
+
+/* hardware definition
+ *
+ * In AC97 mode, we always use 48k/16bit/stereo.
+ * Any request to change data type is ignored by
+ * the card when it is running outside of legacy
+ * mode.
+ */
+static struct snd_pcm_hardware snd_als300_playback_hw =
+{
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_MMAP_VALID),
+ .formats = SNDRV_PCM_FMTBIT_S16,
+ .rates = SNDRV_PCM_RATE_48000,
+ .rate_min = 48000,
+ .rate_max = 48000,
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = 64 * 1024,
+ .period_bytes_min = 64,
+ .period_bytes_max = 32 * 1024,
+ .periods_min = 2,
+ .periods_max = 2,
+};
+
+static struct snd_pcm_hardware snd_als300_capture_hw =
+{
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_MMAP_VALID),
+ .formats = SNDRV_PCM_FMTBIT_S16,
+ .rates = SNDRV_PCM_RATE_48000,
+ .rate_min = 48000,
+ .rate_max = 48000,
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = 64 * 1024,
+ .period_bytes_min = 64,
+ .period_bytes_max = 32 * 1024,
+ .periods_min = 2,
+ .periods_max = 2,
+};
+
+static int snd_als300_playback_open(struct snd_pcm_substream *substream)
+{
+ struct snd_als300 *chip = snd_pcm_substream_chip(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_als300_substream_data *data = kzalloc(sizeof(*data),
+ GFP_KERNEL);
+
+ snd_als300_dbgcallenter();
+ chip->playback_substream = substream;
+ runtime->hw = snd_als300_playback_hw;
+ runtime->private_data = data;
+ data->control_register = PLAYBACK_CONTROL;
+ data->block_counter_register = PLAYBACK_BLOCK_COUNTER;
+ snd_als300_dbgcallleave();
+ return 0;
+}
+
+static int snd_als300_playback_close(struct snd_pcm_substream *substream)
+{
+ struct snd_als300 *chip = snd_pcm_substream_chip(substream);
+ struct snd_als300_substream_data *data;
+
+ data = substream->runtime->private_data;
+ snd_als300_dbgcallenter();
+ kfree(data);
+ chip->playback_substream = NULL;
+ snd_pcm_lib_free_pages(substream);
+ snd_als300_dbgcallleave();
+ return 0;
+}
+
+static int snd_als300_capture_open(struct snd_pcm_substream *substream)
+{
+ struct snd_als300 *chip = snd_pcm_substream_chip(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_als300_substream_data *data = kzalloc(sizeof(*data),
+ GFP_KERNEL);
+
+ snd_als300_dbgcallenter();
+ chip->capture_substream = substream;
+ runtime->hw = snd_als300_capture_hw;
+ runtime->private_data = data;
+ data->control_register = RECORD_CONTROL;
+ data->block_counter_register = RECORD_BLOCK_COUNTER;
+ snd_als300_dbgcallleave();
+ return 0;
+}
+
+static int snd_als300_capture_close(struct snd_pcm_substream *substream)
+{
+ struct snd_als300 *chip = snd_pcm_substream_chip(substream);
+ struct snd_als300_substream_data *data;
+
+ data = substream->runtime->private_data;
+ snd_als300_dbgcallenter();
+ kfree(data);
+ chip->capture_substream = NULL;
+ snd_pcm_lib_free_pages(substream);
+ snd_als300_dbgcallleave();
+ return 0;
+}
+
+static int snd_als300_pcm_hw_params(struct snd_pcm_substream *substream,
+ snd_pcm_hw_params_t * hw_params)
+{
+ return snd_pcm_lib_malloc_pages(substream,
+ params_buffer_bytes(hw_params));
+}
+
+static int snd_als300_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+ return snd_pcm_lib_free_pages(substream);
+}
+
+static int snd_als300_playback_prepare(struct snd_pcm_substream *substream)
+{
+ u32 tmp;
+ struct snd_als300 *chip = snd_pcm_substream_chip(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ unsigned short period_bytes = snd_pcm_lib_period_bytes(substream);
+ unsigned short buffer_bytes = snd_pcm_lib_buffer_bytes(substream);
+
+ snd_als300_dbgcallenter();
+ spin_lock_irq(&chip->reg_lock);
+ tmp = snd_als300_gcr_read(chip->port, PLAYBACK_CONTROL);
+ tmp &= ~TRANSFER_START;
+
+ snd_als300_dbgplay("Period bytes: %d Buffer bytes %d\n",
+ period_bytes, buffer_bytes);
+
+ /* set block size */
+ tmp &= 0xffff0000;
+ tmp |= period_bytes - 1;
+ snd_als300_gcr_write(chip->port, PLAYBACK_CONTROL, tmp);
+
+ /* set dma area */
+ snd_als300_gcr_write(chip->port, PLAYBACK_START,
+ runtime->dma_addr);
+ snd_als300_gcr_write(chip->port, PLAYBACK_END,
+ runtime->dma_addr + buffer_bytes - 1);
+ spin_unlock_irq(&chip->reg_lock);
+ snd_als300_dbgcallleave();
+ return 0;
+}
+
+static int snd_als300_capture_prepare(struct snd_pcm_substream *substream)
+{
+ u32 tmp;
+ struct snd_als300 *chip = snd_pcm_substream_chip(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ unsigned short period_bytes = snd_pcm_lib_period_bytes(substream);
+ unsigned short buffer_bytes = snd_pcm_lib_buffer_bytes(substream);
+
+ snd_als300_dbgcallenter();
+ spin_lock_irq(&chip->reg_lock);
+ tmp = snd_als300_gcr_read(chip->port, RECORD_CONTROL);
+ tmp &= ~TRANSFER_START;
+
+ snd_als300_dbgplay("Period bytes: %d Buffer bytes %d\n", period_bytes,
+ buffer_bytes);
+
+ /* set block size */
+ tmp &= 0xffff0000;
+ tmp |= period_bytes - 1;
+
+ /* set dma area */
+ snd_als300_gcr_write(chip->port, RECORD_CONTROL, tmp);
+ snd_als300_gcr_write(chip->port, RECORD_START,
+ runtime->dma_addr);
+ snd_als300_gcr_write(chip->port, RECORD_END,
+ runtime->dma_addr + buffer_bytes - 1);
+ spin_unlock_irq(&chip->reg_lock);
+ snd_als300_dbgcallleave();
+ return 0;
+}
+
+static int snd_als300_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_als300 *chip = snd_pcm_substream_chip(substream);
+ u32 tmp;
+ struct snd_als300_substream_data *data;
+ unsigned short reg;
+ int ret = 0;
+
+ data = substream->runtime->private_data;
+ reg = data->control_register;
+
+ snd_als300_dbgcallenter();
+ spin_lock(&chip->reg_lock);
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ tmp = snd_als300_gcr_read(chip->port, reg);
+ data->period_flipflop = 1;
+ snd_als300_gcr_write(chip->port, reg, tmp | TRANSFER_START);
+ snd_als300_dbgplay("TRIGGER START\n");
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ tmp = snd_als300_gcr_read(chip->port, reg);
+ snd_als300_gcr_write(chip->port, reg, tmp & ~TRANSFER_START);
+ snd_als300_dbgplay("TRIGGER STOP\n");
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ tmp = snd_als300_gcr_read(chip->port, reg);
+ snd_als300_gcr_write(chip->port, reg, tmp | FIFO_PAUSE);
+ snd_als300_dbgplay("TRIGGER PAUSE\n");
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ tmp = snd_als300_gcr_read(chip->port, reg);
+ snd_als300_gcr_write(chip->port, reg, tmp & ~FIFO_PAUSE);
+ snd_als300_dbgplay("TRIGGER RELEASE\n");
+ break;
+ default:
+ snd_als300_dbgplay("TRIGGER INVALID\n");
+ ret = -EINVAL;
+ }
+ spin_unlock(&chip->reg_lock);
+ snd_als300_dbgcallleave();
+ return ret;
+}
+
+static snd_pcm_uframes_t snd_als300_pointer(struct snd_pcm_substream *substream)
+{
+ u16 current_ptr;
+ struct snd_als300 *chip = snd_pcm_substream_chip(substream);
+ struct snd_als300_substream_data *data;
+ unsigned short period_bytes;
+
+ data = substream->runtime->private_data;
+ period_bytes = snd_pcm_lib_period_bytes(substream);
+
+ snd_als300_dbgcallenter();
+ spin_lock(&chip->reg_lock);
+ current_ptr = (u16) snd_als300_gcr_read(chip->port,
+ data->block_counter_register) + 4;
+ spin_unlock(&chip->reg_lock);
+ if (current_ptr > period_bytes)
+ current_ptr = 0;
+ else
+ current_ptr = period_bytes - current_ptr;
+
+ if (data->period_flipflop == 0)
+ current_ptr += period_bytes;
+ snd_als300_dbgplay("Pointer (bytes): %d\n", current_ptr);
+ snd_als300_dbgcallleave();
+ return bytes_to_frames(substream->runtime, current_ptr);
+}
+
+static struct snd_pcm_ops snd_als300_playback_ops = {
+ .open = snd_als300_playback_open,
+ .close = snd_als300_playback_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_als300_pcm_hw_params,
+ .hw_free = snd_als300_pcm_hw_free,
+ .prepare = snd_als300_playback_prepare,
+ .trigger = snd_als300_trigger,
+ .pointer = snd_als300_pointer,
+};
+
+static struct snd_pcm_ops snd_als300_capture_ops = {
+ .open = snd_als300_capture_open,
+ .close = snd_als300_capture_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_als300_pcm_hw_params,
+ .hw_free = snd_als300_pcm_hw_free,
+ .prepare = snd_als300_capture_prepare,
+ .trigger = snd_als300_trigger,
+ .pointer = snd_als300_pointer,
+};
+
+static int __devinit snd_als300_new_pcm(struct snd_als300 *chip)
+{
+ struct snd_pcm *pcm;
+ int err;
+
+ snd_als300_dbgcallenter();
+ err = snd_pcm_new(chip->card, "ALS300", 0, 1, 1, &pcm);
+ if (err < 0)
+ return err;
+ pcm->private_data = chip;
+ strcpy(pcm->name, "ALS300");
+ chip->pcm = pcm;
+
+ /* set operators */
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ &snd_als300_playback_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+ &snd_als300_capture_ops);
+
+ /* pre-allocation of buffers */
+ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+ snd_dma_pci_data(chip->pci), 64*1024, 64*1024);
+ snd_als300_dbgcallleave();
+ return 0;
+}
+
+static void snd_als300_init(struct snd_als300 *chip)
+{
+ unsigned long flags;
+ u32 tmp;
+
+ snd_als300_dbgcallenter();
+ spin_lock_irqsave(&chip->reg_lock, flags);
+ chip->revision = (snd_als300_gcr_read(chip->port, MISC_CONTROL) >> 16)
+ & 0x0000000F;
+ /* Setup DRAM */
+ tmp = snd_als300_gcr_read(chip->port, DRAM_WRITE_CONTROL);
+ snd_als300_gcr_write(chip->port, DRAM_WRITE_CONTROL,
+ (tmp | DRAM_MODE_2)
+ & ~WRITE_TRANS_START);
+
+ /* Enable IRQ output */
+ snd_als300_set_irq_flag(chip, IRQ_ENABLE);
+
+ /* Unmute hardware devices so their outputs get routed to
+ * the onboard mixer */
+ tmp = snd_als300_gcr_read(chip->port, MISC_CONTROL);
+ snd_als300_gcr_write(chip->port, MISC_CONTROL,
+ tmp | VMUTE_NORMAL | MMUTE_NORMAL);
+
+ /* Reset volumes */
+ snd_als300_gcr_write(chip->port, MUS_VOC_VOL, 0);
+
+ /* Make sure playback transfer is stopped */
+ tmp = snd_als300_gcr_read(chip->port, PLAYBACK_CONTROL);
+ snd_als300_gcr_write(chip->port, PLAYBACK_CONTROL,
+ tmp & ~TRANSFER_START);
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+ snd_als300_dbgcallleave();
+}
+
+static int __devinit snd_als300_create(snd_card_t *card,
+ struct pci_dev *pci, int chip_type,
+ struct snd_als300 **rchip)
+{
+ struct snd_als300 *chip;
+ void *irq_handler;
+ int err;
+
+ static snd_device_ops_t ops = {
+ .dev_free = snd_als300_dev_free,
+ };
+ *rchip = NULL;
+
+ snd_als300_dbgcallenter();
+ if ((err = pci_enable_device(pci)) < 0)
+ return err;
+
+ if (pci_set_dma_mask(pci, 0x0fffffff) < 0 ||
+ pci_set_consistent_dma_mask(pci, 0x0fffffff) < 0) {
+ printk(KERN_ERR "error setting 28bit DMA mask\n");
+ pci_disable_device(pci);
+ return -ENXIO;
+ }
+ pci_set_master(pci);
+
+ chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ if (chip == NULL) {
+ pci_disable_device(pci);
+ return -ENOMEM;
+ }
+
+ chip->card = card;
+ chip->pci = pci;
+ chip->irq = -1;
+ chip->chip_type = chip_type;
+ spin_lock_init(&chip->reg_lock);
+
+ if ((err = pci_request_regions(pci, "ALS300")) < 0) {
+ kfree(chip);
+ pci_disable_device(pci);
+ return err;
+ }
+ chip->port = pci_resource_start(pci, 0);
+
+ if (chip->chip_type == DEVICE_ALS300_PLUS)
+ irq_handler = snd_als300plus_interrupt;
+ else
+ irq_handler = snd_als300_interrupt;
+
+ if (request_irq(pci->irq, irq_handler, SA_INTERRUPT|SA_SHIRQ,
+ card->shortname, (void *)chip)) {
+ snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+ snd_als300_free(chip);
+ return -EBUSY;
+ }
+ chip->irq = pci->irq;
+
+
+ snd_als300_init(chip);
+
+ if (snd_als300_ac97(chip) < 0) {
+ snd_printk(KERN_WARNING "Could not create ac97\n");
+ snd_als300_free(chip);
+ return err;
+ }
+
+ if ((err = snd_als300_new_pcm(chip)) < 0) {
+ snd_printk(KERN_WARNING "Could not create PCM\n");
+ snd_als300_free(chip);
+ return err;
+ }
+
+ if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL,
+ chip, &ops)) < 0) {
+ snd_als300_free(chip);
+ return err;
+ }
+
+ snd_card_set_dev(card, &pci->dev);
+
+ *rchip = chip;
+ snd_als300_dbgcallleave();
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int snd_als300_suspend(struct pci_dev *pci, pm_message_t state)
+{
+ struct snd_card *card = pci_get_drvdata(pci);
+ struct snd_als300 *chip = card->private_data;
+
+ snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+ snd_pcm_suspend_all(chip->pcm);
+ snd_ac97_suspend(chip->ac97);
+
+ pci_set_power_state(pci, PCI_D3hot);
+ pci_disable_device(pci);
+ pci_save_state(pci);
+ return 0;
+}
+
+static int snd_als300_resume(struct pci_dev *pci)
+{
+ struct snd_card *card = pci_get_drvdata(pci);
+ struct snd_als300 *chip = card->private_data;
+
+ pci_restore_state(pci);
+ pci_enable_device(pci);
+ pci_set_power_state(pci, PCI_D0);
+ pci_set_master(pci);
+
+ snd_als300_init(chip);
+ snd_ac97_resume(chip->ac97);
+
+ snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+ return 0;
+}
+#endif
+
+static int __devinit snd_als300_probe(struct pci_dev *pci,
+ const struct pci_device_id *pci_id)
+{
+ static int dev;
+ struct snd_card *card;
+ struct snd_als300 *chip;
+ int err, chip_type;
+
+ if (dev >= SNDRV_CARDS)
+ return -ENODEV;
+ if (!enable[dev]) {
+ dev++;
+ return -ENOENT;
+ }
+
+ card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
+
+ if (card == NULL)
+ return -ENOMEM;
+
+ chip_type = pci_id->driver_data;
+
+ if ((err = snd_als300_create(card, pci, chip_type, &chip)) < 0) {
+ snd_card_free(card);
+ return err;
+ }
+ card->private_data = chip;
+
+ strcpy(card->driver, "ALS300");
+ if (chip->chip_type == DEVICE_ALS300_PLUS)
+ /* don't know much about ALS300+ yet
+ * print revision number for now */
+ sprintf(card->shortname, "ALS300+ (Rev. %d)", chip->revision);
+ else
+ sprintf(card->shortname, "ALS300 (Rev. %c)", 'A' +
+ chip->revision - 1);
+ sprintf(card->longname, "%s at 0x%lx irq %i",
+ card->shortname, chip->port, chip->irq);
+
+ if ((err = snd_card_register(card)) < 0) {
+ snd_card_free(card);
+ return err;
+ }
+ pci_set_drvdata(pci, card);
+ dev++;
+ return 0;
+}
+
+static struct pci_driver driver = {
+ .name = "ALS300",
+ .id_table = snd_als300_ids,
+ .probe = snd_als300_probe,
+ .remove = __devexit_p(snd_als300_remove),
+#ifdef CONFIG_PM
+ .suspend = snd_als300_suspend,
+ .resume = snd_als300_resume,
+#endif
+};
+
+static int __init alsa_card_als300_init(void)
+{
+ return pci_register_driver(&driver);
+}
+
+static void __exit alsa_card_als300_exit(void)
+{
+ pci_unregister_driver(&driver);
+}
+
+module_init(alsa_card_als300_init)
+module_exit(alsa_card_als300_exit)
diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c
index 4f65ec56bf3..ac4e73f69c1 100644
--- a/sound/pci/cs4281.c
+++ b/sound/pci/cs4281.c
@@ -1046,7 +1046,7 @@ static int snd_cs4281_put_volume(struct snd_kcontrol *kcontrol,
snd_cs4281_pokeBA0(chip, regL, volL);
change = 1;
}
- if (ucontrol->value.integer.value[0] != volL) {
+ if (ucontrol->value.integer.value[1] != volR) {
volR = CS_VOL_MASK - (ucontrol->value.integer.value[1] & CS_VOL_MASK);
snd_cs4281_pokeBA0(chip, regR, volR);
change = 1;
@@ -1416,7 +1416,7 @@ static int __devinit snd_cs4281_create(struct snd_card *card,
static int snd_cs4281_chip_init(struct cs4281 *chip)
{
unsigned int tmp;
- int timeout;
+ unsigned long end_time;
int retry_count = 2;
/* Having EPPMC.FPDN=1 prevent proper chip initialisation */
@@ -1496,7 +1496,7 @@ static int snd_cs4281_chip_init(struct cs4281 *chip)
/*
* Wait for the DLL ready signal from the clock logic.
*/
- timeout = 100;
+ end_time = jiffies + HZ;
do {
/*
* Read the AC97 status register to see if we've seen a CODEC
@@ -1504,8 +1504,8 @@ static int snd_cs4281_chip_init(struct cs4281 *chip)
*/
if (snd_cs4281_peekBA0(chip, BA0_CLKCR1) & BA0_CLKCR1_DLLRDY)
goto __ok0;
- msleep(1);
- } while (timeout-- > 0);
+ schedule_timeout_uninterruptible(1);
+ } while (time_after_eq(end_time, jiffies));
snd_printk(KERN_ERR "DLLRDY not seen\n");
return -EIO;
@@ -1522,7 +1522,7 @@ static int snd_cs4281_chip_init(struct cs4281 *chip)
/*
* Wait for the codec ready signal from the AC97 codec.
*/
- timeout = 100;
+ end_time = jiffies + HZ;
do {
/*
* Read the AC97 status register to see if we've seen a CODEC
@@ -1530,20 +1530,20 @@ static int snd_cs4281_chip_init(struct cs4281 *chip)
*/
if (snd_cs4281_peekBA0(chip, BA0_ACSTS) & BA0_ACSTS_CRDY)
goto __ok1;
- msleep(1);
- } while (timeout-- > 0);
+ schedule_timeout_uninterruptible(1);
+ } while (time_after_eq(end_time, jiffies));
snd_printk(KERN_ERR "never read codec ready from AC'97 (0x%x)\n", snd_cs4281_peekBA0(chip, BA0_ACSTS));
return -EIO;
__ok1:
if (chip->dual_codec) {
- timeout = 100;
+ end_time = jiffies + HZ;
do {
if (snd_cs4281_peekBA0(chip, BA0_ACSTS2) & BA0_ACSTS_CRDY)
goto __codec2_ok;
- msleep(1);
- } while (timeout-- > 0);
+ schedule_timeout_uninterruptible(1);
+ } while (time_after_eq(end_time, jiffies));
snd_printk(KERN_INFO "secondary codec doesn't respond. disable it...\n");
chip->dual_codec = 0;
__codec2_ok: ;
@@ -1561,7 +1561,7 @@ static int snd_cs4281_chip_init(struct cs4281 *chip)
* the codec is pumping ADC data across the AC-link.
*/
- timeout = 100;
+ end_time = jiffies + HZ;
do {
/*
* Read the input slot valid register and see if input slots 3
@@ -1569,8 +1569,8 @@ static int snd_cs4281_chip_init(struct cs4281 *chip)
*/
if ((snd_cs4281_peekBA0(chip, BA0_ACISV) & (BA0_ACISV_SLV(3) | BA0_ACISV_SLV(4))) == (BA0_ACISV_SLV(3) | BA0_ACISV_SLV(4)))
goto __ok2;
- msleep(1);
- } while (timeout-- > 0);
+ schedule_timeout_uninterruptible(1);
+ } while (time_after_eq(end_time, jiffies));
if (--retry_count > 0)
goto __retry;
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index b42dff7ceed..5bee3b53647 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -295,7 +295,7 @@ static int init_unsol_queue(struct hda_bus *bus)
snd_printk(KERN_ERR "hda_codec: can't allocate unsolicited queue\n");
return -ENOMEM;
}
- unsol->workq = create_workqueue("hda_codec");
+ unsol->workq = create_singlethread_workqueue("hda_codec");
if (! unsol->workq) {
snd_printk(KERN_ERR "hda_codec: can't create workqueue\n");
kfree(unsol);
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index c096606970f..0ad60ae2901 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -81,6 +81,7 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
"{Intel, ESB2},"
"{Intel, ICH8},"
"{ATI, SB450},"
+ "{ATI, SB600},"
"{VIA, VT8251},"
"{VIA, VT8237A},"
"{SiS, SIS966},"
@@ -1619,6 +1620,7 @@ static struct pci_device_id azx_ids[] = {
{ 0x8086, 0x269a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ESB2 */
{ 0x8086, 0x284b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH8 */
{ 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB450 */
+ { 0x1002, 0x4383, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB600 */
{ 0x1106, 0x3288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_VIA }, /* VIA VT8251/VT8237A */
{ 0x1039, 0x7502, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_SIS }, /* SIS966 */
{ 0x10b9, 0x5461, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ULI }, /* ULI M5461 */
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index 32401bd8c22..2bfe37e8543 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -44,6 +44,7 @@ struct ad198x_spec {
* dig_out_nid and hp_nid are optional
*/
unsigned int cur_eapd;
+ unsigned int need_dac_fix;
/* capture */
unsigned int num_adc_nids;
@@ -836,10 +837,14 @@ static int patch_ad1986a(struct hda_codec *codec)
case AD1986A_3STACK:
spec->num_mixers = 2;
spec->mixers[1] = ad1986a_3st_mixers;
- spec->num_init_verbs = 2;
+ spec->num_init_verbs = 3;
spec->init_verbs[1] = ad1986a_3st_init_verbs;
+ spec->init_verbs[2] = ad1986a_ch2_init;
spec->channel_mode = ad1986a_modes;
spec->num_channel_mode = ARRAY_SIZE(ad1986a_modes);
+ spec->need_dac_fix = 1;
+ spec->multiout.max_channels = 2;
+ spec->multiout.num_dacs = 1;
break;
case AD1986A_LAPTOP:
spec->mixers[0] = ad1986a_laptop_mixers;
@@ -1555,6 +1560,8 @@ static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol,
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct ad198x_spec *spec = codec->spec;
+ if (spec->need_dac_fix)
+ spec->multiout.num_dacs = spec->multiout.max_channels / 2;
return snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
spec->num_channel_mode, &spec->multiout.max_channels);
}
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 4c6c9ec8ea5..66bbdb60f50 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -52,6 +52,7 @@ enum {
ALC880_CLEVO,
ALC880_TCL_S700,
ALC880_LG,
+ ALC880_LG_LW,
#ifdef CONFIG_SND_DEBUG
ALC880_TEST,
#endif
@@ -131,6 +132,7 @@ struct alc_spec {
hda_nid_t dig_in_nid; /* digital-in NID; optional */
/* capture source */
+ unsigned int num_mux_defs;
const struct hda_input_mux *input_mux;
unsigned int cur_mux[3];
@@ -172,6 +174,7 @@ struct alc_config_preset {
hda_nid_t dig_in_nid;
unsigned int num_channel_mode;
const struct hda_channel_mode *channel_mode;
+ unsigned int num_mux_defs;
const struct hda_input_mux *input_mux;
void (*unsol_event)(struct hda_codec *, unsigned int);
void (*init_hook)(struct hda_codec *);
@@ -185,7 +188,10 @@ static int alc_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct alc_spec *spec = codec->spec;
- return snd_hda_input_mux_info(spec->input_mux, uinfo);
+ unsigned int mux_idx = snd_ctl_get_ioffidx(kcontrol, &uinfo->id);
+ if (mux_idx >= spec->num_mux_defs)
+ mux_idx = 0;
+ return snd_hda_input_mux_info(&spec->input_mux[mux_idx], uinfo);
}
static int alc_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -203,7 +209,8 @@ static int alc_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct alc_spec *spec = codec->spec;
unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
- return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
+ unsigned int mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
+ return snd_hda_input_mux_put(codec, &spec->input_mux[mux_idx], ucontrol,
spec->adc_nids[adc_idx], &spec->cur_mux[adc_idx]);
}
@@ -245,7 +252,8 @@ static int alc_ch_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_va
* states other than HiZ (eg: PIN_VREFxx) and revert to HiZ if any of these
* are requested. Therefore order this list so that this behaviour will not
* cause problems when mixer clients move through the enum sequentially.
- * NIDs 0x0f and 0x10 have been observed to have this behaviour.
+ * NIDs 0x0f and 0x10 have been observed to have this behaviour as of
+ * March 2006.
*/
static char *alc_pin_mode_names[] = {
"Mic 50pc bias", "Mic 80pc bias",
@@ -255,19 +263,27 @@ static unsigned char alc_pin_mode_values[] = {
PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP,
};
/* The control can present all 5 options, or it can limit the options based
- * in the pin being assumed to be exclusively an input or an output pin.
+ * in the pin being assumed to be exclusively an input or an output pin. In
+ * addition, "input" pins may or may not process the mic bias option
+ * depending on actual widget capability (NIDs 0x0f and 0x10 don't seem to
+ * accept requests for bias as of chip versions up to March 2006) and/or
+ * wiring in the computer.
*/
-#define ALC_PIN_DIR_IN 0x00
-#define ALC_PIN_DIR_OUT 0x01
-#define ALC_PIN_DIR_INOUT 0x02
+#define ALC_PIN_DIR_IN 0x00
+#define ALC_PIN_DIR_OUT 0x01
+#define ALC_PIN_DIR_INOUT 0x02
+#define ALC_PIN_DIR_IN_NOMICBIAS 0x03
+#define ALC_PIN_DIR_INOUT_NOMICBIAS 0x04
-/* Info about the pin modes supported by the three different pin directions.
+/* Info about the pin modes supported by the different pin direction modes.
* For each direction the minimum and maximum values are given.
*/
-static signed char alc_pin_mode_dir_info[3][2] = {
+static signed char alc_pin_mode_dir_info[5][2] = {
{ 0, 2 }, /* ALC_PIN_DIR_IN */
{ 3, 4 }, /* ALC_PIN_DIR_OUT */
{ 0, 4 }, /* ALC_PIN_DIR_INOUT */
+ { 2, 2 }, /* ALC_PIN_DIR_IN_NOMICBIAS */
+ { 2, 4 }, /* ALC_PIN_DIR_INOUT_NOMICBIAS */
};
#define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0])
#define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1])
@@ -329,9 +345,10 @@ static int alc_pin_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v
* input modes.
*
* Dynamically switching the input/output buffers probably
- * reduces noise slightly, particularly on input. However,
- * havingboth input and output buffers enabled
- * simultaneously doesn't seem to be problematic.
+ * reduces noise slightly (particularly on input) so we'll
+ * do it. However, having both input and output buffers
+ * enabled simultaneously doesn't seem to be problematic if
+ * this turns out to be necessary in the future.
*/
if (val <= 2) {
snd_hda_codec_write(codec,nid,0,AC_VERB_SET_AMP_GAIN_MUTE,
@@ -483,6 +500,9 @@ static void setup_preset(struct alc_spec *spec, const struct alc_config_preset *
spec->multiout.dig_out_nid = preset->dig_out_nid;
spec->multiout.hp_nid = preset->hp_nid;
+ spec->num_mux_defs = preset->num_mux_defs;
+ if (! spec->num_mux_defs)
+ spec->num_mux_defs = 1;
spec->input_mux = preset->input_mux;
spec->num_adc_nids = preset->num_adc_nids;
@@ -1427,6 +1447,82 @@ static void alc880_lg_unsol_event(struct hda_codec *codec, unsigned int res)
}
/*
+ * LG LW20
+ *
+ * Pin assignment:
+ * Speaker-out: 0x14
+ * Mic-In: 0x18
+ * Built-in Mic-In: 0x19 (?)
+ * HP-Out: 0x1b
+ * SPDIF-Out: 0x1e
+ */
+
+/* seems analog CD is not working */
+static struct hda_input_mux alc880_lg_lw_capture_source = {
+ .num_items = 2,
+ .items = {
+ { "Mic", 0x0 },
+ { "Internal Mic", 0x1 },
+ },
+};
+
+static struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
+ HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
+ HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+ { } /* end */
+};
+
+static struct hda_verb alc880_lg_lw_init_verbs[] = {
+ /* set capture source to mic-in */
+ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(7)},
+ /* speaker-out */
+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ /* HP-out */
+ {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
+ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ /* mic-in to input */
+ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ /* built-in mic */
+ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ /* jack sense */
+ {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1},
+ { }
+};
+
+/* toggle speaker-output according to the hp-jack state */
+static void alc880_lg_lw_automute(struct hda_codec *codec)
+{
+ unsigned int present;
+
+ present = snd_hda_codec_read(codec, 0x1b, 0,
+ AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+ snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
+ 0x80, present ? 0x80 : 0);
+ snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
+ 0x80, present ? 0x80 : 0);
+}
+
+static void alc880_lg_lw_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+ /* Looks like the unsol event is incompatible with the standard
+ * definition. 4bit tag is placed at 28 bit!
+ */
+ if ((res >> 28) == 0x01)
+ alc880_lg_lw_automute(codec);
+}
+
+/*
* Common callbacks
*/
@@ -2078,6 +2174,9 @@ static struct hda_board_config alc880_cfg_tbl[] = {
{ .modelname = "lg", .config = ALC880_LG },
{ .pci_subvendor = 0x1854, .pci_subdevice = 0x003b, .config = ALC880_LG },
+ { .modelname = "lg-lw", .config = ALC880_LG_LW },
+ { .pci_subvendor = 0x1854, .pci_subdevice = 0x0018, .config = ALC880_LG_LW },
+
#ifdef CONFIG_SND_DEBUG
{ .modelname = "test", .config = ALC880_TEST },
#endif
@@ -2268,6 +2367,19 @@ static struct alc_config_preset alc880_presets[] = {
.unsol_event = alc880_lg_unsol_event,
.init_hook = alc880_lg_automute,
},
+ [ALC880_LG_LW] = {
+ .mixers = { alc880_lg_lw_mixer },
+ .init_verbs = { alc880_volume_init_verbs,
+ alc880_lg_lw_init_verbs },
+ .num_dacs = 1,
+ .dac_nids = alc880_dac_nids,
+ .dig_out_nid = ALC880_DIGOUT_NID,
+ .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
+ .channel_mode = alc880_2_jack_modes,
+ .input_mux = &alc880_lg_lw_capture_source,
+ .unsol_event = alc880_lg_lw_unsol_event,
+ .init_hook = alc880_lg_lw_automute,
+ },
#ifdef CONFIG_SND_DEBUG
[ALC880_TEST] = {
.mixers = { alc880_test_mixer },
@@ -2593,6 +2705,7 @@ static int alc880_parse_auto_config(struct hda_codec *codec)
spec->init_verbs[spec->num_init_verbs++] = alc880_volume_init_verbs;
+ spec->num_mux_defs = 1;
spec->input_mux = &spec->private_imux;
return 1;
@@ -2722,30 +2835,56 @@ static struct hda_input_mux alc260_capture_source = {
};
/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack,
- * headphone jack and the internal CD lines.
+ * headphone jack and the internal CD lines since these are the only pins at
+ * which audio can appear. For flexibility, also allow the option of
+ * recording the mixer output on the second ADC (ADC0 doesn't have a
+ * connection to the mixer output).
*/
-static struct hda_input_mux alc260_fujitsu_capture_source = {
- .num_items = 3,
- .items = {
- { "Mic/Line", 0x0 },
- { "CD", 0x4 },
- { "Headphone", 0x2 },
+static struct hda_input_mux alc260_fujitsu_capture_sources[2] = {
+ {
+ .num_items = 3,
+ .items = {
+ { "Mic/Line", 0x0 },
+ { "CD", 0x4 },
+ { "Headphone", 0x2 },
+ },
},
+ {
+ .num_items = 4,
+ .items = {
+ { "Mic/Line", 0x0 },
+ { "CD", 0x4 },
+ { "Headphone", 0x2 },
+ { "Mixer", 0x5 },
+ },
+ },
+
};
-/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configutation to
- * the Fujitsu S702x, but jacks are marked differently. We won't allow
- * retasking the Headphone jack, so it won't be available here.
+/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to
+ * the Fujitsu S702x, but jacks are marked differently.
*/
-static struct hda_input_mux alc260_acer_capture_source = {
- .num_items = 3,
- .items = {
- { "Mic", 0x0 },
- { "Line", 0x2 },
- { "CD", 0x4 },
+static struct hda_input_mux alc260_acer_capture_sources[2] = {
+ {
+ .num_items = 4,
+ .items = {
+ { "Mic", 0x0 },
+ { "Line", 0x2 },
+ { "CD", 0x4 },
+ { "Headphone", 0x5 },
+ },
+ },
+ {
+ .num_items = 5,
+ .items = {
+ { "Mic", 0x0 },
+ { "Line", 0x2 },
+ { "CD", 0x4 },
+ { "Headphone", 0x6 },
+ { "Mixer", 0x5 },
+ },
},
};
-
/*
* This is just place-holder, so there's something for alc_build_pcms to look
* at when it calculates the maximum number of channels. ALC260 has no mixer
@@ -2806,6 +2945,9 @@ static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
{ } /* end */
};
+/* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12,
+ * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10.
+ */
static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
@@ -2822,9 +2964,28 @@ static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
{ } /* end */
};
+/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks. Note that current
+ * versions of the ALC260 don't act on requests to enable mic bias from NID
+ * 0x0f (used to drive the headphone jack in these laptops). The ALC260
+ * datasheet doesn't mention this restriction. At this stage it's not clear
+ * whether this behaviour is intentional or is a hardware bug in chip
+ * revisions available in early 2006. Therefore for now allow the
+ * "Headphone Jack Mode" control to span all choices, but if it turns out
+ * that the lack of mic bias for this NID is intentional we could change the
+ * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
+ *
+ * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006
+ * don't appear to make the mic bias available from the "line" jack, even
+ * though the NID used for this jack (0x14) can supply it. The theory is
+ * that perhaps Acer have included blocking capacitors between the ALC260
+ * and the output jack. If this turns out to be the case for all such
+ * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT
+ * to ALC_PIN_DIR_INOUT_NOMICBIAS.
+ */
static struct snd_kcontrol_new alc260_acer_mixer[] = {
HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
+ ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
@@ -3038,7 +3199,8 @@ static struct hda_verb alc260_hp_3013_init_verbs[] = {
};
/* Initialisation sequence for ALC260 as configured in Fujitsu S702x
- * laptops.
+ * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD
+ * audio = 0x16, internal speaker = 0x10.
*/
static struct hda_verb alc260_fujitsu_init_verbs[] = {
/* Disable all GPIOs */
@@ -3185,10 +3347,10 @@ static struct hda_verb alc260_acer_init_verbs[] = {
{0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
/* Do similar with the second ADC: mute capture input amp and
- * set ADC connection to line (on line1 pin)
+ * set ADC connection to mic to match ALSA's default state.
*/
{0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x05, AC_VERB_SET_CONNECT_SEL, 0x02},
+ {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
/* Mute all inputs to mixer widget (even unconnected ones) */
{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
@@ -3213,26 +3375,35 @@ static hda_nid_t alc260_test_dac_nids[1] = {
static hda_nid_t alc260_test_adc_nids[2] = {
0x04, 0x05,
};
-/* This is a bit messy since the two input muxes in the ALC260 have slight
- * variations in their signal assignments. The ideal way to deal with this
- * is to extend alc_spec.input_mux to allow a different input MUX for each
- * ADC. For the purposes of the test model it's sufficient to just list
- * both options for affected signal indices. The separate input mux
- * functionality only needs to be considered if a model comes along which
- * actually uses signals 0x5, 0x6 and 0x7 for something which makes sense to
- * record.
+/* For testing the ALC260, each input MUX needs its own definition since
+ * the signal assignments are different. This assumes that the first ADC
+ * is NID 0x04.
*/
-static struct hda_input_mux alc260_test_capture_source = {
- .num_items = 8,
- .items = {
- { "MIC1 pin", 0x0 },
- { "MIC2 pin", 0x1 },
- { "LINE1 pin", 0x2 },
- { "LINE2 pin", 0x3 },
- { "CD pin", 0x4 },
- { "LINE-OUT pin (cap1), Mixer (cap2)", 0x5 },
- { "HP-OUT pin (cap1), LINE-OUT pin (cap2)", 0x6 },
- { "HP-OUT pin (cap2 only)", 0x7 },
+static struct hda_input_mux alc260_test_capture_sources[2] = {
+ {
+ .num_items = 7,
+ .items = {
+ { "MIC1 pin", 0x0 },
+ { "MIC2 pin", 0x1 },
+ { "LINE1 pin", 0x2 },
+ { "LINE2 pin", 0x3 },
+ { "CD pin", 0x4 },
+ { "LINE-OUT pin", 0x5 },
+ { "HP-OUT pin", 0x6 },
+ },
+ },
+ {
+ .num_items = 8,
+ .items = {
+ { "MIC1 pin", 0x0 },
+ { "MIC2 pin", 0x1 },
+ { "LINE1 pin", 0x2 },
+ { "LINE2 pin", 0x3 },
+ { "CD pin", 0x4 },
+ { "Mixer", 0x5 },
+ { "LINE-OUT pin", 0x6 },
+ { "HP-OUT pin", 0x7 },
+ },
},
};
static struct snd_kcontrol_new alc260_test_mixer[] = {
@@ -3244,7 +3415,17 @@ static struct snd_kcontrol_new alc260_test_mixer[] = {
HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT),
HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT),
- /* Modes for retasking pin widgets */
+ /* Modes for retasking pin widgets
+ * Note: the ALC260 doesn't seem to act on requests to enable mic
+ * bias from NIDs 0x0f and 0x10. The ALC260 datasheet doesn't
+ * mention this restriction. At this stage it's not clear whether
+ * this behaviour is intentional or is a hardware bug in chip
+ * revisions available at least up until early 2006. Therefore for
+ * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all
+ * choices, but if it turns out that the lack of mic bias for these
+ * NIDs is intentional we could change their modes from
+ * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
+ */
ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT),
ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT),
ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT),
@@ -3606,6 +3787,7 @@ static int alc260_parse_auto_config(struct hda_codec *codec)
spec->init_verbs[spec->num_init_verbs++] = alc260_volume_init_verbs;
+ spec->num_mux_defs = 1;
spec->input_mux = &spec->private_imux;
/* check whether NID 0x04 is valid */
@@ -3711,7 +3893,8 @@ static struct alc_config_preset alc260_presets[] = {
.adc_nids = alc260_dual_adc_nids,
.num_channel_mode = ARRAY_SIZE(alc260_modes),
.channel_mode = alc260_modes,
- .input_mux = &alc260_fujitsu_capture_source,
+ .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources),
+ .input_mux = alc260_fujitsu_capture_sources,
},
[ALC260_ACER] = {
.mixers = { alc260_acer_mixer,
@@ -3723,7 +3906,8 @@ static struct alc_config_preset alc260_presets[] = {
.adc_nids = alc260_dual_adc_nids,
.num_channel_mode = ARRAY_SIZE(alc260_modes),
.channel_mode = alc260_modes,
- .input_mux = &alc260_acer_capture_source,
+ .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources),
+ .input_mux = alc260_acer_capture_sources,
},
#ifdef CONFIG_SND_DEBUG
[ALC260_TEST] = {
@@ -3736,7 +3920,8 @@ static struct alc_config_preset alc260_presets[] = {
.adc_nids = alc260_test_adc_nids,
.num_channel_mode = ARRAY_SIZE(alc260_modes),
.channel_mode = alc260_modes,
- .input_mux = &alc260_test_capture_source,
+ .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources),
+ .input_mux = alc260_test_capture_sources,
},
#endif
};
@@ -3828,7 +4013,6 @@ static struct hda_input_mux alc882_capture_source = {
{ "CD", 0x4 },
},
};
-
#define alc882_mux_enum_info alc_mux_enum_info
#define alc882_mux_enum_get alc_mux_enum_get
@@ -4730,6 +4914,7 @@ static int alc262_parse_auto_config(struct hda_codec *codec)
spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
spec->init_verbs[spec->num_init_verbs++] = alc262_volume_init_verbs;
+ spec->num_mux_defs = 1;
spec->input_mux = &spec->private_imux;
return 1;
@@ -5406,6 +5591,7 @@ static int alc861_parse_auto_config(struct hda_codec *codec)
spec->init_verbs[spec->num_init_verbs++] = alc861_auto_init_verbs;
+ spec->num_mux_defs = 1;
spec->input_mux = &spec->private_imux;
spec->adc_nids = alc861_adc_nids;
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index b56ca401939..abe9493f0a2 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -534,6 +534,22 @@ static int stac92xx_build_pcms(struct hda_codec *codec)
return 0;
}
+static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid)
+{
+ unsigned int pincap = snd_hda_param_read(codec, nid,
+ AC_PAR_PIN_CAP);
+ pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
+ if (pincap & AC_PINCAP_VREF_100)
+ return AC_PINCTL_VREF_100;
+ if (pincap & AC_PINCAP_VREF_80)
+ return AC_PINCTL_VREF_80;
+ if (pincap & AC_PINCAP_VREF_50)
+ return AC_PINCTL_VREF_50;
+ if (pincap & AC_PINCAP_VREF_GRD)
+ return AC_PINCTL_VREF_GRD;
+ return 0;
+}
+
static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type)
{
@@ -571,9 +587,12 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_
if (val)
stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
- else
- stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_IN_EN);
-
+ else {
+ unsigned int pinctl = AC_PINCTL_IN_EN;
+ if (io_idx) /* set VREF for mic */
+ pinctl |= stac92xx_get_vref(codec, nid);
+ stac92xx_auto_set_pinctl(codec, nid, pinctl);
+ }
return 1;
}
@@ -767,13 +786,8 @@ static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec, struct auto_pin
return 0;
wid_caps = get_wcaps(codec, pin);
- if (wid_caps & AC_WCAP_UNSOL_CAP) {
- /* Enable unsolicited responses on the HP widget */
- snd_hda_codec_write(codec, pin, 0,
- AC_VERB_SET_UNSOLICITED_ENABLE,
- STAC_UNSOL_ENABLE);
+ if (wid_caps & AC_WCAP_UNSOL_CAP)
spec->hp_detect = 1;
- }
nid = snd_hda_codec_read(codec, pin, 0, AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
for (i = 0; i < cfg->line_outs; i++) {
@@ -896,13 +910,8 @@ static int stac9200_auto_create_hp_ctls(struct hda_codec *codec,
return 0;
wid_caps = get_wcaps(codec, pin);
- if (wid_caps & AC_WCAP_UNSOL_CAP) {
- /* Enable unsolicited responses on the HP widget */
- snd_hda_codec_write(codec, pin, 0,
- AC_VERB_SET_UNSOLICITED_ENABLE,
- STAC_UNSOL_ENABLE);
+ if (wid_caps & AC_WCAP_UNSOL_CAP)
spec->hp_detect = 1;
- }
return 0;
}
@@ -944,6 +953,10 @@ static int stac92xx_init(struct hda_codec *codec)
/* set up pins */
if (spec->hp_detect) {
+ /* Enable unsolicited responses on the HP widget */
+ snd_hda_codec_write(codec, cfg->hp_pin, 0,
+ AC_VERB_SET_UNSOLICITED_ENABLE,
+ STAC_UNSOL_ENABLE);
/* fake event to set up pins */
codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
} else {
@@ -951,9 +964,13 @@ static int stac92xx_init(struct hda_codec *codec)
stac92xx_auto_init_hp_out(codec);
}
for (i = 0; i < AUTO_PIN_LAST; i++) {
- if (cfg->input_pins[i])
- stac92xx_auto_set_pinctl(codec, cfg->input_pins[i],
- AC_PINCTL_IN_EN);
+ hda_nid_t nid = cfg->input_pins[i];
+ if (nid) {
+ unsigned int pinctl = AC_PINCTL_IN_EN;
+ if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC)
+ pinctl |= stac92xx_get_vref(codec, nid);
+ stac92xx_auto_set_pinctl(codec, nid, pinctl);
+ }
}
if (cfg->dig_out_pin)
stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin,
diff --git a/sound/pci/ice1712/aureon.c b/sound/pci/ice1712/aureon.c
index 7e6608b14ab..336dc489aee 100644
--- a/sound/pci/ice1712/aureon.c
+++ b/sound/pci/ice1712/aureon.c
@@ -87,7 +87,151 @@
#define CS8415_C_BUFFER 0x20
#define CS8415_ID 0x7F
-static void aureon_ac97_write(struct snd_ice1712 *ice, unsigned short reg, unsigned short val) {
+/* PCA9554 registers */
+#define PCA9554_DEV 0x40 /* I2C device address */
+#define PCA9554_IN 0x00 /* input port */
+#define PCA9554_OUT 0x01 /* output port */
+#define PCA9554_INVERT 0x02 /* input invert */
+#define PCA9554_DIR 0x03 /* port directions */
+
+/*
+ * Aureon Universe additional controls using PCA9554
+ */
+
+/*
+ * Send data to pca9554
+ */
+static void aureon_pca9554_write(struct snd_ice1712 *ice, unsigned char reg,
+ unsigned char data)
+{
+ unsigned int tmp;
+ int i, j;
+ unsigned char dev = PCA9554_DEV; /* ID 0100000, write */
+ unsigned char val = 0;
+
+ tmp = snd_ice1712_gpio_read(ice);
+
+ snd_ice1712_gpio_set_mask(ice, ~(AUREON_SPI_MOSI|AUREON_SPI_CLK|
+ AUREON_WM_RW|AUREON_WM_CS|
+ AUREON_CS8415_CS));
+ tmp |= AUREON_WM_RW;
+ tmp |= AUREON_CS8415_CS | AUREON_WM_CS; /* disable SPI devices */
+
+ tmp &= ~AUREON_SPI_MOSI;
+ tmp &= ~AUREON_SPI_CLK;
+ snd_ice1712_gpio_write(ice, tmp);
+ udelay(50);
+
+ /*
+ * send i2c stop condition and start condition
+ * to obtain sane state
+ */
+ tmp |= AUREON_SPI_CLK;
+ snd_ice1712_gpio_write(ice, tmp);
+ udelay(50);
+ tmp |= AUREON_SPI_MOSI;
+ snd_ice1712_gpio_write(ice, tmp);
+ udelay(100);
+ tmp &= ~AUREON_SPI_MOSI;
+ snd_ice1712_gpio_write(ice, tmp);
+ udelay(50);
+ tmp &= ~AUREON_SPI_CLK;
+ snd_ice1712_gpio_write(ice, tmp);
+ udelay(100);
+ /*
+ * send device address, command and value,
+ * skipping ack cycles inbetween
+ */
+ for (j = 0; j < 3; j++) {
+ switch(j) {
+ case 0: val = dev; break;
+ case 1: val = reg; break;
+ case 2: val = data; break;
+ }
+ for (i = 7; i >= 0; i--) {
+ tmp &= ~AUREON_SPI_CLK;
+ snd_ice1712_gpio_write(ice, tmp);
+ udelay(40);
+ if (val & (1 << i))
+ tmp |= AUREON_SPI_MOSI;
+ else
+ tmp &= ~AUREON_SPI_MOSI;
+ snd_ice1712_gpio_write(ice, tmp);
+ udelay(40);
+ tmp |= AUREON_SPI_CLK;
+ snd_ice1712_gpio_write(ice, tmp);
+ udelay(40);
+ }
+ tmp &= ~AUREON_SPI_CLK;
+ snd_ice1712_gpio_write(ice, tmp);
+ udelay(40);
+ tmp |= AUREON_SPI_CLK;
+ snd_ice1712_gpio_write(ice, tmp);
+ udelay(40);
+ tmp &= ~AUREON_SPI_CLK;
+ snd_ice1712_gpio_write(ice, tmp);
+ udelay(40);
+ }
+ tmp &= ~AUREON_SPI_CLK;
+ snd_ice1712_gpio_write(ice, tmp);
+ udelay(40);
+ tmp &= ~AUREON_SPI_MOSI;
+ snd_ice1712_gpio_write(ice, tmp);
+ udelay(40);
+ tmp |= AUREON_SPI_CLK;
+ snd_ice1712_gpio_write(ice, tmp);
+ udelay(50);
+ tmp |= AUREON_SPI_MOSI;
+ snd_ice1712_gpio_write(ice, tmp);
+ udelay(100);
+}
+
+static int aureon_universe_inmux_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ char *texts[3] = {"Internal Aux", "Wavetable", "Rear Line-In"};
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 3;
+ if(uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+ uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
+ strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+static int aureon_universe_inmux_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+ ucontrol->value.integer.value[0] = ice->spec.aureon.pca9554_out;
+ return 0;
+}
+
+static int aureon_universe_inmux_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+ unsigned char oval, nval;
+ int change;
+
+ snd_ice1712_save_gpio_status(ice);
+
+ oval = ice->spec.aureon.pca9554_out;
+ nval = ucontrol->value.integer.value[0];
+ if ((change = (oval != nval))) {
+ aureon_pca9554_write(ice, PCA9554_OUT, nval);
+ ice->spec.aureon.pca9554_out = nval;
+ }
+ snd_ice1712_restore_gpio_status(ice);
+
+ return change;
+}
+
+
+static void aureon_ac97_write(struct snd_ice1712 *ice, unsigned short reg,
+ unsigned short val)
+{
unsigned int tmp;
/* Send address to XILINX chip */
@@ -146,7 +290,8 @@ static unsigned short aureon_ac97_read(struct snd_ice1712 *ice, unsigned short r
/*
* Initialize STAC9744 chip
*/
-static int aureon_ac97_init (struct snd_ice1712 *ice) {
+static int aureon_ac97_init (struct snd_ice1712 *ice)
+{
int i;
static unsigned short ac97_defaults[] = {
0x00, 0x9640,
@@ -1598,7 +1743,15 @@ static struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = {
.get = aureon_ac97_vol_get,
.put = aureon_ac97_vol_put,
.private_value = AC97_VIDEO|AUREON_AC97_STEREO
- }
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Aux Source",
+ .info = aureon_universe_inmux_info,
+ .get = aureon_universe_inmux_get,
+ .put = aureon_universe_inmux_put
+ }
+
};
@@ -1856,6 +2009,10 @@ static int __devinit aureon_init(struct snd_ice1712 *ice)
}
snd_ice1712_restore_gpio_status(ice);
+
+ /* initialize PCA9554 pin directions & set default input*/
+ aureon_pca9554_write(ice, PCA9554_DIR, 0x00);
+ aureon_pca9554_write(ice, PCA9554_OUT, 0x00); /* internal AUX */
ice->spec.aureon.master[0] = WM_VOL_MUTE;
ice->spec.aureon.master[1] = WM_VOL_MUTE;
diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c
index b88eeba2f5d..32f8415558a 100644
--- a/sound/pci/ice1712/ice1712.c
+++ b/sound/pci/ice1712/ice1712.c
@@ -2402,7 +2402,7 @@ static int __devinit snd_ice1712_chip_init(struct snd_ice1712 *ice)
if (ice->eeprom.subvendor == ICE1712_SUBDEVICE_DMX6FIRE && !ice->dxr_enable) {
/* Limit active ADCs and DACs to 6; */
/* Note: DXR extension not supported */
- pci_write_config_byte(ice->pci, 0x60, 0x0a);
+ pci_write_config_byte(ice->pci, 0x60, 0x2a);
} else {
pci_write_config_byte(ice->pci, 0x60, ice->eeprom.data[ICE_EEP1_CODEC]);
}
diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h
index f9b22d4a393..053f8e56fd6 100644
--- a/sound/pci/ice1712/ice1712.h
+++ b/sound/pci/ice1712/ice1712.h
@@ -373,6 +373,7 @@ struct snd_ice1712 {
unsigned int cs8415_mux;
unsigned short master[2];
unsigned short vol[8];
+ unsigned char pca9554_out;
} aureon;
/* AC97 register cache for Phase28 */
struct phase28_spec {
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c
index 44393e19092..9c90d901e6b 100644
--- a/sound/pci/maestro3.c
+++ b/sound/pci/maestro3.c
@@ -831,8 +831,8 @@ struct snd_m3 {
struct snd_pcm *pcm;
struct pci_dev *pci;
- struct m3_quirk *quirk;
- struct m3_hv_quirk *hv_quirk;
+ const struct m3_quirk *quirk;
+ const struct m3_hv_quirk *hv_quirk;
int dacs_active;
int timer_users;
@@ -892,7 +892,7 @@ static struct pci_device_id snd_m3_ids[] = {
MODULE_DEVICE_TABLE(pci, snd_m3_ids);
-static struct m3_quirk m3_quirk_list[] = {
+static const struct m3_quirk m3_quirk_list[] = {
/* panasonic CF-28 "toughbook" */
{
.name = "Panasonic CF-28",
@@ -950,7 +950,7 @@ static struct m3_quirk m3_quirk_list[] = {
};
/* These values came from the Windows driver. */
-static struct m3_hv_quirk m3_hv_quirk_list[] = {
+static const struct m3_hv_quirk m3_hv_quirk_list[] = {
/* Allegro chips */
{ 0x125D, 0x1988, 0x0E11, 0x002E, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
{ 0x125D, 0x1988, 0x0E11, 0x0094, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
@@ -1361,7 +1361,7 @@ static void snd_m3_pcm_setup2(struct snd_m3 *chip, struct m3_dma *s,
}
-static struct play_vals {
+static const struct play_vals {
u16 addr, val;
} pv[] = {
{CDATA_LEFT_VOLUME, ARB_VOLUME},
@@ -1428,7 +1428,7 @@ snd_m3_playback_setup(struct snd_m3 *chip, struct m3_dma *s,
/*
* Native record driver
*/
-static struct rec_vals {
+static const struct rec_vals {
u16 addr, val;
} rv[] = {
{CDATA_LEFT_VOLUME, ARB_VOLUME},
@@ -1598,12 +1598,26 @@ static void snd_m3_update_ptr(struct snd_m3 *chip, struct m3_dma *s)
if (! s->running)
return;
- hwptr = snd_m3_get_pointer(chip, s, subs) % s->dma_size;
- diff = (s->dma_size + hwptr - s->hwptr) % s->dma_size;
+ hwptr = snd_m3_get_pointer(chip, s, subs);
+
+ /* try to avoid expensive modulo divisions */
+ if (hwptr >= s->dma_size)
+ hwptr %= s->dma_size;
+
+ diff = s->dma_size + hwptr - s->hwptr;
+ if (diff >= s->dma_size)
+ diff %= s->dma_size;
+
s->hwptr = hwptr;
s->count += diff;
+
if (s->count >= (signed)s->period_size) {
- s->count %= s->period_size;
+
+ if (s->count < 2 * (signed)s->period_size)
+ s->count -= (signed)s->period_size;
+ else
+ s->count %= s->period_size;
+
spin_unlock(&chip->reg_lock);
snd_pcm_period_elapsed(subs);
spin_lock(&chip->reg_lock);
@@ -1942,6 +1956,7 @@ static int snd_m3_ac97_wait(struct snd_m3 *chip)
do {
if (! (snd_m3_inb(chip, 0x30) & 1))
return 0;
+ cpu_relax();
} while (i-- > 0);
snd_printk(KERN_ERR "ac97 serial bus busy\n");
@@ -1953,16 +1968,18 @@ snd_m3_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
{
struct snd_m3 *chip = ac97->private_data;
unsigned long flags;
- unsigned short data;
+ unsigned short data = 0xffff;
if (snd_m3_ac97_wait(chip))
- return 0xffff;
+ goto fail;
spin_lock_irqsave(&chip->ac97_lock, flags);
snd_m3_outb(chip, 0x80 | (reg & 0x7f), CODEC_COMMAND);
if (snd_m3_ac97_wait(chip))
- return 0xffff;
+ goto fail_unlock;
data = snd_m3_inw(chip, CODEC_DATA);
+fail_unlock:
spin_unlock_irqrestore(&chip->ac97_lock, flags);
+fail:
return data;
}
@@ -2121,7 +2138,7 @@ static int __devinit snd_m3_mixer(struct snd_m3 *chip)
* DSP Code images
*/
-static u16 assp_kernel_image[] __devinitdata = {
+static const u16 assp_kernel_image[] __devinitdata = {
0x7980, 0x0030, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x00FB, 0x7980, 0x00DD, 0x7980, 0x03B4,
0x7980, 0x0332, 0x7980, 0x0287, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x03B4,
0x7980, 0x031A, 0x7980, 0x03B4, 0x7980, 0x022F, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x03B4,
@@ -2208,7 +2225,7 @@ static u16 assp_kernel_image[] __devinitdata = {
* Mini sample rate converter code image
* that is to be loaded at 0x400 on the DSP.
*/
-static u16 assp_minisrc_image[] __devinitdata = {
+static const u16 assp_minisrc_image[] __devinitdata = {
0xBF80, 0x101E, 0x906E, 0x006E, 0x8B88, 0x6980, 0xEF88, 0x906F, 0x0D6F, 0x6900, 0xEB08, 0x0412,
0xBC20, 0x696E, 0xB801, 0x906E, 0x7980, 0x0403, 0xB90E, 0x8807, 0xBE43, 0xBF01, 0xBE47, 0xBE41,
@@ -2251,7 +2268,7 @@ static u16 assp_minisrc_image[] __devinitdata = {
*/
#define MINISRC_LPF_LEN 10
-static u16 minisrc_lpf[MINISRC_LPF_LEN] __devinitdata = {
+static const u16 minisrc_lpf[MINISRC_LPF_LEN] __devinitdata = {
0X0743, 0X1104, 0X0A4C, 0XF88D, 0X242C,
0X1023, 0X1AA9, 0X0B60, 0XEFDD, 0X186F
};
@@ -2358,7 +2375,7 @@ static int __devinit snd_m3_assp_client_init(struct snd_m3 *chip, struct m3_dma
*/
/*
- * align instance address to 256 bytes so that it's
+ * align instance address to 256 bytes so that its
* shifted list address is aligned.
* list address = (mem address >> 1) >> 7;
*/
@@ -2647,8 +2664,8 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
{
struct snd_m3 *chip;
int i, err;
- struct m3_quirk *quirk;
- struct m3_hv_quirk *hv_quirk;
+ const struct m3_quirk *quirk;
+ const struct m3_hv_quirk *hv_quirk;
static struct snd_device_ops ops = {
.dev_free = snd_m3_dev_free,
};
@@ -2843,12 +2860,12 @@ snd_m3_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
}
#if 0 /* TODO: not supported yet */
- /* TODO enable midi irq and i/o */
+ /* TODO enable MIDI IRQ and I/O */
err = snd_mpu401_uart_new(chip->card, 0, MPU401_HW_MPU401,
chip->iobase + MPU401_DATA_PORT, 1,
chip->irq, 0, &chip->rmidi);
if (err < 0)
- printk(KERN_WARNING "maestro3: no midi support.\n");
+ printk(KERN_WARNING "maestro3: no MIDI support.\n");
#endif
pci_set_drvdata(pci, card);
diff --git a/sound/pci/pcxhr/pcxhr_core.c b/sound/pci/pcxhr/pcxhr_core.c
index fdc652c6992..c40f5906268 100644
--- a/sound/pci/pcxhr/pcxhr_core.c
+++ b/sound/pci/pcxhr/pcxhr_core.c
@@ -274,12 +274,9 @@ int pcxhr_load_xilinx_binary(struct pcxhr_mgr *mgr, const struct firmware *xilin
/* test first xilinx */
chipsc = PCXHR_INPL(mgr, PCXHR_PLX_CHIPSC);
- if (!second) {
- if (chipsc & PCXHR_CHIPSC_GPI_USERI) {
- snd_printdd("no need to load first xilinx\n");
- return 0; /* first xilinx is already present and cannot be reset */
- }
- } else {
+ /* REV01 cards do not support the PCXHR_CHIPSC_GPI_USERI bit anymore */
+ /* this bit will always be 1; no possibility to test presence of first xilinx */
+ if(second) {
if ((chipsc & PCXHR_CHIPSC_GPI_USERI) == 0) {
snd_printk(KERN_ERR "error loading first xilinx\n");
return -EINVAL;
diff --git a/sound/pci/riptide/Makefile b/sound/pci/riptide/Makefile
new file mode 100644
index 00000000000..dcd2e64e481
--- /dev/null
+++ b/sound/pci/riptide/Makefile
@@ -0,0 +1,3 @@
+snd-riptide-objs := riptide.o
+
+obj-$(CONFIG_SND_RIPTIDE) += snd-riptide.o
diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c
new file mode 100644
index 00000000000..f148ee434a6
--- /dev/null
+++ b/sound/pci/riptide/riptide.c
@@ -0,0 +1,2223 @@
+/*
+ * Driver for the Conexant Riptide Soundchip
+ *
+ * Copyright (c) 2004 Peter Gruber <nokos@gmx.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+/*
+ History:
+ - 02/15/2004 first release
+
+ This Driver is based on the OSS Driver version from Linuxant (riptide-0.6lnxtbeta03111100)
+ credits from the original files:
+
+ MODULE NAME: cnxt_rt.h
+ AUTHOR: K. Lazarev (Transcribed by KNL)
+ HISTORY: Major Revision Date By
+ ----------------------------- -------- -----
+ Created 02/1/2000 KNL
+
+ MODULE NAME: int_mdl.c
+ AUTHOR: Konstantin Lazarev (Transcribed by KNL)
+ HISTORY: Major Revision Date By
+ ----------------------------- -------- -----
+ Created 10/01/99 KNL
+
+ MODULE NAME: riptide.h
+ AUTHOR: O. Druzhinin (Transcribed by OLD)
+ HISTORY: Major Revision Date By
+ ----------------------------- -------- -----
+ Created 10/16/97 OLD
+
+ MODULE NAME: Rp_Cmdif.cpp
+ AUTHOR: O. Druzhinin (Transcribed by OLD)
+ K. Lazarev (Transcribed by KNL)
+ HISTORY: Major Revision Date By
+ ----------------------------- -------- -----
+ Adopted from NT4 driver 6/22/99 OLD
+ Ported to Linux 9/01/99 KNL
+
+ MODULE NAME: rt_hw.c
+ AUTHOR: O. Druzhinin (Transcribed by OLD)
+ C. Lazarev (Transcribed by CNL)
+ HISTORY: Major Revision Date By
+ ----------------------------- -------- -----
+ Created 11/18/97 OLD
+ Hardware functions for RipTide 11/24/97 CNL
+ (ES1) are coded
+ Hardware functions for RipTide 12/24/97 CNL
+ (A0) are coded
+ Hardware functions for RipTide 03/20/98 CNL
+ (A1) are coded
+ Boot loader is included 05/07/98 CNL
+ Redesigned for WDM 07/27/98 CNL
+ Redesigned for Linux 09/01/99 CNL
+
+ MODULE NAME: rt_hw.h
+ AUTHOR: C. Lazarev (Transcribed by CNL)
+ HISTORY: Major Revision Date By
+ ----------------------------- -------- -----
+ Created 11/18/97 CNL
+
+ MODULE NAME: rt_mdl.c
+ AUTHOR: Konstantin Lazarev (Transcribed by KNL)
+ HISTORY: Major Revision Date By
+ ----------------------------- -------- -----
+ Created 10/01/99 KNL
+
+ MODULE NAME: mixer.h
+ AUTHOR: K. Kenney
+ HISTORY: Major Revision Date By
+ ----------------------------- -------- -----
+ Created from MS W95 Sample 11/28/95 KRS
+ RipTide 10/15/97 KRS
+ Adopted for Windows NT driver 01/20/98 CNL
+*/
+
+#include <sound/driver.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/gameport.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <asm/io.h>
+#include <sound/core.h>
+#include <sound/info.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/ac97_codec.h>
+#include <sound/mpu401.h>
+#include <sound/opl3.h>
+#include <sound/initval.h>
+
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+#define SUPPORT_JOYSTICK 1
+#endif
+
+MODULE_AUTHOR("Peter Gruber <nokos@gmx.net>");
+MODULE_DESCRIPTION("riptide");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("{{Conexant,Riptide}}");
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;
+
+#ifdef SUPPORT_JOYSTICK
+static int joystick_port[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS - 1)] = 0x200 };
+#endif
+static int mpu_port[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS - 1)] = 0x330 };
+static int opl3_port[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS - 1)] = 0x388 };
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for Riptide soundcard.");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for Riptide soundcard.");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable Riptide soundcard.");
+#ifdef SUPPORT_JOYSTICK
+module_param_array(joystick_port, int, NULL, 0444);
+MODULE_PARM_DESC(joystick_port, "Joystick port # for Riptide soundcard.");
+#endif
+module_param_array(mpu_port, int, NULL, 0444);
+MODULE_PARM_DESC(mpu_port, "MPU401 port # for Riptide driver.");
+module_param_array(opl3_port, int, NULL, 0444);
+MODULE_PARM_DESC(opl3_port, "OPL3 port # for Riptide driver.");
+
+/*
+ */
+
+#define MPU401_HW_RIPTIDE MPU401_HW_MPU401
+#define OPL3_HW_RIPTIDE OPL3_HW_OPL3
+
+#define PCI_EXT_CapId 0x40
+#define PCI_EXT_NextCapPrt 0x41
+#define PCI_EXT_PWMC 0x42
+#define PCI_EXT_PWSCR 0x44
+#define PCI_EXT_Data00 0x46
+#define PCI_EXT_PMSCR_BSE 0x47
+#define PCI_EXT_SB_Base 0x48
+#define PCI_EXT_FM_Base 0x4a
+#define PCI_EXT_MPU_Base 0x4C
+#define PCI_EXT_Game_Base 0x4E
+#define PCI_EXT_Legacy_Mask 0x50
+#define PCI_EXT_AsicRev 0x52
+#define PCI_EXT_Reserved3 0x53
+
+#define LEGACY_ENABLE_ALL 0x8000 /* legacy device options */
+#define LEGACY_ENABLE_SB 0x4000
+#define LEGACY_ENABLE_FM 0x2000
+#define LEGACY_ENABLE_MPU_INT 0x1000
+#define LEGACY_ENABLE_MPU 0x0800
+#define LEGACY_ENABLE_GAMEPORT 0x0400
+
+#define MAX_WRITE_RETRY 10 /* cmd interface limits */
+#define MAX_ERROR_COUNT 10
+#define CMDIF_TIMEOUT 500000
+#define RESET_TRIES 5
+
+#define READ_PORT_ULONG(p) inl((unsigned long)&(p))
+#define WRITE_PORT_ULONG(p,x) outl(x,(unsigned long)&(p))
+
+#define READ_AUDIO_CONTROL(p) READ_PORT_ULONG(p->audio_control)
+#define WRITE_AUDIO_CONTROL(p,x) WRITE_PORT_ULONG(p->audio_control,x)
+#define UMASK_AUDIO_CONTROL(p,x) WRITE_PORT_ULONG(p->audio_control,READ_PORT_ULONG(p->audio_control)|x)
+#define MASK_AUDIO_CONTROL(p,x) WRITE_PORT_ULONG(p->audio_control,READ_PORT_ULONG(p->audio_control)&x)
+#define READ_AUDIO_STATUS(p) READ_PORT_ULONG(p->audio_status)
+
+#define SET_GRESET(p) UMASK_AUDIO_CONTROL(p,0x0001) /* global reset switch */
+#define UNSET_GRESET(p) MASK_AUDIO_CONTROL(p,~0x0001)
+#define SET_AIE(p) UMASK_AUDIO_CONTROL(p,0x0004) /* interrupt enable */
+#define UNSET_AIE(p) MASK_AUDIO_CONTROL(p,~0x0004)
+#define SET_AIACK(p) UMASK_AUDIO_CONTROL(p,0x0008) /* interrupt acknowledge */
+#define UNSET_AIACKT(p) MASKAUDIO_CONTROL(p,~0x0008)
+#define SET_ECMDAE(p) UMASK_AUDIO_CONTROL(p,0x0010)
+#define UNSET_ECMDAE(p) MASK_AUDIO_CONTROL(p,~0x0010)
+#define SET_ECMDBE(p) UMASK_AUDIO_CONTROL(p,0x0020)
+#define UNSET_ECMDBE(p) MASK_AUDIO_CONTROL(p,~0x0020)
+#define SET_EDATAF(p) UMASK_AUDIO_CONTROL(p,0x0040)
+#define UNSET_EDATAF(p) MASK_AUDIO_CONTROL(p,~0x0040)
+#define SET_EDATBF(p) UMASK_AUDIO_CONTROL(p,0x0080)
+#define UNSET_EDATBF(p) MASK_AUDIO_CONTROL(p,~0x0080)
+#define SET_ESBIRQON(p) UMASK_AUDIO_CONTROL(p,0x0100)
+#define UNSET_ESBIRQON(p) MASK_AUDIO_CONTROL(p,~0x0100)
+#define SET_EMPUIRQ(p) UMASK_AUDIO_CONTROL(p,0x0200)
+#define UNSET_EMPUIRQ(p) MASK_AUDIO_CONTROL(p,~0x0200)
+#define IS_CMDE(a) (READ_PORT_ULONG(a->stat)&0x1) /* cmd empty */
+#define IS_DATF(a) (READ_PORT_ULONG(a->stat)&0x2) /* data filled */
+#define IS_READY(p) (READ_AUDIO_STATUS(p)&0x0001)
+#define IS_DLREADY(p) (READ_AUDIO_STATUS(p)&0x0002)
+#define IS_DLERR(p) (READ_AUDIO_STATUS(p)&0x0004)
+#define IS_GERR(p) (READ_AUDIO_STATUS(p)&0x0008) /* error ! */
+#define IS_CMDAEIRQ(p) (READ_AUDIO_STATUS(p)&0x0010)
+#define IS_CMDBEIRQ(p) (READ_AUDIO_STATUS(p)&0x0020)
+#define IS_DATAFIRQ(p) (READ_AUDIO_STATUS(p)&0x0040)
+#define IS_DATBFIRQ(p) (READ_AUDIO_STATUS(p)&0x0080)
+#define IS_EOBIRQ(p) (READ_AUDIO_STATUS(p)&0x0100) /* interrupt status */
+#define IS_EOSIRQ(p) (READ_AUDIO_STATUS(p)&0x0200)
+#define IS_EOCIRQ(p) (READ_AUDIO_STATUS(p)&0x0400)
+#define IS_UNSLIRQ(p) (READ_AUDIO_STATUS(p)&0x0800)
+#define IS_SBIRQ(p) (READ_AUDIO_STATUS(p)&0x1000)
+#define IS_MPUIRQ(p) (READ_AUDIO_STATUS(p)&0x2000)
+
+#define RESP 0x00000001 /* command flags */
+#define PARM 0x00000002
+#define CMDA 0x00000004
+#define CMDB 0x00000008
+#define NILL 0x00000000
+
+#define LONG0(a) ((u32)a) /* shifts and masks */
+#define BYTE0(a) (LONG0(a)&0xff)
+#define BYTE1(a) (BYTE0(a)<<8)
+#define BYTE2(a) (BYTE0(a)<<16)
+#define BYTE3(a) (BYTE0(a)<<24)
+#define WORD0(a) (LONG0(a)&0xffff)
+#define WORD1(a) (WORD0(a)<<8)
+#define WORD2(a) (WORD0(a)<<16)
+#define TRINIB0(a) (LONG0(a)&0xffffff)
+#define TRINIB1(a) (TRINIB0(a)<<8)
+
+#define RET(a) ((union cmdret *)(a))
+
+#define SEND_GETV(p,b) sendcmd(p,RESP,GETV,0,RET(b)) /* get version */
+#define SEND_GETC(p,b,c) sendcmd(p,PARM|RESP,GETC,c,RET(b))
+#define SEND_GUNS(p,b) sendcmd(p,RESP,GUNS,0,RET(b))
+#define SEND_SCID(p,b) sendcmd(p,RESP,SCID,0,RET(b))
+#define SEND_RMEM(p,b,c,d) sendcmd(p,PARM|RESP,RMEM|BYTE1(b),LONG0(c),RET(d)) /* memory access for firmware write */
+#define SEND_SMEM(p,b,c) sendcmd(p,PARM,SMEM|BYTE1(b),LONG0(c),RET(0)) /* memory access for firmware write */
+#define SEND_WMEM(p,b,c) sendcmd(p,PARM,WMEM|BYTE1(b),LONG0(c),RET(0)) /* memory access for firmware write */
+#define SEND_SDTM(p,b,c) sendcmd(p,PARM|RESP,SDTM|TRINIB1(b),0,RET(c)) /* memory access for firmware write */
+#define SEND_GOTO(p,b) sendcmd(p,PARM,GOTO,LONG0(b),RET(0)) /* memory access for firmware write */
+#define SEND_SETDPLL(p) sendcmd(p,0,ARM_SETDPLL,0,RET(0))
+#define SEND_SSTR(p,b,c) sendcmd(p,PARM,SSTR|BYTE3(b),LONG0(c),RET(0)) /* start stream */
+#define SEND_PSTR(p,b) sendcmd(p,PARM,PSTR,BYTE3(b),RET(0)) /* pause stream */
+#define SEND_KSTR(p,b) sendcmd(p,PARM,KSTR,BYTE3(b),RET(0)) /* stop stream */
+#define SEND_KDMA(p) sendcmd(p,0,KDMA,0,RET(0)) /* stop all dma */
+#define SEND_GPOS(p,b,c,d) sendcmd(p,PARM|RESP,GPOS,BYTE3(c)|BYTE2(b),RET(d)) /* get position in dma */
+#define SEND_SETF(p,b,c,d,e,f,g) sendcmd(p,PARM,SETF|WORD1(b)|BYTE3(c),d|BYTE1(e)|BYTE2(f)|BYTE3(g),RET(0)) /* set sample format at mixer */
+#define SEND_GSTS(p,b,c,d) sendcmd(p,PARM|RESP,GSTS,BYTE3(c)|BYTE2(b),RET(d))
+#define SEND_NGPOS(p,b,c,d) sendcmd(p,PARM|RESP,NGPOS,BYTE3(c)|BYTE2(b),RET(d))
+#define SEND_PSEL(p,b,c) sendcmd(p,PARM,PSEL,BYTE2(b)|BYTE3(c),RET(0)) /* activate lbus path */
+#define SEND_PCLR(p,b,c) sendcmd(p,PARM,PCLR,BYTE2(b)|BYTE3(c),RET(0)) /* deactivate lbus path */
+#define SEND_PLST(p,b) sendcmd(p,PARM,PLST,BYTE3(b),RET(0))
+#define SEND_RSSV(p,b,c,d) sendcmd(p,PARM|RESP,RSSV,BYTE2(b)|BYTE3(c),RET(d))
+#define SEND_LSEL(p,b,c,d,e,f,g,h) sendcmd(p,PARM,LSEL|BYTE1(b)|BYTE2(c)|BYTE3(d),BYTE0(e)|BYTE1(f)|BYTE2(g)|BYTE3(h),RET(0)) /* select paths for internal connections */
+#define SEND_SSRC(p,b,c,d,e) sendcmd(p,PARM,SSRC|BYTE1(b)|WORD2(c),WORD0(d)|WORD2(e),RET(0)) /* configure source */
+#define SEND_SLST(p,b) sendcmd(p,PARM,SLST,BYTE3(b),RET(0))
+#define SEND_RSRC(p,b,c) sendcmd(p,RESP,RSRC|BYTE1(b),0,RET(c)) /* read source config */
+#define SEND_SSRB(p,b,c) sendcmd(p,PARM,SSRB|BYTE1(b),WORD2(c),RET(0))
+#define SEND_SDGV(p,b,c,d,e) sendcmd(p,PARM,SDGV|BYTE2(b)|BYTE3(c),WORD0(d)|WORD2(e),RET(0)) /* set digital mixer */
+#define SEND_RDGV(p,b,c,d) sendcmd(p,PARM|RESP,RDGV|BYTE2(b)|BYTE3(c),0,RET(d)) /* read digital mixer */
+#define SEND_DLST(p,b) sendcmd(p,PARM,DLST,BYTE3(b),RET(0))
+#define SEND_SACR(p,b,c) sendcmd(p,PARM,SACR,WORD0(b)|WORD2(c),RET(0)) /* set AC97 register */
+#define SEND_RACR(p,b,c) sendcmd(p,PARM|RESP,RACR,WORD2(b),RET(c)) /* get AC97 register */
+#define SEND_ALST(p,b) sendcmd(p,PARM,ALST,BYTE3(b),RET(0))
+#define SEND_TXAC(p,b,c,d,e,f) sendcmd(p,PARM,TXAC|BYTE1(b)|WORD2(c),WORD0(d)|BYTE2(e)|BYTE3(f),RET(0))
+#define SEND_RXAC(p,b,c,d) sendcmd(p,PARM|RESP,RXAC,BYTE2(b)|BYTE3(c),RET(d))
+#define SEND_SI2S(p,b) sendcmd(p,PARM,SI2S,WORD2(b),RET(0))
+
+#define EOB_STATUS 0x80000000 /* status flags : block boundary */
+#define EOS_STATUS 0x40000000 /* : stoppped */
+#define EOC_STATUS 0x20000000 /* : stream end */
+#define ERR_STATUS 0x10000000
+#define EMPTY_STATUS 0x08000000
+
+#define IEOB_ENABLE 0x1 /* enable interrupts for status notification above */
+#define IEOS_ENABLE 0x2
+#define IEOC_ENABLE 0x4
+#define RDONCE 0x8
+#define DESC_MAX_MASK 0xff
+
+#define ST_PLAY 0x1 /* stream states */
+#define ST_STOP 0x2
+#define ST_PAUSE 0x4
+
+#define I2S_INTDEC 3 /* config for I2S link */
+#define I2S_MERGER 0
+#define I2S_SPLITTER 0
+#define I2S_MIXER 7
+#define I2S_RATE 44100
+
+#define MODEM_INTDEC 4 /* config for modem link */
+#define MODEM_MERGER 3
+#define MODEM_SPLITTER 0
+#define MODEM_MIXER 11
+
+#define FM_INTDEC 3 /* config for FM/OPL3 link */
+#define FM_MERGER 0
+#define FM_SPLITTER 0
+#define FM_MIXER 9
+
+#define SPLIT_PATH 0x80 /* path splitting flag */
+
+enum FIRMWARE {
+ DATA_REC = 0, EXT_END_OF_FILE, EXT_SEG_ADDR_REC, EXT_GOTO_CMD_REC,
+ EXT_LIN_ADDR_REC,
+};
+
+enum CMDS {
+ GETV = 0x00, GETC, GUNS, SCID, RMEM =
+ 0x10, SMEM, WMEM, SDTM, GOTO, SSTR =
+ 0x20, PSTR, KSTR, KDMA, GPOS, SETF, GSTS, NGPOS, PSEL =
+ 0x30, PCLR, PLST, RSSV, LSEL, SSRC = 0x40, SLST, RSRC, SSRB, SDGV =
+ 0x50, RDGV, DLST, SACR = 0x60, RACR, ALST, TXAC, RXAC, SI2S =
+ 0x70, ARM_SETDPLL = 0x72,
+};
+
+enum E1SOURCE {
+ ARM2LBUS_FIFO0 = 0, ARM2LBUS_FIFO1, ARM2LBUS_FIFO2, ARM2LBUS_FIFO3,
+ ARM2LBUS_FIFO4, ARM2LBUS_FIFO5, ARM2LBUS_FIFO6, ARM2LBUS_FIFO7,
+ ARM2LBUS_FIFO8, ARM2LBUS_FIFO9, ARM2LBUS_FIFO10, ARM2LBUS_FIFO11,
+ ARM2LBUS_FIFO12, ARM2LBUS_FIFO13, ARM2LBUS_FIFO14, ARM2LBUS_FIFO15,
+ INTER0_OUT, INTER1_OUT, INTER2_OUT, INTER3_OUT, INTER4_OUT,
+ INTERM0_OUT, INTERM1_OUT, INTERM2_OUT, INTERM3_OUT, INTERM4_OUT,
+ INTERM5_OUT, INTERM6_OUT, DECIMM0_OUT, DECIMM1_OUT, DECIMM2_OUT,
+ DECIMM3_OUT, DECIM0_OUT, SR3_4_OUT, OPL3_SAMPLE, ASRC0, ASRC1,
+ ACLNK2PADC, ACLNK2MODEM0RX, ACLNK2MIC, ACLNK2MODEM1RX, ACLNK2HNDMIC,
+ DIGITAL_MIXER_OUT0, GAINFUNC0_OUT, GAINFUNC1_OUT, GAINFUNC2_OUT,
+ GAINFUNC3_OUT, GAINFUNC4_OUT, SOFTMODEMTX, SPLITTER0_OUTL,
+ SPLITTER0_OUTR, SPLITTER1_OUTL, SPLITTER1_OUTR, SPLITTER2_OUTL,
+ SPLITTER2_OUTR, SPLITTER3_OUTL, SPLITTER3_OUTR, MERGER0_OUT,
+ MERGER1_OUT, MERGER2_OUT, MERGER3_OUT, ARM2LBUS_FIFO_DIRECT, NO_OUT
+};
+
+enum E2SINK {
+ LBUS2ARM_FIFO0 = 0, LBUS2ARM_FIFO1, LBUS2ARM_FIFO2, LBUS2ARM_FIFO3,
+ LBUS2ARM_FIFO4, LBUS2ARM_FIFO5, LBUS2ARM_FIFO6, LBUS2ARM_FIFO7,
+ INTER0_IN, INTER1_IN, INTER2_IN, INTER3_IN, INTER4_IN, INTERM0_IN,
+ INTERM1_IN, INTERM2_IN, INTERM3_IN, INTERM4_IN, INTERM5_IN, INTERM6_IN,
+ DECIMM0_IN, DECIMM1_IN, DECIMM2_IN, DECIMM3_IN, DECIM0_IN, SR3_4_IN,
+ PDAC2ACLNK, MODEM0TX2ACLNK, MODEM1TX2ACLNK, HNDSPK2ACLNK,
+ DIGITAL_MIXER_IN0, DIGITAL_MIXER_IN1, DIGITAL_MIXER_IN2,
+ DIGITAL_MIXER_IN3, DIGITAL_MIXER_IN4, DIGITAL_MIXER_IN5,
+ DIGITAL_MIXER_IN6, DIGITAL_MIXER_IN7, DIGITAL_MIXER_IN8,
+ DIGITAL_MIXER_IN9, DIGITAL_MIXER_IN10, DIGITAL_MIXER_IN11,
+ GAINFUNC0_IN, GAINFUNC1_IN, GAINFUNC2_IN, GAINFUNC3_IN, GAINFUNC4_IN,
+ SOFTMODEMRX, SPLITTER0_IN, SPLITTER1_IN, SPLITTER2_IN, SPLITTER3_IN,
+ MERGER0_INL, MERGER0_INR, MERGER1_INL, MERGER1_INR, MERGER2_INL,
+ MERGER2_INR, MERGER3_INL, MERGER3_INR, E2SINK_MAX
+};
+
+enum LBUS_SINK {
+ LS_SRC_INTERPOLATOR = 0, LS_SRC_INTERPOLATORM, LS_SRC_DECIMATOR,
+ LS_SRC_DECIMATORM, LS_MIXER_IN, LS_MIXER_GAIN_FUNCTION,
+ LS_SRC_SPLITTER, LS_SRC_MERGER, LS_NONE1, LS_NONE2,
+};
+
+enum RT_CHANNEL_IDS {
+ M0TX = 0, M1TX, TAMTX, HSSPKR, PDAC, DSNDTX0, DSNDTX1, DSNDTX2,
+ DSNDTX3, DSNDTX4, DSNDTX5, DSNDTX6, DSNDTX7, WVSTRTX, COP3DTX, SPARE,
+ M0RX, HSMIC, M1RX, CLEANRX, MICADC, PADC, COPRX1, COPRX2,
+ CHANNEL_ID_COUNTER
+};
+
+enum { SB_CMD = 0, MODEM_CMD, I2S_CMD0, I2S_CMD1, FM_CMD, MAX_CMD };
+
+struct lbuspath {
+ unsigned char *noconv;
+ unsigned char *stereo;
+ unsigned char *mono;
+};
+
+struct cmdport {
+ u32 data1; /* cmd,param */
+ u32 data2; /* param */
+ u32 stat; /* status */
+ u32 pad[5];
+};
+
+struct riptideport {
+ u32 audio_control; /* status registers */
+ u32 audio_status;
+ u32 pad[2];
+ struct cmdport port[2]; /* command ports */
+};
+
+struct cmdif {
+ struct riptideport *hwport;
+ spinlock_t lock;
+ unsigned int cmdcnt; /* cmd statistics */
+ unsigned int cmdtime;
+ unsigned int cmdtimemax;
+ unsigned int cmdtimemin;
+ unsigned int errcnt;
+ int is_reset;
+};
+
+struct riptide_firmware {
+ u16 ASIC;
+ u16 CODEC;
+ u16 AUXDSP;
+ u16 PROG;
+};
+
+union cmdret {
+ u8 retbytes[8];
+ u16 retwords[4];
+ u32 retlongs[2];
+};
+
+union firmware_version {
+ union cmdret ret;
+ struct riptide_firmware firmware;
+};
+
+#define get_pcmhwdev(substream) (struct pcmhw *)(substream->runtime->private_data)
+
+#define PLAYBACK_SUBSTREAMS 3
+struct snd_riptide {
+ struct snd_card *card;
+ struct pci_dev *pci;
+ const struct firmware *fw_entry;
+
+ struct cmdif *cif;
+
+ struct snd_pcm *pcm;
+ struct snd_pcm *pcm_i2s;
+ struct snd_rawmidi *rmidi;
+ struct snd_opl3 *opl3;
+ struct snd_ac97 *ac97;
+ struct snd_ac97_bus *ac97_bus;
+
+ struct snd_pcm_substream *playback_substream[PLAYBACK_SUBSTREAMS];
+ struct snd_pcm_substream *capture_substream;
+
+ int openstreams;
+
+ int irq;
+ unsigned long port;
+ unsigned short mpuaddr;
+ unsigned short opladdr;
+#ifdef SUPPORT_JOYSTICK
+ unsigned short gameaddr;
+#endif
+ struct resource *res_port;
+
+ unsigned short device_id;
+
+ union firmware_version firmware;
+
+ spinlock_t lock;
+ struct tasklet_struct riptide_tq;
+ struct snd_info_entry *proc_entry;
+
+ unsigned long received_irqs;
+ unsigned long handled_irqs;
+#ifdef CONFIG_PM
+ int in_suspend;
+#endif
+};
+
+struct sgd { /* scatter gather desriptor */
+ u32 dwNextLink;
+ u32 dwSegPtrPhys;
+ u32 dwSegLen;
+ u32 dwStat_Ctl;
+};
+
+struct pcmhw { /* pcm descriptor */
+ struct lbuspath paths;
+ unsigned char *lbuspath;
+ unsigned char source;
+ unsigned char intdec[2];
+ unsigned char mixer;
+ unsigned char id;
+ unsigned char state;
+ unsigned int rate;
+ unsigned int channels;
+ snd_pcm_format_t format;
+ struct snd_dma_buffer sgdlist;
+ struct sgd *sgdbuf;
+ unsigned int size;
+ unsigned int pages;
+ unsigned int oldpos;
+ unsigned int pointer;
+};
+
+#define CMDRET_ZERO (union cmdret){{(u32)0, (u32) 0}}
+
+static int sendcmd(struct cmdif *cif, u32 flags, u32 cmd, u32 parm,
+ union cmdret *ret);
+static int getsourcesink(struct cmdif *cif, unsigned char source,
+ unsigned char sink, unsigned char *a,
+ unsigned char *b);
+static int snd_riptide_initialize(struct snd_riptide *chip);
+static int riptide_reset(struct cmdif *cif, struct snd_riptide *chip);
+
+/*
+ */
+
+static struct pci_device_id snd_riptide_ids[] = {
+ {
+ .vendor = 0x127a,.device = 0x4310,
+ .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID,
+ },
+ {
+ .vendor = 0x127a,.device = 0x4320,
+ .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID,
+ },
+ {
+ .vendor = 0x127a,.device = 0x4330,
+ .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID,
+ },
+ {
+ .vendor = 0x127a,.device = 0x4340,
+ .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID,
+ },
+ {0,},
+};
+
+#ifdef SUPPORT_JOYSTICK
+static struct pci_device_id snd_riptide_joystick_ids[] = {
+ {
+ .vendor = 0x127a,.device = 0x4312,
+ .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID,
+ },
+ {
+ .vendor = 0x127a,.device = 0x4322,
+ .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID,
+ },
+ {.vendor = 0x127a,.device = 0x4332,
+ .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID,
+ },
+ {.vendor = 0x127a,.device = 0x4342,
+ .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID,
+ },
+ {0,},
+};
+#endif
+
+MODULE_DEVICE_TABLE(pci, snd_riptide_ids);
+
+/*
+ */
+
+static unsigned char lbusin2out[E2SINK_MAX + 1][2] = {
+ {NO_OUT, LS_NONE1}, {NO_OUT, LS_NONE2}, {NO_OUT, LS_NONE1}, {NO_OUT,
+ LS_NONE2},
+ {NO_OUT, LS_NONE1}, {NO_OUT, LS_NONE2}, {NO_OUT, LS_NONE1}, {NO_OUT,
+ LS_NONE2},
+ {INTER0_OUT, LS_SRC_INTERPOLATOR}, {INTER1_OUT, LS_SRC_INTERPOLATOR},
+ {INTER2_OUT, LS_SRC_INTERPOLATOR}, {INTER3_OUT, LS_SRC_INTERPOLATOR},
+ {INTER4_OUT, LS_SRC_INTERPOLATOR}, {INTERM0_OUT, LS_SRC_INTERPOLATORM},
+ {INTERM1_OUT, LS_SRC_INTERPOLATORM}, {INTERM2_OUT,
+ LS_SRC_INTERPOLATORM},
+ {INTERM3_OUT, LS_SRC_INTERPOLATORM}, {INTERM4_OUT,
+ LS_SRC_INTERPOLATORM},
+ {INTERM5_OUT, LS_SRC_INTERPOLATORM}, {INTERM6_OUT,
+ LS_SRC_INTERPOLATORM},
+ {DECIMM0_OUT, LS_SRC_DECIMATORM}, {DECIMM1_OUT, LS_SRC_DECIMATORM},
+ {DECIMM2_OUT, LS_SRC_DECIMATORM}, {DECIMM3_OUT, LS_SRC_DECIMATORM},
+ {DECIM0_OUT, LS_SRC_DECIMATOR}, {SR3_4_OUT, LS_NONE1}, {NO_OUT,
+ LS_NONE2},
+ {NO_OUT, LS_NONE1}, {NO_OUT, LS_NONE2}, {NO_OUT, LS_NONE1},
+ {DIGITAL_MIXER_OUT0, LS_MIXER_IN}, {DIGITAL_MIXER_OUT0, LS_MIXER_IN},
+ {DIGITAL_MIXER_OUT0, LS_MIXER_IN}, {DIGITAL_MIXER_OUT0, LS_MIXER_IN},
+ {DIGITAL_MIXER_OUT0, LS_MIXER_IN}, {DIGITAL_MIXER_OUT0, LS_MIXER_IN},
+ {DIGITAL_MIXER_OUT0, LS_MIXER_IN}, {DIGITAL_MIXER_OUT0, LS_MIXER_IN},
+ {DIGITAL_MIXER_OUT0, LS_MIXER_IN}, {DIGITAL_MIXER_OUT0, LS_MIXER_IN},
+ {DIGITAL_MIXER_OUT0, LS_MIXER_IN}, {DIGITAL_MIXER_OUT0, LS_MIXER_IN},
+ {GAINFUNC0_OUT, LS_MIXER_GAIN_FUNCTION}, {GAINFUNC1_OUT,
+ LS_MIXER_GAIN_FUNCTION},
+ {GAINFUNC2_OUT, LS_MIXER_GAIN_FUNCTION}, {GAINFUNC3_OUT,
+ LS_MIXER_GAIN_FUNCTION},
+ {GAINFUNC4_OUT, LS_MIXER_GAIN_FUNCTION}, {SOFTMODEMTX, LS_NONE1},
+ {SPLITTER0_OUTL, LS_SRC_SPLITTER}, {SPLITTER1_OUTL, LS_SRC_SPLITTER},
+ {SPLITTER2_OUTL, LS_SRC_SPLITTER}, {SPLITTER3_OUTL, LS_SRC_SPLITTER},
+ {MERGER0_OUT, LS_SRC_MERGER}, {MERGER0_OUT, LS_SRC_MERGER},
+ {MERGER1_OUT, LS_SRC_MERGER},
+ {MERGER1_OUT, LS_SRC_MERGER}, {MERGER2_OUT, LS_SRC_MERGER},
+ {MERGER2_OUT, LS_SRC_MERGER},
+ {MERGER3_OUT, LS_SRC_MERGER}, {MERGER3_OUT, LS_SRC_MERGER}, {NO_OUT,
+ LS_NONE2},
+};
+
+static unsigned char lbus_play_opl3[] = {
+ DIGITAL_MIXER_IN0 + FM_MIXER, 0xff
+};
+static unsigned char lbus_play_modem[] = {
+ DIGITAL_MIXER_IN0 + MODEM_MIXER, 0xff
+};
+static unsigned char lbus_play_i2s[] = {
+ INTER0_IN + I2S_INTDEC, DIGITAL_MIXER_IN0 + I2S_MIXER, 0xff
+};
+static unsigned char lbus_play_out[] = {
+ PDAC2ACLNK, 0xff
+};
+static unsigned char lbus_play_outhp[] = {
+ HNDSPK2ACLNK, 0xff
+};
+static unsigned char lbus_play_noconv1[] = {
+ DIGITAL_MIXER_IN0, 0xff
+};
+static unsigned char lbus_play_stereo1[] = {
+ INTER0_IN, DIGITAL_MIXER_IN0, 0xff
+};
+static unsigned char lbus_play_mono1[] = {
+ INTERM0_IN, DIGITAL_MIXER_IN0, 0xff
+};
+static unsigned char lbus_play_noconv2[] = {
+ DIGITAL_MIXER_IN1, 0xff
+};
+static unsigned char lbus_play_stereo2[] = {
+ INTER1_IN, DIGITAL_MIXER_IN1, 0xff
+};
+static unsigned char lbus_play_mono2[] = {
+ INTERM1_IN, DIGITAL_MIXER_IN1, 0xff
+};
+static unsigned char lbus_play_noconv3[] = {
+ DIGITAL_MIXER_IN2, 0xff
+};
+static unsigned char lbus_play_stereo3[] = {
+ INTER2_IN, DIGITAL_MIXER_IN2, 0xff
+};
+static unsigned char lbus_play_mono3[] = {
+ INTERM2_IN, DIGITAL_MIXER_IN2, 0xff
+};
+static unsigned char lbus_rec_noconv1[] = {
+ LBUS2ARM_FIFO5, 0xff
+};
+static unsigned char lbus_rec_stereo1[] = {
+ DECIM0_IN, LBUS2ARM_FIFO5, 0xff
+};
+static unsigned char lbus_rec_mono1[] = {
+ DECIMM3_IN, LBUS2ARM_FIFO5, 0xff
+};
+
+static unsigned char play_ids[] = { 4, 1, 2, };
+static unsigned char play_sources[] = {
+ ARM2LBUS_FIFO4, ARM2LBUS_FIFO1, ARM2LBUS_FIFO2,
+};
+static struct lbuspath lbus_play_paths[] = {
+ {
+ .noconv = lbus_play_noconv1,
+ .stereo = lbus_play_stereo1,
+ .mono = lbus_play_mono1,
+ },
+ {
+ .noconv = lbus_play_noconv2,
+ .stereo = lbus_play_stereo2,
+ .mono = lbus_play_mono2,
+ },
+ {
+ .noconv = lbus_play_noconv3,
+ .stereo = lbus_play_stereo3,
+ .mono = lbus_play_mono3,
+ },
+};
+static struct lbuspath lbus_rec_path = {
+ .noconv = lbus_rec_noconv1,
+ .stereo = lbus_rec_stereo1,
+ .mono = lbus_rec_mono1,
+};
+
+#define FIRMWARE_VERSIONS 1
+static union firmware_version firmware_versions[] = {
+ {
+ .firmware.ASIC = 3,.firmware.CODEC = 2,
+ .firmware.AUXDSP = 3,.firmware.PROG = 773,
+ },
+};
+
+static u32 atoh(unsigned char *in, unsigned int len)
+{
+ u32 sum = 0;
+ unsigned int mult = 1;
+ unsigned char c;
+
+ while (len) {
+ c = in[len - 1];
+ if ((c >= '0') && (c <= '9'))
+ sum += mult * (c - '0');
+ else if ((c >= 'A') && (c <= 'F'))
+ sum += mult * (c - ('A' - 10));
+ else if ((c >= 'a') && (c <= 'f'))
+ sum += mult * (c - ('a' - 10));
+ mult *= 16;
+ --len;
+ }
+ return sum;
+}
+
+static int senddata(struct cmdif *cif, unsigned char *in, u32 offset)
+{
+ u32 addr;
+ u32 data;
+ u32 i;
+ unsigned char *p;
+
+ i = atoh(&in[1], 2);
+ addr = offset + atoh(&in[3], 4);
+ if (SEND_SMEM(cif, 0, addr) != 0)
+ return -EACCES;
+ p = in + 9;
+ while (i) {
+ data = atoh(p, 8);
+ if (SEND_WMEM(cif, 2,
+ ((data & 0x0f0f0f0f) << 4) | ((data & 0xf0f0f0f0)
+ >> 4)))
+ return -EACCES;
+ i -= 4;
+ p += 8;
+ }
+ return 0;
+}
+
+static int loadfirmware(struct cmdif *cif, unsigned char *img,
+ unsigned int size)
+{
+ unsigned char *in;
+ u32 laddr, saddr, t, val;
+ int err = 0;
+
+ laddr = saddr = 0;
+ while (size > 0 && err == 0) {
+ in = img;
+ if (in[0] == ':') {
+ t = atoh(&in[7], 2);
+ switch (t) {
+ case DATA_REC:
+ err = senddata(cif, in, laddr + saddr);
+ break;
+ case EXT_SEG_ADDR_REC:
+ saddr = atoh(&in[9], 4) << 4;
+ break;
+ case EXT_LIN_ADDR_REC:
+ laddr = atoh(&in[9], 4) << 16;
+ break;
+ case EXT_GOTO_CMD_REC:
+ val = atoh(&in[9], 8);
+ if (SEND_GOTO(cif, val) != 0)
+ err = -EACCES;
+ break;
+ case EXT_END_OF_FILE:
+ size = 0;
+ break;
+ default:
+ break;
+ }
+ while (size > 0) {
+ size--;
+ if (*img++ == '\n')
+ break;
+ }
+ }
+ }
+ snd_printdd("load firmware return %d\n", err);
+ return err;
+}
+
+static void
+alloclbuspath(struct cmdif *cif, unsigned char source,
+ unsigned char *path, unsigned char *mixer, unsigned char *s)
+{
+ while (*path != 0xff) {
+ unsigned char sink, type;
+
+ sink = *path & (~SPLIT_PATH);
+ if (sink != E2SINK_MAX) {
+ snd_printdd("alloc path 0x%x->0x%x\n", source, sink);
+ SEND_PSEL(cif, source, sink);
+ source = lbusin2out[sink][0];
+ type = lbusin2out[sink][1];
+ if (type == LS_MIXER_IN) {
+ if (mixer)
+ *mixer = sink - DIGITAL_MIXER_IN0;
+ }
+ if (type == LS_SRC_DECIMATORM ||
+ type == LS_SRC_DECIMATOR ||
+ type == LS_SRC_INTERPOLATORM ||
+ type == LS_SRC_INTERPOLATOR) {
+ if (s) {
+ if (s[0] != 0xff)
+ s[1] = sink;
+ else
+ s[0] = sink;
+ }
+ }
+ }
+ if (*path++ & SPLIT_PATH) {
+ unsigned char *npath = path;
+
+ while (*npath != 0xff)
+ npath++;
+ alloclbuspath(cif, source + 1, ++npath, mixer, s);
+ }
+ }
+}
+
+static void
+freelbuspath(struct cmdif *cif, unsigned char source, unsigned char *path)
+{
+ while (*path != 0xff) {
+ unsigned char sink;
+
+ sink = *path & (~SPLIT_PATH);
+ if (sink != E2SINK_MAX) {
+ snd_printdd("free path 0x%x->0x%x\n", source, sink);
+ SEND_PCLR(cif, source, sink);
+ source = lbusin2out[sink][0];
+ }
+ if (*path++ & SPLIT_PATH) {
+ unsigned char *npath = path;
+
+ while (*npath != 0xff)
+ npath++;
+ freelbuspath(cif, source + 1, ++npath);
+ }
+ }
+}
+
+static int writearm(struct cmdif *cif, u32 addr, u32 data, u32 mask)
+{
+ union cmdret rptr = CMDRET_ZERO;
+ unsigned int i = MAX_WRITE_RETRY;
+ int flag = 1;
+
+ SEND_RMEM(cif, 0x02, addr, &rptr);
+ rptr.retlongs[0] &= (~mask);
+
+ while (--i) {
+ SEND_SMEM(cif, 0x01, addr);
+ SEND_WMEM(cif, 0x02, (rptr.retlongs[0] | data));
+ SEND_RMEM(cif, 0x02, addr, &rptr);
+ if ((rptr.retlongs[0] & data) == data) {
+ flag = 0;
+ break;
+ } else
+ rptr.retlongs[0] &= ~mask;
+ }
+ snd_printdd("send arm 0x%x 0x%x 0x%x return %d\n", addr, data, mask,
+ flag);
+ return flag;
+}
+
+static int sendcmd(struct cmdif *cif, u32 flags, u32 cmd, u32 parm,
+ union cmdret *ret)
+{
+ int i, j;
+ int err;
+ unsigned int time = 0;
+ unsigned long irqflags;
+ struct riptideport *hwport;
+ struct cmdport *cmdport = NULL;
+
+ snd_assert(cif, return -EINVAL);
+
+ hwport = cif->hwport;
+ if (cif->errcnt > MAX_ERROR_COUNT) {
+ if (cif->is_reset) {
+ snd_printk(KERN_ERR
+ "Riptide: Too many failed cmds, reinitializing\n");
+ if (riptide_reset(cif, NULL) == 0) {
+ cif->errcnt = 0;
+ return -EIO;
+ }
+ }
+ snd_printk(KERN_ERR "Riptide: Initialization failed.\n");
+ return -EINVAL;
+ }
+ if (ret) {
+ ret->retlongs[0] = 0;
+ ret->retlongs[1] = 0;
+ }
+ i = 0;
+ spin_lock_irqsave(&cif->lock, irqflags);
+ while (i++ < CMDIF_TIMEOUT && !IS_READY(cif->hwport))
+ udelay(10);
+ if (i >= CMDIF_TIMEOUT) {
+ err = -EBUSY;
+ goto errout;
+ }
+
+ err = 0;
+ for (j = 0, time = 0; time < CMDIF_TIMEOUT; j++, time += 2) {
+ cmdport = &(hwport->port[j % 2]);
+ if (IS_DATF(cmdport)) { /* free pending data */
+ READ_PORT_ULONG(cmdport->data1);
+ READ_PORT_ULONG(cmdport->data2);
+ }
+ if (IS_CMDE(cmdport)) {
+ if (flags & PARM) /* put data */
+ WRITE_PORT_ULONG(cmdport->data2, parm);
+ WRITE_PORT_ULONG(cmdport->data1, cmd); /* write cmd */
+ if ((flags & RESP) && ret) {
+ while (!IS_DATF(cmdport) &&
+ time++ < CMDIF_TIMEOUT)
+ udelay(10);
+ if (time < CMDIF_TIMEOUT) { /* read response */
+ ret->retlongs[0] =
+ READ_PORT_ULONG(cmdport->data1);
+ ret->retlongs[1] =
+ READ_PORT_ULONG(cmdport->data2);
+ } else {
+ err = -ENOSYS;
+ goto errout;
+ }
+ }
+ break;
+ }
+ udelay(20);
+ }
+ if (time == CMDIF_TIMEOUT) {
+ err = -ENODATA;
+ goto errout;
+ }
+ spin_unlock_irqrestore(&cif->lock, irqflags);
+
+ cif->cmdcnt++; /* update command statistics */
+ cif->cmdtime += time;
+ if (time > cif->cmdtimemax)
+ cif->cmdtimemax = time;
+ if (time < cif->cmdtimemin)
+ cif->cmdtimemin = time;
+ if ((cif->cmdcnt) % 1000 == 0)
+ snd_printdd
+ ("send cmd %d time: %d mintime: %d maxtime %d err: %d\n",
+ cif->cmdcnt, cif->cmdtime, cif->cmdtimemin,
+ cif->cmdtimemax, cif->errcnt);
+ return 0;
+
+ errout:
+ cif->errcnt++;
+ spin_unlock_irqrestore(&cif->lock, irqflags);
+ snd_printdd
+ ("send cmd %d hw: 0x%x flag: 0x%x cmd: 0x%x parm: 0x%x ret: 0x%x 0x%x CMDE: %d DATF: %d failed %d\n",
+ cif->cmdcnt, (int)((void *)&(cmdport->stat) - (void *)hwport),
+ flags, cmd, parm, ret ? ret->retlongs[0] : 0,
+ ret ? ret->retlongs[1] : 0, IS_CMDE(cmdport), IS_DATF(cmdport),
+ err);
+ return err;
+}
+
+static int
+setmixer(struct cmdif *cif, short num, unsigned short rval, unsigned short lval)
+{
+ union cmdret rptr = CMDRET_ZERO;
+ int i = 0;
+
+ snd_printdd("sent mixer %d: 0x%d 0x%d\n", num, rval, lval);
+ do {
+ SEND_SDGV(cif, num, num, rval, lval);
+ SEND_RDGV(cif, num, num, &rptr);
+ if (rptr.retwords[0] == lval && rptr.retwords[1] == rval)
+ return 0;
+ } while (i++ < MAX_WRITE_RETRY);
+ snd_printdd("sent mixer failed\n");
+ return -EIO;
+}
+
+static int getpaths(struct cmdif *cif, unsigned char *o)
+{
+ unsigned char src[E2SINK_MAX];
+ unsigned char sink[E2SINK_MAX];
+ int i, j = 0;
+
+ for (i = 0; i < E2SINK_MAX; i++) {
+ getsourcesink(cif, i, i, &src[i], &sink[i]);
+ if (sink[i] < E2SINK_MAX) {
+ o[j++] = sink[i];
+ o[j++] = i;
+ }
+ }
+ return j;
+}
+
+static int
+getsourcesink(struct cmdif *cif, unsigned char source, unsigned char sink,
+ unsigned char *a, unsigned char *b)
+{
+ union cmdret rptr = CMDRET_ZERO;
+
+ if (SEND_RSSV(cif, source, sink, &rptr) &&
+ SEND_RSSV(cif, source, sink, &rptr))
+ return -EIO;
+ *a = rptr.retbytes[0];
+ *b = rptr.retbytes[1];
+ snd_printdd("getsourcesink 0x%x 0x%x\n", *a, *b);
+ return 0;
+}
+
+static int
+getsamplerate(struct cmdif *cif, unsigned char *intdec, unsigned int *rate)
+{
+ unsigned char *s;
+ unsigned int p[2] = { 0, 0 };
+ int i;
+ union cmdret rptr = CMDRET_ZERO;
+
+ s = intdec;
+ for (i = 0; i < 2; i++) {
+ if (*s != 0xff) {
+ if (SEND_RSRC(cif, *s, &rptr) &&
+ SEND_RSRC(cif, *s, &rptr))
+ return -EIO;
+ p[i] += rptr.retwords[1];
+ p[i] *= rptr.retwords[2];
+ p[i] += rptr.retwords[3];
+ p[i] /= 65536;
+ }
+ s++;
+ }
+ if (p[0]) {
+ if (p[1] != p[0])
+ snd_printdd("rates differ %d %d\n", p[0], p[1]);
+ *rate = (unsigned int)p[0];
+ } else
+ *rate = (unsigned int)p[1];
+ snd_printdd("getsampleformat %d %d %d\n", intdec[0], intdec[1], *rate);
+ return 0;
+}
+
+static int
+setsampleformat(struct cmdif *cif,
+ unsigned char mixer, unsigned char id,
+ unsigned char channels, unsigned char format)
+{
+ unsigned char w, ch, sig, order;
+
+ snd_printdd
+ ("setsampleformat mixer: %d id: %d channels: %d format: %d\n",
+ mixer, id, channels, format);
+ ch = channels == 1;
+ w = snd_pcm_format_width(format) == 8;
+ sig = snd_pcm_format_unsigned(format) != 0;
+ order = snd_pcm_format_big_endian(format) != 0;
+
+ if (SEND_SETF(cif, mixer, w, ch, order, sig, id) &&
+ SEND_SETF(cif, mixer, w, ch, order, sig, id)) {
+ snd_printdd("setsampleformat failed\n");
+ return -EIO;
+ }
+ return 0;
+}
+
+static int
+setsamplerate(struct cmdif *cif, unsigned char *intdec, unsigned int rate)
+{
+ u32 D, M, N;
+ union cmdret rptr = CMDRET_ZERO;
+ int i;
+
+ snd_printdd("setsamplerate intdec: %d,%d rate: %d\n", intdec[0],
+ intdec[1], rate);
+ D = 48000;
+ M = ((rate == 48000) ? 47999 : rate) * 65536;
+ N = M % D;
+ M /= D;
+ for (i = 0; i < 2; i++) {
+ if (*intdec != 0xff) {
+ do {
+ SEND_SSRC(cif, *intdec, D, M, N);
+ SEND_RSRC(cif, *intdec, &rptr);
+ } while (rptr.retwords[1] != D &&
+ rptr.retwords[2] != M &&
+ rptr.retwords[3] != N &&
+ i++ < MAX_WRITE_RETRY);
+ if (i == MAX_WRITE_RETRY) {
+ snd_printdd("sent samplerate %d: %d failed\n",
+ *intdec, rate);
+ return -EIO;
+ }
+ }
+ intdec++;
+ }
+ return 0;
+}
+
+static int
+getmixer(struct cmdif *cif, short num, unsigned short *rval,
+ unsigned short *lval)
+{
+ union cmdret rptr = CMDRET_ZERO;
+
+ if (SEND_RDGV(cif, num, num, &rptr) && SEND_RDGV(cif, num, num, &rptr))
+ return -EIO;
+ *rval = rptr.retwords[0];
+ *lval = rptr.retwords[1];
+ snd_printdd("got mixer %d: 0x%d 0x%d\n", num, *rval, *lval);
+ return 0;
+}
+
+static void riptide_handleirq(unsigned long dev_id)
+{
+ struct snd_riptide *chip = (void *)dev_id;
+ struct cmdif *cif = chip->cif;
+ struct snd_pcm_substream *substream[PLAYBACK_SUBSTREAMS + 1];
+ struct snd_pcm_runtime *runtime;
+ struct pcmhw *data = NULL;
+ unsigned int pos, period_bytes;
+ struct sgd *c;
+ int i, j;
+ unsigned int flag;
+
+ if (!cif)
+ return;
+
+ for (i = 0; i < PLAYBACK_SUBSTREAMS; i++)
+ substream[i] = chip->playback_substream[i];
+ substream[i] = chip->capture_substream;
+ for (i = 0; i < PLAYBACK_SUBSTREAMS + 1; i++) {
+ if (substream[i] &&
+ (runtime = substream[i]->runtime) &&
+ (data = runtime->private_data) && data->state != ST_STOP) {
+ pos = 0;
+ for (j = 0; j < data->pages; j++) {
+ c = &data->sgdbuf[j];
+ flag = le32_to_cpu(c->dwStat_Ctl);
+ if (flag & EOB_STATUS)
+ pos += le32_to_cpu(c->dwSegLen);
+ if (flag & EOC_STATUS)
+ pos += le32_to_cpu(c->dwSegLen);
+ if ((flag & EOS_STATUS)
+ && (data->state == ST_PLAY)) {
+ data->state = ST_STOP;
+ snd_printk(KERN_ERR
+ "Riptide: DMA stopped unexpectedly\n");
+ }
+ c->dwStat_Ctl =
+ cpu_to_le32(flag &
+ ~(EOS_STATUS | EOB_STATUS |
+ EOC_STATUS));
+ }
+ data->pointer += pos;
+ pos += data->oldpos;
+ if (data->state != ST_STOP) {
+ period_bytes =
+ frames_to_bytes(runtime,
+ runtime->period_size);
+ snd_printdd
+ ("interrupt 0x%x after 0x%lx of 0x%lx frames in period\n",
+ READ_AUDIO_STATUS(cif->hwport),
+ bytes_to_frames(runtime, pos),
+ runtime->period_size);
+ j = 0;
+ if (pos >= period_bytes) {
+ j++;
+ while (pos >= period_bytes)
+ pos -= period_bytes;
+ }
+ data->oldpos = pos;
+ if (j > 0)
+ snd_pcm_period_elapsed(substream[i]);
+ }
+ }
+ }
+}
+
+#ifdef CONFIG_PM
+static int riptide_suspend(struct pci_dev *pci, pm_message_t state)
+{
+ struct snd_card *card = pci_get_drvdata(pci);
+ struct snd_riptide *chip = card->private_data;
+
+ chip->in_suspend = 1;
+ snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+ snd_pcm_suspend_all(chip->pcm);
+ snd_ac97_suspend(chip->ac97);
+ pci_set_power_state(pci, PCI_D3hot);
+ pci_disable_device(pci);
+ pci_save_state(pci);
+ return 0;
+}
+
+static int riptide_resume(struct pci_dev *pci)
+{
+ struct snd_card *card = pci_get_drvdata(pci);
+ struct snd_riptide *chip = card->private_data;
+
+ pci_restore_state(pci);
+ pci_enable_device(pci);
+ pci_set_power_state(pci, PCI_D0);
+ pci_set_master(pci);
+ snd_riptide_initialize(chip);
+ snd_ac97_resume(chip->ac97);
+ snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+ chip->in_suspend = 0;
+ return 0;
+}
+#endif
+
+static int riptide_reset(struct cmdif *cif, struct snd_riptide *chip)
+{
+ int timeout, tries;
+ union cmdret rptr = CMDRET_ZERO;
+ union firmware_version firmware;
+ int i, j, err, has_firmware;
+
+ if (!cif)
+ return -EINVAL;
+
+ cif->cmdcnt = 0;
+ cif->cmdtime = 0;
+ cif->cmdtimemax = 0;
+ cif->cmdtimemin = 0xffffffff;
+ cif->errcnt = 0;
+ cif->is_reset = 0;
+
+ tries = RESET_TRIES;
+ has_firmware = 0;
+ while (has_firmware == 0 && tries-- > 0) {
+ for (i = 0; i < 2; i++) {
+ WRITE_PORT_ULONG(cif->hwport->port[i].data1, 0);
+ WRITE_PORT_ULONG(cif->hwport->port[i].data2, 0);
+ }
+ SET_GRESET(cif->hwport);
+ udelay(100);
+ UNSET_GRESET(cif->hwport);
+ udelay(100);
+
+ for (timeout = 100000; --timeout; udelay(10)) {
+ if (IS_READY(cif->hwport) && !IS_GERR(cif->hwport))
+ break;
+ }
+ if (timeout == 0) {
+ snd_printk(KERN_ERR
+ "Riptide: device not ready, audio status: 0x%x ready: %d gerr: %d\n",
+ READ_AUDIO_STATUS(cif->hwport),
+ IS_READY(cif->hwport), IS_GERR(cif->hwport));
+ return -EIO;
+ } else {
+ snd_printdd
+ ("Riptide: audio status: 0x%x ready: %d gerr: %d\n",
+ READ_AUDIO_STATUS(cif->hwport),
+ IS_READY(cif->hwport), IS_GERR(cif->hwport));
+ }
+
+ SEND_GETV(cif, &rptr);
+ for (i = 0; i < 4; i++)
+ firmware.ret.retwords[i] = rptr.retwords[i];
+
+ snd_printdd
+ ("Firmware version: ASIC: %d CODEC %d AUXDSP %d PROG %d\n",
+ firmware.firmware.ASIC, firmware.firmware.CODEC,
+ firmware.firmware.AUXDSP, firmware.firmware.PROG);
+
+ for (j = 0; j < FIRMWARE_VERSIONS; j++) {
+ has_firmware = 1;
+ for (i = 0; i < 4; i++) {
+ if (firmware_versions[j].ret.retwords[i] !=
+ firmware.ret.retwords[i])
+ has_firmware = 0;
+ }
+ if (has_firmware)
+ break;
+ }
+
+ if (chip != NULL && has_firmware == 0) {
+ snd_printdd("Writing Firmware\n");
+ if (!chip->fw_entry) {
+ if ((err =
+ request_firmware(&chip->fw_entry,
+ "riptide.hex",
+ &chip->pci->dev)) != 0) {
+ snd_printk(KERN_ERR
+ "Riptide: Firmware not available %d\n",
+ err);
+ return -EIO;
+ }
+ }
+ err = loadfirmware(cif, chip->fw_entry->data,
+ chip->fw_entry->size);
+ if (err)
+ snd_printk(KERN_ERR
+ "Riptide: Could not load firmware %d\n",
+ err);
+ }
+ }
+
+ SEND_SACR(cif, 0, AC97_RESET);
+ SEND_RACR(cif, AC97_RESET, &rptr);
+ snd_printdd("AC97: 0x%x 0x%x\n", rptr.retlongs[0], rptr.retlongs[1]);
+
+ SEND_PLST(cif, 0);
+ SEND_SLST(cif, 0);
+ SEND_DLST(cif, 0);
+ SEND_ALST(cif, 0);
+ SEND_KDMA(cif);
+
+ writearm(cif, 0x301F8, 1, 1);
+ writearm(cif, 0x301F4, 1, 1);
+
+ SEND_LSEL(cif, MODEM_CMD, 0, 0, MODEM_INTDEC, MODEM_MERGER,
+ MODEM_SPLITTER, MODEM_MIXER);
+ setmixer(cif, MODEM_MIXER, 0x7fff, 0x7fff);
+ alloclbuspath(cif, ARM2LBUS_FIFO13, lbus_play_modem, NULL, NULL);
+
+ SEND_LSEL(cif, FM_CMD, 0, 0, FM_INTDEC, FM_MERGER, FM_SPLITTER,
+ FM_MIXER);
+ setmixer(cif, FM_MIXER, 0x7fff, 0x7fff);
+ writearm(cif, 0x30648 + FM_MIXER * 4, 0x01, 0x00000005);
+ writearm(cif, 0x301A8, 0x02, 0x00000002);
+ writearm(cif, 0x30264, 0x08, 0xffffffff);
+ alloclbuspath(cif, OPL3_SAMPLE, lbus_play_opl3, NULL, NULL);
+
+ SEND_SSRC(cif, I2S_INTDEC, 48000,
+ ((u32) I2S_RATE * 65536) / 48000,
+ ((u32) I2S_RATE * 65536) % 48000);
+ SEND_LSEL(cif, I2S_CMD0, 0, 0, I2S_INTDEC, I2S_MERGER, I2S_SPLITTER,
+ I2S_MIXER);
+ SEND_SI2S(cif, 1);
+ alloclbuspath(cif, ARM2LBUS_FIFO0, lbus_play_i2s, NULL, NULL);
+ alloclbuspath(cif, DIGITAL_MIXER_OUT0, lbus_play_out, NULL, NULL);
+ alloclbuspath(cif, DIGITAL_MIXER_OUT0, lbus_play_outhp, NULL, NULL);
+
+ SET_AIACK(cif->hwport);
+ SET_AIE(cif->hwport);
+ SET_AIACK(cif->hwport);
+ cif->is_reset = 1;
+ if (chip) {
+ for (i = 0; i < 4; i++)
+ chip->firmware.ret.retwords[i] =
+ firmware.ret.retwords[i];
+ }
+
+ return 0;
+}
+
+static struct snd_pcm_hardware snd_riptide_playback = {
+ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP_VALID),
+ .formats =
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8
+ | SNDRV_PCM_FMTBIT_U16_LE,
+ .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000,
+ .rate_min = 5500,
+ .rate_max = 48000,
+ .channels_min = 1,
+ .channels_max = 2,
+ .buffer_bytes_max = (64 * 1024),
+ .period_bytes_min = PAGE_SIZE >> 1,
+ .period_bytes_max = PAGE_SIZE << 8,
+ .periods_min = 2,
+ .periods_max = 64,
+ .fifo_size = 0,
+};
+static struct snd_pcm_hardware snd_riptide_capture = {
+ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP_VALID),
+ .formats =
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8
+ | SNDRV_PCM_FMTBIT_U16_LE,
+ .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000,
+ .rate_min = 5500,
+ .rate_max = 48000,
+ .channels_min = 1,
+ .channels_max = 2,
+ .buffer_bytes_max = (64 * 1024),
+ .period_bytes_min = PAGE_SIZE >> 1,
+ .period_bytes_max = PAGE_SIZE << 3,
+ .periods_min = 2,
+ .periods_max = 64,
+ .fifo_size = 0,
+};
+
+static snd_pcm_uframes_t snd_riptide_pointer(struct snd_pcm_substream
+ *substream)
+{
+ struct snd_riptide *chip = snd_pcm_substream_chip(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct pcmhw *data = get_pcmhwdev(substream);
+ struct cmdif *cif = chip->cif;
+ union cmdret rptr = CMDRET_ZERO;
+ snd_pcm_uframes_t ret;
+
+ SEND_GPOS(cif, 0, data->id, &rptr);
+ if (data->size && runtime->period_size) {
+ snd_printdd
+ ("pointer stream %d position 0x%x(0x%x in buffer) bytes 0x%lx(0x%lx in period) frames\n",
+ data->id, rptr.retlongs[1], rptr.retlongs[1] % data->size,
+ bytes_to_frames(runtime, rptr.retlongs[1]),
+ bytes_to_frames(runtime,
+ rptr.retlongs[1]) % runtime->period_size);
+ if (rptr.retlongs[1] > data->pointer)
+ ret =
+ bytes_to_frames(runtime,
+ rptr.retlongs[1] % data->size);
+ else
+ ret =
+ bytes_to_frames(runtime,
+ data->pointer % data->size);
+ } else {
+ snd_printdd("stream not started or strange parms (%d %ld)\n",
+ data->size, runtime->period_size);
+ ret = bytes_to_frames(runtime, 0);
+ }
+ return ret;
+}
+
+static int snd_riptide_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ int i, j;
+ struct snd_riptide *chip = snd_pcm_substream_chip(substream);
+ struct pcmhw *data = get_pcmhwdev(substream);
+ struct cmdif *cif = chip->cif;
+ union cmdret rptr = CMDRET_ZERO;
+
+ spin_lock(&chip->lock);
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ if (!(data->state & ST_PLAY)) {
+ SEND_SSTR(cif, data->id, data->sgdlist.addr);
+ SET_AIE(cif->hwport);
+ data->state = ST_PLAY;
+ if (data->mixer != 0xff)
+ setmixer(cif, data->mixer, 0x7fff, 0x7fff);
+ chip->openstreams++;
+ data->oldpos = 0;
+ data->pointer = 0;
+ }
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ if (data->mixer != 0xff)
+ setmixer(cif, data->mixer, 0, 0);
+ setmixer(cif, data->mixer, 0, 0);
+ SEND_KSTR(cif, data->id);
+ data->state = ST_STOP;
+ chip->openstreams--;
+ j = 0;
+ do {
+ i = rptr.retlongs[1];
+ SEND_GPOS(cif, 0, data->id, &rptr);
+ udelay(1);
+ } while (i != rptr.retlongs[1] && j++ < MAX_WRITE_RETRY);
+ if (j >= MAX_WRITE_RETRY)
+ snd_printk(KERN_ERR "Riptide: Could not stop stream!");
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ if (!(data->state & ST_PAUSE)) {
+ SEND_PSTR(cif, data->id);
+ data->state |= ST_PAUSE;
+ chip->openstreams--;
+ }
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ if (data->state & ST_PAUSE) {
+ SEND_SSTR(cif, data->id, data->sgdlist.addr);
+ data->state &= ~ST_PAUSE;
+ chip->openstreams++;
+ }
+ break;
+ default:
+ spin_unlock(&chip->lock);
+ return -EINVAL;
+ }
+ spin_unlock(&chip->lock);
+ return 0;
+}
+
+static int snd_riptide_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_riptide *chip = snd_pcm_substream_chip(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream);
+ struct pcmhw *data = get_pcmhwdev(substream);
+ struct cmdif *cif = chip->cif;
+ unsigned char *lbuspath = NULL;
+ unsigned int rate, channels;
+ int err = 0;
+ snd_pcm_format_t format;
+
+ snd_assert(cif && data, return -EINVAL);
+
+ snd_printdd("prepare id %d ch: %d f:0x%x r:%d\n", data->id,
+ runtime->channels, runtime->format, runtime->rate);
+
+ spin_lock_irq(&chip->lock);
+ channels = runtime->channels;
+ format = runtime->format;
+ rate = runtime->rate;
+ switch (channels) {
+ case 1:
+ if (rate == 48000 && format == SNDRV_PCM_FORMAT_S16_LE)
+ lbuspath = data->paths.noconv;
+ else
+ lbuspath = data->paths.mono;
+ break;
+ case 2:
+ if (rate == 48000 && format == SNDRV_PCM_FORMAT_S16_LE)
+ lbuspath = data->paths.noconv;
+ else
+ lbuspath = data->paths.stereo;
+ break;
+ }
+ snd_printdd("use sgdlist at 0x%p and buffer at 0x%p\n",
+ data->sgdlist.area, sgbuf);
+ if (data->sgdlist.area && sgbuf) {
+ unsigned int i, j, size, pages, f, pt, period;
+ struct sgd *c, *p = NULL;
+
+ size = frames_to_bytes(runtime, runtime->buffer_size);
+ period = frames_to_bytes(runtime, runtime->period_size);
+ f = PAGE_SIZE;
+ while ((size + (f >> 1) - 1) <= (f << 7) && (f << 1) > period)
+ f = f >> 1;
+ pages = (size + f - 1) / f;
+ data->size = size;
+ data->pages = pages;
+ snd_printdd
+ ("create sgd size: 0x%x pages %d of size 0x%x for period 0x%x\n",
+ size, pages, f, period);
+ pt = 0;
+ j = 0;
+ for (i = 0; i < pages; i++) {
+ c = &data->sgdbuf[i];
+ if (p)
+ p->dwNextLink = cpu_to_le32(data->sgdlist.addr +
+ (i *
+ sizeof(struct
+ sgd)));
+ c->dwNextLink = cpu_to_le32(data->sgdlist.addr);
+ c->dwSegPtrPhys =
+ cpu_to_le32(sgbuf->table[j].addr + pt);
+ pt = (pt + f) % PAGE_SIZE;
+ if (pt == 0)
+ j++;
+ c->dwSegLen = cpu_to_le32(f);
+ c->dwStat_Ctl =
+ cpu_to_le32(IEOB_ENABLE | IEOS_ENABLE |
+ IEOC_ENABLE);
+ p = c;
+ size -= f;
+ }
+ data->sgdbuf[i].dwSegLen = cpu_to_le32(size);
+ }
+ if (lbuspath && lbuspath != data->lbuspath) {
+ if (data->lbuspath)
+ freelbuspath(cif, data->source, data->lbuspath);
+ alloclbuspath(cif, data->source, lbuspath,
+ &data->mixer, data->intdec);
+ data->lbuspath = lbuspath;
+ data->rate = 0;
+ }
+ if (data->rate != rate || data->format != format ||
+ data->channels != channels) {
+ data->rate = rate;
+ data->format = format;
+ data->channels = channels;
+ if (setsampleformat
+ (cif, data->mixer, data->id, channels, format)
+ || setsamplerate(cif, data->intdec, rate))
+ err = -EIO;
+ }
+ spin_unlock_irq(&chip->lock);
+ return err;
+}
+
+static int
+snd_riptide_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ struct snd_riptide *chip = snd_pcm_substream_chip(substream);
+ struct pcmhw *data = get_pcmhwdev(substream);
+ struct snd_dma_buffer *sgdlist = &data->sgdlist;
+ int err;
+
+ snd_printdd("hw params id %d (sgdlist: 0x%p 0x%lx %d)\n", data->id,
+ sgdlist->area, (unsigned long)sgdlist->addr,
+ (int)sgdlist->bytes);
+ if (sgdlist->area)
+ snd_dma_free_pages(sgdlist);
+ if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
+ snd_dma_pci_data(chip->pci),
+ sizeof(struct sgd) * (DESC_MAX_MASK + 1),
+ sgdlist)) < 0) {
+ snd_printk(KERN_ERR "Riptide: failed to alloc %d dma bytes\n",
+ (int)sizeof(struct sgd) * (DESC_MAX_MASK + 1));
+ return err;
+ }
+ data->sgdbuf = (struct sgd *)sgdlist->area;
+ return snd_pcm_lib_malloc_pages(substream,
+ params_buffer_bytes(hw_params));
+}
+
+static int snd_riptide_hw_free(struct snd_pcm_substream *substream)
+{
+ struct snd_riptide *chip = snd_pcm_substream_chip(substream);
+ struct pcmhw *data = get_pcmhwdev(substream);
+ struct cmdif *cif = chip->cif;
+
+ if (cif && data) {
+ if (data->lbuspath)
+ freelbuspath(cif, data->source, data->lbuspath);
+ data->lbuspath = NULL;
+ data->source = 0xff;
+ data->intdec[0] = 0xff;
+ data->intdec[1] = 0xff;
+
+ if (data->sgdlist.area) {
+ snd_dma_free_pages(&data->sgdlist);
+ data->sgdlist.area = NULL;
+ }
+ }
+ return snd_pcm_lib_free_pages(substream);
+}
+
+static int snd_riptide_playback_open(struct snd_pcm_substream *substream)
+{
+ struct snd_riptide *chip = snd_pcm_substream_chip(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct pcmhw *data;
+ int index = substream->number;
+
+ chip->playback_substream[index] = substream;
+ runtime->hw = snd_riptide_playback;
+ data = kzalloc(sizeof(struct pcmhw), GFP_KERNEL);
+ data->paths = lbus_play_paths[index];
+ data->id = play_ids[index];
+ data->source = play_sources[index];
+ data->intdec[0] = 0xff;
+ data->intdec[1] = 0xff;
+ data->state = ST_STOP;
+ runtime->private_data = data;
+ return snd_pcm_hw_constraint_integer(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+}
+
+static int snd_riptide_capture_open(struct snd_pcm_substream *substream)
+{
+ struct snd_riptide *chip = snd_pcm_substream_chip(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct pcmhw *data;
+
+ chip->capture_substream = substream;
+ runtime->hw = snd_riptide_capture;
+ data = kzalloc(sizeof(struct pcmhw), GFP_KERNEL);
+ data->paths = lbus_rec_path;
+ data->id = PADC;
+ data->source = ACLNK2PADC;
+ data->intdec[0] = 0xff;
+ data->intdec[1] = 0xff;
+ data->state = ST_STOP;
+ runtime->private_data = data;
+ return snd_pcm_hw_constraint_integer(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+}
+
+static int snd_riptide_playback_close(struct snd_pcm_substream *substream)
+{
+ struct snd_riptide *chip = snd_pcm_substream_chip(substream);
+ struct pcmhw *data = get_pcmhwdev(substream);
+ int index = substream->number;
+
+ substream->runtime->private_data = NULL;
+ chip->playback_substream[index] = NULL;
+ kfree(data);
+ return 0;
+}
+
+static int snd_riptide_capture_close(struct snd_pcm_substream *substream)
+{
+ struct snd_riptide *chip = snd_pcm_substream_chip(substream);
+ struct pcmhw *data = get_pcmhwdev(substream);
+
+ substream->runtime->private_data = NULL;
+ chip->capture_substream = NULL;
+ kfree(data);
+ return 0;
+}
+
+static struct snd_pcm_ops snd_riptide_playback_ops = {
+ .open = snd_riptide_playback_open,
+ .close = snd_riptide_playback_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_riptide_hw_params,
+ .hw_free = snd_riptide_hw_free,
+ .prepare = snd_riptide_prepare,
+ .page = snd_pcm_sgbuf_ops_page,
+ .trigger = snd_riptide_trigger,
+ .pointer = snd_riptide_pointer,
+};
+static struct snd_pcm_ops snd_riptide_capture_ops = {
+ .open = snd_riptide_capture_open,
+ .close = snd_riptide_capture_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_riptide_hw_params,
+ .hw_free = snd_riptide_hw_free,
+ .prepare = snd_riptide_prepare,
+ .page = snd_pcm_sgbuf_ops_page,
+ .trigger = snd_riptide_trigger,
+ .pointer = snd_riptide_pointer,
+};
+
+static int __devinit
+snd_riptide_pcm(struct snd_riptide *chip, int device, struct snd_pcm **rpcm)
+{
+ struct snd_pcm *pcm;
+ int err;
+
+ if (rpcm)
+ *rpcm = NULL;
+ if ((err =
+ snd_pcm_new(chip->card, "RIPTIDE", device, PLAYBACK_SUBSTREAMS, 1,
+ &pcm)) < 0)
+ return err;
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ &snd_riptide_playback_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+ &snd_riptide_capture_ops);
+ pcm->private_data = chip;
+ pcm->info_flags = 0;
+ strcpy(pcm->name, "RIPTIDE");
+ chip->pcm = pcm;
+ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
+ snd_dma_pci_data(chip->pci),
+ 64 * 1024, 128 * 1024);
+ if (rpcm)
+ *rpcm = pcm;
+ return 0;
+}
+
+static irqreturn_t
+snd_riptide_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct snd_riptide *chip = dev_id;
+ struct cmdif *cif = chip->cif;
+
+ if (cif) {
+ chip->received_irqs++;
+ if (IS_EOBIRQ(cif->hwport) || IS_EOSIRQ(cif->hwport) ||
+ IS_EOCIRQ(cif->hwport)) {
+ chip->handled_irqs++;
+ tasklet_hi_schedule(&chip->riptide_tq);
+ }
+ if (chip->rmidi && IS_MPUIRQ(cif->hwport)) {
+ chip->handled_irqs++;
+ snd_mpu401_uart_interrupt(irq,
+ chip->rmidi->private_data,
+ regs);
+ }
+ SET_AIACK(cif->hwport);
+ }
+ return IRQ_HANDLED;
+}
+
+static void
+snd_riptide_codec_write(struct snd_ac97 *ac97, unsigned short reg,
+ unsigned short val)
+{
+ struct snd_riptide *chip = ac97->private_data;
+ struct cmdif *cif = chip->cif;
+ union cmdret rptr = CMDRET_ZERO;
+ int i = 0;
+
+ snd_assert(cif, return);
+
+ snd_printdd("Write AC97 reg 0x%x 0x%x\n", reg, val);
+ do {
+ SEND_SACR(cif, val, reg);
+ SEND_RACR(cif, reg, &rptr);
+ } while (rptr.retwords[1] != val && i++ < MAX_WRITE_RETRY);
+ if (i == MAX_WRITE_RETRY)
+ snd_printdd("Write AC97 reg failed\n");
+}
+
+static unsigned short snd_riptide_codec_read(struct snd_ac97 *ac97,
+ unsigned short reg)
+{
+ struct snd_riptide *chip = ac97->private_data;
+ struct cmdif *cif = chip->cif;
+ union cmdret rptr = CMDRET_ZERO;
+
+ snd_assert(cif, return 0);
+
+ if (SEND_RACR(cif, reg, &rptr) != 0)
+ SEND_RACR(cif, reg, &rptr);
+ snd_printdd("Read AC97 reg 0x%x got 0x%x\n", reg, rptr.retwords[1]);
+ return rptr.retwords[1];
+}
+
+static int snd_riptide_initialize(struct snd_riptide *chip)
+{
+ struct cmdif *cif;
+ unsigned int device_id;
+ int err;
+
+ snd_assert(chip, return -EINVAL);
+
+ cif = chip->cif;
+ if (!cif) {
+ if ((cif = kzalloc(sizeof(struct cmdif), GFP_KERNEL)) == NULL)
+ return -ENOMEM;
+ cif->hwport = (struct riptideport *)chip->port;
+ spin_lock_init(&cif->lock);
+ chip->cif = cif;
+ }
+ cif->is_reset = 0;
+ if ((err = riptide_reset(cif, chip)) != 0)
+ return err;
+ device_id = chip->device_id;
+ switch (device_id) {
+ case 0x4310:
+ case 0x4320:
+ case 0x4330:
+ snd_printdd("Modem enable?\n");
+ SEND_SETDPLL(cif);
+ break;
+ }
+ snd_printdd("Enabling MPU IRQs\n");
+ if (chip->rmidi)
+ SET_EMPUIRQ(cif->hwport);
+ return err;
+}
+
+static int snd_riptide_free(struct snd_riptide *chip)
+{
+ struct cmdif *cif;
+
+ snd_assert(chip, return 0);
+
+ if ((cif = chip->cif)) {
+ SET_GRESET(cif->hwport);
+ udelay(100);
+ UNSET_GRESET(cif->hwport);
+ kfree(chip->cif);
+ }
+ if (chip->fw_entry)
+ release_firmware(chip->fw_entry);
+ release_and_free_resource(chip->res_port);
+ if (chip->irq >= 0)
+ free_irq(chip->irq, chip);
+ kfree(chip);
+ return 0;
+}
+
+static int snd_riptide_dev_free(struct snd_device *device)
+{
+ struct snd_riptide *chip = device->device_data;
+
+ return snd_riptide_free(chip);
+}
+
+static int __devinit
+snd_riptide_create(struct snd_card *card, struct pci_dev *pci,
+ struct snd_riptide **rchip)
+{
+ struct snd_riptide *chip;
+ struct riptideport *hwport;
+ int err;
+ static struct snd_device_ops ops = {
+ .dev_free = snd_riptide_dev_free,
+ };
+
+ *rchip = NULL;
+ if ((err = pci_enable_device(pci)) < 0)
+ return err;
+ if (!(chip = kzalloc(sizeof(struct snd_riptide), GFP_KERNEL)))
+ return -ENOMEM;
+
+ spin_lock_init(&chip->lock);
+ chip->card = card;
+ chip->pci = pci;
+ chip->irq = -1;
+ chip->openstreams = 0;
+ chip->port = pci_resource_start(pci, 0);
+ chip->received_irqs = 0;
+ chip->handled_irqs = 0;
+ chip->cif = NULL;
+ tasklet_init(&chip->riptide_tq, riptide_handleirq, (unsigned long)chip);
+
+ if ((chip->res_port =
+ request_region(chip->port, 64, "RIPTIDE")) == NULL) {
+ snd_printk(KERN_ERR
+ "Riptide: unable to grab region 0x%lx-0x%lx\n",
+ chip->port, chip->port + 64 - 1);
+ snd_riptide_free(chip);
+ return -EBUSY;
+ }
+ hwport = (struct riptideport *)chip->port;
+ UNSET_AIE(hwport);
+
+ if (request_irq
+ (pci->irq, snd_riptide_interrupt, SA_INTERRUPT | SA_SHIRQ,
+ "RIPTIDE", chip)) {
+ snd_printk(KERN_ERR "Riptide: unable to grab IRQ %d\n",
+ pci->irq);
+ snd_riptide_free(chip);
+ return -EBUSY;
+ }
+ chip->irq = pci->irq;
+ chip->device_id = pci->device;
+ pci_set_master(pci);
+ if ((err = snd_riptide_initialize(chip)) < 0) {
+ snd_riptide_free(chip);
+ return err;
+ }
+
+ if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
+ snd_riptide_free(chip);
+ return err;
+ }
+
+ *rchip = chip;
+ return 0;
+}
+
+static void
+snd_riptide_proc_read(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
+{
+ struct snd_riptide *chip = entry->private_data;
+ struct pcmhw *data;
+ int i;
+ struct cmdif *cif = NULL;
+ unsigned char p[256];
+ unsigned short rval = 0, lval = 0;
+ unsigned int rate;
+
+ if (!chip)
+ return;
+
+ snd_iprintf(buffer, "%s\n\n", chip->card->longname);
+ snd_iprintf(buffer, "Device ID: 0x%x\nReceived IRQs: (%ld)%ld\nPorts:",
+ chip->device_id, chip->handled_irqs, chip->received_irqs);
+ for (i = 0; i < 64; i += 4)
+ snd_iprintf(buffer, "%c%02x: %08x",
+ (i % 16) ? ' ' : '\n', i, inl(chip->port + i));
+ if ((cif = chip->cif)) {
+ snd_iprintf(buffer,
+ "\nVersion: ASIC: %d CODEC: %d AUXDSP: %d PROG: %d",
+ chip->firmware.firmware.ASIC,
+ chip->firmware.firmware.CODEC,
+ chip->firmware.firmware.AUXDSP,
+ chip->firmware.firmware.PROG);
+ snd_iprintf(buffer, "\nDigital mixer:");
+ for (i = 0; i < 12; i++) {
+ getmixer(cif, i, &rval, &lval);
+ snd_iprintf(buffer, "\n %d: %d %d", i, rval, lval);
+ }
+ snd_iprintf(buffer,
+ "\nARM Commands num: %d failed: %d time: %d max: %d min: %d",
+ cif->cmdcnt, cif->errcnt,
+ cif->cmdtime, cif->cmdtimemax, cif->cmdtimemin);
+ }
+ snd_iprintf(buffer, "\nOpen streams %d:\n", chip->openstreams);
+ for (i = 0; i < PLAYBACK_SUBSTREAMS; i++) {
+ if (chip->playback_substream[i]
+ && chip->playback_substream[i]->runtime
+ && (data =
+ chip->playback_substream[i]->runtime->private_data)) {
+ snd_iprintf(buffer,
+ "stream: %d mixer: %d source: %d (%d,%d)\n",
+ data->id, data->mixer, data->source,
+ data->intdec[0], data->intdec[1]);
+ if (!(getsamplerate(cif, data->intdec, &rate)))
+ snd_iprintf(buffer, "rate: %d\n", rate);
+ }
+ }
+ if (chip->capture_substream
+ && chip->capture_substream->runtime
+ && (data = chip->capture_substream->runtime->private_data)) {
+ snd_iprintf(buffer,
+ "stream: %d mixer: %d source: %d (%d,%d)\n",
+ data->id, data->mixer,
+ data->source, data->intdec[0], data->intdec[1]);
+ if (!(getsamplerate(cif, data->intdec, &rate)))
+ snd_iprintf(buffer, "rate: %d\n", rate);
+ }
+ snd_iprintf(buffer, "Paths:\n");
+ i = getpaths(cif, p);
+ while (i--) {
+ snd_iprintf(buffer, "%x->%x ", p[i - 1], p[i]);
+ i--;
+ }
+ snd_iprintf(buffer, "\n");
+}
+
+static void __devinit snd_riptide_proc_init(struct snd_riptide *chip)
+{
+ struct snd_info_entry *entry;
+
+ if (!snd_card_proc_new(chip->card, "riptide", &entry))
+ snd_info_set_text_ops(entry, chip, 4096, snd_riptide_proc_read);
+}
+
+static int __devinit snd_riptide_mixer(struct snd_riptide *chip)
+{
+ struct snd_ac97_bus *pbus;
+ struct snd_ac97_template ac97;
+ int err = 0;
+ static struct snd_ac97_bus_ops ops = {
+ .write = snd_riptide_codec_write,
+ .read = snd_riptide_codec_read,
+ };
+
+ memset(&ac97, 0, sizeof(ac97));
+ ac97.private_data = chip;
+ ac97.scaps = AC97_SCAP_SKIP_MODEM;
+
+ if ((err = snd_ac97_bus(chip->card, 0, &ops, chip, &pbus)) < 0)
+ return err;
+
+ chip->ac97_bus = pbus;
+ ac97.pci = chip->pci;
+ if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97)) < 0)
+ return err;
+ return err;
+}
+
+#ifdef SUPPORT_JOYSTICK
+static int have_joystick;
+static struct pci_dev *riptide_gameport_pci;
+static struct gameport *riptide_gameport;
+
+static int __devinit
+snd_riptide_joystick_probe(struct pci_dev *pci, const struct pci_device_id *id)
+{
+ static int dev;
+
+ if (dev >= SNDRV_CARDS)
+ return -ENODEV;
+ if (!enable[dev]) {
+ dev++;
+ return -ENOENT;
+ }
+
+ if (joystick_port[dev]) {
+ riptide_gameport = gameport_allocate_port();
+ if (riptide_gameport) {
+ if (!request_region
+ (joystick_port[dev], 8, "Riptide gameport")) {
+ snd_printk(KERN_WARNING
+ "Riptide: cannot grab gameport 0x%x\n",
+ joystick_port[dev]);
+ gameport_free_port(riptide_gameport);
+ riptide_gameport = NULL;
+ } else {
+ riptide_gameport_pci = pci;
+ riptide_gameport->io = joystick_port[dev];
+ gameport_register_port(riptide_gameport);
+ }
+ }
+ }
+ dev++;
+ return 0;
+}
+
+static void __devexit snd_riptide_joystick_remove(struct pci_dev *pci)
+{
+ if (riptide_gameport) {
+ if (riptide_gameport_pci == pci) {
+ release_region(riptide_gameport->io, 8);
+ riptide_gameport_pci = NULL;
+ gameport_unregister_port(riptide_gameport);
+ riptide_gameport = NULL;
+ }
+ }
+}
+#endif
+
+static int __devinit
+snd_card_riptide_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
+{
+ static int dev;
+ struct snd_card *card;
+ struct snd_riptide *chip;
+ unsigned short addr;
+ int err = 0;
+
+ if (dev >= SNDRV_CARDS)
+ return -ENODEV;
+ if (!enable[dev]) {
+ dev++;
+ return -ENOENT;
+ }
+
+ card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
+ if (card == NULL)
+ return -ENOMEM;
+ if ((err = snd_riptide_create(card, pci, &chip)) < 0) {
+ snd_card_free(card);
+ return err;
+ }
+ card->private_data = chip;
+ if ((err = snd_riptide_pcm(chip, 0, NULL)) < 0) {
+ snd_card_free(card);
+ return err;
+ }
+ if ((err = snd_riptide_mixer(chip)) < 0) {
+ snd_card_free(card);
+ return err;
+ }
+ pci_write_config_word(chip->pci, PCI_EXT_Legacy_Mask, LEGACY_ENABLE_ALL
+ | (opl3_port[dev] ? LEGACY_ENABLE_FM : 0)
+#ifdef SUPPORT_JOYSTICK
+ | (joystick_port[dev] ? LEGACY_ENABLE_GAMEPORT :
+ 0)
+#endif
+ | (mpu_port[dev]
+ ? (LEGACY_ENABLE_MPU_INT | LEGACY_ENABLE_MPU) :
+ 0)
+ | ((chip->irq << 4) & 0xF0));
+ if ((addr = mpu_port[dev]) != 0) {
+ pci_write_config_word(chip->pci, PCI_EXT_MPU_Base, addr);
+ if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_RIPTIDE,
+ addr, 0, chip->irq, 0,
+ &chip->rmidi)) < 0)
+ snd_printk(KERN_WARNING
+ "Riptide: Can't Allocate MPU at 0x%x\n",
+ addr);
+ else
+ chip->mpuaddr = addr;
+ }
+ if ((addr = opl3_port[dev]) != 0) {
+ pci_write_config_word(chip->pci, PCI_EXT_FM_Base, addr);
+ if ((err = snd_opl3_create(card, addr, addr + 2,
+ OPL3_HW_RIPTIDE, 0,
+ &chip->opl3)) < 0)
+ snd_printk(KERN_WARNING
+ "Riptide: Can't Allocate OPL3 at 0x%x\n",
+ addr);
+ else {
+ chip->opladdr = addr;
+ if ((err =
+ snd_opl3_hwdep_new(chip->opl3, 0, 1, NULL)) < 0)
+ snd_printk(KERN_WARNING
+ "Riptide: Can't Allocate OPL3-HWDEP\n");
+ }
+ }
+#ifdef SUPPORT_JOYSTICK
+ if ((addr = joystick_port[dev]) != 0) {
+ pci_write_config_word(chip->pci, PCI_EXT_Game_Base, addr);
+ chip->gameaddr = addr;
+ }
+#endif
+
+ strcpy(card->driver, "RIPTIDE");
+ strcpy(card->shortname, "Riptide");
+#ifdef SUPPORT_JOYSTICK
+ snprintf(card->longname, sizeof(card->longname),
+ "%s at 0x%lx, irq %i mpu 0x%x opl3 0x%x gameport 0x%x",
+ card->shortname, chip->port, chip->irq, chip->mpuaddr,
+ chip->opladdr, chip->gameaddr);
+#else
+ snprintf(card->longname, sizeof(card->longname),
+ "%s at 0x%lx, irq %i mpu 0x%x opl3 0x%x",
+ card->shortname, chip->port, chip->irq, chip->mpuaddr,
+ chip->opladdr);
+#endif
+ snd_riptide_proc_init(chip);
+ if ((err = snd_card_register(card)) < 0) {
+ snd_card_free(card);
+ return err;
+ }
+ pci_set_drvdata(pci, card);
+ dev++;
+ return 0;
+}
+
+static void __devexit snd_card_riptide_remove(struct pci_dev *pci)
+{
+ snd_card_free(pci_get_drvdata(pci));
+ pci_set_drvdata(pci, NULL);
+}
+
+static struct pci_driver driver = {
+ .name = "RIPTIDE",
+ .id_table = snd_riptide_ids,
+ .probe = snd_card_riptide_probe,
+ .remove = __devexit_p(snd_card_riptide_remove),
+#ifdef CONFIG_PM
+ .suspend = riptide_suspend,
+ .resume = riptide_resume,
+#endif
+};
+
+#ifdef SUPPORT_JOYSTICK
+static struct pci_driver joystick_driver = {
+ .name = "Riptide Joystick",
+ .id_table = snd_riptide_joystick_ids,
+ .probe = snd_riptide_joystick_probe,
+ .remove = __devexit_p(snd_riptide_joystick_remove),
+};
+#endif
+
+static int __init alsa_card_riptide_init(void)
+{
+ int err;
+ if ((err = pci_register_driver(&driver)) < 0)
+ return err;
+#if defined(SUPPORT_JOYSTICK)
+ if (pci_register_driver(&joystick_driver) < 0) {
+ have_joystick = 0;
+ snd_printk(KERN_INFO "no joystick found\n");
+ } else
+ have_joystick = 1;
+#endif
+ return 0;
+}
+
+static void __exit alsa_card_riptide_exit(void)
+{
+ pci_unregister_driver(&driver);
+#if defined(SUPPORT_JOYSTICK)
+ if (have_joystick)
+ pci_unregister_driver(&joystick_driver);
+#endif
+}
+
+module_init(alsa_card_riptide_init);
+module_exit(alsa_card_riptide_exit);
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c
index 1957d29c119..1e7398de286 100644
--- a/sound/pci/via82xx.c
+++ b/sound/pci/via82xx.c
@@ -2373,6 +2373,7 @@ static int __devinit check_dxs_list(struct pci_dev *pci)
{ .subvendor = 0x161f, .subdevice = 0x2032, .action = VIA_DXS_48K }, /* m680x machines */
{ .subvendor = 0x1631, .subdevice = 0xe004, .action = VIA_DXS_ENABLE }, /* Easy Note 3174, Packard Bell */
{ .subvendor = 0x1695, .subdevice = 0x3005, .action = VIA_DXS_ENABLE }, /* EPoX EP-8K9A */
+ { .subvendor = 0x1695, .subdevice = 0x300c, .action = VIA_DXS_SRC }, /* EPoX EP-8KRAI */
{ .subvendor = 0x1695, .subdevice = 0x300e, .action = VIA_DXS_SRC }, /* EPoX 9HEAI */
{ .subvendor = 0x16f3, .subdevice = 0x6405, .action = VIA_DXS_SRC }, /* Jetway K8M8MS */
{ .subvendor = 0x1734, .subdevice = 0x1078, .action = VIA_DXS_SRC }, /* FSC Amilo L7300 */
diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c
index 8d08b34a1cb..ce86283ee0f 100644
--- a/sound/usb/usbmixer.c
+++ b/sound/usb/usbmixer.c
@@ -306,8 +306,8 @@ static int get_relative_value(struct usb_mixer_elem_info *cval, int val)
cval->res = 1;
if (val < cval->min)
return 0;
- else if (val > cval->max)
- return (cval->max - cval->min) / cval->res;
+ else if (val >= cval->max)
+ return (cval->max - cval->min + cval->res - 1) / cval->res;
else
return (val - cval->min) / cval->res;
}
@@ -670,6 +670,36 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min)
}
if (cval->res == 0)
cval->res = 1;
+
+ /* Additional checks for the proper resolution
+ *
+ * Some devices report smaller resolutions than actually
+ * reacting. They don't return errors but simply clip
+ * to the lower aligned value.
+ */
+ if (cval->min + cval->res < cval->max) {
+ int last_valid_res = cval->res;
+ int saved, test, check;
+ get_cur_mix_value(cval, minchn, &saved);
+ for (;;) {
+ test = saved;
+ if (test < cval->max)
+ test += cval->res;
+ else
+ test -= cval->res;
+ if (test < cval->min || test > cval->max ||
+ set_cur_mix_value(cval, minchn, test) ||
+ get_cur_mix_value(cval, minchn, &check)) {
+ cval->res = last_valid_res;
+ break;
+ }
+ if (test == check)
+ break;
+ cval->res *= 2;
+ }
+ set_cur_mix_value(cval, minchn, saved);
+ }
+
cval->initialized = 1;
}
return 0;
@@ -695,7 +725,8 @@ static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol, struct snd_ctl_
if (! cval->initialized)
get_min_max(cval, 0);
uinfo->value.integer.min = 0;
- uinfo->value.integer.max = (cval->max - cval->min) / cval->res;
+ uinfo->value.integer.max =
+ (cval->max - cval->min + cval->res - 1) / cval->res;
}
return 0;
}