S: Maintained
ACPI
- P: Len Brown
- M: len.brown@intel.com
+ P: Andi Kleen
+ M: ak@linux.intel.com
M: lenb@kernel.org
L: linux-acpi@vger.kernel.org
W: http://www.lesswatts.org/projects/acpi/
S: Supported
ACPI FAN DRIVER
- P: Len Brown
- M: len.brown@intel.com
+ P: Zhang Rui
+ M: rui.zhang@intel.com
L: linux-acpi@vger.kernel.org
W: http://www.lesswatts.org/projects/acpi/
S: Supported
ACPI PCI HOTPLUG DRIVER
P: Kristen Carlson Accardi
M: kristen.c.accardi@intel.com
- L: pcihpd-discuss@lists.sourceforge.net
+ L: linux-pci@vger.kernel.org
S: Supported
ACPI THERMAL DRIVER
- P: Len Brown
- M: len.brown@intel.com
+ P: Zhang Rui
+ M: rui.zhang@intel.com
L: linux-acpi@vger.kernel.org
W: http://www.lesswatts.org/projects/acpi/
S: Supported
ACPI VIDEO DRIVER
- P: Rui Zhang
+ P: Zhang Rui
M: rui.zhang@intel.com
L: linux-acpi@vger.kernel.org
W: http://www.lesswatts.org/projects/acpi/
S: Maintained
ALCHEMY AU1XX0 MMC DRIVER
- S: Orphan
+ P: Manuel Lauss
+ M: manuel.lauss@gmail.com
+ S: Maintained
ALI1563 I2C DRIVER
P: Rudolf Marek
W: http://www.amd.com/us-en/ConnectivitySolutions/TechnicalResources/0,,50_2334_2452_11363,00.html
S: Supported
+ AMD IOMMU (AMD-VI)
+ P: Joerg Roedel
+ M: joerg.roedel@amd.com
+ L: iommu@lists.linux-foundation.org
+ S: Supported
+
AMS (Apple Motion Sensor) DRIVER
P: Stelian Pop
M: stelian@popies.net
S: Maintained
ARM PRIMECELL MMCI PL180/1 DRIVER
- P: Russell King
- M: rmk@arm.linux.org.uk
- L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
- S: Maintained
+ S: Orphan
ARM/ADI ROADRUNNER MACHINE SUPPORT
P: Lennert Buytenhek
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
S: Maintained
+ ARM/COMPULAB CM-X270/EM-X270 MACHINE SUPPORT
+ P: Mike Rapoport
+ M: mike@compulab.co.il
+ L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
+ S: Maintained
+
ARM/CORGI MACHINE SUPPORT
P: Richard Purdie
M: rpurdie@rpsys.net
S: Maintained
+ ARM/EZX SMARTPHONES (A780, A910, A1200, E680, ROKR E2 and ROKR E6)
+ P: Daniel Ribeiro
+ M: drwyrm@gmail.com
+ P: Stefan Schmidt
+ M: stefan@openezx.org
+ P: Harald Welte
+ M: laforge@openezx.org
+ L: openezx-devel@lists.openezx.org (subscribers-only)
+ W: http://www.openezx.org/
+ S: Maintained
+
+ ARM/FREESCALE IMX / MXC ARM ARCHITECTURE
+ P: Sascha Hauer
+ M: kernel@pengutronix.de
+ L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
+ S: Maintained
+
ARM/GLOMATION GESBC9312SX MACHINE SUPPORT
P: Lennert Buytenhek
M: kernel@wantstofly.org
S: Maintained
ARM/TOSA MACHINE SUPPORT
+ P: Dmitry Baryshkov
+ M: dbaryshkov@gmail.com
P: Dirk Opfer
M: dirk@opfer-online.de
S: Maintained
+ ARM/PALMTX SUPPORT
+ P: Marek Vasut
+ M: marek.vasut@gmail.com
+ W: http://hackndev.com
+ S: Maintained
+
ARM/PLEB SUPPORT
P: Peter Chubb
M: pleb@gelato.unsw.edu.au
L: linux-scsi@vger.kernel.org
S: Supported
+ BT8XXGPIO DRIVER
+ P: Michael Buesch
+ M: mb@bu3sch.de
+ W: http://bu3sch.de/btgpio.php
+ S: Maintained
+
BTTV VIDEO4LINUX DRIVER
P: Mauro Carvalho Chehab
M: mchehab@infradead.org
P: Scott Murray
M: scottm@somanetworks.com
M: scott@spiteful.org
- L: pcihpd-discuss@lists.sourceforge.net
+ L: linux-pci@vger.kernel.org
S: Supported
COMPACTPCI HOTPLUG ZIATECH ZT5550 DRIVER
P: Scott Murray
M: scottm@somanetworks.com
M: scott@spiteful.org
- L: pcihpd-discuss@lists.sourceforge.net
+ L: linux-pci@vger.kernel.org
S: Supported
COMPACTPCI HOTPLUG GENERIC DRIVER
P: Scott Murray
M: scottm@somanetworks.com
M: scott@spiteful.org
- L: pcihpd-discuss@lists.sourceforge.net
+ L: linux-pci@vger.kernel.org
S: Supported
+ COMPAL LAPTOP SUPPORT
+ P: Cezary Jackiewicz
+ M: cezary.jackiewicz@gmail.com
+ S: Maintained
+
COMPUTONE INTELLIPORT MULTIPORT CARD
P: Michael H. Warfield
M: mhw@wittsend.com
L: linux-kernel@vger.kernel.org
S: Maintained
+ FREESCALE I2C CPM DRIVER
+ P: Jochen Friedrich
+ M: jochen@scram.de
+ L: linuxppc-dev@ozlabs.org
+ L: i2c@lm-sensors.org
+ S: Maintained
+
FREESCALE SOC FS_ENET DRIVER
P: Pantelis Antoniou
M: pantelis.antoniou@gmail.com
W: ftp://ftp.openlinux.org/pub/people/hch/vxfs
S: Maintained
+ FTRACE
+ P: Steven Rostedt
+ M: srostedt@redhat.com
+ S: Maintained
+
FUJITSU FR-V (FRV) PORT
P: David Howells
M: dhowells@redhat.com
S: Maintained
+ FUJITSU LAPTOP EXTRAS
+ P: Jonathan Woithe
+ M: jwoithe@physics.adelaide.edu.au
+ L: linux-acpi@vger.kernel.org
+ S: Maintained
+
FUSE: FILESYSTEM IN USERSPACE
P: Miklos Szeredi
M: miklos@szeredi.hu
S: Maintained
HARDWARE MONITORING
- P: Mark M. Hoffman
- M: mhoffman@lightlink.com
L: lm-sensors@lm-sensors.org
W: http://www.lm-sensors.org/
- T: git lm-sensors.org:/kernel/mhoffman/hwmon-2.6.git testing
- T: git lm-sensors.org:/kernel/mhoffman/hwmon-2.6.git release
- S: Maintained
+ S: Orphaned
HARDWARE RANDOM NUMBER GENERATOR CORE
S: Orphaned
M: carlos@strangeworlds.co.uk
S: Odd Fixes
- HPET: High Precision Event Timers driver (hpet.c)
+ HPET: High Precision Event Timers driver (drivers/char/hpet.c)
P: Clemens Ladisch
M: clemens@ladisch.de
S: Maintained
W: http://artax.karlin.mff.cuni.cz/~mikulas/vyplody/hpfs/index-e.cgi
S: Maintained
+ HTCPEN TOUCHSCREEN DRIVER
+ P: Pau Oliva Fora
+ M: pof@eslack.org
+ L: linux-input@vger.kernel.org
+ S: Maintained
+
HUGETLB FILESYSTEM
P: William Irwin
M: wli@holomorphy.com
M: jesse.brandeburg@intel.com
P: Bruce Allan
M: bruce.w.allan@intel.com
+ P: PJ Waskiewicz
+ M: peter.p.waskiewicz.jr@intel.com
P: John Ronciak
M: john.ronciak@intel.com
L: e1000-devel@lists.sourceforge.net
W: http://www.linux-mtd.infradead.org/doc/jffs2.html
S: Maintained
+ UBI FILE SYSTEM (UBIFS)
+ P: Artem Bityutskiy
+ M: dedekind@infradead.org
+ P: Adrian Hunter
+ M: ext-adrian.hunter@nokia.com
+ L: linux-mtd@lists.infradead.org
+ T: git git://git.infradead.org/~dedekind/ubifs-2.6.git
+ W: http://www.linux-mtd.infradead.org/doc/ubifs.html
+ S: Maintained
+
JFS FILESYSTEM
P: Dave Kleikamp
M: shaggy@austin.ibm.com
L: linuxppc-dev@ozlabs.org
S: Maintained
- LINUX FOR POWERPC EMBEDDED MPC52XX
+ LINUX FOR POWERPC EMBEDDED MPC5XXX
P: Sylvain Munaut
M: tnt@246tNt.com
P: Grant Likely
M: grant.likely@secretlab.ca
- W: http://www.246tNt.com/mpc52xx/
- W: http://www.penguinppc.org/
L: linuxppc-dev@ozlabs.org
S: Maintained
S: Maintained
MARVELL MV643XX ETHERNET DRIVER
- P: Dale Farnsworth
- M: dale@farnsworth.org
- P: Manish Lachwani
- M: mlachwani@mvista.com
+ P: Lennert Buytenhek
+ M: buytenh@marvell.com
L: netdev@vger.kernel.org
- S: Odd Fixes for 2.4; Maintained for 2.6.
+ S: Supported
MATROX FRAMEBUFFER DRIVER
P: Petr Vandrovec
M: flatif@neteffect.com
P: Chien Tung
M: ctung@neteffect.com
- P: Glenn Streiff
- M: gstreiff@neteffect.com
L: general@lists.openfabrics.org
W: http://www.neteffect.com
S: Supported
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mfasheh/ocfs2.git
S: Supported
+ OMFS FILESYSTEM
+ P: Bob Copeland
+ M: me@bobcopeland.com
+ L: linux-karma-devel@lists.sourceforge.net
+ S: Maintained
+
OMNIKEY CARDMAN 4000 DRIVER
P: Harald Welte
M: laforge@gnumonks.org
PCIE HOTPLUG DRIVER
P: Kristen Carlson Accardi
M: kristen.c.accardi@intel.com
- L: pcihpd-discuss@lists.sourceforge.net
+ L: linux-pci@vger.kernel.org
S: Supported
PCMCIA SUBSYSTEM
T: git git.infradead.org/battery-2.6.git
S: Maintained
- POWERPC 4xx EMAC DRIVER
- P: Eugene Surovegin
- M: ebs@ebshome.net
- W: http://kernel.ebshome.net/emac/
- L: linuxppc-dev@ozlabs.org
- L: netdev@vger.kernel.org
- S: Maintained
-
PNP SUPPORT
P: Adam Belay
M: ambx1@neo.rr.com
S390 NETWORK DRIVERS
P: Ursula Braun
- M: ubraun@linux.vnet.ibm.com
+ M: ursula.braun@de.ibm.com
P: Frank Blaschka
M: blaschka@linux.vnet.ibm.com
M: linux390@de.ibm.com
S390 IUCV NETWORK LAYER
P: Ursula Braun
- M: ubraun@linux.vnet.ibm.com
+ M: ursula.braun@de.ibm.com
M: linux390@de.ibm.com
L: linux-s390@vger.kernel.org
W: http://www.ibm.com/developerworks/linux/linux390/
S: Supported
+ S3C24XX SD/MMC Driver
+ P: Ben Dooks
+ M: ben-linux@fluff.org
+ L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
+ L: linux-kernel@vger.kernel.org
+ S: Supported
+
SAA7146 VIDEO4LINUX-2 DRIVER
P: Michael Hunold
M: michael@mihu.de
M: jim.cromie@gmail.com
S: Maintained
+ SDRICOH_CS MMC/SD HOST CONTROLLER INTERFACE DRIVER
+ P: Sascha Sommer
+ M: saschasommer@freenet.de
+ L: sdricohcs-devel@lists.sourceforge.net (subscribers-only)
+ S: Maintained
+
SECURITY CONTACT
P: Security Officers
M: security@kernel.org
M: bn@niasdigital.com
S: Maintained
+ SOC-CAMERA V4L2 SUBSYSTEM
+ P: Guennadi Liakhovetski
+ M: g.liakhovetski@gmx.de
+ L: video4linux-list@redhat.com
+ S: Maintained
+
SOFTWARE RAID (Multiple Disks) SUPPORT
P: Ingo Molnar
M: mingo@redhat.com
SHPC HOTPLUG DRIVER
P: Kristen Carlson Accardi
M: kristen.c.accardi@intel.com
- L: pcihpd-discuss@lists.sourceforge.net
+ L: linux-pci@vger.kernel.org
S: Supported
SECURE DIGITAL HOST CONTROLLER INTERFACE DRIVER
L: linux-sh@vger.kernel.org
W: http://www.linux-sh.org
T: git kernel.org:/pub/scm/linux/kernel/git/lethal/sh-2.6.git
- S: Maintained
+ S: Supported
SUN3/3X
P: Sam Creasey
TI OMAP MMC INTERFACE DRIVER
P: Carlos Aguiar, Anderson Briglia and Syed Khasim
-M: linux-omap-open-source@linux.omap.com (subscribers only)
+M: linux-omap@vger.kernel.org
W: http://linux.omap.com
W: http://www.muru.com/linux/omap/
S: Maintained
S: Maintained
TPM DEVICE DRIVER
- P: Debora Velarde
- P: Rajiv Andrade
- M: tpmdd-devel@lists.sourceforge.net
+ P: Debora Velarde
+ M: debora@linux.vnet.ibm.com
+ P: Rajiv Andrade
+ M: srajiv@linux.vnet.ibm.com
W: http://tpmdd.sourceforge.net
P: Marcel Selhorst
M: tpm@selhorst.net
L: tpmdd-devel@lists.sourceforge.net
S: Maintained
- TRIDENT 4DWAVE/SIS 7018 PCI AUDIO CORE
- P: Muli Ben-Yehuda
- M: mulix@mulix.org
- L: linux-kernel@vger.kernel.org
- S: Maintained
-
TRIVIAL PATCHES
P: Jesper Juhl
M: trivial@kernel.org
L: uclinux-dev@uclinux.org (subscribers-only)
S: Maintained
- UCLINUX FOR NEC V850
- P: Miles Bader
-
UCLINUX FOR RENESAS H8/300
P: Yoshinori Sato
M: ysato@users.sourceforge.jp
L: netdev@vger.kernel.org
S: Maintained
+ VOLTAGE AND CURRENT REGULATOR FRAMEWORK
+ P: Liam Girdwood
+ M: lg@opensource.wolfsonmicro.com
+ P: Mark Brown
+ M: broonie@opensource.wolfsonmicro.com
+ W: http://opensource.wolfsonmicro.com/node/15
+ T: git kernel.org/pub/scm/linux/kernel/git/lrg/voltage-2.6.git
+ S: Supported
+
VT1211 HARDWARE MONITOR DRIVER
P: Juerg Haefliger
M: juergh@gmail.com
VERSION = 2
PATCHLEVEL = 6
- SUBLEVEL = 26
- EXTRAVERSION =
+ SUBLEVEL = 27
+ EXTRAVERSION = -rc2
NAME = Rotary Wombat
# *DOCUMENTATION*
# o print "Entering directory ...";
MAKEFLAGS += -rR --no-print-directory
+# Add custom flags here to avoid conflict with updates
+EXTRAVERSION := $(EXTRAVERSION)-omap1
+
# We are using a recursive build, so we need to do a little thinking
# to get the ordering right.
#
-e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
-e s/sh.*/sh/ )
+SUBARCH := arm
+
# Cross compiling and selecting different set of gcc/bin-utils
# ---------------------------------------------------------------------------
#
# Note: Some architectures assign CROSS_COMPILE in their arch/*/Makefile
export KBUILD_BUILDHOST := $(SUBARCH)
ARCH ?= $(SUBARCH)
-CROSS_COMPILE ?=
+CROSS_COMPILE ?= arm-linux-
# Architecture as present in compile.h
UTS_MACHINE := $(ARCH)
SRCARCH := x86
endif
+ # Where to locate arch specific headers
+ ifeq ($(ARCH),sparc64)
+ hdr-arch := sparc
+ else
+ hdr-arch := $(SRCARCH)
+ endif
+
KCONFIG_CONFIG ?= .config
# SHELL used by kbuild
# Needed to be compatible with the O= option
LINUXINCLUDE := -Iinclude \
$(if $(KBUILD_SRC),-Iinclude2 -I$(srctree)/include) \
- -include include/linux/autoconf.h
+ -I$(srctree)/arch/$(hdr-arch)/include \
+ -include include/linux/autoconf.h
KBUILD_CPPFLAGS := -D__KERNEL__ $(LINUXINCLUDE)
# Objects we will link into vmlinux / subdirs we need to visit
init-y := init/
- drivers-y := drivers/ sound/
+ drivers-y := drivers/ sound/ firmware/
net-y := net/
libs-y := lib/
core-y := usr/
KBUILD_CFLAGS += -O2
endif
+ include $(srctree)/arch/$(SRCARCH)/Makefile
+
ifneq (CONFIG_FRAME_WARN,0)
KBUILD_CFLAGS += $(call cc-option,-Wframe-larger-than=${CONFIG_FRAME_WARN})
endif
# Arch Makefiles may override this setting
KBUILD_CFLAGS += $(call cc-option, -fno-stack-protector)
- include $(srctree)/arch/$(SRCARCH)/Makefile
-
ifdef CONFIG_FRAME_POINTER
KBUILD_CFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls
else
KBUILD_AFLAGS += -gdwarf-2
endif
+ ifdef CONFIG_FTRACE
+ KBUILD_CFLAGS += -pg
+ endif
+
# We trigger additional mismatches with less inlining
ifdef CONFIG_DEBUG_SECTION_MISMATCH
KBUILD_CFLAGS += $(call cc-option, -fno-inline-functions-called-once)
/bin/false; \
fi;
$(Q)if [ ! -d include2 ]; then mkdir -p include2; fi;
- $(Q)ln -fsn $(srctree)/include/asm-$(SRCARCH) include2/asm
+ $(Q)if [ -e $(srctree)/include/asm-$(SRCARCH)/errno.h ]; then \
+ ln -fsn $(srctree)/include/asm-$(SRCARCH) include2/asm; \
+ fi
endif
# prepare2 creates a makefile if using a separate output directory
# The asm symlink changes when $(ARCH) changes.
# Detect this and ask user to run make mrproper
-
- include/asm: FORCE
- $(Q)set -e; asmlink=`readlink include/asm | cut -d '-' -f 2`; \
- if [ -L include/asm ]; then \
- if [ "$$asmlink" != "$(SRCARCH)" ]; then \
+ define check-symlink
+ set -e; \
+ if [ -L include/asm ]; then \
+ asmlink=`readlink include/asm | cut -d '-' -f 2`; \
+ if [ "$$asmlink" != "$(SRCARCH)" ]; then \
echo "ERROR: the symlink $@ points to asm-$$asmlink but asm-$(SRCARCH) was expected"; \
echo " set ARCH or save .config and run 'make mrproper' to fix it"; \
- exit 1; \
- fi; \
- else \
- echo ' SYMLINK $@ -> include/asm-$(SRCARCH)'; \
- if [ ! -d include ]; then \
- mkdir -p include; \
- fi; \
- ln -fsn asm-$(SRCARCH) $@; \
+ exit 1; \
+ fi; \
fi
+ endef
+
+ # We create the target directory of the symlink if it does
+ # not exist so the test in chack-symlink works and we have a
+ # directory for generated filesas used by some architectures.
+ define create-symlink
+ if [ ! -L include/asm ]; then \
+ echo ' SYMLINK $@ -> include/asm-$(SRCARCH)'; \
+ if [ ! -d include/asm-$(SRCARCH) ]; then \
+ mkdir -p include/asm-$(SRCARCH); \
+ fi; \
+ ln -fsn asm-$(SRCARCH) $@; \
+ fi
+ endef
+
+ include/asm: FORCE
+ $(Q)$(check-symlink)
+ $(Q)$(create-symlink)
# Generate some files
# ---------------------------------------------------------------------------
depend dep:
@echo '*** Warning: make $@ is unnecessary now.'
+ # ---------------------------------------------------------------------------
+ # Firmware install
+ INSTALL_FW_PATH=$(INSTALL_MOD_PATH)/lib/firmware
+ export INSTALL_FW_PATH
+
+ PHONY += firmware_install
+ firmware_install: FORCE
+ @mkdir -p $(objtree)/firmware
+ $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.fwinst obj=firmware __fw_install
+
# ---------------------------------------------------------------------------
# Kernel headers
- INSTALL_HDR_PATH=$(objtree)/usr
- export INSTALL_HDR_PATH
- HDRFILTER=generic i386 x86_64
- HDRARCHES=$(filter-out $(HDRFILTER),$(patsubst $(srctree)/include/asm-%/Kbuild,%,$(wildcard $(srctree)/include/asm-*/Kbuild)))
+ #Default location for installed headers
+ export INSTALL_HDR_PATH = $(objtree)/usr
- PHONY += headers_install_all
- headers_install_all: include/linux/version.h scripts_basic FORCE
+ hdr-inst := -rR -f $(srctree)/scripts/Makefile.headersinst obj
+ # Find out where the Kbuild file is located to support
+ # arch/$(ARCH)/include/asm
+ hdr-dir = $(strip \
+ $(if $(wildcard $(srctree)/arch/$(hdr-arch)/include/asm/Kbuild), \
+ arch/$(hdr-arch)/include/asm, include/asm-$(hdr-arch)))
+
+ # If we do an all arch process set dst to asm-$(hdr-arch)
+ hdr-dst = $(if $(KBUILD_HEADERS), dst=include/asm-$(hdr-arch), dst=include/asm)
+
+ PHONY += __headers
+ __headers: include/linux/version.h scripts_basic FORCE
$(Q)$(MAKE) $(build)=scripts scripts/unifdef
- $(Q)for arch in $(HDRARCHES); do \
- $(MAKE) ARCH=$$arch -f $(srctree)/scripts/Makefile.headersinst obj=include BIASMDIR=-bi-$$arch ;\
- done
+
+ PHONY += headers_install_all
+ headers_install_all:
+ $(Q)$(CONFIG_SHELL) $(srctree)/scripts/headers.sh install
PHONY += headers_install
- headers_install: include/linux/version.h scripts_basic FORCE
- @if [ ! -r $(srctree)/include/asm-$(SRCARCH)/Kbuild ]; then \
- echo '*** Error: Headers not exportable for this architecture ($(SRCARCH))'; \
- exit 1 ; fi
- $(Q)$(MAKE) $(build)=scripts scripts/unifdef
- $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.headersinst ARCH=$(SRCARCH) obj=include
+ headers_install: __headers
+ $(if $(wildcard $(srctree)/$(hdr-dir)/Kbuild),, \
+ $(error Headers not exportable for the $(SRCARCH) architecture))
+ $(Q)$(MAKE) $(hdr-inst)=include
+ $(Q)$(MAKE) $(hdr-inst)=$(hdr-dir) $(hdr-dst)
PHONY += headers_check_all
headers_check_all: headers_install_all
- $(Q)for arch in $(HDRARCHES); do \
- $(MAKE) ARCH=$$arch -f $(srctree)/scripts/Makefile.headersinst obj=include BIASMDIR=-bi-$$arch HDRCHECK=1 ;\
- done
+ $(Q)$(CONFIG_SHELL) $(srctree)/scripts/headers.sh check
PHONY += headers_check
headers_check: headers_install
- $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.headersinst ARCH=$(SRCARCH) obj=include HDRCHECK=1
+ $(Q)$(MAKE) $(hdr-inst)=include HDRCHECK=1
+ $(Q)$(MAKE) $(hdr-inst)=$(hdr-dir) $(hdr-dst) HDRCHECK=1
# ---------------------------------------------------------------------------
# Modules
$(Q)$(AWK) '!x[$$0]++' $(vmlinux-dirs:%=$(objtree)/%/modules.order) > $(objtree)/modules.order
@echo ' Building modules, stage 2.';
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost
+ $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.fwinst obj=firmware __fw_modbuild
# Target to prepare building external modules
# boot script depmod is the master version.
PHONY += _modinst_post
_modinst_post: _modinst_
+ $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.fwinst obj=firmware __fw_modinst
$(call cmd,depmod)
else # CONFIG_MODULES
include/linux/autoconf.h include/linux/version.h \
include/linux/utsrelease.h \
include/linux/bounds.h include/asm*/asm-offsets.h \
- Module.symvers tags TAGS cscope*
+ Module.symvers Module.markers tags TAGS cscope*
# clean - Delete most, but leave enough to build external modules
#
@find . $(RCS_FIND_IGNORE) \
\( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \
-o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \
- -o -name '*.symtypes' -o -name 'modules.order' \) \
+ -o -name '*.symtypes' -o -name 'modules.order' \
+ -o -name 'Module.markers' -o -name '.tmp_*.o.*' \) \
-type f -print | xargs rm -f
# mrproper - Delete all generated files, including .config
@echo '* vmlinux - Build the bare kernel'
@echo '* modules - Build all modules'
@echo ' modules_install - Install all modules to INSTALL_MOD_PATH (default: /)'
+ @echo ' firmware_install- Install all firmware to INSTALL_FW_PATH'
+ @echo ' (default: $$(INSTALL_MOD_PATH)/lib/firmware)'
@echo ' dir/ - Build all files in dir and below'
@echo ' dir/file.[ois] - Build specified target only'
@echo ' dir/file.ko - Build module including final link'
@echo ' cscope - Generate cscope index'
@echo ' kernelrelease - Output the release version string'
@echo ' kernelversion - Output the version stored in Makefile'
- @if [ -r $(srctree)/include/asm-$(SRCARCH)/Kbuild ]; then \
- echo ' headers_install - Install sanitised kernel headers to INSTALL_HDR_PATH'; \
+ @echo ' headers_install - Install sanitised kernel headers to INSTALL_HDR_PATH'; \
echo ' (default: $(INSTALL_HDR_PATH))'; \
- fi
- @echo ''
+ echo ''
@echo 'Static analysers'
@echo ' checkstack - Generate a list of stack hogs'
@echo ' namespacecheck - Name space analysis on compiled kernel'
@echo ' versioncheck - Sanity check on version.h usage'
@echo ' includecheck - Check for duplicate included header files'
@echo ' export_report - List the usages of all exported symbols'
- @if [ -r $(srctree)/include/asm-$(SRCARCH)/Kbuild ]; then \
- echo ' headers_check - Sanity check on exported headers'; \
- fi
- @echo ''
+ @echo ' headers_check - Sanity check on exported headers'; \
+ echo ''
@echo 'Kernel packaging:'
@$(MAKE) $(build)=$(package-dir) help
@echo ''
\( -name config -o -name 'asm-*' \) -prune \
-o -name $1 -print; \
for arch in $(ALLINCLUDE_ARCHS) ; do \
- find $(__srctree)include/asm-$${arch} $(RCS_FIND_IGNORE) \
+ test -e $(__srctree)include/asm-$${arch} && \
+ find $(__srctree)include/asm-$${arch} $(RCS_FIND_IGNORE) \
+ -name $1 -print; \
+ test -e $(__srctree)arch/$${arch}/include/asm && \
+ find $(__srctree)arch/$${arch}/include/asm $(RCS_FIND_IGNORE) \
-name $1 -print; \
done ; \
find $(__srctree)include/asm-generic $(RCS_FIND_IGNORE) \
select RTC_LIB
select SYS_SUPPORTS_APM_EMULATION
select HAVE_OPROFILE
+ select HAVE_ARCH_KGDB
select HAVE_KPROBES if (!XIP_KERNEL)
select HAVE_KRETPROBES if (HAVE_KPROBES)
+ select HAVE_FTRACE if (!XIP_KERNEL)
+ select HAVE_DYNAMIC_FTRACE if (HAVE_FTRACE)
+ select HAVE_GENERIC_DMA_COHERENT
help
The ARM series is a line of low-power-consumption RISC chip designs
licensed by ARM Ltd and targeted at embedded applications and
Europe. There is an ARM Linux project with a web page at
<http://www.arm.linux.org.uk/>.
+ config HAVE_PWM
+ bool
+
config SYS_SUPPORTS_APM_EMULATION
bool
bool
default y
+ config HAVE_LATENCYTOP_SUPPORT
+ bool
+ depends on !SMP
+ default y
+
config LOCKDEP_SUPPORT
bool
default y
config ARCH_MTD_XIP
bool
+ config GENERIC_HARDIRQS_NO__DO_IRQ
+ bool
+ def_bool y
+
if OPROFILE
config OPROFILE_ARMV6
config ARCH_AAEC2000
bool "Agilent AAEC-2000 based"
select ARM_AMBA
+ select HAVE_CLK
help
This enables support for systems based on the Agilent AAEC-2000
config ARCH_INTEGRATOR
bool "ARM Ltd. Integrator family"
select ARM_AMBA
+ select HAVE_CLK
select ICST525
help
Support for ARM's Integrator platform.
config ARCH_REALVIEW
bool "ARM Ltd. RealView family"
select ARM_AMBA
+ select HAVE_CLK
select ICST307
select GENERIC_TIME
select GENERIC_CLOCKEVENTS
bool "ARM Ltd. Versatile family"
select ARM_AMBA
select ARM_VIC
+ select HAVE_CLK
select ICST307
select GENERIC_TIME
select GENERIC_CLOCKEVENTS
config ARCH_AT91
bool "Atmel AT91"
select GENERIC_GPIO
+ select HAVE_CLK
help
This enables support for systems based on the Atmel AT91RM9200,
AT91SAM9 and AT91CAP9 processors.
help
Support for Cirrus Logic 711x/721x based boards.
- config ARCH_CO285
- bool "Co-EBSA285"
- select FOOTBRIDGE
- select FOOTBRIDGE_ADDIN
- help
- Support for Intel's EBSA285 companion chip.
-
config ARCH_EBSA110
bool "EBSA-110"
select ISA
select ARM_AMBA
select ARM_VIC
select GENERIC_GPIO
- select HAVE_GPIO_LIB
+ select HAVE_CLK
+ select ARCH_REQUIRE_GPIOLIB
help
This enables support for the Cirrus EP93xx series of CPUs.
depends on MMU
select PLAT_IOP
select PCI
+ select GENERIC_GPIO
+ select ARCH_REQUIRE_GPIOLIB
help
Support for Intel's 80219 and IOP32X (XScale) family of
processors.
depends on MMU
select PLAT_IOP
select PCI
+ select GENERIC_GPIO
+ select ARCH_REQUIRE_GPIOLIB
help
Support for Intel's IOP33X (XScale) family of processors.
If you have any questions or comments about the Linux kernel port
to this board, send e-mail to <sjhill@cotw.com>.
+ config ARCH_KIRKWOOD
+ bool "Marvell Kirkwood"
+ select PCI
+ select GENERIC_TIME
+ select GENERIC_CLOCKEVENTS
+ select PLAT_ORION
+ help
+ Support for the following Marvell Kirkwood series SoCs:
+ 88F6180, 88F6192 and 88F6281.
+
config ARCH_KS8695
bool "Micrel/Kendin KS8695"
select GENERIC_GPIO
select GENERIC_GPIO
select GENERIC_TIME
select GENERIC_CLOCKEVENTS
+ select HAVE_CLK
help
Say Y here if you intend to run this kernel on a NetSilicon NS9xxx
System.
<http://www.digi.com/products/microprocessors/index.jsp>
+ config ARCH_LOKI
+ bool "Marvell Loki (88RC8480)"
+ select GENERIC_TIME
+ select GENERIC_CLOCKEVENTS
+ select PLAT_ORION
+ help
+ Support for the Marvell Loki (88RC8480) SoC.
+
+ config ARCH_MV78XX0
+ bool "Marvell MV78xx0"
+ select PCI
+ select GENERIC_TIME
+ select GENERIC_CLOCKEVENTS
+ select PLAT_ORION
+ help
+ Support for the following Marvell MV78xx0 series SoCs:
+ MV781x0, MV782x0.
+
config ARCH_MXC
bool "Freescale MXC/iMX-based"
+ select GENERIC_TIME
+ select GENERIC_CLOCKEVENTS
select ARCH_MTD_XIP
+ select GENERIC_GPIO
+ select ARCH_REQUIRE_GPIOLIB
help
Support for Freescale MXC/iMX-based family of processors
select PLAT_ORION
help
Support for the following Marvell Orion 5x series SoCs:
- Orion-1 (5181), Orion-NAS (5182), Orion-2 (5281.)
+ Orion-1 (5181), Orion-VoIP (5181L), Orion-NAS (5182),
+ Orion-2 (5281).
config ARCH_PNX4008
bool "Philips Nexperia PNX4008 Mobile"
+ select HAVE_CLK
help
This enables support for Philips PNX4008 mobile platform.
depends on MMU
select ARCH_MTD_XIP
select GENERIC_GPIO
- select HAVE_GPIO_LIB
+ select HAVE_CLK
+ select ARCH_REQUIRE_GPIOLIB
select GENERIC_TIME
select GENERIC_CLOCKEVENTS
select TICK_ONESHOT
select FIQ
select TIMER_ACORN
select ARCH_MAY_HAVE_PC_FDC
+ select HAVE_PATA_PLATFORM
select ISA_DMA_API
select NO_IOPORT
help
select GENERIC_GPIO
select GENERIC_TIME
select GENERIC_CLOCKEVENTS
+ select HAVE_CLK
select TICK_ONESHOT
- select HAVE_GPIO_LIB
+ select ARCH_REQUIRE_GPIOLIB
help
Support for StrongARM 11x0 based boards.
config ARCH_S3C2410
bool "Samsung S3C2410, S3C2412, S3C2413, S3C2440, S3C2442, S3C2443"
select GENERIC_GPIO
+ select HAVE_CLK
help
Samsung S3C2410X CPU based systems, such as the Simtec Electronics
BAST (<http://www.simtec.co.uk/products/EB110ITX/>), the IPAQ 1940 or
select GENERIC_TIME
select GENERIC_CLOCKEVENTS
select GENERIC_GPIO
+ select HAVE_CLK
help
Support for TI's DaVinci platform.
config ARCH_OMAP
bool "TI OMAP"
select GENERIC_GPIO
- select HAVE_GPIO_LIB
+ select HAVE_CLK
+ select ARCH_REQUIRE_GPIOLIB
select GENERIC_TIME
select GENERIC_CLOCKEVENTS
help
source "arch/arm/mach-ixp23xx/Kconfig"
+ source "arch/arm/mach-loki/Kconfig"
+
+ source "arch/arm/mach-mv78xx0/Kconfig"
+
source "arch/arm/mach-pxa/Kconfig"
source "arch/arm/mach-sa1100/Kconfig"
source "arch/arm/mach-orion5x/Kconfig"
+ source "arch/arm/mach-kirkwood/Kconfig"
+
source "arch/arm/plat-s3c24xx/Kconfig"
source "arch/arm/plat-s3c/Kconfig"
config SMP
bool "Symmetric Multi-Processing (EXPERIMENTAL)"
depends on EXPERIMENTAL && (REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP)
+ select USE_GENERIC_SMP_HELPERS
help
This enables support for systems with more than one CPU. If you have
a system with only one CPU, like most personal computers, say N. If
Say Y here if you are building a kernel for a desktop, embedded
or real-time system. Say N if you are unsure.
- config NO_IDLE_HZ
- bool "Dynamic tick timer"
- depends on !GENERIC_CLOCKEVENTS
- help
- Select this option if you want to disable continuous timer ticks
- and have them programmed to occur as required. This option saves
- power as the system can remain in idle state for longer.
-
- By default dynamic tick is disabled during the boot, and can be
- manually enabled with:
-
- echo 1 > /sys/devices/system/timer/timer0/dyn_tick
-
- Alternatively, if you want dynamic tick automatically enabled
- during boot, pass "dyntick=enable" via the kernel command string.
-
- Please note that dynamic tick may affect the accuracy of
- timekeeping on some platforms depending on the implementation.
- Currently at least OMAP, PXA2xx and SA11x0 platforms are known
- to have accurate timekeeping with dynamic tick.
-
config HZ
int
default 128 if ARCH_L7200
config LEDS
bool "Timer and CPU usage LEDs"
- depends on ARCH_CDB89712 || ARCH_CO285 || ARCH_EBSA110 || \
+ depends on ARCH_CDB89712 || ARCH_EBSA110 || \
ARCH_EBSA285 || ARCH_IMX || ARCH_INTEGRATOR || \
ARCH_LUBBOCK || MACH_MAINSTONE || ARCH_NETWINDER || \
ARCH_OMAP || ARCH_P720T || ARCH_PXA_IDP || \
source "drivers/dca/Kconfig"
+ source "drivers/regulator/Kconfig"
+
source "drivers/uio/Kconfig"
+if ARCH_OMAP
+source "drivers/cbus/Kconfig"
+source "drivers/dsp/dspgateway/Kconfig"
+endif
+
endmenu
source "fs/Kconfig"
tune-$(CONFIG_CPU_ARM740T) :=-mtune=arm7tdmi
tune-$(CONFIG_CPU_ARM9TDMI) :=-mtune=arm9tdmi
tune-$(CONFIG_CPU_ARM940T) :=-mtune=arm9tdmi
- tune-$(CONFIG_CPU_ARM946T) :=$(call cc-option,-mtune=arm9e,-mtune=arm9tdmi)
+ tune-$(CONFIG_CPU_ARM946E) :=$(call cc-option,-mtune=arm9e,-mtune=arm9tdmi)
tune-$(CONFIG_CPU_ARM920T) :=-mtune=arm9tdmi
tune-$(CONFIG_CPU_ARM922T) :=-mtune=arm9tdmi
tune-$(CONFIG_CPU_ARM925T) :=-mtune=arm9tdmi
incdir-$(CONFIG_ARCH_CLPS7500) := cl7500
machine-$(CONFIG_FOOTBRIDGE) := footbridge
incdir-$(CONFIG_FOOTBRIDGE) := ebsa285
- machine-$(CONFIG_ARCH_CO285) := footbridge
- incdir-$(CONFIG_ARCH_CO285) := ebsa285
machine-$(CONFIG_ARCH_SHARK) := shark
machine-$(CONFIG_ARCH_SA1100) := sa1100
ifeq ($(CONFIG_ARCH_SA1100),y)
machine-$(CONFIG_ARCH_IXP23XX) := ixp23xx
machine-$(CONFIG_ARCH_OMAP1) := omap1
machine-$(CONFIG_ARCH_OMAP2) := omap2
+ machine-$(CONFIG_ARCH_OMAP3) := omap2
incdir-$(CONFIG_ARCH_OMAP) := omap
machine-$(CONFIG_ARCH_S3C2410) := s3c2410
machine-$(CONFIG_ARCH_LH7A40X) := lh7a40x
machine-$(CONFIG_ARCH_NETX) := netx
machine-$(CONFIG_ARCH_NS9XXX) := ns9xxx
machine-$(CONFIG_ARCH_DAVINCI) := davinci
+ machine-$(CONFIG_ARCH_KIRKWOOD) := kirkwood
machine-$(CONFIG_ARCH_KS8695) := ks8695
incdir-$(CONFIG_ARCH_MXC) := mxc
+ machine-$(CONFIG_ARCH_MX2) := mx2
machine-$(CONFIG_ARCH_MX3) := mx3
machine-$(CONFIG_ARCH_ORION5X) := orion5x
machine-$(CONFIG_ARCH_MSM7X00A) := msm
+ machine-$(CONFIG_ARCH_LOKI) := loki
+ machine-$(CONFIG_ARCH_MV78XX0) := mv78xx0
ifeq ($(CONFIG_ARCH_EBSA110),y)
# This is what happens if you forget the IOCS16 line.
core-$(CONFIG_ARCH_MXC) += arch/arm/plat-mxc/
drivers-$(CONFIG_OPROFILE) += arch/arm/oprofile/
- drivers-$(CONFIG_ARCH_CLPS7500) += drivers/acorn/char/
- drivers-$(CONFIG_ARCH_L7200) += drivers/acorn/char/
libs-y := arch/arm/lib/ $(libs-y)
OBJS += head-sharpsl.o
endif
+ifeq ($(CONFIG_MACH_OMAP_PERSEUS2),y)
+OBJS += head-omap.o
+endif
+
ifeq ($(CONFIG_CPU_BIG_ENDIAN),y)
ifeq ($(CONFIG_CPU_CP15),y)
OBJS += big-endian.o
targets := vmlinux vmlinux.lds piggy.gz piggy.o font.o font.c \
head.o misc.o $(OBJS)
+
+ ifeq ($(CONFIG_FTRACE),y)
+ ORIG_CFLAGS := $(KBUILD_CFLAGS)
+ KBUILD_CFLAGS = $(subst -pg, , $(ORIG_CFLAGS))
+ endif
+
EXTRA_CFLAGS := -fpic -fno-builtin
EXTRA_AFLAGS :=
$(obj)/vmlinux.lds: $(obj)/vmlinux.lds.in arch/arm/boot/Makefile .config
@sed "$(SEDFLAGS)" < $< > $@
-
- $(obj)/misc.o: $(obj)/misc.c include/asm/arch/uncompress.h lib/inflate.c
-
#elif defined(CONFIG_ARCH_S3C2410)
.macro loadsp, rb
mov \rb, #0x50000000
- add \rb, \rb, #0x4000 * CONFIG_S3C_LOWLEVEL_UART_PORT
+ add \rb, \rb, #0x4000 * CONFIG_S3C2410_LOWLEVEL_UART_PORT
.endm
#else
.macro loadsp, rb
b __armv4_mmu_cache_off
b __armv4_mmu_cache_flush
- .word 0x56055310 @ Feroceon
- .word 0xfffffff0
+ .word 0x56050000 @ Feroceon
+ .word 0xff0f0000
b __armv4_mmu_cache_on
b __armv4_mmu_cache_off
b __armv5tej_mmu_cache_flush
mcr p15, 0, r10, c7, c14, 0 @ clean+invalidate D
b iflush
hierarchical:
+ adr sp, no_cache_id @ non-v7 code is temp stack
stmfd sp!, {r0-r5, r7, r9-r11}
mrc p15, 1, r0, c0, c0, 1 @ read clidr
ands r3, r0, #0x7000000 @ extract loc from clidr
--- /dev/null
+ /*
+ * arch/arm/include/asm/pgtable.h
+ *
+ * Copyright (C) 1995-2002 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.
+ */
+ #ifndef _ASMARM_PGTABLE_H
+ #define _ASMARM_PGTABLE_H
+
+ #include <asm-generic/4level-fixup.h>
+ #include <asm/proc-fns.h>
+
+ #ifndef CONFIG_MMU
+
+ #include "pgtable-nommu.h"
+
+ #else
+
+ #include <asm/memory.h>
+ #include <asm/arch/vmalloc.h>
+ #include <asm/pgtable-hwdef.h>
+
+ /*
+ * Just any arbitrary offset to the start of the vmalloc VM area: the
+ * current 8MB value just means that there will be a 8MB "hole" after the
+ * physical memory until the kernel virtual memory starts. That means that
+ * any out-of-bounds memory accesses will hopefully be caught.
+ * The vmalloc() routines leaves a hole of 4kB between each vmalloced
+ * area for the same reason. ;)
+ *
+ * Note that platforms may override VMALLOC_START, but they must provide
+ * VMALLOC_END. VMALLOC_END defines the (exclusive) limit of this space,
+ * which may not overlap IO space.
+ */
+ #ifndef VMALLOC_START
+ #define VMALLOC_OFFSET (8*1024*1024)
+ #define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+ #endif
+
+ /*
+ * Hardware-wise, we have a two level page table structure, where the first
+ * level has 4096 entries, and the second level has 256 entries. Each entry
+ * is one 32-bit word. Most of the bits in the second level entry are used
+ * by hardware, and there aren't any "accessed" and "dirty" bits.
+ *
+ * Linux on the other hand has a three level page table structure, which can
+ * be wrapped to fit a two level page table structure easily - using the PGD
+ * and PTE only. However, Linux also expects one "PTE" table per page, and
+ * at least a "dirty" bit.
+ *
+ * Therefore, we tweak the implementation slightly - we tell Linux that we
+ * have 2048 entries in the first level, each of which is 8 bytes (iow, two
+ * hardware pointers to the second level.) The second level contains two
+ * hardware PTE tables arranged contiguously, followed by Linux versions
+ * which contain the state information Linux needs. We, therefore, end up
+ * with 512 entries in the "PTE" level.
+ *
+ * This leads to the page tables having the following layout:
+ *
+ * pgd pte
+ * | |
+ * +--------+ +0
+ * | |-----> +------------+ +0
+ * +- - - - + +4 | h/w pt 0 |
+ * | |-----> +------------+ +1024
+ * +--------+ +8 | h/w pt 1 |
+ * | | +------------+ +2048
+ * +- - - - + | Linux pt 0 |
+ * | | +------------+ +3072
+ * +--------+ | Linux pt 1 |
+ * | | +------------+ +4096
+ *
+ * See L_PTE_xxx below for definitions of bits in the "Linux pt", and
+ * PTE_xxx for definitions of bits appearing in the "h/w pt".
+ *
+ * PMD_xxx definitions refer to bits in the first level page table.
+ *
+ * The "dirty" bit is emulated by only granting hardware write permission
+ * iff the page is marked "writable" and "dirty" in the Linux PTE. This
+ * means that a write to a clean page will cause a permission fault, and
+ * the Linux MM layer will mark the page dirty via handle_pte_fault().
+ * For the hardware to notice the permission change, the TLB entry must
+ * be flushed, and ptep_set_access_flags() does that for us.
+ *
+ * The "accessed" or "young" bit is emulated by a similar method; we only
+ * allow accesses to the page if the "young" bit is set. Accesses to the
+ * page will cause a fault, and handle_pte_fault() will set the young bit
+ * for us as long as the page is marked present in the corresponding Linux
+ * PTE entry. Again, ptep_set_access_flags() will ensure that the TLB is
+ * up to date.
+ *
+ * However, when the "young" bit is cleared, we deny access to the page
+ * by clearing the hardware PTE. Currently Linux does not flush the TLB
+ * for us in this case, which means the TLB will retain the transation
+ * until either the TLB entry is evicted under pressure, or a context
+ * switch which changes the user space mapping occurs.
+ */
+ #define PTRS_PER_PTE 512
+ #define PTRS_PER_PMD 1
+ #define PTRS_PER_PGD 2048
+
+ /*
+ * PMD_SHIFT determines the size of the area a second-level page table can map
+ * PGDIR_SHIFT determines what a third-level page table entry can map
+ */
+ #define PMD_SHIFT 21
+ #define PGDIR_SHIFT 21
+
+ #define LIBRARY_TEXT_START 0x0c000000
+
+ #ifndef __ASSEMBLY__
+ extern void __pte_error(const char *file, int line, unsigned long val);
+ extern void __pmd_error(const char *file, int line, unsigned long val);
+ extern void __pgd_error(const char *file, int line, unsigned long val);
+
+ #define pte_ERROR(pte) __pte_error(__FILE__, __LINE__, pte_val(pte))
+ #define pmd_ERROR(pmd) __pmd_error(__FILE__, __LINE__, pmd_val(pmd))
+ #define pgd_ERROR(pgd) __pgd_error(__FILE__, __LINE__, pgd_val(pgd))
+ #endif /* !__ASSEMBLY__ */
+
+ #define PMD_SIZE (1UL << PMD_SHIFT)
+ #define PMD_MASK (~(PMD_SIZE-1))
+ #define PGDIR_SIZE (1UL << PGDIR_SHIFT)
+ #define PGDIR_MASK (~(PGDIR_SIZE-1))
+
+ /*
+ * This is the lowest virtual address we can permit any user space
+ * mapping to be mapped at. This is particularly important for
+ * non-high vector CPUs.
+ */
+ #define FIRST_USER_ADDRESS PAGE_SIZE
+
+ #define FIRST_USER_PGD_NR 1
+ #define USER_PTRS_PER_PGD ((TASK_SIZE/PGDIR_SIZE) - FIRST_USER_PGD_NR)
+
+ /*
+ * section address mask and size definitions.
+ */
+ #define SECTION_SHIFT 20
+ #define SECTION_SIZE (1UL << SECTION_SHIFT)
+ #define SECTION_MASK (~(SECTION_SIZE-1))
+
+ /*
+ * ARMv6 supersection address mask and size definitions.
+ */
+ #define SUPERSECTION_SHIFT 24
+ #define SUPERSECTION_SIZE (1UL << SUPERSECTION_SHIFT)
+ #define SUPERSECTION_MASK (~(SUPERSECTION_SIZE-1))
+
+ /*
+ * "Linux" PTE definitions.
+ *
+ * We keep two sets of PTEs - the hardware and the linux version.
+ * This allows greater flexibility in the way we map the Linux bits
+ * onto the hardware tables, and allows us to have YOUNG and DIRTY
+ * bits.
+ *
+ * The PTE table pointer refers to the hardware entries; the "Linux"
+ * entries are stored 1024 bytes below.
+ */
+ #define L_PTE_PRESENT (1 << 0)
+ #define L_PTE_FILE (1 << 1) /* only when !PRESENT */
+ #define L_PTE_YOUNG (1 << 1)
+ #define L_PTE_BUFFERABLE (1 << 2) /* matches PTE */
+ #define L_PTE_CACHEABLE (1 << 3) /* matches PTE */
+ #define L_PTE_USER (1 << 4)
+ #define L_PTE_WRITE (1 << 5)
+ #define L_PTE_EXEC (1 << 6)
+ #define L_PTE_DIRTY (1 << 7)
+ #define L_PTE_SHARED (1 << 10) /* shared(v6), coherent(xsc3) */
+
+ #ifndef __ASSEMBLY__
+
+ /*
+ * The pgprot_* and protection_map entries will be fixed up in runtime
+ * to include the cachable and bufferable bits based on memory policy,
+ * as well as any architecture dependent bits like global/ASID and SMP
+ * shared mapping bits.
+ */
+ #define _L_PTE_DEFAULT L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_CACHEABLE | L_PTE_BUFFERABLE
+ #define _L_PTE_READ L_PTE_USER | L_PTE_EXEC
+
+ extern pgprot_t pgprot_user;
+ extern pgprot_t pgprot_kernel;
+
+ #define PAGE_NONE pgprot_user
+ #define PAGE_COPY __pgprot(pgprot_val(pgprot_user) | _L_PTE_READ)
+ #define PAGE_SHARED __pgprot(pgprot_val(pgprot_user) | _L_PTE_READ | \
+ L_PTE_WRITE)
+ #define PAGE_READONLY __pgprot(pgprot_val(pgprot_user) | _L_PTE_READ)
+ #define PAGE_KERNEL pgprot_kernel
+
+ #define __PAGE_NONE __pgprot(_L_PTE_DEFAULT)
+ #define __PAGE_COPY __pgprot(_L_PTE_DEFAULT | _L_PTE_READ)
+ #define __PAGE_SHARED __pgprot(_L_PTE_DEFAULT | _L_PTE_READ | L_PTE_WRITE)
+ #define __PAGE_READONLY __pgprot(_L_PTE_DEFAULT | _L_PTE_READ)
+
+ #endif /* __ASSEMBLY__ */
+
+ /*
+ * The table below defines the page protection levels that we insert into our
+ * Linux page table version. These get translated into the best that the
+ * architecture can perform. Note that on most ARM hardware:
+ * 1) We cannot do execute protection
+ * 2) If we could do execute protection, then read is implied
+ * 3) write implies read permissions
+ */
+ #define __P000 __PAGE_NONE
+ #define __P001 __PAGE_READONLY
+ #define __P010 __PAGE_COPY
+ #define __P011 __PAGE_COPY
+ #define __P100 __PAGE_READONLY
+ #define __P101 __PAGE_READONLY
+ #define __P110 __PAGE_COPY
+ #define __P111 __PAGE_COPY
+
+ #define __S000 __PAGE_NONE
+ #define __S001 __PAGE_READONLY
+ #define __S010 __PAGE_SHARED
+ #define __S011 __PAGE_SHARED
+ #define __S100 __PAGE_READONLY
+ #define __S101 __PAGE_READONLY
+ #define __S110 __PAGE_SHARED
+ #define __S111 __PAGE_SHARED
+
+ #ifndef __ASSEMBLY__
+ /*
+ * ZERO_PAGE is a global shared page that is always zero: used
+ * for zero-mapped memory areas etc..
+ */
+ extern struct page *empty_zero_page;
+ #define ZERO_PAGE(vaddr) (empty_zero_page)
+
+ #define pte_pfn(pte) (pte_val(pte) >> PAGE_SHIFT)
+ #define pfn_pte(pfn,prot) (__pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot)))
+
+ #define pte_none(pte) (!pte_val(pte))
+ #define pte_clear(mm,addr,ptep) set_pte_ext(ptep, __pte(0), 0)
+ #define pte_page(pte) (pfn_to_page(pte_pfn(pte)))
+ #define pte_offset_kernel(dir,addr) (pmd_page_vaddr(*(dir)) + __pte_index(addr))
+ #define pte_offset_map(dir,addr) (pmd_page_vaddr(*(dir)) + __pte_index(addr))
+ #define pte_offset_map_nested(dir,addr) (pmd_page_vaddr(*(dir)) + __pte_index(addr))
+ #define pte_unmap(pte) do { } while (0)
+ #define pte_unmap_nested(pte) do { } while (0)
+
+ #define set_pte_ext(ptep,pte,ext) cpu_set_pte_ext(ptep,pte,ext)
+
+ #define set_pte_at(mm,addr,ptep,pteval) do { \
+ set_pte_ext(ptep, pteval, (addr) >= TASK_SIZE ? 0 : PTE_EXT_NG); \
+ } while (0)
+
+ /*
+ * The following only work if pte_present() is true.
+ * Undefined behaviour if not..
+ */
+ #define pte_present(pte) (pte_val(pte) & L_PTE_PRESENT)
+ #define pte_write(pte) (pte_val(pte) & L_PTE_WRITE)
+ #define pte_dirty(pte) (pte_val(pte) & L_PTE_DIRTY)
+ #define pte_young(pte) (pte_val(pte) & L_PTE_YOUNG)
+ #define pte_special(pte) (0)
+
+ /*
+ * The following only works if pte_present() is not true.
+ */
+ #define pte_file(pte) (pte_val(pte) & L_PTE_FILE)
+ #define pte_to_pgoff(x) (pte_val(x) >> 2)
+ #define pgoff_to_pte(x) __pte(((x) << 2) | L_PTE_FILE)
+
+ #define PTE_FILE_MAX_BITS 30
+
+ #define PTE_BIT_FUNC(fn,op) \
+ static inline pte_t pte_##fn(pte_t pte) { pte_val(pte) op; return pte; }
+
+ PTE_BIT_FUNC(wrprotect, &= ~L_PTE_WRITE);
+ PTE_BIT_FUNC(mkwrite, |= L_PTE_WRITE);
+ PTE_BIT_FUNC(mkclean, &= ~L_PTE_DIRTY);
+ PTE_BIT_FUNC(mkdirty, |= L_PTE_DIRTY);
+ PTE_BIT_FUNC(mkold, &= ~L_PTE_YOUNG);
+ PTE_BIT_FUNC(mkyoung, |= L_PTE_YOUNG);
+
+ static inline pte_t pte_mkspecial(pte_t pte) { return pte; }
+
+ /*
+ * Mark the prot value as uncacheable and unbufferable.
+ */
+ #define pgprot_noncached(prot) __pgprot(pgprot_val(prot) & ~(L_PTE_CACHEABLE | L_PTE_BUFFERABLE))
+ #define pgprot_writecombine(prot) __pgprot(pgprot_val(prot) & ~L_PTE_CACHEABLE)
+
+ #define pmd_none(pmd) (!pmd_val(pmd))
+ #define pmd_present(pmd) (pmd_val(pmd))
+ #define pmd_bad(pmd) (pmd_val(pmd) & 2)
++#define pmd_table(pmd) ((pmd_val(pmd) & PMD_TYPE_MASK) == PMD_TYPE_TABLE)
+
+ #define copy_pmd(pmdpd,pmdps) \
+ do { \
+ pmdpd[0] = pmdps[0]; \
+ pmdpd[1] = pmdps[1]; \
+ flush_pmd_entry(pmdpd); \
+ } while (0)
+
+ #define pmd_clear(pmdp) \
+ do { \
+ pmdp[0] = __pmd(0); \
+ pmdp[1] = __pmd(0); \
+ clean_pmd_entry(pmdp); \
+ } while (0)
+
+ static inline pte_t *pmd_page_vaddr(pmd_t pmd)
+ {
+ unsigned long ptr;
+
+ ptr = pmd_val(pmd) & ~(PTRS_PER_PTE * sizeof(void *) - 1);
+ ptr += PTRS_PER_PTE * sizeof(void *);
+
+ return __va(ptr);
+ }
+
+ #define pmd_page(pmd) virt_to_page(__va(pmd_val(pmd)))
+
+ /*
+ * Permanent address of a page. We never have highmem, so this is trivial.
+ */
+ #define pages_to_mb(x) ((x) >> (20 - PAGE_SHIFT))
+
+ /*
+ * Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
+ */
+ #define mk_pte(page,prot) pfn_pte(page_to_pfn(page),prot)
+
+ /*
+ * The "pgd_xxx()" functions here are trivial for a folded two-level
+ * setup: the pgd is never bad, and a pmd always exists (as it's folded
+ * into the pgd entry)
+ */
+ #define pgd_none(pgd) (0)
+ #define pgd_bad(pgd) (0)
+ #define pgd_present(pgd) (1)
+ #define pgd_clear(pgdp) do { } while (0)
+ #define set_pgd(pgd,pgdp) do { } while (0)
+
+ /* to find an entry in a page-table-directory */
+ #define pgd_index(addr) ((addr) >> PGDIR_SHIFT)
+
+ #define pgd_offset(mm, addr) ((mm)->pgd+pgd_index(addr))
+
+ /* to find an entry in a kernel page-table-directory */
+ #define pgd_offset_k(addr) pgd_offset(&init_mm, addr)
+
+ /* Find an entry in the second-level page table.. */
+ #define pmd_offset(dir, addr) ((pmd_t *)(dir))
+
+ /* Find an entry in the third-level page table.. */
+ #define __pte_index(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
+
+ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+ {
+ const unsigned long mask = L_PTE_EXEC | L_PTE_WRITE | L_PTE_USER;
+ pte_val(pte) = (pte_val(pte) & ~mask) | (pgprot_val(newprot) & mask);
+ return pte;
+ }
+
+ extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
+
+ /* Encode and decode a swap entry.
+ *
+ * We support up to 32GB of swap on 4k machines
+ */
+ #define __swp_type(x) (((x).val >> 2) & 0x7f)
+ #define __swp_offset(x) ((x).val >> 9)
+ #define __swp_entry(type,offset) ((swp_entry_t) { ((type) << 2) | ((offset) << 9) })
+ #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) })
+ #define __swp_entry_to_pte(swp) ((pte_t) { (swp).val })
+
+ /* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
+ /* FIXME: this is not correct */
+ #define kern_addr_valid(addr) (1)
+
+ #include <asm-generic/pgtable.h>
+
+ /*
+ * We provide our own arch_get_unmapped_area to cope with VIPT caches.
+ */
+ #define HAVE_ARCH_UNMAPPED_AREA
+
+ /*
+ * remap a physical page `pfn' of size `size' with page protection `prot'
+ * into virtual address `from'
+ */
+ #define io_remap_pfn_range(vma,from,pfn,size,prot) \
+ remap_pfn_range(vma, from, pfn, size, prot)
+
+ #define pgtable_cache_init() do { } while (0)
+
+ #endif /* !__ASSEMBLY__ */
+
+ #endif /* CONFIG_MMU */
+
+ #endif /* _ASMARM_PGTABLE_H */
__u8 adfsdrives;
};
+/* TI OMAP specific information */
+#define ATAG_BOARD 0x414f4d50
+
+struct tag_omap {
+ u8 data[0];
+};
+
/* footbridge memory clock, see arch/arm/mach-footbridge/arch.c */
#define ATAG_MEMCLK 0x41000402
*/
struct tag_acorn acorn;
+ /*
+ * OMAP specific
+ */
+ struct tag_omap omap;
+
/*
* DC21285 specific
*/
#include <linux/kernel.h>
#include <linux/init.h>
+ #include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/clk.h>
#include <linux/spi/ads7846.h>
#include <linux/workqueue.h>
#include <linux/delay.h>
- #include <linux/mutex.h>
#include <asm/hardware.h>
#include <asm/mach-types.h>
#include <asm/arch/dsp_common.h>
#include <asm/arch/aic23.h>
#include <asm/arch/omapfb.h>
+#include <asm/arch/hwa742.h>
#include <asm/arch/lcd_mipid.h>
#define ADS7846_PENDOWN_GPIO 15
},
};
+static struct {
+ struct clk *sys_ck;
+} hwa742;
+
+static int hwa742_get_clocks(void)
+{
+ hwa742.sys_ck = clk_get(NULL, "bclk");
+ if (IS_ERR(hwa742.sys_ck)) {
+ printk(KERN_ERR "can't get HWA742 clock\n");
+ return PTR_ERR(hwa742.sys_ck);
+ }
+ return 0;
+}
+
+static unsigned long hwa742_get_clock_rate(struct device *dev)
+{
+ return clk_get_rate(hwa742.sys_ck);
+}
+
+static void hwa742_power_up(struct device *dev)
+{
+ clk_enable(hwa742.sys_ck);
+}
+
+static void hwa742_power_down(struct device *dev)
+{
+ clk_disable(hwa742.sys_ck);
+}
+
+static struct hwa742_platform_data nokia770_hwa742_platform_data = {
+ .get_clock_rate = hwa742_get_clock_rate,
+ .power_up = hwa742_power_up,
+ .power_down = hwa742_power_down,
+ .te_connected = 1,
+};
+
+static void hwa742_dev_init(void)
+{
+ hwa742_get_clocks();
+ omapfb_set_ctrl_platform_data(&nokia770_hwa742_platform_data);
+}
/* assume no Mini-AB port */
#define AMPLIFIER_CTRL_GPIO 58
static struct clk *dspxor_ck;
- static DEFINE_MUTEX(audio_pwr_mutex);
+ static DEFINE_MUTEX(audio_pwr_lock);
/*
* audio_pwr_state
* +--+-------------------------+---------------------------------------+
static int audio_pwr_state = -1;
/*
- * audio_pwr_up / down should be called under audio_pwr_mutex
+ * audio_pwr_up / down should be called under audio_pwr_lock
*/
static void nokia770_audio_pwr_up(void)
{
static void codec_delayed_power_down(struct work_struct *work)
{
- mutex_lock(&audio_pwr_mutex);
+ mutex_lock(&audio_pwr_lock);
if (audio_pwr_state == -1)
aic23_power_down();
clk_disable(dspxor_ck);
- mutex_unlock(&audio_pwr_mutex);
+ mutex_unlock(&audio_pwr_lock);
}
static DECLARE_DELAYED_WORK(codec_power_down_work, codec_delayed_power_down);
static int
nokia770_audio_pwr_up_request(struct dsp_kfunc_device *kdev, int stage)
{
- mutex_lock(&audio_pwr_mutex);
+ mutex_lock(&audio_pwr_lock);
if (audio_pwr_state == -1)
nokia770_audio_pwr_up();
/* force audio_pwr_state = 0, even if it was 1. */
audio_pwr_state = 0;
- mutex_unlock(&audio_pwr_mutex);
+ mutex_unlock(&audio_pwr_lock);
return 0;
}
static int
nokia770_audio_pwr_down_request(struct dsp_kfunc_device *kdev, int stage)
{
- mutex_lock(&audio_pwr_mutex);
+ mutex_lock(&audio_pwr_lock);
switch (stage) {
case 1:
if (audio_pwr_state == 0)
}
break;
}
- mutex_unlock(&audio_pwr_mutex);
+ mutex_unlock(&audio_pwr_lock);
return 0;
}
omap_serial_init();
omap_register_i2c_bus(1, 100, NULL, 0);
omap_dsp_init();
+ hwa742_dev_init();
ads7846_dev_init();
mipid_dev_init();
}
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
+#include <linux/irq.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/notifier.h>
omap_request_gpio(13);
omap_request_gpio(14);
omap_request_gpio(15);
- set_irq_type(OMAP_GPIO_IRQ(12), IRQT_RISING);
- set_irq_type(OMAP_GPIO_IRQ(13), IRQT_RISING);
- set_irq_type(OMAP_GPIO_IRQ(14), IRQT_RISING);
- set_irq_type(OMAP_GPIO_IRQ(15), IRQT_RISING);
+ set_irq_type(OMAP_GPIO_IRQ(12), IRQ_TYPE_EDGE_RISING);
+ set_irq_type(OMAP_GPIO_IRQ(13), IRQ_TYPE_EDGE_RISING);
+ set_irq_type(OMAP_GPIO_IRQ(14), IRQ_TYPE_EDGE_RISING);
+ set_irq_type(OMAP_GPIO_IRQ(15), IRQ_TYPE_EDGE_RISING);
platform_add_devices(voiceblue_devices, ARRAY_SIZE(voiceblue_devices));
omap_board_config = voiceblue_config;
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap2/board-n800.c
+ *
+ * Copyright (C) 2005-2007 Nokia Corporation
+ * Author: Juha Yrjola <juha.yrjola@nokia.com>
+ *
+ * Modified from mach-omap2/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/clk.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/tsc2301.h>
+#include <linux/spi/tsc2005.h>
+#include <linux/input.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/i2c.h>
+#include <linux/i2c/lm8323.h>
+#include <linux/i2c/menelaus.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/usb.h>
+#include <asm/arch/board.h>
+#include <asm/arch/common.h>
+#include <asm/arch/mcspi.h>
+#include <asm/arch/lcd_mipid.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/gpio-switch.h>
+#include <asm/arch/omapfb.h>
+#include <asm/arch/blizzard.h>
+
+#include <../drivers/cbus/tahvo.h>
+#include <../drivers/media/video/tcm825x.h>
+
+#define N800_BLIZZARD_POWERDOWN_GPIO 15
+#define N800_STI_GPIO 62
+#define N800_KEYB_IRQ_GPIO 109
+#define N800_DAV_IRQ_GPIO 103
+#define N800_TSC2301_RESET_GPIO 118
+
+#ifdef CONFIG_MACH_NOKIA_N810
+static s16 rx44_keymap[LM8323_KEYMAP_SIZE] = {
+ [0x01] = KEY_Q,
+ [0x02] = KEY_K,
+ [0x03] = KEY_O,
+ [0x04] = KEY_P,
+ [0x05] = KEY_BACKSPACE,
+ [0x06] = KEY_A,
+ [0x07] = KEY_S,
+ [0x08] = KEY_D,
+ [0x09] = KEY_F,
+ [0x0a] = KEY_G,
+ [0x0b] = KEY_H,
+ [0x0c] = KEY_J,
+
+ [0x11] = KEY_W,
+ [0x12] = KEY_F4,
+ [0x13] = KEY_L,
+ [0x14] = KEY_APOSTROPHE,
+ [0x16] = KEY_Z,
+ [0x17] = KEY_X,
+ [0x18] = KEY_C,
+ [0x19] = KEY_V,
+ [0x1a] = KEY_B,
+ [0x1b] = KEY_N,
+ [0x1c] = KEY_LEFTSHIFT, /* Actually, this is both shift keys */
+ [0x1f] = KEY_F7,
+
+ [0x21] = KEY_E,
+ [0x22] = KEY_SEMICOLON,
+ [0x23] = KEY_MINUS,
+ [0x24] = KEY_EQUAL,
+ [0x2b] = KEY_FN,
+ [0x2c] = KEY_M,
+ [0x2f] = KEY_F8,
+
+ [0x31] = KEY_R,
+ [0x32] = KEY_RIGHTCTRL,
+ [0x34] = KEY_SPACE,
+ [0x35] = KEY_COMMA,
+ [0x37] = KEY_UP,
+ [0x3c] = KEY_COMPOSE,
+ [0x3f] = KEY_F6,
+
+ [0x41] = KEY_T,
+ [0x44] = KEY_DOT,
+ [0x46] = KEY_RIGHT,
+ [0x4f] = KEY_F5,
+ [0x51] = KEY_Y,
+ [0x53] = KEY_DOWN,
+ [0x55] = KEY_ENTER,
+ [0x5f] = KEY_ESC,
+
+ [0x61] = KEY_U,
+ [0x64] = KEY_LEFT,
+
+ [0x71] = KEY_I,
+ [0x75] = KEY_KPENTER,
+};
+
+static struct lm8323_platform_data lm8323_pdata = {
+ .repeat = 0, /* Repeat is handled in userspace for now. */
+ .keymap = rx44_keymap,
+
+ .name = "Internal keyboard",
+ .pwm1_name = "keyboard",
+ .pwm2_name = "cover",
+};
+#endif
+
+void __init nokia_n800_init_irq(void)
+{
+ omap2_init_common_hw(NULL);
+ omap_init_irq();
+ omap_gpio_init();
+
+#ifdef CONFIG_OMAP_STI
+ if (omap_request_gpio(N800_STI_GPIO) < 0) {
+ printk(KERN_ERR "Failed to request GPIO %d for STI\n",
+ N800_STI_GPIO);
+ return;
+ }
+
+ omap_set_gpio_direction(N800_STI_GPIO, 0);
+ omap_set_gpio_dataout(N800_STI_GPIO, 0);
+#endif
+}
+
+#if defined(CONFIG_MENELAUS) && defined(CONFIG_SENSORS_TMP105)
+
+static int n800_tmp105_set_power(int enable)
+{
+ return menelaus_set_vaux(enable ? 2800 : 0);
+}
+
+#else
+
+#define n800_tmp105_set_power NULL
+
+#endif
+
+static struct omap_uart_config n800_uart_config __initdata = {
+ .enabled_uarts = (1 << 0) | (1 << 2),
+};
+
+#include "../../../drivers/cbus/retu.h"
+
+static struct omap_fbmem_config n800_fbmem0_config __initdata = {
+ .size = 752 * 1024,
+};
+
+static struct omap_fbmem_config n800_fbmem1_config __initdata = {
+ .size = 752 * 1024,
+};
+
+static struct omap_fbmem_config n800_fbmem2_config __initdata = {
+ .size = 752 * 1024,
+};
+
+static struct omap_tmp105_config n800_tmp105_config __initdata = {
+ .tmp105_irq_pin = 125,
+ .set_power = n800_tmp105_set_power,
+};
+
+static void mipid_shutdown(struct mipid_platform_data *pdata)
+{
+ if (pdata->nreset_gpio != -1) {
+ pr_info("shutdown LCD\n");
+ omap_set_gpio_dataout(pdata->nreset_gpio, 0);
+ msleep(120);
+ }
+}
+
+static struct mipid_platform_data n800_mipid_platform_data = {
+ .shutdown = mipid_shutdown,
+};
+
+static void __init mipid_dev_init(void)
+{
+ const struct omap_lcd_config *conf;
+
+ conf = omap_get_config(OMAP_TAG_LCD, struct omap_lcd_config);
+ if (conf != NULL) {
+ n800_mipid_platform_data.nreset_gpio = conf->nreset_gpio;
+ n800_mipid_platform_data.data_lines = conf->data_lines;
+ }
+}
+
+static struct {
+ struct clk *sys_ck;
+} blizzard;
+
+static int blizzard_get_clocks(void)
+{
+ blizzard.sys_ck = clk_get(0, "osc_ck");
+ if (IS_ERR(blizzard.sys_ck)) {
+ printk(KERN_ERR "can't get Blizzard clock\n");
+ return PTR_ERR(blizzard.sys_ck);
+ }
+ return 0;
+}
+
+static unsigned long blizzard_get_clock_rate(struct device *dev)
+{
+ return clk_get_rate(blizzard.sys_ck);
+}
+
+static void blizzard_enable_clocks(int enable)
+{
+ if (enable)
+ clk_enable(blizzard.sys_ck);
+ else
+ clk_disable(blizzard.sys_ck);
+}
+
+static void blizzard_power_up(struct device *dev)
+{
+ /* Vcore to 1.475V */
+ tahvo_set_clear_reg_bits(0x07, 0, 0xf);
+ msleep(10);
+
+ blizzard_enable_clocks(1);
+ omap_set_gpio_dataout(N800_BLIZZARD_POWERDOWN_GPIO, 1);
+}
+
+static void blizzard_power_down(struct device *dev)
+{
+ omap_set_gpio_dataout(N800_BLIZZARD_POWERDOWN_GPIO, 0);
+ blizzard_enable_clocks(0);
+
+ /* Vcore to 1.005V */
+ tahvo_set_clear_reg_bits(0x07, 0xf, 0);
+}
+
+static struct blizzard_platform_data n800_blizzard_data = {
+ .power_up = blizzard_power_up,
+ .power_down = blizzard_power_down,
+ .get_clock_rate = blizzard_get_clock_rate,
+ .te_connected = 1,
+};
+
+static void __init blizzard_dev_init(void)
+{
+ int r;
+
+ r = omap_request_gpio(N800_BLIZZARD_POWERDOWN_GPIO);
+ if (r < 0)
+ return;
+ omap_set_gpio_direction(N800_BLIZZARD_POWERDOWN_GPIO, 0);
+ omap_set_gpio_dataout(N800_BLIZZARD_POWERDOWN_GPIO, 1);
+
+ blizzard_get_clocks();
+ omapfb_set_ctrl_platform_data(&n800_blizzard_data);
+}
+
+static struct omap_mmc_config n800_mmc_config __initdata = {
+ .mmc [0] = {
+ .enabled = 1,
+ .wire4 = 1,
+ },
+};
+
+extern struct omap_mmc_platform_data n800_mmc_data;
+
+static struct omap_board_config_kernel n800_config[] __initdata = {
+ { OMAP_TAG_UART, &n800_uart_config },
+ { OMAP_TAG_FBMEM, &n800_fbmem0_config },
+ { OMAP_TAG_FBMEM, &n800_fbmem1_config },
+ { OMAP_TAG_FBMEM, &n800_fbmem2_config },
+ { OMAP_TAG_TMP105, &n800_tmp105_config },
+ { OMAP_TAG_MMC, &n800_mmc_config },
+};
+
+static struct tsc2301_platform_data tsc2301_config = {
+ .reset_gpio = N800_TSC2301_RESET_GPIO,
+ .keymap = {
+ -1, /* Event for bit 0 */
+ KEY_UP, /* Event for bit 1 (up) */
+ KEY_F5, /* Event for bit 2 (home) */
+ -1, /* Event for bit 3 */
+ KEY_LEFT, /* Event for bit 4 (left) */
+ KEY_ENTER, /* Event for bit 5 (enter) */
+ KEY_RIGHT, /* Event for bit 6 (right) */
+ -1, /* Event for bit 7 */
+ KEY_ESC, /* Event for bit 8 (cycle) */
+ KEY_DOWN, /* Event for bit 9 (down) */
+ KEY_F4, /* Event for bit 10 (menu) */
+ -1, /* Event for bit 11 */
+ KEY_F8, /* Event for bit 12 (Zoom-) */
+ KEY_F6, /* Event for bit 13 (FS) */
+ KEY_F7, /* Event for bit 14 (Zoom+) */
+ -1, /* Event for bit 15 */
+ },
+ .kp_rep = 0,
+ .keyb_name = "Internal keypad",
+};
+
+static void tsc2301_dev_init(void)
+{
+ int r;
+ int gpio = N800_KEYB_IRQ_GPIO;
+
+ r = gpio_request(gpio, "tsc2301 KBD IRQ");
+ if (r >= 0) {
+ gpio_direction_input(gpio);
+ tsc2301_config.keyb_int = OMAP_GPIO_IRQ(gpio);
+ } else {
+ printk(KERN_ERR "unable to get KBD GPIO");
+ }
+
+ gpio = N800_DAV_IRQ_GPIO;
+ r = gpio_request(gpio, "tsc2301 DAV IRQ");
+ if (r >= 0) {
+ gpio_direction_input(gpio);
+ tsc2301_config.dav_int = OMAP_GPIO_IRQ(gpio);
+ } else {
+ printk(KERN_ERR "unable to get DAV GPIO");
+ }
+}
+
+static int __init tea5761_dev_init(void)
+{
+ const struct omap_tea5761_config *info;
+ int enable_gpio = 0;
+
+ info = omap_get_config(OMAP_TAG_TEA5761, struct omap_tea5761_config);
+ if (info)
+ enable_gpio = info->enable_gpio;
+
+ if (enable_gpio) {
+ pr_debug("Enabling tea5761 at GPIO %d\n",
+ enable_gpio);
+
+ if (omap_request_gpio(enable_gpio) < 0) {
+ printk(KERN_ERR "Can't request GPIO %d\n",
+ enable_gpio);
+ return -ENODEV;
+ }
+
+ omap_set_gpio_direction(enable_gpio, 0);
+ udelay(50);
+ omap_set_gpio_dataout(enable_gpio, 1);
+ }
+
+ return 0;
+}
+
+static struct omap2_mcspi_device_config tsc2301_mcspi_config = {
+ .turbo_mode = 0,
+ .single_channel = 1,
+};
+
+static struct omap2_mcspi_device_config mipid_mcspi_config = {
+ .turbo_mode = 0,
+ .single_channel = 1,
+};
+
+static struct omap2_mcspi_device_config cx3110x_mcspi_config = {
+ .turbo_mode = 0,
+ .single_channel = 1,
+};
+
+#ifdef CONFIG_TOUCHSCREEN_TSC2005
+static struct tsc2005_platform_data tsc2005_config = {
+ .reset_gpio = 94,
+ .dav_gpio = 106
+};
+
+static struct omap2_mcspi_device_config tsc2005_mcspi_config = {
+ .turbo_mode = 0,
+ .single_channel = 1,
+};
+#endif
+
+static struct spi_board_info n800_spi_board_info[] __initdata = {
+ {
+ .modalias = "lcd_mipid",
+ .bus_num = 1,
+ .chip_select = 1,
+ .max_speed_hz = 4000000,
+ .controller_data= &mipid_mcspi_config,
+ .platform_data = &n800_mipid_platform_data,
+ }, {
+ .modalias = "cx3110x",
+ .bus_num = 2,
+ .chip_select = 0,
+ .max_speed_hz = 48000000,
+ .controller_data= &cx3110x_mcspi_config,
+ },
+ {
+ .modalias = "tsc2301",
+ .bus_num = 1,
+ .chip_select = 0,
+ .max_speed_hz = 6000000,
+ .controller_data= &tsc2301_mcspi_config,
+ .platform_data = &tsc2301_config,
+ },
+};
+
+static struct spi_board_info n810_spi_board_info[] __initdata = {
+ {
+ .modalias = "lcd_mipid",
+ .bus_num = 1,
+ .chip_select = 1,
+ .max_speed_hz = 4000000,
+ .controller_data = &mipid_mcspi_config,
+ .platform_data = &n800_mipid_platform_data,
+ },
+ {
+ .modalias = "cx3110x",
+ .bus_num = 2,
+ .chip_select = 0,
+ .max_speed_hz = 48000000,
+ .controller_data = &cx3110x_mcspi_config,
+ },
+ {
+ .modalias = "tsc2005",
+ .bus_num = 1,
+ .chip_select = 0,
+ .max_speed_hz = 6000000,
+ .controller_data = &tsc2005_mcspi_config,
+ .platform_data = &tsc2005_config,
+ },
+};
+
+static void __init tsc2005_set_config(void)
+{
+ const struct omap_lcd_config *conf;
+
+ conf = omap_get_config(OMAP_TAG_LCD, struct omap_lcd_config);
+ if (conf != NULL) {
+#ifdef CONFIG_TOUCHSCREEN_TSC2005
+ if (strcmp(conf->panel_name, "lph8923") == 0) {
+ tsc2005_config.ts_x_plate_ohm = 180;
+ tsc2005_config.ts_hw_avg = 0;
+ tsc2005_config.ts_ignore_last = 0;
+ tsc2005_config.ts_touch_pressure = 1500;
+ tsc2005_config.ts_stab_time = 100;
+ tsc2005_config.ts_pressure_max = 2048;
+ tsc2005_config.ts_pressure_fudge = 2;
+ tsc2005_config.ts_x_max = 4096;
+ tsc2005_config.ts_x_fudge = 4;
+ tsc2005_config.ts_y_max = 4096;
+ tsc2005_config.ts_y_fudge = 7;
+ } else if (strcmp(conf->panel_name, "ls041y3") == 0) {
+ tsc2005_config.ts_x_plate_ohm = 280;
+ tsc2005_config.ts_hw_avg = 0;
+ tsc2005_config.ts_ignore_last = 0;
+ tsc2005_config.ts_touch_pressure = 1500;
+ tsc2005_config.ts_stab_time = 1000;
+ tsc2005_config.ts_pressure_max = 2048;
+ tsc2005_config.ts_pressure_fudge = 2;
+ tsc2005_config.ts_x_max = 4096;
+ tsc2005_config.ts_x_fudge = 4;
+ tsc2005_config.ts_y_max = 4096;
+ tsc2005_config.ts_y_fudge = 7;
+ } else {
+ printk(KERN_ERR "Unknown panel type, set default "
+ "touchscreen configuration\n");
+ tsc2005_config.ts_x_plate_ohm = 200;
+ tsc2005_config.ts_stab_time = 100;
+ }
+#endif
+ }
+}
+
+#if defined(CONFIG_CBUS_RETU) && defined(CONFIG_LEDS_OMAP_PWM)
+
+void retu_keypad_led_set_power(struct omap_pwm_led_platform_data *self,
+ int on_off)
+{
+ if (on_off) {
+ retu_write_reg(RETU_REG_CTRL_SET, 1 << 6);
+ msleep(2);
+ retu_write_reg(RETU_REG_CTRL_SET, 1 << 3);
+ } else {
+ retu_write_reg(RETU_REG_CTRL_CLR, (1 << 6) | (1 << 3));
+ }
+}
+
+static struct omap_pwm_led_platform_data n800_keypad_led_data = {
+ .name = "keypad",
+ .intensity_timer = 10,
+ .blink_timer = 9,
+ .set_power = retu_keypad_led_set_power,
+};
+
+static struct platform_device n800_keypad_led_device = {
+ .name = "omap_pwm_led",
+ .id = -1,
+ .dev = {
+ .platform_data = &n800_keypad_led_data,
+ },
+};
+#endif
+
+#if defined(CONFIG_TOUCHSCREEN_TSC2301)
+static void __init n800_ts_set_config(void)
+{
+ const struct omap_lcd_config *conf;
+
+ conf = omap_get_config(OMAP_TAG_LCD, struct omap_lcd_config);
+ if (conf != NULL) {
+ if (strcmp(conf->panel_name, "lph8923") == 0) {
+ tsc2301_config.ts_x_plate_ohm = 180;
+ tsc2301_config.ts_hw_avg = 8;
+ tsc2301_config.ts_max_pressure = 2048;
+ tsc2301_config.ts_touch_pressure = 400;
+ tsc2301_config.ts_stab_time = 100;
+ tsc2301_config.ts_pressure_fudge = 2;
+ tsc2301_config.ts_x_max = 4096;
+ tsc2301_config.ts_x_fudge = 4;
+ tsc2301_config.ts_y_max = 4096;
+ tsc2301_config.ts_y_fudge = 7;
+ } else if (strcmp(conf->panel_name, "ls041y3") == 0) {
+ tsc2301_config.ts_x_plate_ohm = 280;
+ tsc2301_config.ts_hw_avg = 8;
+ tsc2301_config.ts_touch_pressure = 400;
+ tsc2301_config.ts_max_pressure = 2048;
+ tsc2301_config.ts_stab_time = 1000;
+ tsc2301_config.ts_pressure_fudge = 2;
+ tsc2301_config.ts_x_max = 4096;
+ tsc2301_config.ts_x_fudge = 4;
+ tsc2301_config.ts_y_max = 4096;
+ tsc2301_config.ts_y_fudge = 7;
+ } else {
+ printk(KERN_ERR "Unknown panel type, set default "
+ "touchscreen configuration\n");
+ tsc2301_config.ts_x_plate_ohm = 200;
+ tsc2301_config.ts_stab_time = 100;
+ }
+ }
+}
+#else
+static inline void n800_ts_set_config(void)
+{
+}
+#endif
+
+static struct omap_gpio_switch n800_gpio_switches[] __initdata = {
+ {
+ .name = "bat_cover",
+ .gpio = -1,
+ .debounce_rising = 100,
+ .debounce_falling = 0,
+ .notify = n800_mmc_slot1_cover_handler,
+ .notify_data = NULL,
+ }, {
+ .name = "headphone",
+ .gpio = -1,
+ .debounce_rising = 200,
+ .debounce_falling = 200,
+ }, {
+ .name = "cam_act",
+ .gpio = -1,
+ .debounce_rising = 200,
+ .debounce_falling = 200,
+ }, {
+ .name = "cam_turn",
+ .gpio = -1,
+ .debounce_rising = 100,
+ .debounce_falling = 100,
+ },
+};
+
+static struct platform_device *n800_devices[] __initdata = {
+#if defined(CONFIG_CBUS_RETU) && defined(CONFIG_LEDS_OMAP_PWM)
+ &n800_keypad_led_device,
+#endif
+};
+
+#ifdef CONFIG_MENELAUS
+static int n800_auto_sleep_regulators(void)
+{
+ u32 val;
+ int ret;
+
+ val = EN_VPLL_SLEEP | EN_VMMC_SLEEP \
+ | EN_VAUX_SLEEP | EN_VIO_SLEEP \
+ | EN_VMEM_SLEEP | EN_DC3_SLEEP \
+ | EN_VC_SLEEP | EN_DC2_SLEEP;
+
+ ret = menelaus_set_regulator_sleep(1, val);
+ if (ret < 0) {
+ printk(KERN_ERR "Could not set regulators to sleep on "
+ "menelaus: %u\n", ret);
+ return ret;
+ }
+ return 0;
+}
+
+static int n800_auto_voltage_scale(void)
+{
+ int ret;
+
+ ret = menelaus_set_vcore_hw(1400, 1050);
+ if (ret < 0) {
+ printk(KERN_ERR "Could not set VCORE voltage on "
+ "menelaus: %u\n", ret);
+ return ret;
+ }
+ return 0;
+}
+
+static int n800_menelaus_init(struct device *dev)
+{
+ int ret;
+
+ ret = n800_auto_voltage_scale();
+ if (ret < 0)
+ return ret;
+ ret = n800_auto_sleep_regulators();
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+static struct menelaus_platform_data n800_menelaus_platform_data = {
+ .late_init = n800_menelaus_init,
+};
+#endif
+
+static struct i2c_board_info __initdata n800_i2c_board_info_1[] = {
+ {
+ I2C_BOARD_INFO("menelaus", 0x72),
+ .irq = INT_24XX_SYS_NIRQ,
+ .platform_data = &n800_menelaus_platform_data,
+ },
+};
+
+extern struct tcm825x_platform_data n800_tcm825x_platform_data;
+
+static struct i2c_board_info __initdata_or_module n8x0_i2c_board_info_2[] = {
+ {
+ I2C_BOARD_INFO(TCM825X_NAME, TCM825X_I2C_ADDR),
++#if defined (CONFIG_VIDEO_TCM825X) || defined (CONFIG_VIDEO_TCM825X_MODULE)
+ .platform_data = &n800_tcm825x_platform_data,
++#endif
+ },
+ {
+ I2C_BOARD_INFO("tsl2563", 0x29),
+ },
+ {
+ I2C_BOARD_INFO("lp5521", 0x32),
+ },
+};
+
+
+static struct i2c_board_info __initdata_or_module n800_i2c_board_info_2[] = {
+ {
+ I2C_BOARD_INFO("tea5761", 0x10),
+ },
+};
+
+static struct i2c_board_info __initdata_or_module n810_i2c_board_info_2[] = {
+ {
+ I2C_BOARD_INFO("lm8323", 0x45),
+ .irq = OMAP_GPIO_IRQ(109),
+ .platform_data = &lm8323_pdata,
+ },
+};
+
+void __init nokia_n800_common_init(void)
+{
+ platform_add_devices(n800_devices, ARRAY_SIZE(n800_devices));
+
+ n800_flash_init();
+ n800_mmc_init();
+ n800_bt_init();
+ n800_dsp_init();
+ n800_usb_init();
+ n800_cam_init();
+ if (machine_is_nokia_n800())
+ spi_register_board_info(n800_spi_board_info,
+ ARRAY_SIZE(n800_spi_board_info));
+ if (machine_is_nokia_n810()) {
+ tsc2005_set_config();
+ spi_register_board_info(n810_spi_board_info,
+ ARRAY_SIZE(n810_spi_board_info));
+ }
+ omap_serial_init();
+ omap_register_i2c_bus(1, 400, n800_i2c_board_info_1,
+ ARRAY_SIZE(n800_i2c_board_info_1));
+ omap_register_i2c_bus(2, 400, n8x0_i2c_board_info_2,
+ ARRAY_SIZE(n800_i2c_board_info_2));
+ if (machine_is_nokia_n800())
+ i2c_register_board_info(2, n800_i2c_board_info_2,
+ ARRAY_SIZE(n800_i2c_board_info_2));
+ if (machine_is_nokia_n810())
+ i2c_register_board_info(2, n810_i2c_board_info_2,
+ ARRAY_SIZE(n810_i2c_board_info_2));
+
+ mipid_dev_init();
+ blizzard_dev_init();
+}
+
+static void __init nokia_n800_init(void)
+{
+ nokia_n800_common_init();
+
+ n800_audio_init(&tsc2301_config);
+ n800_ts_set_config();
+ tsc2301_dev_init();
+ tea5761_dev_init();
+ omap_register_gpio_switches(n800_gpio_switches,
+ ARRAY_SIZE(n800_gpio_switches));
+}
+
+void __init nokia_n800_map_io(void)
+{
+ omap_board_config = n800_config;
+ omap_board_config_size = ARRAY_SIZE(n800_config);
+
+ omap2_set_globals_242x();
+ omap2_map_common_io();
+}
+
+MACHINE_START(NOKIA_N800, "Nokia N800")
+ .phys_io = 0x48000000,
+ .io_pg_offst = ((0xd8000000) >> 18) & 0xfffc,
+ .boot_params = 0x80000100,
+ .map_io = nokia_n800_map_io,
+ .init_irq = nokia_n800_init_irq,
+ .init_machine = nokia_n800_init,
+ .timer = &omap_timer,
+MACHINE_END
# ARM926T
config CPU_ARM926T
bool "Support ARM926T processor"
- depends on ARCH_INTEGRATOR || ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || MACH_REALVIEW_EB || ARCH_PNX4008 || ARCH_NETX || CPU_S3C2412 || ARCH_AT91SAM9260 || ARCH_AT91SAM9261 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_AT91CAP9 || ARCH_NS9XXX || ARCH_DAVINCI
- default y if ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || ARCH_PNX4008 || ARCH_NETX || CPU_S3C2412 || ARCH_AT91SAM9260 || ARCH_AT91SAM9261 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_AT91CAP9 || ARCH_NS9XXX || ARCH_DAVINCI
+ depends on ARCH_INTEGRATOR || ARCH_VERSATILE_PB || \
+ MACH_VERSATILE_AB || ARCH_OMAP730 || \
+ ARCH_OMAP16XX || MACH_REALVIEW_EB || \
+ ARCH_PNX4008 || ARCH_NETX || CPU_S3C2412 || \
+ ARCH_AT91SAM9260 || ARCH_AT91SAM9261 || \
+ ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || \
+ ARCH_AT91SAM9G20 || ARCH_AT91CAP9 || \
+ ARCH_NS9XXX || ARCH_DAVINCI || ARCH_MX2
+ default y if ARCH_VERSATILE_PB || MACH_VERSATILE_AB || \
+ ARCH_OMAP730 || ARCH_OMAP16XX || \
+ ARCH_PNX4008 || ARCH_NETX || CPU_S3C2412 || \
+ ARCH_AT91SAM9260 || ARCH_AT91SAM9261 || \
+ ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || \
+ ARCH_AT91SAM9G20 || ARCH_AT91CAP9 || \
+ ARCH_NS9XXX || ARCH_DAVINCI || ARCH_MX2
select CPU_32v5
select CPU_ABRT_EV5TJ
select CPU_PABRT_NOIFAR
# Feroceon
config CPU_FEROCEON
bool
- depends on ARCH_ORION5X
+ depends on ARCH_ORION5X || ARCH_LOKI || ARCH_KIRKWOOD || ARCH_MV78XX0
default y
select CPU_32v5
select CPU_ABRT_EV5T
select CPU_CACHE_VIVT
select CPU_CP15_MMU
select CPU_COPY_FEROCEON if MMU
- select CPU_TLB_V4WBI if MMU
+ select CPU_TLB_FEROCEON if MMU
config CPU_FEROCEON_OLD_ID
bool "Accept early Feroceon cores with an ARM926 ID"
# ARMv7
config CPU_V7
bool "Support ARM V7 processor"
- depends on ARCH_INTEGRATOR || MACH_REALVIEW_EB
+ depends on ARCH_INTEGRATOR || MACH_REALVIEW_EB || ARCH_OMAP3
select CPU_32v6K
select CPU_32v7
select CPU_ABRT_EV7
ARM Architecture Version 4 TLB with writeback cache and invalidate
instruction cache entry.
+ config CPU_TLB_FEROCEON
+ bool
+ help
+ Feroceon TLB (v4wbi with non-outer-cachable page table walks).
+
config CPU_TLB_V6
bool
bool
default n
+ config CACHE_FEROCEON_L2
+ bool "Enable the Feroceon L2 cache controller"
+ depends on ARCH_KIRKWOOD || ARCH_MV78XX0
+ default y
+ select OUTER_CACHE
+ help
+ This option enables the Feroceon L2 cache controller.
+
config CACHE_L2X0
bool "Enable the L2x0 outer cache controller"
depends on REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP || MACH_REALVIEW_PB1176
select OUTER_CACHE
help
This option enables the L2x0 PrimeCell.
+
+ config CACHE_XSC3L2
+ bool "Enable the L2 cache on XScale3"
+ depends on CPU_XSC3
+ default y
+ select OUTER_CACHE
+ help
+ This option enables the L2 cache on XScale3.
--- /dev/null
- set_irq_type(OMAP_GPIO_IRQ(sw->gpio), IRQT_FALLING);
+/*
+ * linux/arch/arm/plat-omap/gpio-switch.c
+ *
+ * Copyright (C) 2004-2006 Nokia Corporation
+ * Written by Juha Yrjölä <juha.yrjola@nokia.com>
+ * and Paul Mundt <paul.mundt@nokia.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/sched.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/timer.h>
+#include <linux/err.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/irqs.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/board.h>
+#include <asm/arch/gpio-switch.h>
+
+struct gpio_switch {
+ char name[14];
+ u16 gpio;
+ unsigned flags:4;
+ unsigned type:4;
+ unsigned state:1;
+ unsigned both_edges:1;
+
+ u16 debounce_rising;
+ u16 debounce_falling;
+
+ void (* notify)(void *data, int state);
+ void *notify_data;
+
+ struct work_struct work;
+ struct timer_list timer;
+ struct platform_device pdev;
+
+ struct list_head node;
+};
+
+static LIST_HEAD(gpio_switches);
+static struct platform_device *gpio_sw_platform_dev;
+static struct platform_driver gpio_sw_driver;
+
+static const struct omap_gpio_switch *board_gpio_sw_table;
+static int board_gpio_sw_count;
+
+static const char *cover_str[2] = { "open", "closed" };
+static const char *connection_str[2] = { "disconnected", "connected" };
+static const char *activity_str[2] = { "inactive", "active" };
+
+/*
+ * GPIO switch state default debounce delay in ms
+ */
+#define OMAP_GPIO_SW_DEFAULT_DEBOUNCE 10
+
+static const char **get_sw_str(struct gpio_switch *sw)
+{
+ switch (sw->type) {
+ case OMAP_GPIO_SWITCH_TYPE_COVER:
+ return cover_str;
+ case OMAP_GPIO_SWITCH_TYPE_CONNECTION:
+ return connection_str;
+ case OMAP_GPIO_SWITCH_TYPE_ACTIVITY:
+ return activity_str;
+ default:
+ BUG();
+ return NULL;
+ }
+}
+
+static const char *get_sw_type(struct gpio_switch *sw)
+{
+ switch (sw->type) {
+ case OMAP_GPIO_SWITCH_TYPE_COVER:
+ return "cover";
+ case OMAP_GPIO_SWITCH_TYPE_CONNECTION:
+ return "connection";
+ case OMAP_GPIO_SWITCH_TYPE_ACTIVITY:
+ return "activity";
+ default:
+ BUG();
+ return NULL;
+ }
+}
+
+static void print_sw_state(struct gpio_switch *sw, int state)
+{
+ const char **str;
+
+ str = get_sw_str(sw);
+ if (str != NULL)
+ printk(KERN_INFO "%s (GPIO %d) is now %s\n", sw->name, sw->gpio, str[state]);
+}
+
+static int gpio_sw_get_state(struct gpio_switch *sw)
+{
+ int state;
+
+ state = omap_get_gpio_datain(sw->gpio);
+ if (sw->flags & OMAP_GPIO_SWITCH_FLAG_INVERTED)
+ state = !state;
+
+ return state;
+}
+
+static ssize_t gpio_sw_state_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct gpio_switch *sw = dev_get_drvdata(dev);
+ const char **str;
+ char state[16];
+ int enable;
+
+ if (!(sw->flags & OMAP_GPIO_SWITCH_FLAG_OUTPUT))
+ return -EPERM;
+
+ if (sscanf(buf, "%15s", state) != 1)
+ return -EINVAL;
+
+ str = get_sw_str(sw);
+ if (strcmp(state, str[0]) == 0)
+ sw->state = enable = 0;
+ else if (strcmp(state, str[1]) == 0)
+ sw->state = enable = 1;
+ else
+ return -EINVAL;
+
+ if (sw->flags & OMAP_GPIO_SWITCH_FLAG_INVERTED)
+ enable = !enable;
+ omap_set_gpio_dataout(sw->gpio, enable);
+
+ return count;
+}
+
+static ssize_t gpio_sw_state_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct gpio_switch *sw = dev_get_drvdata(dev);
+ const char **str;
+
+ str = get_sw_str(sw);
+ return sprintf(buf, "%s\n", str[sw->state]);
+}
+
+static DEVICE_ATTR(state, S_IRUGO | S_IWUSR, gpio_sw_state_show,
+ gpio_sw_state_store);
+
+static ssize_t gpio_sw_type_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct gpio_switch *sw = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%s\n", get_sw_type(sw));
+}
+
+static DEVICE_ATTR(type, S_IRUGO, gpio_sw_type_show, NULL);
+
+static ssize_t gpio_sw_direction_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct gpio_switch *sw = dev_get_drvdata(dev);
+ int is_output;
+
+ is_output = sw->flags & OMAP_GPIO_SWITCH_FLAG_OUTPUT;
+ return sprintf(buf, "%s\n", is_output ? "output" : "input");
+}
+
+static DEVICE_ATTR(direction, S_IRUGO, gpio_sw_direction_show, NULL);
+
+
+static irqreturn_t gpio_sw_irq_handler(int irq, void *arg)
+{
+ struct gpio_switch *sw = arg;
+ unsigned long timeout;
+ int state;
+
+ if (!sw->both_edges) {
+ if (omap_get_gpio_datain(sw->gpio))
- set_irq_type(OMAP_GPIO_IRQ(sw->gpio), IRQT_RISING);
++ set_irq_type(OMAP_GPIO_IRQ(sw->gpio), IRQ_TYPE_EDGE_FALLING);
+ else
++ set_irq_type(OMAP_GPIO_IRQ(sw->gpio), IRQ_TYPE_EDGE_RISING);
+ }
+
+ state = gpio_sw_get_state(sw);
+ if (sw->state == state)
+ return IRQ_HANDLED;
+
+ if (state)
+ timeout = sw->debounce_rising;
+ else
+ timeout = sw->debounce_falling;
+ if (!timeout)
+ schedule_work(&sw->work);
+ else
+ mod_timer(&sw->timer, jiffies + msecs_to_jiffies(timeout));
+
+ return IRQ_HANDLED;
+}
+
+static void gpio_sw_timer(unsigned long arg)
+{
+ struct gpio_switch *sw = (struct gpio_switch *) arg;
+
+ schedule_work(&sw->work);
+}
+
+static void gpio_sw_handler(struct work_struct *work)
+{
+ struct gpio_switch *sw = container_of(work, struct gpio_switch, work);
+ int state;
+
+ state = gpio_sw_get_state(sw);
+ if (sw->state == state)
+ return;
+
+ sw->state = state;
+ if (sw->notify != NULL)
+ sw->notify(sw->notify_data, state);
+ sysfs_notify(&sw->pdev.dev.kobj, NULL, "state");
+ print_sw_state(sw, state);
+}
+
+static int __init can_do_both_edges(struct gpio_switch *sw)
+{
+ if (!cpu_class_is_omap1())
+ return 1;
+ if (OMAP_GPIO_IS_MPUIO(sw->gpio))
+ return 0;
+ else
+ return 1;
+}
+
+static void gpio_sw_release(struct device *dev)
+{
+}
+
+static int __init new_switch(struct gpio_switch *sw)
+{
+ int r, direction, trigger;
+
+ switch (sw->type) {
+ case OMAP_GPIO_SWITCH_TYPE_COVER:
+ case OMAP_GPIO_SWITCH_TYPE_CONNECTION:
+ case OMAP_GPIO_SWITCH_TYPE_ACTIVITY:
+ break;
+ default:
+ printk(KERN_ERR "invalid GPIO switch type: %d\n", sw->type);
+ return -EINVAL;
+ }
+
+ sw->pdev.name = sw->name;
+ sw->pdev.id = -1;
+
+ sw->pdev.dev.parent = &gpio_sw_platform_dev->dev;
+ sw->pdev.dev.driver = &gpio_sw_driver.driver;
+ sw->pdev.dev.release = gpio_sw_release;
+
+ r = platform_device_register(&sw->pdev);
+ if (r) {
+ printk(KERN_ERR "gpio-switch: platform device registration "
+ "failed for %s", sw->name);
+ return r;
+ }
+ dev_set_drvdata(&sw->pdev.dev, sw);
+
+ r = omap_request_gpio(sw->gpio);
+ if (r < 0) {
+ platform_device_unregister(&sw->pdev);
+ return r;
+ }
+
+ /* input: 1, output: 0 */
+ direction = !(sw->flags & OMAP_GPIO_SWITCH_FLAG_OUTPUT);
+ omap_set_gpio_direction(sw->gpio, direction);
+
+ sw->state = gpio_sw_get_state(sw);
+
+ r = 0;
+ r |= device_create_file(&sw->pdev.dev, &dev_attr_state);
+ r |= device_create_file(&sw->pdev.dev, &dev_attr_type);
+ r |= device_create_file(&sw->pdev.dev, &dev_attr_direction);
+ if (r)
+ printk(KERN_ERR "gpio-switch: attribute file creation "
+ "failed for %s\n", sw->name);
+
+ if (!direction)
+ return 0;
+
+ if (can_do_both_edges(sw)) {
+ trigger = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING;
+ sw->both_edges = 1;
+ } else {
+ if (omap_get_gpio_datain(sw->gpio))
+ trigger = IRQF_TRIGGER_FALLING;
+ else
+ trigger = IRQF_TRIGGER_RISING;
+ }
+ r = request_irq(OMAP_GPIO_IRQ(sw->gpio), gpio_sw_irq_handler,
+ IRQF_SHARED | trigger, sw->name, sw);
+ if (r < 0) {
+ printk(KERN_ERR "gpio-switch: request_irq() failed "
+ "for GPIO %d\n", sw->gpio);
+ platform_device_unregister(&sw->pdev);
+ omap_free_gpio(sw->gpio);
+ return r;
+ }
+
+ INIT_WORK(&sw->work, gpio_sw_handler);
+ init_timer(&sw->timer);
+
+ sw->timer.function = gpio_sw_timer;
+ sw->timer.data = (unsigned long)sw;
+
+ list_add(&sw->node, &gpio_switches);
+
+ return 0;
+}
+
+static int __init add_atag_switches(void)
+{
+ const struct omap_gpio_switch_config *cfg;
+ struct gpio_switch *sw;
+ int i, r;
+
+ for (i = 0; ; i++) {
+ cfg = omap_get_nr_config(OMAP_TAG_GPIO_SWITCH,
+ struct omap_gpio_switch_config, i);
+ if (cfg == NULL)
+ break;
+ sw = kzalloc(sizeof(*sw), GFP_KERNEL);
+ if (sw == NULL) {
+ printk(KERN_ERR "gpio-switch: kmalloc failed\n");
+ return -ENOMEM;
+ }
+ strncpy(sw->name, cfg->name, sizeof(cfg->name));
+ sw->gpio = cfg->gpio;
+ sw->flags = cfg->flags;
+ sw->type = cfg->type;
+ sw->debounce_rising = OMAP_GPIO_SW_DEFAULT_DEBOUNCE;
+ sw->debounce_falling = OMAP_GPIO_SW_DEFAULT_DEBOUNCE;
+ if ((r = new_switch(sw)) < 0) {
+ kfree(sw);
+ return r;
+ }
+ }
+ return 0;
+}
+
+static struct gpio_switch * __init find_switch(int gpio, const char *name)
+{
+ struct gpio_switch *sw;
+
+ list_for_each_entry(sw, &gpio_switches, node) {
+ if ((gpio < 0 || sw->gpio != gpio) &&
+ (name == NULL || strcmp(sw->name, name) != 0))
+ continue;
+
+ if (gpio < 0 || name == NULL)
+ goto no_check;
+
+ if (strcmp(sw->name, name) != 0)
+ printk("gpio-switch: name mismatch for %d (%s, %s)\n",
+ gpio, name, sw->name);
+ else if (sw->gpio != gpio)
+ printk("gpio-switch: GPIO mismatch for %s (%d, %d)\n",
+ name, gpio, sw->gpio);
+no_check:
+ return sw;
+ }
+ return NULL;
+}
+
+static int __init add_board_switches(void)
+{
+ int i;
+
+ for (i = 0; i < board_gpio_sw_count; i++) {
+ const struct omap_gpio_switch *cfg;
+ struct gpio_switch *sw;
+ int r;
+
+ cfg = board_gpio_sw_table + i;
+ if (strlen(cfg->name) > sizeof(sw->name) - 1)
+ return -EINVAL;
+ /* Check whether we only update an existing switch
+ * or add a new switch. */
+ sw = find_switch(cfg->gpio, cfg->name);
+ if (sw != NULL) {
+ sw->debounce_rising = cfg->debounce_rising;
+ sw->debounce_falling = cfg->debounce_falling;
+ sw->notify = cfg->notify;
+ sw->notify_data = cfg->notify_data;
+ continue;
+ } else {
+ if (cfg->gpio < 0 || cfg->name == NULL) {
+ printk("gpio-switch: required switch not "
+ "found (%d, %s)\n", cfg->gpio,
+ cfg->name);
+ continue;
+ }
+ }
+ sw = kzalloc(sizeof(*sw), GFP_KERNEL);
+ if (sw == NULL) {
+ printk(KERN_ERR "gpio-switch: kmalloc failed\n");
+ return -ENOMEM;
+ }
+ strlcpy(sw->name, cfg->name, sizeof(sw->name));
+ sw->gpio = cfg->gpio;
+ sw->flags = cfg->flags;
+ sw->type = cfg->type;
+ sw->debounce_rising = cfg->debounce_rising;
+ sw->debounce_falling = cfg->debounce_falling;
+ sw->notify = cfg->notify;
+ sw->notify_data = cfg->notify_data;
+ if ((r = new_switch(sw)) < 0) {
+ kfree(sw);
+ return r;
+ }
+ }
+ return 0;
+}
+
+static void gpio_sw_cleanup(void)
+{
+ struct gpio_switch *sw = NULL, *old = NULL;
+
+ list_for_each_entry(sw, &gpio_switches, node) {
+ if (old != NULL)
+ kfree(old);
+ flush_scheduled_work();
+ del_timer_sync(&sw->timer);
+
+ free_irq(OMAP_GPIO_IRQ(sw->gpio), sw);
+
+ device_remove_file(&sw->pdev.dev, &dev_attr_state);
+ device_remove_file(&sw->pdev.dev, &dev_attr_type);
+ device_remove_file(&sw->pdev.dev, &dev_attr_direction);
+
+ platform_device_unregister(&sw->pdev);
+ omap_free_gpio(sw->gpio);
+ old = sw;
+ }
+ kfree(old);
+}
+
+static void __init report_initial_state(void)
+{
+ struct gpio_switch *sw;
+
+ list_for_each_entry(sw, &gpio_switches, node) {
+ int state;
+
+ state = omap_get_gpio_datain(sw->gpio);
+ if (sw->flags & OMAP_GPIO_SWITCH_FLAG_INVERTED)
+ state = !state;
+ if (sw->notify != NULL)
+ sw->notify(sw->notify_data, state);
+ print_sw_state(sw, state);
+ }
+}
+
+static int gpio_sw_remove(struct platform_device *dev)
+{
+ return 0;
+}
+
+static struct platform_driver gpio_sw_driver = {
+ .remove = gpio_sw_remove,
+ .driver = {
+ .name = "gpio-switch",
+ },
+};
+
+void __init omap_register_gpio_switches(const struct omap_gpio_switch *tbl,
+ int count)
+{
+ BUG_ON(board_gpio_sw_table != NULL);
+
+ board_gpio_sw_table = tbl;
+ board_gpio_sw_count = count;
+}
+
+static int __init gpio_sw_init(void)
+{
+ int r;
+
+ printk(KERN_INFO "OMAP GPIO switch handler initializing\n");
+
+ r = platform_driver_register(&gpio_sw_driver);
+ if (r)
+ return r;
+
+ gpio_sw_platform_dev = platform_device_register_simple("gpio-switch",
+ -1, NULL, 0);
+ if (IS_ERR(gpio_sw_platform_dev)) {
+ r = PTR_ERR(gpio_sw_platform_dev);
+ goto err1;
+ }
+
+ r = add_atag_switches();
+ if (r < 0)
+ goto err2;
+
+ r = add_board_switches();
+ if (r < 0)
+ goto err2;
+
+ report_initial_state();
+
+ return 0;
+err2:
+ gpio_sw_cleanup();
+ platform_device_unregister(gpio_sw_platform_dev);
+err1:
+ platform_driver_unregister(&gpio_sw_driver);
+ return r;
+}
+
+static void __exit gpio_sw_exit(void)
+{
+ gpio_sw_cleanup();
+ platform_device_unregister(gpio_sw_platform_dev);
+ platform_driver_unregister(&gpio_sw_driver);
+}
+
+#ifndef MODULE
+late_initcall(gpio_sw_init);
+#else
+module_init(gpio_sw_init);
+#endif
+module_exit(gpio_sw_exit);
+
+MODULE_AUTHOR("Juha Yrjölä <juha.yrjola@nokia.com>, Paul Mundt <paul.mundt@nokia.com");
+MODULE_DESCRIPTION("GPIO switch driver");
+MODULE_LICENSE("GPL");
# Rewritten to use lists instead of if-statements.
#
- obj-$(CONFIG_HAVE_GPIO_LIB) += gpio/
+ obj-y += gpio/
obj-$(CONFIG_PCI) += pci/
obj-$(CONFIG_PARISC) += parisc/
obj-$(CONFIG_RAPIDIO) += rapidio/
# default.
obj-y += char/
+ # gpu/ comes after char for AGP vs DRM startup
+ obj-y += gpu/
+
obj-$(CONFIG_CONNECTOR) += connector/
# i810fb and intelfb depend on char/agp/
obj-$(CONFIG_FB_I810) += video/i810/
obj-$(CONFIG_FB_INTEL) += video/intelfb/
+# we also need input/serio early so serio bus is initialized by the time
+# serial drivers start registering their serio ports
+obj-$(CONFIG_SERIO) += input/serio/
obj-y += serial/
obj-$(CONFIG_PARPORT) += parport/
-obj-y += base/ block/ misc/ mfd/ net/ media/
+obj-y += base/ block/ misc/ mfd/ net/ media/ cbus/
+obj-y += i2c/
+obj-y += cbus/
+obj-$(CONFIG_ARCH_OMAP) += dsp/dspgateway/
obj-$(CONFIG_NUBUS) += nubus/
obj-$(CONFIG_ATM) += atm/
obj-y += macintosh/
obj-$(CONFIG_PARIDE) += block/paride/
obj-$(CONFIG_TC) += tc/
obj-$(CONFIG_USB) += usb/
+obj-$(CONFIG_USB_MUSB_HDRC) += usb/musb/
obj-$(CONFIG_PCI) += usb/
obj-$(CONFIG_USB_GADGET) += usb/gadget/
-obj-$(CONFIG_SERIO) += input/serio/
obj-$(CONFIG_GAMEPORT) += input/gameport/
obj-$(CONFIG_INPUT) += input/
obj-$(CONFIG_I2O) += message/
obj-$(CONFIG_RTC_LIB) += rtc/
-obj-y += i2c/
obj-$(CONFIG_W1) += w1/
obj-$(CONFIG_POWER_SUPPLY) += power/
obj-$(CONFIG_HWMON) += hwmon/
obj-$(CONFIG_OF) += of/
obj-$(CONFIG_SSB) += ssb/
obj-$(CONFIG_VIRTIO) += virtio/
+ obj-$(CONFIG_REGULATOR) += regulator/
config BT_HCIUART_BCSP
bool "BCSP protocol support"
depends on BT_HCIUART
+ select BITREVERSE
help
BCSP (BlueCore Serial Protocol) is serial protocol for communication
between Bluetooth device and host. This protocol is required for non
Say Y here to compile support for HCI UART devices into the
kernel or say M to compile it as module (btuart_cs).
+config BT_HCIBRF6150
+ tristate "HCI TI BRF6150 driver with H4 extensions"
+ depends on BT && ARCH_OMAP
+ help
+ Bluetooth HCI driver for TI BRF6150 with H4 extensions.
+ This driver provides support for BRF6150 Bluetooth chip
+ with vendor-specific H4 extensions.
+
+ Say Y here to compile support for TI BRF6150 devices into the
+ kernel or say M to compile it as module (brf6150).
+
+config BT_HCIH4P
+ tristate "HCI driver with H4 Nokia extensions"
+ depends on BT && ARCH_OMAP
+ help
+ Bluetooth HCI driver with H4 extensions. This driver provides
+ support for H4+ Bluetooth chip with vendor-specific H4 extensions.
+
+ Say Y here to compile support for h4 extended devices into the kernel
+ or say M to compile it as module (hci_h4p).
+
config BT_HCIVHCI
tristate "HCI VHCI (Virtual HCI device) driver"
help
--- /dev/null
- set_irq_type(OMAP_GPIO_IRQ(info->btinfo->host_wakeup_gpio), IRQT_NOEDGE);
+/*
+ * linux/drivers/bluetooth/brf6150/brf6150.c
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ * Written by Ville Tervo <ville.tervo@nokia.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/module.h>
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/serial_reg.h>
+#include <linux/skbuff.h>
+#include <linux/firmware.h>
+#include <linux/irq.h>
+#include <linux/timer.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/board.h>
+#include <asm/arch/irqs.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/hci.h>
+
+#include "brf6150.h"
+
+#if 0
+#define NBT_DBG(fmt, arg...) printk("%s: " fmt "" , __FUNCTION__ , ## arg)
+#else
+#define NBT_DBG(...)
+#endif
+
+#if 0
+#define NBT_DBG_FW(fmt, arg...) printk("%s: " fmt "" , __FUNCTION__ , ## arg)
+#else
+#define NBT_DBG_FW(...)
+#endif
+
+#if 0
+#define NBT_DBG_POWER(fmt, arg...) printk("%s: " fmt "" , __FUNCTION__ , ## arg)
+#else
+#define NBT_DBG_POWER(...)
+#endif
+
+#if 0
+#define NBT_DBG_TRANSFER(fmt, arg...) printk("%s: " fmt "" , __FUNCTION__ , ## arg)
+#else
+#define NBT_DBG_TRANSFER(...)
+#endif
+
+#if 0
+#define NBT_DBG_TRANSFER_NF(fmt, arg...) printk(fmt "" , ## arg)
+#else
+#define NBT_DBG_TRANSFER_NF(...)
+#endif
+
+#define PM_TIMEOUT (2000)
+
+static void brf6150_device_release(struct device *dev);
+static struct brf6150_info *exit_info;
+
+static struct platform_device brf6150_device = {
+ .name = BT_DEVICE,
+ .id = -1,
+ .num_resources = 0,
+ .dev = {
+ .release = brf6150_device_release,
+ }
+};
+
+static struct device_driver brf6150_driver = {
+ .name = BT_DRIVER,
+ .bus = &platform_bus_type,
+};
+
+static inline void brf6150_outb(struct brf6150_info *info, unsigned int offset, u8 val)
+{
+ outb(val, info->uart_base + (offset << 2));
+}
+
+static inline u8 brf6150_inb(struct brf6150_info *info, unsigned int offset)
+{
+ return inb(info->uart_base + (offset << 2));
+}
+
+static void brf6150_set_rts(struct brf6150_info *info, int active)
+{
+ u8 b;
+
+ b = brf6150_inb(info, UART_MCR);
+ if (active)
+ b |= UART_MCR_RTS;
+ else
+ b &= ~UART_MCR_RTS;
+ brf6150_outb(info, UART_MCR, b);
+}
+
+static void brf6150_wait_for_cts(struct brf6150_info *info, int active,
+ int timeout_ms)
+{
+ int okay;
+ unsigned long timeout;
+
+ okay = 0;
+ timeout = jiffies + msecs_to_jiffies(timeout_ms);
+ for (;;) {
+ int state;
+
+ state = brf6150_inb(info, UART_MSR) & UART_MSR_CTS;
+ if (active) {
+ if (state)
+ break;
+ } else {
+ if (!state)
+ break;
+ }
+ if (jiffies > timeout)
+ break;
+ }
+}
+
+static inline void brf6150_set_auto_ctsrts(struct brf6150_info *info, int on)
+{
+ u8 lcr, b;
+
+ lcr = brf6150_inb(info, UART_LCR);
+ brf6150_outb(info, UART_LCR, 0xbf);
+ b = brf6150_inb(info, UART_EFR);
+ if (on)
+ b |= UART_EFR_CTS | UART_EFR_RTS;
+ else
+ b &= ~(UART_EFR_CTS | UART_EFR_RTS);
+ brf6150_outb(info, UART_EFR, b);
+ brf6150_outb(info, UART_LCR, lcr);
+}
+
+static inline void brf6150_enable_pm_rx(struct brf6150_info *info)
+{
+ if (info->pm_enabled) {
+ info->rx_pm_enabled = 1;
+ }
+}
+
+static inline void brf6150_disable_pm_rx(struct brf6150_info *info)
+{
+ if (info->pm_enabled) {
+ info->rx_pm_enabled = 0;
+ }
+}
+
+static void brf6150_enable_pm_tx(struct brf6150_info *info)
+{
+ if (info->pm_enabled) {
+ mod_timer(&info->pm_timer, jiffies + msecs_to_jiffies(PM_TIMEOUT));
+ info->tx_pm_enabled = 1;
+ }
+}
+
+static void brf6150_disable_pm_tx(struct brf6150_info *info)
+{
+ if (info->pm_enabled) {
+ info->tx_pm_enabled = 0;
+ omap_set_gpio_dataout(info->btinfo->bt_wakeup_gpio, 1);
+ }
+ if (omap_get_gpio_datain(info->btinfo->host_wakeup_gpio))
+ tasklet_schedule(&info->tx_task);
+}
+
+static void brf6150_pm_timer(unsigned long data)
+{
+ struct brf6150_info *info;
+
+ info = (struct brf6150_info *)data;
+ if (info->tx_pm_enabled && info->rx_pm_enabled && !test_bit(HCI_INQUIRY, &info->hdev->flags))
+ omap_set_gpio_dataout(info->btinfo->bt_wakeup_gpio, 0);
+ else
+ mod_timer(&info->pm_timer, jiffies + msecs_to_jiffies(PM_TIMEOUT));
+}
+
+static int brf6150_change_speed(struct brf6150_info *info, unsigned long speed)
+{
+ unsigned int divisor;
+ u8 lcr, mdr1;
+
+ NBT_DBG("Setting speed %lu\n", speed);
+
+ if (speed >= 460800) {
+ divisor = UART_CLOCK / 13 / speed;
+ mdr1 = 3;
+ } else {
+ divisor = UART_CLOCK / 16 / speed;
+ mdr1 = 0;
+ }
+
+ brf6150_outb(info, UART_OMAP_MDR1, 7); /* Make sure UART mode is disabled */
+ lcr = brf6150_inb(info, UART_LCR);
+ brf6150_outb(info, UART_LCR, UART_LCR_DLAB); /* Set DLAB */
+ brf6150_outb(info, UART_DLL, divisor & 0xff); /* Set speed */
+ brf6150_outb(info, UART_DLM, divisor >> 8);
+ brf6150_outb(info, UART_LCR, lcr);
+ brf6150_outb(info, UART_OMAP_MDR1, mdr1); /* Make sure UART mode is enabled */
+
+ return 0;
+}
+
+/* Firmware handling */
+static int brf6150_open_firmware(struct brf6150_info *info)
+{
+ int err;
+
+ info->fw_pos = 0;
+ err = request_firmware(&info->fw_entry, "brf6150fw.bin", &brf6150_device.dev);
+
+ return err;
+}
+
+static struct sk_buff *brf6150_read_fw_cmd(struct brf6150_info *info, int how)
+{
+ struct sk_buff *skb;
+ unsigned int cmd_len;
+
+ if (info->fw_pos >= info->fw_entry->size) {
+ return NULL;
+ }
+
+ cmd_len = info->fw_entry->data[info->fw_pos++];
+ if (!cmd_len)
+ return NULL;
+
+ if (info->fw_pos + cmd_len > info->fw_entry->size) {
+ printk(KERN_WARNING "Corrupted firmware image\n");
+ return NULL;
+ }
+
+ skb = bt_skb_alloc(cmd_len, how);
+ if (!skb) {
+ printk(KERN_WARNING "Cannot reserve memory for buffer\n");
+ return NULL;
+ }
+ memcpy(skb_put(skb, cmd_len), &info->fw_entry->data[info->fw_pos], cmd_len);
+
+ info->fw_pos += cmd_len;
+
+ return skb;
+}
+
+static int brf6150_close_firmware(struct brf6150_info *info)
+{
+ release_firmware(info->fw_entry);
+ return 0;
+}
+
+static int brf6150_send_alive_packet(struct brf6150_info *info)
+{
+ struct sk_buff *skb;
+
+ NBT_DBG("Sending alive packet\n");
+ skb = brf6150_read_fw_cmd(info, GFP_ATOMIC);
+ if (!skb) {
+ printk(KERN_WARNING "Cannot read alive command");
+ return -1;
+ }
+
+ clk_enable(info->uart_ck);
+ skb_queue_tail(&info->txq, skb);
+ tasklet_schedule(&info->tx_task);
+
+ NBT_DBG("Alive packet sent\n");
+ return 0;
+}
+
+static void brf6150_alive_packet(struct brf6150_info *info, struct sk_buff *skb)
+{
+ NBT_DBG("Received alive packet\n");
+ if (skb->data[1] == 0xCC) {
+ complete(&info->init_completion);
+ }
+
+ kfree_skb(skb);
+}
+
+static int brf6150_send_negotiation(struct brf6150_info *info)
+{
+ struct sk_buff *skb;
+ NBT_DBG("Sending negotiation..\n");
+
+ brf6150_change_speed(info, INIT_SPEED);
+
+ skb = brf6150_read_fw_cmd(info, GFP_KERNEL);
+
+ if (!skb) {
+ printk(KERN_WARNING "Cannot read negoatiation message");
+ return -1;
+ }
+
+ clk_enable(info->uart_ck);
+ skb_queue_tail(&info->txq, skb);
+ tasklet_schedule(&info->tx_task);
+
+
+ NBT_DBG("Negotiation sent\n");
+ return 0;
+}
+
+static void brf6150_negotiation_packet(struct brf6150_info *info,
+ struct sk_buff *skb)
+{
+ if (skb->data[1] == 0x20) {
+ /* Change to operational settings */
+ brf6150_set_rts(info, 0);
+ brf6150_wait_for_cts(info, 0, 100);
+ brf6150_change_speed(info, MAX_BAUD_RATE);
+ brf6150_set_rts(info, 1);
+ brf6150_wait_for_cts(info, 1, 100);
+ brf6150_set_auto_ctsrts(info, 1);
+ brf6150_send_alive_packet(info);
+ } else {
+ printk(KERN_WARNING "Could not negotiate brf6150 settings\n");
+ }
+ kfree_skb(skb);
+}
+
+static int brf6150_get_hdr_len(u8 pkt_type)
+{
+ long retval;
+
+ switch (pkt_type) {
+ case H4_EVT_PKT:
+ retval = HCI_EVENT_HDR_SIZE;
+ break;
+ case H4_ACL_PKT:
+ retval = HCI_ACL_HDR_SIZE;
+ break;
+ case H4_SCO_PKT:
+ retval = HCI_SCO_HDR_SIZE;
+ break;
+ case H4_NEG_PKT:
+ retval = 9;
+ break;
+ case H4_ALIVE_PKT:
+ retval = 3;
+ break;
+ default:
+ printk(KERN_ERR "brf6150: Unknown H4 packet");
+ retval = -1;
+ break;
+ }
+
+ return retval;
+}
+
+static unsigned int brf6150_get_data_len(struct brf6150_info *info,
+ struct sk_buff *skb)
+{
+ long retval = -1;
+ struct hci_event_hdr *evt_hdr;
+ struct hci_acl_hdr *acl_hdr;
+ struct hci_sco_hdr *sco_hdr;
+
+ switch (bt_cb(skb)->pkt_type) {
+ case H4_EVT_PKT:
+ evt_hdr = (struct hci_event_hdr *)skb->data;
+ retval = evt_hdr->plen;
+ break;
+ case H4_ACL_PKT:
+ acl_hdr = (struct hci_acl_hdr *)skb->data;
+ retval = le16_to_cpu(acl_hdr->dlen);
+ break;
+ case H4_SCO_PKT:
+ sco_hdr = (struct hci_sco_hdr *)skb->data;
+ retval = sco_hdr->dlen;
+ break;
+ case H4_NEG_PKT:
+ retval = 0;
+ break;
+ case H4_ALIVE_PKT:
+ retval = 0;
+ break;
+ }
+
+ return retval;
+}
+
+static void brf6150_parse_fw_event(struct brf6150_info *info)
+{
+ struct hci_fw_event *ev;
+
+ if (bt_cb(info->rx_skb)->pkt_type != H4_EVT_PKT) {
+ printk(KERN_WARNING "Got non event fw packet.\n");
+ info->fw_error = 1;
+ return;
+ }
+
+ ev = (struct hci_fw_event *)info->rx_skb->data;
+ if (ev->hev.evt != HCI_EV_CMD_COMPLETE) {
+ printk(KERN_WARNING "Got non cmd complete fw event\n");
+ info->fw_error = 1;
+ return;
+ }
+
+ if (ev->status != 0) {
+ printk(KERN_WARNING "Got error status from fw command\n");
+ info->fw_error = 1;
+ return;
+ }
+
+ complete(&info->fw_completion);
+}
+
+static inline void brf6150_recv_frame(struct brf6150_info *info,
+ struct sk_buff *skb)
+{
+ if (unlikely(!test_bit(HCI_RUNNING, &info->hdev->flags))) {
+ NBT_DBG("fw_event\n");
+ brf6150_parse_fw_event(info);
+ kfree_skb(skb);
+ } else {
+ hci_recv_frame(skb);
+ if (!(brf6150_inb(info, UART_LSR) & UART_LSR_DR))
+ brf6150_enable_pm_rx(info);
+ NBT_DBG("Frame sent to upper layer\n");
+ }
+
+}
+
+static inline void brf6150_rx(struct brf6150_info *info)
+{
+ u8 byte;
+
+ NBT_DBG_TRANSFER("rx_tasklet woke up\ndata ");
+
+ while (brf6150_inb(info, UART_LSR) & UART_LSR_DR) {
+ if (info->rx_skb == NULL) {
+ info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
+ if (!info->rx_skb) {
+ printk(KERN_WARNING "brf6150: Can't allocate memory for new packet\n");
+ return;
+ }
+ info->rx_state = WAIT_FOR_PKT_TYPE;
+ info->rx_skb->dev = (void *)info->hdev;
+ brf6150_disable_pm_rx(info);
+ clk_enable(info->uart_ck);
+ }
+
+ byte = brf6150_inb(info, UART_RX);
+ if (info->garbage_bytes) {
+ info->garbage_bytes--;
+ info->hdev->stat.err_rx++;
+ continue;
+ }
+ info->hdev->stat.byte_rx++;
+ NBT_DBG_TRANSFER_NF("0x%.2x ", byte);
+ switch (info->rx_state) {
+ case WAIT_FOR_PKT_TYPE:
+ bt_cb(info->rx_skb)->pkt_type = byte;
+ info->rx_count = brf6150_get_hdr_len(byte);
+ if (info->rx_count >= 0) {
+ info->rx_state = WAIT_FOR_HEADER;
+ } else {
+ info->hdev->stat.err_rx++;
+ kfree_skb(info->rx_skb);
+ info->rx_skb = NULL;
+ clk_disable(info->uart_ck);
+ }
+ break;
+ case WAIT_FOR_HEADER:
+ info->rx_count--;
+ *skb_put(info->rx_skb, 1) = byte;
+ if (info->rx_count == 0) {
+ info->rx_count = brf6150_get_data_len(info, info->rx_skb);
+ if (info->rx_count > skb_tailroom(info->rx_skb)) {
+ printk(KERN_WARNING "brf6150: Frame is %ld bytes too long.\n",
+ info->rx_count - skb_tailroom(info->rx_skb));
+ info->rx_skb = NULL;
+ info->garbage_bytes = info->rx_count - skb_tailroom(info->rx_skb);
+ clk_disable(info->uart_ck);
+ break;
+ }
+ info->rx_state = WAIT_FOR_DATA;
+ if (bt_cb(info->rx_skb)->pkt_type == H4_NEG_PKT) {
+ brf6150_negotiation_packet(info, info->rx_skb);
+ info->rx_skb = NULL;
+ clk_disable(info->uart_ck);
+ return;
+ }
+ if (bt_cb(info->rx_skb)->pkt_type == H4_ALIVE_PKT) {
+ brf6150_alive_packet(info, info->rx_skb);
+ info->rx_skb = NULL;
+ clk_disable(info->uart_ck);
+ return;
+ }
+ }
+ break;
+ case WAIT_FOR_DATA:
+ info->rx_count--;
+ *skb_put(info->rx_skb, 1) = byte;
+ if (info->rx_count == 0) {
+ brf6150_recv_frame(info, info->rx_skb);
+ info->rx_skb = NULL;
+ clk_disable(info->uart_ck);
+ }
+ break;
+ default:
+ WARN_ON(1);
+ break;
+ }
+ }
+
+ NBT_DBG_TRANSFER_NF("\n");
+}
+
+static void brf6150_tx_tasklet(unsigned long data)
+{
+ unsigned int sent = 0;
+ unsigned long flags;
+ struct sk_buff *skb;
+ struct brf6150_info *info = (struct brf6150_info *)data;
+
+ NBT_DBG_TRANSFER("tx_tasklet woke up\n data ");
+
+ skb = skb_dequeue(&info->txq);
+ if (!skb) {
+ /* No data in buffer */
+ brf6150_enable_pm_tx(info);
+ return;
+ }
+
+ /* Copy data to tx fifo */
+ while (!(brf6150_inb(info, UART_OMAP_SSR) & UART_OMAP_SSR_TXFULL) &&
+ (sent < skb->len)) {
+ NBT_DBG_TRANSFER_NF("0x%.2x ", skb->data[sent]);
+ brf6150_outb(info, UART_TX, skb->data[sent]);
+ sent++;
+ }
+
+ info->hdev->stat.byte_tx += sent;
+ NBT_DBG_TRANSFER_NF("\n");
+ if (skb->len == sent) {
+ kfree_skb(skb);
+ clk_disable(info->uart_ck);
+ } else {
+ skb_pull(skb, sent);
+ skb_queue_head(&info->txq, skb);
+ }
+
+ spin_lock_irqsave(&info->lock, flags);
+ brf6150_outb(info, UART_IER, brf6150_inb(info, UART_IER) | UART_IER_THRI);
+ spin_unlock_irqrestore(&info->lock, flags);
+}
+
+static irqreturn_t brf6150_interrupt(int irq, void *data)
+{
+ struct brf6150_info *info = (struct brf6150_info *)data;
+ u8 iir, msr;
+ int ret;
+ unsigned long flags;
+
+ ret = IRQ_NONE;
+
+ clk_enable(info->uart_ck);
+ iir = brf6150_inb(info, UART_IIR);
+ if (iir & UART_IIR_NO_INT) {
+ printk("Interrupt but no reason irq 0x%.2x\n", iir);
+ clk_disable(info->uart_ck);
+ return IRQ_HANDLED;
+ }
+
+ NBT_DBG("In interrupt handler iir 0x%.2x\n", iir);
+
+ iir &= UART_IIR_ID;
+
+ if (iir == UART_IIR_MSI) {
+ msr = brf6150_inb(info, UART_MSR);
+ ret = IRQ_HANDLED;
+ }
+ if (iir == UART_IIR_RLSI) {
+ brf6150_inb(info, UART_RX);
+ brf6150_inb(info, UART_LSR);
+ ret = IRQ_HANDLED;
+ }
+
+ if (iir == UART_IIR_RDI) {
+ brf6150_rx(info);
+ ret = IRQ_HANDLED;
+ }
+
+ if (iir == UART_IIR_THRI) {
+ spin_lock_irqsave(&info->lock, flags);
+ brf6150_outb(info, UART_IER, brf6150_inb(info, UART_IER) & ~UART_IER_THRI);
+ spin_unlock_irqrestore(&info->lock, flags);
+ tasklet_schedule(&info->tx_task);
+ ret = IRQ_HANDLED;
+ }
+
+ clk_disable(info->uart_ck);
+ return ret;
+}
+
+static irqreturn_t brf6150_wakeup_interrupt(int irq, void *dev_inst)
+{
+ struct brf6150_info *info = dev_inst;
+ int should_wakeup;
+ unsigned long flags;
+
+ spin_lock_irqsave(&info->lock, flags);
+ should_wakeup = omap_get_gpio_datain(info->btinfo->host_wakeup_gpio);
+ NBT_DBG_POWER("gpio interrupt %d\n", should_wakeup);
+ if (should_wakeup) {
+ clk_enable(info->uart_ck);
+ brf6150_set_auto_ctsrts(info, 1);
+ brf6150_rx(info);
+ tasklet_schedule(&info->tx_task);
+ } else {
+ brf6150_set_auto_ctsrts(info, 0);
+ brf6150_set_rts(info, 0);
+ clk_disable(info->uart_ck);
+ }
+
+ spin_unlock_irqrestore(&info->lock, flags);
+ return IRQ_HANDLED;
+}
+
+static int brf6150_init_uart(struct brf6150_info *info)
+{
+ int count = 0;
+
+ /* Reset the UART */
+ brf6150_outb(info, UART_OMAP_SYSC, UART_SYSC_OMAP_RESET);
+ while (!(brf6150_inb(info, UART_OMAP_SYSS) & UART_SYSS_RESETDONE)) {
+ if (count++ > 100) {
+ printk(KERN_ERR "brf6150: UART reset timeout\n");
+ return -1;
+ }
+ udelay(1);
+ }
+
+ /* Enable and setup FIFO */
+ brf6150_outb(info, UART_LCR, UART_LCR_WLEN8);
+ brf6150_outb(info, UART_OMAP_MDR1, 0x00); /* Make sure UART mode is enabled */
+ brf6150_outb(info, UART_OMAP_SCR, 0x00);
+ brf6150_outb(info, UART_EFR, brf6150_inb(info, UART_EFR) | UART_EFR_ECB);
+ brf6150_outb(info, UART_MCR, brf6150_inb(info, UART_MCR) | UART_MCR_TCRTLR);
+ brf6150_outb(info, UART_TI752_TLR, 0xff);
+ brf6150_outb(info, UART_TI752_TCR, 0x1f);
+ brf6150_outb(info, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
+ brf6150_outb(info, UART_IER, UART_IER_RDI);
+
+ return 0;
+}
+
+static int brf6150_reset(struct brf6150_info *info)
+{
+ omap_set_gpio_dataout(info->btinfo->bt_wakeup_gpio, 0);
+ omap_set_gpio_dataout(info->btinfo->reset_gpio, 0);
+ current->state = TASK_UNINTERRUPTIBLE;
+ schedule_timeout(msecs_to_jiffies(10));
+ omap_set_gpio_dataout(info->btinfo->bt_wakeup_gpio, 1);
+ current->state = TASK_UNINTERRUPTIBLE;
+ schedule_timeout(msecs_to_jiffies(100));
+ omap_set_gpio_dataout(info->btinfo->reset_gpio, 1);
+ current->state = TASK_UNINTERRUPTIBLE;
+ schedule_timeout(msecs_to_jiffies(100));
+
+ return 0;
+}
+
+static int brf6150_send_firmware(struct brf6150_info *info)
+{
+ struct sk_buff *skb;
+
+ init_completion(&info->fw_completion);
+ info->fw_error = 0;
+
+ while ((skb = brf6150_read_fw_cmd(info, GFP_KERNEL)) != NULL) {
+ clk_enable(info->uart_ck);
+ skb_queue_tail(&info->txq, skb);
+ tasklet_schedule(&info->tx_task);
+
+ if (!wait_for_completion_timeout(&info->fw_completion, HZ)) {
+ return -1;
+ }
+
+ if (info->fw_error) {
+ return -1;
+ }
+ }
+ NBT_DBG_FW("Firmware sent\n");
+
+ return 0;
+
+}
+
+/* hci callback functions */
+static int brf6150_hci_flush(struct hci_dev *hdev)
+{
+ struct brf6150_info *info;
+ info = hdev->driver_data;
+
+ skb_queue_purge(&info->txq);
+
+ return 0;
+}
+
+static int brf6150_hci_open(struct hci_dev *hdev)
+{
+ struct brf6150_info *info;
+ int err;
+
+ info = hdev->driver_data;
+
+ if (test_bit(HCI_RUNNING, &hdev->flags))
+ return 0;
+
+ if (brf6150_open_firmware(info) < 0) {
+ printk("Cannot open firmware\n");
+ return -1;
+ }
+
+ info->rx_state = WAIT_FOR_PKT_TYPE;
+ info->rx_count = 0;
+ info->garbage_bytes = 0;
+ info->rx_skb = NULL;
+ info->pm_enabled = 0;
- set_irq_type(OMAP_GPIO_IRQ(info->btinfo->host_wakeup_gpio), IRQT_BOTHEDGE);
++ set_irq_type(OMAP_GPIO_IRQ(info->btinfo->host_wakeup_gpio), IRQ_TYPE_NONE);
+ init_completion(&info->fw_completion);
+
+ clk_enable(info->uart_ck);
+
+ brf6150_init_uart(info);
+ brf6150_set_auto_ctsrts(info, 0);
+ brf6150_set_rts(info, 0);
+ brf6150_reset(info);
+ brf6150_wait_for_cts(info, 1, 10);
+ brf6150_set_rts(info, 1);
+ if (brf6150_send_negotiation(info)) {
+ brf6150_close_firmware(info);
+ return -1;
+ }
+
+ if (!wait_for_completion_interruptible_timeout(&info->init_completion, HZ)) {
+ brf6150_close_firmware(info);
+ clk_disable(info->uart_ck);
+ clear_bit(HCI_RUNNING, &hdev->flags);
+ return -1;
+ }
+ brf6150_set_auto_ctsrts(info, 1);
+
+ err = brf6150_send_firmware(info);
+ brf6150_close_firmware(info);
+ if (err < 0)
+ printk(KERN_ERR "brf6150: Sending firmware failed. Bluetooth won't work properly\n");
+
- set_irq_type(OMAP_GPIO_IRQ(info->btinfo->host_wakeup_gpio), IRQT_NOEDGE);
++ set_irq_type(OMAP_GPIO_IRQ(info->btinfo->host_wakeup_gpio), IRQ_TYPE_EDGE_BOTH);
+ info->pm_enabled = 1;
+ set_bit(HCI_RUNNING, &hdev->flags);
+ return 0;
+}
+
+static int brf6150_hci_close(struct hci_dev *hdev)
+{
+ struct brf6150_info *info = hdev->driver_data;
+ if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
+ return 0;
+
+ brf6150_hci_flush(hdev);
+ clk_disable(info->uart_ck);
+ del_timer_sync(&info->pm_timer);
+ omap_set_gpio_dataout(info->btinfo->bt_wakeup_gpio, 0);
- set_irq_type(OMAP_GPIO_IRQ(info->btinfo->host_wakeup_gpio), IRQT_NOEDGE);
++ set_irq_type(OMAP_GPIO_IRQ(info->btinfo->host_wakeup_gpio), IRQ_TYPE_NONE);
+
+ return 0;
+}
+
+static void brf6150_hci_destruct(struct hci_dev *hdev)
+{
+}
+
+static int brf6150_hci_send_frame(struct sk_buff *skb)
+{
+ struct brf6150_info *info;
+ struct hci_dev *hdev = (struct hci_dev *)skb->dev;
+
+ if (!hdev) {
+ printk(KERN_WARNING "brf6150: Frame for unknown device\n");
+ return -ENODEV;
+ }
+
+ if (!test_bit(HCI_RUNNING, &hdev->flags)) {
+ printk(KERN_WARNING "brf6150: Frame for non-running device\n");
+ return -EIO;
+ }
+
+ info = hdev->driver_data;
+
+ switch (bt_cb(skb)->pkt_type) {
+ case HCI_COMMAND_PKT:
+ hdev->stat.cmd_tx++;
+ break;
+ case HCI_ACLDATA_PKT:
+ hdev->stat.acl_tx++;
+ break;
+ case HCI_SCODATA_PKT:
+ hdev->stat.sco_tx++;
+ break;
+ };
+
+ /* Push frame type to skb */
+ clk_enable(info->uart_ck);
+ *skb_push(skb, 1) = bt_cb(skb)->pkt_type;
+ skb_queue_tail(&info->txq, skb);
+
+ brf6150_disable_pm_tx(info);
+
+ return 0;
+}
+
+static int brf6150_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
+{
+ return -ENOIOCTLCMD;
+}
+
+static void brf6150_device_release(struct device *dev)
+{
+}
+
+static int brf6150_register_hdev(struct brf6150_info *info)
+{
+ struct hci_dev *hdev;
+
+ /* Initialize and register HCI device */
+
+ hdev = hci_alloc_dev();
+ if (!hdev) {
+ printk(KERN_WARNING "brf6150: Can't allocate memory for device\n");
+ return -ENOMEM;
+ }
+ info->hdev = hdev;
+
+ hdev->type = HCI_UART;
+ hdev->driver_data = info;
+
+ hdev->open = brf6150_hci_open;
+ hdev->close = brf6150_hci_close;
+ hdev->destruct = brf6150_hci_destruct;
+ hdev->flush = brf6150_hci_flush;
+ hdev->send = brf6150_hci_send_frame;
+ hdev->destruct = brf6150_hci_destruct;
+ hdev->ioctl = brf6150_hci_ioctl;
+
+ hdev->owner = THIS_MODULE;
+
+ if (hci_register_dev(hdev) < 0) {
+ printk(KERN_WARNING "brf6150: Can't register HCI device %s.\n", hdev->name);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int __init brf6150_init(void)
+{
+ struct brf6150_info *info;
+ int irq, err;
+
+ info = kmalloc(sizeof(struct brf6150_info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+ memset(info, 0, sizeof(struct brf6150_info));
+
+ brf6150_device.dev.driver_data = info;
+ init_completion(&info->init_completion);
+ init_completion(&info->fw_completion);
+ info->pm_enabled = 0;
+ info->rx_pm_enabled = 0;
+ info->tx_pm_enabled = 0;
+ info->garbage_bytes = 0;
+ tasklet_init(&info->tx_task, brf6150_tx_tasklet, (unsigned long)info);
+ spin_lock_init(&info->lock);
+ skb_queue_head_init(&info->txq);
+ init_timer(&info->pm_timer);
+ info->pm_timer.function = brf6150_pm_timer;
+ info->pm_timer.data = (unsigned long)info;
+ exit_info = NULL;
+
+ info->btinfo = omap_get_config(OMAP_TAG_NOKIA_BT, struct omap_bluetooth_config);
+ if (info->btinfo == NULL)
+ return -1;
+
+ NBT_DBG("RESET gpio: %d\n", info->btinfo->reset_gpio);
+ NBT_DBG("BTWU gpio: %d\n", info->btinfo->bt_wakeup_gpio);
+ NBT_DBG("HOSTWU gpio: %d\n", info->btinfo->host_wakeup_gpio);
+ NBT_DBG("Uart: %d\n", info->btinfo->bt_uart);
+ NBT_DBG("sysclk: %d\n", info->btinfo->bt_sysclk);
+
+ err = omap_request_gpio(info->btinfo->reset_gpio);
+ if (err < 0)
+ {
+ printk(KERN_WARNING "Cannot get GPIO line %d",
+ info->btinfo->reset_gpio);
+ kfree(info);
+ return err;
+ }
+
+ err = omap_request_gpio(info->btinfo->bt_wakeup_gpio);
+ if (err < 0)
+ {
+ printk(KERN_WARNING "Cannot get GPIO line 0x%d",
+ info->btinfo->bt_wakeup_gpio);
+ omap_free_gpio(info->btinfo->reset_gpio);
+ kfree(info);
+ return err;
+ }
+
+ err = omap_request_gpio(info->btinfo->host_wakeup_gpio);
+ if (err < 0)
+ {
+ printk(KERN_WARNING "Cannot get GPIO line %d",
+ info->btinfo->host_wakeup_gpio);
+ omap_free_gpio(info->btinfo->reset_gpio);
+ omap_free_gpio(info->btinfo->bt_wakeup_gpio);
+ kfree(info);
+ return err;
+ }
+
+ omap_set_gpio_direction(info->btinfo->reset_gpio, 0);
+ omap_set_gpio_direction(info->btinfo->bt_wakeup_gpio, 0);
+ omap_set_gpio_direction(info->btinfo->host_wakeup_gpio, 1);
++ set_irq_type(OMAP_GPIO_IRQ(info->btinfo->host_wakeup_gpio), IRQ_TYPE_NONE);
+
+ switch (info->btinfo->bt_uart) {
+ case 1:
+ irq = INT_UART1;
+ info->uart_ck = clk_get(NULL, "uart1_ck");
+ info->uart_base = io_p2v((unsigned long)OMAP_UART1_BASE);
+ break;
+ case 2:
+ irq = INT_UART2;
+ info->uart_ck = clk_get(NULL, "uart2_ck");
+ info->uart_base = io_p2v((unsigned long)OMAP_UART2_BASE);
+ break;
+ case 3:
+ irq = INT_UART3;
+ info->uart_ck = clk_get(NULL, "uart3_ck");
+ info->uart_base = io_p2v((unsigned long)OMAP_UART3_BASE);
+ break;
+ default:
+ printk(KERN_ERR "No uart defined\n");
+ goto cleanup;
+ }
+
+ info->irq = irq;
+ err = request_irq(irq, brf6150_interrupt, 0, "brf6150", (void *)info);
+ if (err < 0) {
+ printk(KERN_ERR "brf6150: unable to get IRQ %d\n", irq);
+ goto cleanup;
+ }
+
+ err = request_irq(OMAP_GPIO_IRQ(info->btinfo->host_wakeup_gpio),
+ brf6150_wakeup_interrupt, 0, "brf6150_wkup", (void *)info);
+ if (err < 0) {
+ printk(KERN_ERR "brf6150: unable to get wakeup IRQ %d\n",
+ OMAP_GPIO_IRQ(info->btinfo->host_wakeup_gpio));
+ free_irq(irq, (void *)info);
+ goto cleanup;
+ }
+
+ /* Register with LDM */
+ if (platform_device_register(&brf6150_device)) {
+ printk(KERN_ERR "failed to register brf6150 device\n");
+ err = -ENODEV;
+ goto cleanup_irq;
+ }
+ /* Register the driver with LDM */
+ if (driver_register(&brf6150_driver)) {
+ printk(KERN_WARNING "failed to register brf6150 driver\n");
+ platform_device_unregister(&brf6150_device);
+ err = -ENODEV;
+ goto cleanup_irq;
+ }
+
+ if (brf6150_register_hdev(info) < 0) {
+ printk(KERN_WARNING "failed to register brf6150 hci device\n");
+ platform_device_unregister(&brf6150_device);
+ driver_unregister(&brf6150_driver);
+ goto cleanup_irq;
+ }
+
+ exit_info = info;
+ return 0;
+
+cleanup_irq:
+ free_irq(irq, (void *)info);
+ free_irq(OMAP_GPIO_IRQ(info->btinfo->host_wakeup_gpio), (void *)info);
+cleanup:
+ omap_free_gpio(info->btinfo->reset_gpio);
+ omap_free_gpio(info->btinfo->bt_wakeup_gpio);
+ omap_free_gpio(info->btinfo->host_wakeup_gpio);
+ kfree(info);
+
+ return err;
+}
+
+static void __exit brf6150_exit(void)
+{
+ brf6150_hci_close(exit_info->hdev);
+ hci_free_dev(exit_info->hdev);
+ omap_free_gpio(exit_info->btinfo->reset_gpio);
+ omap_free_gpio(exit_info->btinfo->bt_wakeup_gpio);
+ omap_free_gpio(exit_info->btinfo->host_wakeup_gpio);
+ free_irq(exit_info->irq, (void *)exit_info);
+ free_irq(OMAP_GPIO_IRQ(exit_info->btinfo->host_wakeup_gpio), (void *)exit_info);
+ kfree(exit_info);
+}
+
+module_init(brf6150_init);
+module_exit(brf6150_exit);
+
+MODULE_DESCRIPTION("brf6150 hci driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ville Tervo <ville.tervo@nokia.com>");
--- /dev/null
- set_irq_type(OMAP_GPIO_IRQ(retu_irq_pin), IRQT_RISING);
+/**
+ * drivers/cbus/retu.c
+ *
+ * Support functions for Retu ASIC
+ *
+ * Copyright (C) 2004, 2005 Nokia Corporation
+ *
+ * Written by Juha Yrjölä <juha.yrjola@nokia.com>,
+ * David Weinehall <david.weinehall@nokia.com>, and
+ * Mikko Ylinen <mikko.k.ylinen@nokia.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/miscdevice.h>
+#include <linux/poll.h>
+#include <linux/fs.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+
+#include <asm/uaccess.h>
+
+#include <asm/arch/mux.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/board.h>
+
+#include "cbus.h"
+#include "retu.h"
+
+#define RETU_ID 0x01
+#define PFX "retu: "
+
+static int retu_initialized;
+static int retu_irq_pin;
+static int retu_is_vilma;
+
+static struct tasklet_struct retu_tasklet;
+spinlock_t retu_lock = SPIN_LOCK_UNLOCKED;
+
+static struct completion device_release;
+
+struct retu_irq_handler_desc {
+ int (*func)(unsigned long);
+ unsigned long arg;
+ char name[8];
+};
+
+static struct retu_irq_handler_desc retu_irq_handlers[MAX_RETU_IRQ_HANDLERS];
+
+/**
+ * retu_read_reg - Read a value from a register in Retu
+ * @reg: the register to read from
+ *
+ * This function returns the contents of the specified register
+ */
+int retu_read_reg(int reg)
+{
+ BUG_ON(!retu_initialized);
+ return cbus_read_reg(cbus_host, RETU_ID, reg);
+}
+
+/**
+ * retu_write_reg - Write a value to a register in Retu
+ * @reg: the register to write to
+ * @reg: the value to write to the register
+ *
+ * This function writes a value to the specified register
+ */
+void retu_write_reg(int reg, u16 val)
+{
+ BUG_ON(!retu_initialized);
+ cbus_write_reg(cbus_host, RETU_ID, reg, val);
+}
+
+void retu_set_clear_reg_bits(int reg, u16 set, u16 clear)
+{
+ unsigned long flags;
+ u16 w;
+
+ spin_lock_irqsave(&retu_lock, flags);
+ w = retu_read_reg(reg);
+ w &= ~clear;
+ w |= set;
+ retu_write_reg(reg, w);
+ spin_unlock_irqrestore(&retu_lock, flags);
+}
+
+#define ADC_MAX_CHAN_NUMBER 13
+
+int retu_read_adc(int channel)
+{
+ unsigned long flags;
+ int res;
+
+ if (channel < 0 || channel > ADC_MAX_CHAN_NUMBER)
+ return -EINVAL;
+
+ spin_lock_irqsave(&retu_lock, flags);
+
+ if ((channel == 8) && retu_is_vilma) {
+ int scr = retu_read_reg(RETU_REG_ADCSCR);
+ int ch = (retu_read_reg(RETU_REG_ADCR) >> 10) & 0xf;
+ if (((scr & 0xff) != 0) && (ch != 8))
+ retu_write_reg (RETU_REG_ADCSCR, (scr & ~0xff));
+ }
+
+ /* Select the channel and read result */
+ retu_write_reg(RETU_REG_ADCR, channel << 10);
+ res = retu_read_reg(RETU_REG_ADCR) & 0x3ff;
+
+ if (retu_is_vilma)
+ retu_write_reg(RETU_REG_ADCR, (1 << 13));
+
+ /* Unlock retu */
+ spin_unlock_irqrestore(&retu_lock, flags);
+
+ return res;
+}
+
+
+static u16 retu_disable_bogus_irqs(u16 mask)
+{
+ int i;
+
+ for (i = 0; i < MAX_RETU_IRQ_HANDLERS; i++) {
+ if (mask & (1 << i))
+ continue;
+ if (retu_irq_handlers[i].func != NULL)
+ continue;
+ /* an IRQ was enabled but we don't have a handler for it */
+ printk(KERN_INFO PFX "disabling bogus IRQ %d\n", i);
+ mask |= (1 << i);
+ }
+ return mask;
+}
+
+/*
+ * Disable given RETU interrupt
+ */
+void retu_disable_irq(int id)
+{
+ unsigned long flags;
+ u16 mask;
+
+ spin_lock_irqsave(&retu_lock, flags);
+ mask = retu_read_reg(RETU_REG_IMR);
+ mask |= 1 << id;
+ mask = retu_disable_bogus_irqs(mask);
+ retu_write_reg(RETU_REG_IMR, mask);
+ spin_unlock_irqrestore(&retu_lock, flags);
+}
+
+/*
+ * Enable given RETU interrupt
+ */
+void retu_enable_irq(int id)
+{
+ unsigned long flags;
+ u16 mask;
+
+ if (id == 3) {
+ printk("Enabling Retu IRQ %d\n", id);
+ dump_stack();
+ }
+ spin_lock_irqsave(&retu_lock, flags);
+ mask = retu_read_reg(RETU_REG_IMR);
+ mask &= ~(1 << id);
+ mask = retu_disable_bogus_irqs(mask);
+ retu_write_reg(RETU_REG_IMR, mask);
+ spin_unlock_irqrestore(&retu_lock, flags);
+}
+
+/*
+ * Acknowledge given RETU interrupt
+ */
+void retu_ack_irq(int id)
+{
+ retu_write_reg(RETU_REG_IDR, 1 << id);
+}
+
+/*
+ * RETU interrupt handler. Only schedules the tasklet.
+ */
+static irqreturn_t retu_irq_handler(int irq, void *dev_id)
+{
+ tasklet_schedule(&retu_tasklet);
+ return IRQ_HANDLED;
+}
+
+/*
+ * Tasklet handler
+ */
+static void retu_tasklet_handler(unsigned long data)
+{
+ struct retu_irq_handler_desc *hnd;
+ u16 id;
+ u16 im;
+ int i;
+
+ for (;;) {
+ id = retu_read_reg(RETU_REG_IDR);
+ im = ~retu_read_reg(RETU_REG_IMR);
+ id &= im;
+
+ if (!id)
+ break;
+
+ for (i = 0; id != 0; i++, id >>= 1) {
+ if (!(id & 1))
+ continue;
+ hnd = &retu_irq_handlers[i];
+ if (hnd->func == NULL) {
+ /* Spurious retu interrupt - disable and ack it */
+ printk(KERN_INFO "Spurious Retu interrupt "
+ "(id %d)\n", i);
+ retu_disable_irq(i);
+ retu_ack_irq(i);
+ continue;
+ }
+ hnd->func(hnd->arg);
+ /*
+ * Don't acknowledge the interrupt here
+ * It must be done explicitly
+ */
+ }
+ }
+}
+
+/*
+ * Register the handler for a given RETU interrupt source.
+ */
+int retu_request_irq(int id, void *irq_handler, unsigned long arg, char *name)
+{
+ struct retu_irq_handler_desc *hnd;
+
+ if (irq_handler == NULL || id >= MAX_RETU_IRQ_HANDLERS ||
+ name == NULL) {
+ printk(KERN_ERR PFX "Invalid arguments to %s\n",
+ __FUNCTION__);
+ return -EINVAL;
+ }
+ hnd = &retu_irq_handlers[id];
+ if (hnd->func != NULL) {
+ printk(KERN_ERR PFX "IRQ %d already reserved\n", id);
+ return -EBUSY;
+ }
+ printk(KERN_INFO PFX "Registering interrupt %d for device %s\n",
+ id, name);
+ hnd->func = irq_handler;
+ hnd->arg = arg;
+ strlcpy(hnd->name, name, sizeof(hnd->name));
+
+ retu_ack_irq(id);
+ retu_enable_irq(id);
+
+ return 0;
+}
+
+/*
+ * Unregister the handler for a given RETU interrupt source.
+ */
+void retu_free_irq(int id)
+{
+ struct retu_irq_handler_desc *hnd;
+
+ if (id >= MAX_RETU_IRQ_HANDLERS) {
+ printk(KERN_ERR PFX "Invalid argument to %s\n",
+ __FUNCTION__);
+ return;
+ }
+ hnd = &retu_irq_handlers[id];
+ if (hnd->func == NULL) {
+ printk(KERN_ERR PFX "IRQ %d already freed\n", id);
+ return;
+ }
+
+ retu_disable_irq(id);
+ hnd->func = NULL;
+}
+
+/**
+ * retu_power_off - Shut down power to system
+ *
+ * This function puts the system in power off state
+ */
+static void retu_power_off(void)
+{
+ /* Ignore power button state */
+ retu_write_reg(RETU_REG_CC1, retu_read_reg(RETU_REG_CC1) | 2);
+ /* Expire watchdog immediately */
+ retu_write_reg(RETU_REG_WATCHDOG, 0);
+ /* Wait for poweroff*/
+ for (;;);
+}
+
+/**
+ * retu_probe - Probe for Retu ASIC
+ * @dev: the Retu device
+ *
+ * Probe for the Retu ASIC and allocate memory
+ * for its device-struct if found
+ */
+static int __devinit retu_probe(struct device *dev)
+{
+ const struct omap_em_asic_bb5_config * em_asic_config;
+ int rev, ret;
+
+ /* Prepare tasklet */
+ tasklet_init(&retu_tasklet, retu_tasklet_handler, 0);
+
+ em_asic_config = omap_get_config(OMAP_TAG_EM_ASIC_BB5,
+ struct omap_em_asic_bb5_config);
+ if (em_asic_config == NULL) {
+ printk(KERN_ERR PFX "Unable to retrieve config data\n");
+ return -ENODATA;
+ }
+
+ retu_irq_pin = em_asic_config->retu_irq_gpio;
+
+ if ((ret = omap_request_gpio(retu_irq_pin)) < 0) {
+ printk(KERN_ERR PFX "Unable to reserve IRQ GPIO\n");
+ return ret;
+ }
+
+ /* Set the pin as input */
+ omap_set_gpio_direction(retu_irq_pin, 1);
+
+ /* Rising edge triggers the IRQ */
++ set_irq_type(OMAP_GPIO_IRQ(retu_irq_pin), IRQ_TYPE_EDGE_RISING);
+
+ retu_initialized = 1;
+
+ rev = retu_read_reg(RETU_REG_ASICR) & 0xff;
+ if (rev & (1 << 7))
+ retu_is_vilma = 1;
+
+ printk(KERN_INFO "%s v%d.%d found\n", retu_is_vilma ? "Vilma" : "Retu",
+ (rev >> 4) & 0x07, rev & 0x0f);
+
+ /* Mask all RETU interrupts */
+ retu_write_reg(RETU_REG_IMR, 0xffff);
+
+ ret = request_irq(OMAP_GPIO_IRQ(retu_irq_pin), retu_irq_handler, 0,
+ "retu", 0);
+ if (ret < 0) {
+ printk(KERN_ERR PFX "Unable to register IRQ handler\n");
+ omap_free_gpio(retu_irq_pin);
+ return ret;
+ }
+ set_irq_wake(OMAP_GPIO_IRQ(retu_irq_pin), 1);
+
+ /* Register power off function */
+ pm_power_off = retu_power_off;
+
+#ifdef CONFIG_CBUS_RETU_USER
+ /* Initialize user-space interface */
+ if (retu_user_init() < 0) {
+ printk(KERN_ERR "Unable to initialize driver\n");
+ free_irq(OMAP_GPIO_IRQ(retu_irq_pin), 0);
+ omap_free_gpio(retu_irq_pin);
+ return ret;
+ }
+#endif
+
+ return 0;
+}
+
+static int retu_remove(struct device *dev)
+{
+#ifdef CONFIG_CBUS_RETU_USER
+ retu_user_cleanup();
+#endif
+ /* Mask all RETU interrupts */
+ retu_write_reg(RETU_REG_IMR, 0xffff);
+ free_irq(OMAP_GPIO_IRQ(retu_irq_pin), 0);
+ omap_free_gpio(retu_irq_pin);
+ tasklet_kill(&retu_tasklet);
+
+ return 0;
+}
+
+static void retu_device_release(struct device *dev)
+{
+ complete(&device_release);
+}
+
+static struct device_driver retu_driver = {
+ .name = "retu",
+ .bus = &platform_bus_type,
+ .probe = retu_probe,
+ .remove = retu_remove,
+};
+
+static struct platform_device retu_device = {
+ .name = "retu",
+ .id = -1,
+ .dev = {
+ .release = retu_device_release,
+ }
+};
+
+/**
+ * retu_init - initialise Retu driver
+ *
+ * Initialise the Retu driver and return 0 if everything worked ok
+ */
+static int __init retu_init(void)
+{
+ int ret = 0;
+
+ printk(KERN_INFO "Retu/Vilma driver initialising\n");
+
+ init_completion(&device_release);
+
+ if ((ret = driver_register(&retu_driver)) < 0)
+ return ret;
+
+ if ((ret = platform_device_register(&retu_device)) < 0) {
+ driver_unregister(&retu_driver);
+ return ret;
+ }
+ return 0;
+}
+
+/*
+ * Cleanup
+ */
+static void __exit retu_exit(void)
+{
+ platform_device_unregister(&retu_device);
+ driver_unregister(&retu_driver);
+ wait_for_completion(&device_release);
+}
+
+EXPORT_SYMBOL(retu_request_irq);
+EXPORT_SYMBOL(retu_free_irq);
+EXPORT_SYMBOL(retu_enable_irq);
+EXPORT_SYMBOL(retu_disable_irq);
+EXPORT_SYMBOL(retu_ack_irq);
+EXPORT_SYMBOL(retu_read_reg);
+EXPORT_SYMBOL(retu_write_reg);
+
+subsys_initcall(retu_init);
+module_exit(retu_exit);
+
+MODULE_DESCRIPTION("Retu ASIC control");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Juha Yrjölä, David Weinehall, and Mikko Ylinen");
--- /dev/null
- set_irq_type(OMAP_GPIO_IRQ(tahvo_irq_pin), IRQT_RISING);
+/**
+ * drivers/cbus/tahvo.c
+ *
+ * Support functions for Tahvo ASIC
+ *
+ * Copyright (C) 2004, 2005 Nokia Corporation
+ *
+ * Written by Juha Yrjölä <juha.yrjola@nokia.com>,
+ * David Weinehall <david.weinehall@nokia.com>, and
+ * Mikko Ylinen <mikko.k.ylinen@nokia.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/miscdevice.h>
+#include <linux/poll.h>
+#include <linux/fs.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+
+#include <asm/uaccess.h>
+
+#include <asm/arch/mux.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/board.h>
+
+#include "cbus.h"
+#include "tahvo.h"
+
+#define TAHVO_ID 0x02
+#define PFX "tahvo: "
+
+static int tahvo_initialized;
+static int tahvo_irq_pin;
+static int tahvo_is_betty;
+
+static struct tasklet_struct tahvo_tasklet;
+spinlock_t tahvo_lock = SPIN_LOCK_UNLOCKED;
+
+static struct completion device_release;
+
+struct tahvo_irq_handler_desc {
+ int (*func)(unsigned long);
+ unsigned long arg;
+ char name[8];
+};
+
+static struct tahvo_irq_handler_desc tahvo_irq_handlers[MAX_TAHVO_IRQ_HANDLERS];
+
+/**
+ * tahvo_read_reg - Read a value from a register in Tahvo
+ * @reg: the register to read from
+ *
+ * This function returns the contents of the specified register
+ */
+int tahvo_read_reg(int reg)
+{
+ BUG_ON(!tahvo_initialized);
+ return cbus_read_reg(cbus_host, TAHVO_ID, reg);
+}
+
+/**
+ * tahvo_write_reg - Write a value to a register in Tahvo
+ * @reg: the register to write to
+ * @reg: the value to write to the register
+ *
+ * This function writes a value to the specified register
+ */
+void tahvo_write_reg(int reg, u16 val)
+{
+ BUG_ON(!tahvo_initialized);
+ cbus_write_reg(cbus_host, TAHVO_ID, reg, val);
+}
+
+/**
+ * tahvo_set_clear_reg_bits - set and clear register bits atomically
+ * @reg: the register to write to
+ * @bits: the bits to set
+ *
+ * This function sets and clears the specified Tahvo register bits atomically
+ */
+void tahvo_set_clear_reg_bits(int reg, u16 set, u16 clear)
+{
+ unsigned long flags;
+ u16 w;
+
+ spin_lock_irqsave(&tahvo_lock, flags);
+ w = tahvo_read_reg(reg);
+ w &= ~clear;
+ w |= set;
+ tahvo_write_reg(reg, w);
+ spin_unlock_irqrestore(&tahvo_lock, flags);
+}
+
+/*
+ * Disable given TAHVO interrupt
+ */
+void tahvo_disable_irq(int id)
+{
+ unsigned long flags;
+ u16 mask;
+
+ spin_lock_irqsave(&tahvo_lock, flags);
+ mask = tahvo_read_reg(TAHVO_REG_IMR);
+ mask |= 1 << id;
+ tahvo_write_reg(TAHVO_REG_IMR, mask);
+ spin_unlock_irqrestore(&tahvo_lock, flags);
+}
+
+/*
+ * Enable given TAHVO interrupt
+ */
+void tahvo_enable_irq(int id)
+{
+ unsigned long flags;
+ u16 mask;
+
+ spin_lock_irqsave(&tahvo_lock, flags);
+ mask = tahvo_read_reg(TAHVO_REG_IMR);
+ mask &= ~(1 << id);
+ tahvo_write_reg(TAHVO_REG_IMR, mask);
+ spin_unlock_irqrestore(&tahvo_lock, flags);
+}
+
+/*
+ * Acknowledge given TAHVO interrupt
+ */
+void tahvo_ack_irq(int id)
+{
+ tahvo_write_reg(TAHVO_REG_IDR, 1 << id);
+}
+
+static int tahvo_7bit_backlight;
+
+int tahvo_get_backlight_level(void)
+{
+ int mask;
+
+ if (tahvo_7bit_backlight)
+ mask = 0x7f;
+ else
+ mask = 0x0f;
+ return tahvo_read_reg(TAHVO_REG_LEDPWMR) & mask;
+}
+
+int tahvo_get_max_backlight_level(void)
+{
+ if (tahvo_7bit_backlight)
+ return 0x7f;
+ else
+ return 0x0f;
+}
+
+void tahvo_set_backlight_level(int level)
+{
+ int max_level;
+
+ max_level = tahvo_get_max_backlight_level();
+ if (level > max_level)
+ level = max_level;
+ tahvo_write_reg(TAHVO_REG_LEDPWMR, level);
+}
+
+/*
+ * TAHVO interrupt handler. Only schedules the tasklet.
+ */
+static irqreturn_t tahvo_irq_handler(int irq, void *dev_id)
+{
+ tasklet_schedule(&tahvo_tasklet);
+ return IRQ_HANDLED;
+}
+
+/*
+ * Tasklet handler
+ */
+static void tahvo_tasklet_handler(unsigned long data)
+{
+ struct tahvo_irq_handler_desc *hnd;
+ u16 id;
+ u16 im;
+ int i;
+
+ for (;;) {
+ id = tahvo_read_reg(TAHVO_REG_IDR);
+ im = ~tahvo_read_reg(TAHVO_REG_IMR);
+ id &= im;
+
+ if (!id)
+ break;
+
+ for (i = 0; id != 0; i++, id >>= 1) {
+ if (!(id & 1))
+ continue;
+ hnd = &tahvo_irq_handlers[i];
+ if (hnd->func == NULL) {
+ /* Spurious tahvo interrupt - just ack it */
+ printk(KERN_INFO "Spurious Tahvo interrupt "
+ "(id %d)\n", i);
+ tahvo_disable_irq(i);
+ tahvo_ack_irq(i);
+ continue;
+ }
+ hnd->func(hnd->arg);
+ /*
+ * Don't acknowledge the interrupt here
+ * It must be done explicitly
+ */
+ }
+ }
+}
+
+/*
+ * Register the handler for a given TAHVO interrupt source.
+ */
+int tahvo_request_irq(int id, void *irq_handler, unsigned long arg, char *name)
+{
+ struct tahvo_irq_handler_desc *hnd;
+
+ if (irq_handler == NULL || id >= MAX_TAHVO_IRQ_HANDLERS ||
+ name == NULL) {
+ printk(KERN_ERR PFX "Invalid arguments to %s\n",
+ __FUNCTION__);
+ return -EINVAL;
+ }
+ hnd = &tahvo_irq_handlers[id];
+ if (hnd->func != NULL) {
+ printk(KERN_ERR PFX "IRQ %d already reserved\n", id);
+ return -EBUSY;
+ }
+ printk(KERN_INFO PFX "Registering interrupt %d for device %s\n",
+ id, name);
+ hnd->func = irq_handler;
+ hnd->arg = arg;
+ strlcpy(hnd->name, name, sizeof(hnd->name));
+
+ tahvo_ack_irq(id);
+ tahvo_enable_irq(id);
+
+ return 0;
+}
+
+/*
+ * Unregister the handler for a given TAHVO interrupt source.
+ */
+void tahvo_free_irq(int id)
+{
+ struct tahvo_irq_handler_desc *hnd;
+
+ if (id >= MAX_TAHVO_IRQ_HANDLERS) {
+ printk(KERN_ERR PFX "Invalid argument to %s\n",
+ __FUNCTION__);
+ return;
+ }
+ hnd = &tahvo_irq_handlers[id];
+ if (hnd->func == NULL) {
+ printk(KERN_ERR PFX "IRQ %d already freed\n", id);
+ return;
+ }
+
+ tahvo_disable_irq(id);
+ hnd->func = NULL;
+}
+
+/**
+ * tahvo_probe - Probe for Tahvo ASIC
+ * @dev: the Tahvo device
+ *
+ * Probe for the Tahvo ASIC and allocate memory
+ * for its device-struct if found
+ */
+static int __devinit tahvo_probe(struct device *dev)
+{
+ const struct omap_em_asic_bb5_config * em_asic_config;
+ int rev, id, ret;
+
+ /* Prepare tasklet */
+ tasklet_init(&tahvo_tasklet, tahvo_tasklet_handler, 0);
+
+ em_asic_config = omap_get_config(OMAP_TAG_EM_ASIC_BB5,
+ struct omap_em_asic_bb5_config);
+ if (em_asic_config == NULL) {
+ printk(KERN_ERR PFX "Unable to retrieve config data\n");
+ return -ENODATA;
+ }
+
+ tahvo_initialized = 1;
+
+ rev = tahvo_read_reg(TAHVO_REG_ASICR);
+
+ id = (rev >> 8) & 0xff;
+ if (id == 0x03) {
+ if ((rev & 0xff) >= 0x50)
+ tahvo_7bit_backlight = 1;
+ } else if (id == 0x0b) {
+ tahvo_is_betty = 1;
+ tahvo_7bit_backlight = 1;
+ } else {
+ printk(KERN_ERR "Tahvo/Betty chip not found");
+ return -ENODEV;
+ }
+
+ printk(KERN_INFO "%s v%d.%d found\n", tahvo_is_betty ? "Betty" : "Tahvo",
+ (rev >> 4) & 0x0f, rev & 0x0f);
+
+ tahvo_irq_pin = em_asic_config->tahvo_irq_gpio;
+
+ if ((ret = omap_request_gpio(tahvo_irq_pin)) < 0) {
+ printk(KERN_ERR PFX "Unable to reserve IRQ GPIO\n");
+ return ret;
+ }
+
+ /* Set the pin as input */
+ omap_set_gpio_direction(tahvo_irq_pin, 1);
+
+ /* Rising edge triggers the IRQ */
++ set_irq_type(OMAP_GPIO_IRQ(tahvo_irq_pin), IRQ_TYPE_EDGE_RISING);
+
+ /* Mask all TAHVO interrupts */
+ tahvo_write_reg(TAHVO_REG_IMR, 0xffff);
+
+ ret = request_irq(OMAP_GPIO_IRQ(tahvo_irq_pin), tahvo_irq_handler, 0,
+ "tahvo", 0);
+ if (ret < 0) {
+ printk(KERN_ERR PFX "Unable to register IRQ handler\n");
+ omap_free_gpio(tahvo_irq_pin);
+ return ret;
+ }
+#ifdef CONFIG_CBUS_TAHVO_USER
+ /* Initialize user-space interface */
+ if (tahvo_user_init() < 0) {
+ printk(KERN_ERR "Unable to initialize driver\n");
+ free_irq(OMAP_GPIO_IRQ(tahvo_irq_pin), 0);
+ omap_free_gpio(tahvo_irq_pin);
+ return ret;
+ }
+#endif
+ return 0;
+}
+
+static int tahvo_remove(struct device *dev)
+{
+#ifdef CONFIG_CBUS_TAHVO_USER
+ tahvo_user_cleanup();
+#endif
+ /* Mask all TAHVO interrupts */
+ tahvo_write_reg(TAHVO_REG_IMR, 0xffff);
+ free_irq(OMAP_GPIO_IRQ(tahvo_irq_pin), 0);
+ omap_free_gpio(tahvo_irq_pin);
+ tasklet_kill(&tahvo_tasklet);
+
+ return 0;
+}
+
+static void tahvo_device_release(struct device *dev)
+{
+ complete(&device_release);
+}
+
+static struct device_driver tahvo_driver = {
+ .name = "tahvo",
+ .bus = &platform_bus_type,
+ .probe = tahvo_probe,
+ .remove = tahvo_remove,
+};
+
+static struct platform_device tahvo_device = {
+ .name = "tahvo",
+ .id = -1,
+ .dev = {
+ .release = tahvo_device_release,
+ }
+};
+
+/**
+ * tahvo_init - initialise Tahvo driver
+ *
+ * Initialise the Tahvo driver and return 0 if everything worked ok
+ */
+static int __init tahvo_init(void)
+{
+ int ret = 0;
+
+ printk(KERN_INFO "Tahvo/Betty driver initialising\n");
+
+ init_completion(&device_release);
+
+ if ((ret = driver_register(&tahvo_driver)) < 0)
+ return ret;
+
+ if ((ret = platform_device_register(&tahvo_device)) < 0) {
+ driver_unregister(&tahvo_driver);
+ return ret;
+ }
+ return 0;
+}
+
+/*
+ * Cleanup
+ */
+static void __exit tahvo_exit(void)
+{
+ platform_device_unregister(&tahvo_device);
+ driver_unregister(&tahvo_driver);
+ wait_for_completion(&device_release);
+}
+
+EXPORT_SYMBOL(tahvo_request_irq);
+EXPORT_SYMBOL(tahvo_free_irq);
+EXPORT_SYMBOL(tahvo_enable_irq);
+EXPORT_SYMBOL(tahvo_disable_irq);
+EXPORT_SYMBOL(tahvo_ack_irq);
+EXPORT_SYMBOL(tahvo_read_reg);
+EXPORT_SYMBOL(tahvo_write_reg);
+EXPORT_SYMBOL(tahvo_get_backlight_level);
+EXPORT_SYMBOL(tahvo_get_max_backlight_level);
+EXPORT_SYMBOL(tahvo_set_backlight_level);
+
+subsys_initcall(tahvo_init);
+module_exit(tahvo_exit);
+
+MODULE_DESCRIPTION("Tahvo ASIC control");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Juha Yrjölä, David Weinehall, and Mikko Ylinen");
that contains all parts of the crypto device driver (ap bus,
request router and all the card drivers).
+config OMAP_SHA1_MD5
+ tristate "Support for OMAP SHA1/MD5 hw engine"
+ depends on ARCH_OMAP24XX && CRYPTO_SHA1 && CRYPTO_MD5
+ help
+ OMAP processors have SHA1/MD5 module accelerator. Select this if you
+ want to use the OMAP module for SHA1/MD5 algorithms.
+
config CRYPTO_SHA1_S390
tristate "SHA1 digest algorithm"
depends on S390
Select this option if you want to enable the random number generator
on the HIFN 795x crypto adapters.
+ config CRYPTO_DEV_TALITOS
+ tristate "Talitos Freescale Security Engine (SEC)"
+ select CRYPTO_ALGAPI
+ select CRYPTO_AUTHENC
+ select HW_RANDOM
+ depends on FSL_SOC
+ help
+ Say 'Y' here to use the Freescale Security Engine (SEC)
+ to offload cryptographic algorithm computation.
+
+ The Freescale SEC is present on PowerQUICC 'E' processors, such
+ as the MPC8349E and MPC8548E.
+
+ To compile this driver as a module, choose M here: the module
+ will be called talitos.
+
+ config CRYPTO_DEV_IXP4XX
+ tristate "Driver for IXP4xx crypto hardware acceleration"
+ depends on ARCH_IXP4XX
+ select CRYPTO_DES
+ select CRYPTO_ALGAPI
+ select CRYPTO_AUTHENC
+ select CRYPTO_BLKCIPHER
+ help
+ Driver for the IXP4xx NPE crypto engine.
+
endif # CRYPTO_HW
obj-$(CONFIG_CRYPTO_DEV_PADLOCK_AES) += padlock-aes.o
obj-$(CONFIG_CRYPTO_DEV_PADLOCK_SHA) += padlock-sha.o
obj-$(CONFIG_CRYPTO_DEV_GEODE) += geode-aes.o
+obj-$(CONFIG_OMAP_SHA1_MD5) += omap-sha1-md5.o
obj-$(CONFIG_CRYPTO_DEV_HIFN_795X) += hifn_795x.o
+ obj-$(CONFIG_CRYPTO_DEV_TALITOS) += talitos.o
+ obj-$(CONFIG_CRYPTO_DEV_IXP4XX) += ixp4xx_crypto.o
--- /dev/null
- if (find_task_by_pid(pl->pid) != NULL)
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.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.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/major.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <linux/kfifo.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/arch/mailbox.h>
+#include <asm/arch/dsp.h>
+#include "uaccess_dsp.h"
+#include "dsp_mbcmd.h"
+#include "dsp.h"
+#include "ipbuf.h"
+#include "proclist.h"
+
+/*
+ * devstate: task device state machine
+ * NOTASK: task is not attached.
+ * ATTACHED: task is attached.
+ * GARBAGE: task is detached. waiting for all processes to close this device.
+ * ADDREQ: requesting for tadd
+ * DELREQ: requesting for tdel. no process is opening this device.
+ * FREEZED: task is attached, but reserved to be killed.
+ * ADDFAIL: tadd failed.
+ * ADDING: tadd in process.
+ * DELING: tdel in process.
+ * KILLING: tkill in process.
+ */
+#define TASKDEV_ST_NOTASK 0x00000001
+#define TASKDEV_ST_ATTACHED 0x00000002
+#define TASKDEV_ST_GARBAGE 0x00000004
+#define TASKDEV_ST_INVALID 0x00000008
+#define TASKDEV_ST_ADDREQ 0x00000100
+#define TASKDEV_ST_DELREQ 0x00000200
+#define TASKDEV_ST_FREEZED 0x00000400
+#define TASKDEV_ST_ADDFAIL 0x00001000
+#define TASKDEV_ST_ADDING 0x00010000
+#define TASKDEV_ST_DELING 0x00020000
+#define TASKDEV_ST_KILLING 0x00040000
+#define TASKDEV_ST_STATE_MASK 0x7fffffff
+#define TASKDEV_ST_STALE 0x80000000
+
+static struct {
+ long state;
+ char *name;
+} devstate_desc[] = {
+ { TASKDEV_ST_NOTASK, "notask" },
+ { TASKDEV_ST_ATTACHED, "attached" },
+ { TASKDEV_ST_GARBAGE, "garbage" },
+ { TASKDEV_ST_INVALID, "invalid" },
+ { TASKDEV_ST_ADDREQ, "addreq" },
+ { TASKDEV_ST_DELREQ, "delreq" },
+ { TASKDEV_ST_FREEZED, "freezed" },
+ { TASKDEV_ST_ADDFAIL, "addfail" },
+ { TASKDEV_ST_ADDING, "adding" },
+ { TASKDEV_ST_DELING, "deling" },
+ { TASKDEV_ST_KILLING, "killing" },
+};
+
+static char *devstate_name(long state)
+{
+ int i;
+ int max = ARRAY_SIZE(devstate_desc);
+
+ for (i = 0; i < max; i++) {
+ if (state & devstate_desc[i].state)
+ return devstate_desc[i].name;
+ }
+ return "unknown";
+}
+
+struct rcvdt_bk_struct {
+ struct ipblink link;
+ unsigned int rp;
+};
+
+struct taskdev {
+ struct bus_type *bus;
+ struct device dev; /* Generic device interface */
+
+ long state;
+ struct rw_semaphore state_sem;
+ wait_queue_head_t state_wait_q;
+ struct mutex usecount_lock;
+ unsigned int usecount;
+ char name[TNM_LEN];
+ struct file_operations fops;
+ spinlock_t proc_list_lock;
+ struct list_head proc_list;
+ struct dsptask *task;
+
+ /* read stuff */
+ wait_queue_head_t read_wait_q;
+ struct mutex read_mutex;
+ spinlock_t read_lock;
+ union {
+ struct kfifo *fifo; /* for active word */
+ struct rcvdt_bk_struct bk;
+ } rcvdt;
+
+ /* write stuff */
+ wait_queue_head_t write_wait_q;
+ struct mutex write_mutex;
+ spinlock_t wsz_lock;
+ size_t wsz;
+
+ /* tctl stuff */
+ wait_queue_head_t tctl_wait_q;
+ struct mutex tctl_mutex;
+ int tctl_stat;
+ int tctl_ret; /* return value for tctl_show() */
+
+ /* device lock */
+ struct mutex lock;
+ pid_t lock_pid;
+};
+
+#define to_taskdev(n) container_of(n, struct taskdev, dev)
+
+struct dsptask {
+ enum {
+ TASK_ST_ERR = 0,
+ TASK_ST_READY,
+ TASK_ST_CFGREQ
+ } state;
+ u8 tid;
+ char name[TNM_LEN];
+ u16 ttyp;
+ struct taskdev *dev;
+
+ /* read stuff */
+ struct ipbuf_p *ipbuf_pvt_r;
+
+ /* write stuff */
+ struct ipbuf_p *ipbuf_pvt_w;
+
+ /* mmap stuff */
+ void *map_base;
+ size_t map_length;
+};
+
+#define sndtyp_acv(ttyp) ((ttyp) & TTYP_ASND)
+#define sndtyp_psv(ttyp) (!((ttyp) & TTYP_ASND))
+#define sndtyp_bk(ttyp) ((ttyp) & TTYP_BKDM)
+#define sndtyp_wd(ttyp) (!((ttyp) & TTYP_BKDM))
+#define sndtyp_pvt(ttyp) ((ttyp) & TTYP_PVDM)
+#define sndtyp_gbl(ttyp) (!((ttyp) & TTYP_PVDM))
+#define rcvtyp_acv(ttyp) ((ttyp) & TTYP_ARCV)
+#define rcvtyp_psv(ttyp) (!((ttyp) & TTYP_ARCV))
+#define rcvtyp_bk(ttyp) ((ttyp) & TTYP_BKMD)
+#define rcvtyp_wd(ttyp) (!((ttyp) & TTYP_BKMD))
+#define rcvtyp_pvt(ttyp) ((ttyp) & TTYP_PVMD)
+#define rcvtyp_gbl(ttyp) (!((ttyp) & TTYP_PVMD))
+
+static inline int has_taskdev_lock(struct taskdev *dev);
+static int dsp_rmdev_minor(unsigned char minor);
+static int taskdev_init(struct taskdev *dev, char *name, unsigned char minor);
+static void taskdev_delete(unsigned char minor);
+static int taskdev_attach_task(struct taskdev *dev, struct dsptask *task);
+static int dsp_tdel_bh(struct taskdev *dev, u16 type);
+
+static struct bus_type dsptask_bus = {
+ .name = "dsptask",
+};
+
+static struct class *dsp_task_class;
+static DEFINE_MUTEX(devmgr_lock);
+static struct taskdev *taskdev[TASKDEV_MAX];
+static struct dsptask *dsptask[TASKDEV_MAX];
+static DEFINE_MUTEX(cfg_lock);
+static u16 cfg_cmd;
+static u8 cfg_tid;
+static DECLARE_WAIT_QUEUE_HEAD(cfg_wait_q);
+static u8 n_task; /* static task count */
+static void *heap;
+
+#define is_dynamic_task(tid) ((tid) >= n_task)
+
+#define devstate_read_lock(dev, devstate) \
+ devstate_read_lock_timeout(dev, devstate, 0)
+#define devstate_read_unlock(dev) up_read(&(dev)->state_sem)
+#define devstate_write_lock(dev, devstate) \
+ devstate_write_lock_timeout(dev, devstate, 0)
+#define devstate_write_unlock(dev) up_write(&(dev)->state_sem)
+
+static ssize_t devname_show(struct device *d, struct device_attribute *attr,
+ char *buf);
+static ssize_t devstate_show(struct device *d, struct device_attribute *attr,
+ char *buf);
+static ssize_t proc_list_show(struct device *d, struct device_attribute *attr,
+ char *buf);
+static ssize_t taskname_show(struct device *d, struct device_attribute *attr,
+ char *buf);
+static ssize_t ttyp_show(struct device *d, struct device_attribute *attr,
+ char *buf);
+static ssize_t fifosz_show(struct device *d, struct device_attribute *attr,
+ char *buf);
+static int fifosz_store(struct device *d, struct device_attribute *attr,
+ const char *buf, size_t count);
+static ssize_t fifocnt_show(struct device *d, struct device_attribute *attr,
+ char *buf);
+static ssize_t ipblink_show(struct device *d, struct device_attribute *attr,
+ char *buf);
+static ssize_t wsz_show(struct device *d, struct device_attribute *attr,
+ char *buf);
+static ssize_t mmap_show(struct device *d, struct device_attribute *attr,
+ char *buf);
+
+#define __ATTR_RW(_name,_mode) { \
+ .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE }, \
+ .show = _name##_show, \
+ .store = _name##_store, \
+}
+
+static struct device_attribute dev_attr_devname = __ATTR_RO(devname);
+static struct device_attribute dev_attr_devstate = __ATTR_RO(devstate);
+static struct device_attribute dev_attr_proc_list = __ATTR_RO(proc_list);
+static struct device_attribute dev_attr_taskname = __ATTR_RO(taskname);
+static struct device_attribute dev_attr_ttyp = __ATTR_RO(ttyp);
+static struct device_attribute dev_attr_fifosz = __ATTR_RW(fifosz, 0666);
+static struct device_attribute dev_attr_fifocnt = __ATTR_RO(fifocnt);
+static struct device_attribute dev_attr_ipblink = __ATTR_RO(ipblink);
+static struct device_attribute dev_attr_wsz = __ATTR_RO(wsz);
+static struct device_attribute dev_attr_mmap = __ATTR_RO(mmap);
+
+static inline void set_taskdev_state(struct taskdev *dev, int state)
+{
+ pr_debug("omapdsp: devstate: CHANGE %s[%d]:\"%s\"->\"%s\"\n",
+ dev->name,
+ (dev->task ? dev->task->tid : -1),
+ devstate_name(dev->state),
+ devstate_name(state));
+ dev->state = state;
+}
+
+/*
+ * devstate_read_lock_timeout()
+ * devstate_write_lock_timeout():
+ * timeout != 0: dev->state can be diffeent from what you want.
+ * timeout == 0: no timeout
+ */
+#define BUILD_DEVSTATE_LOCK_TIMEOUT(rw) \
+static int devstate_##rw##_lock_timeout(struct taskdev *dev, long devstate, \
+ int timeout) \
+{ \
+ DEFINE_WAIT(wait); \
+ down_##rw(&dev->state_sem); \
+ while (!(dev->state & devstate)) { \
+ up_##rw(&dev->state_sem); \
+ prepare_to_wait(&dev->state_wait_q, &wait, TASK_INTERRUPTIBLE); \
+ if (!timeout) \
+ timeout = MAX_SCHEDULE_TIMEOUT; \
+ timeout = schedule_timeout(timeout); \
+ finish_wait(&dev->state_wait_q, &wait); \
+ if (timeout == 0) \
+ return -ETIME; \
+ if (signal_pending(current)) \
+ return -EINTR; \
+ down_##rw(&dev->state_sem); \
+ } \
+ return 0; \
+}
+BUILD_DEVSTATE_LOCK_TIMEOUT(read)
+BUILD_DEVSTATE_LOCK_TIMEOUT(write)
+
+#define BUILD_DEVSTATE_LOCK_AND_TEST(rw) \
+static int devstate_##rw##_lock_and_test(struct taskdev *dev, long devstate) \
+{ \
+ down_##rw(&dev->state_sem); \
+ if (dev->state & devstate) \
+ return 1; /* success */ \
+ /* failure */ \
+ up_##rw(&dev->state_sem); \
+ return 0; \
+}
+BUILD_DEVSTATE_LOCK_AND_TEST(read)
+BUILD_DEVSTATE_LOCK_AND_TEST(write)
+
+static int taskdev_lock_interruptible(struct taskdev *dev,
+ struct mutex *lock)
+{
+ int ret;
+
+ if (has_taskdev_lock(dev))
+ ret = mutex_lock_interruptible(lock);
+ else {
+ if ((ret = mutex_lock_interruptible(&dev->lock)) != 0)
+ return ret;
+ ret = mutex_lock_interruptible(lock);
+ mutex_unlock(&dev->lock);
+ }
+
+ return ret;
+}
+
+static int taskdev_lock_and_statelock_attached(struct taskdev *dev,
+ struct mutex *lock)
+{
+ int ret;
+
+ if (!devstate_read_lock_and_test(dev, TASKDEV_ST_ATTACHED))
+ return -ENODEV;
+
+ if ((ret = taskdev_lock_interruptible(dev, lock)) != 0)
+ devstate_read_unlock(dev);
+
+ return ret;
+}
+
+static inline void taskdev_unlock_and_stateunlock(struct taskdev *dev,
+ struct mutex *lock)
+{
+ mutex_unlock(lock);
+ devstate_read_unlock(dev);
+}
+
+/*
+ * taskdev_flush_buf()
+ * must be called under state_lock(ATTACHED) and dev->read_mutex.
+ */
+static int taskdev_flush_buf(struct taskdev *dev)
+{
+ u16 ttyp = dev->task->ttyp;
+
+ if (sndtyp_wd(ttyp)) {
+ /* word receiving */
+ kfifo_reset(dev->rcvdt.fifo);
+ } else {
+ /* block receiving */
+ struct rcvdt_bk_struct *rcvdt = &dev->rcvdt.bk;
+
+ if (sndtyp_gbl(ttyp))
+ ipblink_flush(&rcvdt->link);
+ else {
+ ipblink_flush_pvt(&rcvdt->link);
+ release_ipbuf_pvt(dev->task->ipbuf_pvt_r);
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * taskdev_set_fifosz()
+ * must be called under dev->read_mutex.
+ */
+static int taskdev_set_fifosz(struct taskdev *dev, unsigned long sz)
+{
+ u16 ttyp = dev->task->ttyp;
+
+ if (!(sndtyp_wd(ttyp) && sndtyp_acv(ttyp))) {
+ printk(KERN_ERR
+ "omapdsp: buffer size can be changed only for "
+ "active word sending task.\n");
+ return -EINVAL;
+ }
+ if ((sz == 0) || (sz & 1)) {
+ printk(KERN_ERR "omapdsp: illegal buffer size! (%ld)\n"
+ "it must be even and non-zero value.\n", sz);
+ return -EINVAL;
+ }
+
+ if (kfifo_len(dev->rcvdt.fifo)) {
+ printk(KERN_ERR "omapdsp: buffer is not empty!\n");
+ return -EIO;
+ }
+
+ kfifo_free(dev->rcvdt.fifo);
+ dev->rcvdt.fifo = kfifo_alloc(sz, GFP_KERNEL, &dev->read_lock);
+ if (IS_ERR(dev->rcvdt.fifo)) {
+ printk(KERN_ERR
+ "omapdsp: unable to change receive buffer size. "
+ "(%ld bytes for %s)\n", sz, dev->name);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static inline int has_taskdev_lock(struct taskdev *dev)
+{
+ return (dev->lock_pid == current->pid);
+}
+
+static int taskdev_lock(struct taskdev *dev)
+{
+ if (mutex_lock_interruptible(&dev->lock))
+ return -EINTR;
+ dev->lock_pid = current->pid;
+ return 0;
+}
+
+static int taskdev_unlock(struct taskdev *dev)
+{
+ if (!has_taskdev_lock(dev)) {
+ printk(KERN_ERR
+ "omapdsp: an illegal process attempted to "
+ "unlock the dsptask lock!\n");
+ return -EINVAL;
+ }
+ dev->lock_pid = 0;
+ mutex_unlock(&dev->lock);
+ return 0;
+}
+
+static int dsp_task_config(struct dsptask *task, u8 tid)
+{
+ u16 ttyp;
+ int ret;
+
+ task->tid = tid;
+ dsptask[tid] = task;
+
+ /* TCFG request */
+ task->state = TASK_ST_CFGREQ;
+ if (mutex_lock_interruptible(&cfg_lock)) {
+ ret = -EINTR;
+ goto fail_out;
+ }
+ cfg_cmd = MBOX_CMD_DSP_TCFG;
+ mbcompose_send_and_wait(TCFG, tid, 0, &cfg_wait_q);
+ cfg_cmd = 0;
+ mutex_unlock(&cfg_lock);
+
+ if (task->state != TASK_ST_READY) {
+ printk(KERN_ERR "omapdsp: task %d configuration error!\n", tid);
+ ret = -EINVAL;
+ goto fail_out;
+ }
+
+ if (strlen(task->name) <= 1)
+ sprintf(task->name, "%d", tid);
+ pr_info("omapdsp: task %d: name %s\n", tid, task->name);
+
+ ttyp = task->ttyp;
+
+ /*
+ * task info sanity check
+ */
+
+ /* task type check */
+ if (rcvtyp_psv(ttyp) && rcvtyp_pvt(ttyp)) {
+ printk(KERN_ERR "omapdsp: illegal task type(0x%04x), tid=%d\n",
+ tid, ttyp);
+ ret = -EINVAL;
+ goto fail_out;
+ }
+
+ /* private buffer address check */
+ if (sndtyp_pvt(ttyp) &&
+ (ipbuf_p_validate(task->ipbuf_pvt_r, DIR_D2A) < 0)) {
+ ret = -EINVAL;
+ goto fail_out;
+ }
+ if (rcvtyp_pvt(ttyp) &&
+ (ipbuf_p_validate(task->ipbuf_pvt_w, DIR_A2D) < 0)) {
+ ret = -EINVAL;
+ goto fail_out;
+ }
+
+ /* mmap buffer configuration check */
+ if ((task->map_length > 0) &&
+ ((!ALIGN((unsigned long)task->map_base, PAGE_SIZE)) ||
+ (!ALIGN(task->map_length, PAGE_SIZE)) ||
+ (dsp_mem_type(task->map_base, task->map_length) != MEM_TYPE_EXTERN))) {
+ printk(KERN_ERR
+ "omapdsp: illegal mmap buffer address(0x%p) or "
+ "length(0x%x).\n"
+ " It needs to be page-aligned and located at "
+ "external memory.\n",
+ task->map_base, task->map_length);
+ ret = -EINVAL;
+ goto fail_out;
+ }
+
+ return 0;
+
+fail_out:
+ dsptask[tid] = NULL;
+ return ret;
+}
+
+static void dsp_task_init(struct dsptask *task)
+{
+ mbcompose_send(TCTL, task->tid, TCTL_TINIT);
+}
+
+int dsp_task_config_all(u8 n)
+{
+ int i, ret;
+ struct taskdev *devheap;
+ struct dsptask *taskheap;
+ size_t devheapsz, taskheapsz;
+
+ pr_info("omapdsp: found %d task(s)\n", n);
+ if (n == 0)
+ return 0;
+
+ /*
+ * reducing kmalloc!
+ */
+ devheapsz = sizeof(struct taskdev) * n;
+ taskheapsz = sizeof(struct dsptask) * n;
+ heap = kzalloc(devheapsz + taskheapsz, GFP_KERNEL);
+ if (heap == NULL)
+ return -ENOMEM;
+ devheap = heap;
+ taskheap = heap + devheapsz;
+
+ n_task = n;
+ for (i = 0; i < n; i++) {
+ struct taskdev *dev = &devheap[i];
+ struct dsptask *task = &taskheap[i];
+
+ if ((ret = dsp_task_config(task, i)) < 0)
+ return ret;
+ if ((ret = taskdev_init(dev, task->name, i)) < 0)
+ return ret;
+ if ((ret = taskdev_attach_task(dev, task)) < 0)
+ return ret;
+ dsp_task_init(task);
+ pr_info("omapdsp: taskdev %s enabled.\n", dev->name);
+ }
+
+ return 0;
+}
+
+static void dsp_task_unconfig(struct dsptask *task)
+{
+ dsptask[task->tid] = NULL;
+}
+
+void dsp_task_unconfig_all(void)
+{
+ unsigned char minor;
+ u8 tid;
+ struct dsptask *task;
+
+ for (minor = 0; minor < n_task; minor++) {
+ /*
+ * taskdev[minor] can be NULL in case of
+ * configuration failure
+ */
+ if (taskdev[minor])
+ taskdev_delete(minor);
+ }
+ for (; minor < TASKDEV_MAX; minor++) {
+ if (taskdev[minor])
+ dsp_rmdev_minor(minor);
+ }
+
+ for (tid = 0; tid < n_task; tid++) {
+ /*
+ * dsptask[tid] can be NULL in case of
+ * configuration failure
+ */
+ task = dsptask[tid];
+ if (task)
+ dsp_task_unconfig(task);
+ }
+ for (; tid < TASKDEV_MAX; tid++) {
+ task = dsptask[tid];
+ if (task) {
+ /*
+ * on-demand tasks should be deleted in
+ * rmdev_minor(), but just in case.
+ */
+ dsp_task_unconfig(task);
+ kfree(task);
+ }
+ }
+
+ if (heap) {
+ kfree(heap);
+ heap = NULL;
+ }
+
+ n_task = 0;
+}
+
+static struct device_driver dsptask_driver = {
+ .name = "dsptask",
+ .bus = &dsptask_bus,
+};
+
+u8 dsp_task_count(void)
+{
+ return n_task;
+}
+
+int dsp_taskmod_busy(void)
+{
+ struct taskdev *dev;
+ unsigned char minor;
+ unsigned int usecount;
+
+ for (minor = 0; minor < TASKDEV_MAX; minor++) {
+ dev = taskdev[minor];
+ if (dev == NULL)
+ continue;
+ if ((usecount = dev->usecount) > 0) {
+ printk("dsp_taskmod_busy(): %s: usecount=%d\n",
+ dev->name, usecount);
+ return 1;
+ }
+/*
+ if ((dev->state & (TASKDEV_ST_ADDREQ |
+ TASKDEV_ST_DELREQ)) {
+*/
+ if (dev->state & TASKDEV_ST_ADDREQ) {
+ printk("dsp_taskmod_busy(): %s is in %s\n",
+ dev->name, devstate_name(dev->state));
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * DSP task device file operations
+ */
+static ssize_t dsp_task_read_wd_acv(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+ struct taskdev *dev = taskdev[minor];
+ int ret = 0;
+ DEFINE_WAIT(wait);
+
+ if (count == 0) {
+ return 0;
+ } else if (count & 0x1) {
+ printk(KERN_ERR
+ "omapdsp: odd count is illegal for DSP task device.\n");
+ return -EINVAL;
+ }
+
+ if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
+ return -ENODEV;
+
+
+ prepare_to_wait(&dev->read_wait_q, &wait, TASK_INTERRUPTIBLE);
+ if (kfifo_len(dev->rcvdt.fifo) == 0)
+ schedule();
+ finish_wait(&dev->read_wait_q, &wait);
+ if (kfifo_len(dev->rcvdt.fifo) == 0) {
+ /* failure */
+ if (signal_pending(current))
+ ret = -EINTR;
+ goto up_out;
+ }
+
+
+ ret = kfifo_get_to_user(dev->rcvdt.fifo, buf, count);
+
+ up_out:
+ taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
+ return ret;
+}
+
+static ssize_t dsp_task_read_bk_acv(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+ struct taskdev *dev = taskdev[minor];
+ struct rcvdt_bk_struct *rcvdt = &dev->rcvdt.bk;
+ ssize_t ret = 0;
+ DEFINE_WAIT(wait);
+
+ if (count == 0) {
+ return 0;
+ } else if (count & 0x1) {
+ printk(KERN_ERR
+ "omapdsp: odd count is illegal for DSP task device.\n");
+ return -EINVAL;
+ } else if ((int)buf & 0x1) {
+ printk(KERN_ERR
+ "omapdsp: buf should be word aligned for "
+ "dsp_task_read().\n");
+ return -EINVAL;
+ }
+
+ if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
+ return -ENODEV;
+
+ prepare_to_wait(&dev->read_wait_q, &wait, TASK_INTERRUPTIBLE);
+ if (ipblink_empty(&rcvdt->link))
+ schedule();
+ finish_wait(&dev->read_wait_q, &wait);
+ if (ipblink_empty(&rcvdt->link)) {
+ /* failure */
+ if (signal_pending(current))
+ ret = -EINTR;
+ goto up_out;
+ }
+
+ /* copy from delayed IPBUF */
+ if (sndtyp_pvt(dev->task->ttyp)) {
+ /* private */
+ if (!ipblink_empty(&rcvdt->link)) {
+ struct ipbuf_p *ipbp = dev->task->ipbuf_pvt_r;
+ unsigned char *base, *src;
+ size_t bkcnt;
+
+ if (dsp_mem_enable(ipbp) < 0) {
+ ret = -EBUSY;
+ goto up_out;
+ }
+ base = MKVIRT(ipbp->ah, ipbp->al);
+ bkcnt = ((unsigned long)ipbp->c) * 2 - rcvdt->rp;
+ if (dsp_address_validate(base, bkcnt,
+ "task %s read buffer",
+ dev->task->name) < 0) {
+ ret = -EINVAL;
+ goto pv_out1;
+ }
+ if (dsp_mem_enable(base) < 0) {
+ ret = -EBUSY;
+ goto pv_out1;
+ }
+ src = base + rcvdt->rp;
+ if (bkcnt > count) {
+ if (copy_to_user_dsp(buf, src, count)) {
+ ret = -EFAULT;
+ goto pv_out2;
+ }
+ ret = count;
+ rcvdt->rp += count;
+ } else {
+ if (copy_to_user_dsp(buf, src, bkcnt)) {
+ ret = -EFAULT;
+ goto pv_out2;
+ }
+ ret = bkcnt;
+ ipblink_del_pvt(&rcvdt->link);
+ release_ipbuf_pvt(ipbp);
+ rcvdt->rp = 0;
+ }
+ pv_out2:
+ dsp_mem_disable(src);
+ pv_out1:
+ dsp_mem_disable(ipbp);
+ }
+ } else {
+ /* global */
+ if (dsp_mem_enable_ipbuf() < 0) {
+ ret = -EBUSY;
+ goto up_out;
+ }
+ while (!ipblink_empty(&rcvdt->link)) {
+ unsigned char *src;
+ size_t bkcnt;
+ struct ipbuf_head *ipb_h = bid_to_ipbuf(rcvdt->link.top);
+
+ src = ipb_h->p->d + rcvdt->rp;
+ bkcnt = ((unsigned long)ipb_h->p->c) * 2 - rcvdt->rp;
+ if (bkcnt > count) {
+ if (copy_to_user_dsp(buf, src, count)) {
+ ret = -EFAULT;
+ goto gb_out;
+ }
+ ret += count;
+ rcvdt->rp += count;
+ break;
+ } else {
+ if (copy_to_user_dsp(buf, src, bkcnt)) {
+ ret = -EFAULT;
+ goto gb_out;
+ }
+ ret += bkcnt;
+ buf += bkcnt;
+ count -= bkcnt;
+ ipblink_del_top(&rcvdt->link);
+ unuse_ipbuf(ipb_h);
+ rcvdt->rp = 0;
+ }
+ }
+ gb_out:
+ dsp_mem_disable_ipbuf();
+ }
+
+ up_out:
+ taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
+ return ret;
+}
+
+static ssize_t dsp_task_read_wd_psv(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+ struct taskdev *dev = taskdev[minor];
+ int ret = 0;
+
+ if (count == 0) {
+ return 0;
+ } else if (count & 0x1) {
+ printk(KERN_ERR
+ "omapdsp: odd count is illegal for DSP task device.\n");
+ return -EINVAL;
+ } else {
+ /* force! */
+ count = 2;
+ }
+
+ if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
+ return -ENODEV;
+
+ mbcompose_send_and_wait(WDREQ, dev->task->tid, 0, &dev->read_wait_q);
+
+ if (kfifo_len(dev->rcvdt.fifo) == 0) {
+ /* failure */
+ if (signal_pending(current))
+ ret = -EINTR;
+ goto up_out;
+ }
+
+ ret = kfifo_get_to_user(dev->rcvdt.fifo, buf, count);
+
+up_out:
+ taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
+ return ret;
+}
+
+static ssize_t dsp_task_read_bk_psv(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+ struct taskdev *dev = taskdev[minor];
+ struct rcvdt_bk_struct *rcvdt = &dev->rcvdt.bk;
+ int ret = 0;
+
+ if (count == 0) {
+ return 0;
+ } else if (count & 0x1) {
+ printk(KERN_ERR
+ "omapdsp: odd count is illegal for DSP task device.\n");
+ return -EINVAL;
+ } else if ((int)buf & 0x1) {
+ printk(KERN_ERR
+ "omapdsp: buf should be word aligned for "
+ "dsp_task_read().\n");
+ return -EINVAL;
+ }
+
+ if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
+ return -ENODEV;
+
+ mbcompose_send_and_wait(BKREQ, dev->task->tid, count/2,
+ &dev->read_wait_q);
+
+ if (ipblink_empty(&rcvdt->link)) {
+ /* failure */
+ if (signal_pending(current))
+ ret = -EINTR;
+ goto up_out;
+ }
+
+ /*
+ * We will not receive more than requested count.
+ */
+ if (sndtyp_pvt(dev->task->ttyp)) {
+ /* private */
+ struct ipbuf_p *ipbp = dev->task->ipbuf_pvt_r;
+ size_t rcvcnt;
+ void *src;
+
+ if (dsp_mem_enable(ipbp) < 0) {
+ ret = -EBUSY;
+ goto up_out;
+ }
+ src = MKVIRT(ipbp->ah, ipbp->al);
+ rcvcnt = ((unsigned long)ipbp->c) * 2;
+ if (dsp_address_validate(src, rcvcnt, "task %s read buffer",
+ dev->task->name) < 0) {
+ ret = -EINVAL;
+ goto pv_out1;
+ }
+ if (dsp_mem_enable(src) < 0) {
+ ret = -EBUSY;
+ goto pv_out1;
+ }
+ if (count > rcvcnt)
+ count = rcvcnt;
+ if (copy_to_user_dsp(buf, src, count)) {
+ ret = -EFAULT;
+ goto pv_out2;
+ }
+ ipblink_del_pvt(&rcvdt->link);
+ release_ipbuf_pvt(ipbp);
+ ret = count;
+pv_out2:
+ dsp_mem_disable(src);
+pv_out1:
+ dsp_mem_disable(ipbp);
+ } else {
+ /* global */
+ struct ipbuf_head *ipb_h = bid_to_ipbuf(rcvdt->link.top);
+ size_t rcvcnt;
+
+ if (dsp_mem_enable_ipbuf() < 0) {
+ ret = -EBUSY;
+ goto up_out;
+ }
+ rcvcnt = ((unsigned long)ipb_h->p->c) * 2;
+ if (count > rcvcnt)
+ count = rcvcnt;
+ if (copy_to_user_dsp(buf, ipb_h->p->d, count)) {
+ ret = -EFAULT;
+ goto gb_out;
+ }
+ ipblink_del_top(&rcvdt->link);
+ unuse_ipbuf(ipb_h);
+ ret = count;
+gb_out:
+ dsp_mem_disable_ipbuf();
+ }
+
+up_out:
+ taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
+ return ret;
+}
+
+static ssize_t dsp_task_write_wd(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+ struct taskdev *dev = taskdev[minor];
+ u16 wd;
+ int ret = 0;
+ DEFINE_WAIT(wait);
+
+ if (count == 0) {
+ return 0;
+ } else if (count & 0x1) {
+ printk(KERN_ERR
+ "omapdsp: odd count is illegal for DSP task device.\n");
+ return -EINVAL;
+ } else {
+ /* force! */
+ count = 2;
+ }
+
+ if (taskdev_lock_and_statelock_attached(dev, &dev->write_mutex))
+ return -ENODEV;
+
+ prepare_to_wait(&dev->write_wait_q, &wait, TASK_INTERRUPTIBLE);
+ if (dev->wsz == 0)
+ schedule();
+ finish_wait(&dev->write_wait_q, &wait);
+ if (dev->wsz == 0) {
+ /* failure */
+ if (signal_pending(current))
+ ret = -EINTR;
+ goto up_out;
+ }
+
+ if (copy_from_user(&wd, buf, count)) {
+ ret = -EFAULT;
+ goto up_out;
+ }
+
+ spin_lock(&dev->wsz_lock);
+ if (mbcompose_send(WDSND, dev->task->tid, wd) < 0) {
+ spin_unlock(&dev->wsz_lock);
+ goto up_out;
+ }
+ ret = count;
+ if (rcvtyp_acv(dev->task->ttyp))
+ dev->wsz = 0;
+ spin_unlock(&dev->wsz_lock);
+
+ up_out:
+ taskdev_unlock_and_stateunlock(dev, &dev->write_mutex);
+ return ret;
+}
+
+static ssize_t dsp_task_write_bk(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+ struct taskdev *dev = taskdev[minor];
+ int ret = 0;
+ DEFINE_WAIT(wait);
+
+ if (count == 0) {
+ return 0;
+ } else if (count & 0x1) {
+ printk(KERN_ERR
+ "omapdsp: odd count is illegal for DSP task device.\n");
+ return -EINVAL;
+ } else if ((int)buf & 0x1) {
+ printk(KERN_ERR
+ "omapdsp: buf should be word aligned for "
+ "dsp_task_write().\n");
+ return -EINVAL;
+ }
+
+ if (taskdev_lock_and_statelock_attached(dev, &dev->write_mutex))
+ return -ENODEV;
+
+ prepare_to_wait(&dev->write_wait_q, &wait, TASK_INTERRUPTIBLE);
+ if (dev->wsz == 0)
+ schedule();
+ finish_wait(&dev->write_wait_q, &wait);
+ if (dev->wsz == 0) {
+ /* failure */
+ if (signal_pending(current))
+ ret = -EINTR;
+ goto up_out;
+ }
+
+ if (count > dev->wsz)
+ count = dev->wsz;
+
+ if (rcvtyp_pvt(dev->task->ttyp)) {
+ /* private */
+ struct ipbuf_p *ipbp = dev->task->ipbuf_pvt_w;
+ unsigned char *dst;
+
+ if (dsp_mem_enable(ipbp) < 0) {
+ ret = -EBUSY;
+ goto up_out;
+ }
+ dst = MKVIRT(ipbp->ah, ipbp->al);
+ if (dsp_address_validate(dst, count, "task %s write buffer",
+ dev->task->name) < 0) {
+ ret = -EINVAL;
+ goto pv_out1;
+ }
+ if (dsp_mem_enable(dst) < 0) {
+ ret = -EBUSY;
+ goto pv_out1;
+ }
+ if (copy_from_user_dsp(dst, buf, count)) {
+ ret = -EFAULT;
+ goto pv_out2;
+ }
+ ipbp->c = count/2;
+ ipbp->s = dev->task->tid;
+ spin_lock(&dev->wsz_lock);
+ if (mbcompose_send(BKSNDP, dev->task->tid, 0) == 0) {
+ if (rcvtyp_acv(dev->task->ttyp))
+ dev->wsz = 0;
+ ret = count;
+ }
+ spin_unlock(&dev->wsz_lock);
+ pv_out2:
+ dsp_mem_disable(dst);
+ pv_out1:
+ dsp_mem_disable(ipbp);
+ } else {
+ /* global */
+ struct ipbuf_head *ipb_h;
+
+ if (dsp_mem_enable_ipbuf() < 0) {
+ ret = -EBUSY;
+ goto up_out;
+ }
+ if ((ipb_h = get_free_ipbuf(dev->task->tid)) == NULL)
+ goto gb_out;
+ if (copy_from_user_dsp(ipb_h->p->d, buf, count)) {
+ release_ipbuf(ipb_h);
+ ret = -EFAULT;
+ goto gb_out;
+ }
+ ipb_h->p->c = count/2;
+ ipb_h->p->sa = dev->task->tid;
+ spin_lock(&dev->wsz_lock);
+ if (mbcompose_send(BKSND, dev->task->tid, ipb_h->bid) == 0) {
+ if (rcvtyp_acv(dev->task->ttyp))
+ dev->wsz = 0;
+ ret = count;
+ ipb_bsycnt_inc(&ipbcfg);
+ } else
+ release_ipbuf(ipb_h);
+ spin_unlock(&dev->wsz_lock);
+ gb_out:
+ dsp_mem_disable_ipbuf();
+ }
+
+ up_out:
+ taskdev_unlock_and_stateunlock(dev, &dev->write_mutex);
+ return ret;
+}
+
+static unsigned int dsp_task_poll(struct file * file, poll_table * wait)
+{
+ unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+ struct taskdev *dev = taskdev[minor];
+ struct dsptask *task = dev->task;
+ unsigned int mask = 0;
+
+ if (!devstate_read_lock_and_test(dev, TASKDEV_ST_ATTACHED))
+ return 0;
+ poll_wait(file, &dev->read_wait_q, wait);
+ poll_wait(file, &dev->write_wait_q, wait);
+ if (sndtyp_psv(task->ttyp) ||
+ (sndtyp_wd(task->ttyp) && kfifo_len(dev->rcvdt.fifo)) ||
+ (sndtyp_bk(task->ttyp) && !ipblink_empty(&dev->rcvdt.bk.link)))
+ mask |= POLLIN | POLLRDNORM;
+ if (dev->wsz)
+ mask |= POLLOUT | POLLWRNORM;
+ devstate_read_unlock(dev);
+
+ return mask;
+}
+
+static int dsp_tctl_issue(struct taskdev *dev, u16 cmd, int argc, u16 argv[])
+{
+ int tctl_argc;
+ struct mb_exarg mbarg, *mbargp;
+ int interactive;
+ u8 tid;
+ int ret = 0;
+
+ if (cmd < 0x8000) {
+ /*
+ * 0x0000 - 0x7fff
+ * system reserved TCTL commands
+ */
+ switch (cmd) {
+ case TCTL_TEN:
+ case TCTL_TDIS:
+ tctl_argc = 0;
+ interactive = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+ /*
+ * 0x8000 - 0xffff
+ * user-defined TCTL commands
+ */
+ else if (cmd < 0x8100) {
+ /* 0x8000-0x80ff: no arg, non-interactive */
+ tctl_argc = 0;
+ interactive = 0;
+ } else if (cmd < 0x8200) {
+ /* 0x8100-0x81ff: 1 arg, non-interactive */
+ tctl_argc = 1;
+ interactive = 0;
+ } else if (cmd < 0x9000) {
+ /* 0x8200-0x8fff: reserved */
+ return -EINVAL;
+ } else if (cmd < 0x9100) {
+ /* 0x9000-0x90ff: no arg, interactive */
+ tctl_argc = 0;
+ interactive = 1;
+ } else if (cmd < 0x9200) {
+ /* 0x9100-0x91ff: 1 arg, interactive */
+ tctl_argc = 1;
+ interactive = 1;
+ } else {
+ /* 0x9200-0xffff: reserved */
+ return -EINVAL;
+ }
+
+ /*
+ * if argc < 0, use tctl_argc as is.
+ * if argc >= 0, check arg count.
+ */
+ if ((argc >= 0) && (argc != tctl_argc))
+ return -EINVAL;
+
+ /*
+ * issue TCTL
+ */
+ if (taskdev_lock_interruptible(dev, &dev->tctl_mutex))
+ return -EINTR;
+
+ tid = dev->task->tid;
+ if (tctl_argc > 0) {
+ mbarg.argc = tctl_argc;
+ mbarg.tid = tid;
+ mbarg.argv = argv;
+ mbargp = &mbarg;
+ } else
+ mbargp = NULL;
+
+ if (interactive) {
+ dev->tctl_stat = -EINVAL;
+
+ mbcompose_send_and_wait_exarg(TCTL, tid, cmd, mbargp,
+ &dev->tctl_wait_q);
+ if (signal_pending(current)) {
+ ret = -EINTR;
+ goto up_out;
+ }
+ if ((ret = dev->tctl_stat) < 0) {
+ printk(KERN_ERR "omapdsp: TCTL not responding.\n");
+ goto up_out;
+ }
+ } else
+ mbcompose_send_exarg(TCTL, tid, cmd, mbargp);
+
+up_out:
+ mutex_unlock(&dev->tctl_mutex);
+ return ret;
+}
+
+static int dsp_task_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ unsigned int minor = MINOR(inode->i_rdev);
+ struct taskdev *dev = taskdev[minor];
+ int ret;
+
+ if (cmd < 0x10000) {
+ /* issue TCTL */
+ u16 mbargv[1];
+
+ mbargv[0] = arg & 0xffff;
+ return dsp_tctl_issue(dev, cmd, -1, mbargv);
+ }
+
+ /* non TCTL ioctls */
+ switch (cmd) {
+
+ case TASK_IOCTL_LOCK:
+ ret = taskdev_lock(dev);
+ break;
+
+ case TASK_IOCTL_UNLOCK:
+ ret = taskdev_unlock(dev);
+ break;
+
+ case TASK_IOCTL_BFLSH:
+ if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
+ return -ENODEV;
+ ret = taskdev_flush_buf(dev);
+ taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
+ break;
+
+ case TASK_IOCTL_SETBSZ:
+ if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
+ return -ENODEV;
+ ret = taskdev_set_fifosz(dev, arg);
+ taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
+ break;
+
+ case TASK_IOCTL_GETNAME:
+ ret = 0;
+ if (copy_to_user((void __user *)arg, dev->name,
+ strlen(dev->name) + 1))
+ ret = -EFAULT;
+ break;
+
+ default:
+ ret = -ENOIOCTLCMD;
+
+ }
+
+ return ret;
+}
+
+static void dsp_task_mmap_open(struct vm_area_struct *vma)
+{
+ struct taskdev *dev = (struct taskdev *)vma->vm_private_data;
+ struct dsptask *task;
+ size_t len = vma->vm_end - vma->vm_start;
+
+ BUG_ON(!(dev->state & TASKDEV_ST_ATTACHED));
+ task = dev->task;
+ omap_mmu_exmap_use(&dsp_mmu, task->map_base, len);
+}
+
+static void dsp_task_mmap_close(struct vm_area_struct *vma)
+{
+ struct taskdev *dev = (struct taskdev *)vma->vm_private_data;
+ struct dsptask *task;
+ size_t len = vma->vm_end - vma->vm_start;
+
+ BUG_ON(!(dev->state & TASKDEV_ST_ATTACHED));
+ task = dev->task;
+ omap_mmu_exmap_unuse(&dsp_mmu, task->map_base, len);
+}
+
+/**
+ * On demand page allocation is not allowed. The mapping area is defined by
+ * corresponding DSP tasks.
+ */
+static int dsp_task_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+ return VM_FAULT_NOPAGE;
+}
+
+static struct vm_operations_struct dsp_task_vm_ops = {
+ .open = dsp_task_mmap_open,
+ .close = dsp_task_mmap_close,
+ .fault = dsp_task_mmap_fault,
+};
+
+static int dsp_task_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ void *tmp_vadr;
+ unsigned long tmp_padr, tmp_vmadr, off;
+ size_t req_len, tmp_len;
+ unsigned int minor = MINOR(filp->f_dentry->d_inode->i_rdev);
+ struct taskdev *dev = taskdev[minor];
+ struct dsptask *task;
+ int ret = 0;
+
+ if (!devstate_read_lock_and_test(dev, TASKDEV_ST_ATTACHED))
+ return -ENODEV;
+ task = dev->task;
+
+ /*
+ * Don't swap this area out
+ * Don't dump this area to a core file
+ */
+ vma->vm_flags |= VM_RESERVED | VM_IO;
+
+ /* Do not cache this area */
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+ req_len = vma->vm_end - vma->vm_start;
+ off = vma->vm_pgoff << PAGE_SHIFT;
+ tmp_vmadr = vma->vm_start;
+ tmp_vadr = task->map_base + off;
+ do {
+ tmp_padr = omap_mmu_virt_to_phys(&dsp_mmu, tmp_vadr, &tmp_len);
+ if (tmp_padr == 0) {
+ printk(KERN_ERR
+ "omapdsp: task %s: illegal address "
+ "for mmap: %p", task->name, tmp_vadr);
+ /* partial mapping will be cleared in upper layer */
+ ret = -EINVAL;
+ goto unlock_out;
+ }
+ if (tmp_len > req_len)
+ tmp_len = req_len;
+
+ pr_debug("omapdsp: mmap info: "
+ "vmadr = %08lx, padr = %08lx, len = %x\n",
+ tmp_vmadr, tmp_padr, tmp_len);
+ if (remap_pfn_range(vma, tmp_vmadr, tmp_padr >> PAGE_SHIFT,
+ tmp_len, vma->vm_page_prot) != 0) {
+ printk(KERN_ERR
+ "omapdsp: task %s: remap_page_range() failed.\n",
+ task->name);
+ /* partial mapping will be cleared in upper layer */
+ ret = -EINVAL;
+ goto unlock_out;
+ }
+
+ req_len -= tmp_len;
+ tmp_vmadr += tmp_len;
+ tmp_vadr += tmp_len;
+ } while (req_len);
+
+ vma->vm_ops = &dsp_task_vm_ops;
+ vma->vm_private_data = dev;
+ omap_mmu_exmap_use(&dsp_mmu, task->map_base, vma->vm_end - vma->vm_start);
+
+unlock_out:
+ devstate_read_unlock(dev);
+ return ret;
+}
+
+static int dsp_task_open(struct inode *inode, struct file *file)
+{
+ unsigned int minor = MINOR(inode->i_rdev);
+ struct taskdev *dev;
+ int ret = 0;
+
+ if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL))
+ return -ENODEV;
+
+ restart:
+ mutex_lock(&dev->usecount_lock);
+ down_write(&dev->state_sem);
+
+ /* state can be NOTASK, ATTACHED/FREEZED, KILLING, GARBAGE or INVALID here. */
+ switch (dev->state & TASKDEV_ST_STATE_MASK) {
+ case TASKDEV_ST_NOTASK:
+ break;
+ case TASKDEV_ST_ATTACHED:
+ goto attached;
+
+ case TASKDEV_ST_INVALID:
+ up_write(&dev->state_sem);
+ mutex_unlock(&dev->usecount_lock);
+ return -ENODEV;
+
+ case TASKDEV_ST_FREEZED:
+ case TASKDEV_ST_KILLING:
+ case TASKDEV_ST_GARBAGE:
+ case TASKDEV_ST_DELREQ:
+ /* on the kill process. wait until it becomes NOTASK. */
+ up_write(&dev->state_sem);
+ mutex_unlock(&dev->usecount_lock);
+ if (devstate_write_lock(dev, TASKDEV_ST_NOTASK) < 0)
+ return -EINTR;
+ devstate_write_unlock(dev);
+ goto restart;
+ }
+
+ /* NOTASK */
+ set_taskdev_state(dev, TASKDEV_ST_ADDREQ);
+ /* wake up twch daemon for tadd */
+ dsp_twch_touch();
+ up_write(&dev->state_sem);
+ if (devstate_write_lock(dev, TASKDEV_ST_ATTACHED |
+ TASKDEV_ST_ADDFAIL) < 0) {
+ /* cancelled */
+ if (!devstate_write_lock_and_test(dev, TASKDEV_ST_ADDREQ)) {
+ mutex_unlock(&dev->usecount_lock);
+ /* out of control ??? */
+ return -EINTR;
+ }
+ set_taskdev_state(dev, TASKDEV_ST_NOTASK);
+ ret = -EINTR;
+ goto change_out;
+ }
+ if (dev->state & TASKDEV_ST_ADDFAIL) {
+ printk(KERN_ERR "omapdsp: task attach failed for %s!\n",
+ dev->name);
+ ret = -EBUSY;
+ set_taskdev_state(dev, TASKDEV_ST_NOTASK);
+ goto change_out;
+ }
+
+ attached:
+ ret = proc_list_add(&dev->proc_list_lock,
+ &dev->proc_list, current, file);
+ if (ret)
+ goto out;
+
+ dev->usecount++;
+ file->f_op = &dev->fops;
+ up_write(&dev->state_sem);
+ mutex_unlock(&dev->usecount_lock);
+
+#ifdef DSP_PTE_FREE /* not used currently. */
+ dsp_map_update(current);
+ dsp_cur_users_add(current);
+#endif /* DSP_PTE_FREE */
+ return 0;
+
+ change_out:
+ wake_up_interruptible_all(&dev->state_wait_q);
+ out:
+ up_write(&dev->state_sem);
+ mutex_unlock(&dev->usecount_lock);
+ return ret;
+}
+
+static int dsp_task_release(struct inode *inode, struct file *file)
+{
+ unsigned int minor = MINOR(inode->i_rdev);
+ struct taskdev *dev = taskdev[minor];
+
+#ifdef DSP_PTE_FREE /* not used currently. */
+ dsp_cur_users_del(current);
+#endif /* DSP_PTE_FREE */
+
+ if (has_taskdev_lock(dev))
+ taskdev_unlock(dev);
+
+ proc_list_del(&dev->proc_list_lock, &dev->proc_list, current, file);
+ mutex_lock(&dev->usecount_lock);
+ if (--dev->usecount > 0) {
+ /* other processes are using this device. no state change. */
+ mutex_unlock(&dev->usecount_lock);
+ return 0;
+ }
+
+ /* usecount == 0 */
+ down_write(&dev->state_sem);
+
+ /* state can be ATTACHED/FREEZED, KILLING or GARBAGE here. */
+ switch (dev->state & TASKDEV_ST_STATE_MASK) {
+
+ case TASKDEV_ST_KILLING:
+ break;
+
+ case TASKDEV_ST_GARBAGE:
+ set_taskdev_state(dev, TASKDEV_ST_NOTASK);
+ wake_up_interruptible_all(&dev->state_wait_q);
+ break;
+
+ case TASKDEV_ST_ATTACHED:
+ case TASKDEV_ST_FREEZED:
+ if (is_dynamic_task(minor)) {
+ set_taskdev_state(dev, TASKDEV_ST_DELREQ);
+ /* wake up twch daemon for tdel */
+ dsp_twch_touch();
+ }
+ break;
+
+ }
+
+ up_write(&dev->state_sem);
+ mutex_unlock(&dev->usecount_lock);
+ return 0;
+}
+
+/*
+ * mkdev / rmdev
+ */
+int dsp_mkdev(char *name)
+{
+ struct taskdev *dev;
+ int status;
+ unsigned char minor;
+ int ret;
+
+ if (dsp_cfgstat_get_stat() != CFGSTAT_READY) {
+ printk(KERN_ERR "omapdsp: dsp has not been configured.\n");
+ return -EINVAL;
+ }
+
+ if (mutex_lock_interruptible(&devmgr_lock))
+ return -EINTR;
+
+ /* naming check */
+ for (minor = 0; minor < TASKDEV_MAX; minor++) {
+ if (taskdev[minor] && !strcmp(taskdev[minor]->name, name)) {
+ printk(KERN_ERR
+ "omapdsp: task device name %s is already "
+ "in use.\n", name);
+ ret = -EINVAL;
+ goto out;
+ }
+ }
+
+ /* find free minor number */
+ for (minor = n_task; minor < TASKDEV_MAX; minor++) {
+ if (taskdev[minor] == NULL)
+ goto do_make;
+ }
+ printk(KERN_ERR "omapdsp: Too many task devices.\n");
+ ret = -EBUSY;
+ goto out;
+
+do_make:
+ if ((dev = kzalloc(sizeof(struct taskdev), GFP_KERNEL)) == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ if ((status = taskdev_init(dev, name, minor)) < 0) {
+ kfree(dev);
+ ret = status;
+ goto out;
+ }
+ ret = minor;
+
+out:
+ mutex_unlock(&devmgr_lock);
+ return ret;
+}
+
+int dsp_rmdev(char *name)
+{
+ unsigned char minor;
+ int status;
+ int ret;
+
+ if (dsp_cfgstat_get_stat() != CFGSTAT_READY) {
+ printk(KERN_ERR "omapdsp: dsp has not been configured.\n");
+ return -EINVAL;
+ }
+
+ if (mutex_lock_interruptible(&devmgr_lock))
+ return -EINTR;
+
+ /* find in dynamic devices */
+ for (minor = n_task; minor < TASKDEV_MAX; minor++) {
+ if (taskdev[minor] && !strcmp(taskdev[minor]->name, name))
+ goto do_remove;
+ }
+
+ /* find in static devices */
+ for (minor = 0; minor < n_task; minor++) {
+ if (taskdev[minor] && !strcmp(taskdev[minor]->name, name)) {
+ printk(KERN_ERR
+ "omapdsp: task device %s is static.\n", name);
+ ret = -EINVAL;
+ goto out;
+ }
+ }
+
+ printk(KERN_ERR "omapdsp: task device %s not found.\n", name);
+ return -EINVAL;
+
+do_remove:
+ ret = minor;
+ if ((status = dsp_rmdev_minor(minor)) < 0)
+ ret = status;
+out:
+ mutex_unlock(&devmgr_lock);
+ return ret;
+}
+
+static int dsp_rmdev_minor(unsigned char minor)
+{
+ struct taskdev *dev = taskdev[minor];
+
+ while (!down_write_trylock(&dev->state_sem)) {
+ down_read(&dev->state_sem);
+ if (dev->state & (TASKDEV_ST_ATTACHED |
+ TASKDEV_ST_FREEZED)) {
+ /*
+ * task is working. kill it.
+ * ATTACHED -> FREEZED can be changed under
+ * down_read of state_sem..
+ */
+ set_taskdev_state(dev, TASKDEV_ST_FREEZED);
+ wake_up_interruptible_all(&dev->read_wait_q);
+ wake_up_interruptible_all(&dev->write_wait_q);
+ wake_up_interruptible_all(&dev->tctl_wait_q);
+ }
+ up_read(&dev->state_sem);
+ schedule();
+ }
+
+ switch (dev->state & TASKDEV_ST_STATE_MASK) {
+
+ case TASKDEV_ST_NOTASK:
+ case TASKDEV_ST_INVALID:
+ /* fine */
+ goto notask;
+
+ case TASKDEV_ST_ATTACHED:
+ case TASKDEV_ST_FREEZED:
+ /* task is working. kill it. */
+ set_taskdev_state(dev, TASKDEV_ST_KILLING);
+ up_write(&dev->state_sem);
+ dsp_tdel_bh(dev, TDEL_KILL);
+ goto invalidate;
+
+ case TASKDEV_ST_ADDREQ:
+ /* open() is waiting. drain it. */
+ set_taskdev_state(dev, TASKDEV_ST_ADDFAIL);
+ wake_up_interruptible_all(&dev->state_wait_q);
+ break;
+
+ case TASKDEV_ST_DELREQ:
+ /* nobody is waiting. */
+ set_taskdev_state(dev, TASKDEV_ST_NOTASK);
+ wake_up_interruptible_all(&dev->state_wait_q);
+ break;
+
+ case TASKDEV_ST_ADDING:
+ case TASKDEV_ST_DELING:
+ case TASKDEV_ST_KILLING:
+ case TASKDEV_ST_GARBAGE:
+ case TASKDEV_ST_ADDFAIL:
+ /* transient state. wait for a moment. */
+ break;
+
+ }
+
+ up_write(&dev->state_sem);
+
+invalidate:
+ /* wait for some time and hope the state is settled */
+ devstate_read_lock_timeout(dev, TASKDEV_ST_NOTASK, 5 * HZ);
+ if (!(dev->state & TASKDEV_ST_NOTASK)) {
+ printk(KERN_WARNING
+ "omapdsp: illegal device state (%s) on rmdev %s.\n",
+ devstate_name(dev->state), dev->name);
+ }
+notask:
+ set_taskdev_state(dev, TASKDEV_ST_INVALID);
+ devstate_read_unlock(dev);
+
+ taskdev_delete(minor);
+ kfree(dev);
+
+ return 0;
+}
+
+static struct file_operations dsp_task_fops = {
+ .owner = THIS_MODULE,
+ .poll = dsp_task_poll,
+ .ioctl = dsp_task_ioctl,
+ .open = dsp_task_open,
+ .release = dsp_task_release,
+};
+
+static void dsptask_dev_release(struct device *dev)
+{
+}
+
+static int taskdev_init(struct taskdev *dev, char *name, unsigned char minor)
+{
+ int ret;
+ struct device *task_dev;
+
+ taskdev[minor] = dev;
+
+ spin_lock_init(&dev->proc_list_lock);
+ INIT_LIST_HEAD(&dev->proc_list);
+ init_waitqueue_head(&dev->read_wait_q);
+ init_waitqueue_head(&dev->write_wait_q);
+ init_waitqueue_head(&dev->tctl_wait_q);
+ mutex_init(&dev->read_mutex);
+ mutex_init(&dev->write_mutex);
+ mutex_init(&dev->tctl_mutex);
+ mutex_init(&dev->lock);
+ spin_lock_init(&dev->wsz_lock);
+ dev->tctl_ret = -EINVAL;
+ dev->lock_pid = 0;
+
+ strncpy(dev->name, name, TNM_LEN);
+ dev->name[TNM_LEN-1] = '\0';
+ set_taskdev_state(dev, (minor < n_task) ? TASKDEV_ST_ATTACHED : TASKDEV_ST_NOTASK);
+ dev->usecount = 0;
+ mutex_init(&dev->usecount_lock);
+ memcpy(&dev->fops, &dsp_task_fops, sizeof(struct file_operations));
+
+ dev->dev.parent = omap_dsp->dev;
+ dev->dev.bus = &dsptask_bus;
+ sprintf(dev->dev.bus_id, "dsptask%d", minor);
+ dev->dev.release = dsptask_dev_release;
+ ret = device_register(&dev->dev);
+ if (ret) {
+ printk(KERN_ERR "device_register failed: %d\n", ret);
+ return ret;
+ }
+ ret = device_create_file(&dev->dev, &dev_attr_devname);
+ if (ret)
+ goto fail_create_devname;
+ ret = device_create_file(&dev->dev, &dev_attr_devstate);
+ if (ret)
+ goto fail_create_devstate;
+ ret = device_create_file(&dev->dev, &dev_attr_proc_list);
+ if (ret)
+ goto fail_create_proclist;
+
+ task_dev = device_create(dsp_task_class, NULL,
+ MKDEV(OMAP_DSP_TASK_MAJOR, minor),
+ "dsptask%d", (int)minor);
+
+ if (unlikely(IS_ERR(task_dev))) {
+ ret = -EINVAL;
+ goto fail_create_taskclass;
+ }
+
+ init_waitqueue_head(&dev->state_wait_q);
+ init_rwsem(&dev->state_sem);
+
+ return 0;
+
+ fail_create_taskclass:
+ device_remove_file(&dev->dev, &dev_attr_proc_list);
+ fail_create_proclist:
+ device_remove_file(&dev->dev, &dev_attr_devstate);
+ fail_create_devstate:
+ device_remove_file(&dev->dev, &dev_attr_devname);
+ fail_create_devname:
+ device_unregister(&dev->dev);
+ return ret;
+}
+
+static void taskdev_delete(unsigned char minor)
+{
+ struct taskdev *dev = taskdev[minor];
+
+ if (!dev)
+ return;
+ device_remove_file(&dev->dev, &dev_attr_devname);
+ device_remove_file(&dev->dev, &dev_attr_devstate);
+ device_remove_file(&dev->dev, &dev_attr_proc_list);
+ device_destroy(dsp_task_class, MKDEV(OMAP_DSP_TASK_MAJOR, minor));
+ device_unregister(&dev->dev);
+ proc_list_flush(&dev->proc_list_lock, &dev->proc_list);
+ taskdev[minor] = NULL;
+}
+
+static int taskdev_attach_task(struct taskdev *dev, struct dsptask *task)
+{
+ u16 ttyp = task->ttyp;
+ int ret;
+
+ dev->fops.read =
+ sndtyp_acv(ttyp) ?
+ sndtyp_wd(ttyp) ? dsp_task_read_wd_acv:
+ /* sndtyp_bk */ dsp_task_read_bk_acv:
+ /* sndtyp_psv */
+ sndtyp_wd(ttyp) ? dsp_task_read_wd_psv:
+ /* sndtyp_bk */ dsp_task_read_bk_psv;
+ if (sndtyp_wd(ttyp)) {
+ /* word */
+ size_t fifosz = sndtyp_psv(ttyp) ? 2:32; /* passive:active */
+
+ dev->rcvdt.fifo = kfifo_alloc(fifosz, GFP_KERNEL,
+ &dev->read_lock);
+ if (IS_ERR(dev->rcvdt.fifo)) {
+ printk(KERN_ERR
+ "omapdsp: unable to allocate receive buffer. "
+ "(%d bytes for %s)\n", fifosz, dev->name);
+ return -ENOMEM;
+ }
+ } else {
+ /* block */
+ INIT_IPBLINK(&dev->rcvdt.bk.link);
+ dev->rcvdt.bk.rp = 0;
+ }
+
+ dev->fops.write =
+ rcvtyp_wd(ttyp) ? dsp_task_write_wd:
+ /* rcvbyp_bk */ dsp_task_write_bk;
+ dev->wsz = rcvtyp_acv(ttyp) ? 0 : /* active */
+ rcvtyp_wd(ttyp) ? 2 : /* passive word */
+ ipbcfg.lsz*2; /* passive block */
+
+ if (task->map_length)
+ dev->fops.mmap = dsp_task_mmap;
+
+ ret = device_create_file(&dev->dev, &dev_attr_taskname);
+ if (unlikely(ret))
+ goto fail_create_taskname;
+ ret = device_create_file(&dev->dev, &dev_attr_ttyp);
+ if (unlikely(ret))
+ goto fail_create_ttyp;
+ ret = device_create_file(&dev->dev, &dev_attr_wsz);
+ if (unlikely(ret))
+ goto fail_create_wsz;
+ if (task->map_length) {
+ ret = device_create_file(&dev->dev, &dev_attr_mmap);
+ if (unlikely(ret))
+ goto fail_create_mmap;
+ }
+ if (sndtyp_wd(ttyp)) {
+ ret = device_create_file(&dev->dev, &dev_attr_fifosz);
+ if (unlikely(ret))
+ goto fail_create_fifosz;
+ ret = device_create_file(&dev->dev, &dev_attr_fifocnt);
+ if (unlikely(ret))
+ goto fail_create_fifocnt;
+ } else {
+ ret = device_create_file(&dev->dev, &dev_attr_ipblink);
+ if (unlikely(ret))
+ goto fail_create_ipblink;
+ }
+
+ dev->task = task;
+ task->dev = dev;
+
+ return 0;
+
+ fail_create_fifocnt:
+ device_remove_file(&dev->dev, &dev_attr_fifosz);
+ fail_create_ipblink:
+ fail_create_fifosz:
+ if (task->map_length)
+ device_remove_file(&dev->dev, &dev_attr_mmap);
+ fail_create_mmap:
+ device_remove_file(&dev->dev, &dev_attr_wsz);
+ fail_create_wsz:
+ device_remove_file(&dev->dev, &dev_attr_ttyp);
+ fail_create_ttyp:
+ device_remove_file(&dev->dev, &dev_attr_taskname);
+ fail_create_taskname:
+ if (task->map_length)
+ dev->fops.mmap = NULL;
+
+ dev->fops.write = NULL;
+ dev->wsz = 0;
+
+ dev->fops.read = NULL;
+ taskdev_flush_buf(dev);
+
+ if (sndtyp_wd(ttyp))
+ kfifo_free(dev->rcvdt.fifo);
+
+ dev->task = NULL;
+
+ return ret;
+}
+
+static void taskdev_detach_task(struct taskdev *dev)
+{
+ u16 ttyp = dev->task->ttyp;
+
+ device_remove_file(&dev->dev, &dev_attr_taskname);
+ device_remove_file(&dev->dev, &dev_attr_ttyp);
+ if (sndtyp_wd(ttyp)) {
+ device_remove_file(&dev->dev, &dev_attr_fifosz);
+ device_remove_file(&dev->dev, &dev_attr_fifocnt);
+ } else
+ device_remove_file(&dev->dev, &dev_attr_ipblink);
+ device_remove_file(&dev->dev, &dev_attr_wsz);
+ if (dev->task->map_length) {
+ device_remove_file(&dev->dev, &dev_attr_mmap);
+ dev->fops.mmap = NULL;
+ }
+
+ dev->fops.read = NULL;
+ taskdev_flush_buf(dev);
+ if (sndtyp_wd(ttyp))
+ kfifo_free(dev->rcvdt.fifo);
+
+ dev->fops.write = NULL;
+ dev->wsz = 0;
+
+ pr_info("omapdsp: taskdev %s disabled.\n", dev->name);
+ dev->task = NULL;
+}
+
+/*
+ * tadd / tdel / tkill
+ */
+static int dsp_tadd(struct taskdev *dev, dsp_long_t adr)
+{
+ struct dsptask *task;
+ struct mb_exarg arg;
+ u8 tid, tid_response;
+ u16 argv[2];
+ int ret = 0;
+
+ if (!devstate_write_lock_and_test(dev, TASKDEV_ST_ADDREQ)) {
+ printk(KERN_ERR
+ "omapdsp: taskdev %s is not requesting for tadd. "
+ "(state is %s)\n", dev->name, devstate_name(dev->state));
+ return -EINVAL;
+ }
+ set_taskdev_state(dev, TASKDEV_ST_ADDING);
+ devstate_write_unlock(dev);
+
+ if (adr == TADD_ABORTADR) {
+ /* aborting tadd intentionally */
+ pr_info("omapdsp: tadd address is ABORTADR.\n");
+ goto fail_out;
+ }
+ if (adr >= DSPSPACE_SIZE) {
+ printk(KERN_ERR
+ "omapdsp: illegal address 0x%08x for tadd\n", adr);
+ ret = -EINVAL;
+ goto fail_out;
+ }
+
+ adr >>= 1; /* word address */
+ argv[0] = adr >> 16; /* addrh */
+ argv[1] = adr & 0xffff; /* addrl */
+
+ if (mutex_lock_interruptible(&cfg_lock)) {
+ ret = -EINTR;
+ goto fail_out;
+ }
+ cfg_tid = TID_ANON;
+ cfg_cmd = MBOX_CMD_DSP_TADD;
+ arg.tid = TID_ANON;
+ arg.argc = 2;
+ arg.argv = argv;
+
+ if (dsp_mem_sync_inc() < 0) {
+ printk(KERN_ERR "omapdsp: memory sync failed!\n");
+ ret = -EBUSY;
+ goto fail_out;
+ }
+ mbcompose_send_and_wait_exarg(TADD, 0, 0, &arg, &cfg_wait_q);
+
+ tid = cfg_tid;
+ cfg_tid = TID_ANON;
+ cfg_cmd = 0;
+ mutex_unlock(&cfg_lock);
+
+ if (tid == TID_ANON) {
+ printk(KERN_ERR "omapdsp: tadd failed!\n");
+ ret = -EINVAL;
+ goto fail_out;
+ }
+ if ((tid < n_task) || dsptask[tid]) {
+ printk(KERN_ERR "omapdsp: illegal tid (%d)!\n", tid);
+ ret = -EINVAL;
+ goto fail_out;
+ }
+ if ((task = kzalloc(sizeof(struct dsptask), GFP_KERNEL)) == NULL) {
+ ret = -ENOMEM;
+ goto del_out;
+ }
+
+ if ((ret = dsp_task_config(task, tid)) < 0)
+ goto free_out;
+
+ if (strcmp(dev->name, task->name)) {
+ printk(KERN_ERR
+ "omapdsp: task name (%s) doesn't match with "
+ "device name (%s).\n", task->name, dev->name);
+ ret = -EINVAL;
+ goto free_out;
+ }
+
+ if ((ret = taskdev_attach_task(dev, task)) < 0)
+ goto free_out;
+
+ dsp_task_init(task);
+ pr_info("omapdsp: taskdev %s enabled.\n", dev->name);
+ set_taskdev_state(dev, TASKDEV_ST_ATTACHED);
+ wake_up_interruptible_all(&dev->state_wait_q);
+ return 0;
+
+free_out:
+ kfree(task);
+
+del_out:
+ printk(KERN_ERR "omapdsp: deleting the task...\n");
+
+ set_taskdev_state(dev, TASKDEV_ST_DELING);
+
+ if (mutex_lock_interruptible(&cfg_lock)) {
+ printk(KERN_ERR "omapdsp: aborting tdel process. "
+ "DSP side could be corrupted.\n");
+ goto fail_out;
+ }
+ cfg_tid = TID_ANON;
+ cfg_cmd = MBOX_CMD_DSP_TDEL;
+ mbcompose_send_and_wait(TDEL, tid, TDEL_KILL, &cfg_wait_q);
+ tid_response = cfg_tid;
+ cfg_tid = TID_ANON;
+ cfg_cmd = 0;
+ mutex_unlock(&cfg_lock);
+
+ if (tid_response != tid)
+ printk(KERN_ERR "omapdsp: tdel failed. "
+ "DSP side could be corrupted.\n");
+
+fail_out:
+ set_taskdev_state(dev, TASKDEV_ST_ADDFAIL);
+ wake_up_interruptible_all(&dev->state_wait_q);
+ return ret;
+}
+
+int dsp_tadd_minor(unsigned char minor, dsp_long_t adr)
+{
+ struct taskdev *dev;
+ int status;
+ int ret;
+
+ if (mutex_lock_interruptible(&devmgr_lock))
+ return -EINTR;
+
+ if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL)) {
+ printk(KERN_ERR
+ "omapdsp: no task device with minor %d\n", minor);
+ ret = -EINVAL;
+ goto out;
+ }
+ ret = minor;
+ if ((status = dsp_tadd(dev, adr)) < 0)
+ ret = status;
+
+out:
+ mutex_unlock(&devmgr_lock);
+ return ret;
+}
+
+static int dsp_tdel(struct taskdev *dev)
+{
+ if (!devstate_write_lock_and_test(dev, TASKDEV_ST_DELREQ)) {
+ printk(KERN_ERR
+ "omapdsp: taskdev %s is not requesting for tdel. "
+ "(state is %s)\n", dev->name, devstate_name(dev->state));
+ return -EINVAL;
+ }
+ set_taskdev_state(dev, TASKDEV_ST_DELING);
+ devstate_write_unlock(dev);
+
+ return dsp_tdel_bh(dev, TDEL_SAFE);
+}
+
+int dsp_tdel_minor(unsigned char minor)
+{
+ struct taskdev *dev;
+ int status;
+ int ret;
+
+ if (mutex_lock_interruptible(&devmgr_lock))
+ return -EINTR;
+
+ if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL)) {
+ printk(KERN_ERR
+ "omapdsp: no task device with minor %d\n", minor);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = minor;
+ if ((status = dsp_tdel(dev)) < 0)
+ ret = status;
+
+out:
+ mutex_unlock(&devmgr_lock);
+ return ret;
+}
+
+static int dsp_tkill(struct taskdev *dev)
+{
+ while (!down_write_trylock(&dev->state_sem)) {
+ if (!devstate_read_lock_and_test(dev, (TASKDEV_ST_ATTACHED |
+ TASKDEV_ST_FREEZED))) {
+ printk(KERN_ERR
+ "omapdsp: task has not been attached for "
+ "taskdev %s\n", dev->name);
+ return -EINVAL;
+ }
+ /* ATTACHED -> FREEZED can be changed under read semaphore. */
+ set_taskdev_state(dev, TASKDEV_ST_FREEZED);
+ wake_up_interruptible_all(&dev->read_wait_q);
+ wake_up_interruptible_all(&dev->write_wait_q);
+ wake_up_interruptible_all(&dev->tctl_wait_q);
+ devstate_read_unlock(dev);
+ schedule();
+ }
+
+ if (!(dev->state & (TASKDEV_ST_ATTACHED |
+ TASKDEV_ST_FREEZED))) {
+ printk(KERN_ERR
+ "omapdsp: task has not been attached for taskdev %s\n",
+ dev->name);
+ devstate_write_unlock(dev);
+ return -EINVAL;
+ }
+ if (!is_dynamic_task(dev->task->tid)) {
+ printk(KERN_ERR "omapdsp: task %s is not a dynamic task.\n",
+ dev->name);
+ devstate_write_unlock(dev);
+ return -EINVAL;
+ }
+ set_taskdev_state(dev, TASKDEV_ST_KILLING);
+ devstate_write_unlock(dev);
+
+ return dsp_tdel_bh(dev, TDEL_KILL);
+}
+
+int dsp_tkill_minor(unsigned char minor)
+{
+ struct taskdev *dev;
+ int status;
+ int ret;
+
+ if (mutex_lock_interruptible(&devmgr_lock))
+ return -EINTR;
+
+ if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL)) {
+ printk(KERN_ERR
+ "omapdsp: no task device with minor %d\n", minor);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = minor;
+ if ((status = dsp_tkill(dev)) < 0)
+ ret = status;
+
+out:
+ mutex_unlock(&devmgr_lock);
+ return ret;
+}
+
+static int dsp_tdel_bh(struct taskdev *dev, u16 type)
+{
+ struct dsptask *task;
+ u8 tid, tid_response;
+ int ret = 0;
+
+ task = dev->task;
+ tid = task->tid;
+ if (mutex_lock_interruptible(&cfg_lock)) {
+ if (type == TDEL_SAFE) {
+ set_taskdev_state(dev, TASKDEV_ST_DELREQ);
+ return -EINTR;
+ } else {
+ tid_response = TID_ANON;
+ ret = -EINTR;
+ goto detach_out;
+ }
+ }
+ cfg_tid = TID_ANON;
+ cfg_cmd = MBOX_CMD_DSP_TDEL;
+ mbcompose_send_and_wait(TDEL, tid, type, &cfg_wait_q);
+ tid_response = cfg_tid;
+ cfg_tid = TID_ANON;
+ cfg_cmd = 0;
+ mutex_unlock(&cfg_lock);
+
+detach_out:
+ taskdev_detach_task(dev);
+ dsp_task_unconfig(task);
+ kfree(task);
+
+ if (tid_response != tid) {
+ printk(KERN_ERR "omapdsp: %s failed!\n",
+ (type == TDEL_SAFE) ? "tdel" : "tkill");
+ ret = -EINVAL;
+ }
+ down_write(&dev->state_sem);
+ set_taskdev_state(dev, (dev->usecount > 0) ? TASKDEV_ST_GARBAGE :
+ TASKDEV_ST_NOTASK);
+ wake_up_interruptible_all(&dev->state_wait_q);
+ up_write(&dev->state_sem);
+
+ return ret;
+}
+
+/*
+ * state inquiry
+ */
+long taskdev_state_stale(unsigned char minor)
+{
+ if (taskdev[minor]) {
+ long state = taskdev[minor]->state;
+ taskdev[minor]->state |= TASKDEV_ST_STALE;
+ return state;
+ } else
+ return TASKDEV_ST_NOTASK;
+}
+
+/*
+ * functions called from mailbox interrupt routine
+ */
+void mbox_wdsnd(struct mbcmd *mb)
+{
+ unsigned int n;
+ u8 tid = mb->cmd_l;
+ u16 data = mb->data;
+ struct dsptask *task = dsptask[tid];
+
+ if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+ printk(KERN_ERR "mbox: WDSND with illegal tid! %d\n", tid);
+ return;
+ }
+ if (sndtyp_bk(task->ttyp)) {
+ printk(KERN_ERR
+ "mbox: WDSND from block sending task! (task%d)\n", tid);
+ return;
+ }
+ if (sndtyp_psv(task->ttyp) &&
+ !waitqueue_active(&task->dev->read_wait_q)) {
+ printk(KERN_WARNING
+ "mbox: WDSND from passive sending task (task%d) "
+ "without request!\n", tid);
+ return;
+ }
+
+ n = kfifo_put(task->dev->rcvdt.fifo, (unsigned char *)&data,
+ sizeof(data));
+ if (n != sizeof(data))
+ printk(KERN_WARNING "Receive FIFO(%d) is full\n", tid);
+
+ wake_up_interruptible(&task->dev->read_wait_q);
+}
+
+void mbox_wdreq(struct mbcmd *mb)
+{
+ u8 tid = mb->cmd_l;
+ struct dsptask *task = dsptask[tid];
+ struct taskdev *dev;
+
+ if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+ printk(KERN_ERR "mbox: WDREQ with illegal tid! %d\n", tid);
+ return;
+ }
+ if (rcvtyp_psv(task->ttyp)) {
+ printk(KERN_ERR
+ "mbox: WDREQ from passive receiving task! (task%d)\n",
+ tid);
+ return;
+ }
+
+ dev = task->dev;
+ spin_lock(&dev->wsz_lock);
+ dev->wsz = 2;
+ spin_unlock(&dev->wsz_lock);
+ wake_up_interruptible(&dev->write_wait_q);
+}
+
+void mbox_bksnd(struct mbcmd *mb)
+{
+ u8 tid = mb->cmd_l;
+ u16 bid = mb->data;
+ struct dsptask *task = dsptask[tid];
+ struct ipbuf_head *ipb_h;
+ u16 cnt;
+
+ if (bid >= ipbcfg.ln) {
+ printk(KERN_ERR "mbox: BKSND with illegal bid! %d\n", bid);
+ return;
+ }
+ ipb_h = bid_to_ipbuf(bid);
+ ipb_bsycnt_dec(&ipbcfg);
+ if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+ printk(KERN_ERR "mbox: BKSND with illegal tid! %d\n", tid);
+ goto unuse_ipbuf_out;
+ }
+ if (sndtyp_wd(task->ttyp)) {
+ printk(KERN_ERR
+ "mbox: BKSND from word sending task! (task%d)\n", tid);
+ goto unuse_ipbuf_out;
+ }
+ if (sndtyp_pvt(task->ttyp)) {
+ printk(KERN_ERR
+ "mbox: BKSND from private sending task! (task%d)\n", tid);
+ goto unuse_ipbuf_out;
+ }
+ if (sync_with_dsp(&ipb_h->p->sd, tid, 10) < 0) {
+ printk(KERN_ERR "mbox: BKSND - IPBUF sync failed!\n");
+ return;
+ }
+
+ /* should be done in DSP, but just in case. */
+ ipb_h->p->next = BID_NULL;
+
+ cnt = ipb_h->p->c;
+ if (cnt > ipbcfg.lsz) {
+ printk(KERN_ERR "mbox: BKSND cnt(%d) > ipbuf line size(%d)!\n",
+ cnt, ipbcfg.lsz);
+ goto unuse_ipbuf_out;
+ }
+
+ if (cnt == 0) {
+ /* 0-byte send from DSP */
+ unuse_ipbuf_nowait(ipb_h);
+ goto done;
+ }
+ ipblink_add_tail(&task->dev->rcvdt.bk.link, bid);
+ /* we keep coming bid and return alternative line to DSP. */
+ balance_ipbuf();
+
+done:
+ wake_up_interruptible(&task->dev->read_wait_q);
+ return;
+
+unuse_ipbuf_out:
+ unuse_ipbuf_nowait(ipb_h);
+ return;
+}
+
+void mbox_bkreq(struct mbcmd *mb)
+{
+ u8 tid = mb->cmd_l;
+ u16 cnt = mb->data;
+ struct dsptask *task = dsptask[tid];
+ struct taskdev *dev;
+
+ if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+ printk(KERN_ERR "mbox: BKREQ with illegal tid! %d\n", tid);
+ return;
+ }
+ if (rcvtyp_wd(task->ttyp)) {
+ printk(KERN_ERR
+ "mbox: BKREQ from word receiving task! (task%d)\n", tid);
+ return;
+ }
+ if (rcvtyp_pvt(task->ttyp)) {
+ printk(KERN_ERR
+ "mbox: BKREQ from private receiving task! (task%d)\n",
+ tid);
+ return;
+ }
+ if (rcvtyp_psv(task->ttyp)) {
+ printk(KERN_ERR
+ "mbox: BKREQ from passive receiving task! (task%d)\n",
+ tid);
+ return;
+ }
+
+ dev = task->dev;
+ spin_lock(&dev->wsz_lock);
+ dev->wsz = cnt*2;
+ spin_unlock(&dev->wsz_lock);
+ wake_up_interruptible(&dev->write_wait_q);
+}
+
+void mbox_bkyld(struct mbcmd *mb)
+{
+ u16 bid = mb->data;
+ struct ipbuf_head *ipb_h;
+
+ if (bid >= ipbcfg.ln) {
+ printk(KERN_ERR "mbox: BKYLD with illegal bid! %d\n", bid);
+ return;
+ }
+ ipb_h = bid_to_ipbuf(bid);
+
+ /* should be done in DSP, but just in case. */
+ ipb_h->p->next = BID_NULL;
+
+ /* we don't need to sync with DSP */
+ ipb_bsycnt_dec(&ipbcfg);
+ release_ipbuf(ipb_h);
+}
+
+void mbox_bksndp(struct mbcmd *mb)
+{
+ u8 tid = mb->cmd_l;
+ struct dsptask *task = dsptask[tid];
+ struct ipbuf_p *ipbp;
+
+ if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+ printk(KERN_ERR "mbox: BKSNDP with illegal tid! %d\n", tid);
+ return;
+ }
+ if (sndtyp_wd(task->ttyp)) {
+ printk(KERN_ERR
+ "mbox: BKSNDP from word sending task! (task%d)\n", tid);
+ return;
+ }
+ if (sndtyp_gbl(task->ttyp)) {
+ printk(KERN_ERR
+ "mbox: BKSNDP from non-private sending task! (task%d)\n",
+ tid);
+ return;
+ }
+
+ /*
+ * we should not have delayed block at this point
+ * because read() routine releases the lock of the buffer and
+ * until then DSP can't send next data.
+ */
+
+ ipbp = task->ipbuf_pvt_r;
+ if (sync_with_dsp(&ipbp->s, tid, 10) < 0) {
+ printk(KERN_ERR "mbox: BKSNDP - IPBUF sync failed!\n");
+ return;
+ }
+ pr_debug("mbox: ipbuf_pvt_r->a = 0x%08lx\n",
+ MKLONG(ipbp->ah, ipbp->al));
+ ipblink_add_pvt(&task->dev->rcvdt.bk.link);
+ wake_up_interruptible(&task->dev->read_wait_q);
+}
+
+void mbox_bkreqp(struct mbcmd *mb)
+{
+ u8 tid = mb->cmd_l;
+ struct dsptask *task = dsptask[tid];
+ struct taskdev *dev;
+ struct ipbuf_p *ipbp;
+
+ if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+ printk(KERN_ERR "mbox: BKREQP with illegal tid! %d\n", tid);
+ return;
+ }
+ if (rcvtyp_wd(task->ttyp)) {
+ printk(KERN_ERR
+ "mbox: BKREQP from word receiving task! (task%d)\n", tid);
+ return;
+ }
+ if (rcvtyp_gbl(task->ttyp)) {
+ printk(KERN_ERR
+ "mbox: BKREQP from non-private receiving task! (task%d)\n", tid);
+ return;
+ }
+ if (rcvtyp_psv(task->ttyp)) {
+ printk(KERN_ERR
+ "mbox: BKREQP from passive receiving task! (task%d)\n", tid);
+ return;
+ }
+
+ ipbp = task->ipbuf_pvt_w;
+ if (sync_with_dsp(&ipbp->s, TID_FREE, 10) < 0) {
+ printk(KERN_ERR "mbox: BKREQP - IPBUF sync failed!\n");
+ return;
+ }
+ pr_debug("mbox: ipbuf_pvt_w->a = 0x%08lx\n",
+ MKLONG(ipbp->ah, ipbp->al));
+ dev = task->dev;
+ spin_lock(&dev->wsz_lock);
+ dev->wsz = ipbp->c*2;
+ spin_unlock(&dev->wsz_lock);
+ wake_up_interruptible(&dev->write_wait_q);
+}
+
+void mbox_tctl(struct mbcmd *mb)
+{
+ u8 tid = mb->cmd_l;
+ struct dsptask *task = dsptask[tid];
+
+ if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+ printk(KERN_ERR "mbox: TCTL with illegal tid! %d\n", tid);
+ return;
+ }
+
+ if (!waitqueue_active(&task->dev->tctl_wait_q)) {
+ printk(KERN_WARNING "mbox: unexpected TCTL from DSP!\n");
+ return;
+ }
+
+ task->dev->tctl_stat = mb->data;
+ wake_up_interruptible(&task->dev->tctl_wait_q);
+}
+
+void mbox_tcfg(struct mbcmd *mb)
+{
+ u8 tid = mb->cmd_l;
+ struct dsptask *task = dsptask[tid];
+ u16 *tnm;
+ volatile u16 *buf;
+ int i;
+
+ if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+ printk(KERN_ERR "mbox: TCFG with illegal tid! %d\n", tid);
+ return;
+ }
+ if ((task->state != TASK_ST_CFGREQ) || (cfg_cmd != MBOX_CMD_DSP_TCFG)) {
+ printk(KERN_WARNING "mbox: unexpected TCFG from DSP!\n");
+ return;
+ }
+
+ if (dsp_mem_enable(ipbuf_sys_da) < 0) {
+ printk(KERN_ERR "mbox: TCFG - ipbuf_sys_da read failed!\n");
+ dsp_mem_disable(ipbuf_sys_da);
+ goto out;
+ }
+ if (sync_with_dsp(&ipbuf_sys_da->s, tid, 10) < 0) {
+ printk(KERN_ERR "mbox: TCFG - IPBUF sync failed!\n");
+ dsp_mem_disable(ipbuf_sys_da);
+ goto out;
+ }
+
+ /*
+ * read configuration data on system IPBUF
+ */
+ buf = ipbuf_sys_da->d;
+ task->ttyp = buf[0];
+ task->ipbuf_pvt_r = MKVIRT(buf[1], buf[2]);
+ task->ipbuf_pvt_w = MKVIRT(buf[3], buf[4]);
+ task->map_base = MKVIRT(buf[5], buf[6]);
+ task->map_length = MKLONG(buf[7], buf[8]) << 1; /* word -> byte */
+ tnm = MKVIRT(buf[9], buf[10]);
+ release_ipbuf_pvt(ipbuf_sys_da);
+ dsp_mem_disable(ipbuf_sys_da);
+
+ /*
+ * copy task name string
+ */
+ if (dsp_address_validate(tnm, TNM_LEN, "task name buffer") < 0) {
+ task->name[0] = '\0';
+ goto out;
+ }
+
+ for (i = 0; i < TNM_LEN-1; i++) {
+ /* avoiding byte access */
+ u16 tmp = tnm[i];
+ task->name[i] = tmp & 0x00ff;
+ if (!tmp)
+ break;
+ }
+ task->name[TNM_LEN-1] = '\0';
+
+ task->state = TASK_ST_READY;
+out:
+ wake_up_interruptible(&cfg_wait_q);
+}
+
+void mbox_tadd(struct mbcmd *mb)
+{
+ u8 tid = mb->cmd_l;
+
+ if ((!waitqueue_active(&cfg_wait_q)) || (cfg_cmd != MBOX_CMD_DSP_TADD)) {
+ printk(KERN_WARNING "mbox: unexpected TADD from DSP!\n");
+ return;
+ }
+ cfg_tid = tid;
+ wake_up_interruptible(&cfg_wait_q);
+}
+
+void mbox_tdel(struct mbcmd *mb)
+{
+ u8 tid = mb->cmd_l;
+
+ if ((!waitqueue_active(&cfg_wait_q)) || (cfg_cmd != MBOX_CMD_DSP_TDEL)) {
+ printk(KERN_WARNING "mbox: unexpected TDEL from DSP!\n");
+ return;
+ }
+ cfg_tid = tid;
+ wake_up_interruptible(&cfg_wait_q);
+}
+
+void mbox_err_fatal(u8 tid)
+{
+ struct dsptask *task = dsptask[tid];
+ struct taskdev *dev;
+
+ if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+ printk(KERN_ERR "mbox: FATAL ERR with illegal tid! %d\n", tid);
+ return;
+ }
+
+ /* wake up waiting processes */
+ dev = task->dev;
+ wake_up_interruptible_all(&dev->read_wait_q);
+ wake_up_interruptible_all(&dev->write_wait_q);
+ wake_up_interruptible_all(&dev->tctl_wait_q);
+}
+
+static u16 *dbg_buf;
+static u16 dbg_buf_sz, dbg_line_sz;
+static int dbg_rp;
+
+int dsp_dbg_config(u16 *buf, u16 sz, u16 lsz)
+{
+#ifdef OLD_BINARY_SUPPORT
+ if ((mbox_revision == MBREV_3_0) || (mbox_revision == MBREV_3_2)) {
+ dbg_buf = NULL;
+ dbg_buf_sz = 0;
+ dbg_line_sz = 0;
+ dbg_rp = 0;
+ return 0;
+ }
+#endif
+
+ if (dsp_address_validate(buf, sz, "debug buffer") < 0)
+ return -1;
+
+ if (lsz > sz) {
+ printk(KERN_ERR
+ "omapdsp: dbg_buf lsz (%d) is greater than its "
+ "buffer size (%d)\n", lsz, sz);
+ return -1;
+ }
+
+ dbg_buf = buf;
+ dbg_buf_sz = sz;
+ dbg_line_sz = lsz;
+ dbg_rp = 0;
+
+ return 0;
+}
+
+void dsp_dbg_stop(void)
+{
+ dbg_buf = NULL;
+}
+
+#ifdef OLD_BINARY_SUPPORT
+static void mbox_dbg_old(struct mbcmd *mb);
+#endif
+
+void mbox_dbg(struct mbcmd *mb)
+{
+ u8 tid = mb->cmd_l;
+ int cnt = mb->data;
+ char s[80], *s_end = &s[79], *p;
+ u16 *src;
+ int i;
+
+#ifdef OLD_BINARY_SUPPORT
+ if ((mbox_revision == MBREV_3_0) || (mbox_revision == MBREV_3_2)) {
+ mbox_dbg_old(mb);
+ return;
+ }
+#endif
+
+ if (((tid >= TASKDEV_MAX) || (dsptask[tid] == NULL)) &&
+ (tid != TID_ANON)) {
+ printk(KERN_ERR "mbox: DBG with illegal tid! %d\n", tid);
+ return;
+ }
+ if (dbg_buf == NULL) {
+ printk(KERN_ERR "mbox: DBG command received, but "
+ "dbg_buf has not been configured yet.\n");
+ return;
+ }
+
+ if (dsp_mem_enable(dbg_buf) < 0)
+ return;
+
+ src = &dbg_buf[dbg_rp];
+ p = s;
+ for (i = 0; i < cnt; i++) {
+ u16 tmp;
+ /*
+ * Be carefull that dbg_buf should not be read with
+ * 1-byte access since it might be placed in DARAM/SARAM
+ * and it can cause unexpected byteswap.
+ * For example,
+ * *(p++) = *(src++) & 0xff;
+ * causes 1-byte access!
+ */
+ tmp = *src++;
+ *(p++) = tmp & 0xff;
+ if (*(p-1) == '\n') {
+ *p = '\0';
+ pr_info("%s", s);
+ p = s;
+ continue;
+ }
+ if (p == s_end) {
+ *p = '\0';
+ pr_info("%s\n", s);
+ p = s;
+ continue;
+ }
+ }
+ if (p > s) {
+ *p = '\0';
+ pr_info("%s\n", s);
+ }
+ if ((dbg_rp += cnt + 1) > dbg_buf_sz - dbg_line_sz)
+ dbg_rp = 0;
+
+ dsp_mem_disable(dbg_buf);
+}
+
+#ifdef OLD_BINARY_SUPPORT
+static void mbox_dbg_old(struct mbcmd *mb)
+{
+ u8 tid = mb->cmd_l;
+ char s[80], *s_end = &s[79], *p;
+ u16 *src;
+ volatile u16 *buf;
+ int cnt;
+ int i;
+
+ if (((tid >= TASKDEV_MAX) || (dsptask[tid] == NULL)) &&
+ (tid != TID_ANON)) {
+ printk(KERN_ERR "mbox: DBG with illegal tid! %d\n", tid);
+ return;
+ }
+ if (dsp_mem_enable(ipbuf_sys_da) < 0) {
+ printk(KERN_ERR "mbox: DBG - ipbuf_sys_da read failed!\n");
+ return;
+ }
+ if (sync_with_dsp(&ipbuf_sys_da->s, tid, 10) < 0) {
+ printk(KERN_ERR "mbox: DBG - IPBUF sync failed!\n");
+ goto out1;
+ }
+ buf = ipbuf_sys_da->d;
+ cnt = buf[0];
+ src = MKVIRT(buf[1], buf[2]);
+ if (dsp_address_validate(src, cnt, "dbg buffer") < 0)
+ goto out2;
+
+ if (dsp_mem_enable(src) < 0)
+ goto out2;
+
+ p = s;
+ for (i = 0; i < cnt; i++) {
+ u16 tmp;
+ /*
+ * Be carefull that ipbuf should not be read with
+ * 1-byte access since it might be placed in DARAM/SARAM
+ * and it can cause unexpected byteswap.
+ * For example,
+ * *(p++) = *(src++) & 0xff;
+ * causes 1-byte access!
+ */
+ tmp = *src++;
+ *(p++) = tmp & 0xff;
+ if (*(p-1) == '\n') {
+ *p = '\0';
+ pr_info("%s", s);
+ p = s;
+ continue;
+ }
+ if (p == s_end) {
+ *p = '\0';
+ pr_info("%s\n", s);
+ p = s;
+ continue;
+ }
+ }
+ if (p > s) {
+ *p = '\0';
+ pr_info("%s\n", s);
+ }
+
+ dsp_mem_disable(src);
+out2:
+ release_ipbuf_pvt(ipbuf_sys_da);
+out1:
+ dsp_mem_disable(ipbuf_sys_da);
+}
+#endif /* OLD_BINARY_SUPPORT */
+
+/*
+ * sysfs files: for each device
+ */
+
+/* devname */
+static ssize_t devname_show(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%s\n", to_taskdev(d)->name);
+}
+
+/* devstate */
+static ssize_t devstate_show(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%s\n", devstate_name(to_taskdev(d)->state));
+}
+
+/* proc_list */
+static ssize_t proc_list_show(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ struct taskdev *dev;
+ struct proc_list *pl;
+ int len = 0;
+
+ dev = to_taskdev(d);
+ spin_lock(&dev->proc_list_lock);
+ list_for_each_entry(pl, &dev->proc_list, list_head) {
+ /* need to lock tasklist_lock before calling
+ * find_task_by_pid_type. */
++ if (find_task_by_pid_type_ns(PIDTYPE_PID, pl->pid, &init_pid_ns) != NULL)
+ len += sprintf(buf + len, "%d\n", pl->pid);
+ read_unlock(&tasklist_lock);
+ }
+ spin_unlock(&dev->proc_list_lock);
+
+ return len;
+}
+
+/* taskname */
+static ssize_t taskname_show(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ struct taskdev *dev = to_taskdev(d);
+ int len;
+
+ if (!devstate_read_lock_and_test(dev, TASKDEV_ST_ATTACHED))
+ return -ENODEV;
+
+ len = sprintf(buf, "%s\n", dev->task->name);
+
+ devstate_read_unlock(dev);
+ return len;
+}
+
+/* ttyp */
+static ssize_t ttyp_show(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ struct taskdev *dev = to_taskdev(d);
+ u16 ttyp;
+ int len = 0;
+
+ if (!devstate_read_lock_and_test(dev, TASKDEV_ST_ATTACHED))
+ return -ENODEV;
+
+ ttyp = dev->task->ttyp;
+ len += sprintf(buf + len, "0x%04x\n", ttyp);
+ len += sprintf(buf + len, "%s %s send\n",
+ (sndtyp_acv(ttyp)) ? "active" :
+ "passive",
+ (sndtyp_wd(ttyp)) ? "word" :
+ (sndtyp_pvt(ttyp)) ? "private block" :
+ "global block");
+ len += sprintf(buf + len, "%s %s receive\n",
+ (rcvtyp_acv(ttyp)) ? "active" :
+ "passive",
+ (rcvtyp_wd(ttyp)) ? "word" :
+ (rcvtyp_pvt(ttyp)) ? "private block" :
+ "global block");
+
+ devstate_read_unlock(dev);
+ return len;
+}
+
+/* fifosz */
+static ssize_t fifosz_show(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ struct kfifo *fifo = to_taskdev(d)->rcvdt.fifo;
+ return sprintf(buf, "%d\n", fifo->size);
+}
+
+static int fifosz_store(struct device *d, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct taskdev *dev = to_taskdev(d);
+ unsigned long fifosz;
+ int ret;
+
+ fifosz = simple_strtol(buf, NULL, 10);
+ if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
+ return -ENODEV;
+ ret = taskdev_set_fifosz(dev, fifosz);
+ taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
+
+ return (ret < 0) ? ret : strlen(buf);
+}
+
+/* fifocnt */
+static ssize_t fifocnt_show(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ struct kfifo *fifo = to_taskdev(d)->rcvdt.fifo;
+ return sprintf(buf, "%d\n", fifo->size);
+}
+
+/* ipblink */
+static inline char *bid_name(u16 bid)
+{
+ static char s[6];
+
+ switch (bid) {
+ case BID_NULL:
+ return "NULL";
+ case BID_PVT:
+ return "PRIVATE";
+ default:
+ sprintf(s, "%d", bid);
+ return s;
+ }
+}
+
+static ssize_t ipblink_show(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ struct rcvdt_bk_struct *rcvdt = &to_taskdev(d)->rcvdt.bk;
+ int len;
+
+ spin_lock(&rcvdt->link.lock);
+ len = sprintf(buf, "top %s\ntail %s\n",
+ bid_name(rcvdt->link.top), bid_name(rcvdt->link.tail));
+ spin_unlock(&rcvdt->link.lock);
+
+ return len;
+}
+
+/* wsz */
+static ssize_t wsz_show(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d\n", to_taskdev(d)->wsz);
+}
+
+/* mmap */
+static ssize_t mmap_show(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ struct dsptask *task = to_taskdev(d)->task;
+ return sprintf(buf, "0x%p 0x%x\n", task->map_base, task->map_length);
+}
+
+/*
+ * called from ipbuf_show()
+ */
+int ipbuf_is_held(u8 tid, u16 bid)
+{
+ struct dsptask *task = dsptask[tid];
+ struct ipblink *link;
+ u16 b;
+ int ret = 0;
+
+ if (task == NULL)
+ return 0;
+
+ link = &task->dev->rcvdt.bk.link;
+ spin_lock(&link->lock);
+ ipblink_for_each(b, link) {
+ if (b == bid) { /* found */
+ ret = 1;
+ break;
+ }
+ }
+ spin_unlock(&link->lock);
+
+ return ret;
+}
+
+int __init dsp_taskmod_init(void)
+{
+ int retval;
+
+ memset(taskdev, 0, sizeof(void *) * TASKDEV_MAX);
+ memset(dsptask, 0, sizeof(void *) * TASKDEV_MAX);
+
+ retval = register_chrdev(OMAP_DSP_TASK_MAJOR, "dsptask",
+ &dsp_task_fops);
+ if (retval < 0) {
+ printk(KERN_ERR
+ "omapdsp: failed to register task device: %d\n", retval);
+ return retval;
+ }
+
+ retval = bus_register(&dsptask_bus);
+ if (retval) {
+ printk(KERN_ERR
+ "omapdsp: failed to register DSP task bus: %d\n",
+ retval);
+ unregister_chrdev(OMAP_DSP_TASK_MAJOR, "dsptask");
+ return -EINVAL;
+ }
+ retval = driver_register(&dsptask_driver);
+ if (retval) {
+ printk(KERN_ERR
+ "omapdsp: failed to register DSP task driver: %d\n",
+ retval);
+ bus_unregister(&dsptask_bus);
+ unregister_chrdev(OMAP_DSP_TASK_MAJOR, "dsptask");
+ return -EINVAL;
+ }
+ dsp_task_class = class_create(THIS_MODULE, "dsptask");
+ if (IS_ERR(dsp_task_class)) {
+ printk(KERN_ERR "omapdsp: failed to create DSP task class\n");
+ driver_unregister(&dsptask_driver);
+ bus_unregister(&dsptask_bus);
+ unregister_chrdev(OMAP_DSP_TASK_MAJOR, "dsptask");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+void dsp_taskmod_exit(void)
+{
+ class_destroy(dsp_task_class);
+ driver_unregister(&dsptask_driver);
+ bus_unregister(&dsptask_bus);
+ unregister_chrdev(OMAP_DSP_TASK_MAJOR, "dsptask");
+}
tristate "National Semiconductor LM75 and compatibles"
depends on I2C
help
- If you say yes here you get support for National Semiconductor LM75
- sensor chips and clones: Dallas Semiconductor DS75 and DS1775 (in
- 9-bit precision mode), and TelCom (now Microchip) TCN75.
-
- The DS75 and DS1775 in 10- to 12-bit precision modes will require
- a force module parameter. The driver will not handle the extra
- precision anyhow.
+ If you say yes here you get support for one common type of
+ temperature sensor chip, with models including:
+
+ - Dallas Semiconductor DS75 and DS1775
+ - Maxim MAX6625 and MAX6626
+ - Microchip MCP980x
+ - National Semiconductor LM75
+ - NXP's LM75A
+ - ST Microelectronics STDS75
+ - TelCom (now Microchip) TCN75
+ - Texas Instruments TMP100, TMP101, TMP75, TMP175, TMP275
+
+ This driver supports driver model based binding through board
+ specific I2C device tables.
+
+ It also supports the "legacy" style of driver binding. To use
+ that with some chips which don't replicate LM75 quirks exactly,
+ you may need the "force" module parameter.
This driver can also be built as a module. If so, the module
will be called lm75.
Say Y here if you have an applicable laptop and want to experience
the awesome power of applesmc.
+config SENSORS_TSC210X
+ tristate "TI TSC210x battery & temperature sensors"
+ depends on HWMON && SPI_MASTER
+ select SPI_TSC210X
+ help
+ Say Y if your board has a TSC210x chip and you want to
+ have its battery state, auxiliary input and/or temperature
+ sensors exported through hwmon.
+
+ This driver can also be built as a module. In this case
+ the module will be called tsc210x_sensors.
+
+config SENSORS_OMAP34XX
+ tristate "TI OMAP34xx internal temperature sensor"
+ depends on ARCH_OMAP3 && HIGH_RES_TIMERS
+
config HWMON_DEBUG_CHIP
bool "Hardware Monitoring Chip debugging messages"
default n
menu "I2C Hardware Bus support"
+ comment "PC SMBus host controller drivers"
+ depends on PCI
+
config I2C_ALI1535
tristate "ALI 1535"
depends on PCI
This driver can also be built as a module. If so, the module
will be called i2c-amd8111.
- config I2C_AT91
- tristate "Atmel AT91 I2C Two-Wire interface (TWI)"
- depends on ARCH_AT91 && EXPERIMENTAL && BROKEN
- help
- This supports the use of the I2C interface on Atmel AT91
- processors.
-
- This driver is BROKEN because the controller which it uses
- will easily trigger RX overrun and TX underrun errors. Using
- low I2C clock rates may partially work around those issues
- on some systems. Another serious problem is that there is no
- documented way to issue repeated START conditions, as needed
- to support combined I2C messages. Use the i2c-gpio driver
- unless your system can cope with those limitations.
-
- config I2C_AU1550
- tristate "Au1550/Au1200 SMBus interface"
- depends on SOC_AU1550 || SOC_AU1200
- help
- If you say yes to this option, support will be included for the
- Au1550 and Au1200 SMBus interface.
-
- This driver can also be built as a module. If so, the module
- will be called i2c-au1550.
-
- config I2C_BLACKFIN_TWI
- tristate "Blackfin TWI I2C support"
- depends on BLACKFIN
- help
- This is the TWI I2C device driver for Blackfin BF522, BF525,
- BF527, BF534, BF536, BF537 and BF54x. For other Blackfin processors,
- please don't use this driver.
-
- This driver can also be built as a module. If so, the module
- will be called i2c-bfin-twi.
-
- config I2C_BLACKFIN_TWI_CLK_KHZ
- int "Blackfin TWI I2C clock (kHz)"
- depends on I2C_BLACKFIN_TWI
- range 10 400
- default 50
- help
- The unit of the TWI clock is kHz.
-
- config I2C_DAVINCI
- tristate "DaVinci I2C driver"
- depends on ARCH_DAVINCI
- help
- Support for TI DaVinci I2C controller driver.
-
- This driver can also be built as a module. If so, the module
- will be called i2c-davinci.
-
- Please note that this driver might be needed to bring up other
- devices such as DaVinci NIC.
- For details please see http://www.ti.com/davinci
-
- config I2C_ELEKTOR
- tristate "Elektor ISA card"
- depends on ISA && BROKEN_ON_SMP
- select I2C_ALGOPCF
- help
- This supports the PCF8584 ISA bus I2C adapter. Say Y if you own
- such an adapter.
-
- This support is also available as a module. If so, the module
- will be called i2c-elektor.
-
- config I2C_GPIO
- tristate "GPIO-based bitbanging I2C"
- depends on GENERIC_GPIO
- select I2C_ALGOBIT
- help
- This is a very simple bitbanging I2C driver utilizing the
- arch-neutral GPIO API to control the SCL and SDA lines.
-
- config I2C_HYDRA
- tristate "CHRP Apple Hydra Mac I/O I2C interface"
- depends on PCI && PPC_CHRP && EXPERIMENTAL
- select I2C_ALGOBIT
- help
- This supports the use of the I2C interface in the Apple Hydra Mac
- I/O chip on some CHRP machines (e.g. the LongTrail). Say Y if you
- have such a machine.
-
- This support is also available as a module. If so, the module
- will be called i2c-hydra.
-
config I2C_I801
tristate "Intel 82801 (ICH)"
depends on PCI
This driver can also be built as a module. If so, the module
will be called i2c-i801.
- config I2C_I810
- tristate "Intel 810/815 (DEPRECATED)"
- default n
+ config I2C_ISCH
+ tristate "Intel SCH SMBus 1.0"
depends on PCI
- select I2C_ALGOBIT
- help
- If you say yes to this option, support will be included for the Intel
- 810/815 family of mainboard I2C interfaces. Specifically, the
- following versions of the chipset are supported:
- i810AA
- i810AB
- i810E
- i815
- i845G
-
- This driver is deprecated in favor of the i810fb and intelfb drivers.
-
- This driver can also be built as a module. If so, the module
- will be called i2c-i810.
-
- config I2C_PXA
- tristate "Intel PXA2XX I2C adapter (EXPERIMENTAL)"
- depends on EXPERIMENTAL && ARCH_PXA
help
- If you have devices in the PXA I2C bus, say yes to this option.
- This driver can also be built as a module. If so, the module
- will be called i2c-pxa.
+ Say Y here if you want to use SMBus controller on the Intel SCH
+ based systems.
- config I2C_PXA_SLAVE
- bool "Intel PXA2XX I2C Slave comms support"
- depends on I2C_PXA
- help
- Support I2C slave mode communications on the PXA I2C bus. This
- is necessary for systems where the PXA may be a target on the
- I2C bus.
+ This driver can also be built as a module. If so, the module
+ will be called i2c-isch.
config I2C_PIIX4
tristate "Intel PIIX4 and compatible (ATI/Serverworks/Broadcom/SMSC)"
This driver can also be built as a module. If so, the module
will be called i2c-piix4.
- config I2C_IBM_IIC
- tristate "IBM PPC 4xx on-chip I2C interface"
- depends on 4xx
+ config I2C_NFORCE2
+ tristate "Nvidia nForce2, nForce3 and nForce4"
+ depends on PCI
help
- Say Y here if you want to use IIC peripheral found on
- embedded IBM PPC 4xx based systems.
+ If you say yes to this option, support will be included for the Nvidia
+ nForce2, nForce3 and nForce4 families of mainboard I2C interfaces.
This driver can also be built as a module. If so, the module
- will be called i2c-ibm_iic.
+ will be called i2c-nforce2.
- config I2C_IOP3XX
- tristate "Intel IOPx3xx and IXP4xx on-chip I2C interface"
- depends on ARCH_IOP32X || ARCH_IOP33X || ARCH_IXP4XX || ARCH_IOP13XX
+ config I2C_NFORCE2_S4985
+ tristate "SMBus multiplexing on the Tyan S4985"
+ depends on I2C_NFORCE2 && EXPERIMENTAL
help
- Say Y here if you want to use the IIC bus controller on
- the Intel IOPx3xx I/O Processors or IXP4xx Network Processors.
+ Enabling this option will add specific SMBus support for the Tyan
+ S4985 motherboard. On this 4-CPU board, the SMBus is multiplexed
+ over 4 different channels, where the various memory module EEPROMs
+ live. Saying yes here will give you access to these in addition
+ to the trunk.
This driver can also be built as a module. If so, the module
- will be called i2c-iop3xx.
+ will be called i2c-nforce2-s4985.
- config I2C_IXP2000
- tristate "IXP2000 GPIO-Based I2C Interface (DEPRECATED)"
- depends on ARCH_IXP2000
+ config I2C_SIS5595
+ tristate "SiS 5595"
+ depends on PCI
+ help
+ If you say yes to this option, support will be included for the
+ SiS5595 SMBus (a subset of I2C) interface.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-sis5595.
+
+ config I2C_SIS630
+ tristate "SiS 630/730"
+ depends on PCI
+ help
+ If you say yes to this option, support will be included for the
+ SiS630 and SiS730 SMBus (a subset of I2C) interface.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-sis630.
+
+ config I2C_SIS96X
+ tristate "SiS 96x"
+ depends on PCI
+ help
+ If you say yes to this option, support will be included for the SiS
+ 96x SMBus (a subset of I2C) interfaces. Specifically, the following
+ chipsets are supported:
+ 645/961
+ 645DX/961
+ 645DX/962
+ 648/961
+ 650/961
+ 735
+ 745
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-sis96x.
+
+ config I2C_VIA
+ tristate "VIA VT82C586B"
+ depends on PCI && EXPERIMENTAL
select I2C_ALGOBIT
help
- Say Y here if you have an Intel IXP2000 (2400, 2800, 2850) based
- system and are using GPIO lines for an I2C bus.
+ If you say yes to this option, support will be included for the VIA
+ 82C586B I2C interface
- This support is also available as a module. If so, the module
- will be called i2c-ixp2000.
+ This driver can also be built as a module. If so, the module
+ will be called i2c-via.
- This driver is deprecated and will be dropped soon. Use i2c-gpio
- instead.
+ config I2C_VIAPRO
+ tristate "VIA VT82C596/82C686/82xx and CX700"
+ depends on PCI
+ help
+ If you say yes to this option, support will be included for the VIA
+ VT82C596 and later SMBus interface. Specifically, the following
+ chipsets are supported:
+ VT82C596A/B
+ VT82C686A/B
+ VT8231
+ VT8233/A
+ VT8235
+ VT8237R/A/S
+ VT8251
+ CX700
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-viapro.
+
+ comment "Mac SMBus host controller drivers"
+ depends on PPC_CHRP || PPC_PMAC
+
+ config I2C_HYDRA
+ tristate "CHRP Apple Hydra Mac I/O I2C interface"
+ depends on PCI && PPC_CHRP && EXPERIMENTAL
+ select I2C_ALGOBIT
+ help
+ This supports the use of the I2C interface in the Apple Hydra Mac
+ I/O chip on some CHRP machines (e.g. the LongTrail). Say Y if you
+ have such a machine.
+
+ This support is also available as a module. If so, the module
+ will be called i2c-hydra.
config I2C_POWERMAC
tristate "Powermac I2C interface"
This support is also available as a module. If so, the module
will be called i2c-powermac.
- config I2C_MPC
- tristate "MPC107/824x/85xx/52xx/86xx"
- depends on PPC32
+ comment "I2C system bus drivers (mostly embedded / system-on-chip)"
+
+ config I2C_AT91
+ tristate "Atmel AT91 I2C Two-Wire interface (TWI)"
+ depends on ARCH_AT91 && EXPERIMENTAL && BROKEN
help
- If you say yes to this option, support will be included for the
- built-in I2C interface on the MPC107/Tsi107/MPC8240/MPC8245 and
- MPC85xx/MPC8641 family processors. The driver may also work on 52xx
- family processors, though interrupts are known not to work.
+ This supports the use of the I2C interface on Atmel AT91
+ processors.
- This driver can also be built as a module. If so, the module
- will be called i2c-mpc.
+ This driver is BROKEN because the controller which it uses
+ will easily trigger RX overrun and TX underrun errors. Using
+ low I2C clock rates may partially work around those issues
+ on some systems. Another serious problem is that there is no
+ documented way to issue repeated START conditions, as needed
+ to support combined I2C messages. Use the i2c-gpio driver
+ unless your system can cope with those limitations.
- config I2C_NFORCE2
- tristate "Nvidia nForce2, nForce3 and nForce4"
- depends on PCI
+ config I2C_AU1550
+ tristate "Au1550/Au1200 SMBus interface"
+ depends on SOC_AU1550 || SOC_AU1200
help
- If you say yes to this option, support will be included for the Nvidia
- nForce2, nForce3 and nForce4 families of mainboard I2C interfaces.
+ If you say yes to this option, support will be included for the
+ Au1550 and Au1200 SMBus interface.
This driver can also be built as a module. If so, the module
- will be called i2c-nforce2.
+ will be called i2c-au1550.
- config I2C_OCORES
- tristate "OpenCores I2C Controller"
- depends on EXPERIMENTAL
+ config I2C_BLACKFIN_TWI
+ tristate "Blackfin TWI I2C support"
+ depends on BLACKFIN
+ depends on !BF561 && !BF531 && !BF532 && !BF533
help
- If you say yes to this option, support will be included for the
- OpenCores I2C controller. For details see
- http://www.opencores.org/projects.cgi/web/i2c/overview
+ This is the I2C bus driver for Blackfin on-chip TWI interface.
This driver can also be built as a module. If so, the module
- will be called i2c-ocores.
+ will be called i2c-bfin-twi.
+
+ config I2C_BLACKFIN_TWI_CLK_KHZ
+ int "Blackfin TWI I2C clock (kHz)"
+ depends on I2C_BLACKFIN_TWI
+ range 10 400
+ default 50
+ help
+ The unit of the TWI clock is kHz.
+
+ config I2C_CPM
+ tristate "Freescale CPM1 or CPM2 (MPC8xx/826x)"
+ depends on (CPM1 || CPM2) && OF_I2C
+ help
+ This supports the use of the I2C interface on Freescale
+ processors with CPM1 or CPM2.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-cpm.
+
+ config I2C_DAVINCI
+ tristate "DaVinci I2C driver"
+ depends on ARCH_DAVINCI
+ help
+ Support for TI DaVinci I2C controller driver.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-davinci.
+
+ Please note that this driver might be needed to bring up other
+ devices such as DaVinci NIC.
+ For details please see http://www.ti.com/davinci
+
+ config I2C_GPIO
+ tristate "GPIO-based bitbanging I2C"
+ depends on GENERIC_GPIO
+ select I2C_ALGOBIT
+ help
+ This is a very simple bitbanging I2C driver utilizing the
+ arch-neutral GPIO API to control the SCL and SDA lines.
+
+ config I2C_IBM_IIC
+ tristate "IBM PPC 4xx on-chip I2C interface"
+ depends on 4xx
+ help
+ Say Y here if you want to use IIC peripheral found on
+ embedded IBM PPC 4xx based systems.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-ibm_iic.
+
+ config I2C_IOP3XX
+ tristate "Intel IOPx3xx and IXP4xx on-chip I2C interface"
+ depends on ARCH_IOP32X || ARCH_IOP33X || ARCH_IXP4XX || ARCH_IOP13XX
+ help
+ Say Y here if you want to use the IIC bus controller on
+ the Intel IOPx3xx I/O Processors or IXP4xx Network Processors.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-iop3xx.
+
+ config I2C_IXP2000
+ tristate "IXP2000 GPIO-Based I2C Interface (DEPRECATED)"
+ depends on ARCH_IXP2000
+ select I2C_ALGOBIT
+ help
+ Say Y here if you have an Intel IXP2000 (2400, 2800, 2850) based
+ system and are using GPIO lines for an I2C bus.
+
+ This support is also available as a module. If so, the module
+ will be called i2c-ixp2000.
+
+ This driver is deprecated and will be dropped soon. Use i2c-gpio
+ instead.
+
+ config I2C_MPC
+ tristate "MPC107/824x/85xx/52xx/86xx"
+ depends on PPC32
+ help
+ If you say yes to this option, support will be included for the
+ built-in I2C interface on the MPC107/Tsi107/MPC8240/MPC8245 and
+ MPC85xx/MPC8641 family processors. The driver may also work on 52xx
+ family processors, though interrupts are known not to work.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-mpc.
+
+ config I2C_MV64XXX
+ tristate "Marvell mv64xxx I2C Controller"
+ depends on (MV64X60 || PLAT_ORION) && EXPERIMENTAL
+ help
+ If you say yes to this option, support will be included for the
+ built-in I2C interface on the Marvell 64xxx line of host bridges.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-mv64xxx.
+
+ config I2C_OCORES
+ tristate "OpenCores I2C Controller"
+ depends on EXPERIMENTAL
+ help
+ If you say yes to this option, support will be included for the
+ OpenCores I2C controller. For details see
+ http://www.opencores.org/projects.cgi/web/i2c/overview
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-ocores.
config I2C_OMAP
tristate "OMAP I2C adapter"
default y if MACH_OMAP_H3 || MACH_OMAP_OSK
help
If you say yes to this option, support will be included for the
- I2C interface on the Texas Instruments OMAP1/2 family of processors.
- Like OMAP1510/1610/1710/5912 and OMAP242x.
+ I2C interface on the Texas Instruments OMAP1/2/3 family of
+ processors.
+ Like OMAP1510/1610/1710/5912, OMAP242x, OMAP34x and OMAP35x.
For details see http://www.ti.com/omap.
-
- config I2C_PARPORT
- tristate "Parallel port adapter"
- depends on PARPORT
- select I2C_ALGOBIT
- help
- This supports parallel port I2C adapters such as the ones made by
- Philips or Velleman, Analog Devices evaluation boards, and more.
- Basically any adapter using the parallel port as an I2C bus with
- no extra chipset is supported by this driver, or could be.
-
- This driver is a replacement for (and was inspired by) an older
- driver named i2c-philips-par. The new driver supports more devices,
- and makes it easier to add support for new devices.
-
- An adapter type parameter is now mandatory. Please read the file
- Documentation/i2c/busses/i2c-parport for details.
-
- Another driver exists, named i2c-parport-light, which doesn't depend
- on the parport driver. This is meant for embedded systems. Don't say
- Y here if you intend to say Y or M there.
-
- This support is also available as a module. If so, the module
- will be called i2c-parport.
-
- config I2C_PARPORT_LIGHT
- tristate "Parallel port adapter (light)"
- select I2C_ALGOBIT
- help
- This supports parallel port I2C adapters such as the ones made by
- Philips or Velleman, Analog Devices evaluation boards, and more.
- Basically any adapter using the parallel port as an I2C bus with
- no extra chipset is supported by this driver, or could be.
-
- This driver is a light version of i2c-parport. It doesn't depend
- on the parport driver, and uses direct I/O access instead. This
- might be preferred on embedded systems where wasting memory for
- the clean but heavy parport handling is not an option. The
- drawback is a reduced portability and the impossibility to
- daisy-chain other parallel port devices.
-
- Don't say Y here if you said Y or M to i2c-parport. Saying M to
- both is possible but both modules should not be loaded at the same
- time.
-
- This support is also available as a module. If so, the module
- will be called i2c-parport-light.
-
+config I2C2_OMAP_BEAGLE
+ bool "Enable I2C2 for OMAP3 BeagleBoard"
+ depends on ARCH_OMAP && MACH_OMAP3_BEAGLE
+ select OMAP_MUX
+ default n
+ help
+ Say Y here if you want to enable I2C bus 2 at OMAP3 based
+ BeagleBoard.
+ I2C2 at BeagleBoard is connected to expansion connector, i.e. unused
+ if nothing is connected to this connector. As internal OMAP3 pull up
+ resistors are not strong enough, enabled but unused I2C2 bus results
+ in error messages (e.g. I2C timeouts). Enable this only if you have
+ something connected to I2C2 at board's expansion connector and this
+ extension has additional pull up resistors for I2C2 bus.
+
config I2C_PASEMI
tristate "PA Semi SMBus interface"
depends on PPC_PASEMI && PCI
help
Supports the PA Semi PWRficient on-chip SMBus interfaces.
- config I2C_PROSAVAGE
- tristate "S3/VIA (Pro)Savage (DEPRECATED)"
- default n
- depends on PCI
- select I2C_ALGOBIT
+ config I2C_PNX
+ tristate "I2C bus support for Philips PNX targets"
+ depends on ARCH_PNX4008
help
- If you say yes to this option, support will be included for the
- I2C bus and DDC bus of the S3VIA embedded Savage4 and ProSavage8
- graphics processors.
- chipsets supported:
- S3/VIA KM266/VT8375 aka ProSavage8
- S3/VIA KM133/VT8365 aka Savage4
+ This driver supports the Philips IP3204 I2C IP block master and/or
+ slave controller
- This driver is deprecated in favor of the savagefb driver.
+ This driver can also be built as a module. If so, the module
+ will be called i2c-pnx.
- This support is also available as a module. If so, the module
- will be called i2c-prosavage.
+ config I2C_PXA
+ tristate "Intel PXA2XX I2C adapter (EXPERIMENTAL)"
+ depends on EXPERIMENTAL && ARCH_PXA
+ help
+ If you have devices in the PXA I2C bus, say yes to this option.
+ This driver can also be built as a module. If so, the module
+ will be called i2c-pxa.
+
+ config I2C_PXA_SLAVE
+ bool "Intel PXA2XX I2C Slave comms support"
+ depends on I2C_PXA
+ help
+ Support I2C slave mode communications on the PXA I2C bus. This
+ is necessary for systems where the PXA may be a target on the
+ I2C bus.
config I2C_S3C2410
tristate "S3C2410 I2C Driver"
Say Y here to include support for I2C controller in the
Samsung S3C2410 based System-on-Chip devices.
- config I2C_SAVAGE4
- tristate "S3 Savage 4 (DEPRECATED)"
- default n
- depends on PCI
- select I2C_ALGOBIT
+ config I2C_SH7760
+ tristate "Renesas SH7760 I2C Controller"
+ depends on CPU_SUBTYPE_SH7760
help
- If you say yes to this option, support will be included for the
- S3 Savage 4 I2C interface.
-
- This driver is deprecated in favor of the savagefb driver.
+ This driver supports the 2 I2C interfaces on the Renesas SH7760.
This driver can also be built as a module. If so, the module
- will be called i2c-savage4.
+ will be called i2c-sh7760.
- config I2C_SIBYTE
- tristate "SiByte SMBus interface"
- depends on SIBYTE_SB1xxx_SOC
+ config I2C_SH_MOBILE
+ tristate "SuperH Mobile I2C Controller"
+ depends on SUPERH
help
- Supports the SiByte SOC on-chip I2C interfaces (2 channels).
+ If you say yes to this option, support will be included for the
+ built-in I2C interface on the Renesas SH-Mobile processor.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-sh_mobile.
config I2C_SIMTEC
tristate "Simtec Generic I2C interface"
This driver can also be built as a module. If so, the module
will be called i2c-simtec.
- config SCx200_I2C
- tristate "NatSemi SCx200 I2C using GPIO pins (DEPRECATED)"
- depends on SCx200_GPIO
+ config I2C_VERSATILE
+ tristate "ARM Versatile/Realview I2C bus support"
+ depends on ARCH_VERSATILE || ARCH_REALVIEW
select I2C_ALGOBIT
help
- Enable the use of two GPIO pins of a SCx200 processor as an I2C bus.
-
- If you don't know what to do here, say N.
+ Say yes if you want to support the I2C serial bus on ARMs Versatile
+ range of platforms.
- This support is also available as a module. If so, the module
- will be called scx200_i2c.
+ This driver can also be built as a module. If so, the module
+ will be called i2c-versatile.
- This driver is deprecated and will be dropped soon. Use i2c-gpio
- (or scx200_acb) instead.
+ comment "External I2C/SMBus adapter drivers"
- config SCx200_I2C_SCL
- int "GPIO pin used for SCL"
- depends on SCx200_I2C
- default "12"
+ config I2C_PARPORT
+ tristate "Parallel port adapter"
+ depends on PARPORT
+ select I2C_ALGOBIT
help
- Enter the GPIO pin number used for the SCL signal. This value can
- also be specified with a module parameter.
+ This supports parallel port I2C adapters such as the ones made by
+ Philips or Velleman, Analog Devices evaluation boards, and more.
+ Basically any adapter using the parallel port as an I2C bus with
+ no extra chipset is supported by this driver, or could be.
- config SCx200_I2C_SDA
- int "GPIO pin used for SDA"
- depends on SCx200_I2C
- default "13"
- help
- Enter the GPIO pin number used for the SSA signal. This value can
- also be specified with a module parameter.
+ This driver is a replacement for (and was inspired by) an older
+ driver named i2c-philips-par. The new driver supports more devices,
+ and makes it easier to add support for new devices.
- config SCx200_ACB
- tristate "Geode ACCESS.bus support"
- depends on X86_32 && PCI
- help
- Enable the use of the ACCESS.bus controllers on the Geode SCx200 and
- SC1100 processors and the CS5535 and CS5536 Geode companion devices.
+ An adapter type parameter is now mandatory. Please read the file
+ Documentation/i2c/busses/i2c-parport for details.
- If you don't know what to do here, say N.
+ Another driver exists, named i2c-parport-light, which doesn't depend
+ on the parport driver. This is meant for embedded systems. Don't say
+ Y here if you intend to say Y or M there.
This support is also available as a module. If so, the module
- will be called scx200_acb.
-
- config I2C_SIS5595
- tristate "SiS 5595"
- depends on PCI
- help
- If you say yes to this option, support will be included for the
- SiS5595 SMBus (a subset of I2C) interface.
-
- This driver can also be built as a module. If so, the module
- will be called i2c-sis5595.
+ will be called i2c-parport.
- config I2C_SIS630
- tristate "SiS 630/730"
- depends on PCI
+ config I2C_PARPORT_LIGHT
+ tristate "Parallel port adapter (light)"
+ select I2C_ALGOBIT
help
- If you say yes to this option, support will be included for the
- SiS630 and SiS730 SMBus (a subset of I2C) interface.
+ This supports parallel port I2C adapters such as the ones made by
+ Philips or Velleman, Analog Devices evaluation boards, and more.
+ Basically any adapter using the parallel port as an I2C bus with
+ no extra chipset is supported by this driver, or could be.
- This driver can also be built as a module. If so, the module
- will be called i2c-sis630.
+ This driver is a light version of i2c-parport. It doesn't depend
+ on the parport driver, and uses direct I/O access instead. This
+ might be preferred on embedded systems where wasting memory for
+ the clean but heavy parport handling is not an option. The
+ drawback is a reduced portability and the impossibility to
+ daisy-chain other parallel port devices.
- config I2C_SIS96X
- tristate "SiS 96x"
- depends on PCI
- help
- If you say yes to this option, support will be included for the SiS
- 96x SMBus (a subset of I2C) interfaces. Specifically, the following
- chipsets are supported:
- 645/961
- 645DX/961
- 645DX/962
- 648/961
- 650/961
- 735
- 745
+ Don't say Y here if you said Y or M to i2c-parport. Saying M to
+ both is possible but both modules should not be loaded at the same
+ time.
- This driver can also be built as a module. If so, the module
- will be called i2c-sis96x.
+ This support is also available as a module. If so, the module
+ will be called i2c-parport-light.
config I2C_TAOS_EVM
tristate "TAOS evaluation module"
This support is also available as a module. If so, the module
will be called i2c-taos-evm.
- config I2C_STUB
- tristate "I2C/SMBus Test Stub"
- depends on EXPERIMENTAL && m
- default 'n'
- help
- This module may be useful to developers of SMBus client drivers,
- especially for certain kinds of sensor chips.
-
- If you do build this module, be sure to read the notes and warnings
- in <file:Documentation/i2c/i2c-stub>.
-
- If you don't know what to do here, definitely say N.
-
config I2C_TINY_USB
- tristate "I2C-Tiny-USB"
+ tristate "Tiny-USB adapter"
depends on USB
help
If you say yes to this option, support will be included for the
This driver can also be built as a module. If so, the module
will be called i2c-tiny-usb.
- config I2C_VERSATILE
- tristate "ARM Versatile/Realview I2C bus support"
- depends on ARCH_VERSATILE || ARCH_REALVIEW
+ comment "Graphics adapter I2C/DDC channel drivers"
+ depends on PCI
+
+ config I2C_VOODOO3
+ tristate "Voodoo 3"
+ depends on PCI
select I2C_ALGOBIT
help
- Say yes if you want to support the I2C serial bus on ARMs Versatile
- range of platforms.
+ If you say yes to this option, support will be included for the
+ Voodoo 3 I2C interface.
This driver can also be built as a module. If so, the module
- will be called i2c-versatile.
+ will be called i2c-voodoo3.
+
+ comment "Other I2C/SMBus bus drivers"
config I2C_ACORN
tristate "Acorn IOC/IOMD I2C bus support"
If you don't know, say Y.
- config I2C_VIA
- tristate "VIA 82C586B"
- depends on PCI && EXPERIMENTAL
- select I2C_ALGOBIT
- help
- If you say yes to this option, support will be included for the VIA
- 82C586B I2C interface
-
- This driver can also be built as a module. If so, the module
- will be called i2c-via.
-
- config I2C_VIAPRO
- tristate "VIA VT82C596/82C686/82xx and CX700"
- depends on PCI
- help
- If you say yes to this option, support will be included for the VIA
- VT82C596 and later SMBus interface. Specifically, the following
- chipsets are supported:
- VT82C596A/B
- VT82C686A/B
- VT8231
- VT8233/A
- VT8235
- VT8237R/A/S
- VT8251
- CX700
-
- This driver can also be built as a module. If so, the module
- will be called i2c-viapro.
-
- config I2C_VOODOO3
- tristate "Voodoo 3"
- depends on PCI
- select I2C_ALGOBIT
+ config I2C_ELEKTOR
+ tristate "Elektor ISA card"
+ depends on ISA && BROKEN_ON_SMP
+ select I2C_ALGOPCF
help
- If you say yes to this option, support will be included for the
- Voodoo 3 I2C interface.
+ This supports the PCF8584 ISA bus I2C adapter. Say Y if you own
+ such an adapter.
- This driver can also be built as a module. If so, the module
- will be called i2c-voodoo3.
+ This support is also available as a module. If so, the module
+ will be called i2c-elektor.
config I2C_PCA_ISA
tristate "PCA9564 on an ISA bus"
This driver can also be built as a module. If so, the module
will be called i2c-pca-platform.
- config I2C_MV64XXX
- tristate "Marvell mv64xxx I2C Controller"
- depends on (MV64X60 || PLAT_ORION) && EXPERIMENTAL
- help
- If you say yes to this option, support will be included for the
- built-in I2C interface on the Marvell 64xxx line of host bridges.
-
- This driver can also be built as a module. If so, the module
- will be called i2c-mv64xxx.
-
- config I2C_PNX
- tristate "I2C bus support for Philips PNX targets"
- depends on ARCH_PNX4008
- help
- This driver supports the Philips IP3204 I2C IP block master and/or
- slave controller
-
- This driver can also be built as a module. If so, the module
- will be called i2c-pnx.
-
config I2C_PMCMSP
tristate "PMC MSP I2C TWI Controller"
depends on PMC_MSP
This driver can also be built as module. If so, the module
will be called i2c-pmcmsp.
- config I2C_SH7760
- tristate "Renesas SH7760 I2C Controller"
- depends on CPU_SUBTYPE_SH7760
+ config I2C_SIBYTE
+ tristate "SiByte SMBus interface"
+ depends on SIBYTE_SB1xxx_SOC
help
- This driver supports the 2 I2C interfaces on the Renesas SH7760.
+ Supports the SiByte SOC on-chip I2C interfaces (2 channels).
- This driver can also be built as a module. If so, the module
- will be called i2c-sh7760.
+ config I2C_STUB
+ tristate "I2C/SMBus Test Stub"
+ depends on EXPERIMENTAL && m
+ default 'n'
+ help
+ This module may be useful to developers of SMBus client drivers,
+ especially for certain kinds of sensor chips.
- config I2C_SH_MOBILE
- tristate "SuperH Mobile I2C Controller"
- depends on SUPERH
+ If you do build this module, be sure to read the notes and warnings
+ in <file:Documentation/i2c/i2c-stub>.
+
+ If you don't know what to do here, definitely say N.
+
+ config SCx200_I2C
+ tristate "NatSemi SCx200 I2C using GPIO pins (DEPRECATED)"
+ depends on SCx200_GPIO
+ select I2C_ALGOBIT
help
- If you say yes to this option, support will be included for the
- built-in I2C interface on the Renesas SH-Mobile processor.
+ Enable the use of two GPIO pins of a SCx200 processor as an I2C bus.
- This driver can also be built as a module. If so, the module
- will be called i2c-sh_mobile.
+ If you don't know what to do here, say N.
+
+ This support is also available as a module. If so, the module
+ will be called scx200_i2c.
+
+ This driver is deprecated and will be dropped soon. Use i2c-gpio
+ (or scx200_acb) instead.
+
+ config SCx200_I2C_SCL
+ int "GPIO pin used for SCL"
+ depends on SCx200_I2C
+ default "12"
+ help
+ Enter the GPIO pin number used for the SCL signal. This value can
+ also be specified with a module parameter.
+
+ config SCx200_I2C_SDA
+ int "GPIO pin used for SDA"
+ depends on SCx200_I2C
+ default "13"
+ help
+ Enter the GPIO pin number used for the SSA signal. This value can
+ also be specified with a module parameter.
+
+ config SCx200_ACB
+ tristate "Geode ACCESS.bus support"
+ depends on X86_32 && PCI
+ help
+ Enable the use of the ACCESS.bus controllers on the Geode SCx200 and
+ SC1100 processors and the CS5535 and CS5536 Geode companion devices.
+
+ If you don't know what to do here, say N.
+
+ This support is also available as a module. If so, the module
+ will be called scx200_acb.
endmenu
# Makefile for the i2c bus drivers.
#
+ # PC SMBus host controller drivers
obj-$(CONFIG_I2C_ALI1535) += i2c-ali1535.o
obj-$(CONFIG_I2C_ALI1563) += i2c-ali1563.o
obj-$(CONFIG_I2C_ALI15X3) += i2c-ali15x3.o
obj-$(CONFIG_I2C_AMD756) += i2c-amd756.o
obj-$(CONFIG_I2C_AMD756_S4882) += i2c-amd756-s4882.o
obj-$(CONFIG_I2C_AMD8111) += i2c-amd8111.o
+ obj-$(CONFIG_I2C_I801) += i2c-i801.o
+ obj-$(CONFIG_I2C_ISCH) += i2c-isch.o
+ obj-$(CONFIG_I2C_NFORCE2) += i2c-nforce2.o
+ obj-$(CONFIG_I2C_NFORCE2_S4985) += i2c-nforce2-s4985.o
+ obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o
+ obj-$(CONFIG_I2C_SIS5595) += i2c-sis5595.o
+ obj-$(CONFIG_I2C_SIS630) += i2c-sis630.o
+ obj-$(CONFIG_I2C_SIS96X) += i2c-sis96x.o
+ obj-$(CONFIG_I2C_VIA) += i2c-via.o
+ obj-$(CONFIG_I2C_VIAPRO) += i2c-viapro.o
+
+ # Mac SMBus host controller drivers
+ obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o
+ obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o
+
+ # Embebbed system I2C/SMBus host controller drivers
obj-$(CONFIG_I2C_AT91) += i2c-at91.o
obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o
obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o
+ obj-$(CONFIG_I2C_CPM) += i2c-cpm.o
obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o
- obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o
obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o
- obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o
- obj-$(CONFIG_I2C_I801) += i2c-i801.o
- obj-$(CONFIG_I2C_I810) += i2c-i810.o
obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o
obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o
obj-$(CONFIG_I2C_IXP2000) += i2c-ixp2000.o
- obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o
obj-$(CONFIG_I2C_MPC) += i2c-mpc.o
obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o
- obj-$(CONFIG_I2C_NFORCE2) += i2c-nforce2.o
obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o
obj-$(CONFIG_I2C_OMAP) += i2c-omap.o
- obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o
- obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o
obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi.o
- obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o
- obj-$(CONFIG_I2C_PCA_PLATFORM) += i2c-pca-platform.o
- obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o
- obj-$(CONFIG_I2C_PMCMSP) += i2c-pmcmsp.o
obj-$(CONFIG_I2C_PNX) += i2c-pnx.o
- obj-$(CONFIG_I2C_PROSAVAGE) += i2c-prosavage.o
obj-$(CONFIG_I2C_PXA) += i2c-pxa.o
obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o
- obj-$(CONFIG_I2C_SAVAGE4) += i2c-savage4.o
obj-$(CONFIG_I2C_SH7760) += i2c-sh7760.o
obj-$(CONFIG_I2C_SH_MOBILE) += i2c-sh_mobile.o
- obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o
obj-$(CONFIG_I2C_SIMTEC) += i2c-simtec.o
- obj-$(CONFIG_I2C_SIS5595) += i2c-sis5595.o
- obj-$(CONFIG_I2C_SIS630) += i2c-sis630.o
- obj-$(CONFIG_I2C_SIS96X) += i2c-sis96x.o
- obj-$(CONFIG_I2C_STUB) += i2c-stub.o
+ obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o
+
+ # External I2C/SMBus adapter drivers
+ obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o
+ obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o
obj-$(CONFIG_I2C_TAOS_EVM) += i2c-taos-evm.o
obj-$(CONFIG_I2C_TINY_USB) += i2c-tiny-usb.o
- obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o
- obj-$(CONFIG_I2C_ACORN) += i2c-acorn.o
- obj-$(CONFIG_I2C_VIA) += i2c-via.o
- obj-$(CONFIG_I2C_VIAPRO) += i2c-viapro.o
+
+ # Graphics adapter I2C/DDC channel drivers
obj-$(CONFIG_I2C_VOODOO3) += i2c-voodoo3.o
+
+ # Other I2C/SMBus bus drivers
+ obj-$(CONFIG_I2C_ACORN) += i2c-acorn.o
+ obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o
+ obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o
+ obj-$(CONFIG_I2C_PCA_PLATFORM) += i2c-pca-platform.o
+ obj-$(CONFIG_I2C_PMCMSP) += i2c-pmcmsp.o
+ obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o
+ obj-$(CONFIG_I2C_STUB) += i2c-stub.o
obj-$(CONFIG_SCx200_ACB) += scx200_acb.o
obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o
+obj-$(CONFIG_I2C_OMAP) += i2c-omap.o
ifeq ($(CONFIG_I2C_DEBUG_BUS),y)
EXTRA_CFLAGS += -DDEBUG
This driver can also be built as a module. If so, the module
will be called ds1682.
+ config AT24
+ tristate "EEPROMs from most vendors"
+ depends on SYSFS && EXPERIMENTAL
+ help
+ Enable this driver to get read/write support to most I2C EEPROMs,
+ after you configure the driver to know about each EEPROM on
+ your target board. Use these generic chip names, instead of
+ vendor-specific ones like at24c64 or 24lc02:
+
+ 24c00, 24c01, 24c02, spd (readonly 24c02), 24c04, 24c08,
+ 24c16, 24c32, 24c64, 24c128, 24c256, 24c512, 24c1024
+
+ Unless you like data loss puzzles, always be sure that any chip
+ you configure as a 24c32 (32 kbit) or larger is NOT really a
+ 24c16 (16 kbit) or smaller, and vice versa. Marking the chip
+ as read-only won't help recover from this. Also, if your chip
+ has any software write-protect mechanism you may want to review the
+ code to make sure this driver won't turn it on by accident.
+
+ If you use this with an SMBus adapter instead of an I2C adapter,
+ full functionality is not available. Only smaller devices are
+ supported (24c16 and below, max 4 kByte).
+
+ This driver can also be built as a module. If so, the module
+ will be called at24.
+
config SENSORS_EEPROM
tristate "EEPROM reader"
depends on EXPERIMENTAL
will be called eeprom.
config SENSORS_PCF8574
- tristate "Philips PCF8574 and PCF8574A"
- depends on EXPERIMENTAL
+ tristate "Philips PCF8574 and PCF8574A (DEPRECATED)"
+ depends on EXPERIMENTAL && GPIO_PCF857X = "n"
default n
help
If you say yes here you get support for Philips PCF8574 and
This driver can also be built as a module. If so, the module
will be called pcf8574.
+ This driver is deprecated and will be dropped soon. Use
+ drivers/gpio/pcf857x.c instead.
+
These devices are hard to detect and rarely found on mainstream
hardware. If unsure, say N.
config PCF8575
- tristate "Philips PCF8575"
+ tristate "Philips PCF8575 (DEPRECATED)"
default n
+ depends on GPIO_PCF857X = "n"
help
If you say yes here you get support for Philips PCF8575 chip.
This chip is a 16-bit I/O expander for the I2C bus. Several other
This driver can also be built as a module. If so, the module
will be called pcf8575.
+ This driver is deprecated and will be dropped soon. Use
+ drivers/gpio/pcf857x.c instead.
+
This device is hard to detect and is rarely found on mainstream
hardware. If unsure, say N.
config SENSORS_PCA9539
tristate "Philips PCA9539 16-bit I/O port (DEPRECATED)"
- depends on EXPERIMENTAL && GPIO_PCA9539 = "n"
+ depends on EXPERIMENTAL && GPIO_PCA953X = "n"
help
If you say yes here you get support for the Philips PCA9539
16-bit I/O port.
will be called pca9539.
This driver is deprecated and will be dropped soon. Use
- drivers/gpio/pca9539.c instead.
+ drivers/gpio/pca953x.c instead.
config SENSORS_PCF8591
tristate "Philips PCF8591"
config TPS65010
tristate "TPS6501x Power Management chips"
- depends on HAVE_GPIO_LIB
+ depends on GPIOLIB
default y if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_OSK
help
If you say yes here you get support for the TPS6501x series of
This driver can also be built as a module. If so, the module
will be called tps65010.
+config SENSORS_TLV320AIC23
+ tristate "Texas Instruments TLV320AIC23 Codec"
+ depends on I2C && I2C_OMAP
+ help
+ If you say yes here you get support for the I2C control
+ interface for Texas Instruments TLV320AIC23 audio codec.
+
+config GPIOEXPANDER_OMAP
+ bool "GPIO Expander PCF8574PWR for OMAP"
+ depends on I2C && (ARCH_OMAP16XX || ARCH_OMAP24XX)
+ help
+ If you say yes here you get support for I/O expander calls
+ to configure IrDA, Camera and audio devices.
+
+config TWL4030_CORE
+ bool "TI's TWL4030 companion chip Core Driver Support"
+ depends on I2C=y && (ARCH_OMAP24XX || ARCH_OMAP34XX)
+ help
+ Say yes here if you have TWL4030 chip on your board
+
+config TWL4030_GPIO
+ bool "TWL4030 GPIO Driver"
+ depends on TWL4030_CORE
+
+config TWL4030_MADC
+ tristate "TWL4030 MADC Driver"
+ depends on TWL4030_CORE
+ help
+ The TWL4030 Monitoring ADC driver enables the host
+ processor to monitor analog signals using analog-to-digital
+ conversions on the input source. TWL4030 MADC provides the
+ following features:
+ - Single 10-bit ADC with successive approximation register (SAR) conversion;
+ - Analog multiplexer for 16 inputs;
+ - Seven (of the 16) inputs are freely available;
+ - Battery voltage monitoring;
+ - Concurrent conversion request management;
+ - Interrupt signal to Primary Interrupt Handler;
+ - Averaging feature;
+ - Selective enable/disable of the averaging feature.
+
+ Say 'y' here to statically link this module into the kernel or 'm'
+ to build it as a dinamically loadable module. The module will be
+ called twl4030-madc.ko
+
+config TWL4030_USB
+ tristate "TWL4030 USB Transceiver Driver"
+ depends on TWL4030_CORE
+
+choice
+ prompt "Transceiver mode"
+ depends on TWL4030_USB
+ help
+ TWL4030 USB transceiver can operate in various
+ mutually-exclusive modes. Select one of them.
+
+config TWL4030_USB_HS_ULPI
+ depends on TWL4030_USB
+ bool "High-speed ULPI"
+ help
+ Say Y here if the TWL4030 is connected to high-speed USB
+ controller through a ULPI interface.
+
+endchoice
+
+config TWL4030_PWRBUTTON
+ tristate "TWL4030 Power button Driver"
+ depends on TWL4030_CORE
+
+config TWL4030_POWEROFF
+ tristate "TWL4030 device poweroff"
+ depends on TWL4030_CORE
+
config SENSORS_MAX6875
tristate "Maxim MAX6875 Power supply supervisor"
depends on EXPERIMENTAL
This driver can also be built as a module. If so, the module
will be called tsl2550.
+config SENSORS_TSL2563
+ tristate "Taos TSL2563 ambient light sensor"
+ depends on I2C && HWMON
+ help
+ If you say yes here you get support for the Taos TSL2563
+ ambient light sensor.
+
+ This driver can also be built as a module. If so, the module
+ will be called tsl2563.
+
+config LP5521
+ tristate "LP5521 LED driver chip"
+ depends on I2C
+ help
+ If you say yes here you get support for the National Semiconductor
+ LP5521 LED driver.
+
config MENELAUS
bool "TWL92330/Menelaus PM chip"
depends on I2C=y && ARCH_OMAP24XX
#
obj-$(CONFIG_DS1682) += ds1682.o
+ obj-$(CONFIG_AT24) += at24.o
obj-$(CONFIG_SENSORS_EEPROM) += eeprom.o
obj-$(CONFIG_SENSORS_MAX6875) += max6875.o
obj-$(CONFIG_SENSORS_PCA9539) += pca9539.o
obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o
obj-$(CONFIG_TPS65010) += tps65010.o
+obj-$(CONFIG_SENSORS_TLV320AIC23) += tlv320aic23.o
+obj-$(CONFIG_GPIOEXPANDER_OMAP) += gpio_expander_omap.o
obj-$(CONFIG_MENELAUS) += menelaus.o
obj-$(CONFIG_SENSORS_TSL2550) += tsl2550.o
+obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o
+obj-$(CONFIG_TWL4030_CORE) += twl4030-core.o twl4030-pwrirq.o
+obj-$(CONFIG_TWL4030_GPIO) += twl4030-gpio.o
+obj-$(CONFIG_TWL4030_USB) += twl4030-usb.o
+obj-$(CONFIG_TWL4030_POWEROFF) += twl4030-poweroff.o
+obj-$(CONFIG_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o
+obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o
+obj-$(CONFIG_RTC_X1205_I2C) += x1205.o
+obj-$(CONFIG_LP5521) += lp5521.o
ifeq ($(CONFIG_I2C_DEBUG_CHIP),y)
EXTRA_CFLAGS += -DDEBUG
endif
-
--- /dev/null
- set_irq_type(irq_num, IRQT_FALLING);
+/*
+ * twl4030_core.c - driver for TWL4030 PM and audio CODEC device
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * Modifications to defer interrupt handling to a kernel thread:
+ * Copyright (C) 2006 MontaVista Software, Inc.
+ *
+ * Based on tlv320aic23.c:
+ * Copyright (c) by Kai Svahn <kai.svahn@nokia.com>
+ *
+ * Code cleanup and modifications to IRQ handler.
+ * by syed khasim <x0khasim@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/module.h>
+#include <linux/kernel_stat.h>
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <linux/random.h>
+#include <linux/syscalls.h>
+#include <linux/kthread.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c/twl4030.h>
+#include <linux/i2c/twl4030-gpio.h>
+#include <linux/i2c/twl4030-madc.h>
+#include <linux/i2c/twl4030-pwrirq.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/irq.h>
+
+#include <asm/mach/irq.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/mux.h>
+
+#define DRIVER_NAME "twl4030"
+
+/* Macro Definitions */
+#define TWL_CLIENT_STRING "TWL4030-ID"
+#define TWL_CLIENT_USED 1
+#define TWL_CLIENT_FREE 0
+
+/* IRQ Flags */
+#define FREE 0
+#define USED 1
+
+/* Primary Interrupt Handler on TWL4030 Registers */
+
+/* Register Definitions */
+
+#define REG_PIH_ISR_P1 (0x1)
+#define REG_PIH_ISR_P2 (0x2)
+#define REG_PIH_SIR (0x3)
+
+/* Triton Core internal information (BEGIN) */
+
+/* Last - for index max*/
+#define TWL4030_MODULE_LAST TWL4030_MODULE_SECURED_REG
+
+/* Slave address */
+#define TWL4030_NUM_SLAVES 0x04
+#define TWL4030_SLAVENUM_NUM0 0x00
+#define TWL4030_SLAVENUM_NUM1 0x01
+#define TWL4030_SLAVENUM_NUM2 0x02
+#define TWL4030_SLAVENUM_NUM3 0x03
+#define TWL4030_SLAVEID_ID0 0x48
+#define TWL4030_SLAVEID_ID1 0x49
+#define TWL4030_SLAVEID_ID2 0x4A
+#define TWL4030_SLAVEID_ID3 0x4B
+
+/* Base Address defns */
+/* USB ID */
+#define TWL4030_BASEADD_USB 0x0000
+/* AUD ID */
+#define TWL4030_BASEADD_AUDIO_VOICE 0x0000
+#define TWL4030_BASEADD_GPIO 0x0098
+
+#define TWL4030_BASEADD_INTBR 0x0085
+#define TWL4030_BASEADD_PIH 0x0080
+#define TWL4030_BASEADD_TEST 0x004C
+/* AUX ID */
+#define TWL4030_BASEADD_INTERRUPTS 0x00B9
+#define TWL4030_BASEADD_LED 0x00EE
+#define TWL4030_BASEADD_MADC 0x0000
+#define TWL4030_BASEADD_MAIN_CHARGE 0x0074
+#define TWL4030_BASEADD_PRECHARGE 0x00AA
+#define TWL4030_BASEADD_PWM0 0x00F8
+#define TWL4030_BASEADD_PWM1 0x00FB
+#define TWL4030_BASEADD_PWMA 0x00EF
+#define TWL4030_BASEADD_PWMB 0x00F1
+#define TWL4030_BASEADD_KEYPAD 0x00D2
+/* POWER ID */
+#define TWL4030_BASEADD_BACKUP 0x0014
+#define TWL4030_BASEADD_INT 0x002E
+#define TWL4030_BASEADD_PM_MASTER 0x0036
+#define TWL4030_BASEADD_PM_RECEIVER 0x005B
+#define TWL4030_BASEADD_RTC 0x001C
+#define TWL4030_BASEADD_SECURED_REG 0x0000
+
+/* TWL4030 BCI registers */
+#define TWL4030_INTERRUPTS_BCIIMR1A 0x2
+#define TWL4030_INTERRUPTS_BCIIMR2A 0x3
+#define TWL4030_INTERRUPTS_BCIIMR1B 0x6
+#define TWL4030_INTERRUPTS_BCIIMR2B 0x7
+#define TWL4030_INTERRUPTS_BCIISR1A 0x0
+#define TWL4030_INTERRUPTS_BCIISR2A 0x1
+#define TWL4030_INTERRUPTS_BCIISR1B 0x4
+#define TWL4030_INTERRUPTS_BCIISR2B 0x5
+
+/* TWL4030 keypad registers */
+#define TWL4030_KEYPAD_KEYP_IMR1 0x12
+#define TWL4030_KEYPAD_KEYP_IMR2 0x14
+#define TWL4030_KEYPAD_KEYP_ISR1 0x11
+#define TWL4030_KEYPAD_KEYP_ISR2 0x13
+
+
+/* Triton Core internal information (END) */
+
+/* Few power values */
+#define R_CFG_BOOT 0x05
+#define R_PROTECT_KEY 0x0E
+
+/* access control */
+#define KEY_UNLOCK1 0xce
+#define KEY_UNLOCK2 0xec
+#define KEY_LOCK 0x00
+
+#define HFCLK_FREQ_19p2_MHZ (1 << 0)
+#define HFCLK_FREQ_26_MHZ (2 << 0)
+#define HFCLK_FREQ_38p4_MHZ (3 << 0)
+#define HIGH_PERF_SQ (1 << 3)
+
+/* on I2C-1 for 2430SDP */
+#define CONFIG_I2C_TWL4030_ID 1
+
+/* SIH_CTRL registers that aren't defined elsewhere */
+#define TWL4030_INTERRUPTS_BCISIHCTRL 0x0d
+#define TWL4030_MADC_MADC_SIH_CTRL 0x67
+#define TWL4030_KEYPAD_KEYP_SIH_CTRL 0x17
+
+#define TWL4030_SIH_CTRL_COR_MASK (1 << 2)
+
+/**
+ * struct twl4030_mod_iregs - TWL module IMR/ISR regs to mask/clear at init
+ * @mod_no: TWL4030 module number (e.g., TWL4030_MODULE_GPIO)
+ * @sih_ctrl: address of module SIH_CTRL register
+ * @reg_cnt: number of IMR/ISR regs
+ * @imrs: pointer to array of TWL module interrupt mask register indices
+ * @isrs: pointer to array of TWL module interrupt status register indices
+ *
+ * Ties together TWL4030 modules and lists of IMR/ISR registers to mask/clear
+ * during twl_init_irq().
+ */
+struct twl4030_mod_iregs {
+ const u8 mod_no;
+ const u8 sih_ctrl;
+ const u8 reg_cnt;
+ const u8 *imrs;
+ const u8 *isrs;
+};
+
+/* TWL4030 INT module interrupt mask registers */
+static const u8 __initconst twl4030_int_imr_regs[] = {
+ TWL4030_INT_PWR_IMR1,
+ TWL4030_INT_PWR_IMR2,
+};
+
+/* TWL4030 INT module interrupt status registers */
+static const u8 __initconst twl4030_int_isr_regs[] = {
+ TWL4030_INT_PWR_ISR1,
+ TWL4030_INT_PWR_ISR2,
+};
+
+/* TWL4030 INTERRUPTS module interrupt mask registers */
+static const u8 __initconst twl4030_interrupts_imr_regs[] = {
+ TWL4030_INTERRUPTS_BCIIMR1A,
+ TWL4030_INTERRUPTS_BCIIMR1B,
+ TWL4030_INTERRUPTS_BCIIMR2A,
+ TWL4030_INTERRUPTS_BCIIMR2B,
+};
+
+/* TWL4030 INTERRUPTS module interrupt status registers */
+static const u8 __initconst twl4030_interrupts_isr_regs[] = {
+ TWL4030_INTERRUPTS_BCIISR1A,
+ TWL4030_INTERRUPTS_BCIISR1B,
+ TWL4030_INTERRUPTS_BCIISR2A,
+ TWL4030_INTERRUPTS_BCIISR2B,
+};
+
+/* TWL4030 MADC module interrupt mask registers */
+static const u8 __initconst twl4030_madc_imr_regs[] = {
+ TWL4030_MADC_IMR1,
+ TWL4030_MADC_IMR2,
+};
+
+/* TWL4030 MADC module interrupt status registers */
+static const u8 __initconst twl4030_madc_isr_regs[] = {
+ TWL4030_MADC_ISR1,
+ TWL4030_MADC_ISR2,
+};
+
+/* TWL4030 keypad module interrupt mask registers */
+static const u8 __initconst twl4030_keypad_imr_regs[] = {
+ TWL4030_KEYPAD_KEYP_IMR1,
+ TWL4030_KEYPAD_KEYP_IMR2,
+};
+
+/* TWL4030 keypad module interrupt status registers */
+static const u8 __initconst twl4030_keypad_isr_regs[] = {
+ TWL4030_KEYPAD_KEYP_ISR1,
+ TWL4030_KEYPAD_KEYP_ISR2,
+};
+
+/* TWL4030 GPIO module interrupt mask registers */
+static const u8 __initconst twl4030_gpio_imr_regs[] = {
+ REG_GPIO_IMR1A,
+ REG_GPIO_IMR1B,
+ REG_GPIO_IMR2A,
+ REG_GPIO_IMR2B,
+ REG_GPIO_IMR3A,
+ REG_GPIO_IMR3B,
+};
+
+/* TWL4030 GPIO module interrupt status registers */
+static const u8 __initconst twl4030_gpio_isr_regs[] = {
+ REG_GPIO_ISR1A,
+ REG_GPIO_ISR1B,
+ REG_GPIO_ISR2A,
+ REG_GPIO_ISR2B,
+ REG_GPIO_ISR3A,
+ REG_GPIO_ISR3B,
+};
+
+/* TWL4030 modules that have IMR/ISR registers that must be masked/cleared */
+static const struct twl4030_mod_iregs __initconst twl4030_mod_regs[] = {
+ {
+ .mod_no = TWL4030_MODULE_INT,
+ .sih_ctrl = TWL4030_INT_PWR_SIH_CTRL,
+ .reg_cnt = ARRAY_SIZE(twl4030_int_imr_regs),
+ .imrs = twl4030_int_imr_regs,
+ .isrs = twl4030_int_isr_regs,
+ },
+ {
+ .mod_no = TWL4030_MODULE_INTERRUPTS,
+ .sih_ctrl = TWL4030_INTERRUPTS_BCISIHCTRL,
+ .reg_cnt = ARRAY_SIZE(twl4030_interrupts_imr_regs),
+ .imrs = twl4030_interrupts_imr_regs,
+ .isrs = twl4030_interrupts_isr_regs,
+ },
+ {
+ .mod_no = TWL4030_MODULE_MADC,
+ .sih_ctrl = TWL4030_MADC_MADC_SIH_CTRL,
+ .reg_cnt = ARRAY_SIZE(twl4030_madc_imr_regs),
+ .imrs = twl4030_madc_imr_regs,
+ .isrs = twl4030_madc_isr_regs,
+ },
+ {
+ .mod_no = TWL4030_MODULE_KEYPAD,
+ .sih_ctrl = TWL4030_KEYPAD_KEYP_SIH_CTRL,
+ .reg_cnt = ARRAY_SIZE(twl4030_keypad_imr_regs),
+ .imrs = twl4030_keypad_imr_regs,
+ .isrs = twl4030_keypad_isr_regs,
+ },
+ {
+ .mod_no = TWL4030_MODULE_GPIO,
+ .sih_ctrl = REG_GPIO_SIH_CTRL,
+ .reg_cnt = ARRAY_SIZE(twl4030_gpio_imr_regs),
+ .imrs = twl4030_gpio_imr_regs,
+ .isrs = twl4030_gpio_isr_regs,
+ },
+};
+
+
+/* Helper functions */
+static int
+twl4030_detect_client(struct i2c_adapter *adapter, unsigned char sid);
+static int twl4030_attach_adapter(struct i2c_adapter *adapter);
+static int twl4030_detach_client(struct i2c_client *client);
+static void do_twl4030_irq(unsigned int irq, irq_desc_t *desc);
+
+static void twl_init_irq(void);
+
+/* Data Structures */
+/* To have info on T2 IRQ substem activated or not */
+static unsigned char twl_irq_used = FREE;
+static struct completion irq_event;
+
+/* Structure to define on TWL4030 Slave ID */
+struct twl4030_client {
+ struct i2c_client client;
+ const char client_name[sizeof(TWL_CLIENT_STRING) + 1];
+ const unsigned char address;
+ const char adapter_index;
+ unsigned char inuse;
+
+ /* max numb of i2c_msg required is for read =2 */
+ struct i2c_msg xfer_msg[2];
+
+ /* To lock access to xfer_msg */
+ struct mutex xfer_lock;
+};
+
+/* Module Mapping */
+struct twl4030mapping {
+ unsigned char sid; /* Slave ID */
+ unsigned char base; /* base address */
+};
+
+/* mapping the module id to slave id and base address */
+static struct twl4030mapping twl4030_map[TWL4030_MODULE_LAST + 1] = {
+ { TWL4030_SLAVENUM_NUM0, TWL4030_BASEADD_USB },
+ { TWL4030_SLAVENUM_NUM1, TWL4030_BASEADD_AUDIO_VOICE },
+ { TWL4030_SLAVENUM_NUM1, TWL4030_BASEADD_GPIO },
+ { TWL4030_SLAVENUM_NUM1, TWL4030_BASEADD_INTBR },
+ { TWL4030_SLAVENUM_NUM1, TWL4030_BASEADD_PIH },
+ { TWL4030_SLAVENUM_NUM1, TWL4030_BASEADD_TEST },
+ { TWL4030_SLAVENUM_NUM2, TWL4030_BASEADD_KEYPAD },
+ { TWL4030_SLAVENUM_NUM2, TWL4030_BASEADD_MADC },
+ { TWL4030_SLAVENUM_NUM2, TWL4030_BASEADD_INTERRUPTS },
+ { TWL4030_SLAVENUM_NUM2, TWL4030_BASEADD_LED },
+ { TWL4030_SLAVENUM_NUM2, TWL4030_BASEADD_MAIN_CHARGE },
+ { TWL4030_SLAVENUM_NUM2, TWL4030_BASEADD_PRECHARGE },
+ { TWL4030_SLAVENUM_NUM2, TWL4030_BASEADD_PWM0 },
+ { TWL4030_SLAVENUM_NUM2, TWL4030_BASEADD_PWM1 },
+ { TWL4030_SLAVENUM_NUM2, TWL4030_BASEADD_PWMA },
+ { TWL4030_SLAVENUM_NUM2, TWL4030_BASEADD_PWMB },
+ { TWL4030_SLAVENUM_NUM3, TWL4030_BASEADD_BACKUP },
+ { TWL4030_SLAVENUM_NUM3, TWL4030_BASEADD_INT },
+ { TWL4030_SLAVENUM_NUM3, TWL4030_BASEADD_PM_MASTER },
+ { TWL4030_SLAVENUM_NUM3, TWL4030_BASEADD_PM_RECEIVER },
+ { TWL4030_SLAVENUM_NUM3, TWL4030_BASEADD_RTC },
+ { TWL4030_SLAVENUM_NUM3, TWL4030_BASEADD_SECURED_REG },
+};
+
+static struct twl4030_client twl4030_modules[TWL4030_NUM_SLAVES] = {
+ {
+ .address = TWL4030_SLAVEID_ID0,
+ .client_name = TWL_CLIENT_STRING "0",
+ .adapter_index = CONFIG_I2C_TWL4030_ID,
+ },
+ {
+ .address = TWL4030_SLAVEID_ID1,
+ .client_name = TWL_CLIENT_STRING "1",
+ .adapter_index = CONFIG_I2C_TWL4030_ID,
+ },
+ {
+ .address = TWL4030_SLAVEID_ID2,
+ .client_name = TWL_CLIENT_STRING "2",
+ .adapter_index = CONFIG_I2C_TWL4030_ID,
+ },
+ {
+ .address = TWL4030_SLAVEID_ID3,
+ .client_name = TWL_CLIENT_STRING "3",
+ .adapter_index = CONFIG_I2C_TWL4030_ID,
+ },
+};
+
+/* One Client Driver , 4 Clients */
+static struct i2c_driver twl4030_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+ .attach_adapter = twl4030_attach_adapter,
+ .detach_client = twl4030_detach_client,
+};
+
+/*
+ * TWL4030 doesn't have PIH mask, hence dummy function for mask
+ * and unmask.
+ */
+
+static void twl4030_i2c_ackirq(unsigned int irq) {}
+static void twl4030_i2c_disableint(unsigned int irq) {}
+static void twl4030_i2c_enableint(unsigned int irq) {}
+
+/* information for processing in the Work Item */
+static struct irq_chip twl4030_irq_chip = {
+ .name = "twl4030",
+ .ack = twl4030_i2c_ackirq,
+ .mask = twl4030_i2c_disableint,
+ .unmask = twl4030_i2c_enableint,
+};
+
+/* Global Functions */
+
+/**
+ * twl4030_i2c_write - Writes a n bit register in TWL4030
+ * @mod_no: module number
+ * @value: an array of num_bytes+1 containing data to write
+ * @reg: register address (just offset will do)
+ * @num_bytes: number of bytes to transfer
+ *
+ * IMPORTANT: for 'value' parameter: Allocate value num_bytes+1 and
+ * valid data starts at Offset 1.
+ *
+ * Returns the result of operation - 0 is success
+ */
+int twl4030_i2c_write(u8 mod_no, u8 *value, u8 reg, u8 num_bytes)
+{
+ int ret;
+ int sid;
+ struct twl4030_client *twl;
+ struct i2c_msg *msg;
+
+ if (unlikely(mod_no > TWL4030_MODULE_LAST)) {
+ pr_err("Invalid module Number\n");
+ return -EPERM;
+ }
+ sid = twl4030_map[mod_no].sid;
+ twl = &twl4030_modules[sid];
+
+ if (unlikely(twl->inuse != TWL_CLIENT_USED)) {
+ pr_err("I2C Client[%d] is not initialized[%d]\n",
+ sid, __LINE__);
+ return -EPERM;
+ }
+ mutex_lock(&twl->xfer_lock);
+ /*
+ * [MSG1]: fill the register address data
+ * fill the data Tx buffer
+ */
+ msg = &twl->xfer_msg[0];
+ msg->addr = twl->address;
+ msg->len = num_bytes + 1;
+ msg->flags = 0;
+ msg->buf = value;
+ /* over write the first byte of buffer with the register address */
+ *value = twl4030_map[mod_no].base + reg;
+ ret = i2c_transfer(twl->client.adapter, twl->xfer_msg, 1);
+ mutex_unlock(&twl->xfer_lock);
+
+ /* i2cTransfer returns num messages.translate it pls.. */
+ if (ret >= 0)
+ ret = 0;
+ return ret;
+}
+EXPORT_SYMBOL(twl4030_i2c_write);
+
+/**
+ * twl4030_i2c_read - Reads a n bit register in TWL4030
+ * @mod_no: module number
+ * @value: an array of num_bytes containing data to be read
+ * @reg: register address (just offset will do)
+ * @num_bytes: number of bytes to transfer
+ *
+ * Returns result of operation - num_bytes is success else failure.
+ */
+int twl4030_i2c_read(u8 mod_no, u8 *value, u8 reg, u8 num_bytes)
+{
+ int ret;
+ u8 val;
+ int sid;
+ struct twl4030_client *twl;
+ struct i2c_msg *msg;
+
+ if (unlikely(mod_no > TWL4030_MODULE_LAST)) {
+ pr_err("Invalid module Number\n");
+ return -EPERM;
+ }
+ sid = twl4030_map[mod_no].sid;
+ twl = &twl4030_modules[sid];
+
+ if (unlikely(twl->inuse != TWL_CLIENT_USED)) {
+ pr_err("I2C Client[%d] is not initialized[%d]\n", sid,
+ __LINE__);
+ return -EPERM;
+ }
+ mutex_lock(&twl->xfer_lock);
+ /* [MSG1] fill the register address data */
+ msg = &twl->xfer_msg[0];
+ msg->addr = twl->address;
+ msg->len = 1;
+ msg->flags = 0; /* Read the register value */
+ val = twl4030_map[mod_no].base + reg;
+ msg->buf = &val;
+ /* [MSG2] fill the data rx buffer */
+ msg = &twl->xfer_msg[1];
+ msg->addr = twl->address;
+ msg->flags = I2C_M_RD; /* Read the register value */
+ msg->len = num_bytes; /* only n bytes */
+ msg->buf = value;
+ ret = i2c_transfer(twl->client.adapter, twl->xfer_msg, 2);
+ mutex_unlock(&twl->xfer_lock);
+
+ /* i2cTransfer returns num messages.translate it pls.. */
+ if (ret >= 0)
+ ret = 0;
+ return ret;
+}
+EXPORT_SYMBOL(twl4030_i2c_read);
+
+/**
+ * twl4030_i2c_write_u8 - Writes a 8 bit register in TWL4030
+ * @mod_no: module number
+ * @value: the value to be written 8 bit
+ * @reg: register address (just offset will do)
+ *
+ * Returns result of operation - 0 is success
+ */
+int twl4030_i2c_write_u8(u8 mod_no, u8 value, u8 reg)
+{
+
+ /* 2 bytes offset 1 contains the data offset 0 is used by i2c_write */
+ u8 temp_buffer[2] = { 0 };
+ /* offset 1 contains the data */
+ temp_buffer[1] = value;
+ return twl4030_i2c_write(mod_no, temp_buffer, reg, 1);
+}
+EXPORT_SYMBOL(twl4030_i2c_write_u8);
+
+/**
+ * twl4030_i2c_read_u8 - Reads a 8 bit register from TWL4030
+ * @mod_no: module number
+ * @value: the value read 8 bit
+ * @reg: register address (just offset will do)
+ *
+ * Returns result of operation - 0 is success
+ */
+int twl4030_i2c_read_u8(u8 mod_no, u8 *value, u8 reg)
+{
+ return twl4030_i2c_read(mod_no, value, reg, 1);
+}
+EXPORT_SYMBOL(twl4030_i2c_read_u8);
+
+/* Helper Functions */
+
+/*
+ * do_twl4030_module_irq() is the desc->handle method for each of the twl4030
+ * module interrupts. It executes in kernel thread context.
+ * On entry, cpu interrupts are disabled.
+ */
+static void do_twl4030_module_irq(unsigned int irq, irq_desc_t *desc)
+{
+ struct irqaction *action;
+ const unsigned int cpu = smp_processor_id();
+
+ /*
+ * Earlier this was desc->triggered = 1;
+ */
+ desc->status |= IRQ_LEVEL;
+
+ /*
+ * The desc->handle method would normally call the desc->chip->ack
+ * method here, but we won't bother since our ack method is NULL.
+ */
+
+ if (!desc->depth) {
+ kstat_cpu(cpu).irqs[irq]++;
+
+ action = desc->action;
+ if (action) {
+ int ret;
+ int status = 0;
+ int retval = 0;
+
+ local_irq_enable();
+
+ do {
+ /* Call the ISR with cpu interrupts enabled */
+ ret = action->handler(irq, action->dev_id);
+ if (ret == IRQ_HANDLED)
+ status |= action->flags;
+ retval |= ret;
+ action = action->next;
+ } while (action);
+
+ if (status & IRQF_SAMPLE_RANDOM)
+ add_interrupt_randomness(irq);
+
+ local_irq_disable();
+
+ if (retval != IRQ_HANDLED)
+ printk(KERN_ERR "ISR for TWL4030 module"
+ " irq %d can't handle interrupt\n",
+ irq);
+
+ /*
+ * Here is where we should call the unmask method, but
+ * again we won't bother since it is NULL.
+ */
+ } else
+ printk(KERN_CRIT "TWL4030 module irq %d has no ISR"
+ " but can't be masked!\n", irq);
+ } else
+ printk(KERN_CRIT "TWL4030 module irq %d is disabled but can't"
+ " be masked!\n", irq);
+}
+
+/*
+ * twl4030_irq_thread() runs as a kernel thread. It queries the twl4030
+ * interrupt controller to see which modules are generating interrupt requests
+ * and then calls the desc->handle method for each module requesting service.
+ */
+static int twl4030_irq_thread(void *data)
+{
+ int irq = (int)data;
+ irq_desc_t *desc = irq_desc + irq;
+ static unsigned i2c_errors;
+ const static unsigned max_i2c_errors = 100;
+
+ daemonize("twl4030-irq");
+ current->flags |= PF_NOFREEZE;
+
+ while (!kthread_should_stop()) {
+ int ret;
+ int module_irq;
+ u8 pih_isr;
+
+ wait_for_completion_interruptible(&irq_event);
+
+ ret = twl4030_i2c_read_u8(TWL4030_MODULE_PIH, &pih_isr,
+ REG_PIH_ISR_P1);
+ if (ret) {
+ printk(KERN_WARNING "I2C error %d while reading TWL4030"
+ " PIH ISR register.\n", ret);
+ if (++i2c_errors >= max_i2c_errors) {
+ printk(KERN_ERR "Maximum I2C error count"
+ " exceeded. Terminating %s.\n",
+ __func__);
+ break;
+ }
+ continue;
+ }
+
+ for (module_irq = TWL4030_IRQ_BASE; 0 != pih_isr;
+ pih_isr >>= 1, module_irq++) {
+ if (pih_isr & 0x1) {
+ irq_desc_t *d = irq_desc + module_irq;
+
+ local_irq_disable();
+
+ d->handle_irq(module_irq, d);
+
+ local_irq_enable();
+ }
+ }
+
+ desc->chip->unmask(irq);
+ }
+
+ return 0;
+}
+
+/*
+ * do_twl4030_irq() is the desc->handle method for the twl4030 interrupt.
+ * This is a chained interrupt, so there is no desc->action method for it.
+ * Now we need to query the interrupt controller in the twl4030 to determine
+ * which module is generating the interrupt request. However, we can't do i2c
+ * transactions in interrupt context, so we must defer that work to a kernel
+ * thread. All we do here is acknowledge and mask the interrupt and wakeup
+ * the kernel thread.
+ */
+static void do_twl4030_irq(unsigned int irq, irq_desc_t *desc)
+{
+ const unsigned int cpu = smp_processor_id();
+
+ /*
+ * Earlier this was desc->triggered = 1;
+ */
+ desc->status |= IRQ_LEVEL;
+
+ /*
+ * Acknowledge, clear _AND_ disable the interrupt.
+ */
+ desc->chip->ack(irq);
+
+ if (!desc->depth) {
+ kstat_cpu(cpu).irqs[irq]++;
+
+ complete(&irq_event);
+ }
+}
+
+/* attach a client to the adapter */
+static int __init twl4030_detect_client(struct i2c_adapter *adapter,
+ unsigned char sid)
+{
+ int err = 0;
+ struct twl4030_client *twl;
+
+ if (unlikely(sid >= TWL4030_NUM_SLAVES)) {
+ pr_err("sid[%d] > MOD_LAST[%d]\n", sid, TWL4030_NUM_SLAVES);
+ return -EPERM;
+ }
+
+ /* Check basic functionality */
+ err = i2c_check_functionality(adapter,
+ I2C_FUNC_SMBUS_WORD_DATA
+ | I2C_FUNC_SMBUS_WRITE_BYTE);
+ if (!err) {
+ pr_err("SlaveID=%d functionality check failed\n", sid);
+ return err;
+ }
+ twl = &twl4030_modules[sid];
+ if (unlikely(twl->inuse)) {
+ pr_err("Client %s is already in use\n", twl->client_name);
+ return -EPERM;
+ }
+
+ memset(&twl->client, 0, sizeof(struct i2c_client));
+
+ twl->client.addr = twl->address;
+ twl->client.adapter = adapter;
+ twl->client.driver = &twl4030_driver;
+
+ memcpy(&twl->client.name, twl->client_name,
+ sizeof(TWL_CLIENT_STRING) + 1);
+
+ pr_info("TWL4030: TRY attach Slave %s on Adapter %s [%x]\n",
+ twl->client_name, adapter->name, err);
+
+ err = i2c_attach_client(&twl->client);
+ if (err) {
+ pr_err("Couldn't attach Slave %s on Adapter"
+ "%s [%x]\n", twl->client_name, adapter->name, err);
+ } else {
+ twl->inuse = TWL_CLIENT_USED;
+ mutex_init(&twl->xfer_lock);
+ }
+
+ return err;
+}
+
+/* adapter callback */
+static int __init twl4030_attach_adapter(struct i2c_adapter *adapter)
+{
+ int i;
+ int ret = 0;
+ static int twl_i2c_adapter = 1;
+
+ for (i = 0; i < TWL4030_NUM_SLAVES; i++) {
+ /* Check if I need to hook on to this adapter or not */
+ if (twl4030_modules[i].adapter_index == twl_i2c_adapter) {
+ ret = twl4030_detect_client(adapter, i);
+ if (ret)
+ goto free_client;
+ }
+ }
+ twl_i2c_adapter++;
+
+ /*
+ * Check if the PIH module is initialized, if yes, then init
+ * the T2 Interrupt subsystem
+ */
+ if ((twl4030_modules[twl4030_map[TWL4030_MODULE_PIH].sid].inuse ==
+ TWL_CLIENT_USED) && (twl_irq_used != USED)) {
+ twl_init_irq();
+ twl_irq_used = USED;
+ }
+ return 0;
+
+free_client:
+ pr_err("TWL_CLIENT(Idx=%d] registration failed[0x%x]\n", i, ret);
+
+ /* ignore current slave..it never got registered */
+ i--;
+ while (i >= 0) {
+ /* now remove all those from the current adapter... */
+ if (twl4030_modules[i].adapter_index == twl_i2c_adapter)
+ (void)twl4030_detach_client(&twl4030_modules[i].client);
+ i--;
+ }
+ return ret;
+}
+
+/* adapter's callback */
+static int twl4030_detach_client(struct i2c_client *client)
+{
+ int err;
+ err = i2c_detach_client(client);
+ if (err) {
+ pr_err("Client detach failed\n");
+ return err;
+ }
+ return 0;
+}
+
+static struct task_struct * __init start_twl4030_irq_thread(int irq)
+{
+ struct task_struct *thread;
+
+ init_completion(&irq_event);
+ thread = kthread_run(twl4030_irq_thread, (void *)irq,
+ "twl4030 irq %d", irq);
+ if (!thread)
+ pr_err("%s: could not create twl4030 irq %d thread!\n",
+ __func__, irq);
+
+ return thread;
+}
+
+/*
+ * These three functions should be part of Voltage frame work
+ * added here to complete the functionality for now.
+ */
+static int __init protect_pm_master(void)
+{
+ int e = 0;
+
+ e = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_LOCK,
+ R_PROTECT_KEY);
+ return e;
+}
+
+static int __init unprotect_pm_master(void)
+{
+ int e = 0;
+
+ e |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_UNLOCK1,
+ R_PROTECT_KEY);
+ e |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_UNLOCK2,
+ R_PROTECT_KEY);
+ return e;
+}
+
+static int __init power_companion_init(void)
+{
+ struct clk *osc;
+ u32 rate;
+ u8 ctrl = HFCLK_FREQ_26_MHZ;
+ int e = 0;
+
+ if (cpu_is_omap2430())
+ osc = clk_get(NULL, "osc_ck");
+ else
+ osc = clk_get(NULL, "osc_sys_ck");
+ if (IS_ERR(osc)) {
+ printk(KERN_WARNING "Skipping twl3040 internal clock init and "
+ "using bootloader value (unknown osc rate)\n");
+ return 0;
+ }
+
+ rate = clk_get_rate(osc);
+ clk_put(osc);
+
+ switch (rate) {
+ case 19200000 : ctrl = HFCLK_FREQ_19p2_MHZ; break;
+ case 26000000 : ctrl = HFCLK_FREQ_26_MHZ; break;
+ case 38400000 : ctrl = HFCLK_FREQ_38p4_MHZ; break;
+ }
+
+ ctrl |= HIGH_PERF_SQ;
+ e |= unprotect_pm_master();
+ /* effect->MADC+USB ck en */
+ e |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, ctrl, R_CFG_BOOT);
+ e |= protect_pm_master();
+
+ return e;
+}
+
+/**
+ * twl4030_i2c_clear_isr - clear TWL4030 SIH ISR regs via read + write
+ * @mod_no: TWL4030 module number
+ * @reg: register index to clear
+ * @cor: value of the <module>_SIH_CTRL.COR bit (1 or 0)
+ *
+ * Either reads (cor == 1) or writes (cor == 0) to a TWL4030 interrupt
+ * status register to ensure that any prior interrupts are cleared.
+ * Returns the status from the I2C read operation.
+ */
+static int __init twl4030_i2c_clear_isr(u8 mod_no, u8 reg, u8 cor)
+{
+ u8 tmp;
+
+ return (cor) ? twl4030_i2c_read_u8(mod_no, &tmp, reg) :
+ twl4030_i2c_write_u8(mod_no, 0xff, reg);
+}
+
+/**
+ * twl4030_read_cor_bit - are TWL module ISRs cleared by reads or writes?
+ * @mod_no: TWL4030 module number
+ * @reg: register index to clear
+ *
+ * Returns 1 if the TWL4030 SIH interrupt status registers (ISRs) for
+ * the specified TWL module are cleared by reads, or 0 if cleared by
+ * writes.
+ */
+static int twl4030_read_cor_bit(u8 mod_no, u8 reg)
+{
+ u8 tmp = 0;
+
+ WARN_ON(twl4030_i2c_read_u8(mod_no, &tmp, reg) < 0);
+
+ tmp &= TWL4030_SIH_CTRL_COR_MASK;
+ tmp >>= __ffs(TWL4030_SIH_CTRL_COR_MASK);
+
+ return tmp;
+}
+
+/**
+ * twl4030_mask_clear_intrs - mask and clear all TWL4030 interrupts
+ * @t: pointer to twl4030_mod_iregs array
+ * @t_sz: ARRAY_SIZE(t) (starting at 1)
+ *
+ * Mask all TWL4030 interrupt mask registers (IMRs) and clear all
+ * interrupt status registers (ISRs). No return value, but will WARN if
+ * any I2C operations fail.
+ */
+static void __init twl4030_mask_clear_intrs(const struct twl4030_mod_iregs *t,
+ const u8 t_sz)
+{
+ int i, j;
+
+ /*
+ * N.B. - further efficiency is possible here. Eight I2C
+ * operations on BCI and GPIO modules are avoidable if I2C
+ * burst read/write transactions were implemented. Would
+ * probably save about 1ms of boot time and a small amount of
+ * power.
+ */
+ for (i = 0; i < t_sz; i++) {
+ const struct twl4030_mod_iregs tmr = t[i];
+ int cor;
+
+ /* Are ISRs cleared by reads or writes? */
+ cor = twl4030_read_cor_bit(tmr.mod_no, tmr.sih_ctrl);
+ WARN_ON(cor < 0);
+
+ for (j = 0; j < tmr.reg_cnt; j++) {
+
+ /* Mask interrupts at the TWL4030 */
+ WARN_ON(twl4030_i2c_write_u8(tmr.mod_no, 0xff,
+ tmr.imrs[j]) < 0);
+
+ /* Clear TWL4030 ISRs */
+ WARN_ON(twl4030_i2c_clear_isr(tmr.mod_no,
+ tmr.isrs[j], cor) < 0);
+ }
+ }
+
+ return;
+}
+
+
+static void twl_init_irq(void)
+{
+ int i;
+ int res = 0;
+ char *msg = "Unable to register interrupt subsystem";
+ unsigned int irq_num;
+
+ /*
+ * Mask and clear all TWL4030 interrupts since initially we do
+ * not have any TWL4030 module interrupt handlers present
+ */
+ twl4030_mask_clear_intrs(twl4030_mod_regs,
+ ARRAY_SIZE(twl4030_mod_regs));
+
+ /* install an irq handler for each of the PIH modules */
+ for (i = TWL4030_IRQ_BASE; i < TWL4030_IRQ_END; i++) {
+ set_irq_chip(i, &twl4030_irq_chip);
+ set_irq_handler(i, do_twl4030_module_irq);
+ set_irq_flags(i, IRQF_VALID);
+ }
+
+ irq_num = (cpu_is_omap2430()) ? INT_24XX_SYS_NIRQ : INT_34XX_SYS_NIRQ;
+
+ /* install an irq handler to demultiplex the TWL4030 interrupt */
+ set_irq_data(irq_num, start_twl4030_irq_thread(irq_num));
++ set_irq_type(irq_num, IRQ_TYPE_EDGE_FALLING);
+ set_irq_chained_handler(irq_num, do_twl4030_irq);
+
+ res = power_companion_init();
+ if (res < 0)
+ pr_err("%s[%d][%d]\n", msg, res, __LINE__);
+}
+
+static int __init twl4030_init(void)
+{
+ return i2c_add_driver(&twl4030_driver);
+}
+
+static void __exit twl4030_exit(void)
+{
+ i2c_del_driver(&twl4030_driver);
+ twl_irq_used = FREE;
+}
+
+subsys_initcall(twl4030_init);
+module_exit(twl4030_exit);
+
+MODULE_ALIAS("i2c:" DRIVER_NAME);
+MODULE_AUTHOR("Texas Instruments, Inc.");
+MODULE_DESCRIPTION("I2C Core interface for TWL4030");
+MODULE_LICENSE("GPL");
--- /dev/null
- set_irq_type(kp->irq, IRQT_FALLING);
+/*
+ * TSC2301 keypad driver
+ *
+ * Copyright (C) 2005-2006 Nokia Corporation
+ *
+ * Written by Jarkko Oikarinen
+ * Rewritten by Juha Yrjola <juha.yrjola@nokia.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/kernel.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/spi/spi.h>
+
+#include <linux/spi/tsc2301.h>
+
+#define TSC2301_KEYBOARD_PRODUCT_ID 0x0051
+#define TSC2301_KEYBOARD_PRODUCT_VERSION 0x0001
+#define TSC2301_DEBOUNCE_TIME_2MS 0x0000
+#define TSC2301_DEBOUNCE_TIME_10MS 0x0800
+#define TSC2301_DEBOUNCE_TIME_20MS 0x1000
+#define TSC2301_DEBOUNCE_TIME_50MS 0x1800
+#define TSC2301_DEBOUNCE_TIME_60MS 0x2000
+#define TSC2301_DEBOUNCE_TIME_80MS 0x2800
+#define TSC2301_DEBOUNCE_TIME_100MS 0x3000
+#define TSC2301_DEBOUNCE_TIME_120MS 0x3800
+
+#define TSC2301_DEBOUNCE_TIME TSC2301_DEBOUNCE_TIME_20MS
+
+#define TSC2301_RELEASE_TIMEOUT 50
+
+struct tsc2301_kp {
+ struct input_dev *idev;
+ char phys[32];
+ spinlock_t lock;
+ struct mutex mutex;
+ struct timer_list timer;
+ u16 keys_pressed;
+ unsigned pending:1;
+ unsigned user_disabled:1;
+ unsigned disable_depth;
+
+ struct spi_transfer read_xfer[4];
+ struct spi_message read_msg;
+
+ u16 data;
+ u16 mask;
+
+ int irq;
+ s16 keymap[16];
+};
+
+static inline int tsc2301_kp_disabled(struct tsc2301 *tsc)
+{
+ return tsc->kp->disable_depth != 0;
+}
+
+static void tsc2301_kp_send_key_events(struct tsc2301 *tsc,
+ u16 prev_state,
+ u16 new_state)
+{
+ struct tsc2301_kp *kp = tsc->kp;
+ u16 common, released, pressed;
+ int i;
+
+ common = prev_state & new_state;
+ released = common ^ prev_state;
+ pressed = common ^ new_state;
+ if (!released && !pressed)
+ return;
+ for (i = 0; i < 16 && (released || pressed); i++) {
+ if (released & 1) {
+ dev_dbg(&tsc->spi->dev, "key %d released\n", i);
+ input_report_key(kp->idev, kp->keymap[i], 0);
+ }
+ released >>= 1;
+ if (pressed & 1) {
+ dev_dbg(&tsc->spi->dev, "key %d pressed\n", i);
+ input_report_key(kp->idev, kp->keymap[i], 1);
+ }
+ pressed >>= 1;
+ }
+ input_sync(kp->idev);
+}
+
+static inline void _filter_out(struct tsc2301 *tsc, u16 prev_state,
+ u16 *new_state, int row1, int row2, u8 rect_pat)
+{
+ u16 mask;
+
+ mask = (rect_pat << (row1 * 4)) | (rect_pat << (row2 * 4));
+ mask &= ~prev_state;
+ *new_state &= ~mask;
+ dev_dbg(&tsc->spi->dev, "filtering ghost keys %02x\n", mask);
+}
+
+static void tsc2301_filter_ghost_keys(struct tsc2301 *tsc, u16 prev_state,
+ u16 *new_state)
+{
+ int row1, row2;
+ u16 key_map;
+ u16 row1_map;
+ static const u8 rect_pat[] = {
+ 0x3, 0x5, 0x9, 0x6, 0xa, 0xc, 0,
+ };
+
+ key_map = *new_state;
+ for (row1 = 0; row1 < 4; row1++) {
+ row1_map = (key_map >> (row1 * 4)) & 0xf;
+ if (!row1_map)
+ continue;
+ for (row2 = row1 + 1; row2 < 4; row2++) {
+ u16 rect_map = (key_map >> (row2 * 4)) & 0xf;
+ const u8 *rp;
+
+ rect_map &= row1_map;
+ if (!rect_map)
+ continue;
+ for (rp = rect_pat; *rp; rp++)
+ if ((rect_map & *rp) == *rp)
+ _filter_out(tsc, prev_state, new_state,
+ row1, row2, *rp);
+ }
+ }
+}
+
+static void tsc2301_kp_timer(unsigned long arg)
+{
+ struct tsc2301 *tsc = (void *) arg;
+ struct tsc2301_kp *kp = tsc->kp;
+ unsigned long flags;
+
+ tsc2301_kp_send_key_events(tsc, kp->keys_pressed, 0);
+ spin_lock_irqsave(&kp->lock, flags);
+ kp->keys_pressed = 0;
+ spin_unlock_irqrestore(&kp->lock, flags);
+}
+
+static void tsc2301_kp_rx(void *arg)
+{
+ struct tsc2301 *tsc = arg;
+ struct tsc2301_kp *kp = tsc->kp;
+ unsigned long flags;
+ u16 kp_data;
+
+ kp_data = kp->data;
+ dev_dbg(&tsc->spi->dev, "KP data %04x\n", kp_data);
+
+ tsc2301_filter_ghost_keys(tsc, kp->keys_pressed, &kp_data);
+ tsc2301_kp_send_key_events(tsc, kp->keys_pressed, kp_data);
+ spin_lock_irqsave(&kp->lock, flags);
+ kp->keys_pressed = kp_data;
+ kp->pending = 0;
+ spin_unlock_irqrestore(&kp->lock, flags);
+}
+
+static irqreturn_t tsc2301_kp_irq_handler(int irq, void *dev_id)
+{
+ struct tsc2301 *tsc = dev_id;
+ struct tsc2301_kp *kp = tsc->kp;
+ unsigned long flags;
+ int r;
+
+ spin_lock_irqsave(&kp->lock, flags);
+ if (tsc2301_kp_disabled(tsc)) {
+ spin_unlock_irqrestore(&kp->lock, flags);
+ return IRQ_HANDLED;
+ }
+ kp->pending = 1;
+ spin_unlock_irqrestore(&kp->lock, flags);
+ mod_timer(&kp->timer,
+ jiffies + msecs_to_jiffies(TSC2301_RELEASE_TIMEOUT));
+ r = spi_async(tsc->spi, &tsc->kp->read_msg);
+ if (r)
+ dev_err(&tsc->spi->dev, "kp: spi_async() failed");
+ return IRQ_HANDLED;
+}
+
+static void tsc2301_kp_start_scan(struct tsc2301 *tsc)
+{
+ tsc2301_write_reg(tsc, TSC2301_REG_KPMASK, tsc->kp->mask);
+ tsc2301_write_reg(tsc, TSC2301_REG_KEY, TSC2301_DEBOUNCE_TIME);
+}
+
+static void tsc2301_kp_stop_scan(struct tsc2301 *tsc)
+{
+ tsc2301_write_reg(tsc, TSC2301_REG_KEY, 1 << 14);
+}
+
+/* Must be called with the mutex held */
+static void tsc2301_kp_enable(struct tsc2301 *tsc)
+{
+ struct tsc2301_kp *kp = tsc->kp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&kp->lock, flags);
+ BUG_ON(!tsc2301_kp_disabled(tsc));
+ if (--kp->disable_depth != 0) {
+ spin_unlock_irqrestore(&kp->lock, flags);
+ return;
+ }
+ spin_unlock_irqrestore(&kp->lock, flags);
+
- set_irq_type(kp->irq, IRQT_NOEDGE);
++ set_irq_type(kp->irq, IRQ_TYPE_EDGE_FALLING);
+ tsc2301_kp_start_scan(tsc);
+ enable_irq(kp->irq);
+}
+
+/* Must be called with the mutex held */
+static int tsc2301_kp_disable(struct tsc2301 *tsc, int release_keys)
+{
+ struct tsc2301_kp *kp = tsc->kp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&kp->lock, flags);
+ if (kp->disable_depth++ != 0) {
+ spin_unlock_irqrestore(&kp->lock, flags);
+ goto out;
+ }
+ disable_irq_nosync(kp->irq);
- set_irq_type(kp->irq, IRQT_FALLING);
++ set_irq_type(kp->irq, IRQ_TYPE_NONE);
+ spin_unlock_irqrestore(&kp->lock, flags);
+
+ while (kp->pending) {
+ msleep(1);
+ }
+
+ tsc2301_kp_stop_scan(tsc);
+out:
+ if (!release_keys)
+ del_timer(&kp->timer); /* let timeout release keys */
+
+ return 0;
+}
+
+/* The following workaround is needed for a HW bug triggered by the
+ * following:
+ * 1. keep any key pressed
+ * 2. disable keypad
+ * 3. release all keys
+ * 4. reenable keypad
+ * 5. disable touch screen controller
+ *
+ * After this the keypad scanner will get stuck in busy state and won't
+ * report any interrupts for further keypresses. One way to recover is to
+ * restart the keypad scanner whenever we enable / disable the
+ * touchscreen controller.
+ */
+void tsc2301_kp_restart(struct tsc2301 *tsc)
+{
+ if (!tsc2301_kp_disabled(tsc)) {
+ tsc2301_kp_start_scan(tsc);
+ }
+}
+
+static ssize_t tsc2301_kp_disable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tsc2301 *tsc = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%u\n", tsc2301_kp_disabled(tsc) ? 1 : 0);
+}
+
+static ssize_t tsc2301_kp_disable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct tsc2301 *tsc = dev_get_drvdata(dev);
+ struct tsc2301_kp *kp = tsc->kp;
+ char *endp;
+ int i;
+
+ i = simple_strtoul(buf, &endp, 10);
+ i = i ? 1 : 0;
+
+ mutex_lock(&kp->mutex);
+ if (i == kp->user_disabled) {
+ mutex_unlock(&kp->mutex);
+ return count;
+ }
+ kp->user_disabled = i;
+
+ if (i)
+ tsc2301_kp_disable(tsc, 1);
+ else
+ tsc2301_kp_enable(tsc);
+ mutex_unlock(&kp->mutex);
+
+ return count;
+}
+
+static DEVICE_ATTR(disable_kp, 0664, tsc2301_kp_disable_show,
+ tsc2301_kp_disable_store);
+
+static const u16 tsc2301_kp_read_data = 0x8000 | TSC2301_REG_KPDATA;
+
+static void tsc2301_kp_setup_spi_xfer(struct tsc2301 *tsc)
+{
+ struct tsc2301_kp *kp = tsc->kp;
+ struct spi_message *m = &kp->read_msg;
+ struct spi_transfer *x = &kp->read_xfer[0];
+
+ spi_message_init(&kp->read_msg);
+
+ x->tx_buf = &tsc2301_kp_read_data;
+ x->len = 2;
+ spi_message_add_tail(x, m);
+ x++;
+
+ x->rx_buf = &kp->data;
+ x->len = 2;
+ spi_message_add_tail(x, m);
+
+ m->complete = tsc2301_kp_rx;
+ m->context = tsc;
+}
+
+#ifdef CONFIG_PM
+int tsc2301_kp_suspend(struct tsc2301 *tsc)
+{
+ struct tsc2301_kp *kp = tsc->kp;
+
+ mutex_lock(&kp->mutex);
+ tsc2301_kp_disable(tsc, 1);
+ mutex_unlock(&kp->mutex);
+ return 0;
+}
+
+void tsc2301_kp_resume(struct tsc2301 *tsc)
+{
+ struct tsc2301_kp *kp = tsc->kp;
+
+ mutex_lock(&kp->mutex);
+ tsc2301_kp_enable(tsc);
+ mutex_unlock(&kp->mutex);
+}
+#endif
+
+int __devinit tsc2301_kp_init(struct tsc2301 *tsc,
+ struct tsc2301_platform_data *pdata)
+{
+ struct input_dev *idev;
+ struct tsc2301_kp *kp;
+ int r, i;
+ u16 mask;
+
+ if (pdata->keyb_int < 0) {
+ dev_err(&tsc->spi->dev, "need kbirq");
+ return -EINVAL;
+ }
+
+ kp = kzalloc(sizeof(*kp), GFP_KERNEL);
+ if (kp == NULL)
+ return -ENOMEM;
+ tsc->kp = kp;
+
+ kp->irq = pdata->keyb_int;
+ spin_lock_init(&kp->lock);
+ mutex_init(&kp->mutex);
+
+ init_timer(&kp->timer);
+ kp->timer.data = (unsigned long) tsc;
+ kp->timer.function = tsc2301_kp_timer;
+
+ idev = input_allocate_device();
+ if (idev == NULL) {
+ r = -ENOMEM;
+ goto err1;
+ }
+ if (pdata->keyb_name)
+ idev->name = pdata->keyb_name;
+ else
+ idev->name = "TSC2301 keypad";
+ snprintf(kp->phys, sizeof(kp->phys), "%s/input-kp", tsc->spi->dev.bus_id);
+ idev->phys = kp->phys;
+
+ mask = 0;
+ idev->evbit[0] = BIT(EV_KEY);
+ for (i = 0; i < 16; i++) {
+ if (pdata->keymap[i] > 0) {
+ set_bit(pdata->keymap[i], idev->keybit);
+ kp->keymap[i] = pdata->keymap[i];
+ } else {
+ kp->keymap[i] = -1;
+ mask |= 1 << i;
+ }
+ }
+
+ if (pdata->kp_rep)
+ set_bit(EV_REP, idev->evbit);
+
+ kp->idev = idev;
+
+ tsc2301_kp_setup_spi_xfer(tsc);
+
+ r = device_create_file(&tsc->spi->dev, &dev_attr_disable_kp);
+ if (r < 0)
+ goto err2;
+
+ tsc2301_kp_start_scan(tsc);
+
+ /* IRQ mode 0 is faulty, it can cause the KBIRQ to get stuck.
+ * Mode 2 deasserts the IRQ at:
+ * - HW or SW reset
+ * - Setting SCS flag in REG_KEY register
+ * - Releasing all keys
+ * - Reading the REG_KPDATA
+ */
+ tsc2301_write_kbc(tsc, 2);
+
+ tsc2301_write_reg(tsc, TSC2301_REG_KPMASK, mask);
+ kp->mask = mask;
+
++ set_irq_type(kp->irq, IRQ_TYPE_EDGE_FALLING);
+
+ r = request_irq(kp->irq, tsc2301_kp_irq_handler, IRQF_SAMPLE_RANDOM,
+ "tsc2301-kp", tsc);
+ if (r < 0) {
+ dev_err(&tsc->spi->dev, "unable to get kbirq IRQ");
+ goto err3;
+ }
+ set_irq_wake(kp->irq, 1);
+
+ /* We need to read the register once..? */
+ tsc2301_read_reg(tsc, TSC2301_REG_KPDATA);
+
+ r = input_register_device(idev);
+ if (r < 0) {
+ dev_err(&tsc->spi->dev, "can't register keypad device\n");
+ goto err4;
+ }
+
+ return 0;
+
+err4:
+ free_irq(kp->irq, tsc);
+err3:
+ tsc2301_kp_stop_scan(tsc);
+ device_remove_file(&tsc->spi->dev, &dev_attr_disable_kp);
+err2:
+ input_free_device(kp->idev);
+err1:
+ kfree(kp);
+ return r;
+}
+
+void __devexit tsc2301_kp_exit(struct tsc2301 *tsc)
+{
+ struct tsc2301_kp *kp = tsc->kp;
+
+ tsc2301_kp_disable(tsc, 1);
+ input_unregister_device(kp->idev);
+ free_irq(kp->irq, tsc);
+ device_remove_file(&tsc->spi->dev, &dev_attr_disable_kp);
+
+ kfree(kp);
+}
To compile this driver as a module, choose M here: the
module will be called mtouch.
+ config TOUCHSCREEN_INEXIO
+ tristate "iNexio serial touchscreens"
+ select SERIO
+ help
+ Say Y here if you have an iNexio serial touchscreen connected to
+ your system.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called inexio.
+
config TOUCHSCREEN_MK712
tristate "ICS MicroClock MK712 touchscreen"
help
To compile this driver as a module, choose M here: the
module will be called jornada720_ts.
+ config TOUCHSCREEN_HTCPEN
+ tristate "HTC Shift X9500 touchscreen"
+ depends on ISA
+ help
+ Say Y here if you have an HTC Shift UMPC also known as HTC X9500
+ Clio / Shangrila and want to support the built-in touchscreen.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called htcpen.
+
config TOUCHSCREEN_PENMOUNT
tristate "Penmount serial touchscreen"
select SERIO
To compile this driver as a module, choose M here: the
module will be called penmount.
+ config TOUCHSCREEN_MIGOR
+ tristate "Renesas MIGO-R touchscreen"
+ depends on SH_MIGOR && I2C
+ help
+ Say Y here to enable MIGO-R touchscreen support.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called migor_ts.
+
config TOUCHSCREEN_TOUCHRIGHT
tristate "Touchright serial touchscreen"
select SERIO
To compile this driver as a module, choose M here: the
module will be called touchwin.
+ config TOUCHSCREEN_ATMEL_TSADCC
+ tristate "Atmel Touchscreen Interface"
+ depends on ARCH_AT91SAM9RL
+ help
+ Say Y here if you have a 4-wire touchscreen connected to the
+ ADC Controller on your Atmel SoC (such as the AT91SAM9RL).
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called atmel_tsadcc.
+
+config TOUCHSCREEN_TSC2005
+ tristate "TSC2005 touchscreen support"
+ help
+ Say Y here for if you are using the touchscreen features of TSC2301.
+
+config TOUCHSCREEN_TSC2102
+ tristate "TSC 2102 based touchscreens"
+ depends on SPI_MASTER
+ select SPI_TSC2102
+ help
+ Say Y here if you have a touchscreen interface using the
+ TI TSC 2102 controller, and your board-specific initialization
+ code includes that in its table of SPI devices. Also make
+ sure the proper SPI controller is selected.
+
+ If unsure, say N (but it's safe to say "Y").
+
+ To compile this driver as a module, choose M here: the
+ module will be called tsc2102_ts.
+
+config TOUCHSCREEN_TSC210X
+ tristate "TI TSC210x based touchscreens"
+ depends on SPI_MASTER
+ select SPI_TSC210X
+ help
+ Say Y here if you have a touchscreen interface using a
+ TI TSC210x controller, and your board-specific initialisation
+ code includes that in its table of SPI devices.
+
+ If unsure, say N (but it's safe to say "Y").
+
+ To compile this driver as a module, choose M here: the
+ module will be called tsc210x_ts.
+
+config TOUCHSCREEN_TSC2301
+ tristate "TSC2301 touchscreen support"
+ depends on SPI_TSC2301
+ help
+ Say Y here for if you are using the touchscreen features of TSC2301.
+
config TOUCHSCREEN_UCB1400
tristate "Philips UCB1400 touchscreen"
select AC97_BUS
bool "GoTop Super_Q2/GogoPen/PenPower tablet device support" if EMBEDDED
depends on TOUCHSCREEN_USB_COMPOSITE
+ config TOUCHSCREEN_TOUCHIT213
+ tristate "Sahara TouchIT-213 touchscreen"
+ select SERIO
+ help
+ Say Y here if you have a Sahara TouchIT-213 Tablet PC.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called touchit213.
+
endif
wm97xx-ts-y := wm97xx-core.o
obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o
+ obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o
obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o
obj-$(CONFIG_TOUCHSCREEN_CORGI) += corgi_ts.o
obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o
obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o
obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o
+ obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o
+ obj-$(CONFIG_TOUCHSCREEN_MIGOR) += migor_ts.o
obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o
obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o
obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o
obj-$(CONFIG_TOUCHSCREEN_HP7XX) += jornada720_ts.o
+ obj-$(CONFIG_TOUCHSCREEN_HTCPEN) += htcpen.o
obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE) += usbtouchscreen.o
obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o
+ obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o
obj-$(CONFIG_TOUCHSCREEN_UCB1400) += ucb1400_ts.o
+obj-$(CONFIG_TOUCHSCREEN_TSC2005) += tsc2005.o
+obj-$(CONFIG_TOUCHSCREEN_TSC2102) += tsc2102_ts.o
+obj-$(CONFIG_TOUCHSCREEN_OMAP) += omap/
+obj-$(CONFIG_TOUCHSCREEN_TSC210X) += tsc210x_ts.o
+obj-$(CONFIG_TOUCHSCREEN_TSC2301) += tsc2301_ts.o
obj-$(CONFIG_TOUCHSCREEN_WM97XX) += wm97xx-ts.o
wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9705) += wm9705.o
wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9712) += wm9712.o
if (x == MAX_12BIT)
x = 0;
- if (likely(x && z1)) {
+ if (ts->model == 7843) {
+ Rt = ts->pressure_max / 2;
+ } else if (likely(x && z1)) {
/* compute touch pressure resistance using equation #2 */
Rt = z2;
Rt -= z1;
Rt *= ts->x_plate_ohms;
Rt /= z1;
Rt = (Rt + 2047) >> 12;
- } else
+ } else {
Rt = 0;
-
- if (ts->model == 7843)
- Rt = ts->pressure_max / 2;
+ }
/* Sample found inconsistent by debouncing or pressure is beyond
* the maximum. Don't report it to user space, repeat at least
struct ads7846 *ts = ads;
struct spi_message *m;
struct spi_transfer *t;
- u16 *rx_val;
int val;
int action;
int status;
m = &ts->msg[ts->msg_idx];
t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
- rx_val = t->rx_buf;
/* adjust: on-wire is a must-ignore bit, a BE12 value, then padding;
* built from two 8 bit values written msb-first.
*/
- val = be16_to_cpu(*rx_val) >> 3;
+ val = be16_to_cpup((__be16 *)t->rx_buf) >> 3;
action = ts->filter(ts->filter_data, ts->msg_idx, &val);
switch (action) {
m = ts->last_msg;
break;
case ADS7846_FILTER_OK:
- *rx_val = val;
+ *(u16 *)t->rx_buf = val;
ts->tc.ignore = 0;
m = &ts->msg[++ts->msg_idx];
break;
return -ENODEV;
}
+ /* enable voltage */
+ if (pdata->vaux_control != NULL) {
+ err = pdata->vaux_control(VAUX_ENABLE);
+ if (err != 0) {
+ dev_dbg(&spi->dev, "TS vaux enable failed\n");
+ return err;
+ }
+ }
+
/* don't exceed max specified sample rate */
if (spi->max_speed_hz > (125000 * SAMPLE_BITS)) {
dev_dbg(&spi->dev, "f(sample) %d KHz?\n",
help
This option enables support for the PCEngines WRAP programmable LEDs.
+config LEDS_OMAP_DEBUG
+ boolean "LED Support for OMAP debug board LEDs"
+ depends on LEDS_CLASS=y && ARCH_OMAP
+ help
+ Enables support for the LEDs on the debug board used with OMAP
+ reference boards like H2/H3/H4 and Perseus2. Up to six of these
+ may be claimed by the original ARM debug LED API.
+
+config LEDS_OMAP
+ tristate "LED Support for OMAP GPIO LEDs"
+ depends on LEDS_CLASS && ARCH_OMAP
+ help
+ This option enables support for the LEDs on OMAP processors.
+
+config LEDS_OMAP_PWM
+ tristate "LED Support for OMAP PWM-controlled LEDs"
+ depends on LEDS_CLASS && ARCH_OMAP && OMAP_DM_TIMER
+ help
+ This options enables support for LEDs connected to GPIO lines
+ controlled by a PWM timer on OMAP CPUs.
+
config LEDS_H1940
tristate "LED Support for iPAQ H1940 device"
depends on LEDS_CLASS && ARCH_H1940
This option enables led support for the handheld
HP Jornada 620/660/680/690.
+ config LEDS_PCA9532
+ tristate "LED driver for PCA9532 dimmer"
+ depends on LEDS_CLASS && I2C && INPUT && EXPERIMENTAL
+ help
+ This option enables support for NXP pca9532
+ led controller. It is generally only usefull
+ as a platform driver
+
config LEDS_GPIO
tristate "LED Support for GPIO connected LEDs"
depends on LEDS_CLASS && GENERIC_GPIO
To compile this driver as a module, choose M here: the
module will be called leds-clevo-mail.
+ config LEDS_PCA955X
+ tristate "LED Support for PCA955x I2C chips"
+ depends on LEDS_CLASS && I2C
+ help
+ This option enables support for LEDs connected to PCA955x
+ LED driver chips accessed via the I2C bus. Supported
+ devices include PCA9550, PCA9551, PCA9552, and PCA9553.
+
comment "LED Triggers"
config LEDS_TRIGGERS
obj-$(CONFIG_LEDS_AMS_DELTA) += leds-ams-delta.o
obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o
obj-$(CONFIG_LEDS_WRAP) += leds-wrap.o
+obj-$(CONFIG_LEDS_OMAP) += leds-omap.o
+obj-$(CONFIG_LEDS_OMAP_PWM) += leds-omap-pwm.o
obj-$(CONFIG_LEDS_H1940) += leds-h1940.o
obj-$(CONFIG_LEDS_COBALT_QUBE) += leds-cobalt-qube.o
obj-$(CONFIG_LEDS_COBALT_RAQ) += leds-cobalt-raq.o
+ obj-$(CONFIG_LEDS_PCA9532) += leds-pca9532.o
obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o
obj-$(CONFIG_LEDS_CM_X270) += leds-cm-x270.o
obj-$(CONFIG_LEDS_CLEVO_MAIL) += leds-clevo-mail.o
obj-$(CONFIG_LEDS_HP6XX) += leds-hp6xx.o
obj-$(CONFIG_LEDS_FSG) += leds-fsg.o
+ obj-$(CONFIG_LEDS_PCA955X) += leds-pca955x.o
# LED Triggers
obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o
select VIDEOBUF_GEN
tristate
+ config VIDEOBUF_DMA_CONTIG
+ depends on HAS_DMA
+ select VIDEOBUF_GEN
+ tristate
+
config VIDEOBUF_DVB
tristate
select VIDEOBUF_GEN
- select VIDEOBUF_DMA_SG
config VIDEO_BTCX
tristate
- config VIDEO_IR_I2C
- tristate
-
config VIDEO_IR
tristate
depends on INPUT
- select VIDEO_IR_I2C if I2C
config VIDEO_TVEEPROM
tristate
In doubt, say Y.
+ config VIDEO_IR_I2C
+ tristate "I2C module for IR" if !VIDEO_HELPER_CHIPS_AUTO
+ depends on I2C && VIDEO_IR
+ default y
+ ---help---
+ Most boards have an IR chip directly connected via GPIO. However,
+ some video boards have the IR connected via I2C bus.
+
+ If your board doesn't have an I2C IR chip, you may disable this
+ option.
+
+ In doubt, say Y.
+
#
# Encoder / Decoder module configuration
#
This is a driver for the Toshiba TCM825x VGA camera sensor.
It is used for example in Nokia N800.
+config VIDEO_OV9640
+ tristate "OmniVision OV9640 sensor support"
+ depends on I2C && VIDEO_V4L2
+ ---help---
+ This is a Video4Linux2 sensor-level driver for the OmniVision
+ OV9640 camera. It is currently working with the TI OMAP2
+ camera controller.
+
config VIDEO_SAA7110
tristate "Philips SAA7110 video decoder"
depends on VIDEO_V4L1 && I2C
To compile this driver as a module, choose M here: the
module will be called pms.
- config VIDEO_PLANB
- tristate "PlanB Video-In on PowerMac"
- depends on PPC_PMAC && VIDEO_V4L1 && BROKEN
- help
- PlanB is the V4L driver for the PowerMac 7x00/8x00 series video
- input hardware. If you want to experiment with this, say Y.
- Otherwise, or if you don't understand a word, say N. See
- <http://www.cpu.lu/~mlan/linux/dev/planb.html> for more info.
-
- Saying M will compile this driver as a module (planb).
-
config VIDEO_BWQCAM
tristate "Quickcam BW Video For Linux"
depends on PARPORT && VIDEO_V4L1
driver for PCI. There is a product page at
<http://www.stradis.com/>.
- config VIDEO_ZORAN_ZR36060
- tristate
-
config VIDEO_ZORAN
tristate "Zoran ZR36057/36067 Video For Linux"
depends on PCI && I2C_ALGOBIT && VIDEO_V4L1 && VIRT_TO_BUS
To compile this driver as a module, choose M here: the
module will be called zr36067.
+ config VIDEO_ZORAN_DC30
+ tristate "Pinnacle/Miro DC30(+) support"
+ depends on VIDEO_ZORAN
+ select VIDEO_ADV7175 if VIDEO_HELPER_CHIPS_AUTO
+ select VIDEO_VPX3220 if VIDEO_HELPER_CHIPS_AUTO
+ help
+ Support for the Pinnacle/Miro DC30(+) MJPEG capture/playback
+ card. This also supports really old DC10 cards based on the
+ zr36050 MJPEG codec and zr36016 VFE.
+
+ config VIDEO_ZORAN_ZR36060
+ tristate "Zoran ZR36060"
+ depends on VIDEO_ZORAN
+ help
+ Say Y to support Zoran boards based on 36060 chips.
+ This includes Iomega Bus, Pinnacle DC10, Linux media Labs 33
+ and 33 R10 and AverMedia 6 boards.
+
config VIDEO_ZORAN_BUZ
tristate "Iomega Buz support"
- depends on VIDEO_ZORAN
+ depends on VIDEO_ZORAN_ZR36060
select VIDEO_SAA7111 if VIDEO_HELPER_CHIPS_AUTO
select VIDEO_SAA7185 if VIDEO_HELPER_CHIPS_AUTO
- select VIDEO_ZORAN_ZR36060
help
Support for the Iomega Buz MJPEG capture/playback card.
config VIDEO_ZORAN_DC10
tristate "Pinnacle/Miro DC10(+) support"
- depends on VIDEO_ZORAN
- select VIDEO_SAA7110
+ depends on VIDEO_ZORAN_ZR36060
+ select VIDEO_SAA7110 if VIDEO_HELPER_CHIPS_AUTO
select VIDEO_ADV7175 if VIDEO_HELPER_CHIPS_AUTO
- select VIDEO_ZORAN_ZR36060
help
Support for the Pinnacle/Miro DC10(+) MJPEG capture/playback
card.
- config VIDEO_ZORAN_DC30
- tristate "Pinnacle/Miro DC30(+) support"
- depends on VIDEO_ZORAN
- select VIDEO_ADV7175 if VIDEO_HELPER_CHIPS_AUTO
- select VIDEO_VPX3220 if VIDEO_HELPER_CHIPS_AUTO
- help
- Support for the Pinnacle/Miro DC30(+) MJPEG capture/playback
- card. This also supports really old DC10 cards based on the
- zr36050 MJPEG codec and zr36016 VFE.
-
config VIDEO_ZORAN_LML33
tristate "Linux Media Labs LML33 support"
- depends on VIDEO_ZORAN
+ depends on VIDEO_ZORAN_ZR36060
select VIDEO_BT819 if VIDEO_HELPER_CHIPS_AUTO
select VIDEO_BT856 if VIDEO_HELPER_CHIPS_AUTO
- select VIDEO_ZORAN_ZR36060
help
Support for the Linux Media Labs LML33 MJPEG capture/playback
card.
config VIDEO_ZORAN_LML33R10
tristate "Linux Media Labs LML33R10 support"
- depends on VIDEO_ZORAN
+ depends on VIDEO_ZORAN_ZR36060
select VIDEO_SAA7114 if VIDEO_HELPER_CHIPS_AUTO
select VIDEO_ADV7170 if VIDEO_HELPER_CHIPS_AUTO
- select VIDEO_ZORAN_ZR36060
help
support for the Linux Media Labs LML33R10 MJPEG capture/playback
card.
config VIDEO_ZORAN_AVS6EYES
tristate "AverMedia 6 Eyes support (EXPERIMENTAL)"
- depends on VIDEO_ZORAN && EXPERIMENTAL && VIDEO_V4L1
+ depends on VIDEO_ZORAN_ZR36060 && EXPERIMENTAL && VIDEO_V4L1
select VIDEO_BT856 if VIDEO_HELPER_CHIPS_AUTO
select VIDEO_KS0127 if VIDEO_HELPER_CHIPS_AUTO
- select VIDEO_ZORAN_ZR36060
help
Support for the AverMedia 6 Eyes video surveillance card.
source "drivers/media/video/ivtv/Kconfig"
+source drivers/media/video/omap/Kconfig
+
source "drivers/media/video/cx18/Kconfig"
config VIDEO_M32R_AR
CMOS camera controller. This is the controller found on first-
generation OLPC systems.
+config VIDEO_OMAP2
+ tristate "OMAP 2 Camera support (EXPERIMENTAL)"
+ select VIDEOBUF_GEN
+ select VIDEOBUF_DMA_SG
+ depends on VIDEO_V4L2 && ARCH_OMAP24XX
+ ---help---
+ Driver for an OMAP 2 camera controller.
+
+
#
# USB Multimedia device configuration
#
if V4L_USB_DRIVERS && USB
- config USB_VIDEO_CLASS
- tristate "USB Video Class (UVC)"
- ---help---
- Support for the USB Video Class (UVC). Currently only video
- input devices, such as webcams, are supported.
+ source "drivers/media/video/uvc/Kconfig"
- For more information see: <http://linux-uvc.berlios.de/>
+ source "drivers/media/video/gspca/Kconfig"
source "drivers/media/video/pvrusb2/Kconfig"
To compile this driver as a module, choose M here: the
module will be called stkwebcam.
+ config USB_S2255
+ tristate "USB Sensoray 2255 video capture device"
+ depends on VIDEO_V4L2
+ select VIDEOBUF_VMALLOC
+ default n
+ help
+ Say Y here if you want support for the Sensoray 2255 USB device.
+ This driver can be compiled as a module, called s2255drv.
+
endif # V4L_USB_DRIVERS
config SOC_CAMERA
tristate "SoC camera support"
depends on VIDEO_V4L2 && HAS_DMA
- select VIDEOBUF_DMA_SG
+ select VIDEOBUF_GEN
help
SoC Camera is a common API to several cameras, not connecting
over a bus like PCI or USB. For example some i2c camera connected
Select this if your MT9V022 camera uses a PCA9536 I2C GPIO
extender to switch between 8 and 10 bit datawidth modes
+ config SOC_CAMERA_PLATFORM
+ tristate "platform camera support"
+ depends on SOC_CAMERA
+ help
+ This is a generic SoC camera platform driver, useful for testing
+
config VIDEO_PXA27x
tristate "PXA27x Quick Capture Interface driver"
depends on VIDEO_DEV && PXA27x
select SOC_CAMERA
+ select VIDEOBUF_DMA_SG
---help---
This is a v4l2 driver for the PXA27x Quick Capture Interface
+ config VIDEO_SH_MOBILE_CEU
+ tristate "SuperH Mobile CEU Interface driver"
+ depends on VIDEO_DEV
+ select SOC_CAMERA
+ select VIDEOBUF_DMA_CONTIG
+ ---help---
+ This is a v4l2 driver for the SuperH Mobile CEU Interface
+
endif # VIDEO_CAPTURE_DRIVERS
stkwebcam-objs := stk-webcam.o stk-sensor.o
+ videodev-objs := v4l2-dev.o v4l2-ioctl.o
+
obj-$(CONFIG_VIDEO_DEV) += videodev.o compat_ioctl32.o v4l2-int-device.o
obj-$(CONFIG_VIDEO_V4L2_COMMON) += v4l2-common.o
obj-$(CONFIG_VIDEO_ZORAN_ZR36060) += zr36060.o
obj-$(CONFIG_VIDEO_PMS) += pms.o
- obj-$(CONFIG_VIDEO_PLANB) += planb.o
obj-$(CONFIG_VIDEO_VINO) += vino.o indycam.o
obj-$(CONFIG_VIDEO_STRADIS) += stradis.o
obj-$(CONFIG_VIDEO_CPIA) += cpia.o
obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o
obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o
+ obj-$(CONFIG_VIDEOBUF_DMA_CONTIG) += videobuf-dma-contig.o
obj-$(CONFIG_VIDEOBUF_VMALLOC) += videobuf-vmalloc.o
obj-$(CONFIG_VIDEOBUF_DVB) += videobuf-dvb.o
obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o
obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o
+obj-$(CONFIG_VIDEO_OMAP_CAMERA) += omap/
obj-$(CONFIG_VIDEO_CX25840) += cx25840/
obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o
obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o
obj-$(CONFIG_VIDEO_OV7670) += ov7670.o
+obj-$(CONFIG_VIDEO_OMAP2) += omap24xxcam.o omap24xxcam-dma.o
obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
+obj-$(CONFIG_VIDEO_OV9640) += ov9640.o
obj-$(CONFIG_USB_DABUSB) += dabusb.o
obj-$(CONFIG_USB_OV511) += ov511.o
obj-$(CONFIG_USB_ET61X251) += et61x251/
obj-$(CONFIG_USB_PWC) += pwc/
obj-$(CONFIG_USB_ZC0301) += zc0301/
+ obj-$(CONFIG_USB_GSPCA) += gspca/
obj-$(CONFIG_USB_IBMCAM) += usbvideo/
obj-$(CONFIG_USB_KONICAWC) += usbvideo/
obj-$(CONFIG_USB_VICAM) += usbvideo/
obj-$(CONFIG_USB_QUICKCAM_MESSENGER) += usbvideo/
+ obj-$(CONFIG_USB_S2255) += s2255drv.o
obj-$(CONFIG_VIDEO_IVTV) += ivtv/
obj-$(CONFIG_VIDEO_CX18) += cx18/
obj-$(CONFIG_VIDEO_CX23885) += cx23885/
obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o
+ obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o
obj-$(CONFIG_SOC_CAMERA) += soc_camera.o
obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o
obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o
+ obj-$(CONFIG_SOC_CAMERA_PLATFORM) += soc_camera_platform.o
obj-$(CONFIG_VIDEO_AU0828) += au0828/
--- /dev/null
- .owner = THIS_MODULE,
+/*
+ * drivers/media/video/omap24xxcam.c
+ *
+ * OMAP 2 camera block driver.
+ *
+ * Copyright (C) 2004 MontaVista Software, Inc.
+ * Copyright (C) 2004 Texas Instruments.
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Sakari Ailus <sakari.ailus@nokia.com>
+ *
+ * Based on code from Andy Lowe <source@mvista.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.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/videodev2.h>
+#include <linux/pci.h> /* needed for videobufs */
+#include <linux/version.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <media/v4l2-common.h>
++#include <media/v4l2-ioctl.h>
+
+#include "omap24xxcam.h"
+
+#define OMAP24XXCAM_VERSION KERNEL_VERSION(0, 0, 0)
+
+#define RESET_TIMEOUT_NS 10000
+
+static void omap24xxcam_reset(struct omap24xxcam_device *cam);
+static int omap24xxcam_sensor_if_enable(struct omap24xxcam_device *cam);
+static void omap24xxcam_device_unregister(struct v4l2_int_device *s);
+static int omap24xxcam_remove(struct platform_device *pdev);
+
+/* module parameters */
+static int video_nr = -1; /* video device minor (-1 ==> auto assign) */
+/*
+ * Maximum amount of memory to use for capture buffers.
+ * Default is 4800KB, enough to double-buffer SXGA.
+ */
+static int capture_mem = 1280 * 960 * 2 * 2;
+
+static struct v4l2_int_device omap24xxcam;
+
+/*
+ *
+ * Clocks.
+ *
+ */
+
+static void omap24xxcam_clock_put(struct omap24xxcam_device *cam)
+{
+ if (cam->ick != NULL && !IS_ERR(cam->ick))
+ clk_put(cam->ick);
+ if (cam->fck != NULL && !IS_ERR(cam->fck))
+ clk_put(cam->fck);
+
+ cam->ick = cam->fck = NULL;
+}
+
+static int omap24xxcam_clock_get(struct omap24xxcam_device *cam)
+{
+ int rval = 0;
+
+ cam->fck = clk_get(cam->dev, "cam_fck");
+ if (IS_ERR(cam->fck)) {
+ dev_err(cam->dev, "can't get cam_fck");
+ rval = PTR_ERR(cam->fck);
+ omap24xxcam_clock_put(cam);
+ return rval;
+ }
+
+ cam->ick = clk_get(cam->dev, "cam_ick");
+ if (IS_ERR(cam->ick)) {
+ dev_err(cam->dev, "can't get cam_ick");
+ rval = PTR_ERR(cam->ick);
+ omap24xxcam_clock_put(cam);
+ }
+
+ return rval;
+}
+
+static void omap24xxcam_clock_on(struct omap24xxcam_device *cam)
+{
+ clk_enable(cam->fck);
+ clk_enable(cam->ick);
+}
+
+static void omap24xxcam_clock_off(struct omap24xxcam_device *cam)
+{
+ clk_disable(cam->fck);
+ clk_disable(cam->ick);
+}
+
+/*
+ *
+ * Camera core
+ *
+ */
+
+/*
+ * Set xclk.
+ *
+ * To disable xclk, use value zero.
+ */
+static void omap24xxcam_core_xclk_set(const struct omap24xxcam_device *cam,
+ u32 xclk)
+{
+ if (xclk) {
+ u32 divisor = CAM_MCLK / xclk;
+
+ if (divisor == 1)
+ omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET,
+ CC_CTRL_XCLK,
+ CC_CTRL_XCLK_DIV_BYPASS);
+ else
+ omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET,
+ CC_CTRL_XCLK, divisor);
+ } else
+ omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET,
+ CC_CTRL_XCLK, CC_CTRL_XCLK_DIV_STABLE_LOW);
+}
+
+static void omap24xxcam_core_hwinit(const struct omap24xxcam_device *cam)
+{
+ /*
+ * Setting the camera core AUTOIDLE bit causes problems with frame
+ * synchronization, so we will clear the AUTOIDLE bit instead.
+ */
+ omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_SYSCONFIG,
+ CC_SYSCONFIG_AUTOIDLE);
+
+ /* program the camera interface DMA packet size */
+ omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_CTRL_DMA,
+ CC_CTRL_DMA_EN | (DMA_THRESHOLD / 4 - 1));
+
+ /* enable camera core error interrupts */
+ omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_IRQENABLE,
+ CC_IRQENABLE_FW_ERR_IRQ
+ | CC_IRQENABLE_FSC_ERR_IRQ
+ | CC_IRQENABLE_SSC_ERR_IRQ
+ | CC_IRQENABLE_FIFO_OF_IRQ);
+}
+
+/*
+ * Enable the camera core.
+ *
+ * Data transfer to the camera DMA starts from next starting frame.
+ */
+static void omap24xxcam_core_enable(const struct omap24xxcam_device *cam)
+{
+
+ omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_CTRL,
+ cam->cc_ctrl);
+}
+
+/*
+ * Disable camera core.
+ *
+ * The data transfer will be stopped immediately (CC_CTRL_CC_RST). The
+ * core internal state machines will be reset. Use
+ * CC_CTRL_CC_FRAME_TRIG instead if you want to transfer the current
+ * frame completely.
+ */
+static void omap24xxcam_core_disable(const struct omap24xxcam_device *cam)
+{
+ omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_CTRL,
+ CC_CTRL_CC_RST);
+}
+
+/* Interrupt service routine for camera core interrupts. */
+static void omap24xxcam_core_isr(struct omap24xxcam_device *cam)
+{
+ u32 cc_irqstatus;
+ const u32 cc_irqstatus_err =
+ CC_IRQSTATUS_FW_ERR_IRQ
+ | CC_IRQSTATUS_FSC_ERR_IRQ
+ | CC_IRQSTATUS_SSC_ERR_IRQ
+ | CC_IRQSTATUS_FIFO_UF_IRQ
+ | CC_IRQSTATUS_FIFO_OF_IRQ;
+
+ cc_irqstatus = omap24xxcam_reg_in(cam->mmio_base + CC_REG_OFFSET,
+ CC_IRQSTATUS);
+ omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_IRQSTATUS,
+ cc_irqstatus);
+
+ if (cc_irqstatus & cc_irqstatus_err
+ && !atomic_read(&cam->in_reset)) {
+ dev_dbg(cam->dev, "resetting camera, cc_irqstatus 0x%x\n",
+ cc_irqstatus);
+ omap24xxcam_reset(cam);
+ }
+}
+
+/*
+ *
+ * videobuf_buffer handling.
+ *
+ * Memory for mmapped videobuf_buffers is not allocated
+ * conventionally, but by several kmalloc allocations and then
+ * creating the scatterlist on our own. User-space buffers are handled
+ * normally.
+ *
+ */
+
+/*
+ * Free the memory-mapped buffer memory allocated for a
+ * videobuf_buffer and the associated scatterlist.
+ */
+static void omap24xxcam_vbq_free_mmap_buffer(struct videobuf_buffer *vb)
+{
+ struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
+ size_t alloc_size;
+ struct page *page;
+ int i;
+
+ if (dma->sglist == NULL)
+ return;
+
+ i = dma->sglen;
+ while (i) {
+ i--;
+ alloc_size = sg_dma_len(&dma->sglist[i]);
+ page = sg_page(&dma->sglist[i]);
+ do {
+ ClearPageReserved(page++);
+ } while (alloc_size -= PAGE_SIZE);
+ __free_pages(sg_page(&dma->sglist[i]),
+ get_order(sg_dma_len(&dma->sglist[i])));
+ }
+
+ kfree(dma->sglist);
+ dma->sglist = NULL;
+}
+
+/* Release all memory related to the videobuf_queue. */
+static void omap24xxcam_vbq_free_mmap_buffers(struct videobuf_queue *vbq)
+{
+ int i;
+
+ mutex_lock(&vbq->vb_lock);
+
+ for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+ if (NULL == vbq->bufs[i])
+ continue;
+ if (V4L2_MEMORY_MMAP != vbq->bufs[i]->memory)
+ continue;
+ vbq->ops->buf_release(vbq, vbq->bufs[i]);
+ omap24xxcam_vbq_free_mmap_buffer(vbq->bufs[i]);
+ kfree(vbq->bufs[i]);
+ vbq->bufs[i] = NULL;
+ }
+
+ mutex_unlock(&vbq->vb_lock);
+
+ videobuf_mmap_free(vbq);
+}
+
+/*
+ * Allocate physically as contiguous as possible buffer for video
+ * frame and allocate and build DMA scatter-gather list for it.
+ */
+static int omap24xxcam_vbq_alloc_mmap_buffer(struct videobuf_buffer *vb)
+{
+ unsigned int order;
+ size_t alloc_size, size = vb->bsize; /* vb->bsize is page aligned */
+ struct page *page;
+ int max_pages, err = 0, i = 0;
+ struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
+
+ /*
+ * allocate maximum size scatter-gather list. Note this is
+ * overhead. We may not use as many entries as we allocate
+ */
+ max_pages = vb->bsize >> PAGE_SHIFT;
+ dma->sglist = kcalloc(max_pages, sizeof(*dma->sglist), GFP_KERNEL);
+ if (dma->sglist == NULL) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ while (size) {
+ order = get_order(size);
+ /*
+ * do not over-allocate even if we would get larger
+ * contiguous chunk that way
+ */
+ if ((PAGE_SIZE << order) > size)
+ order--;
+
+ /* try to allocate as many contiguous pages as possible */
+ page = alloc_pages(GFP_KERNEL | GFP_DMA, order);
+ /* if allocation fails, try to allocate smaller amount */
+ while (page == NULL) {
+ order--;
+ page = alloc_pages(GFP_KERNEL | GFP_DMA, order);
+ if (page == NULL && !order) {
+ err = -ENOMEM;
+ goto out;
+ }
+ }
+ size -= (PAGE_SIZE << order);
+
+ /* append allocated chunk of pages into scatter-gather list */
+ sg_set_page(&dma->sglist[i], page, PAGE_SIZE << order, 0);
+ dma->sglen++;
+ i++;
+
+ alloc_size = (PAGE_SIZE << order);
+
+ /* clear pages before giving them to user space */
+ memset(page_address(page), 0, alloc_size);
+
+ /* mark allocated pages reserved */
+ do {
+ SetPageReserved(page++);
+ } while (alloc_size -= PAGE_SIZE);
+ }
+ /*
+ * REVISIT: not fully correct to assign nr_pages == sglen but
+ * video-buf is passing nr_pages for e.g. unmap_sg calls
+ */
+ dma->nr_pages = dma->sglen;
+ dma->direction = PCI_DMA_FROMDEVICE;
+
+ return 0;
+
+out:
+ omap24xxcam_vbq_free_mmap_buffer(vb);
+ return err;
+}
+
+static int omap24xxcam_vbq_alloc_mmap_buffers(struct videobuf_queue *vbq,
+ unsigned int count)
+{
+ int i, err = 0;
+ struct omap24xxcam_fh *fh =
+ container_of(vbq, struct omap24xxcam_fh, vbq);
+
+ mutex_lock(&vbq->vb_lock);
+
+ for (i = 0; i < count; i++) {
+ err = omap24xxcam_vbq_alloc_mmap_buffer(vbq->bufs[i]);
+ if (err)
+ goto out;
+ dev_dbg(fh->cam->dev, "sglen is %d for buffer %d\n",
+ videobuf_to_dma(vbq->bufs[i])->sglen, i);
+ }
+
+ mutex_unlock(&vbq->vb_lock);
+
+ return 0;
+out:
+ while (i) {
+ i--;
+ omap24xxcam_vbq_free_mmap_buffer(vbq->bufs[i]);
+ }
+
+ mutex_unlock(&vbq->vb_lock);
+
+ return err;
+}
+
+/*
+ * This routine is called from interrupt context when a scatter-gather DMA
+ * transfer of a videobuf_buffer completes.
+ */
+static void omap24xxcam_vbq_complete(struct omap24xxcam_sgdma *sgdma,
+ u32 csr, void *arg)
+{
+ struct omap24xxcam_device *cam =
+ container_of(sgdma, struct omap24xxcam_device, sgdma);
+ struct omap24xxcam_fh *fh = cam->streaming->private_data;
+ struct videobuf_buffer *vb = (struct videobuf_buffer *)arg;
+ const u32 csr_error = CAMDMA_CSR_MISALIGNED_ERR
+ | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR
+ | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cam->core_enable_disable_lock, flags);
+ if (--cam->sgdma_in_queue == 0)
+ omap24xxcam_core_disable(cam);
+ spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags);
+
+ do_gettimeofday(&vb->ts);
+ vb->field_count = atomic_add_return(2, &fh->field_count);
+ if (csr & csr_error) {
+ vb->state = VIDEOBUF_ERROR;
+ if (!atomic_read(&fh->cam->in_reset)) {
+ dev_dbg(cam->dev, "resetting camera, csr 0x%x\n", csr);
+ omap24xxcam_reset(cam);
+ }
+ } else
+ vb->state = VIDEOBUF_DONE;
+ wake_up(&vb->done);
+}
+
+static void omap24xxcam_vbq_release(struct videobuf_queue *vbq,
+ struct videobuf_buffer *vb)
+{
+ struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
+
+ /* wait for buffer, especially to get out of the sgdma queue */
+ videobuf_waiton(vb, 0, 0);
+ if (vb->memory == V4L2_MEMORY_MMAP) {
+ dma_unmap_sg(vbq->dev, dma->sglist, dma->sglen,
+ dma->direction);
+ dma->direction = DMA_NONE;
+ } else {
+ videobuf_dma_unmap(vbq, videobuf_to_dma(vb));
+ videobuf_dma_free(videobuf_to_dma(vb));
+ }
+
+ vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+/*
+ * Limit the number of available kernel image capture buffers based on the
+ * number requested, the currently selected image size, and the maximum
+ * amount of memory permitted for kernel capture buffers.
+ */
+static int omap24xxcam_vbq_setup(struct videobuf_queue *vbq, unsigned int *cnt,
+ unsigned int *size)
+{
+ struct omap24xxcam_fh *fh = vbq->priv_data;
+
+ if (*cnt <= 0)
+ *cnt = VIDEO_MAX_FRAME; /* supply a default number of buffers */
+
+ if (*cnt > VIDEO_MAX_FRAME)
+ *cnt = VIDEO_MAX_FRAME;
+
+ *size = fh->pix.sizeimage;
+
+ /* accessing fh->cam->capture_mem is ok, it's constant */
+ while (*size * *cnt > fh->cam->capture_mem)
+ (*cnt)--;
+
+ return 0;
+}
+
+static int omap24xxcam_dma_iolock(struct videobuf_queue *vbq,
+ struct videobuf_dmabuf *dma)
+{
+ int err = 0;
+
+ dma->direction = PCI_DMA_FROMDEVICE;
+ if (!dma_map_sg(vbq->dev, dma->sglist, dma->sglen, dma->direction)) {
+ kfree(dma->sglist);
+ dma->sglist = NULL;
+ dma->sglen = 0;
+ err = -EIO;
+ }
+
+ return err;
+}
+
+static int omap24xxcam_vbq_prepare(struct videobuf_queue *vbq,
+ struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct omap24xxcam_fh *fh = vbq->priv_data;
+ int err = 0;
+
+ /*
+ * Accessing pix here is okay since it's constant while
+ * streaming is on (and we only get called then).
+ */
+ if (vb->baddr) {
+ /* This is a userspace buffer. */
+ if (fh->pix.sizeimage > vb->bsize) {
+ /* The buffer isn't big enough. */
+ err = -EINVAL;
+ } else
+ vb->size = fh->pix.sizeimage;
+ } else {
+ if (vb->state != VIDEOBUF_NEEDS_INIT) {
+ /*
+ * We have a kernel bounce buffer that has
+ * already been allocated.
+ */
+ if (fh->pix.sizeimage > vb->size) {
+ /*
+ * The image size has been changed to
+ * a larger size since this buffer was
+ * allocated, so we need to free and
+ * reallocate it.
+ */
+ omap24xxcam_vbq_release(vbq, vb);
+ vb->size = fh->pix.sizeimage;
+ }
+ } else {
+ /* We need to allocate a new kernel bounce buffer. */
+ vb->size = fh->pix.sizeimage;
+ }
+ }
+
+ if (err)
+ return err;
+
+ vb->width = fh->pix.width;
+ vb->height = fh->pix.height;
+ vb->field = field;
+
+ if (vb->state == VIDEOBUF_NEEDS_INIT) {
+ if (vb->memory == V4L2_MEMORY_MMAP)
+ /*
+ * we have built the scatter-gather list by ourself so
+ * do the scatter-gather mapping as well
+ */
+ err = omap24xxcam_dma_iolock(vbq, videobuf_to_dma(vb));
+ else
+ err = videobuf_iolock(vbq, vb, NULL);
+ }
+
+ if (!err)
+ vb->state = VIDEOBUF_PREPARED;
+ else
+ omap24xxcam_vbq_release(vbq, vb);
+
+ return err;
+}
+
+static void omap24xxcam_vbq_queue(struct videobuf_queue *vbq,
+ struct videobuf_buffer *vb)
+{
+ struct omap24xxcam_fh *fh = vbq->priv_data;
+ struct omap24xxcam_device *cam = fh->cam;
+ enum videobuf_state state = vb->state;
+ unsigned long flags;
+ int err;
+
+ /*
+ * FIXME: We're marking the buffer active since we have no
+ * pretty way of marking it active exactly when the
+ * scatter-gather transfer starts.
+ */
+ vb->state = VIDEOBUF_ACTIVE;
+
+ err = omap24xxcam_sgdma_queue(&fh->cam->sgdma,
+ videobuf_to_dma(vb)->sglist,
+ videobuf_to_dma(vb)->sglen, vb->size,
+ omap24xxcam_vbq_complete, vb);
+
+ if (!err) {
+ spin_lock_irqsave(&cam->core_enable_disable_lock, flags);
+ if (++cam->sgdma_in_queue == 1
+ && !atomic_read(&cam->in_reset))
+ omap24xxcam_core_enable(cam);
+ spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags);
+ } else {
+ /*
+ * Oops. We're not supposed to get any errors here.
+ * The only way we could get an error is if we ran out
+ * of scatter-gather DMA slots, but we are supposed to
+ * have at least as many scatter-gather DMA slots as
+ * video buffers so that can't happen.
+ */
+ dev_err(cam->dev, "failed to queue a video buffer for dma!\n");
+ dev_err(cam->dev, "likely a bug in the driver!\n");
+ vb->state = state;
+ }
+}
+
+static struct videobuf_queue_ops omap24xxcam_vbq_ops = {
+ .buf_setup = omap24xxcam_vbq_setup,
+ .buf_prepare = omap24xxcam_vbq_prepare,
+ .buf_queue = omap24xxcam_vbq_queue,
+ .buf_release = omap24xxcam_vbq_release,
+};
+
+/*
+ *
+ * OMAP main camera system
+ *
+ */
+
+/*
+ * Reset camera block to power-on state.
+ */
+static void omap24xxcam_poweron_reset(const struct omap24xxcam_device *cam)
+{
+ int max_loop = RESET_TIMEOUT_NS;
+
+ /* Reset whole camera subsystem */
+ omap24xxcam_reg_out(cam->mmio_base,
+ CAM_SYSCONFIG,
+ CAM_SYSCONFIG_SOFTRESET);
+
+ /* Wait till it's finished */
+ while (!(omap24xxcam_reg_in(cam->mmio_base, CAM_SYSSTATUS)
+ & CAM_SYSSTATUS_RESETDONE)
+ && --max_loop) {
+ ndelay(1);
+ }
+
+ if (!(omap24xxcam_reg_in(cam->mmio_base, CAM_SYSSTATUS)
+ & CAM_SYSSTATUS_RESETDONE))
+ dev_err(cam->dev, "camera soft reset timeout\n");
+}
+
+/*
+ * (Re)initialise the camera block.
+ */
+static void omap24xxcam_hwinit(const struct omap24xxcam_device *cam)
+{
+ omap24xxcam_poweron_reset(cam);
+
+ /* set the camera subsystem autoidle bit */
+ omap24xxcam_reg_out(cam->mmio_base, CAM_SYSCONFIG,
+ CAM_SYSCONFIG_AUTOIDLE);
+
+ /* set the camera MMU autoidle bit */
+ omap24xxcam_reg_out(cam->mmio_base,
+ CAMMMU_REG_OFFSET + CAMMMU_SYSCONFIG,
+ CAMMMU_SYSCONFIG_AUTOIDLE);
+
+ omap24xxcam_core_hwinit(cam);
+
+ omap24xxcam_dma_hwinit(&cam->sgdma.dma);
+}
+
+/*
+ * Callback for dma transfer stalling.
+ */
+static void omap24xxcam_stalled_dma_reset(unsigned long data)
+{
+ struct omap24xxcam_device *cam = (struct omap24xxcam_device *)data;
+
+ if (!atomic_read(&cam->in_reset)) {
+ dev_dbg(cam->dev, "dma stalled, resetting camera\n");
+ omap24xxcam_reset(cam);
+ }
+}
+
+/*
+ * Stop capture. Mark we're doing a reset, stop DMA transfers and
+ * core. (No new scatter-gather transfers will be queued whilst
+ * in_reset is non-zero.)
+ *
+ * If omap24xxcam_capture_stop is called from several places at
+ * once, only the first call will have an effect. Similarly, the last
+ * call omap24xxcam_streaming_cont will have effect.
+ *
+ * Serialisation is ensured by using cam->core_enable_disable_lock.
+ */
+static void omap24xxcam_capture_stop(struct omap24xxcam_device *cam)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&cam->core_enable_disable_lock, flags);
+
+ if (atomic_inc_return(&cam->in_reset) != 1) {
+ spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags);
+ return;
+ }
+
+ omap24xxcam_core_disable(cam);
+
+ spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags);
+
+ omap24xxcam_sgdma_sync(&cam->sgdma);
+}
+
+/*
+ * Reset and continue streaming.
+ *
+ * Note: Resetting the camera FIFO via the CC_RST bit in the CC_CTRL
+ * register is supposed to be sufficient to recover from a camera
+ * interface error, but it doesn't seem to be enough. If we only do
+ * that then subsequent image captures are out of sync by either one
+ * or two times DMA_THRESHOLD bytes. Resetting and re-initializing the
+ * entire camera subsystem prevents the problem with frame
+ * synchronization.
+ */
+static void omap24xxcam_capture_cont(struct omap24xxcam_device *cam)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&cam->core_enable_disable_lock, flags);
+
+ if (atomic_read(&cam->in_reset) != 1)
+ goto out;
+
+ omap24xxcam_hwinit(cam);
+
+ omap24xxcam_sensor_if_enable(cam);
+
+ omap24xxcam_sgdma_process(&cam->sgdma);
+
+ if (cam->sgdma_in_queue)
+ omap24xxcam_core_enable(cam);
+
+out:
+ atomic_dec(&cam->in_reset);
+ spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags);
+}
+
+static ssize_t
+omap24xxcam_streaming_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct omap24xxcam_device *cam = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%s\n", cam->streaming ? "active" : "inactive");
+}
+static DEVICE_ATTR(streaming, S_IRUGO, omap24xxcam_streaming_show, NULL);
+
+/*
+ * Stop capture and restart it. I.e. reset the camera during use.
+ */
+static void omap24xxcam_reset(struct omap24xxcam_device *cam)
+{
+ omap24xxcam_capture_stop(cam);
+ omap24xxcam_capture_cont(cam);
+}
+
+/*
+ * The main interrupt handler.
+ */
+static irqreturn_t omap24xxcam_isr(int irq, void *arg)
+{
+ struct omap24xxcam_device *cam = (struct omap24xxcam_device *)arg;
+ u32 irqstatus;
+ unsigned int irqhandled = 0;
+
+ irqstatus = omap24xxcam_reg_in(cam->mmio_base, CAM_IRQSTATUS);
+
+ if (irqstatus &
+ (CAM_IRQSTATUS_DMA_IRQ2 | CAM_IRQSTATUS_DMA_IRQ1
+ | CAM_IRQSTATUS_DMA_IRQ0)) {
+ omap24xxcam_dma_isr(&cam->sgdma.dma);
+ irqhandled = 1;
+ }
+ if (irqstatus & CAM_IRQSTATUS_CC_IRQ) {
+ omap24xxcam_core_isr(cam);
+ irqhandled = 1;
+ }
+ if (irqstatus & CAM_IRQSTATUS_MMU_IRQ)
+ dev_err(cam->dev, "unhandled camera MMU interrupt!\n");
+
+ return IRQ_RETVAL(irqhandled);
+}
+
+/*
+ *
+ * Sensor handling.
+ *
+ */
+
+/*
+ * Enable the external sensor interface. Try to negotiate interface
+ * parameters with the sensor and start using the new ones. The calls
+ * to sensor_if_enable and sensor_if_disable need not to be balanced.
+ */
+static int omap24xxcam_sensor_if_enable(struct omap24xxcam_device *cam)
+{
+ int rval;
+ struct v4l2_ifparm p;
+
+ rval = vidioc_int_g_ifparm(cam->sdev, &p);
+ if (rval) {
+ dev_err(cam->dev, "vidioc_int_g_ifparm failed with %d\n", rval);
+ return rval;
+ }
+
+ cam->if_type = p.if_type;
+
+ cam->cc_ctrl = CC_CTRL_CC_EN;
+
+ switch (p.if_type) {
+ case V4L2_IF_TYPE_BT656:
+ if (p.u.bt656.frame_start_on_rising_vs)
+ cam->cc_ctrl |= CC_CTRL_NOBT_SYNCHRO;
+ if (p.u.bt656.bt_sync_correct)
+ cam->cc_ctrl |= CC_CTRL_BT_CORRECT;
+ if (p.u.bt656.swap)
+ cam->cc_ctrl |= CC_CTRL_PAR_ORDERCAM;
+ if (p.u.bt656.latch_clk_inv)
+ cam->cc_ctrl |= CC_CTRL_PAR_CLK_POL;
+ if (p.u.bt656.nobt_hs_inv)
+ cam->cc_ctrl |= CC_CTRL_NOBT_HS_POL;
+ if (p.u.bt656.nobt_vs_inv)
+ cam->cc_ctrl |= CC_CTRL_NOBT_VS_POL;
+
+ switch (p.u.bt656.mode) {
+ case V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT:
+ cam->cc_ctrl |= CC_CTRL_PAR_MODE_NOBT8;
+ break;
+ case V4L2_IF_TYPE_BT656_MODE_NOBT_10BIT:
+ cam->cc_ctrl |= CC_CTRL_PAR_MODE_NOBT10;
+ break;
+ case V4L2_IF_TYPE_BT656_MODE_NOBT_12BIT:
+ cam->cc_ctrl |= CC_CTRL_PAR_MODE_NOBT12;
+ break;
+ case V4L2_IF_TYPE_BT656_MODE_BT_8BIT:
+ cam->cc_ctrl |= CC_CTRL_PAR_MODE_BT8;
+ break;
+ case V4L2_IF_TYPE_BT656_MODE_BT_10BIT:
+ cam->cc_ctrl |= CC_CTRL_PAR_MODE_BT10;
+ break;
+ default:
+ dev_err(cam->dev,
+ "bt656 interface mode %d not supported\n",
+ p.u.bt656.mode);
+ return -EINVAL;
+ }
+ /*
+ * The clock rate that the sensor wants has changed.
+ * We have to adjust the xclk from OMAP 2 side to
+ * match the sensor's wish as closely as possible.
+ */
+ if (p.u.bt656.clock_curr != cam->if_u.bt656.xclk) {
+ u32 xclk = p.u.bt656.clock_curr;
+ u32 divisor;
+
+ if (xclk == 0)
+ return -EINVAL;
+
+ if (xclk > CAM_MCLK)
+ xclk = CAM_MCLK;
+
+ divisor = CAM_MCLK / xclk;
+ if (divisor * xclk < CAM_MCLK)
+ divisor++;
+ if (CAM_MCLK / divisor < p.u.bt656.clock_min
+ && divisor > 1)
+ divisor--;
+ if (divisor > 30)
+ divisor = 30;
+
+ xclk = CAM_MCLK / divisor;
+
+ if (xclk < p.u.bt656.clock_min
+ || xclk > p.u.bt656.clock_max)
+ return -EINVAL;
+
+ cam->if_u.bt656.xclk = xclk;
+ }
+ omap24xxcam_core_xclk_set(cam, cam->if_u.bt656.xclk);
+ break;
+ default:
+ /* FIXME: how about other interfaces? */
+ dev_err(cam->dev, "interface type %d not supported\n",
+ p.if_type);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void omap24xxcam_sensor_if_disable(const struct omap24xxcam_device *cam)
+{
+ switch (cam->if_type) {
+ case V4L2_IF_TYPE_BT656:
+ omap24xxcam_core_xclk_set(cam, 0);
+ break;
+ }
+}
+
+/*
+ * Initialise the sensor hardware.
+ */
+static int omap24xxcam_sensor_init(struct omap24xxcam_device *cam)
+{
+ int err = 0;
+ struct v4l2_int_device *sdev = cam->sdev;
+
+ omap24xxcam_clock_on(cam);
+ err = omap24xxcam_sensor_if_enable(cam);
+ if (err) {
+ dev_err(cam->dev, "sensor interface could not be enabled at "
+ "initialisation, %d\n", err);
+ cam->sdev = NULL;
+ goto out;
+ }
+
+ /* power up sensor during sensor initialization */
+ vidioc_int_s_power(sdev, 1);
+
+ err = vidioc_int_dev_init(sdev);
+ if (err) {
+ dev_err(cam->dev, "cannot initialize sensor, error %d\n", err);
+ /* Sensor init failed --- it's nonexistent to us! */
+ cam->sdev = NULL;
+ goto out;
+ }
+
+ dev_info(cam->dev, "sensor is %s\n", sdev->name);
+
+out:
+ omap24xxcam_sensor_if_disable(cam);
+ omap24xxcam_clock_off(cam);
+
+ vidioc_int_s_power(sdev, 0);
+
+ return err;
+}
+
+static void omap24xxcam_sensor_exit(struct omap24xxcam_device *cam)
+{
+ if (cam->sdev)
+ vidioc_int_dev_exit(cam->sdev);
+}
+
+static void omap24xxcam_sensor_disable(struct omap24xxcam_device *cam)
+{
+ omap24xxcam_sensor_if_disable(cam);
+ omap24xxcam_clock_off(cam);
+ vidioc_int_s_power(cam->sdev, 0);
+}
+
+/*
+ * Power-up and configure camera sensor. It's ready for capturing now.
+ */
+static int omap24xxcam_sensor_enable(struct omap24xxcam_device *cam)
+{
+ int rval;
+
+ omap24xxcam_clock_on(cam);
+
+ omap24xxcam_sensor_if_enable(cam);
+
+ rval = vidioc_int_s_power(cam->sdev, 1);
+ if (rval)
+ goto out;
+
+ rval = vidioc_int_init(cam->sdev);
+ if (rval)
+ goto out;
+
+ return 0;
+
+out:
+ omap24xxcam_sensor_disable(cam);
+
+ return rval;
+}
+
+static void omap24xxcam_sensor_reset_work(struct work_struct *work)
+{
+ struct omap24xxcam_device *cam =
+ container_of(work, struct omap24xxcam_device,
+ sensor_reset_work);
+
+ if (atomic_read(&cam->reset_disable))
+ return;
+
+ omap24xxcam_capture_stop(cam);
+
+ if (vidioc_int_reset(cam->sdev) == 0) {
+ vidioc_int_init(cam->sdev);
+ } else {
+ /* Can't reset it by vidioc_int_reset. */
+ omap24xxcam_sensor_disable(cam);
+ omap24xxcam_sensor_enable(cam);
+ }
+
+ omap24xxcam_capture_cont(cam);
+}
+
+/*
+ *
+ * IOCTL interface.
+ *
+ */
+
+static int vidioc_querycap(struct file *file, void *fh,
+ struct v4l2_capability *cap)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+
+ strlcpy(cap->driver, CAM_NAME, sizeof(cap->driver));
+ strlcpy(cap->card, cam->vfd->name, sizeof(cap->card));
+ cap->version = OMAP24XXCAM_VERSION;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+
+ return 0;
+}
+
+static int vidioc_enum_fmt_cap(struct file *file, void *fh,
+ struct v4l2_fmtdesc *f)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ int rval;
+
+ rval = vidioc_int_enum_fmt_cap(cam->sdev, f);
+
+ return rval;
+}
+
+static int vidioc_g_fmt_cap(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ int rval;
+
+ mutex_lock(&cam->mutex);
+ rval = vidioc_int_g_fmt_cap(cam->sdev, f);
+ mutex_unlock(&cam->mutex);
+
+ return rval;
+}
+
+static int vidioc_s_fmt_cap(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ int rval;
+
+ mutex_lock(&cam->mutex);
+ if (cam->streaming) {
+ rval = -EBUSY;
+ goto out;
+ }
+
+ rval = vidioc_int_s_fmt_cap(cam->sdev, f);
+
+out:
+ mutex_unlock(&cam->mutex);
+
+ if (!rval) {
+ mutex_lock(&ofh->vbq.vb_lock);
+ ofh->pix = f->fmt.pix;
+ mutex_unlock(&ofh->vbq.vb_lock);
+ }
+
+ memset(f, 0, sizeof(*f));
+ vidioc_g_fmt_cap(file, fh, f);
+
+ return rval;
+}
+
+static int vidioc_try_fmt_cap(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ int rval;
+
+ mutex_lock(&cam->mutex);
+ rval = vidioc_int_try_fmt_cap(cam->sdev, f);
+ mutex_unlock(&cam->mutex);
+
+ return rval;
+}
+
+static int vidioc_reqbufs(struct file *file, void *fh,
+ struct v4l2_requestbuffers *b)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ int rval;
+
+ mutex_lock(&cam->mutex);
+ if (cam->streaming) {
+ mutex_unlock(&cam->mutex);
+ return -EBUSY;
+ }
+
+ omap24xxcam_vbq_free_mmap_buffers(&ofh->vbq);
+ mutex_unlock(&cam->mutex);
+
+ rval = videobuf_reqbufs(&ofh->vbq, b);
+
+ /*
+ * Either videobuf_reqbufs failed or the buffers are not
+ * memory-mapped (which would need special attention).
+ */
+ if (rval < 0 || b->memory != V4L2_MEMORY_MMAP)
+ goto out;
+
+ rval = omap24xxcam_vbq_alloc_mmap_buffers(&ofh->vbq, rval);
+ if (rval)
+ omap24xxcam_vbq_free_mmap_buffers(&ofh->vbq);
+
+out:
+ return rval;
+}
+
+static int vidioc_querybuf(struct file *file, void *fh,
+ struct v4l2_buffer *b)
+{
+ struct omap24xxcam_fh *ofh = fh;
+
+ return videobuf_querybuf(&ofh->vbq, b);
+}
+
+static int vidioc_qbuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+ struct omap24xxcam_fh *ofh = fh;
+
+ return videobuf_qbuf(&ofh->vbq, b);
+}
+
+static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ struct videobuf_buffer *vb;
+ int rval;
+
+videobuf_dqbuf_again:
+ rval = videobuf_dqbuf(&ofh->vbq, b, file->f_flags & O_NONBLOCK);
+ if (rval)
+ goto out;
+
+ vb = ofh->vbq.bufs[b->index];
+
+ mutex_lock(&cam->mutex);
+ /* _needs_reset returns -EIO if reset is required. */
+ rval = vidioc_int_g_needs_reset(cam->sdev, (void *)vb->baddr);
+ mutex_unlock(&cam->mutex);
+ if (rval == -EIO)
+ schedule_work(&cam->sensor_reset_work);
+ else
+ rval = 0;
+
+out:
+ /*
+ * This is a hack. We don't want to show -EIO to the user
+ * space. Requeue the buffer and try again if we're not doing
+ * this in non-blocking mode.
+ */
+ if (rval == -EIO) {
+ videobuf_qbuf(&ofh->vbq, b);
+ if (!(file->f_flags & O_NONBLOCK))
+ goto videobuf_dqbuf_again;
+ /*
+ * We don't have a videobuf_buffer now --- maybe next
+ * time...
+ */
+ rval = -EAGAIN;
+ }
+
+ return rval;
+}
+
+static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ int rval;
+
+ mutex_lock(&cam->mutex);
+ if (cam->streaming) {
+ rval = -EBUSY;
+ goto out;
+ }
+
+ rval = omap24xxcam_sensor_if_enable(cam);
+ if (rval) {
+ dev_dbg(cam->dev, "vidioc_int_g_ifparm failed\n");
+ goto out;
+ }
+
+ rval = videobuf_streamon(&ofh->vbq);
+ if (!rval) {
+ cam->streaming = file;
+ sysfs_notify(&cam->dev->kobj, NULL, "streaming");
+ }
+
+out:
+ mutex_unlock(&cam->mutex);
+
+ return rval;
+}
+
+static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ struct videobuf_queue *q = &ofh->vbq;
+ int rval;
+
+ atomic_inc(&cam->reset_disable);
+
+ flush_scheduled_work();
+
+ rval = videobuf_streamoff(q);
+ if (!rval) {
+ mutex_lock(&cam->mutex);
+ cam->streaming = NULL;
+ mutex_unlock(&cam->mutex);
+ sysfs_notify(&cam->dev->kobj, NULL, "streaming");
+ }
+
+ atomic_dec(&cam->reset_disable);
+
+ return rval;
+}
+
+static int vidioc_enum_input(struct file *file, void *fh,
+ struct v4l2_input *inp)
+{
+ if (inp->index > 0)
+ return -EINVAL;
+
+ strlcpy(inp->name, "camera", sizeof(inp->name));
+ inp->type = V4L2_INPUT_TYPE_CAMERA;
+
+ return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
+{
+ *i = 0;
+
+ return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *fh, unsigned int i)
+{
+ if (i > 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int vidioc_queryctrl(struct file *file, void *fh,
+ struct v4l2_queryctrl *a)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ int rval;
+
+ rval = vidioc_int_queryctrl(cam->sdev, a);
+
+ return rval;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *fh,
+ struct v4l2_control *a)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ int rval;
+
+ mutex_lock(&cam->mutex);
+ rval = vidioc_int_g_ctrl(cam->sdev, a);
+ mutex_unlock(&cam->mutex);
+
+ return rval;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *fh,
+ struct v4l2_control *a)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ int rval;
+
+ mutex_lock(&cam->mutex);
+ rval = vidioc_int_s_ctrl(cam->sdev, a);
+ mutex_unlock(&cam->mutex);
+
+ return rval;
+}
+
+static int vidioc_g_parm(struct file *file, void *fh,
+ struct v4l2_streamparm *a) {
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ int rval;
+
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ mutex_lock(&cam->mutex);
+ rval = vidioc_int_g_parm(cam->sdev, a);
+ mutex_unlock(&cam->mutex);
+
+ return rval;
+}
+
+static int vidioc_s_parm(struct file *file, void *fh,
+ struct v4l2_streamparm *a)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ struct v4l2_streamparm old_streamparm;
+ int rval;
+
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ mutex_lock(&cam->mutex);
+ if (cam->streaming) {
+ rval = -EBUSY;
+ goto out;
+ }
+
+ old_streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ rval = vidioc_int_g_parm(cam->sdev, &old_streamparm);
+ if (rval)
+ goto out;
+
+ rval = vidioc_int_s_parm(cam->sdev, a);
+ if (rval)
+ goto out;
+
+ rval = omap24xxcam_sensor_if_enable(cam);
+ /*
+ * Revert to old streaming parameters if enabling sensor
+ * interface with the new ones failed.
+ */
+ if (rval)
+ vidioc_int_s_parm(cam->sdev, &old_streamparm);
+
+out:
+ mutex_unlock(&cam->mutex);
+
+ return rval;
+}
+
+/*
+ *
+ * File operations.
+ *
+ */
+
+static unsigned int omap24xxcam_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct omap24xxcam_fh *fh = file->private_data;
+ struct omap24xxcam_device *cam = fh->cam;
+ struct videobuf_buffer *vb;
+
+ mutex_lock(&cam->mutex);
+ if (cam->streaming != file) {
+ mutex_unlock(&cam->mutex);
+ return POLLERR;
+ }
+ mutex_unlock(&cam->mutex);
+
+ mutex_lock(&fh->vbq.vb_lock);
+ if (list_empty(&fh->vbq.stream)) {
+ mutex_unlock(&fh->vbq.vb_lock);
+ return POLLERR;
+ }
+ vb = list_entry(fh->vbq.stream.next, struct videobuf_buffer, stream);
+ mutex_unlock(&fh->vbq.vb_lock);
+
+ poll_wait(file, &vb->done, wait);
+
+ if (vb->state == VIDEOBUF_DONE || vb->state == VIDEOBUF_ERROR)
+ return POLLIN | POLLRDNORM;
+
+ return 0;
+}
+
+static int omap24xxcam_mmap_buffers(struct file *file,
+ struct vm_area_struct *vma)
+{
+ struct omap24xxcam_fh *fh = file->private_data;
+ struct omap24xxcam_device *cam = fh->cam;
+ struct videobuf_queue *vbq = &fh->vbq;
+ unsigned int first, last, size, i, j;
+ int err = 0;
+
+ mutex_lock(&cam->mutex);
+ if (cam->streaming) {
+ mutex_unlock(&cam->mutex);
+ return -EBUSY;
+ }
+ mutex_unlock(&cam->mutex);
+ mutex_lock(&vbq->vb_lock);
+
+ /* look for first buffer to map */
+ for (first = 0; first < VIDEO_MAX_FRAME; first++) {
+ if (NULL == vbq->bufs[first])
+ continue;
+ if (V4L2_MEMORY_MMAP != vbq->bufs[first]->memory)
+ continue;
+ if (vbq->bufs[first]->boff == (vma->vm_pgoff << PAGE_SHIFT))
+ break;
+ }
+
+ /* look for last buffer to map */
+ for (size = 0, last = first; last < VIDEO_MAX_FRAME; last++) {
+ if (NULL == vbq->bufs[last])
+ continue;
+ if (V4L2_MEMORY_MMAP != vbq->bufs[last]->memory)
+ continue;
+ size += vbq->bufs[last]->bsize;
+ if (size == (vma->vm_end - vma->vm_start))
+ break;
+ }
+
+ size = 0;
+ for (i = first; i <= last; i++) {
+ struct videobuf_dmabuf *dma = videobuf_to_dma(vbq->bufs[i]);
+
+ for (j = 0; j < dma->sglen; j++) {
+ err = remap_pfn_range(
+ vma, vma->vm_start + size,
+ page_to_pfn(sg_page(&dma->sglist[j])),
+ sg_dma_len(&dma->sglist[j]), vma->vm_page_prot);
+ if (err)
+ goto out;
+ size += sg_dma_len(&dma->sglist[j]);
+ }
+ }
+
+out:
+ mutex_unlock(&vbq->vb_lock);
+
+ return err;
+}
+
+static int omap24xxcam_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct omap24xxcam_fh *fh = file->private_data;
+ int rval;
+
+ /* let the video-buf mapper check arguments and set-up structures */
+ rval = videobuf_mmap_mapper(&fh->vbq, vma);
+ if (rval)
+ return rval;
+
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+ /* do mapping to our allocated buffers */
+ rval = omap24xxcam_mmap_buffers(file, vma);
+ /*
+ * In case of error, free vma->vm_private_data allocated by
+ * videobuf_mmap_mapper.
+ */
+ if (rval)
+ kfree(vma->vm_private_data);
+
+ return rval;
+}
+
+static int omap24xxcam_open(struct inode *inode, struct file *file)
+{
+ int minor = iminor(inode);
+ struct omap24xxcam_device *cam = omap24xxcam.priv;
+ struct omap24xxcam_fh *fh;
+ struct v4l2_format format;
+
+ if (!cam || !cam->vfd || (cam->vfd->minor != minor))
+ return -ENODEV;
+
+ fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+ if (fh == NULL)
+ return -ENOMEM;
+
+ mutex_lock(&cam->mutex);
+ if (cam->sdev == NULL || !try_module_get(cam->sdev->module)) {
+ mutex_unlock(&cam->mutex);
+ goto out_try_module_get;
+ }
+
+ if (atomic_inc_return(&cam->users) == 1) {
+ omap24xxcam_hwinit(cam);
+ if (omap24xxcam_sensor_enable(cam)) {
+ mutex_unlock(&cam->mutex);
+ goto out_omap24xxcam_sensor_enable;
+ }
+ }
+ mutex_unlock(&cam->mutex);
+
+ fh->cam = cam;
+ mutex_lock(&cam->mutex);
+ vidioc_int_g_fmt_cap(cam->sdev, &format);
+ mutex_unlock(&cam->mutex);
+ /* FIXME: how about fh->pix when there are more users? */
+ fh->pix = format.fmt.pix;
+
+ file->private_data = fh;
+
+ spin_lock_init(&fh->vbq_lock);
+
+ videobuf_queue_sg_init(&fh->vbq, &omap24xxcam_vbq_ops, NULL,
+ &fh->vbq_lock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ V4L2_FIELD_NONE,
+ sizeof(struct videobuf_buffer), fh);
+
+ return 0;
+
+out_omap24xxcam_sensor_enable:
+ omap24xxcam_poweron_reset(cam);
+ module_put(cam->sdev->module);
+
+out_try_module_get:
+ kfree(fh);
+
+ return -ENODEV;
+}
+
+static int omap24xxcam_release(struct inode *inode, struct file *file)
+{
+ struct omap24xxcam_fh *fh = file->private_data;
+ struct omap24xxcam_device *cam = fh->cam;
+
+ atomic_inc(&cam->reset_disable);
+
+ flush_scheduled_work();
+
+ /* stop streaming capture */
+ videobuf_streamoff(&fh->vbq);
+
+ mutex_lock(&cam->mutex);
+ if (cam->streaming == file) {
+ cam->streaming = NULL;
+ mutex_unlock(&cam->mutex);
+ sysfs_notify(&cam->dev->kobj, NULL, "streaming");
+ } else {
+ mutex_unlock(&cam->mutex);
+ }
+
+ atomic_dec(&cam->reset_disable);
+
+ omap24xxcam_vbq_free_mmap_buffers(&fh->vbq);
+
+ /*
+ * Make sure the reset work we might have scheduled is not
+ * pending! It may be run *only* if we have users. (And it may
+ * not be scheduled anymore since streaming is already
+ * disabled.)
+ */
+ flush_scheduled_work();
+
+ mutex_lock(&cam->mutex);
+ if (atomic_dec_return(&cam->users) == 0) {
+ omap24xxcam_sensor_disable(cam);
+ omap24xxcam_poweron_reset(cam);
+ }
+ mutex_unlock(&cam->mutex);
+
+ file->private_data = NULL;
+
+ module_put(cam->sdev->module);
+ kfree(fh);
+
+ return 0;
+}
+
+static struct file_operations omap24xxcam_fops = {
+ .llseek = no_llseek,
+ .ioctl = video_ioctl2,
+ .poll = omap24xxcam_poll,
+ .mmap = omap24xxcam_mmap,
+ .open = omap24xxcam_open,
+ .release = omap24xxcam_release,
+};
+
+/*
+ *
+ * Power management.
+ *
+ */
+
+#ifdef CONFIG_PM
+static int omap24xxcam_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct omap24xxcam_device *cam = platform_get_drvdata(pdev);
+
+ if (atomic_read(&cam->users) == 0)
+ return 0;
+
+ if (!atomic_read(&cam->reset_disable))
+ omap24xxcam_capture_stop(cam);
+
+ omap24xxcam_sensor_disable(cam);
+ omap24xxcam_poweron_reset(cam);
+
+ return 0;
+}
+
+static int omap24xxcam_resume(struct platform_device *pdev)
+{
+ struct omap24xxcam_device *cam = platform_get_drvdata(pdev);
+
+ if (atomic_read(&cam->users) == 0)
+ return 0;
+
+ omap24xxcam_hwinit(cam);
+ omap24xxcam_sensor_enable(cam);
+
+ if (!atomic_read(&cam->reset_disable))
+ omap24xxcam_capture_cont(cam);
+
+ return 0;
+}
+#endif /* CONFIG_PM */
+
+/*
+ *
+ * Camera device (i.e. /dev/video).
+ *
+ */
+
+static int omap24xxcam_device_register(struct v4l2_int_device *s)
+{
+ struct omap24xxcam_device *cam = s->u.slave->master->priv;
+ struct video_device *vfd;
+ int rval;
+
+ /* We already have a slave. */
+ if (cam->sdev)
+ return -EBUSY;
+
+ cam->sdev = s;
+
+ if (device_create_file(cam->dev, &dev_attr_streaming) != 0) {
+ dev_err(cam->dev, "could not register sysfs entry\n");
+ rval = -EBUSY;
+ goto err;
+ }
+
+ /* initialize the video_device struct */
+ vfd = cam->vfd = video_device_alloc();
+ if (!vfd) {
+ dev_err(cam->dev, "could not allocate video device struct\n");
+ rval = -ENOMEM;
+ goto err;
+ }
+ vfd->release = video_device_release;
+
+ vfd->dev = cam->dev;
+
+ strlcpy(vfd->name, CAM_NAME, sizeof(vfd->name));
+ vfd->type = VID_TYPE_CAPTURE | VID_TYPE_CHROMAKEY;
+ vfd->fops = &omap24xxcam_fops;
+ vfd->priv = cam;
+ vfd->minor = -1;
+
+ vfd->vidioc_querycap = vidioc_querycap;
+ vfd->vidioc_enum_fmt_cap = vidioc_enum_fmt_cap;
+ vfd->vidioc_g_fmt_cap = vidioc_g_fmt_cap;
+ vfd->vidioc_s_fmt_cap = vidioc_s_fmt_cap;
+ vfd->vidioc_try_fmt_cap = vidioc_try_fmt_cap;
+ vfd->vidioc_reqbufs = vidioc_reqbufs;
+ vfd->vidioc_querybuf = vidioc_querybuf;
+ vfd->vidioc_qbuf = vidioc_qbuf;
+ vfd->vidioc_dqbuf = vidioc_dqbuf;
+ vfd->vidioc_streamon = vidioc_streamon;
+ vfd->vidioc_streamoff = vidioc_streamoff;
+ vfd->vidioc_enum_input = vidioc_enum_input;
+ vfd->vidioc_g_input = vidioc_g_input;
+ vfd->vidioc_s_input = vidioc_s_input;
+ vfd->vidioc_queryctrl = vidioc_queryctrl;
+ vfd->vidioc_g_ctrl = vidioc_g_ctrl;
+ vfd->vidioc_s_ctrl = vidioc_s_ctrl;
+ vfd->vidioc_g_parm = vidioc_g_parm;
+ vfd->vidioc_s_parm = vidioc_s_parm;
+
+ omap24xxcam_hwinit(cam);
+
+ rval = omap24xxcam_sensor_init(cam);
+ if (rval)
+ goto err;
+
+ if (video_register_device(vfd, VFL_TYPE_GRABBER, video_nr) < 0) {
+ dev_err(cam->dev, "could not register V4L device\n");
+ vfd->minor = -1;
+ rval = -EBUSY;
+ goto err;
+ }
+
+ omap24xxcam_poweron_reset(cam);
+
+ dev_info(cam->dev, "registered device video%d\n", vfd->minor);
+
+ return 0;
+
+err:
+ omap24xxcam_device_unregister(s);
+
+ return rval;
+}
+
+static void omap24xxcam_device_unregister(struct v4l2_int_device *s)
+{
+ struct omap24xxcam_device *cam = s->u.slave->master->priv;
+
+ omap24xxcam_sensor_exit(cam);
+
+ if (cam->vfd) {
+ if (cam->vfd->minor == -1) {
+ /*
+ * The device was never registered, so release the
+ * video_device struct directly.
+ */
+ video_device_release(cam->vfd);
+ } else {
+ /*
+ * The unregister function will release the
+ * video_device struct as well as
+ * unregistering it.
+ */
+ video_unregister_device(cam->vfd);
+ }
+ cam->vfd = NULL;
+ }
+
+ device_remove_file(cam->dev, &dev_attr_streaming);
+
+ cam->sdev = NULL;
+}
+
+static struct v4l2_int_master omap24xxcam_master = {
+ .attach = omap24xxcam_device_register,
+ .detach = omap24xxcam_device_unregister,
+};
+
+static struct v4l2_int_device omap24xxcam = {
+ .module = THIS_MODULE,
+ .name = CAM_NAME,
+ .type = v4l2_int_type_master,
+ .u = {
+ .master = &omap24xxcam_master
+ },
+};
+
+/*
+ *
+ * Driver initialisation and deinitialisation.
+ *
+ */
+
+static int __init omap24xxcam_probe(struct platform_device *pdev)
+{
+ struct omap24xxcam_device *cam;
+ struct resource *mem;
+ int irq;
+
+ cam = kzalloc(sizeof(*cam), GFP_KERNEL);
+ if (!cam) {
+ dev_err(&pdev->dev, "could not allocate memory\n");
+ goto err;
+ }
+
+ platform_set_drvdata(pdev, cam);
+
+ cam->dev = &pdev->dev;
+
+ /*
+ * Impose a lower limit on the amount of memory allocated for
+ * capture. We require at least enough memory to double-buffer
+ * QVGA (300KB).
+ */
+ if (capture_mem < 320 * 240 * 2 * 2)
+ capture_mem = 320 * 240 * 2 * 2;
+ cam->capture_mem = capture_mem;
+
+ /* request the mem region for the camera registers */
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ dev_err(cam->dev, "no mem resource?\n");
+ goto err;
+ }
+ if (!request_mem_region(mem->start, (mem->end - mem->start) + 1,
+ pdev->name)) {
+ dev_err(cam->dev,
+ "cannot reserve camera register I/O region\n");
+ goto err;
+ }
+ cam->mmio_base_phys = mem->start;
+ cam->mmio_size = (mem->end - mem->start) + 1;
+
+ /* map the region */
+ cam->mmio_base = (unsigned long)
+ ioremap_nocache(cam->mmio_base_phys, cam->mmio_size);
+ if (!cam->mmio_base) {
+ dev_err(cam->dev, "cannot map camera register I/O region\n");
+ goto err;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq <= 0) {
+ dev_err(cam->dev, "no irq for camera?\n");
+ goto err;
+ }
+
+ /* install the interrupt service routine */
+ if (request_irq(irq, omap24xxcam_isr, 0, CAM_NAME, cam)) {
+ dev_err(cam->dev,
+ "could not install interrupt service routine\n");
+ goto err;
+ }
+ cam->irq = irq;
+
+ if (omap24xxcam_clock_get(cam))
+ goto err;
+
+ INIT_WORK(&cam->sensor_reset_work, omap24xxcam_sensor_reset_work);
+
+ mutex_init(&cam->mutex);
+ spin_lock_init(&cam->core_enable_disable_lock);
+
+ omap24xxcam_sgdma_init(&cam->sgdma,
+ cam->mmio_base + CAMDMA_REG_OFFSET,
+ omap24xxcam_stalled_dma_reset,
+ (unsigned long)cam);
+
+ omap24xxcam.priv = cam;
+
+ if (v4l2_int_device_register(&omap24xxcam))
+ goto err;
+
+ return 0;
+
+err:
+ omap24xxcam_remove(pdev);
+ return -ENODEV;
+}
+
+static int omap24xxcam_remove(struct platform_device *pdev)
+{
+ struct omap24xxcam_device *cam = platform_get_drvdata(pdev);
+
+ if (!cam)
+ return 0;
+
+ if (omap24xxcam.priv != NULL)
+ v4l2_int_device_unregister(&omap24xxcam);
+ omap24xxcam.priv = NULL;
+
+ omap24xxcam_clock_put(cam);
+
+ if (cam->irq) {
+ free_irq(cam->irq, cam);
+ cam->irq = 0;
+ }
+
+ if (cam->mmio_base) {
+ iounmap((void *)cam->mmio_base);
+ cam->mmio_base = 0;
+ }
+
+ if (cam->mmio_base_phys) {
+ release_mem_region(cam->mmio_base_phys, cam->mmio_size);
+ cam->mmio_base_phys = 0;
+ }
+
+ kfree(cam);
+
+ return 0;
+}
+
+static struct platform_driver omap24xxcam_driver = {
+ .probe = omap24xxcam_probe,
+ .remove = omap24xxcam_remove,
+#ifdef CONFIG_PM
+ .suspend = omap24xxcam_suspend,
+ .resume = omap24xxcam_resume,
+#endif
+ .driver = {
+ .name = CAM_NAME,
+ },
+};
+
+/*
+ *
+ * Module initialisation and deinitialisation
+ *
+ */
+
+static int __init omap24xxcam_init(void)
+{
+ return platform_driver_register(&omap24xxcam_driver);
+}
+
+static void __exit omap24xxcam_cleanup(void)
+{
+ platform_driver_unregister(&omap24xxcam_driver);
+}
+
+MODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com>");
+MODULE_DESCRIPTION("OMAP24xx Video for Linux camera driver");
+MODULE_LICENSE("GPL");
+module_param(video_nr, int, 0);
+MODULE_PARM_DESC(video_nr,
+ "Minor number for video device (-1 ==> auto assign)");
+module_param(capture_mem, int, 0);
+MODULE_PARM_DESC(capture_mem, "Maximum amount of memory for capture "
+ "buffers (default 4800kiB)");
+
+module_init(omap24xxcam_init);
+module_exit(omap24xxcam_cleanup);
for your IBM server.
config PHANTOM
- tristate "Sensable PHANToM"
+ tristate "Sensable PHANToM (PCI)"
depends on PCI
help
Say Y here if you want to build a driver for Sensable PHANToM device.
+ This driver is only for PCI PHANToMs.
+
If you choose to build module, its name will be phantom. If unsure,
say N here.
tristate "Fujitsu Laptop Extras"
depends on X86
depends on ACPI
+ depends on INPUT
depends on BACKLIGHT_CLASS_DEVICE
---help---
This is a driver for laptops built by Fujitsu:
* P2xxx/P5xxx/S6xxx/S7xxx series Lifebooks
* Possibly other Fujitsu laptop models
+ * Tested with S6410 and S7020
- It adds support for LCD brightness control.
+ It adds support for LCD brightness control and some hotkeys.
If you have a Fujitsu laptop, say Y or M here.
+ config FUJITSU_LAPTOP_DEBUG
+ bool "Verbose debug mode for Fujitsu Laptop Extras"
+ depends on FUJITSU_LAPTOP
+ default n
+ ---help---
+ Enables extra debug output from the fujitsu extras driver, at the
+ expense of a slight increase in driver size.
+
+ If you are not sure, say N here.
+
config TC1100_WMI
tristate "HP Compaq TC1100 Tablet WMI Extras (EXPERIMENTAL)"
depends on X86 && !X86_64
This is a driver for the WMI extensions (wireless and bluetooth power
control) of the HP Compaq TC1100 tablet.
+ config HP_WMI
+ tristate "HP WMI extras"
+ depends on ACPI_WMI
+ depends on INPUT
+ depends on RFKILL
+ help
+ Say Y here if you want to support WMI-based hotkeys on HP laptops and
+ to read data from WMI such as docking or ambient light sensor state.
+
+ To compile this driver as a module, choose M here: the module will
+ be called hp-wmi.
+
config MSI_LAPTOP
tristate "MSI Laptop Extras"
depends on X86
If you have an MSI S270 laptop, say Y or M here.
+ config COMPAL_LAPTOP
+ tristate "Compal Laptop Extras"
+ depends on X86
+ depends on ACPI_EC
+ depends on BACKLIGHT_CLASS_DEVICE
+ ---help---
+ This is a driver for laptops built by Compal:
+
+ Compal FL90/IFL90
+ Compal FL91/IFL91
+ Compal FL92/JFL92
+ Compal FT00/IFT00
+
+ It adds support for Bluetooth, WLAN and LCD brightness control.
+
+ If you have an Compal FL9x/IFL9x/FT00 laptop, say Y or M here.
+
config SONY_LAPTOP
tristate "Sony Laptop Extras"
depends on X86 && ACPI
select INPUT
select NEW_LEDS
select LEDS_CLASS
+ select NET
+ select RFKILL
---help---
This is a driver for the IBM and Lenovo ThinkPad laptops. It adds
support for Fn-Fx key combinations, Bluetooth control, video
If you are not sure, say Y here.
config THINKPAD_ACPI_HOTKEY_POLL
- bool "Suport NVRAM polling for hot keys"
+ bool "Support NVRAM polling for hot keys"
depends on THINKPAD_ACPI
default y
---help---
depends on BACKLIGHT_CLASS_DEVICE
depends on HWMON
depends on EXPERIMENTAL
+
---help---
This driver supports the Fn-Fx keys on Eee PC laptops.
It also adds the ability to switch camera/wlan on/off.
- If you have an Eee PC laptop, say Y or M here.
+config OMAP_STI
+ bool "Serial Trace Interface support"
+ depends on ARCH_OMAP16XX || ARCH_OMAP24XX || ARCH_OMAP34XX
+ default n
+ help
+ Serial Trace Interface. The protocols suported for OMAP1/2/3 are
+ STI/CSTI/XTIv2 correspondingly.
+
+config OMAP_STI_CONSOLE
+ bool "STI console support"
+ depends on OMAP_STI
+ help
+ This enables a console driver by way of STI/XTI.
config ENCLOSURE_SERVICES
tristate "Enclosure Services"
config SGI_XP
tristate "Support communication between SGI SSIs"
- depends on IA64_GENERIC || IA64_SGI_SN2
+ depends on NET
+ depends on IA64_GENERIC || IA64_SGI_SN2 || IA64_SGI_UV || (X86_64 && SMP)
select IA64_UNCACHED_ALLOCATOR if IA64_GENERIC || IA64_SGI_SN2
select GENERIC_ALLOCATOR if IA64_GENERIC || IA64_SGI_SN2
+ select SGI_GRU if IA64_GENERIC || IA64_SGI_UV || (X86_64 && SMP)
---help---
An SGI machine can be divided into multiple Single System
Images which act independently of each other and have
this feature will allow for direct communication between SSIs
based on a network adapter and DMA messaging.
+ config HP_ILO
+ tristate "Channel interface driver for HP iLO/iLO2 processor"
+ depends on PCI
+ default n
+ help
+ The channel interface driver allows applications to communicate
+ with iLO/iLO2 management processors present on HP ProLiant
+ servers. Upon loading, the driver creates /dev/hpilo/dXccbN files,
+ which can be used to gather data from the management processor,
+ via read and write system calls.
+
+ To compile this driver as a module, choose M here: the
+ module will be called hpilo.
+
+ config SGI_GRU
+ tristate "SGI GRU driver"
+ depends on (X86_64 || IA64_SGI_UV || IA64_GENERIC) && SMP
+ default n
+ select MMU_NOTIFIER
+ ---help---
+ The GRU is a hardware resource located in the system chipset. The GRU
+ contains memory that can be mmapped into the user address space. This memory is
+ used to communicate with the GRU to perform functions such as load/store,
+ scatter/gather, bcopy, AMOs, etc. The GRU is directly accessed by user
+ instructions using user virtual addresses. GRU instructions (ex., bcopy) use
+ user virtual addresses for operands.
+
+ If you are not running on a SGI UV system, say N.
+
+ config SGI_GRU_DEBUG
+ bool "SGI GRU driver debug"
+ depends on SGI_GRU
+ default n
+ ---help---
+ This option enables addition debugging code for the SGI GRU driver. If
+ you are unsure, say N.
+
endif # MISC_DEVICES
obj-$(CONFIG_IBM_ASM) += ibmasm/
obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/
- obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o
- obj-$(CONFIG_ACER_WMI) += acer-wmi.o
+obj-$(CONFIG_OMAP_STI) += sti/
obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o
obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o
+ obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o
+ obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o
+ obj-$(CONFIG_ACER_WMI) += acer-wmi.o
obj-$(CONFIG_ATMEL_PWM) += atmel_pwm.o
obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o
obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o
+ obj-$(CONFIG_HP_WMI) += hp-wmi.o
obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o
obj-$(CONFIG_LKDTM) += lkdtm.o
obj-$(CONFIG_TIFM_CORE) += tifm_core.o
obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o
obj-$(CONFIG_KGDB_TESTS) += kgdbts.o
obj-$(CONFIG_SGI_XP) += sgi-xp/
+ obj-$(CONFIG_SGI_GRU) += sgi-gru/
+ obj-$(CONFIG_HP_ILO) += hpilo.o
config MMC_SDHCI
tristate "Secure Digital Host Controller Interface support"
- depends on PCI
+ depends on HAS_DMA
help
- This select the generic Secure Digital Host Controller Interface.
+ This selects the generic Secure Digital Host Controller Interface.
It is used by manufacturers such as Texas Instruments(R), Ricoh(R)
and Toshiba(R). Most controllers found in laptops are of this type.
+
+ If you have a controller with this interface, say Y or M here. You
+ also need to enable an appropriate bus interface.
+
+ If unsure, say N.
+
+ config MMC_SDHCI_PCI
+ tristate "SDHCI support on PCI bus"
+ depends on MMC_SDHCI && PCI
+ help
+ This selects the PCI Secure Digital Host Controller Interface.
+ Most controllers found today are PCI devices.
+
If you have a controller with this interface, say Y or M here.
If unsure, say N.
config MMC_RICOH_MMC
tristate "Ricoh MMC Controller Disabler (EXPERIMENTAL)"
- depends on PCI && EXPERIMENTAL && MMC_SDHCI
+ depends on MMC_SDHCI_PCI
help
This selects the disabler for the Ricoh MMC Controller. This
proprietary controller is unnecessary because the SDHCI driver
config MMC_OMAP
tristate "TI OMAP Multimedia Card Interface support"
- depends on ARCH_OMAP
+ depends on ARCH_OMAP1 || (ARCH_OMAP2 && ARCH_OMAP2420)
select TPS65010 if MACH_OMAP_H2
+ select OMAP_GPIO_SWITCH if MACH_NOKIA_N800
help
This selects the TI OMAP Multimedia card Interface.
If you have an OMAP board with a Multimedia Card slot,
say Y or M here.
If unsure, say N.
+
+config MMC_OMAP_HS
+ tristate "TI OMAP High Speed Multimedia Card Interface support"
+ depends on (ARCH_OMAP2 && ARCH_OMAP2430) || ARCH_OMAP3
+ select TWL4030_CORE if MACH_OMAP_2430SDP || MACH_OMAP_3430SDP
+ help
+ This selects the TI OMAP High Speed Multimedia card Interface.
+ If you have an OMAP2(2430) or OMAP3 board with a Multimedia Card slot,
+ say Y or M here.
+
+ If unsure, say N.
config MMC_WBSD
tristate "Winbond W83L51xD SD/MMC Card Interface support"
If unsure, say N.
+ config MMC_ATMELMCI
+ tristate "Atmel Multimedia Card Interface support"
+ depends on AVR32
+ help
+ This selects the Atmel Multimedia Card Interface driver. If
+ you have an AT32 (AVR32) platform with a Multimedia Card
+ slot, say Y or M here.
+
+ If unsure, say N.
+
config MMC_IMX
tristate "Motorola i.MX Multimedia Card Interface support"
depends on ARCH_IMX
If unsure, or if your system has no SPI master driver, say N.
+ config MMC_S3C
+ tristate "Samsung S3C SD/MMC Card Interface support"
+ depends on ARCH_S3C2410 && MMC
+ help
+ This selects a driver for the MCI interface found in
+ Samsung's S3C2410, S3C2412, S3C2440, S3C2442 CPUs.
+ If you have a board based on one of those and a MMC/SD
+ slot, say Y or M here.
+
+ If unsure, say N.
+
+ config MMC_SDRICOH_CS
+ tristate "MMC/SD driver for Ricoh Bay1Controllers (EXPERIMENTAL)"
+ depends on EXPERIMENTAL && MMC && PCI && PCMCIA
+ help
+ Say Y here if your Notebook reports a Ricoh Bay1Controller PCMCIA
+ card whenever you insert a MMC or SD card into the card slot.
+
+ To compile this driver as a module, choose M here: the
+ module will be called sdricoh_cs.
+
obj-$(CONFIG_MMC_PXA) += pxamci.o
obj-$(CONFIG_MMC_IMX) += imxmmc.o
obj-$(CONFIG_MMC_SDHCI) += sdhci.o
+ obj-$(CONFIG_MMC_SDHCI_PCI) += sdhci-pci.o
obj-$(CONFIG_MMC_RICOH_MMC) += ricoh_mmc.o
obj-$(CONFIG_MMC_WBSD) += wbsd.o
obj-$(CONFIG_MMC_AU1X) += au1xmmc.o
obj-$(CONFIG_MMC_OMAP) += omap.o
+obj-$(CONFIG_MMC_OMAP_HS) += omap_hsmmc.o
obj-$(CONFIG_MMC_AT91) += at91_mci.o
+ obj-$(CONFIG_MMC_ATMELMCI) += atmel-mci.o
obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o
obj-$(CONFIG_MMC_SPI) += mmc_spi.o
+ obj-$(CONFIG_MMC_S3C) += s3cmci.o
+ obj-$(CONFIG_MMC_SDRICOH_CS) += sdricoh_cs.o
/*
- * $Id: cmdlinepart.c,v 1.19 2005/11/07 11:14:19 gleixner Exp $
- *
* Read flash partition table from command line
*
* Copyright 2002 SYSGO Real-Time Solutions GmbH
unsigned long offset;
int i;
struct cmdline_mtd_partition *part;
- char *mtd_id = master->name;
+ const char *mtd_id = master->name;
/* parse command line */
if (!cmdline_parsed)
*
* This function needs to be visible for bootloaders.
*/
-static int mtdpart_setup(char *s)
+int mtdpart_setup(char *s)
{
cmdline = s;
return 1;
# drivers/mtd/nand/Kconfig
- # $Id: Kconfig,v 1.35 2005/11/07 11:14:30 gleixner Exp $
menuconfig MTD_NAND
tristate "NAND Device Support"
help
Support for NAND flash on Amstrad E3 (Delta).
+config MTD_NAND_OMAP2
+ tristate "NAND Flash device on OMAP2 and OMAP3"
+ depends on ARM && MTD_NAND && (ARCH_OMAP2 || ARCH_OMAP3)
+ help
+ Support for NAND flash on Texas Instruments OMAP2 and OMAP3 platforms.
+
+config MTD_NAND_OMAP
+ tristate "NAND Flash device on OMAP H3/H2/P2 boards"
+ depends on ARM && ARCH_OMAP1 && MTD_NAND && (MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_PERSEUS2)
+ help
+ Support for NAND flash on Texas Instruments H3/H2/P2 platforms.
+
+config MTD_NAND_OMAP_HW
+ bool "OMAP HW NAND Flash controller support"
+ depends on ARM && ARCH_OMAP16XX && MTD_NAND
+
+ help
+ Driver for TI OMAP16xx hardware NAND flash controller.
+
config MTD_NAND_TOTO
tristate "NAND Flash device on TOTO board"
depends on ARCH_OMAP && BROKEN
config MTD_NAND_BF5XX_HWECC
bool "BF5XX NAND Hardware ECC"
+ default y
depends on MTD_NAND_BF5XX
help
Enable the use of the BF5XX's internal ECC generator when
using NAND.
+ config MTD_NAND_BF5XX_BOOTROM_ECC
+ bool "Use Blackfin BootROM ECC Layout"
+ default n
+ depends on MTD_NAND_BF5XX_HWECC
+ help
+ If you wish to modify NAND pages and allow the Blackfin on-chip
+ BootROM to boot from them, say Y here. This is only necessary
+ if you are booting U-Boot out of NAND and you wish to update
+ U-Boot from Linux' userspace. Otherwise, you should say N here.
+
+ If unsure, say N.
+
config MTD_NAND_RTC_FROM4
tristate "Renesas Flash ROM 4-slot interface board (FROM_BOARD4)"
depends on SH_SOLUTION_ENGINE
If you say "m", the module will be called "cs553x_nand.ko".
- config MTD_NAND_AT91
- bool "Support for NAND Flash / SmartMedia on AT91"
- depends on ARCH_AT91
+ config MTD_NAND_ATMEL
+ tristate "Support for NAND Flash / SmartMedia on AT91 and AVR32"
+ depends on ARCH_AT91 || AVR32
help
Enables support for NAND Flash / Smart Media Card interface
- on Atmel AT91 processors.
+ on Atmel AT91 and AVR32 processors.
choice
- prompt "ECC management for NAND Flash / SmartMedia on AT91"
- depends on MTD_NAND_AT91
+ prompt "ECC management for NAND Flash / SmartMedia on AT91 / AVR32"
+ depends on MTD_NAND_ATMEL
- config MTD_NAND_AT91_ECC_HW
+ config MTD_NAND_ATMEL_ECC_HW
bool "Hardware ECC"
- depends on ARCH_AT91SAM9263 || ARCH_AT91SAM9260
+ depends on ARCH_AT91SAM9263 || ARCH_AT91SAM9260 || AVR32
help
- Uses hardware ECC provided by the at91sam9260/at91sam9263 chip
- instead of software ECC.
+ Use hardware ECC instead of software ECC when the chip
+ supports it.
+
The hardware ECC controller is capable of single bit error
correction and 2-bit random detection per page.
If unsure, say Y
- config MTD_NAND_AT91_ECC_SOFT
+ config MTD_NAND_ATMEL_ECC_SOFT
bool "Software ECC"
help
- Uses software ECC.
+ Use software ECC.
NB : hardware and software ECC schemes are incompatible.
If you switch from one to another, you'll have to erase your
mtd partition.
- config MTD_NAND_AT91_ECC_NONE
+ config MTD_NAND_ATMEL_ECC_NONE
bool "No ECC (testing only, DANGEROUS)"
depends on DEBUG_KERNEL
help
#
# linux/drivers/nand/Makefile
#
- # $Id: Makefile.common,v 1.15 2004/11/26 12:28:22 dedekind Exp $
obj-$(CONFIG_MTD_NAND) += nand.o nand_ecc.o
obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o
obj-$(CONFIG_MTD_NAND_NANDSIM) += nandsim.o
obj-$(CONFIG_MTD_NAND_CS553X) += cs553x_nand.o
obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o
- obj-$(CONFIG_MTD_NAND_AT91) += at91_nand.o
+ obj-$(CONFIG_MTD_NAND_ATMEL) += atmel_nand.o
+obj-$(CONFIG_MTD_NAND_OMAP) += omap-nand-flash.o
+obj-$(CONFIG_MTD_NAND_OMAP2) += omap2.o
+obj-$(CONFIG_MTD_NAND_OMAP_HW) += omap-hw.o
obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o
obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o
obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o
--- /dev/null
- if (dma_mapping_error(dma_dst)) {
+/*
+ * linux/drivers/mtd/onenand/omap2.c
+ *
+ * OneNAND driver for OMAP2 / OMAP3
+ *
+ * Copyright (C) 2005-2006 Nokia Corporation
+ *
+ * Author: Jarkko Lavinen <jarkko.lavinen@nokia.com> and Juha Yrjola
+ * IRQ and DMA support written by Timo Teras
+ *
+ * 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 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; see the file COPYING. If not, write to the Free Software
+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/onenand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+
+#include <asm/io.h>
+#include <asm/mach/flash.h>
+#include <asm/arch/gpmc.h>
+#include <asm/arch/onenand.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/gpmc.h>
+#include <asm/arch/pm.h>
+
+#include <linux/dma-mapping.h>
+#include <asm/dma-mapping.h>
+#include <asm/arch/dma.h>
+
+#include <asm/arch/board.h>
+
+#define DRIVER_NAME "omap2-onenand"
+
+#define ONENAND_IO_SIZE SZ_128K
+#define ONENAND_BUFRAM_SIZE (1024 * 5)
+
+struct omap2_onenand {
+ struct platform_device *pdev;
+ int gpmc_cs;
+ unsigned long phys_base;
+ int gpio_irq;
+ struct mtd_info mtd;
+ struct mtd_partition *parts;
+ struct onenand_chip onenand;
+ struct completion irq_done;
+ struct completion dma_done;
+ int dma_channel;
+ int freq;
+ int (*setup)(void __iomem *base, int freq);
+};
+
+static void omap2_onenand_dma_cb(int lch, u16 ch_status, void *data)
+{
+ struct omap2_onenand *c = data;
+
+ complete(&c->dma_done);
+}
+
+static irqreturn_t omap2_onenand_interrupt(int irq, void *dev_id)
+{
+ struct omap2_onenand *c = dev_id;
+
+ complete(&c->irq_done);
+
+ return IRQ_HANDLED;
+}
+
+static inline unsigned short read_reg(struct omap2_onenand *c, int reg)
+{
+ return readw(c->onenand.base + reg);
+}
+
+static inline void write_reg(struct omap2_onenand *c, unsigned short value,
+ int reg)
+{
+ writew(value, c->onenand.base + reg);
+}
+
+static void wait_err(char *msg, int state, unsigned int ctrl, unsigned int intr)
+{
+ printk(KERN_ERR "onenand_wait: %s! state %d ctrl 0x%04x intr 0x%04x\n",
+ msg, state, ctrl, intr);
+}
+
+static void wait_warn(char *msg, int state, unsigned int ctrl,
+ unsigned int intr)
+{
+ printk(KERN_WARNING "onenand_wait: %s! state %d ctrl 0x%04x "
+ "intr 0x%04x\n", msg, state, ctrl, intr);
+}
+
+static int omap2_onenand_wait(struct mtd_info *mtd, int state)
+{
+ struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd);
+ unsigned int intr = 0;
+ unsigned int ctrl;
+ unsigned long timeout;
+ u32 syscfg;
+
+ if (state == FL_RESETING) {
+ int i;
+
+ for (i = 0; i < 20; i++) {
+ udelay(1);
+ intr = read_reg(c, ONENAND_REG_INTERRUPT);
+ if (intr & ONENAND_INT_MASTER)
+ break;
+ }
+ ctrl = read_reg(c, ONENAND_REG_CTRL_STATUS);
+ if (ctrl & ONENAND_CTRL_ERROR) {
+ wait_err("controller error", state, ctrl, intr);
+ return -EIO;
+ }
+ if (!(intr & ONENAND_INT_RESET)) {
+ wait_err("timeout", state, ctrl, intr);
+ return -EIO;
+ }
+ return 0;
+ }
+
+ if (state != FL_READING) {
+ int result;
+
+ /* Turn interrupts on */
+ syscfg = read_reg(c, ONENAND_REG_SYS_CFG1);
+ syscfg |= ONENAND_SYS_CFG1_IOBE;
+ write_reg(c, syscfg, ONENAND_REG_SYS_CFG1);
+
+ INIT_COMPLETION(c->irq_done);
+ if (c->gpio_irq) {
+ result = omap_get_gpio_datain(c->gpio_irq);
+ if (result == -1) {
+ ctrl = read_reg(c, ONENAND_REG_CTRL_STATUS);
+ intr = read_reg(c, ONENAND_REG_INTERRUPT);
+ wait_err("gpio error", state, ctrl, intr);
+ return -EIO;
+ }
+ } else
+ result = 0;
+ if (result == 0) {
+ int retry_cnt = 0;
+retry:
+ result = wait_for_completion_timeout(&c->irq_done,
+ msecs_to_jiffies(20));
+ if (result == 0) {
+ /* Timeout after 20ms */
+ ctrl = read_reg(c, ONENAND_REG_CTRL_STATUS);
+ if (ctrl & ONENAND_CTRL_ONGO) {
+ /*
+ * The operation seems to be still going
+ * so give it some more time.
+ */
+ retry_cnt += 1;
+ if (retry_cnt < 3)
+ goto retry;
+ intr = read_reg(c,
+ ONENAND_REG_INTERRUPT);
+ wait_err("timeout", state, ctrl, intr);
+ return -EIO;
+ }
+ intr = read_reg(c, ONENAND_REG_INTERRUPT);
+ if ((intr & ONENAND_INT_MASTER) == 0)
+ wait_warn("timeout", state, ctrl, intr);
+ }
+ }
+ } else {
+ /* Turn interrupts off */
+ syscfg = read_reg(c, ONENAND_REG_SYS_CFG1);
+ syscfg &= ~ONENAND_SYS_CFG1_IOBE;
+ write_reg(c, syscfg, ONENAND_REG_SYS_CFG1);
+
+ timeout = jiffies + msecs_to_jiffies(20);
+ while (time_before(jiffies, timeout)) {
+ intr = read_reg(c, ONENAND_REG_INTERRUPT);
+ if (intr & ONENAND_INT_MASTER)
+ break;
+ }
+ }
+
+ intr = read_reg(c, ONENAND_REG_INTERRUPT);
+ ctrl = read_reg(c, ONENAND_REG_CTRL_STATUS);
+
+ if (intr & ONENAND_INT_READ) {
+ int ecc = read_reg(c, ONENAND_REG_ECC_STATUS);
+
+ if (ecc) {
+ unsigned int addr1, addr8;
+
+ addr1 = read_reg(c, ONENAND_REG_START_ADDRESS1);
+ addr8 = read_reg(c, ONENAND_REG_START_ADDRESS8);
+ if (ecc & ONENAND_ECC_2BIT_ALL) {
+ printk(KERN_ERR "onenand_wait: ECC error = "
+ "0x%04x, addr1 %#x, addr8 %#x\n",
+ ecc, addr1, addr8);
+ mtd->ecc_stats.failed++;
+ return -EBADMSG;
+ } else if (ecc & ONENAND_ECC_1BIT_ALL) {
+ printk(KERN_NOTICE "onenand_wait: correctable "
+ "ECC error = 0x%04x, addr1 %#x, "
+ "addr8 %#x\n", ecc, addr1, addr8);
+ mtd->ecc_stats.corrected++;
+ }
+ }
+ } else if (state == FL_READING) {
+ wait_err("timeout", state, ctrl, intr);
+ return -EIO;
+ }
+
+ if (ctrl & ONENAND_CTRL_ERROR) {
+ wait_err("controller error", state, ctrl, intr);
+ if (ctrl & ONENAND_CTRL_LOCK)
+ printk(KERN_ERR "onenand_wait: "
+ "Device is write protected!!!\n");
+ return -EIO;
+ }
+
+ if (ctrl & 0xFE9F)
+ wait_warn("unexpected controller status", state, ctrl, intr);
+
+ return 0;
+}
+
+static inline int omap2_onenand_bufferram_offset(struct mtd_info *mtd, int area)
+{
+ struct onenand_chip *this = mtd->priv;
+
+ if (ONENAND_CURRENT_BUFFERRAM(this)) {
+ if (area == ONENAND_DATARAM)
+ return mtd->writesize;
+ if (area == ONENAND_SPARERAM)
+ return mtd->oobsize;
+ }
+
+ return 0;
+}
+
+#if defined(CONFIG_ARCH_OMAP3) || defined(MULTI_OMAP2)
+
+static int omap3_onenand_read_bufferram(struct mtd_info *mtd, int area,
+ unsigned char *buffer, int offset,
+ size_t count)
+{
+ struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd);
+ struct onenand_chip *this = mtd->priv;
+ dma_addr_t dma_src, dma_dst;
+ int bram_offset;
+ unsigned long timeout;
+ void *buf = (void *)buffer;
+ size_t xtra;
+ volatile unsigned *done;
+
+ bram_offset = omap2_onenand_bufferram_offset(mtd, area) + area + offset;
+ if (bram_offset & 3 || (size_t)buf & 3 || count < 384)
+ goto out_copy;
+
+ if (buf >= high_memory) {
+ struct page *p1;
+
+ if (((size_t)buf & PAGE_MASK) !=
+ ((size_t)(buf + count - 1) & PAGE_MASK))
+ goto out_copy;
+ p1 = vmalloc_to_page(buf);
+ if (!p1)
+ goto out_copy;
+ buf = page_address(p1) + ((size_t)buf & ~PAGE_MASK);
+ }
+
+ xtra = count & 3;
+ if (xtra) {
+ count -= xtra;
+ memcpy(buf + count, this->base + bram_offset + count, xtra);
+ }
+
+ dma_src = c->phys_base + bram_offset;
+ dma_dst = dma_map_single(&c->pdev->dev, buf, count, DMA_FROM_DEVICE);
- if (dma_mapping_error(dma_dst)) {
++ if (dma_mapping_error(&c->pdev->dev, dma_dst)) {
+ dev_err(&c->pdev->dev,
+ "Couldn't DMA map a %d byte buffer\n",
+ count);
+ goto out_copy;
+ }
+
+ omap_set_dma_transfer_params(c->dma_channel, OMAP_DMA_DATA_TYPE_S32,
+ count >> 2, 1, 0, 0, 0);
+ omap_set_dma_src_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC,
+ dma_src, 0, 0);
+ omap_set_dma_dest_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC,
+ dma_dst, 0, 0);
+
+ INIT_COMPLETION(c->dma_done);
+ omap_start_dma(c->dma_channel);
+
+ timeout = jiffies + msecs_to_jiffies(20);
+ done = &c->dma_done.done;
+ while (time_before(jiffies, timeout))
+ if (*done)
+ break;
+
+ dma_unmap_single(&c->pdev->dev, dma_dst, count, DMA_FROM_DEVICE);
+
+ if (!*done) {
+ dev_err(&c->pdev->dev, "timeout waiting for DMA\n");
+ goto out_copy;
+ }
+
+ return 0;
+
+out_copy:
+ memcpy(buf, this->base + bram_offset, count);
+ return 0;
+}
+
+static int omap3_onenand_write_bufferram(struct mtd_info *mtd, int area,
+ const unsigned char *buffer,
+ int offset, size_t count)
+{
+ struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd);
+ struct onenand_chip *this = mtd->priv;
+ dma_addr_t dma_src, dma_dst;
+ int bram_offset;
+ unsigned long timeout;
+ void *buf = (void *)buffer;
+ volatile unsigned *done;
+
+ bram_offset = omap2_onenand_bufferram_offset(mtd, area) + area + offset;
+ if (bram_offset & 3 || (size_t)buf & 3 || count < 384)
+ goto out_copy;
+
+ /* panic_write() may be in an interrupt context */
+ if (in_interrupt())
+ goto out_copy;
+
+ if (buf >= high_memory) {
+ struct page *p1;
+
+ if (((size_t)buf & PAGE_MASK) !=
+ ((size_t)(buf + count - 1) & PAGE_MASK))
+ goto out_copy;
+ p1 = vmalloc_to_page(buf);
+ if (!p1)
+ goto out_copy;
+ buf = page_address(p1) + ((size_t)buf & ~PAGE_MASK);
+ }
+
+ dma_src = dma_map_single(&c->pdev->dev, buf, count, DMA_TO_DEVICE);
+ dma_dst = c->phys_base + bram_offset;
- if (dma_mapping_error(dma_dst)) {
++ if (dma_mapping_error(&c->pdev->dev, dma_dst)) {
+ dev_err(&c->pdev->dev,
+ "Couldn't DMA map a %d byte buffer\n",
+ count);
+ return -1;
+ }
+
+ omap_set_dma_transfer_params(c->dma_channel, OMAP_DMA_DATA_TYPE_S32,
+ count >> 2, 1, 0, 0, 0);
+ omap_set_dma_src_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC,
+ dma_src, 0, 0);
+ omap_set_dma_dest_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC,
+ dma_dst, 0, 0);
+
+ INIT_COMPLETION(c->dma_done);
+ omap_start_dma(c->dma_channel);
+
+ timeout = jiffies + msecs_to_jiffies(20);
+ done = &c->dma_done.done;
+ while (time_before(jiffies, timeout))
+ if (*done)
+ break;
+
+ dma_unmap_single(&c->pdev->dev, dma_dst, count, DMA_TO_DEVICE);
+
+ if (!*done) {
+ dev_err(&c->pdev->dev, "timeout waiting for DMA\n");
+ goto out_copy;
+ }
+
+ return 0;
+
+out_copy:
+ memcpy(this->base + bram_offset, buf, count);
+ return 0;
+}
+
+#else
+
+int omap3_onenand_read_bufferram(struct mtd_info *mtd, int area,
+ unsigned char *buffer, int offset,
+ size_t count);
+
+int omap3_onenand_write_bufferram(struct mtd_info *mtd, int area,
+ const unsigned char *buffer,
+ int offset, size_t count);
+
+#endif
+
+#if defined(CONFIG_ARCH_OMAP2) || defined(MULTI_OMAP2)
+
+static int omap2_onenand_read_bufferram(struct mtd_info *mtd, int area,
+ unsigned char *buffer, int offset,
+ size_t count)
+{
+ struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd);
+ struct onenand_chip *this = mtd->priv;
+ dma_addr_t dma_src, dma_dst;
+ int bram_offset;
+
+ bram_offset = omap2_onenand_bufferram_offset(mtd, area) + area + offset;
+ /* DMA is not used. Revisit PM requirements before enabling it. */
+ if (1 || (c->dma_channel < 0) ||
+ ((void *) buffer >= (void *) high_memory) || (bram_offset & 3) ||
+ (((unsigned int) buffer) & 3) || (count < 1024) || (count & 3)) {
+ memcpy(buffer, (__force void *)(this->base + bram_offset),
+ count);
+ return 0;
+ }
+
+ dma_src = c->phys_base + bram_offset;
+ dma_dst = dma_map_single(&c->pdev->dev, buffer, count,
+ DMA_FROM_DEVICE);
- if (dma_mapping_error(dma_dst)) {
++ if (dma_mapping_error(&c->pdev->dev, dma_dst)) {
+ dev_err(&c->pdev->dev,
+ "Couldn't DMA map a %d byte buffer\n",
+ count);
+ return -1;
+ }
+
+ omap_set_dma_transfer_params(c->dma_channel, OMAP_DMA_DATA_TYPE_S32,
+ count / 4, 1, 0, 0, 0);
+ omap_set_dma_src_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC,
+ dma_src, 0, 0);
+ omap_set_dma_dest_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC,
+ dma_dst, 0, 0);
+
+ INIT_COMPLETION(c->dma_done);
+ omap_start_dma(c->dma_channel);
+ wait_for_completion(&c->dma_done);
+
+ dma_unmap_single(&c->pdev->dev, dma_dst, count, DMA_FROM_DEVICE);
+
+ return 0;
+}
+
+static int omap2_onenand_write_bufferram(struct mtd_info *mtd, int area,
+ const unsigned char *buffer,
+ int offset, size_t count)
+{
+ struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd);
+ struct onenand_chip *this = mtd->priv;
+ dma_addr_t dma_src, dma_dst;
+ int bram_offset;
+
+ bram_offset = omap2_onenand_bufferram_offset(mtd, area) + area + offset;
+ /* DMA is not used. Revisit PM requirements before enabling it. */
+ if (1 || (c->dma_channel < 0) ||
+ ((void *) buffer >= (void *) high_memory) || (bram_offset & 3) ||
+ (((unsigned int) buffer) & 3) || (count < 1024) || (count & 3)) {
+ memcpy((__force void *)(this->base + bram_offset), buffer,
+ count);
+ return 0;
+ }
+
+ dma_src = dma_map_single(&c->pdev->dev, (void *) buffer, count,
+ DMA_TO_DEVICE);
+ dma_dst = c->phys_base + bram_offset;
++ if (dma_mapping_error(&c->pdev->dev, dma_dst)) {
+ dev_err(&c->pdev->dev,
+ "Couldn't DMA map a %d byte buffer\n",
+ count);
+ return -1;
+ }
+
+ omap_set_dma_transfer_params(c->dma_channel, OMAP_DMA_DATA_TYPE_S16,
+ count / 2, 1, 0, 0, 0);
+ omap_set_dma_src_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC,
+ dma_src, 0, 0);
+ omap_set_dma_dest_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC,
+ dma_dst, 0, 0);
+
+ INIT_COMPLETION(c->dma_done);
+ omap_start_dma(c->dma_channel);
+ wait_for_completion(&c->dma_done);
+
+ dma_unmap_single(&c->pdev->dev, dma_dst, count, DMA_TO_DEVICE);
+
+ return 0;
+}
+
+#else
+
+int omap2_onenand_read_bufferram(struct mtd_info *mtd, int area,
+ unsigned char *buffer, int offset,
+ size_t count);
+
+int omap2_onenand_write_bufferram(struct mtd_info *mtd, int area,
+ const unsigned char *buffer,
+ int offset, size_t count);
+
+#endif
+
+static struct platform_driver omap2_onenand_driver;
+
+static int __adjust_timing(struct device *dev, void *data)
+{
+ int ret = 0;
+ struct omap2_onenand *c;
+
+ c = dev_get_drvdata(dev);
+
+ BUG_ON(c->setup == NULL);
+
+ /* DMA is not in use so this is all that is needed */
+ /* Revisit for OMAP3! */
+ ret = c->setup(c->onenand.base, c->freq);
+
+ return ret;
+}
+
+int omap2_onenand_rephase(void)
+{
+ return driver_for_each_device(&omap2_onenand_driver.driver, NULL,
+ NULL, __adjust_timing);
+}
+
+static void __devexit omap2_onenand_shutdown(struct platform_device *pdev)
+{
+ struct omap2_onenand *c = dev_get_drvdata(&pdev->dev);
+
+ /* With certain content in the buffer RAM, the OMAP boot ROM code
+ * can recognize the flash chip incorrectly. Zero it out before
+ * soft reset.
+ */
+ memset((__force void *)c->onenand.base, 0, ONENAND_BUFRAM_SIZE);
+}
+
+static int __devinit omap2_onenand_probe(struct platform_device *pdev)
+{
+ struct omap_onenand_platform_data *pdata;
+ struct omap2_onenand *c;
+ int r;
+
+ pdata = pdev->dev.platform_data;
+ if (pdata == NULL) {
+ dev_err(&pdev->dev, "platform data missing\n");
+ return -ENODEV;
+ }
+
+ c = kzalloc(sizeof(struct omap2_onenand), GFP_KERNEL);
+ if (!c)
+ return -ENOMEM;
+
+ init_completion(&c->irq_done);
+ init_completion(&c->dma_done);
+ c->gpmc_cs = pdata->cs;
+ c->gpio_irq = pdata->gpio_irq;
+ c->dma_channel = pdata->dma_channel;
+ if (c->dma_channel < 0) {
+ /* if -1, don't use DMA */
+ c->gpio_irq = 0;
+ }
+
+ r = gpmc_cs_request(c->gpmc_cs, ONENAND_IO_SIZE, &c->phys_base);
+ if (r < 0) {
+ dev_err(&pdev->dev, "Cannot request GPMC CS\n");
+ goto err_kfree;
+ }
+
+ if (request_mem_region(c->phys_base, ONENAND_IO_SIZE,
+ pdev->dev.driver->name) == NULL) {
+ dev_err(&pdev->dev, "Cannot reserve memory region at 0x%08lx, "
+ "size: 0x%x\n", c->phys_base, ONENAND_IO_SIZE);
+ r = -EBUSY;
+ goto err_free_cs;
+ }
+ c->onenand.base = ioremap(c->phys_base, ONENAND_IO_SIZE);
+ if (c->onenand.base == NULL) {
+ r = -ENOMEM;
+ goto err_release_mem_region;
+ }
+
+ if (pdata->onenand_setup != NULL) {
+ r = pdata->onenand_setup(c->onenand.base, c->freq);
+ if (r < 0) {
+ dev_err(&pdev->dev, "Onenand platform setup failed: "
+ "%d\n", r);
+ goto err_iounmap;
+ }
+ c->setup = pdata->onenand_setup;
+ }
+
+ if (c->gpio_irq) {
+ if ((r = omap_request_gpio(c->gpio_irq)) < 0) {
+ dev_err(&pdev->dev, "Failed to request GPIO%d for "
+ "OneNAND\n", c->gpio_irq);
+ goto err_iounmap;
+ }
+ omap_set_gpio_direction(c->gpio_irq, 1);
+
+ if ((r = request_irq(OMAP_GPIO_IRQ(c->gpio_irq),
+ omap2_onenand_interrupt, IRQF_TRIGGER_RISING,
+ pdev->dev.driver->name, c)) < 0)
+ goto err_release_gpio;
+ }
+
+ if (c->dma_channel >= 0) {
+ r = omap_request_dma(0, pdev->dev.driver->name,
+ omap2_onenand_dma_cb, (void *) c,
+ &c->dma_channel);
+ if (r == 0) {
+ omap_set_dma_write_mode(c->dma_channel,
+ OMAP_DMA_WRITE_NON_POSTED);
+ omap_set_dma_src_data_pack(c->dma_channel, 1);
+ omap_set_dma_src_burst_mode(c->dma_channel,
+ OMAP_DMA_DATA_BURST_8);
+ omap_set_dma_dest_data_pack(c->dma_channel, 1);
+ omap_set_dma_dest_burst_mode(c->dma_channel,
+ OMAP_DMA_DATA_BURST_8);
+ } else {
+ dev_info(&pdev->dev,
+ "failed to allocate DMA for OneNAND, "
+ "using PIO instead\n");
+ c->dma_channel = -1;
+ }
+ }
+
+ dev_info(&pdev->dev, "initializing on CS%d, phys base 0x%08lx, virtual "
+ "base %p\n", c->gpmc_cs, c->phys_base,
+ c->onenand.base);
+
+ c->pdev = pdev;
+ c->mtd.name = pdev->dev.bus_id;
+ c->mtd.priv = &c->onenand;
+ c->mtd.owner = THIS_MODULE;
+
+ if (c->dma_channel >= 0) {
+ struct onenand_chip *this = &c->onenand;
+
+ this->wait = omap2_onenand_wait;
+ if (cpu_is_omap34xx()) {
+ this->read_bufferram = omap3_onenand_read_bufferram;
+ this->write_bufferram = omap3_onenand_write_bufferram;
+ } else {
+ this->read_bufferram = omap2_onenand_read_bufferram;
+ this->write_bufferram = omap2_onenand_write_bufferram;
+ }
+ }
+
+ if ((r = onenand_scan(&c->mtd, 1)) < 0)
+ goto err_release_dma;
+
+ switch ((c->onenand.version_id >> 4) & 0xf) {
+ case 0:
+ c->freq = 40;
+ break;
+ case 1:
+ c->freq = 54;
+ break;
+ case 2:
+ c->freq = 66;
+ break;
+ case 3:
+ c->freq = 83;
+ break;
+ }
+
+#ifdef CONFIG_MTD_PARTITIONS
+ if (pdata->parts != NULL)
+ r = add_mtd_partitions(&c->mtd, pdata->parts,
+ pdata->nr_parts);
+ else
+#endif
+ r = add_mtd_device(&c->mtd);
+ if (r < 0)
+ goto err_release_onenand;
+
+ platform_set_drvdata(pdev, c);
+
+ return 0;
+
+err_release_onenand:
+ onenand_release(&c->mtd);
+err_release_dma:
+ if (c->dma_channel != -1)
+ omap_free_dma(c->dma_channel);
+ if (c->gpio_irq)
+ free_irq(OMAP_GPIO_IRQ(c->gpio_irq), c);
+err_release_gpio:
+ if (c->gpio_irq)
+ omap_free_gpio(c->gpio_irq);
+err_iounmap:
+ iounmap(c->onenand.base);
+err_release_mem_region:
+ release_mem_region(c->phys_base, ONENAND_IO_SIZE);
+err_free_cs:
+ gpmc_cs_free(c->gpmc_cs);
+err_kfree:
+ kfree(c);
+
+ return r;
+}
+
+static int __devexit omap2_onenand_remove(struct platform_device *pdev)
+{
+ struct omap2_onenand *c = dev_get_drvdata(&pdev->dev);
+
+ BUG_ON(c == NULL);
+
+#ifdef CONFIG_MTD_PARTITIONS
+ if (c->parts)
+ del_mtd_partitions(&c->mtd);
+ else
+ del_mtd_device(&c->mtd);
+#else
+ del_mtd_device(&c->mtd);
+#endif
+
+ onenand_release(&c->mtd);
+ if (c->dma_channel != -1)
+ omap_free_dma(c->dma_channel);
+ omap2_onenand_shutdown(pdev);
+ platform_set_drvdata(pdev, NULL);
+ if (c->gpio_irq) {
+ free_irq(OMAP_GPIO_IRQ(c->gpio_irq), c);
+ omap_free_gpio(c->gpio_irq);
+ }
+ iounmap(c->onenand.base);
+ release_mem_region(c->phys_base, ONENAND_IO_SIZE);
+ kfree(c);
+
+ return 0;
+}
+
+static struct platform_driver omap2_onenand_driver = {
+ .probe = omap2_onenand_probe,
+ .remove = omap2_onenand_remove,
+ .shutdown = omap2_onenand_shutdown,
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init omap2_onenand_init(void)
+{
+ printk(KERN_INFO "OneNAND driver initializing\n");
+ return platform_driver_register(&omap2_onenand_driver);
+}
+
+static void __exit omap2_onenand_exit(void)
+{
+ platform_driver_unregister(&omap2_onenand_driver);
+}
+
+module_init(omap2_onenand_init);
+module_exit(omap2_onenand_exit);
+
+MODULE_ALIAS(DRIVER_NAME);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jarkko Lavinen <jarkko.lavinen@nokia.com>");
+MODULE_DESCRIPTION("Glue layer for OneNAND flash on OMAP2 / OMAP3");
# that for each of the symbols.
if NETDEVICES
- config NETDEVICES_MULTIQUEUE
- bool "Netdevice multiple hardware queue support"
- ---help---
- Say Y here if you want to allow the network stack to use multiple
- hardware TX queues on an ethernet device.
-
- Most people will say N here.
-
config IFB
tristate "Intermediate Functional Block support"
depends on NET_CLS_ACT
config MACB
tristate "Atmel MACB support"
- depends on AVR32 || ARCH_AT91SAM9260 || ARCH_AT91SAM9263 || ARCH_AT91CAP9
+ depends on AVR32 || ARCH_AT91SAM9260 || ARCH_AT91SAM9263 || ARCH_AT91SAM9G20 || ARCH_AT91CAP9
select PHYLIB
help
The Atmel MACB ethernet interface is found on many AT32 and AT91
To compile this driver as a module, choose M here: the module
will be called apne.
- config APOLLO_ELPLUS
- tristate "Apollo 3c505 support"
- depends on APOLLO
- help
- Say Y or M here if your Apollo has a 3Com 3c505 ISA Ethernet card.
- If you don't have one made for Apollos, you can use one from a PC,
- except that your Apollo won't be able to boot from it (because the
- code in the ROM will be for a PC).
-
config MAC8390
bool "Macintosh NS 8390 based ethernet cards"
depends on MAC
If unsure, say N.
+ config SH_ETH
+ tristate "Renesas SuperH Ethernet support"
+ depends on SUPERH && \
+ (CPU_SUBTYPE_SH7710 || CPU_SUBTYPE_SH7712 || CPU_SUBTYPE_SH7763)
+ select CRC32
+ select MII
+ select MDIO_BITBANG
+ select PHYLIB
+ help
+ Renesas SuperH Ethernet device driver.
+ This driver support SH7710, SH7712 and SH7763.
+
config SUNLANCE
tristate "Sun LANCE support"
depends on SBUS
To compile this driver as a module, choose M here. The module
will be called dm9000.
+ config DM9000_DEBUGLEVEL
+ int "DM9000 maximum debug level"
+ depends on DM9000
+ default 4
+ help
+ The maximum level of debugging code compiled into the DM9000
+ driver.
+
+ config DM9000_FORCE_SIMPLE_PHY_POLL
+ bool "Force simple NSR based PHY polling"
+ depends on DM9000
+ ---help---
+ This configuration forces the DM9000 to use the NSR's LinkStatus
+ bit to determine if the link is up or down instead of the more
+ costly MII PHY reads. Note, this will not work if the chip is
+ operating with an external PHY.
+
config ENC28J60
tristate "ENC28J60 support"
depends on EXPERIMENTAL && SPI && NET_ETHERNET
Enable the verify after the buffer write useful for debugging purpose.
If unsure, say N.
- config DM9000_DEBUGLEVEL
- int "DM9000 maximum debug level"
- depends on DM9000
- default 4
- help
- The maximum level of debugging code compiled into the DM9000
- driver.
-
config SMC911X
tristate "SMSC LAN911[5678] support"
select CRC32
select MII
- depends on ARCH_PXA || SH_MAGIC_PANEL_R2 || ARCH_OMAP24XX || ARCH_OMAP34XX
- depends on ARCH_PXA || SUPERH
++ depends on ARCH_PXA || SUPERH || SH_MAGIC_PANEL_R2 || ARCH_OMAP24XX || ARCH_OMAP34XX
help
This is a driver for SMSC's LAN911x series of Ethernet chipsets
including the new LAN9115, LAN9116, LAN9117, and LAN9118.
To compile this driver as a module, choose M here. The module will
be called ibmveth.
- source "drivers/net/ibm_emac/Kconfig"
source "drivers/net/ibm_newemac/Kconfig"
config NET_PCI
To compile this driver as a module, choose M here. The module
will be called amd8111e.
- config AMD8111E_NAPI
- bool "Use RX polling (NAPI)"
- depends on AMD8111_ETH
- help
- NAPI is a new driver API designed to reduce CPU and interrupt load
- when the driver is receiving lots of packets from the card. It is
- still somewhat experimental and thus not yet enabled by default.
-
- If your estimated Rx load is 10kpps or more, or if the card will be
- deployed on potentially unfriendly networks (e.g. in a firewall),
- then say Y here.
-
- If in doubt, say N.
-
config ADAPTEC_STARFIRE
tristate "Adaptec Starfire/DuraLAN support"
depends on NET_PCI && PCI
To compile this driver as a module, choose M here: the module
will be called starfire. This is recommended.
- config ADAPTEC_STARFIRE_NAPI
- bool "Use Rx Polling (NAPI) (EXPERIMENTAL)"
- depends on ADAPTEC_STARFIRE && EXPERIMENTAL
- help
- NAPI is a new driver API designed to reduce CPU and interrupt load
- when the driver is receiving lots of packets from the card. It is
- still somewhat experimental and thus not yet enabled by default.
-
- If your estimated Rx load is 10kpps or more, or if the card will be
- deployed on potentially unfriendly networks (e.g. in a firewall),
- then say Y here.
-
- If in doubt, say N.
-
config AC3200
tristate "Ansel Communications EISA 3200 support (EXPERIMENTAL)"
depends on NET_PCI && (ISA || EISA) && EXPERIMENTAL
config TLAN
tristate "TI ThunderLAN support"
- depends on NET_PCI && (PCI || EISA) && !64BIT
+ depends on NET_PCI && (PCI || EISA)
---help---
If you have a PCI Ethernet network card based on the ThunderLAN chip
which is supported by this driver, say Y and read the
If unsure, say Y.
- config VIA_RHINE_NAPI
- bool "Use Rx Polling (NAPI)"
- depends on VIA_RHINE
- help
- NAPI is a new driver API designed to reduce CPU and interrupt load
- when the driver is receiving lots of packets from the card.
-
- If your estimated Rx load is 10kpps or more, or if the card will be
- deployed on potentially unfriendly networks (e.g. in a firewall),
- then say Y here.
-
- config LAN_SAA9730
- bool "Philips SAA9730 Ethernet support"
- depends on NET_PCI && PCI && MIPS_ATLAS
- help
- The SAA9730 is a combined multimedia and peripheral controller used
- in thin clients, Internet access terminals, and diskless
- workstations.
- See <http://www.semiconductors.philips.com/pip/SAA9730_flyer_1>.
-
config SC92031
tristate "Silan SC92031 PCI Fast Ethernet Adapter driver (EXPERIMENTAL)"
depends on NET_PCI && PCI && EXPERIMENTAL
Say Y here if you want to use the NE2000 compatible
controller on the Renesas H8/300 processor.
- source "drivers/net/fec_8xx/Kconfig"
source "drivers/net/fs_enet/Kconfig"
endif # NET_ETHERNET
To compile this driver as a module, choose M here. The module
will be called e1000.
- config E1000_NAPI
- bool "Use Rx Polling (NAPI)"
- depends on E1000
- help
- NAPI is a new driver API designed to reduce CPU and interrupt load
- when the driver is receiving lots of packets from the card. It is
- still somewhat experimental and thus not yet enabled by default.
-
- If your estimated Rx load is 10kpps or more, or if the card will be
- deployed on potentially unfriendly networks (e.g. in a firewall),
- then say Y here.
-
- If in doubt, say N.
-
config E1000_DISABLE_PACKET_SPLIT
bool "Disable Packet Split for PCI express adapters"
depends on E1000
To compile this driver as a module, choose M here. The module
will be called e1000e.
- config E1000E_ENABLED
- def_bool E1000E != n
-
config IP1000
tristate "IP1000 Gigabit Ethernet support"
depends on PCI && EXPERIMENTAL
To compile this driver as a module, choose M here. The module
will be called igb.
+ config IGB_LRO
+ bool "Use software LRO"
+ depends on IGB && INET
+ select INET_LRO
+ ---help---
+ Say Y here if you want to use large receive offload.
+
+ If in doubt, say N.
+
source "drivers/net/ixp2000/Kconfig"
config MYRI_SBUS
To compile this driver as a module, choose M here: the module
will be called r8169. This is recommended.
- config R8169_NAPI
- bool "Use Rx Polling (NAPI) (EXPERIMENTAL)"
- depends on R8169 && EXPERIMENTAL
- help
- NAPI is a new driver API designed to reduce CPU and interrupt load
- when the driver is receiving lots of packets from the card. It is
- still somewhat experimental and thus not yet enabled by default.
-
- If your estimated Rx load is 10kpps or more, or if the card will be
- deployed on potentially unfriendly networks (e.g. in a firewall),
- then say Y here.
-
- If in doubt, say N.
-
config R8169_VLAN
bool "VLAN support"
depends on R8169 && VLAN_8021Q
---help---
Say Y here for the r8169 driver to support the functions required
by the kernel 802.1Q code.
-
+
If in doubt, say Y.
config SB1250_MAC
config TIGON3
tristate "Broadcom Tigon3 support"
depends on PCI
+ select PHYLIB
help
This driver supports Broadcom Tigon3 based gigabit Ethernet cards.
the driver automatically distinguishes the models, you can
safely enable this option even if you have a wireless-less model.
+ config GELIC_WIRELESS_OLD_PSK_INTERFACE
+ bool "PS3 Wireless private PSK interface (OBSOLETE)"
+ depends on GELIC_WIRELESS
+ help
+ This option retains the obsolete private interface to pass
+ the PSK from user space programs to the driver. The PSK
+ stands for 'Pre Shared Key' and is used for WPA[2]-PSK
+ (WPA-Personal) environment.
+ If WPA[2]-PSK is used and you need to use old programs that
+ support only this old interface, say Y. Otherwise N.
+
+ If unsure, say N.
+
config GIANFAR
tristate "Gianfar Ethernet"
depends on FSL_SOC
This driver supports the Gigabit TSEC on the MPC83xx, MPC85xx,
and MPC86xx family of chips, and the FEC on the 8540.
- config GFAR_NAPI
- bool "Use Rx Polling (NAPI)"
- depends on GIANFAR
-
config UCC_GETH
tristate "Freescale QE Gigabit Ethernet"
depends on QUICC_ENGINE
This driver supports the Gigabit Ethernet mode of the QUICC Engine,
which is available on some Freescale SOCs.
- config UGETH_NAPI
- bool "Use Rx Polling (NAPI)"
- depends on UCC_GETH
-
config UGETH_MAGIC_PACKET
bool "Magic Packet detection support"
depends on UCC_GETH
To compile this driver as a module, choose M here. The module
will be called atl1.
+ config ATL1E
+ tristate "Atheros L1E Gigabit Ethernet support (EXPERIMENTAL)"
+ depends on PCI && EXPERIMENTAL
+ select CRC32
+ select MII
+ help
+ This driver supports the Atheros L1E gigabit ethernet adapter.
+
+ To compile this driver as a module, choose M here. The module
+ will be called atl1e.
+
endif # NETDEV_1000
#
Enables support for Chelsio's gigabit Ethernet PCI cards. If you
are using only 10G cards say 'N' here.
- config CHELSIO_T1_NAPI
- bool "Use Rx Polling (NAPI)"
- depends on CHELSIO_T1
- default y
- help
- NAPI is a driver API designed to reduce CPU and interrupt load
- when the driver is receiving lots of packets from the card.
-
config CHELSIO_T3
tristate "Chelsio Communications T3 10Gb Ethernet support"
- depends on PCI
+ depends on PCI && INET
select FW_LOADER
+ select INET_LRO
help
This driver supports Chelsio T3-based gigabit and 10Gb Ethernet
adapters.
config IXGBE
tristate "Intel(R) 10GbE PCI Express adapters support"
- depends on PCI
+ depends on PCI && INET
+ select INET_LRO
---help---
This driver supports Intel(R) 10GbE PCI Express family of
adapters. For more information on how to identify your adapter, go
To compile this driver as a module, choose M here. The module
will be called ixgb.
- config IXGB_NAPI
- bool "Use Rx Polling (NAPI) (EXPERIMENTAL)"
- depends on IXGB && EXPERIMENTAL
- help
- NAPI is a new driver API designed to reduce CPU and interrupt load
- when the driver is receiving lots of packets from the card. It is
- still somewhat experimental and thus not yet enabled by default.
-
- If your estimated Rx load is 10kpps or more, or if the card will be
- deployed on potentially unfriendly networks (e.g. in a firewall),
- then say Y here.
-
- If in doubt, say N.
-
config S2IO
tristate "S2IO 10Gbe XFrame NIC"
depends on PCI
More specific information on configuring the driver is in
<file:Documentation/networking/s2io.txt>.
- config S2IO_NAPI
- bool "Use Rx Polling (NAPI) (EXPERIMENTAL)"
- depends on S2IO && EXPERIMENTAL
- help
- NAPI is a new driver API designed to reduce CPU and interrupt load
- when the driver is receiving lots of packets from the card. It is
- still somewhat experimental and thus not yet enabled by default.
-
- If your estimated Rx load is 10kpps or more, or if the card will be
- deployed on potentially unfriendly networks (e.g. in a firewall),
- then say Y here.
-
- If in doubt, say N.
-
config MYRI10GE
tristate "Myricom Myri-10G Ethernet support"
depends on PCI && INET
tristate "Broadcom NetXtremeII 10Gb support"
depends on PCI
select ZLIB_INFLATE
+ select LIBCRC32C
help
This driver supports Broadcom NetXtremeII 10 gigabit Ethernet cards.
To compile this driver as a module, choose M here: the module
#ifndef _SMC911X_H_
#define _SMC911X_H_
+ #include <linux/smc911x.h>
/*
* Use the DMA feature on PXA chips
*/
#define SMC_USE_32BIT 1
#define SMC_IRQ_SENSE IRQF_TRIGGER_FALLING
#elif defined(CONFIG_SH_MAGIC_PANEL_R2)
- #define SMC_USE_SH_DMA 0
#define SMC_USE_16BIT 0
#define SMC_USE_32BIT 1
#define SMC_IRQ_SENSE IRQF_TRIGGER_LOW
+#elif defined(CONFIG_ARCH_OMAP34XX)
+ #define SMC_USE_16BIT 0
+ #define SMC_USE_32BIT 1
+ #define SMC_IRQ_SENSE IRQF_TRIGGER_LOW
+ #define SMC_MEM_RESERVED 1
+#elif defined(CONFIG_ARCH_OMAP24XX)
+ #define SMC_USE_16BIT 0
+ #define SMC_USE_32BIT 1
+ #define SMC_IRQ_SENSE IRQF_TRIGGER_LOW
+ #define SMC_MEM_RESERVED 1
+ #else
+ /*
+ * Default configuration
+ */
+
+ #define SMC_DYNAMIC_BUS_CONFIG
#endif
+ /* store this information for the driver.. */
+ struct smc911x_local {
+ /*
+ * If I have to wait until the DMA is finished and ready to reload a
+ * packet, I will store the skbuff here. Then, the DMA will send it
+ * out and free it.
+ */
+ struct sk_buff *pending_tx_skb;
+
+ /* version/revision of the SMC911x chip */
+ u16 version;
+ u16 revision;
+
+ /* FIFO sizes */
+ int tx_fifo_kb;
+ int tx_fifo_size;
+ int rx_fifo_size;
+ int afc_cfg;
+
+ /* Contains the current active receive/phy mode */
+ int ctl_rfduplx;
+ int ctl_rspeed;
+
+ u32 msg_enable;
+ u32 phy_type;
+ struct mii_if_info mii;
+
+ /* work queue */
+ struct work_struct phy_configure;
+
+ int tx_throttle;
+ spinlock_t lock;
+
+ struct net_device *netdev;
+
+ #ifdef SMC_USE_DMA
+ /* DMA needs the physical address of the chip */
+ u_long physaddr;
+ int rxdma;
+ int txdma;
+ int rxdma_active;
+ int txdma_active;
+ struct sk_buff *current_rx_skb;
+ struct sk_buff *current_tx_skb;
+ struct device *dev;
+ #endif
+ void __iomem *base;
+ #ifdef SMC_DYNAMIC_BUS_CONFIG
+ struct smc911x_platdata cfg;
+ #endif
+ };
/*
* Define the bus width specific IO macros
*/
+ #ifdef SMC_DYNAMIC_BUS_CONFIG
+ static inline unsigned int SMC_inl(struct smc911x_local *lp, int reg)
+ {
+ void __iomem *ioaddr = lp->base + reg;
+
+ if (lp->cfg.flags & SMC911X_USE_32BIT)
+ return readl(ioaddr);
+
+ if (lp->cfg.flags & SMC911X_USE_16BIT)
+ return readw(ioaddr) | (readw(ioaddr + 2) << 16);
+
+ BUG();
+ }
+
+ static inline void SMC_outl(unsigned int value, struct smc911x_local *lp,
+ int reg)
+ {
+ void __iomem *ioaddr = lp->base + reg;
+
+ if (lp->cfg.flags & SMC911X_USE_32BIT) {
+ writel(value, ioaddr);
+ return;
+ }
+
+ if (lp->cfg.flags & SMC911X_USE_16BIT) {
+ writew(value & 0xffff, ioaddr);
+ writew(value >> 16, ioaddr + 2);
+ return;
+ }
+
+ BUG();
+ }
+
+ static inline void SMC_insl(struct smc911x_local *lp, int reg,
+ void *addr, unsigned int count)
+ {
+ void __iomem *ioaddr = lp->base + reg;
+
+ if (lp->cfg.flags & SMC911X_USE_32BIT) {
+ readsl(ioaddr, addr, count);
+ return;
+ }
+
+ if (lp->cfg.flags & SMC911X_USE_16BIT) {
+ readsw(ioaddr, addr, count * 2);
+ return;
+ }
+
+ BUG();
+ }
+
+ static inline void SMC_outsl(struct smc911x_local *lp, int reg,
+ void *addr, unsigned int count)
+ {
+ void __iomem *ioaddr = lp->base + reg;
+
+ if (lp->cfg.flags & SMC911X_USE_32BIT) {
+ writesl(ioaddr, addr, count);
+ return;
+ }
+
+ if (lp->cfg.flags & SMC911X_USE_16BIT) {
+ writesw(ioaddr, addr, count * 2);
+ return;
+ }
+
+ BUG();
+ }
+ #else
#if SMC_USE_16BIT
- #define SMC_inb(a, r) readb((a) + (r))
- #define SMC_inw(a, r) readw((a) + (r))
- #define SMC_inl(a, r) ((SMC_inw(a, r) & 0xFFFF)+(SMC_inw(a+2, r)<<16))
- #define SMC_outb(v, a, r) writeb(v, (a) + (r))
- #define SMC_outw(v, a, r) writew(v, (a) + (r))
- #define SMC_outl(v, a, r) \
+ #define SMC_inl(lp, r) ((readw((lp)->base + (r)) & 0xFFFF) + (readw((lp)->base + (r) + 2) << 16))
+ #define SMC_outl(v, lp, r) \
do{ \
- writel(v & 0xFFFF, (a) + (r)); \
- writel(v >> 16, (a) + (r) + 2); \
+ writew(v & 0xFFFF, (lp)->base + (r)); \
+ writew(v >> 16, (lp)->base + (r) + 2); \
} while (0)
- #define SMC_insl(a, r, p, l) readsw((short*)((a) + (r)), p, l*2)
- #define SMC_outsl(a, r, p, l) writesw((short*)((a) + (r)), p, l*2)
+ #define SMC_insl(lp, r, p, l) readsw((short*)((lp)->base + (r)), p, l*2)
+ #define SMC_outsl(lp, r, p, l) writesw((short*)((lp)->base + (r)), p, l*2)
#elif SMC_USE_32BIT
- #define SMC_inb(a, r) readb((a) + (r))
- #define SMC_inw(a, r) readw((a) + (r))
- #define SMC_inl(a, r) readl((a) + (r))
- #define SMC_outb(v, a, r) writeb(v, (a) + (r))
- #define SMC_outl(v, a, r) writel(v, (a) + (r))
- #define SMC_insl(a, r, p, l) readsl((int*)((a) + (r)), p, l)
- #define SMC_outsl(a, r, p, l) writesl((int*)((a) + (r)), p, l)
+ #define SMC_inl(lp, r) readl((lp)->base + (r))
+ #define SMC_outl(v, lp, r) writel(v, (lp)->base + (r))
+ #define SMC_insl(lp, r, p, l) readsl((int*)((lp)->base + (r)), p, l)
+ #define SMC_outsl(lp, r, p, l) writesl((int*)((lp)->base + (r)), p, l)
#endif /* SMC_USE_16BIT */
-
+ #endif /* SMC_DYNAMIC_BUS_CONFIG */
#ifdef SMC_USE_PXA_DMA
#ifdef SMC_insl
#undef SMC_insl
- #define SMC_insl(a, r, p, l) \
- smc_pxa_dma_insl(lp->dev, a, lp->physaddr, r, lp->rxdma, p, l)
+ #define SMC_insl(lp, r, p, l) \
+ smc_pxa_dma_insl(lp, lp->physaddr, r, lp->rxdma, p, l)
static inline void
- smc_pxa_dma_insl(struct device *dev, u_long ioaddr, u_long physaddr,
+ smc_pxa_dma_insl(struct smc911x_local *lp, u_long physaddr,
int reg, int dma, u_char *buf, int len)
{
/* 64 bit alignment is required for memory to memory DMA */
if ((long)buf & 4) {
- *((u32 *)buf) = SMC_inl(ioaddr, reg);
+ *((u32 *)buf) = SMC_inl(lp, reg);
buf += 4;
len--;
}
len *= 4;
- rx_dmabuf = dma_map_single(dev, buf, len, DMA_FROM_DEVICE);
+ rx_dmabuf = dma_map_single(lp->dev, buf, len, DMA_FROM_DEVICE);
rx_dmalen = len;
DCSR(dma) = DCSR_NODESC;
DTADR(dma) = rx_dmabuf;
}
#endif
- #ifdef SMC_insw
- #undef SMC_insw
- #define SMC_insw(a, r, p, l) \
- smc_pxa_dma_insw(lp->dev, a, lp->physaddr, r, lp->rxdma, p, l)
-
- static inline void
- smc_pxa_dma_insw(struct device *dev, u_long ioaddr, u_long physaddr,
- int reg, int dma, u_char *buf, int len)
- {
- /* 64 bit alignment is required for memory to memory DMA */
- while ((long)buf & 6) {
- *((u16 *)buf) = SMC_inw(ioaddr, reg);
- buf += 2;
- len--;
- }
-
- len *= 2;
- rx_dmabuf = dma_map_single(dev, buf, len, DMA_FROM_DEVICE);
- rx_dmalen = len;
- DCSR(dma) = DCSR_NODESC;
- DTADR(dma) = rx_dmabuf;
- DSADR(dma) = physaddr + reg;
- DCMD(dma) = (DCMD_INCTRGADDR | DCMD_BURST32 |
- DCMD_WIDTH2 | DCMD_ENDIRQEN | (DCMD_LENGTH & rx_dmalen));
- DCSR(dma) = DCSR_NODESC | DCSR_RUN;
- }
- #endif
-
#ifdef SMC_outsl
#undef SMC_outsl
- #define SMC_outsl(a, r, p, l) \
- smc_pxa_dma_outsl(lp->dev, a, lp->physaddr, r, lp->txdma, p, l)
+ #define SMC_outsl(lp, r, p, l) \
+ smc_pxa_dma_outsl(lp, lp->physaddr, r, lp->txdma, p, l)
static inline void
- smc_pxa_dma_outsl(struct device *dev, u_long ioaddr, u_long physaddr,
+ smc_pxa_dma_outsl(struct smc911x_local *lp, u_long physaddr,
int reg, int dma, u_char *buf, int len)
{
/* 64 bit alignment is required for memory to memory DMA */
if ((long)buf & 4) {
- SMC_outl(*((u32 *)buf), ioaddr, reg);
+ SMC_outl(*((u32 *)buf), lp, reg);
buf += 4;
len--;
}
len *= 4;
- tx_dmabuf = dma_map_single(dev, buf, len, DMA_TO_DEVICE);
+ tx_dmabuf = dma_map_single(lp->dev, buf, len, DMA_TO_DEVICE);
tx_dmalen = len;
DCSR(dma) = DCSR_NODESC;
DSADR(dma) = tx_dmabuf;
DCSR(dma) = DCSR_NODESC | DCSR_RUN;
}
#endif
-
- #ifdef SMC_outsw
- #undef SMC_outsw
- #define SMC_outsw(a, r, p, l) \
- smc_pxa_dma_outsw(lp->dev, a, lp->physaddr, r, lp->txdma, p, l)
-
- static inline void
- smc_pxa_dma_outsw(struct device *dev, u_long ioaddr, u_long physaddr,
- int reg, int dma, u_char *buf, int len)
- {
- /* 64 bit alignment is required for memory to memory DMA */
- while ((long)buf & 6) {
- SMC_outw(*((u16 *)buf), ioaddr, reg);
- buf += 2;
- len--;
- }
-
- len *= 2;
- tx_dmabuf = dma_map_single(dev, buf, len, DMA_TO_DEVICE);
- tx_dmalen = len;
- DCSR(dma) = DCSR_NODESC;
- DSADR(dma) = tx_dmabuf;
- DTADR(dma) = physaddr + reg;
- DCMD(dma) = (DCMD_INCSRCADDR | DCMD_BURST32 |
- DCMD_WIDTH2 | DCMD_ENDIRQEN | (DCMD_LENGTH & tx_dmalen));
- DCSR(dma) = DCSR_NODESC | DCSR_RUN;
- }
- #endif
-
#endif /* SMC_USE_PXA_DMA */
* capabilities. Please use those and not the in/out primitives.
*/
/* FIFO read/write macros */
- #define SMC_PUSH_DATA(p, l) SMC_outsl( ioaddr, TX_DATA_FIFO, p, (l) >> 2 )
- #define SMC_PULL_DATA(p, l) SMC_insl ( ioaddr, RX_DATA_FIFO, p, (l) >> 2 )
- #define SMC_SET_TX_FIFO(x) SMC_outl( x, ioaddr, TX_DATA_FIFO )
- #define SMC_GET_RX_FIFO() SMC_inl( ioaddr, RX_DATA_FIFO )
+ #define SMC_PUSH_DATA(lp, p, l) SMC_outsl( lp, TX_DATA_FIFO, p, (l) >> 2 )
+ #define SMC_PULL_DATA(lp, p, l) SMC_insl ( lp, RX_DATA_FIFO, p, (l) >> 2 )
+ #define SMC_SET_TX_FIFO(lp, x) SMC_outl( x, lp, TX_DATA_FIFO )
+ #define SMC_GET_RX_FIFO(lp) SMC_inl( lp, RX_DATA_FIFO )
/* I/O mapped register read/write macros */
- #define SMC_GET_TX_STS_FIFO() SMC_inl( ioaddr, TX_STATUS_FIFO )
- #define SMC_GET_RX_STS_FIFO() SMC_inl( ioaddr, RX_STATUS_FIFO )
- #define SMC_GET_RX_STS_FIFO_PEEK() SMC_inl( ioaddr, RX_STATUS_FIFO_PEEK )
- #define SMC_GET_PN() (SMC_inl( ioaddr, ID_REV ) >> 16)
- #define SMC_GET_REV() (SMC_inl( ioaddr, ID_REV ) & 0xFFFF)
- #define SMC_GET_IRQ_CFG() SMC_inl( ioaddr, INT_CFG )
- #define SMC_SET_IRQ_CFG(x) SMC_outl( x, ioaddr, INT_CFG )
- #define SMC_GET_INT() SMC_inl( ioaddr, INT_STS )
- #define SMC_ACK_INT(x) SMC_outl( x, ioaddr, INT_STS )
- #define SMC_GET_INT_EN() SMC_inl( ioaddr, INT_EN )
- #define SMC_SET_INT_EN(x) SMC_outl( x, ioaddr, INT_EN )
- #define SMC_GET_BYTE_TEST() SMC_inl( ioaddr, BYTE_TEST )
- #define SMC_SET_BYTE_TEST(x) SMC_outl( x, ioaddr, BYTE_TEST )
- #define SMC_GET_FIFO_INT() SMC_inl( ioaddr, FIFO_INT )
- #define SMC_SET_FIFO_INT(x) SMC_outl( x, ioaddr, FIFO_INT )
- #define SMC_SET_FIFO_TDA(x) \
+ #define SMC_GET_TX_STS_FIFO(lp) SMC_inl( lp, TX_STATUS_FIFO )
+ #define SMC_GET_RX_STS_FIFO(lp) SMC_inl( lp, RX_STATUS_FIFO )
+ #define SMC_GET_RX_STS_FIFO_PEEK(lp) SMC_inl( lp, RX_STATUS_FIFO_PEEK )
+ #define SMC_GET_PN(lp) (SMC_inl( lp, ID_REV ) >> 16)
+ #define SMC_GET_REV(lp) (SMC_inl( lp, ID_REV ) & 0xFFFF)
+ #define SMC_GET_IRQ_CFG(lp) SMC_inl( lp, INT_CFG )
+ #define SMC_SET_IRQ_CFG(lp, x) SMC_outl( x, lp, INT_CFG )
+ #define SMC_GET_INT(lp) SMC_inl( lp, INT_STS )
+ #define SMC_ACK_INT(lp, x) SMC_outl( x, lp, INT_STS )
+ #define SMC_GET_INT_EN(lp) SMC_inl( lp, INT_EN )
+ #define SMC_SET_INT_EN(lp, x) SMC_outl( x, lp, INT_EN )
+ #define SMC_GET_BYTE_TEST(lp) SMC_inl( lp, BYTE_TEST )
+ #define SMC_SET_BYTE_TEST(lp, x) SMC_outl( x, lp, BYTE_TEST )
+ #define SMC_GET_FIFO_INT(lp) SMC_inl( lp, FIFO_INT )
+ #define SMC_SET_FIFO_INT(lp, x) SMC_outl( x, lp, FIFO_INT )
+ #define SMC_SET_FIFO_TDA(lp, x) \
do { \
unsigned long __flags; \
int __mask; \
local_irq_save(__flags); \
- __mask = SMC_GET_FIFO_INT() & ~(0xFF<<24); \
- SMC_SET_FIFO_INT( __mask | (x)<<24 ); \
+ __mask = SMC_GET_FIFO_INT((lp)) & ~(0xFF<<24); \
+ SMC_SET_FIFO_INT( (lp), __mask | (x)<<24 ); \
local_irq_restore(__flags); \
} while (0)
- #define SMC_SET_FIFO_TSL(x) \
+ #define SMC_SET_FIFO_TSL(lp, x) \
do { \
unsigned long __flags; \
int __mask; \
local_irq_save(__flags); \
- __mask = SMC_GET_FIFO_INT() & ~(0xFF<<16); \
- SMC_SET_FIFO_INT( __mask | (((x) & 0xFF)<<16)); \
+ __mask = SMC_GET_FIFO_INT((lp)) & ~(0xFF<<16); \
+ SMC_SET_FIFO_INT( (lp), __mask | (((x) & 0xFF)<<16)); \
local_irq_restore(__flags); \
} while (0)
- #define SMC_SET_FIFO_RSA(x) \
+ #define SMC_SET_FIFO_RSA(lp, x) \
do { \
unsigned long __flags; \
int __mask; \
local_irq_save(__flags); \
- __mask = SMC_GET_FIFO_INT() & ~(0xFF<<8); \
- SMC_SET_FIFO_INT( __mask | (((x) & 0xFF)<<8)); \
+ __mask = SMC_GET_FIFO_INT((lp)) & ~(0xFF<<8); \
+ SMC_SET_FIFO_INT( (lp), __mask | (((x) & 0xFF)<<8)); \
local_irq_restore(__flags); \
} while (0)
- #define SMC_SET_FIFO_RSL(x) \
+ #define SMC_SET_FIFO_RSL(lp, x) \
do { \
unsigned long __flags; \
int __mask; \
local_irq_save(__flags); \
- __mask = SMC_GET_FIFO_INT() & ~0xFF; \
- SMC_SET_FIFO_INT( __mask | ((x) & 0xFF)); \
+ __mask = SMC_GET_FIFO_INT((lp)) & ~0xFF; \
+ SMC_SET_FIFO_INT( (lp),__mask | ((x) & 0xFF)); \
local_irq_restore(__flags); \
} while (0)
- #define SMC_GET_RX_CFG() SMC_inl( ioaddr, RX_CFG )
- #define SMC_SET_RX_CFG(x) SMC_outl( x, ioaddr, RX_CFG )
- #define SMC_GET_TX_CFG() SMC_inl( ioaddr, TX_CFG )
- #define SMC_SET_TX_CFG(x) SMC_outl( x, ioaddr, TX_CFG )
- #define SMC_GET_HW_CFG() SMC_inl( ioaddr, HW_CFG )
- #define SMC_SET_HW_CFG(x) SMC_outl( x, ioaddr, HW_CFG )
- #define SMC_GET_RX_DP_CTRL() SMC_inl( ioaddr, RX_DP_CTRL )
- #define SMC_SET_RX_DP_CTRL(x) SMC_outl( x, ioaddr, RX_DP_CTRL )
- #define SMC_GET_PMT_CTRL() SMC_inl( ioaddr, PMT_CTRL )
- #define SMC_SET_PMT_CTRL(x) SMC_outl( x, ioaddr, PMT_CTRL )
- #define SMC_GET_GPIO_CFG() SMC_inl( ioaddr, GPIO_CFG )
- #define SMC_SET_GPIO_CFG(x) SMC_outl( x, ioaddr, GPIO_CFG )
- #define SMC_GET_RX_FIFO_INF() SMC_inl( ioaddr, RX_FIFO_INF )
- #define SMC_SET_RX_FIFO_INF(x) SMC_outl( x, ioaddr, RX_FIFO_INF )
- #define SMC_GET_TX_FIFO_INF() SMC_inl( ioaddr, TX_FIFO_INF )
- #define SMC_SET_TX_FIFO_INF(x) SMC_outl( x, ioaddr, TX_FIFO_INF )
- #define SMC_GET_GPT_CFG() SMC_inl( ioaddr, GPT_CFG )
- #define SMC_SET_GPT_CFG(x) SMC_outl( x, ioaddr, GPT_CFG )
- #define SMC_GET_RX_DROP() SMC_inl( ioaddr, RX_DROP )
- #define SMC_SET_RX_DROP(x) SMC_outl( x, ioaddr, RX_DROP )
- #define SMC_GET_MAC_CMD() SMC_inl( ioaddr, MAC_CSR_CMD )
- #define SMC_SET_MAC_CMD(x) SMC_outl( x, ioaddr, MAC_CSR_CMD )
- #define SMC_GET_MAC_DATA() SMC_inl( ioaddr, MAC_CSR_DATA )
- #define SMC_SET_MAC_DATA(x) SMC_outl( x, ioaddr, MAC_CSR_DATA )
- #define SMC_GET_AFC_CFG() SMC_inl( ioaddr, AFC_CFG )
- #define SMC_SET_AFC_CFG(x) SMC_outl( x, ioaddr, AFC_CFG )
- #define SMC_GET_E2P_CMD() SMC_inl( ioaddr, E2P_CMD )
- #define SMC_SET_E2P_CMD(x) SMC_outl( x, ioaddr, E2P_CMD )
- #define SMC_GET_E2P_DATA() SMC_inl( ioaddr, E2P_DATA )
- #define SMC_SET_E2P_DATA(x) SMC_outl( x, ioaddr, E2P_DATA )
+ #define SMC_GET_RX_CFG(lp) SMC_inl( lp, RX_CFG )
+ #define SMC_SET_RX_CFG(lp, x) SMC_outl( x, lp, RX_CFG )
+ #define SMC_GET_TX_CFG(lp) SMC_inl( lp, TX_CFG )
+ #define SMC_SET_TX_CFG(lp, x) SMC_outl( x, lp, TX_CFG )
+ #define SMC_GET_HW_CFG(lp) SMC_inl( lp, HW_CFG )
+ #define SMC_SET_HW_CFG(lp, x) SMC_outl( x, lp, HW_CFG )
+ #define SMC_GET_RX_DP_CTRL(lp) SMC_inl( lp, RX_DP_CTRL )
+ #define SMC_SET_RX_DP_CTRL(lp, x) SMC_outl( x, lp, RX_DP_CTRL )
+ #define SMC_GET_PMT_CTRL(lp) SMC_inl( lp, PMT_CTRL )
+ #define SMC_SET_PMT_CTRL(lp, x) SMC_outl( x, lp, PMT_CTRL )
+ #define SMC_GET_GPIO_CFG(lp) SMC_inl( lp, GPIO_CFG )
+ #define SMC_SET_GPIO_CFG(lp, x) SMC_outl( x, lp, GPIO_CFG )
+ #define SMC_GET_RX_FIFO_INF(lp) SMC_inl( lp, RX_FIFO_INF )
+ #define SMC_SET_RX_FIFO_INF(lp, x) SMC_outl( x, lp, RX_FIFO_INF )
+ #define SMC_GET_TX_FIFO_INF(lp) SMC_inl( lp, TX_FIFO_INF )
+ #define SMC_SET_TX_FIFO_INF(lp, x) SMC_outl( x, lp, TX_FIFO_INF )
+ #define SMC_GET_GPT_CFG(lp) SMC_inl( lp, GPT_CFG )
+ #define SMC_SET_GPT_CFG(lp, x) SMC_outl( x, lp, GPT_CFG )
+ #define SMC_GET_RX_DROP(lp) SMC_inl( lp, RX_DROP )
+ #define SMC_SET_RX_DROP(lp, x) SMC_outl( x, lp, RX_DROP )
+ #define SMC_GET_MAC_CMD(lp) SMC_inl( lp, MAC_CSR_CMD )
+ #define SMC_SET_MAC_CMD(lp, x) SMC_outl( x, lp, MAC_CSR_CMD )
+ #define SMC_GET_MAC_DATA(lp) SMC_inl( lp, MAC_CSR_DATA )
+ #define SMC_SET_MAC_DATA(lp, x) SMC_outl( x, lp, MAC_CSR_DATA )
+ #define SMC_GET_AFC_CFG(lp) SMC_inl( lp, AFC_CFG )
+ #define SMC_SET_AFC_CFG(lp, x) SMC_outl( x, lp, AFC_CFG )
+ #define SMC_GET_E2P_CMD(lp) SMC_inl( lp, E2P_CMD )
+ #define SMC_SET_E2P_CMD(lp, x) SMC_outl( x, lp, E2P_CMD )
+ #define SMC_GET_E2P_DATA(lp) SMC_inl( lp, E2P_DATA )
+ #define SMC_SET_E2P_DATA(lp, x) SMC_outl( x, lp, E2P_DATA )
/* MAC register read/write macros */
- #define SMC_GET_MAC_CSR(a,v) \
+ #define SMC_GET_MAC_CSR(lp,a,v) \
do { \
- while (SMC_GET_MAC_CMD() & MAC_CSR_CMD_CSR_BUSY_); \
- SMC_SET_MAC_CMD(MAC_CSR_CMD_CSR_BUSY_ | \
+ while (SMC_GET_MAC_CMD((lp)) & MAC_CSR_CMD_CSR_BUSY_); \
+ SMC_SET_MAC_CMD((lp),MAC_CSR_CMD_CSR_BUSY_ | \
MAC_CSR_CMD_R_NOT_W_ | (a) ); \
- while (SMC_GET_MAC_CMD() & MAC_CSR_CMD_CSR_BUSY_); \
- v = SMC_GET_MAC_DATA(); \
+ while (SMC_GET_MAC_CMD((lp)) & MAC_CSR_CMD_CSR_BUSY_); \
+ v = SMC_GET_MAC_DATA((lp)); \
} while (0)
- #define SMC_SET_MAC_CSR(a,v) \
+ #define SMC_SET_MAC_CSR(lp,a,v) \
do { \
- while (SMC_GET_MAC_CMD() & MAC_CSR_CMD_CSR_BUSY_); \
- SMC_SET_MAC_DATA(v); \
- SMC_SET_MAC_CMD(MAC_CSR_CMD_CSR_BUSY_ | (a) ); \
- while (SMC_GET_MAC_CMD() & MAC_CSR_CMD_CSR_BUSY_); \
+ while (SMC_GET_MAC_CMD((lp)) & MAC_CSR_CMD_CSR_BUSY_); \
+ SMC_SET_MAC_DATA((lp), v); \
+ SMC_SET_MAC_CMD((lp), MAC_CSR_CMD_CSR_BUSY_ | (a) ); \
+ while (SMC_GET_MAC_CMD((lp)) & MAC_CSR_CMD_CSR_BUSY_); \
} while (0)
- #define SMC_GET_MAC_CR(x) SMC_GET_MAC_CSR( MAC_CR, x )
- #define SMC_SET_MAC_CR(x) SMC_SET_MAC_CSR( MAC_CR, x )
- #define SMC_GET_ADDRH(x) SMC_GET_MAC_CSR( ADDRH, x )
- #define SMC_SET_ADDRH(x) SMC_SET_MAC_CSR( ADDRH, x )
- #define SMC_GET_ADDRL(x) SMC_GET_MAC_CSR( ADDRL, x )
- #define SMC_SET_ADDRL(x) SMC_SET_MAC_CSR( ADDRL, x )
- #define SMC_GET_HASHH(x) SMC_GET_MAC_CSR( HASHH, x )
- #define SMC_SET_HASHH(x) SMC_SET_MAC_CSR( HASHH, x )
- #define SMC_GET_HASHL(x) SMC_GET_MAC_CSR( HASHL, x )
- #define SMC_SET_HASHL(x) SMC_SET_MAC_CSR( HASHL, x )
- #define SMC_GET_MII_ACC(x) SMC_GET_MAC_CSR( MII_ACC, x )
- #define SMC_SET_MII_ACC(x) SMC_SET_MAC_CSR( MII_ACC, x )
- #define SMC_GET_MII_DATA(x) SMC_GET_MAC_CSR( MII_DATA, x )
- #define SMC_SET_MII_DATA(x) SMC_SET_MAC_CSR( MII_DATA, x )
- #define SMC_GET_FLOW(x) SMC_GET_MAC_CSR( FLOW, x )
- #define SMC_SET_FLOW(x) SMC_SET_MAC_CSR( FLOW, x )
- #define SMC_GET_VLAN1(x) SMC_GET_MAC_CSR( VLAN1, x )
- #define SMC_SET_VLAN1(x) SMC_SET_MAC_CSR( VLAN1, x )
- #define SMC_GET_VLAN2(x) SMC_GET_MAC_CSR( VLAN2, x )
- #define SMC_SET_VLAN2(x) SMC_SET_MAC_CSR( VLAN2, x )
- #define SMC_SET_WUFF(x) SMC_SET_MAC_CSR( WUFF, x )
- #define SMC_GET_WUCSR(x) SMC_GET_MAC_CSR( WUCSR, x )
- #define SMC_SET_WUCSR(x) SMC_SET_MAC_CSR( WUCSR, x )
+ #define SMC_GET_MAC_CR(lp, x) SMC_GET_MAC_CSR( (lp), MAC_CR, x )
+ #define SMC_SET_MAC_CR(lp, x) SMC_SET_MAC_CSR( (lp), MAC_CR, x )
+ #define SMC_GET_ADDRH(lp, x) SMC_GET_MAC_CSR( (lp), ADDRH, x )
+ #define SMC_SET_ADDRH(lp, x) SMC_SET_MAC_CSR( (lp), ADDRH, x )
+ #define SMC_GET_ADDRL(lp, x) SMC_GET_MAC_CSR( (lp), ADDRL, x )
+ #define SMC_SET_ADDRL(lp, x) SMC_SET_MAC_CSR( (lp), ADDRL, x )
+ #define SMC_GET_HASHH(lp, x) SMC_GET_MAC_CSR( (lp), HASHH, x )
+ #define SMC_SET_HASHH(lp, x) SMC_SET_MAC_CSR( (lp), HASHH, x )
+ #define SMC_GET_HASHL(lp, x) SMC_GET_MAC_CSR( (lp), HASHL, x )
+ #define SMC_SET_HASHL(lp, x) SMC_SET_MAC_CSR( (lp), HASHL, x )
+ #define SMC_GET_MII_ACC(lp, x) SMC_GET_MAC_CSR( (lp), MII_ACC, x )
+ #define SMC_SET_MII_ACC(lp, x) SMC_SET_MAC_CSR( (lp), MII_ACC, x )
+ #define SMC_GET_MII_DATA(lp, x) SMC_GET_MAC_CSR( (lp), MII_DATA, x )
+ #define SMC_SET_MII_DATA(lp, x) SMC_SET_MAC_CSR( (lp), MII_DATA, x )
+ #define SMC_GET_FLOW(lp, x) SMC_GET_MAC_CSR( (lp), FLOW, x )
+ #define SMC_SET_FLOW(lp, x) SMC_SET_MAC_CSR( (lp), FLOW, x )
+ #define SMC_GET_VLAN1(lp, x) SMC_GET_MAC_CSR( (lp), VLAN1, x )
+ #define SMC_SET_VLAN1(lp, x) SMC_SET_MAC_CSR( (lp), VLAN1, x )
+ #define SMC_GET_VLAN2(lp, x) SMC_GET_MAC_CSR( (lp), VLAN2, x )
+ #define SMC_SET_VLAN2(lp, x) SMC_SET_MAC_CSR( (lp), VLAN2, x )
+ #define SMC_SET_WUFF(lp, x) SMC_SET_MAC_CSR( (lp), WUFF, x )
+ #define SMC_GET_WUCSR(lp, x) SMC_GET_MAC_CSR( (lp), WUCSR, x )
+ #define SMC_SET_WUCSR(lp, x) SMC_SET_MAC_CSR( (lp), WUCSR, x )
/* PHY register read/write macros */
- #define SMC_GET_MII(a,phy,v) \
+ #define SMC_GET_MII(lp,a,phy,v) \
do { \
u32 __v; \
do { \
- SMC_GET_MII_ACC(__v); \
+ SMC_GET_MII_ACC((lp), __v); \
} while ( __v & MII_ACC_MII_BUSY_ ); \
- SMC_SET_MII_ACC( ((phy)<<11) | ((a)<<6) | \
+ SMC_SET_MII_ACC( (lp), ((phy)<<11) | ((a)<<6) | \
MII_ACC_MII_BUSY_); \
do { \
- SMC_GET_MII_ACC(__v); \
+ SMC_GET_MII_ACC( (lp), __v); \
} while ( __v & MII_ACC_MII_BUSY_ ); \
- SMC_GET_MII_DATA(v); \
+ SMC_GET_MII_DATA((lp), v); \
} while (0)
- #define SMC_SET_MII(a,phy,v) \
+ #define SMC_SET_MII(lp,a,phy,v) \
do { \
u32 __v; \
do { \
- SMC_GET_MII_ACC(__v); \
+ SMC_GET_MII_ACC((lp), __v); \
} while ( __v & MII_ACC_MII_BUSY_ ); \
- SMC_SET_MII_DATA(v); \
- SMC_SET_MII_ACC( ((phy)<<11) | ((a)<<6) | \
+ SMC_SET_MII_DATA((lp), v); \
+ SMC_SET_MII_ACC( (lp), ((phy)<<11) | ((a)<<6) | \
MII_ACC_MII_BUSY_ | \
MII_ACC_MII_WRITE_ ); \
do { \
- SMC_GET_MII_ACC(__v); \
+ SMC_GET_MII_ACC((lp), __v); \
} while ( __v & MII_ACC_MII_BUSY_ ); \
} while (0)
- #define SMC_GET_PHY_BMCR(phy,x) SMC_GET_MII( MII_BMCR, phy, x )
- #define SMC_SET_PHY_BMCR(phy,x) SMC_SET_MII( MII_BMCR, phy, x )
- #define SMC_GET_PHY_BMSR(phy,x) SMC_GET_MII( MII_BMSR, phy, x )
- #define SMC_GET_PHY_ID1(phy,x) SMC_GET_MII( MII_PHYSID1, phy, x )
- #define SMC_GET_PHY_ID2(phy,x) SMC_GET_MII( MII_PHYSID2, phy, x )
- #define SMC_GET_PHY_MII_ADV(phy,x) SMC_GET_MII( MII_ADVERTISE, phy, x )
- #define SMC_SET_PHY_MII_ADV(phy,x) SMC_SET_MII( MII_ADVERTISE, phy, x )
- #define SMC_GET_PHY_MII_LPA(phy,x) SMC_GET_MII( MII_LPA, phy, x )
- #define SMC_SET_PHY_MII_LPA(phy,x) SMC_SET_MII( MII_LPA, phy, x )
- #define SMC_GET_PHY_CTRL_STS(phy,x) SMC_GET_MII( PHY_MODE_CTRL_STS, phy, x )
- #define SMC_SET_PHY_CTRL_STS(phy,x) SMC_SET_MII( PHY_MODE_CTRL_STS, phy, x )
- #define SMC_GET_PHY_INT_SRC(phy,x) SMC_GET_MII( PHY_INT_SRC, phy, x )
- #define SMC_SET_PHY_INT_SRC(phy,x) SMC_SET_MII( PHY_INT_SRC, phy, x )
- #define SMC_GET_PHY_INT_MASK(phy,x) SMC_GET_MII( PHY_INT_MASK, phy, x )
- #define SMC_SET_PHY_INT_MASK(phy,x) SMC_SET_MII( PHY_INT_MASK, phy, x )
- #define SMC_GET_PHY_SPECIAL(phy,x) SMC_GET_MII( PHY_SPECIAL, phy, x )
+ #define SMC_GET_PHY_BMCR(lp,phy,x) SMC_GET_MII( (lp), MII_BMCR, phy, x )
+ #define SMC_SET_PHY_BMCR(lp,phy,x) SMC_SET_MII( (lp), MII_BMCR, phy, x )
+ #define SMC_GET_PHY_BMSR(lp,phy,x) SMC_GET_MII( (lp), MII_BMSR, phy, x )
+ #define SMC_GET_PHY_ID1(lp,phy,x) SMC_GET_MII( (lp), MII_PHYSID1, phy, x )
+ #define SMC_GET_PHY_ID2(lp,phy,x) SMC_GET_MII( (lp), MII_PHYSID2, phy, x )
+ #define SMC_GET_PHY_MII_ADV(lp,phy,x) SMC_GET_MII( (lp), MII_ADVERTISE, phy, x )
+ #define SMC_SET_PHY_MII_ADV(lp,phy,x) SMC_SET_MII( (lp), MII_ADVERTISE, phy, x )
+ #define SMC_GET_PHY_MII_LPA(lp,phy,x) SMC_GET_MII( (lp), MII_LPA, phy, x )
+ #define SMC_SET_PHY_MII_LPA(lp,phy,x) SMC_SET_MII( (lp), MII_LPA, phy, x )
+ #define SMC_GET_PHY_CTRL_STS(lp,phy,x) SMC_GET_MII( (lp), PHY_MODE_CTRL_STS, phy, x )
+ #define SMC_SET_PHY_CTRL_STS(lp,phy,x) SMC_SET_MII( (lp), PHY_MODE_CTRL_STS, phy, x )
+ #define SMC_GET_PHY_INT_SRC(lp,phy,x) SMC_GET_MII( (lp), PHY_INT_SRC, phy, x )
+ #define SMC_SET_PHY_INT_SRC(lp,phy,x) SMC_SET_MII( (lp), PHY_INT_SRC, phy, x )
+ #define SMC_GET_PHY_INT_MASK(lp,phy,x) SMC_GET_MII( (lp), PHY_INT_MASK, phy, x )
+ #define SMC_SET_PHY_INT_MASK(lp,phy,x) SMC_SET_MII( (lp), PHY_INT_MASK, phy, x )
+ #define SMC_GET_PHY_SPECIAL(lp,phy,x) SMC_GET_MII( (lp), PHY_SPECIAL, phy, x )
/* Misc read/write macros */
#ifndef SMC_GET_MAC_ADDR
- #define SMC_GET_MAC_ADDR(addr) \
+ #define SMC_GET_MAC_ADDR(lp, addr) \
do { \
unsigned int __v; \
\
- SMC_GET_MAC_CSR(ADDRL, __v); \
+ SMC_GET_MAC_CSR((lp), ADDRL, __v); \
addr[0] = __v; addr[1] = __v >> 8; \
addr[2] = __v >> 16; addr[3] = __v >> 24; \
- SMC_GET_MAC_CSR(ADDRH, __v); \
+ SMC_GET_MAC_CSR((lp), ADDRH, __v); \
addr[4] = __v; addr[5] = __v >> 8; \
} while (0)
#endif
- #define SMC_SET_MAC_ADDR(addr) \
+ #define SMC_SET_MAC_ADDR(lp, addr) \
do { \
- SMC_SET_MAC_CSR(ADDRL, \
+ SMC_SET_MAC_CSR((lp), ADDRL, \
addr[0] | \
(addr[1] << 8) | \
(addr[2] << 16) | \
(addr[3] << 24)); \
- SMC_SET_MAC_CSR(ADDRH, addr[4]|(addr[5] << 8));\
+ SMC_SET_MAC_CSR((lp), ADDRH, addr[4]|(addr[5] << 8));\
} while (0)
- #define SMC_WRITE_EEPROM_CMD(cmd, addr) \
+ #define SMC_WRITE_EEPROM_CMD(lp, cmd, addr) \
do { \
- while (SMC_GET_E2P_CMD() & MAC_CSR_CMD_CSR_BUSY_); \
- SMC_SET_MAC_CMD(MAC_CSR_CMD_R_NOT_W_ | a ); \
- while (SMC_GET_MAC_CMD() & MAC_CSR_CMD_CSR_BUSY_); \
+ while (SMC_GET_E2P_CMD((lp)) & MAC_CSR_CMD_CSR_BUSY_); \
+ SMC_SET_MAC_CMD((lp), MAC_CSR_CMD_R_NOT_W_ | a ); \
+ while (SMC_GET_MAC_CMD((lp)) & MAC_CSR_CMD_CSR_BUSY_); \
} while (0)
#endif /* _SMC911X_H_ */
* can't handle it then there will be no recovery except for
* a hard reset or power cycle
*/
- if (nowait)
+ if (lp->cfg.flags & SMC91X_NOWAIT)
cfg |= CONFIG_NO_WAIT;
/*
dev->name, packet_number, status,
packet_len, packet_len);
+ if (unlikely(packet_len == 0 && !(status & RS_ERRORS))) {
+ printk(KERN_ERR "%s: bad memory timings: rxlen %u status %x\n",
+ dev->name, packet_len, status);
+ status |= RS_TOOSHORT;
+ }
back:
if (unlikely(packet_len < 6 || status & RS_ERRORS)) {
if (status & RS_TOOLONG && packet_len <= (1514 + 4 + 6)) {
if (retval)
goto err_out;
- #ifdef SMC_USE_PXA_DMA
- {
+ #ifdef CONFIG_ARCH_PXA
+ # ifdef SMC_USE_PXA_DMA
+ lp->cfg.flags |= SMC91X_USE_DMA;
+ # endif
+ if (lp->cfg.flags & SMC91X_USE_DMA) {
int dma = pxa_request_dma(dev->name, DMA_PRIO_LOW,
smc_pxa_dma_irq, NULL);
if (dma >= 0)
}
err_out:
- #ifdef SMC_USE_PXA_DMA
+ #ifdef CONFIG_ARCH_PXA
if (retval && dev->dma != (unsigned char)-1)
pxa_free_dma(dev->dma);
#endif
return 0;
}
- static int smc_request_attrib(struct platform_device *pdev)
+ static int smc_request_attrib(struct platform_device *pdev,
+ struct net_device *ndev)
{
struct resource * res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-attrib");
+ struct smc_local *lp = netdev_priv(ndev);
if (!res)
return 0;
return 0;
}
- static void smc_release_attrib(struct platform_device *pdev)
+ static void smc_release_attrib(struct platform_device *pdev,
+ struct net_device *ndev)
{
struct resource * res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-attrib");
+ struct smc_local *lp = netdev_priv(ndev);
if (res)
release_mem_region(res->start, ATTRIB_SIZE);
struct net_device *ndev;
struct resource *res, *ires;
unsigned int __iomem *addr;
+ unsigned long irq_flags = SMC_IRQ_FLAGS;
int ret;
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-regs");
- if (!res)
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- ret = -ENODEV;
- goto out;
- }
-
-
- if (!request_mem_region(res->start, SMC_IO_EXTENT, CARDNAME)) {
- ret = -EBUSY;
- goto out;
- }
-
ndev = alloc_etherdev(sizeof(struct smc_local));
if (!ndev) {
printk("%s: could not allocate device.\n", CARDNAME);
ret = -ENOMEM;
- goto out_release_io;
+ goto out;
}
SET_NETDEV_DEV(ndev, &pdev->dev);
*/
lp = netdev_priv(ndev);
- lp->cfg.irq_flags = SMC_IRQ_FLAGS;
- #ifdef SMC_DYNAMIC_BUS_CONFIG
- if (pd)
+ if (pd) {
memcpy(&lp->cfg, pd, sizeof(lp->cfg));
- else {
- lp->cfg.flags = SMC91X_USE_8BIT;
- lp->cfg.flags |= SMC91X_USE_16BIT;
- lp->cfg.flags |= SMC91X_USE_32BIT;
+ lp->io_shift = SMC91X_IO_SHIFT(lp->cfg.flags);
+ } else {
+ lp->cfg.flags |= (SMC_CAN_USE_8BIT) ? SMC91X_USE_8BIT : 0;
+ lp->cfg.flags |= (SMC_CAN_USE_16BIT) ? SMC91X_USE_16BIT : 0;
+ lp->cfg.flags |= (SMC_CAN_USE_32BIT) ? SMC91X_USE_32BIT : 0;
+ lp->cfg.flags |= (nowait) ? SMC91X_NOWAIT : 0;
}
- lp->cfg.flags &= ~(SMC_CAN_USE_8BIT ? 0 : SMC91X_USE_8BIT);
- lp->cfg.flags &= ~(SMC_CAN_USE_16BIT ? 0 : SMC91X_USE_16BIT);
- lp->cfg.flags &= ~(SMC_CAN_USE_32BIT ? 0 : SMC91X_USE_32BIT);
- #endif
-
ndev->dma = (unsigned char)-1;
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-regs");
+ if (!res)
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ ret = -ENODEV;
+ goto out_free_netdev;
+ }
+
+
+ if (!request_mem_region(res->start, SMC_IO_EXTENT, CARDNAME)) {
+ ret = -EBUSY;
+ goto out_free_netdev;
+ }
+
ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!ires) {
ret = -ENODEV;
- goto out_free_netdev;
+ goto out_release_io;
}
ndev->irq = ires->start;
- if (SMC_IRQ_FLAGS == -1)
- lp->cfg.irq_flags = ires->flags & IRQF_TRIGGER_MASK;
- ret = smc_request_attrib(pdev);
+ if (ires->flags & IRQF_TRIGGER_MASK)
+ irq_flags = ires->flags & IRQF_TRIGGER_MASK;
+
+ ret = smc_request_attrib(pdev, ndev);
if (ret)
- goto out_free_netdev;
+ goto out_release_io;
#if defined(CONFIG_SA1100_ASSABET)
NCR_0 |= NCR_ENET_OSC_EN;
#endif
goto out_release_attrib;
}
- #ifdef SMC_USE_PXA_DMA
+ #ifdef CONFIG_ARCH_PXA
{
struct smc_local *lp = netdev_priv(ndev);
lp->device = &pdev->dev;
}
#endif
- ret = smc_probe(ndev, addr, lp->cfg.irq_flags);
+ ret = smc_probe(ndev, addr, irq_flags);
if (ret != 0)
goto out_iounmap;
platform_set_drvdata(pdev, NULL);
iounmap(addr);
out_release_attrib:
- smc_release_attrib(pdev);
- out_free_netdev:
- free_netdev(ndev);
+ smc_release_attrib(pdev, ndev);
out_release_io:
release_mem_region(res->start, SMC_IO_EXTENT);
+ out_free_netdev:
+ free_netdev(ndev);
out:
printk("%s: not found (%d).\n", CARDNAME, ret);
free_irq(ndev->irq, ndev);
- #ifdef SMC_USE_PXA_DMA
+ #ifdef CONFIG_ARCH_PXA
if (ndev->dma != (unsigned char)-1)
pxa_free_dma(ndev->dma);
#endif
iounmap(lp->base);
smc_release_datacs(pdev,ndev);
- smc_release_attrib(pdev);
+ smc_release_attrib(pdev,ndev);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-regs");
if (!res)
help
Say Y to enable support for the battery on the OLPC laptop.
+config BATTERY_BQ27x00
+ tristate "BQ27x00 battery driver"
+ help
+ Say Y here to enable support for batteries with BQ27000 or BQ27200 chip.
+
+config BATTERY_BQ27000
+ bool "BQ27000 battery driver"
+ depends on BATTERY_BQ27x00
+ select W1
+ select W1_SLAVE_BQ27000
+ help
+ Say Y here to enable support for batteries with BQ27000(HDQ) chip.
+
+config BATTERY_BQ27200
+ bool "BQ27200 battery driver"
+ depends on BATTERY_BQ27x00
+ select I2C
+ select I2C_OMAP
+ help
+ Say Y here to enable support for batteries with BQ27200(I2C) chip.
+
+config TWL4030_BCI_BATTERY
+ tristate "OMAP TWL4030 BCI Battery driver"
+ depends on (MACH_OMAP_2430SDP || MACH_OMAP_3430SDP) && TWL4030_MADC
+ default y
+ help
+ Support for OMAP TWL4030 BCI Battery driver.
+ This driver can give support for TWL4030 Battery Charge Interface.
+
+ config BATTERY_TOSA
+ tristate "Sharp SL-6000 (tosa) battery"
+ depends on MACH_TOSA && MFD_TC6393XB
+ help
+ Say Y to enable support for the battery on the Sharp Zaurus
+ SL-6000 (tosa) models.
+
+ config BATTERY_PALMTX
+ tristate "Palm T|X battery"
+ depends on MACH_PALMTX
+ help
+ Say Y to enable support for the battery in Palm T|X.
+
endif # POWER_SUPPLY
obj-$(CONFIG_BATTERY_DS2760) += ds2760_battery.o
obj-$(CONFIG_BATTERY_PMU) += pmu_battery.o
obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o
+obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o
+obj-$(CONFIG_TWL4030_BCI_BATTERY) += twl4030_bci_battery.o
+ obj-$(CONFIG_BATTERY_TOSA) += tosa_battery.o
+ obj-$(CONFIG_BATTERY_PALMTX) += palmtx_battery.o
platforms. The support is integrated with the rest of
the Menelaus driver; it's not separate module.
+config RTC_DRV_TWL4030
+ tristate "OMAP TWL4030 Real Time Clock"
+ depends on RTC_CLASS && TWL4030_CORE
+ help
+ If you say yes here you get support for internal Real-Time
+ Clock of TWL4030 chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-twl4030.
+
config RTC_DRV_S35390A
tristate "Seiko Instruments S-35390A"
select BITREVERSE
if SPI_MASTER
+ config RTC_DRV_M41T94
+ tristate "ST M41T94"
+ help
+ If you say yes here you will get support for the
+ ST M41T94 SPI RTC chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-m41t94.
+
+ config RTC_DRV_DS1305
+ tristate "Dallas/Maxim DS1305/DS1306"
+ help
+ Select this driver to get support for the Dallas/Maxim DS1305
+ and DS1306 real time clock chips. These support a trickle
+ charger, alarms, and NVRAM in addition to the clock.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-ds1305.
+
config RTC_DRV_MAX6902
tristate "Maxim MAX6902"
help
To compile this driver as a module, choose M here: the
module will be called rtc-vr41xx.
+ config RTC_DRV_PL030
+ tristate "ARM AMBA PL030 RTC"
+ depends on ARM_AMBA
+ help
+ If you say Y here you will get access to ARM AMBA
+ PrimeCell PL030 RTC found on certain ARM SOCs.
+
+ To compile this driver as a module, choose M here: the
+ module will be called rtc-pl030.
+
config RTC_DRV_PL031
tristate "ARM AMBA PL031 RTC"
depends on ARM_AMBA
this is powered by the backup power supply.
config RTC_DRV_AT91SAM9
- tristate "AT91SAM9x"
+ tristate "AT91SAM9x/AT91CAP9"
depends on ARCH_AT91 && !(ARCH_AT91RM9200 || ARCH_AT91X40)
help
- RTC driver for the Atmel AT91SAM9x internal RTT (Real Time Timer).
- These timers are powered by the backup power supply (such as a
- small coin cell battery), but do not need to be used as RTCs.
+ RTC driver for the Atmel AT91SAM9x and AT91CAP9 internal RTT
+ (Real Time Timer). These timers are powered by the backup power
+ supply (such as a small coin cell battery), but do not need to
+ be used as RTCs.
(On AT91SAM9rl chips you probably want to use the dedicated RTC
module and leave the RTT available for other uses.)
obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o
obj-$(CONFIG_RTC_DRV_DS1216) += rtc-ds1216.o
obj-$(CONFIG_RTC_DRV_DS1302) += rtc-ds1302.o
+ obj-$(CONFIG_RTC_DRV_DS1305) += rtc-ds1305.o
obj-$(CONFIG_RTC_DRV_DS1307) += rtc-ds1307.o
obj-$(CONFIG_RTC_DRV_DS1374) += rtc-ds1374.o
obj-$(CONFIG_RTC_DRV_DS1511) += rtc-ds1511.o
obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o
obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o
obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o
+ obj-$(CONFIG_RTC_DRV_M41T94) += rtc-m41t94.o
obj-$(CONFIG_RTC_DRV_M48T59) += rtc-m48t59.o
obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o
obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o
obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o
obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o
obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o
+ obj-$(CONFIG_RTC_DRV_PL030) += rtc-pl030.o
obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o
obj-$(CONFIG_RTC_DRV_PPC) += rtc-ppc.o
obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o
obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o
obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o
obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o
+obj-$(CONFIG_RTC_DRV_TWL4030) += rtc-twl4030.o
obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o
obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o
obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
- * $Id: 8250.c,v 1.90 2002/07/28 10:03:27 rmk Exp $
- *
* A note about mapbase / membase
*
* mapbase is the physical address of the IO port.
static void
receive_chars(struct uart_8250_port *up, unsigned int *status)
{
- struct tty_struct *tty = up->port.info->tty;
+ struct tty_struct *tty = up->port.info->port.tty;
unsigned char ch, lsr = *status;
int max_count = 256;
char flag;
do {
- ch = serial_inp(up, UART_RX);
+ if (likely(lsr & UART_LSR_DR))
+ ch = serial_inp(up, UART_RX);
+ else
+ /*
+ * Intel 82571 has a Serial Over Lan device that will
+ * set UART_LSR_BI without setting UART_LSR_DR when
+ * it receives a break. To avoid reading from the
+ * receive buffer without UART_LSR_DR bit set, we
+ * just force the read character to be 0
+ */
+ ch = 0;
+
flag = TTY_NORMAL;
up->port.icount.rx++;
ignore_char:
lsr = serial_inp(up, UART_LSR);
- } while ((lsr & UART_LSR_DR) && (max_count-- > 0));
+ } while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (max_count-- > 0));
spin_unlock(&up->port.lock);
tty_flip_buffer_push(tty);
spin_lock(&up->port.lock);
DEBUG_INTR("status = %x...", status);
- if (status & UART_LSR_DR)
+ if (status & (UART_LSR_DR | UART_LSR_BI))
receive_chars(up, &status);
check_modem_status(up);
if (status & UART_LSR_THRE)
DEBUG_INTR("end.\n");
+#ifdef CONFIG_ARCH_OMAP15XX
+ return IRQ_HANDLED; /* FIXME: iir status not ready on 1510 */
+#else
return IRQ_RETVAL(handled);
+#endif
}
/*
* allow register changes to become visible.
*/
spin_lock_irqsave(&up->port.lock, flags);
+ if (up->port.flags & UPF_SHARE_IRQ)
+ disable_irq_nosync(up->port.irq);
wait_for_xmitr(up, UART_LSR_THRE);
serial_out_sync(up, UART_IER, UART_IER_THRI);
iir = serial_in(up, UART_IIR);
serial_out(up, UART_IER, 0);
+ if (up->port.flags & UPF_SHARE_IRQ)
+ enable_irq(up->port.irq);
spin_unlock_irqrestore(&up->port.lock, flags);
/*
/* emulated UARTs (Lucent Venus 167x) need two steps */
serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
}
+
+ /* Note that we need to set ECB to access write water mark
+ * bits. First allow FCR tx fifo write, then set fcr with
+ * possible TX fifo settings. */
+ if (uart_config[up->port.type].flags & UART_CAP_EFR) {
+ serial_outp(up, UART_LCR, 0xbf); /* Access EFR */
+ serial_outp(up, UART_EFR, UART_EFR_ECB);
+ serial_outp(up, UART_LCR, 0x0); /* Access FCR */
+ serial_outp(up, UART_FCR, fcr);
+ serial_outp(up, UART_LCR, 0xbf); /* Access EFR */
+ serial_outp(up, UART_EFR, 0);
+ serial_outp(up, UART_LCR, cval); /* Access FCR */
+ } else
serial_outp(up, UART_FCR, fcr); /* set fcr */
}
serial8250_set_mctrl(&up->port, up->port.mctrl);
unsigned int size = 8 << up->port.regshift;
int ret = 0;
+#ifdef CONFIG_ARCH_OMAP
+ if (is_omap_port((unsigned int)up->port.membase))
+ size = 0x16 << up->port.regshift;
+#endif
+
switch (up->port.iotype) {
case UPIO_AU:
size = 0x100000;
if (nr_uarts > UART_NR)
nr_uarts = UART_NR;
- printk(KERN_INFO "Serial: 8250/16550 driver $Revision: 1.90 $ "
+ printk(KERN_INFO "Serial: 8250/16550 driver"
"%d ports, IRQ sharing %sabled\n", nr_uarts,
share_irqs ? "en" : "dis");
EXPORT_SYMBOL(serial8250_resume_port);
MODULE_LICENSE("GPL");
- MODULE_DESCRIPTION("Generic 8250/16x50 serial driver $Revision: 1.90 $");
+ MODULE_DESCRIPTION("Generic 8250/16x50 serial driver");
module_param(share_irqs, uint, 0644);
MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices"
controller and the protocol drivers for the SPI slave chips
that are connected.
+ if SPI_MASTER
+
comment "SPI Master Controller Drivers"
- depends on SPI_MASTER
config SPI_ATMEL
tristate "Atmel SPI Controller"
- depends on (ARCH_AT91 || AVR32) && SPI_MASTER
+ depends on (ARCH_AT91 || AVR32)
help
This selects a driver for the Atmel SPI Controller, present on
many AT32 (AVR32) and AT91 (ARM) chips.
config SPI_BFIN
tristate "SPI controller driver for ADI Blackfin5xx"
- depends on SPI_MASTER && BLACKFIN
+ depends on BLACKFIN
help
This is the SPI controller master driver for Blackfin 5xx processor.
config SPI_AU1550
tristate "Au1550/Au12x0 SPI Controller"
- depends on SPI_MASTER && (SOC_AU1550 || SOC_AU1200) && EXPERIMENTAL
+ depends on (SOC_AU1550 || SOC_AU1200) && EXPERIMENTAL
select SPI_BITBANG
help
If you say yes to this option, support will be included for the
config SPI_BITBANG
tristate "Bitbanging SPI master"
- depends on SPI_MASTER && EXPERIMENTAL
help
With a few GPIO pins, your system can bitbang the SPI protocol.
Select this to get SPI support through I/O pins (GPIO, parallel
config SPI_BUTTERFLY
tristate "Parallel port adapter for AVR Butterfly (DEVELOPMENT)"
- depends on SPI_MASTER && PARPORT && EXPERIMENTAL
+ depends on PARPORT
select SPI_BITBANG
help
This uses a custom parallel port cable to connect to an AVR
config SPI_IMX
tristate "Freescale iMX SPI controller"
- depends on SPI_MASTER && ARCH_IMX && EXPERIMENTAL
+ depends on ARCH_IMX && EXPERIMENTAL
help
This enables using the Freescale iMX SPI controller in master
mode.
config SPI_LM70_LLP
tristate "Parallel port adapter for LM70 eval board (DEVELOPMENT)"
- depends on SPI_MASTER && PARPORT && EXPERIMENTAL
+ depends on PARPORT && EXPERIMENTAL
select SPI_BITBANG
help
This driver supports the NS LM70 LLP Evaluation Board,
config SPI_MPC52xx_PSC
tristate "Freescale MPC52xx PSC SPI controller"
- depends on SPI_MASTER && PPC_MPC52xx && EXPERIMENTAL
+ depends on PPC_MPC52xx && EXPERIMENTAL
help
This enables using the Freescale MPC52xx Programmable Serial
Controller in master SPI mode.
config SPI_MPC83xx
tristate "Freescale MPC83xx/QUICC Engine SPI controller"
- depends on SPI_MASTER && (PPC_83xx || QUICC_ENGINE) && EXPERIMENTAL
+ depends on (PPC_83xx || QUICC_ENGINE) && EXPERIMENTAL
help
This enables using the Freescale MPC83xx and QUICC Engine SPI
controllers in master mode.
config SPI_OMAP_UWIRE
tristate "OMAP1 MicroWire"
- depends on SPI_MASTER && ARCH_OMAP1
+ depends on ARCH_OMAP1
select SPI_BITBANG
help
This hooks up to the MicroWire controller on OMAP1 chips.
config SPI_OMAP24XX
tristate "McSPI driver for OMAP24xx/OMAP34xx"
- depends on SPI_MASTER && (ARCH_OMAP24XX || ARCH_OMAP34XX)
+ depends on ARCH_OMAP24XX || ARCH_OMAP34XX
help
SPI master controller for OMAP24xx/OMAP34xx Multichannel SPI
(McSPI) modules.
+ config SPI_ORION
+ tristate "Orion SPI master (EXPERIMENTAL)"
+ depends on PLAT_ORION && EXPERIMENTAL
+ help
+ This enables using the SPI master controller on the Orion chips.
+
config SPI_PXA2XX
tristate "PXA2xx SSP SPI master"
- depends on SPI_MASTER && ARCH_PXA && EXPERIMENTAL
+ depends on ARCH_PXA && EXPERIMENTAL
select PXA_SSP
help
This enables using a PXA2xx SSP port as a SPI master controller.
config SPI_S3C24XX
tristate "Samsung S3C24XX series SPI"
- depends on SPI_MASTER && ARCH_S3C2410 && EXPERIMENTAL
+ depends on ARCH_S3C2410 && EXPERIMENTAL
select SPI_BITBANG
help
SPI driver for Samsung S3C24XX series ARM SoCs
config SPI_S3C24XX_GPIO
tristate "Samsung S3C24XX series SPI by GPIO"
- depends on SPI_MASTER && ARCH_S3C2410 && EXPERIMENTAL
+ depends on ARCH_S3C2410 && EXPERIMENTAL
select SPI_BITBANG
help
SPI driver for Samsung S3C24XX series ARM SoCs using
config SPI_SH_SCI
tristate "SuperH SCI SPI controller"
- depends on SPI_MASTER && SUPERH
+ depends on SUPERH
select SPI_BITBANG
help
SPI driver for SuperH SCI blocks.
config SPI_TXX9
tristate "Toshiba TXx9 SPI controller"
- depends on SPI_MASTER && GENERIC_GPIO && CPU_TX49XX
+ depends on GENERIC_GPIO && CPU_TX49XX
help
SPI driver for Toshiba TXx9 MIPS SoCs
config SPI_XILINX
tristate "Xilinx SPI controller"
- depends on SPI_MASTER && XILINX_VIRTEX && EXPERIMENTAL
+ depends on XILINX_VIRTEX && EXPERIMENTAL
select SPI_BITBANG
help
This exposes the SPI controller IP from the Xilinx EDK.
# being probably the most widely used ones.
#
comment "SPI Protocol Masters"
- depends on SPI_MASTER
config SPI_AT25
tristate "SPI EEPROMs from most vendors"
- depends on SPI_MASTER && SYSFS
+ depends on SYSFS
help
Enable this driver to get read/write support to most SPI EEPROMs,
after you configure the board init code to know about each eeprom
This driver can also be built as a module. If so, the module
will be called at25.
+config SPI_TSC2101
+ depends on SPI_MASTER
+ tristate "TSC2101 chip support"
+ ---help---
+ Say Y here if you want support for the TSC2101 chip.
+ At the moment it provides basic register read / write interface
+ as well as a way to enable the MCLK clock.
+
+config SPI_TSC2102
+ depends on SPI_MASTER
+ tristate "TSC2102 codec support"
+ ---help---
+ Say Y here if you want support for the TSC2102 chip. It
+ will be needed for the touchscreen driver on some boards.
+
+config SPI_TSC210X
+ depends on SPI_MASTER && EXPERIMENTAL
+ tristate "TI TSC210x (TSC2101/TSC2102) support"
+ help
+ Say Y here if you want support for the TSC210x chips. Some
+ boards use these for touchscreen and audio support.
+
+ These are members of a family of highly integrated PDA analog
+ interface circuit. They include a 12-bit ADC used for battery,
+ temperature, touchscreen, and other sensors. They also have
+ an audio DAC and amplifier, and in some models an audio ADC.
+ The audio support is highly chip-specific, but most of the
+ sensor support works the same.
+
+ Note that the device has to be present in the board's SPI
+ devices table for this driver to load. This driver doesn't
+ automatically enable touchscreen, sensors or audio
+ functionality - enable these in their respective menus.
+
+config SPI_TSC2301
+ tristate "TSC2301 driver"
+ depends on SPI_MASTER
+ help
+ Say Y here if you have a TSC2301 chip connected to an SPI
+ bus on your board.
+
+ The TSC2301 is a highly integrated PDA analog interface circuit.
+ It contains a complete 12-bit A/D resistive touch screen
+ converter (ADC) including drivers, touch pressure measurement
+ capability, keypad controller, and 8-bit D/A converter (DAC) output
+ for LCD contrast control.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tsc2301.
+
+config SPI_TSC2301_AUDIO
+ boolean "TSC2301 audio support"
+ depends on SPI_TSC2301 && SND
+ help
+ Say Y here for if you are using the audio features of TSC2301.
+
config SPI_SPIDEV
tristate "User mode SPI device driver support"
- depends on SPI_MASTER && EXPERIMENTAL
+ depends on EXPERIMENTAL
help
This supports user mode SPI protocol drivers.
config SPI_TLE62X0
tristate "Infineon TLE62X0 (for power switching)"
- depends on SPI_MASTER && SYSFS
+ depends on SYSFS
help
SPI driver for Infineon TLE62X0 series line driver chips,
such as the TLE6220, TLE6230 and TLE6240. This provides a
# Add new SPI protocol masters in alphabetical order above this line
#
+ endif # SPI_MASTER
+
# (slave support would go here)
endif # SPI
obj-$(CONFIG_SPI_PXA2XX) += pxa2xx_spi.o
obj-$(CONFIG_SPI_OMAP_UWIRE) += omap_uwire.o
obj-$(CONFIG_SPI_OMAP24XX) += omap2_mcspi.o
+ obj-$(CONFIG_SPI_ORION) += orion_spi.o
obj-$(CONFIG_SPI_MPC52xx_PSC) += mpc52xx_psc_spi.o
obj-$(CONFIG_SPI_MPC83xx) += spi_mpc83xx.o
obj-$(CONFIG_SPI_S3C24XX_GPIO) += spi_s3c24xx_gpio.o
obj-$(CONFIG_SPI_AT25) += at25.o
obj-$(CONFIG_SPI_SPIDEV) += spidev.o
obj-$(CONFIG_SPI_TLE62X0) += tle62x0.o
+obj-$(CONFIG_SPI_TSC2101) += tsc2101.o
+obj-$(CONFIG_SPI_TSC2102) += tsc2102.o
+obj-$(CONFIG_SPI_TSC210X) += tsc210x.o
+obj-$(CONFIG_SPI_TSC2301) += tsc2301.o
+tsc2301-objs := tsc2301-core.o
+tsc2301-$(CONFIG_SPI_TSC2301_AUDIO) += tsc2301-mixer.o
# ... add above this line ...
# SPI slave controller drivers (upstream link)
config USB_GADGET_ATMEL_USBA
boolean "Atmel USBA"
select USB_GADGET_DUALSPEED
- depends on AVR32 || ARCH_AT91CAP9
+ depends on AVR32 || ARCH_AT91CAP9 || ARCH_AT91SAM9RL
help
USBA is the integrated high-speed USB Device controller on
- the AT32AP700x and AT91CAP9 processors from Atmel.
+ the AT32AP700x, some AT91SAM9 and AT91CAP9 processors from Atmel.
config USB_ATMEL_USBA
tristate
default USB_GADGET
select USB_GADGET_SELECTED
- config USB_GADGET_PXA2XX
+ config USB_GADGET_PXA25X
boolean "PXA 25x or IXP 4xx"
depends on (ARCH_PXA && PXA25x) || ARCH_IXP4XX
help
zero (for control transfers).
Say "y" to link the driver statically, or "m" to build a
- dynamically linked module called "pxa2xx_udc" and force all
+ dynamically linked module called "pxa25x_udc" and force all
gadget drivers to also be dynamically linked.
- config USB_PXA2XX
+ config USB_PXA25X
tristate
- depends on USB_GADGET_PXA2XX
+ depends on USB_GADGET_PXA25X
default USB_GADGET
select USB_GADGET_SELECTED
# if there's only one gadget driver, using only two bulk endpoints,
# don't waste memory for the other endpoints
- config USB_PXA2XX_SMALL
- depends on USB_GADGET_PXA2XX
+ config USB_PXA25X_SMALL
+ depends on USB_GADGET_PXA25X
bool
default n if USB_ETH_RNDIS
default y if USB_ZERO
default USB_GADGET
select USB_GADGET_SELECTED
+# built in ../musb along with host support
+config USB_GADGET_MUSB_HDRC
+ boolean "Inventra HDRC USB Peripheral (TI, ...)"
+ depends on USB_MUSB_HDRC && (USB_MUSB_PERIPHERAL || USB_MUSB_OTG)
+ select USB_GADGET_DUALSPEED
+ select USB_GADGET_SELECTED
+ help
+ This OTG-capable silicon IP is used in dual designs including
+ the TI DaVinci, OMAP 243x, OMAP 343x, and TUSB 6010.
+
config USB_GADGET_OMAP
boolean "OMAP USB Device Controller"
depends on ARCH_OMAP
- select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3
+ select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_H4_OTG
help
Many Texas Instruments OMAP processors have flexible full
speed USB device controllers, with support for up to 30
For more information, see Documentation/usb/gadget_printer.txt
which includes sample code for accessing the device file.
+ config USB_CDC_COMPOSITE
+ tristate "CDC Composite Device (Ethernet and ACM)"
+ depends on NET
+ help
+ This driver provides two functions in one configuration:
+ a CDC Ethernet (ECM) link, and a CDC ACM (serial port) link.
+
+ This driver requires four bulk and two interrupt endpoints,
+ plus the ability to handle altsettings. Not all peripheral
+ controllers are that capable.
+
+ Say "y" to link the driver statically, or "m" to build a
+ dynamically linked module.
+
# put drivers that need isochronous transfer support (for audio
# or video class gadget drivers), or specific hardware, here.
#include <asm/arch/dma.h>
#include <asm/arch/usb.h>
- #include <asm/arch/control.h>
#include "omap_udc.h"
status = -EINVAL;
else if (value) {
if (ep->udc->ep0_set_config) {
- WARN("error changing config?\n");
+ WARNING("error changing config?\n");
omap_writew(UDC_CLR_CFG, UDC_SYSCON2);
}
omap_writew(UDC_STALL_CMD, UDC_SYSCON2);
u.r.bRequestType, u.r.bRequest, status);
if (udc->ep0_set_config) {
if (udc->ep0_reset_config)
- WARN("error resetting config?\n");
+ WARNING("error resetting config?\n");
else
omap_writew(UDC_CLR_CFG, UDC_SYSCON2);
}
u32 trans;
char *ctrl_name;
- tmp = OTG_REV_REG;
+ tmp = omap_readw(OTG_REV);
if (cpu_is_omap24xx()) {
+ /*
+ * REVISIT: Not clear how this works on OMAP2. trans
+ * is ANDed to produce bits 7 and 8, which might make
+ * sense for USB_TRANSCEIVER_CTRL on OMAP1,
+ * but with CONTROL_DEVCONF, these bits have something to
+ * do with the frame adjustment counter and McBSP2.
+ */
ctrl_name = "control_devconf";
- trans = CONTROL_DEVCONF_REG;
+ trans = omap_ctrl_readb(OMAP2_CONTROL_DEVCONF0);
} else {
ctrl_name = "tranceiver_ctrl";
trans = omap_readw(USB_TRANSCEIVER_CTRL);
* and ignored for PIO-IN on newer chips
* (for more reliable behavior)
*/
- if (!use_dma || cpu_is_omap15xx() || cpu_is_omap24xx())
+ if ((!use_dma && (addr & USB_DIR_IN))
+ || machine_is_omap_apollon()
+ || cpu_is_omap15xx())
dbuf = 0;
switch (maxp) {
udc->gadget.name = driver_name;
device_initialize(&udc->gadget.dev);
- dev_set_name(&udc->gadget.dev, "gadget");
+ strcpy (udc->gadget.dev.bus_id, "gadget");
udc->gadget.dev.release = omap_udc_release;
udc->gadget.dev.parent = &odev->dev;
if (use_dma)
* which would prevent entry to deep sleep...
*/
if ((devstat & UDC_ATT) != 0 && (devstat & UDC_SUS) == 0) {
- WARN("session active; suspend requires disconnect\n");
+ WARNING("session active; suspend requires disconnect\n");
omap_pullup(&udc->gadget, 0);
}
#define EHCI_IAA_MSECS 10 /* arbitrary */
#define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */
#define EHCI_ASYNC_JIFFIES (HZ/20) /* async idle timeout */
- #define EHCI_SHRINK_JIFFIES (HZ/200) /* async qh unlink delay */
+ #define EHCI_SHRINK_FRAMES 5 /* async qh unlink delay */
/* Initial IRQ latency: faster than hw default */
static int log2_irq_thresh = 0; // 0 to 6
#define PLATFORM_DRIVER ehci_hcd_au1xxx_driver
#endif
+#ifdef CONFIG_ARCH_OMAP34XX
+#include "ehci-omap.c"
+#define PLATFORM_DRIVER ehci_hcd_omap_driver
+#endif
+
#ifdef CONFIG_PPC_PS3
#include "ehci-ps3.c"
#define PS3_SYSTEM_BUS_DRIVER ps3_ehci_driver
omap_ohci_clock_power(1);
- if (cpu_is_omap1510()) {
+ if (cpu_is_omap15xx()) {
omap_1510_local_bus_power(1);
omap_1510_local_bus_init();
}
if (IS_ERR(usb_host_ck))
return PTR_ERR(usb_host_ck);
- if (!cpu_is_omap1510())
+ if (!cpu_is_omap15xx())
usb_dc_ck = clk_get(0, "usb_dc_ck");
else
usb_dc_ck = clk_get(0, "lb_ck");
}
- hcd = usb_create_hcd (driver, &pdev->dev, pdev->dev.bus_id);
+ hcd = usb_create_hcd (driver, &pdev->dev, dev_name(&pdev->dev));
if (!hcd) {
retval = -ENOMEM;
goto err0;
The LTV350QV panel is present on all ATSTK1000 boards.
+ config LCD_ILI9320
+ tristate
+ depends on LCD_CLASS_DEVICE && BACKLIGHT_LCD_SUPPORT
+ default n
+ help
+ If you have a panel based on the ILI9320 controller chip
+ then say y to include a power driver for it.
+
+ config LCD_VGG2432A4
+ tristate "VGG2432A4 LCM device support"
+ depends on BACKLIGHT_LCD_SUPPORT && LCD_CLASS_DEVICE && SPI_MASTER
+ select LCD_ILI9320
+ default n
+ help
+ If you have a VGG2432A4 panel based on the ILI9320 controller chip
+ then say y to include a power driver for it.
+
+ config LCD_PLATFORM
+ tristate "Platform LCD controls"
+ depends on LCD_CLASS_DEVICE
+ help
+ This driver provides a platform-device registered LCD power
+ control interface.
+
#
# Backlight
#
If in doubt, it's safe to enable this option; it doesn't kick
in unless the board's description says it's wired that way.
+ config BACKLIGHT_ATMEL_PWM
+ tristate "Atmel PWM backlight control"
+ depends on BACKLIGHT_CLASS_DEVICE && ATMEL_PWM
+ default n
+ help
+ Say Y here if you want to use the PWM peripheral in Atmel AT91 and
+ AVR32 devices. This driver will need additional platform data to know
+ which PWM instance to use and how to configure it.
+
+ To compile this driver as a module, choose M here: the module will be
+ called atmel-pwm-bl.
+
config BACKLIGHT_CORGI
tristate "Generic (aka Sharp Corgi) Backlight Driver"
depends on BACKLIGHT_CLASS_DEVICE
If you have a HP Jornada 680, say y to enable the
backlight driver.
+config BACKLIGHT_OMAP
+ tristate "OMAP LCD Backlight"
+ depends on BACKLIGHT_CLASS_DEVICE && (ARCH_OMAP1 || ARCH_OMAP2)
+ default y
+ help
+ This driver controls the LCD backlight level and power
+ for the PWL module of OMAP processors. Say Y if you plan
+ to use power saving.
+
config BACKLIGHT_PROGEAR
tristate "Frontpath ProGear Backlight Driver"
depends on BACKLIGHT_CLASS_DEVICE && PCI && X86
help
If you have a Intel LE80578 (Carillo Ranch) say Y to enable the
backlight driver.
+
+ config BACKLIGHT_PWM
+ tristate "Generic PWM based Backlight Driver"
+ depends on BACKLIGHT_CLASS_DEVICE && HAVE_PWM
+ help
+ If you have a LCD backlight adjustable by PWM, say Y to enable
+ this driver.
+
+ config BACKLIGHT_MBP_NVIDIA
+ tristate "MacBook Pro Nvidia Backlight Driver"
+ depends on BACKLIGHT_CLASS_DEVICE && X86
+ default n
+ help
+ If you have an Apple Macbook Pro with Nvidia graphics hardware say Y
+ to enable a driver for its backlight
+
*/
#include <linux/kernel.h>
#include <linux/dma-mapping.h>
+ #include <linux/mm.h>
#include <linux/vmalloc.h>
#include <linux/clk.h>
#include <linux/io.h>
static int get_dss_clocks(void)
{
- if (IS_ERR((dispc.dss_ick = clk_get(dispc.fbdev->dev, "dss_ick")))) {
- dev_err(dispc.fbdev->dev, "can't get dss_ick\n");
+ char *dss_ick = "dss_ick";
+ char *dss1_fck = cpu_is_omap34xx() ? "dss1_alwon_fck" : "dss1_fck";
+ char *tv_fck = cpu_is_omap34xx() ? "dss_tv_fck" : "dss_54m_fck";
+
+ if (IS_ERR((dispc.dss_ick = clk_get(dispc.fbdev->dev, dss_ick)))) {
+ dev_err(dispc.fbdev->dev, "can't get %s", dss_ick);
return PTR_ERR(dispc.dss_ick);
}
- if (IS_ERR((dispc.dss1_fck = clk_get(dispc.fbdev->dev, "dss1_fck")))) {
- dev_err(dispc.fbdev->dev, "can't get dss1_fck\n");
+ if (IS_ERR((dispc.dss1_fck = clk_get(dispc.fbdev->dev, dss1_fck)))) {
+ dev_err(dispc.fbdev->dev, "can't get %s", dss1_fck);
clk_put(dispc.dss_ick);
return PTR_ERR(dispc.dss1_fck);
}
if (IS_ERR((dispc.dss_54m_fck =
- clk_get(dispc.fbdev->dev, "dss_54m_fck")))) {
- dev_err(dispc.fbdev->dev, "can't get dss_54m_fck\n");
+ clk_get(dispc.fbdev->dev, tv_fck)))) {
+ dev_err(dispc.fbdev->dev, "can't get %s", tv_fck);
clk_put(dispc.dss_ick);
clk_put(dispc.dss1_fck);
return PTR_ERR(dispc.dss_54m_fck);
}
/* Enable smart idle and autoidle */
- l = dispc_read_reg(DISPC_CONTROL);
+ l = dispc_read_reg(DISPC_SYSCONFIG);
l &= ~((3 << 12) | (3 << 3));
l |= (2 << 12) | (2 << 3) | (1 << 0);
dispc_write_reg(DISPC_SYSCONFIG, l);
dispc_write_reg(DISPC_CONFIG, l);
l = dispc_read_reg(DISPC_IRQSTATUS);
- dispc_write_reg(l, DISPC_IRQSTATUS);
+ dispc_write_reg(DISPC_IRQSTATUS, l);
/* Enable those that we handle always */
omap_dispc_enable_irqs(DISPC_IRQ_FRAMEMASK);
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <linux/platform_device.h>
+ #include <linux/mm.h>
#include <linux/uaccess.h>
#include <asm/mach-types.h>
{ OMAPFB_CAPS_WINDOW_PIXEL_DOUBLE, "pixel double window" },
{ OMAPFB_CAPS_WINDOW_SCALE, "scale window" },
{ OMAPFB_CAPS_WINDOW_OVERLAY, "overlay window" },
+ { OMAPFB_CAPS_WINDOW_ROTATE, "rotate window" },
{ OMAPFB_CAPS_SET_BACKLIGHT, "backlight setting" },
};
offset, var->xres_virtual,
plane->info.pos_x, plane->info.pos_y,
var->xres, var->yres, plane->color_mode);
+ if (r < 0)
+ return r;
+
+ if (fbdev->ctrl->set_rotate != NULL)
+ if((r = fbdev->ctrl->set_rotate(var->rotate)) < 0)
+ return r;
+
if (fbdev->ctrl->set_scale != NULL)
r = fbdev->ctrl->set_scale(plane->idx,
var->xres, var->yres,
var->xoffset = var->xres_virtual - var->xres;
if (var->yres + var->yoffset > var->yres_virtual)
var->yoffset = var->yres_virtual - var->yres;
- line_size = var->xres * bpp / 8;
if (plane->color_mode == OMAPFB_COLOR_RGB444) {
var->red.offset = 8; var->red.length = 4;
struct omapfb_device *fbdev = plane->fbdev;
omapfb_rqueue_lock(fbdev);
- if (cpu_is_omap15xx() && rotate != fbi->var.rotate) {
+ if (rotate != fbi->var.rotate) {
struct fb_var_screeninfo *new_var = &fbdev->new_var;
memcpy(new_var, &fbi->var, sizeof(*new_var));
void (*callback)(void *),
void *callback_data)
{
+ int xres, yres;
struct omapfb_plane_struct *plane = fbi->par;
struct omapfb_device *fbdev = plane->fbdev;
- struct fb_var_screeninfo *var;
+ struct fb_var_screeninfo *var = &fbi->var;
- var = &fbi->var;
- if (win->x >= var->xres || win->y >= var->yres ||
- win->out_x > var->xres || win->out_y >= var->yres)
+ switch (var->rotate) {
+ case 0:
+ case 180:
+ xres = fbdev->panel->x_res;
+ yres = fbdev->panel->y_res;
+ break;
+ case 90:
+ case 270:
+ xres = fbdev->panel->y_res;
+ yres = fbdev->panel->x_res;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (win->x >= xres || win->y >= yres ||
+ win->out_x > xres || win->out_y > yres)
return -EINVAL;
if (!fbdev->ctrl->update_window ||
fbdev->ctrl->get_update_mode() != OMAPFB_MANUAL_UPDATE)
return -ENODEV;
- if (win->x + win->width >= var->xres)
- win->width = var->xres - win->x;
- if (win->y + win->height >= var->yres)
- win->height = var->yres - win->y;
- /* The out sizes should be cropped to the LCD size */
- if (win->out_x + win->out_width > fbdev->panel->x_res)
- win->out_width = fbdev->panel->x_res - win->out_x;
- if (win->out_y + win->out_height > fbdev->panel->y_res)
- win->out_height = fbdev->panel->y_res - win->out_y;
+ if (win->x + win->width > xres)
+ win->width = xres - win->x;
+ if (win->y + win->height > yres)
+ win->height = yres - win->y;
+ if (win->out_x + win->out_width > xres)
+ win->out_width = xres - win->out_x;
+ if (win->out_y + win->out_height > yres)
+ win->out_height = yres - win->out_y;
if (!win->width || !win->height || !win->out_width || !win->out_height)
return 0;
{
struct omapfb_device *fbdev = platform_get_drvdata(pdev);
- omapfb_blank(VESA_POWERDOWN, fbdev->fb_info[0]);
-
+ if (fbdev != NULL)
+ omapfb_blank(VESA_POWERDOWN, fbdev->fb_info[0]);
return 0;
}
{
struct omapfb_device *fbdev = platform_get_drvdata(pdev);
- omapfb_blank(VESA_NO_BLANKING, fbdev->fb_info[0]);
+ if (fbdev != NULL)
+ omapfb_blank(VESA_NO_BLANKING, fbdev->fb_info[0]);
return 0;
}
* OMAP1 Special OptimiSed Screen Interface support
*
* Copyright (C) 2004-2005 Nokia Corporation
- * Author: Juha Yrjölä <juha.yrjola@nokia.com>
+ * Author: Juha Yrj�l� <juha.yrjola@nokia.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
sossi_write_reg(SOSSI_INIT1_REG, l);
if ((r = request_irq(INT_1610_SoSSI_MATCH, sossi_match_irq,
- IRQT_FALLING,
+ IRQ_TYPE_EDGE_FALLING,
"sossi_match", sossi.fbdev->dev)) < 0) {
dev_err(sossi.fbdev->dev, "can't get SoSSI match IRQ\n");
goto err;
config OMAP_WATCHDOG
tristate "OMAP Watchdog"
- depends on ARCH_OMAP16XX || ARCH_OMAP24XX
+ depends on ARCH_OMAP16XX || ARCH_OMAP24XX || ARCH_OMAP34XX
help
- Support for TI OMAP1610/OMAP1710/OMAP2420 watchdog. Say 'Y' here to
- enable the OMAP1610/OMAP1710 watchdog timer.
+ Support for TI OMAP1610/OMAP1710/OMAP2420/OMAP3430 watchdog. Say 'Y'
+ here to enable the OMAP1610/OMAP1710/OMAP2420/OMAP3430 watchdog timer.
config PNX4008_WATCHDOG
tristate "PNX4008 Watchdog"
machines. The watchdog timeout period is normally one minute but
can be changed with a boot-time parameter.
- # V850 Architecture
-
# XTENSA Architecture
#
#define CN_VAL_CIFS 0x1
#define CN_W1_IDX 0x3 /* w1 communication */
#define CN_W1_VAL 0x1
+#define CN_IDX_SX1SND 0x4
+#define CN_VAL_SX1SND 0x1
#define CN_IDX_V86D 0x4
#define CN_VAL_V86D_UVESAFB 0x1
+ #define CN_IDX_BB 0x5 /* BlackBoard, from the TSP GPL sampling framework */
- #define CN_NETLINK_USERS 5
+ #define CN_NETLINK_USERS 6
/*
* Maximum connector's message size.
/*
* Architectures can override it:
*/
- void __attribute__((weak)) early_printk(const char *fmt, ...)
+ void asmlinkage __attribute__((weak)) early_printk(const char *fmt, ...)
{
}
#define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT)
+#ifdef CONFIG_DEBUG_LL
+extern void printascii(char *);
+#endif
+
/* printk's without a loglevel use this.. */
#define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */
static DECLARE_MUTEX(console_sem);
static DECLARE_MUTEX(secondary_console_sem);
struct console *console_drivers;
+ EXPORT_SYMBOL_GPL(console_drivers);
+
/*
* This is used for debugging the mess that is the VT code by
* keeping track if we have the console semaphore held. It's
static struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES];
static int selected_console = -1;
static int preferred_console = -1;
+ int console_set_on_cmdline;
+ EXPORT_SYMBOL(console_set_on_cmdline);
/* Flag: console code may call schedule() */
static int console_may_schedule;
/*
* Return the number of unread characters in the log buffer.
*/
- int log_buf_get_len(void)
+ static int log_buf_get_len(void)
{
return logged_chars;
}
return ret;
}
- /*
- * Extract a single character from the log buffer.
- */
- int log_buf_read(int idx)
- {
- char ret;
-
- if (log_buf_copy(&ret, idx, 1) == 1)
- return ret;
- else
- return -1;
- }
-
/*
* Commands to do_syslog:
*
spin_unlock(&logbuf_lock);
return retval;
}
-
- static const char printk_recursion_bug_msg [] =
- KERN_CRIT "BUG: recent printk recursion!\n";
- static int printk_recursion_bug;
+ static const char recursion_bug_msg [] =
+ KERN_CRIT "BUG: recent printk recursion!\n";
+ static int recursion_bug;
+ static int new_text_line = 1;
+ static char printk_buf[1024];
asmlinkage int vprintk(const char *fmt, va_list args)
{
- static int log_level_unknown = 1;
- static char printk_buf[1024];
-
- unsigned long flags;
int printed_len = 0;
+ int current_log_level = default_message_loglevel;
+ unsigned long flags;
int this_cpu;
char *p;
* it can be printed at the next appropriate moment:
*/
if (!oops_in_progress) {
- printk_recursion_bug = 1;
+ recursion_bug = 1;
goto out_restore_irqs;
}
zap_locks();
spin_lock(&logbuf_lock);
printk_cpu = this_cpu;
- if (printk_recursion_bug) {
- printk_recursion_bug = 0;
- strcpy(printk_buf, printk_recursion_bug_msg);
- printed_len = sizeof(printk_recursion_bug_msg);
+ if (recursion_bug) {
+ recursion_bug = 0;
+ strcpy(printk_buf, recursion_bug_msg);
+ printed_len = sizeof(recursion_bug_msg);
}
/* Emit the output into the temporary buffer */
printed_len += vscnprintf(printk_buf + printed_len,
sizeof(printk_buf) - printed_len, fmt, args);
+#ifdef CONFIG_DEBUG_LL
+ printascii(printk_buf);
+#endif
/*
* Copy the output into log_buf. If the caller didn't provide
* appropriate log level tags, we insert them here
*/
for (p = printk_buf; *p; p++) {
- if (log_level_unknown) {
- /* log_level_unknown signals the start of a new line */
+ if (new_text_line) {
+ /* If a token, set current_log_level and skip over */
+ if (p[0] == '<' && p[1] >= '0' && p[1] <= '7' &&
+ p[2] == '>') {
+ current_log_level = p[1] - '0';
+ p += 3;
+ printed_len -= 3;
+ }
+
+ /* Always output the token */
+ emit_log_char('<');
+ emit_log_char(current_log_level + '0');
+ emit_log_char('>');
+ printed_len += 3;
+ new_text_line = 0;
+
if (printk_time) {
- int loglev_char;
+ /* Follow the token with the time */
char tbuf[50], *tp;
unsigned tlen;
unsigned long long t;
unsigned long nanosec_rem;
- /*
- * force the log level token to be
- * before the time output.
- */
- if (p[0] == '<' && p[1] >='0' &&
- p[1] <= '7' && p[2] == '>') {
- loglev_char = p[1];
- p += 3;
- printed_len -= 3;
- } else {
- loglev_char = default_message_loglevel
- + '0';
- }
t = cpu_clock(printk_cpu);
nanosec_rem = do_div(t, 1000000000);
- tlen = sprintf(tbuf,
- "<%c>[%5lu.%06lu] ",
- loglev_char,
- (unsigned long)t,
- nanosec_rem/1000);
+ tlen = sprintf(tbuf, "[%5lu.%06lu] ",
+ (unsigned long) t,
+ nanosec_rem / 1000);
for (tp = tbuf; tp < tbuf + tlen; tp++)
emit_log_char(*tp);
printed_len += tlen;
- } else {
- if (p[0] != '<' || p[1] < '0' ||
- p[1] > '7' || p[2] != '>') {
- emit_log_char('<');
- emit_log_char(default_message_loglevel
- + '0');
- emit_log_char('>');
- printed_len += 3;
- }
}
- log_level_unknown = 0;
+
if (!*p)
break;
}
+
emit_log_char(*p);
if (*p == '\n')
- log_level_unknown = 1;
+ new_text_line = 1;
}
/*
*s = 0;
__add_preferred_console(buf, idx, options, brl_options);
+ console_set_on_cmdline = 1;
return 1;
}
__setup("console=", console_setup);
{
if (!console_suspend_enabled)
return;
- printk("Suspending console(s)\n");
+ printk("Suspending console(s) (use no_console_suspend to debug)\n");
acquire_console_sem();
console_suspended = 1;
}
_log_end = log_end;
con_start = log_end; /* Flush */
spin_unlock(&logbuf_lock);
+ stop_critical_timings(); /* don't trace print latency */
call_console_drivers(_con_start, _log_end);
+ start_critical_timings();
local_irq_restore(flags);
}
console_locked = 0;
console->index = 0;
if (console->setup == NULL ||
console->setup(console, NULL) == 0) {
- console->flags |= CON_ENABLED | CON_CONSDEV;
- preferred_console = 0;
+ console->flags |= CON_ENABLED;
+ if (console->device) {
+ console->flags |= CON_CONSDEV;
+ preferred_console = 0;
+ }
}
}
}
#if defined CONFIG_PRINTK
+
/*
* printk rate limiting, lifted from the networking subsystem.
*
- * This enforces a rate limit: not more than one kernel message
- * every printk_ratelimit_jiffies to make a denial-of-service
- * attack impossible.
+ * This enforces a rate limit: not more than 10 kernel messages
+ * every 5s to make a denial-of-service attack impossible.
*/
- int __printk_ratelimit(int ratelimit_jiffies, int ratelimit_burst)
- {
- return __ratelimit(ratelimit_jiffies, ratelimit_burst);
- }
- EXPORT_SYMBOL(__printk_ratelimit);
-
- /* minimum time in jiffies between messages */
- int printk_ratelimit_jiffies = 5 * HZ;
-
- /* number of messages we send before ratelimiting */
- int printk_ratelimit_burst = 10;
+ DEFINE_RATELIMIT_STATE(printk_ratelimit_state, 5 * HZ, 10);
int printk_ratelimit(void)
{
- return __printk_ratelimit(printk_ratelimit_jiffies,
- printk_ratelimit_burst);
+ return __ratelimit(&printk_ratelimit_state);
}
EXPORT_SYMBOL(printk_ratelimit);
help
NETMAP is an implementation of static 1:1 NAT mapping of network
addresses. It maps the network address part, while keeping the host
- address part intact. It is similar to Fast NAT, except that
- Netfilter's connection tracking doesn't work well with Fast NAT.
+ address part intact.
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_TARGET_IDLETIMER
+ tristate "IDLETIMER target support"
+ depends on IP_NF_IPTABLES
+ help
+ This option adds a `IDLETIMER' target. Each matching packet resets
+ the timer associated with input and/or output interfaces. Timer
+ expiry causes kobject uevent. Idle timer can be read via sysfs.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+
To compile it as a module, choose M here. If unsure, say N.
config NF_NAT_SNMP_BASIC
If you want to compile it as a module, say M here and read
<file:Documentation/kbuild/modules.txt>. If unsure, say `N'.
+
+ # security table for MAC policy
+ config IP_NF_SECURITY
+ tristate "Security table"
+ depends on IP_NF_IPTABLES
+ depends on SECURITY
+ depends on NETFILTER_ADVANCED
+ help
+ This option adds a `security' table to iptables, for use
+ with Mandatory Access Control (MAC) policy.
+
+ If unsure, say N.
# ARP tables
config IP_NF_ARPTABLES
obj-$(CONFIG_IP_NF_MANGLE) += iptable_mangle.o
obj-$(CONFIG_NF_NAT) += iptable_nat.o
obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o
+ obj-$(CONFIG_IP_NF_SECURITY) += iptable_security.o
# matches
obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o
obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o
obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o
+obj-$(CONFIG_IP_NF_TARGET_IDLETIMER) += ipt_IDLETIMER.o
obj-$(CONFIG_IP_NF_TARGET_TTL) += ipt_TTL.o
obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o
IPSec.
If you are unsure how to answer this question, answer N.
- config SECURITY_CAPABILITIES
- bool "Default Linux Capabilities"
- depends on SECURITY
- default y
- help
- This enables the "default" Linux capabilities functionality.
- If you are unsure how to answer this question, answer Y.
-
config SECURITY_FILE_CAPABILITIES
- bool "File POSIX Capabilities (EXPERIMENTAL)"
- depends on (SECURITY=n || SECURITY_CAPABILITIES!=n) && EXPERIMENTAL
+ bool "File POSIX Capabilities"
default n
help
This enables filesystem capabilities, allowing you to give
If you are unsure how to answer this question, answer N.
+config SECURITY_LOWMEM
+ tristate "Low memory watermark support"
+ depends on SECURITY
+ help
+ Implements low memory watermark support
+
+ If you are unsure how to answer this question, answer N.
+
config SECURITY_DEFAULT_MMAP_MIN_ADDR
int "Low address space to protect from user allocation"
depends on SECURITY
subdir-$(CONFIG_SECURITY_SELINUX) += selinux
subdir-$(CONFIG_SECURITY_SMACK) += smack
- # if we don't select a security model, use the default capabilities
- ifneq ($(CONFIG_SECURITY),y)
+ # always enable default capabilities
obj-y += commoncap.o
- endif
# Object file lists
- obj-$(CONFIG_SECURITY) += security.o dummy.o inode.o
+ obj-$(CONFIG_SECURITY) += security.o capability.o inode.o
# Must precede capability.o in order to stack properly.
obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o
- obj-$(CONFIG_SECURITY_SMACK) += commoncap.o smack/built-in.o
- obj-$(CONFIG_SECURITY_CAPABILITIES) += commoncap.o capability.o
- obj-$(CONFIG_SECURITY_ROOTPLUG) += commoncap.o root_plug.o
+ obj-$(CONFIG_SECURITY_SMACK) += smack/built-in.o
+ obj-$(CONFIG_SECURITY_ROOTPLUG) += root_plug.o
+obj-$(CONFIG_SECURITY_LOWMEM) += commoncap.o lowmem.o
obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o
# ALSA ARM drivers
- menu "ALSA ARM devices"
- depends on SND!=n && ARM
+ menuconfig SND_ARM
+ bool "ARM sound devices"
+ depends on ARM
+ default y
+ help
+ Support for sound devices specific to ARM architectures.
+ Drivers that are implemented on ASoC can be found in
+ "ALSA for SoC audio support" section.
+
+ if SND_ARM
config SND_SA11XX_UDA1341
tristate "SA11xx UDA1341TS driver (iPaq H3600)"
- depends on ARCH_SA1100 && SND && L3
+ depends on ARCH_SA1100 && L3
select SND_PCM
help
Say Y here if you have a Compaq iPaq H3x00 handheld computer
config SND_ARMAACI
tristate "ARM PrimeCell PL041 AC Link support"
- depends on SND && ARM_AMBA
+ depends on ARM_AMBA
select SND_PCM
select SND_AC97_CODEC
config SND_PXA2XX_AC97
tristate "AC97 driver for the Intel PXA2xx chip"
- depends on ARCH_PXA && SND
+ depends on ARCH_PXA
select SND_PXA2XX_PCM
select SND_AC97_CODEC
help
Say Y or M if you want to support any AC97 codec attached to
the PXA2xx AC97 interface.
-endif # SND_ARM
+config SND_OMAP_AIC23
+ tristate "OMAP AIC23 alsa driver (osk5912)"
+ depends on ARCH_OMAP && SND
+ select SND_PCM
+ select I2C
+ select I2C_OMAP if ARCH_OMAP
+ select SENSORS_TLV320AIC23
+ help
+ Say Y here if you have a OSK platform board
+ and want to use its AIC23 audio chip.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-omap-aic23.
+
+config SND_OMAP_TSC2101
+ tristate "OMAP TSC2101 alsa driver"
+ depends on ARCH_OMAP && SND
+ select SND_PCM
+ select SPI_TSC2101
+ help
+ Say Y here if you have a OMAP platform board
+ and want to use its TSC2101 audio chip. Driver has
+ been tested with H2 and iPAQ h6300.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-omap-tsc2101.
+
+config SND_SX1
+ tristate "Siemens SX1 Egold alsa driver"
+ depends on ARCH_OMAP && SND
+ select SND_PCM
+ help
+ Say Y here if you have a OMAP310 based Siemens SX1.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-omap-sx1.
+
+config SND_OMAP_TSC2102
+ tristate "OMAP TSC2102 alsa driver"
+ depends on ARCH_OMAP && SND
+ select SND_PCM
+ select SPI_TSC2102
+ help
+ Say Y here if you have an OMAP platform board
+ and want to use its TSC2102 audio chip.
- endmenu
+ To compile this driver as a module, choose M here: the module
+ will be called snd-omap-tsc2102.
+
+config SND_OMAP24XX_EAC
+ tristate "Audio driver for OMAP24xx EAC"
+ depends on SND
+ help
+ Audio driver for Enhanced Audio Controller found in TI's OMAP24xx
+ processors.
+
+ Currently contains only low-level support functions for
+ initializing EAC HW, creating ALSA sound card instance for it
+ and registering mixer controls implemented by a codec driver.
+ PCM stream is expected to be under DSP co-processor control.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-omap24xx-eac.
+
++endif # SND_ARM
obj-$(CONFIG_SOUND_OSS) += sound.o
+obj-$(CONFIG_SOUND_OMAP) += omap-audio-dma-intfc.o omap-audio.o
+obj-$(CONFIG_SOUND_OMAP_TSC2101)+= omap-audio-tsc2101.o
+obj-$(CONFIG_SOUND_OMAP_AIC23) += omap-audio-aic23.o
+
# Please leave it as is, cause the link order is significant !
obj-$(CONFIG_SOUND_SH_DAC_AUDIO) += sh_dac_audio.o
obj-$(CONFIG_SOUND_MSNDPIN) += msnd.o msnd_pinnacle.o
obj-$(CONFIG_SOUND_VWSND) += vwsnd.o
obj-$(CONFIG_SOUND_AU1550_AC97) += au1550_ac97.o ac97_codec.o
- obj-$(CONFIG_SOUND_TRIDENT) += trident.o ac97_codec.o
obj-$(CONFIG_SOUND_BCM_CS4297A) += swarm_cs4297a.o
- obj-$(CONFIG_SOUND_WM97XX) += ac97_plugin_wm97xx.o
-
obj-$(CONFIG_DMASOUND) += dmasound/
# Declare multi-part drivers.