Merge branch 'next-samsung' into for-next
Conflicts: arch/arm/mach-s5p6440/Kconfig arch/arm/mach-s5p6442/Kconfig arch/arm/mach-s5pc100/Kconfig arch/arm/mach-s5pv210/Kconfig arch/arm/mach-s5pv210/cpu.c arch/arm/plat-samsung/include/plat/sdhci.h
This commit is contained in:
Коммит
d61bd77ff1
|
@ -6,31 +6,149 @@ Multi-touch (MT) Protocol
|
|||
Introduction
|
||||
------------
|
||||
|
||||
In order to utilize the full power of the new multi-touch devices, a way to
|
||||
report detailed finger data to user space is needed. This document
|
||||
describes the multi-touch (MT) protocol which allows kernel drivers to
|
||||
report details for an arbitrary number of fingers.
|
||||
In order to utilize the full power of the new multi-touch and multi-user
|
||||
devices, a way to report detailed data from multiple contacts, i.e.,
|
||||
objects in direct contact with the device surface, is needed. This
|
||||
document describes the multi-touch (MT) protocol which allows kernel
|
||||
drivers to report details for an arbitrary number of contacts.
|
||||
|
||||
The protocol is divided into two types, depending on the capabilities of the
|
||||
hardware. For devices handling anonymous contacts (type A), the protocol
|
||||
describes how to send the raw data for all contacts to the receiver. For
|
||||
devices capable of tracking identifiable contacts (type B), the protocol
|
||||
describes how to send updates for individual contacts via event slots.
|
||||
|
||||
|
||||
Usage
|
||||
-----
|
||||
Protocol Usage
|
||||
--------------
|
||||
|
||||
Anonymous finger details are sent sequentially as separate packets of ABS
|
||||
events. Only the ABS_MT events are recognized as part of a finger
|
||||
packet. The end of a packet is marked by calling the input_mt_sync()
|
||||
function, which generates a SYN_MT_REPORT event. This instructs the
|
||||
receiver to accept the data for the current finger and prepare to receive
|
||||
another. The end of a multi-touch transfer is marked by calling the usual
|
||||
Contact details are sent sequentially as separate packets of ABS_MT
|
||||
events. Only the ABS_MT events are recognized as part of a contact
|
||||
packet. Since these events are ignored by current single-touch (ST)
|
||||
applications, the MT protocol can be implemented on top of the ST protocol
|
||||
in an existing driver.
|
||||
|
||||
Drivers for type A devices separate contact packets by calling
|
||||
input_mt_sync() at the end of each packet. This generates a SYN_MT_REPORT
|
||||
event, which instructs the receiver to accept the data for the current
|
||||
contact and prepare to receive another.
|
||||
|
||||
Drivers for type B devices separate contact packets by calling
|
||||
input_mt_slot(), with a slot as argument, at the beginning of each packet.
|
||||
This generates an ABS_MT_SLOT event, which instructs the receiver to
|
||||
prepare for updates of the given slot.
|
||||
|
||||
All drivers mark the end of a multi-touch transfer by calling the usual
|
||||
input_sync() function. This instructs the receiver to act upon events
|
||||
accumulated since last EV_SYN/SYN_REPORT and prepare to receive a new
|
||||
set of events/packets.
|
||||
accumulated since last EV_SYN/SYN_REPORT and prepare to receive a new set
|
||||
of events/packets.
|
||||
|
||||
The main difference between the stateless type A protocol and the stateful
|
||||
type B slot protocol lies in the usage of identifiable contacts to reduce
|
||||
the amount of data sent to userspace. The slot protocol requires the use of
|
||||
the ABS_MT_TRACKING_ID, either provided by the hardware or computed from
|
||||
the raw data [5].
|
||||
|
||||
For type A devices, the kernel driver should generate an arbitrary
|
||||
enumeration of the full set of anonymous contacts currently on the
|
||||
surface. The order in which the packets appear in the event stream is not
|
||||
important. Event filtering and finger tracking is left to user space [3].
|
||||
|
||||
For type B devices, the kernel driver should associate a slot with each
|
||||
identified contact, and use that slot to propagate changes for the contact.
|
||||
Creation, replacement and destruction of contacts is achieved by modifying
|
||||
the ABS_MT_TRACKING_ID of the associated slot. A non-negative tracking id
|
||||
is interpreted as a contact, and the value -1 denotes an unused slot. A
|
||||
tracking id not previously present is considered new, and a tracking id no
|
||||
longer present is considered removed. Since only changes are propagated,
|
||||
the full state of each initiated contact has to reside in the receiving
|
||||
end. Upon receiving an MT event, one simply updates the appropriate
|
||||
attribute of the current slot.
|
||||
|
||||
|
||||
Protocol Example A
|
||||
------------------
|
||||
|
||||
Here is what a minimal event sequence for a two-contact touch would look
|
||||
like for a type A device:
|
||||
|
||||
ABS_MT_POSITION_X x[0]
|
||||
ABS_MT_POSITION_Y y[0]
|
||||
SYN_MT_REPORT
|
||||
ABS_MT_POSITION_X x[1]
|
||||
ABS_MT_POSITION_Y y[1]
|
||||
SYN_MT_REPORT
|
||||
SYN_REPORT
|
||||
|
||||
The sequence after moving one of the contacts looks exactly the same; the
|
||||
raw data for all present contacts are sent between every synchronization
|
||||
with SYN_REPORT.
|
||||
|
||||
Here is the sequence after lifting the first contact:
|
||||
|
||||
ABS_MT_POSITION_X x[1]
|
||||
ABS_MT_POSITION_Y y[1]
|
||||
SYN_MT_REPORT
|
||||
SYN_REPORT
|
||||
|
||||
And here is the sequence after lifting the second contact:
|
||||
|
||||
SYN_MT_REPORT
|
||||
SYN_REPORT
|
||||
|
||||
If the driver reports one of BTN_TOUCH or ABS_PRESSURE in addition to the
|
||||
ABS_MT events, the last SYN_MT_REPORT event may be omitted. Otherwise, the
|
||||
last SYN_REPORT will be dropped by the input core, resulting in no
|
||||
zero-contact event reaching userland.
|
||||
|
||||
|
||||
Protocol Example B
|
||||
------------------
|
||||
|
||||
Here is what a minimal event sequence for a two-contact touch would look
|
||||
like for a type B device:
|
||||
|
||||
ABS_MT_SLOT 0
|
||||
ABS_MT_TRACKING_ID 45
|
||||
ABS_MT_POSITION_X x[0]
|
||||
ABS_MT_POSITION_Y y[0]
|
||||
ABS_MT_SLOT 1
|
||||
ABS_MT_TRACKING_ID 46
|
||||
ABS_MT_POSITION_X x[1]
|
||||
ABS_MT_POSITION_Y y[1]
|
||||
SYN_REPORT
|
||||
|
||||
Here is the sequence after moving contact 45 in the x direction:
|
||||
|
||||
ABS_MT_SLOT 0
|
||||
ABS_MT_POSITION_X x[0]
|
||||
SYN_REPORT
|
||||
|
||||
Here is the sequence after lifting the contact in slot 0:
|
||||
|
||||
ABS_MT_TRACKING_ID -1
|
||||
SYN_REPORT
|
||||
|
||||
The slot being modified is already 0, so the ABS_MT_SLOT is omitted. The
|
||||
message removes the association of slot 0 with contact 45, thereby
|
||||
destroying contact 45 and freeing slot 0 to be reused for another contact.
|
||||
|
||||
Finally, here is the sequence after lifting the second contact:
|
||||
|
||||
ABS_MT_SLOT 1
|
||||
ABS_MT_TRACKING_ID -1
|
||||
SYN_REPORT
|
||||
|
||||
|
||||
Event Usage
|
||||
-----------
|
||||
|
||||
A set of ABS_MT events with the desired properties is defined. The events
|
||||
are divided into categories, to allow for partial implementation. The
|
||||
minimum set consists of ABS_MT_POSITION_X and ABS_MT_POSITION_Y, which
|
||||
allows for multiple fingers to be tracked. If the device supports it, the
|
||||
allows for multiple contacts to be tracked. If the device supports it, the
|
||||
ABS_MT_TOUCH_MAJOR and ABS_MT_WIDTH_MAJOR may be used to provide the size
|
||||
of the contact area and approaching finger, respectively.
|
||||
of the contact area and approaching contact, respectively.
|
||||
|
||||
The TOUCH and WIDTH parameters have a geometrical interpretation; imagine
|
||||
looking through a window at someone gently holding a finger against the
|
||||
|
@ -41,56 +159,26 @@ ABS_MT_TOUCH_MAJOR, the diameter of the outer region is
|
|||
ABS_MT_WIDTH_MAJOR. Now imagine the person pressing the finger harder
|
||||
against the glass. The inner region will increase, and in general, the
|
||||
ratio ABS_MT_TOUCH_MAJOR / ABS_MT_WIDTH_MAJOR, which is always smaller than
|
||||
unity, is related to the finger pressure. For pressure-based devices,
|
||||
unity, is related to the contact pressure. For pressure-based devices,
|
||||
ABS_MT_PRESSURE may be used to provide the pressure on the contact area
|
||||
instead.
|
||||
|
||||
In addition to the MAJOR parameters, the oval shape of the finger can be
|
||||
In addition to the MAJOR parameters, the oval shape of the contact can be
|
||||
described by adding the MINOR parameters, such that MAJOR and MINOR are the
|
||||
major and minor axis of an ellipse. Finally, the orientation of the oval
|
||||
shape can be describe with the ORIENTATION parameter.
|
||||
|
||||
The ABS_MT_TOOL_TYPE may be used to specify whether the touching tool is a
|
||||
finger or a pen or something else. Devices with more granular information
|
||||
contact or a pen or something else. Devices with more granular information
|
||||
may specify general shapes as blobs, i.e., as a sequence of rectangular
|
||||
shapes grouped together by an ABS_MT_BLOB_ID. Finally, for the few devices
|
||||
that currently support it, the ABS_MT_TRACKING_ID event may be used to
|
||||
report finger tracking from hardware [5].
|
||||
report contact tracking from hardware [5].
|
||||
|
||||
Here is what a minimal event sequence for a two-finger touch would look
|
||||
like:
|
||||
|
||||
ABS_MT_POSITION_X
|
||||
ABS_MT_POSITION_Y
|
||||
SYN_MT_REPORT
|
||||
ABS_MT_POSITION_X
|
||||
ABS_MT_POSITION_Y
|
||||
SYN_MT_REPORT
|
||||
SYN_REPORT
|
||||
|
||||
Here is the sequence after lifting one of the fingers:
|
||||
|
||||
ABS_MT_POSITION_X
|
||||
ABS_MT_POSITION_Y
|
||||
SYN_MT_REPORT
|
||||
SYN_REPORT
|
||||
|
||||
And here is the sequence after lifting the remaining finger:
|
||||
|
||||
SYN_MT_REPORT
|
||||
SYN_REPORT
|
||||
|
||||
If the driver reports one of BTN_TOUCH or ABS_PRESSURE in addition to the
|
||||
ABS_MT events, the last SYN_MT_REPORT event may be omitted. Otherwise, the
|
||||
last SYN_REPORT will be dropped by the input core, resulting in no
|
||||
zero-finger event reaching userland.
|
||||
|
||||
Event Semantics
|
||||
---------------
|
||||
|
||||
The word "contact" is used to describe a tool which is in direct contact
|
||||
with the surface. A finger, a pen or a rubber all classify as contacts.
|
||||
|
||||
ABS_MT_TOUCH_MAJOR
|
||||
|
||||
The length of the major axis of the contact. The length should be given in
|
||||
|
@ -157,15 +245,16 @@ MT_TOOL_PEN [2].
|
|||
ABS_MT_BLOB_ID
|
||||
|
||||
The BLOB_ID groups several packets together into one arbitrarily shaped
|
||||
contact. This is a low-level anonymous grouping, and should not be confused
|
||||
with the high-level trackingID [5]. Most kernel drivers will not have blob
|
||||
capability, and can safely omit the event.
|
||||
contact. This is a low-level anonymous grouping for type A devices, and
|
||||
should not be confused with the high-level trackingID [5]. Most type A
|
||||
devices do not have blob capability, so drivers can safely omit this event.
|
||||
|
||||
ABS_MT_TRACKING_ID
|
||||
|
||||
The TRACKING_ID identifies an initiated contact throughout its life cycle
|
||||
[5]. There are currently only a few devices that support it, so this event
|
||||
should normally be omitted.
|
||||
[5]. This event is mandatory for type B devices. The value range of the
|
||||
TRACKING_ID should be large enough to ensure unique identification of a
|
||||
contact maintained over an extended period of time.
|
||||
|
||||
|
||||
Event Computation
|
||||
|
@ -192,20 +281,11 @@ finger along the X axis (1).
|
|||
Finger Tracking
|
||||
---------------
|
||||
|
||||
The kernel driver should generate an arbitrary enumeration of the set of
|
||||
anonymous contacts currently on the surface. The order in which the packets
|
||||
appear in the event stream is not important.
|
||||
|
||||
The process of finger tracking, i.e., to assign a unique trackingID to each
|
||||
initiated contact on the surface, is left to user space; preferably the
|
||||
multi-touch X driver [3]. In that driver, the trackingID stays the same and
|
||||
unique until the contact vanishes (when the finger leaves the surface). The
|
||||
problem of assigning a set of anonymous fingers to a set of identified
|
||||
fingers is a euclidian bipartite matching problem at each event update, and
|
||||
relies on a sufficiently rapid update rate.
|
||||
|
||||
There are a few devices that support trackingID in hardware. User space can
|
||||
make use of these native identifiers to reduce bandwidth and cpu usage.
|
||||
initiated contact on the surface, is a Euclidian Bipartite Matching
|
||||
problem. At each event synchronization, the set of actual contacts is
|
||||
matched to the set of contacts from the previous synchronization. A full
|
||||
implementation can be found in [3].
|
||||
|
||||
|
||||
Gestures
|
||||
|
|
|
@ -634,6 +634,7 @@ config ARCH_S3C2410
|
|||
select ARCH_HAS_CPUFREQ
|
||||
select HAVE_CLK
|
||||
select ARCH_USES_GETTIMEOFFSET
|
||||
select HAVE_S3C2410_I2C
|
||||
help
|
||||
Samsung S3C2410X CPU based systems, such as the Simtec Electronics
|
||||
BAST (<http://www.simtec.co.uk/products/EB110ITX/>), the IPAQ 1940 or
|
||||
|
@ -663,6 +664,8 @@ config ARCH_S3C64XX
|
|||
select S3C_DEV_NAND
|
||||
select USB_ARCH_HAS_OHCI
|
||||
select SAMSUNG_GPIOLIB_4BIT
|
||||
select HAVE_S3C2410_I2C
|
||||
select HAVE_S3C2410_WATCHDOG
|
||||
help
|
||||
Samsung S3C64XX series based systems
|
||||
|
||||
|
@ -671,7 +674,10 @@ config ARCH_S5P6440
|
|||
select CPU_V6
|
||||
select GENERIC_GPIO
|
||||
select HAVE_CLK
|
||||
select HAVE_S3C2410_WATCHDOG
|
||||
select ARCH_USES_GETTIMEOFFSET
|
||||
select HAVE_S3C2410_I2C
|
||||
select HAVE_S3C_RTC
|
||||
help
|
||||
Samsung S5P6440 CPU based systems
|
||||
|
||||
|
@ -681,6 +687,7 @@ config ARCH_S5P6442
|
|||
select GENERIC_GPIO
|
||||
select HAVE_CLK
|
||||
select ARCH_USES_GETTIMEOFFSET
|
||||
select HAVE_S3C2410_WATCHDOG
|
||||
help
|
||||
Samsung S5P6442 CPU based systems
|
||||
|
||||
|
@ -691,6 +698,9 @@ config ARCH_S5PC100
|
|||
select CPU_V7
|
||||
select ARM_L1_CACHE_SHIFT_6
|
||||
select ARCH_USES_GETTIMEOFFSET
|
||||
select HAVE_S3C2410_I2C
|
||||
select HAVE_S3C_RTC
|
||||
select HAVE_S3C2410_WATCHDOG
|
||||
help
|
||||
Samsung S5PC100 series based systems
|
||||
|
||||
|
@ -701,6 +711,9 @@ config ARCH_S5PV210
|
|||
select HAVE_CLK
|
||||
select ARM_L1_CACHE_SHIFT_6
|
||||
select ARCH_USES_GETTIMEOFFSET
|
||||
select HAVE_S3C2410_I2C
|
||||
select HAVE_S3C_RTC
|
||||
select HAVE_S3C2410_WATCHDOG
|
||||
help
|
||||
Samsung S5PV210/S5PC110 series based systems
|
||||
|
||||
|
|
|
@ -57,11 +57,21 @@ config S3C64XX_SETUP_I2C1
|
|||
help
|
||||
Common setup code for i2c bus 1.
|
||||
|
||||
config S3C64XX_SETUP_IDE
|
||||
bool
|
||||
help
|
||||
Common setup code for S3C64XX IDE.
|
||||
|
||||
config S3C64XX_SETUP_FB_24BPP
|
||||
bool
|
||||
help
|
||||
Common setup code for S3C64XX with an 24bpp RGB display helper.
|
||||
|
||||
config S3C64XX_SETUP_KEYPAD
|
||||
bool
|
||||
help
|
||||
Common setup code for S3C64XX KEYPAD GPIO configurations
|
||||
|
||||
config S3C64XX_SETUP_SDHCI_GPIO
|
||||
bool
|
||||
help
|
||||
|
@ -95,15 +105,20 @@ config MACH_SMDK6410
|
|||
select S3C_DEV_HSMMC
|
||||
select S3C_DEV_HSMMC1
|
||||
select S3C_DEV_I2C1
|
||||
select SAMSUNG_DEV_IDE
|
||||
select S3C_DEV_FB
|
||||
select S3C_DEV_RTC
|
||||
select SAMSUNG_DEV_TS
|
||||
select S3C_DEV_USB_HOST
|
||||
select S3C_DEV_USB_HSOTG
|
||||
select S3C_DEV_WDT
|
||||
select SAMSUNG_DEV_KEYPAD
|
||||
select HAVE_S3C2410_WATCHDOG
|
||||
select S3C64XX_SETUP_SDHCI
|
||||
select S3C64XX_SETUP_I2C1
|
||||
select S3C64XX_SETUP_IDE
|
||||
select S3C64XX_SETUP_FB_24BPP
|
||||
select S3C64XX_SETUP_KEYPAD
|
||||
help
|
||||
Machine support for the Samsung SMDK6410
|
||||
|
||||
|
|
|
@ -35,6 +35,8 @@ obj-$(CONFIG_S3C64XX_DMA) += dma.o
|
|||
|
||||
obj-$(CONFIG_S3C64XX_SETUP_I2C0) += setup-i2c0.o
|
||||
obj-$(CONFIG_S3C64XX_SETUP_I2C1) += setup-i2c1.o
|
||||
obj-$(CONFIG_S3C64XX_SETUP_IDE) += setup-ide.o
|
||||
obj-$(CONFIG_S3C64XX_SETUP_KEYPAD) += setup-keypad.o
|
||||
obj-$(CONFIG_S3C64XX_SETUP_SDHCI) += setup-sdhci.o
|
||||
obj-$(CONFIG_S3C64XX_SETUP_FB_24BPP) += setup-fb-24bpp.o
|
||||
obj-$(CONFIG_S3C64XX_SETUP_SDHCI_GPIO) += setup-sdhci-gpio.o
|
||||
|
|
|
@ -132,6 +132,12 @@ static struct clk init_clocks_disable[] = {
|
|||
.name = "nand",
|
||||
.id = -1,
|
||||
.parent = &clk_h,
|
||||
}, {
|
||||
.name = "rtc",
|
||||
.id = -1,
|
||||
.parent = &clk_p,
|
||||
.enable = s3c64xx_pclk_ctrl,
|
||||
.ctrlbit = S3C_CLKCON_PCLK_RTC,
|
||||
}, {
|
||||
.name = "adc",
|
||||
.id = -1,
|
||||
|
@ -165,6 +171,12 @@ static struct clk init_clocks_disable[] = {
|
|||
.ctrlbit = S3C6410_CLKCON_PCLK_IIS2,
|
||||
}, {
|
||||
#endif
|
||||
.name = "keypad",
|
||||
.id = -1,
|
||||
.parent = &clk_p,
|
||||
.enable = s3c64xx_pclk_ctrl,
|
||||
.ctrlbit = S3C_CLKCON_PCLK_KEYPAD,
|
||||
}, {
|
||||
.name = "spi",
|
||||
.id = 0,
|
||||
.parent = &clk_p,
|
||||
|
@ -294,12 +306,6 @@ static struct clk init_clocks[] = {
|
|||
.parent = &clk_p,
|
||||
.enable = s3c64xx_pclk_ctrl,
|
||||
.ctrlbit = S3C_CLKCON_PCLK_UART3,
|
||||
}, {
|
||||
.name = "rtc",
|
||||
.id = -1,
|
||||
.parent = &clk_p,
|
||||
.enable = s3c64xx_pclk_ctrl,
|
||||
.ctrlbit = S3C_CLKCON_PCLK_RTC,
|
||||
}, {
|
||||
.name = "watchdog",
|
||||
.id = -1,
|
||||
|
@ -310,6 +316,12 @@ static struct clk init_clocks[] = {
|
|||
.id = -1,
|
||||
.parent = &clk_p,
|
||||
.ctrlbit = S3C_CLKCON_PCLK_AC97,
|
||||
}, {
|
||||
.name = "cfcon",
|
||||
.id = -1,
|
||||
.parent = &clk_h,
|
||||
.enable = s3c64xx_hclk_ctrl,
|
||||
.ctrlbit = S3C_CLKCON_HCLK_IHOST,
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -12,11 +12,11 @@
|
|||
#include <linux/string.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <mach/irqs.h>
|
||||
#include <mach/map.h>
|
||||
#include <mach/dma.h>
|
||||
#include <mach/gpio.h>
|
||||
|
||||
#include <plat/devs.h>
|
||||
#include <plat/audio.h>
|
||||
|
|
|
@ -12,10 +12,10 @@
|
|||
#include <linux/string.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <mach/dma.h>
|
||||
#include <mach/map.h>
|
||||
#include <mach/gpio.h>
|
||||
#include <mach/gpio-bank-c.h>
|
||||
#include <mach/spi-clocks.h>
|
||||
|
||||
|
|
|
@ -15,9 +15,9 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <mach/map.h>
|
||||
#include <mach/gpio.h>
|
||||
|
||||
#include <plat/gpio-core.h>
|
||||
#include <plat/gpio-cfg.h>
|
||||
|
|
|
@ -67,6 +67,7 @@
|
|||
#define S3C64XX_PA_USB_HSOTG (0x7C000000)
|
||||
#define S3C64XX_PA_WATCHDOG (0x7E004000)
|
||||
#define S3C64XX_PA_RTC (0x7E005000)
|
||||
#define S3C64XX_PA_KEYPAD (0x7E00A000)
|
||||
#define S3C64XX_PA_ADC (0x7E00B000)
|
||||
#define S3C64XX_PA_SYSCON (0x7E00F000)
|
||||
#define S3C64XX_PA_AC97 (0x7F001000)
|
||||
|
@ -86,6 +87,9 @@
|
|||
#define S3C64XX_SZ_GPIO SZ_4K
|
||||
|
||||
#define S3C64XX_PA_SDRAM (0x50000000)
|
||||
|
||||
#define S3C64XX_PA_CFCON (0x70300000)
|
||||
|
||||
#define S3C64XX_PA_VIC0 (0x71200000)
|
||||
#define S3C64XX_PA_VIC1 (0x71300000)
|
||||
|
||||
|
@ -120,5 +124,7 @@
|
|||
#define S3C_PA_WDT S3C64XX_PA_WATCHDOG
|
||||
|
||||
#define SAMSUNG_PA_ADC S3C64XX_PA_ADC
|
||||
#define SAMSUNG_PA_CFCON S3C64XX_PA_CFCON
|
||||
#define SAMSUNG_PA_KEYPAD S3C64XX_PA_KEYPAD
|
||||
|
||||
#endif /* __ASM_ARCH_6400_MAP_H */
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#define S3C_SCLK_GATE S3C_CLKREG(0x38)
|
||||
#define S3C_MEM0_GATE S3C_CLKREG(0x3C)
|
||||
#define S3C6410_CLK_SRC2 S3C_CLKREG(0x10C)
|
||||
#define S3C_MEM_SYS_CFG S3C_CLKREG(0x120)
|
||||
|
||||
/* CLKDIV0 */
|
||||
#define S3C6400_CLKDIV0_PCLK_MASK (0xf << 12)
|
||||
|
@ -154,4 +155,8 @@
|
|||
#define S3C6400_CLKSRC_EPLL_MOUT_SHIFT (2)
|
||||
#define S3C6400_CLKSRC_MFC (1 << 4)
|
||||
|
||||
/* MEM_SYS_CFG */
|
||||
#define MEM_SYS_CFG_INDEP_CF 0x4000
|
||||
#define MEM_SYS_CFG_EBI_FIX_PRI_CFCON 0x30
|
||||
|
||||
#endif /* _PLAT_REGS_CLOCK_H */
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/list.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/io.h>
|
||||
|
@ -56,6 +57,7 @@
|
|||
#include <mach/regs-gpio.h>
|
||||
#include <mach/regs-sys.h>
|
||||
#include <mach/regs-srom.h>
|
||||
#include <plat/ata.h>
|
||||
#include <plat/iic.h>
|
||||
#include <plat/fb.h>
|
||||
#include <plat/gpio-cfg.h>
|
||||
|
@ -66,6 +68,7 @@
|
|||
#include <plat/cpu.h>
|
||||
#include <plat/adc.h>
|
||||
#include <plat/ts.h>
|
||||
#include <plat/keypad.h>
|
||||
|
||||
#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK
|
||||
#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
|
||||
|
@ -242,6 +245,29 @@ static struct platform_device smdk6410_b_pwr_5v = {
|
|||
};
|
||||
#endif
|
||||
|
||||
static struct s3c_ide_platdata smdk6410_ide_pdata __initdata = {
|
||||
.setup_gpio = s3c64xx_ide_setup_gpio,
|
||||
};
|
||||
|
||||
static uint32_t smdk6410_keymap[] __initdata = {
|
||||
/* KEY(row, col, keycode) */
|
||||
KEY(0, 3, KEY_1), KEY(0, 4, KEY_2), KEY(0, 5, KEY_3),
|
||||
KEY(0, 6, KEY_4), KEY(0, 7, KEY_5),
|
||||
KEY(1, 3, KEY_A), KEY(1, 4, KEY_B), KEY(1, 5, KEY_C),
|
||||
KEY(1, 6, KEY_D), KEY(1, 7, KEY_E)
|
||||
};
|
||||
|
||||
static struct matrix_keymap_data smdk6410_keymap_data __initdata = {
|
||||
.keymap = smdk6410_keymap,
|
||||
.keymap_size = ARRAY_SIZE(smdk6410_keymap),
|
||||
};
|
||||
|
||||
static struct samsung_keypad_platdata smdk6410_keypad_data __initdata = {
|
||||
.keymap_data = &smdk6410_keymap_data,
|
||||
.rows = 2,
|
||||
.cols = 8,
|
||||
};
|
||||
|
||||
static struct map_desc smdk6410_iodesc[] = {};
|
||||
|
||||
static struct platform_device *smdk6410_devices[] __initdata = {
|
||||
|
@ -257,6 +283,7 @@ static struct platform_device *smdk6410_devices[] __initdata = {
|
|||
&s3c_device_ohci,
|
||||
&s3c_device_usb_hsotg,
|
||||
&s3c64xx_device_iisv4,
|
||||
&samsung_device_keypad,
|
||||
|
||||
#ifdef CONFIG_REGULATOR
|
||||
&smdk6410_b_pwr_5v,
|
||||
|
@ -265,6 +292,8 @@ static struct platform_device *smdk6410_devices[] __initdata = {
|
|||
|
||||
&smdk6410_smsc911x,
|
||||
&s3c_device_adc,
|
||||
&s3c_device_cfcon,
|
||||
&s3c_device_rtc,
|
||||
&s3c_device_ts,
|
||||
&s3c_device_wdt,
|
||||
};
|
||||
|
@ -636,6 +665,8 @@ static void __init smdk6410_machine_init(void)
|
|||
s3c_i2c1_set_platdata(NULL);
|
||||
s3c_fb_set_platdata(&smdk6410_lcd_pdata);
|
||||
|
||||
samsung_keypad_set_platdata(&smdk6410_keypad_data);
|
||||
|
||||
s3c24xx_ts_set_platdata(&s3c_ts_platform);
|
||||
|
||||
/* configure nCS1 width to 16 bits */
|
||||
|
@ -665,6 +696,8 @@ static void __init smdk6410_machine_init(void)
|
|||
i2c_register_board_info(0, i2c_devs0, ARRAY_SIZE(i2c_devs0));
|
||||
i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1));
|
||||
|
||||
s3c_ide_set_platdata(&smdk6410_ide_pdata);
|
||||
|
||||
platform_add_devices(smdk6410_devices, ARRAY_SIZE(smdk6410_devices));
|
||||
}
|
||||
|
||||
|
|
|
@ -37,8 +37,9 @@
|
|||
#include <plat/devs.h>
|
||||
#include <plat/clock.h>
|
||||
#include <plat/sdhci.h>
|
||||
#include <plat/ata-core.h>
|
||||
#include <plat/adc-core.h>
|
||||
#include <plat/iic-core.h>
|
||||
#include <plat/adc.h>
|
||||
#include <plat/onenand-core.h>
|
||||
#include <mach/s3c6400.h>
|
||||
#include <mach/s3c6410.h>
|
||||
|
@ -54,10 +55,11 @@ void __init s3c6410_map_io(void)
|
|||
s3c_i2c0_setname("s3c2440-i2c");
|
||||
s3c_i2c1_setname("s3c2440-i2c");
|
||||
|
||||
s3c_device_adc.name = "s3c64xx-adc";
|
||||
s3c_adc_setname("s3c64xx-adc");
|
||||
s3c_device_nand.name = "s3c6400-nand";
|
||||
s3c_onenand_setname("s3c6410-onenand");
|
||||
s3c64xx_onenand1_setname("s3c6410-onenand");
|
||||
s3c_cfcon_setname("s3c64xx-pata");
|
||||
}
|
||||
|
||||
void __init s3c6410_init_clocks(int xtal)
|
||||
|
|
|
@ -15,9 +15,9 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <mach/regs-fb.h>
|
||||
#include <mach/gpio.h>
|
||||
#include <plat/fb.h>
|
||||
#include <plat/gpio-cfg.h>
|
||||
|
||||
|
|
|
@ -14,10 +14,10 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
struct platform_device; /* don't need the contents */
|
||||
|
||||
#include <mach/gpio.h>
|
||||
#include <mach/gpio-bank-b.h>
|
||||
#include <plat/iic.h>
|
||||
#include <plat/gpio-cfg.h>
|
||||
|
|
|
@ -14,10 +14,10 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
struct platform_device; /* don't need the contents */
|
||||
|
||||
#include <mach/gpio.h>
|
||||
#include <mach/gpio-bank-b.h>
|
||||
#include <plat/iic.h>
|
||||
#include <plat/gpio-cfg.h>
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
/* linux/arch/arm/mach-s3c64xx/setup-ide.c
|
||||
*
|
||||
* Copyright (c) 2010 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com/
|
||||
*
|
||||
* S3C64XX setup information for IDE
|
||||
*
|
||||
* 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/gpio.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <mach/map.h>
|
||||
#include <mach/regs-clock.h>
|
||||
#include <plat/gpio-cfg.h>
|
||||
|
||||
void s3c64xx_ide_setup_gpio(void)
|
||||
{
|
||||
u32 reg;
|
||||
u32 gpio = 0;
|
||||
|
||||
reg = readl(S3C_MEM_SYS_CFG) & (~0x3f);
|
||||
|
||||
/* Independent CF interface, CF chip select configuration */
|
||||
writel(reg | MEM_SYS_CFG_INDEP_CF |
|
||||
MEM_SYS_CFG_EBI_FIX_PRI_CFCON, S3C_MEM_SYS_CFG);
|
||||
|
||||
s3c_gpio_cfgpin(S3C64XX_GPB(4), S3C_GPIO_SFN(4));
|
||||
|
||||
/* Set XhiDATA[15:0] pins as CF Data[15:0] */
|
||||
for (gpio = S3C64XX_GPK(0); gpio <= S3C64XX_GPK(15); gpio++)
|
||||
s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(5));
|
||||
|
||||
/* Set XhiADDR[2:0] pins as CF ADDR[2:0] */
|
||||
for (gpio = S3C64XX_GPL(0); gpio <= S3C64XX_GPL(2); gpio++)
|
||||
s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(6));
|
||||
|
||||
/* Set Xhi ctrl pins as CF ctrl pins(IORDY, IOWR, IORD, CE[0:1]) */
|
||||
s3c_gpio_cfgpin(S3C64XX_GPM(5), S3C_GPIO_SFN(1));
|
||||
for (gpio = S3C64XX_GPM(0); gpio <= S3C64XX_GPM(4); gpio++)
|
||||
s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(6));
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/* linux/arch/arm/mach-s3c64xx/setup-keypad.c
|
||||
*
|
||||
* Copyright (c) 2010 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com/
|
||||
*
|
||||
* GPIO configuration for S3C64XX KeyPad device
|
||||
*
|
||||
* 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/gpio.h>
|
||||
#include <plat/gpio-cfg.h>
|
||||
|
||||
void samsung_keypad_cfg_gpio(unsigned int rows, unsigned int cols)
|
||||
{
|
||||
unsigned int gpio;
|
||||
unsigned int end;
|
||||
|
||||
/* Set all the necessary GPK pins to special-function 3: KP_ROW[x] */
|
||||
end = S3C64XX_GPK(8 + rows);
|
||||
for (gpio = S3C64XX_GPK(8); gpio < end; gpio++) {
|
||||
s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(3));
|
||||
s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
|
||||
}
|
||||
|
||||
/* Set all the necessary GPL pins to special-function 3: KP_COL[x] */
|
||||
end = S3C64XX_GPL(0 + cols);
|
||||
for (gpio = S3C64XX_GPL(0); gpio < end; gpio++) {
|
||||
s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(3));
|
||||
s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
|
||||
}
|
||||
}
|
|
@ -16,12 +16,14 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <mach/gpio.h>
|
||||
#include <plat/gpio-cfg.h>
|
||||
#include <plat/sdhci.h>
|
||||
|
||||
void s3c64xx_setup_sdhci0_cfg_gpio(struct platform_device *dev, int width)
|
||||
{
|
||||
struct s3c_sdhci_platdata *pdata = dev->dev.platform_data;
|
||||
unsigned int gpio;
|
||||
unsigned int end;
|
||||
|
||||
|
@ -33,12 +35,15 @@ void s3c64xx_setup_sdhci0_cfg_gpio(struct platform_device *dev, int width)
|
|||
s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
|
||||
}
|
||||
|
||||
s3c_gpio_setpull(S3C64XX_GPG(6), S3C_GPIO_PULL_UP);
|
||||
s3c_gpio_cfgpin(S3C64XX_GPG(6), S3C_GPIO_SFN(2));
|
||||
if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) {
|
||||
s3c_gpio_setpull(S3C64XX_GPG(6), S3C_GPIO_PULL_UP);
|
||||
s3c_gpio_cfgpin(S3C64XX_GPG(6), S3C_GPIO_SFN(2));
|
||||
}
|
||||
}
|
||||
|
||||
void s3c64xx_setup_sdhci1_cfg_gpio(struct platform_device *dev, int width)
|
||||
{
|
||||
struct s3c_sdhci_platdata *pdata = dev->dev.platform_data;
|
||||
unsigned int gpio;
|
||||
unsigned int end;
|
||||
|
||||
|
@ -50,8 +55,10 @@ void s3c64xx_setup_sdhci1_cfg_gpio(struct platform_device *dev, int width)
|
|||
s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
|
||||
}
|
||||
|
||||
s3c_gpio_setpull(S3C64XX_GPG(6), S3C_GPIO_PULL_UP);
|
||||
s3c_gpio_cfgpin(S3C64XX_GPG(6), S3C_GPIO_SFN(3));
|
||||
if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) {
|
||||
s3c_gpio_setpull(S3C64XX_GPG(6), S3C_GPIO_PULL_UP);
|
||||
s3c_gpio_cfgpin(S3C64XX_GPG(6), S3C_GPIO_SFN(3));
|
||||
}
|
||||
}
|
||||
|
||||
void s3c64xx_setup_sdhci2_cfg_gpio(struct platform_device *dev, int width)
|
||||
|
|
|
@ -21,13 +21,11 @@ config S5P6440_SETUP_I2C1
|
|||
config MACH_SMDK6440
|
||||
bool "SMDK6440"
|
||||
select CPU_S5P6440
|
||||
select SAMSUNG_DEV_TS
|
||||
select SAMSUNG_DEV_ADC
|
||||
select S3C_DEV_RTC
|
||||
select S3C_DEV_I2C1
|
||||
select S3C_DEV_RTC
|
||||
select S3C_DEV_WDT
|
||||
select HAVE_S3C_RTC
|
||||
select HAVE_S3C2410_WATCHDOG
|
||||
select SAMSUNG_DEV_ADC
|
||||
select SAMSUNG_DEV_TS
|
||||
select S5P6440_SETUP_I2C1
|
||||
help
|
||||
Machine support for the Samsung SMDK6440
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include <plat/devs.h>
|
||||
#include <plat/clock.h>
|
||||
#include <plat/s5p6440.h>
|
||||
#include <plat/adc-core.h>
|
||||
|
||||
static void s5p6440_idle(void)
|
||||
{
|
||||
|
@ -61,7 +62,7 @@ static void s5p6440_idle(void)
|
|||
void __init s5p6440_map_io(void)
|
||||
{
|
||||
/* initialize any device information early */
|
||||
s3c_device_adc.name = "s3c64xx-adc";
|
||||
s3c_adc_setname("s3c64xx-adc");
|
||||
}
|
||||
|
||||
void __init s5p6440_init_clocks(int xtal)
|
||||
|
|
|
@ -10,11 +10,11 @@
|
|||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <plat/gpio-cfg.h>
|
||||
#include <plat/audio.h>
|
||||
|
||||
#include <mach/gpio.h>
|
||||
#include <mach/map.h>
|
||||
#include <mach/dma.h>
|
||||
#include <mach/irqs.h>
|
||||
|
|
|
@ -10,11 +10,11 @@
|
|||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <mach/dma.h>
|
||||
#include <mach/map.h>
|
||||
#include <mach/irqs.h>
|
||||
#include <mach/gpio.h>
|
||||
#include <mach/spi-clocks.h>
|
||||
|
||||
#include <plat/s3c64xx-spi.h>
|
||||
|
|
|
@ -13,9 +13,11 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <mach/map.h>
|
||||
#include <mach/gpio.h>
|
||||
#include <mach/regs-gpio.h>
|
||||
|
||||
#include <plat/gpio-core.h>
|
||||
#include <plat/gpio-cfg.h>
|
||||
#include <plat/gpio-cfg-helpers.h>
|
||||
|
|
|
@ -20,7 +20,6 @@ config MACH_SMDK6442
|
|||
bool "SMDK6442"
|
||||
select CPU_S5P6442
|
||||
select S3C_DEV_WDT
|
||||
select HAVE_S3C2410_WATCHDOG
|
||||
help
|
||||
Machine support for Samsung SMDK6442
|
||||
|
||||
|
|
|
@ -10,11 +10,11 @@
|
|||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <plat/gpio-cfg.h>
|
||||
#include <plat/audio.h>
|
||||
|
||||
#include <mach/gpio.h>
|
||||
#include <mach/map.h>
|
||||
#include <mach/dma.h>
|
||||
#include <mach/irqs.h>
|
||||
|
|
|
@ -10,11 +10,11 @@
|
|||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <mach/dma.h>
|
||||
#include <mach/map.h>
|
||||
#include <mach/irqs.h>
|
||||
#include <mach/gpio.h>
|
||||
#include <mach/spi-clocks.h>
|
||||
|
||||
#include <plat/s3c64xx-spi.h>
|
||||
|
|
|
@ -49,24 +49,22 @@ config S5PC100_SETUP_SDHCI_GPIO
|
|||
config MACH_SMDKC100
|
||||
bool "SMDKC100"
|
||||
select CPU_S5PC100
|
||||
select SAMSUNG_DEV_ADC
|
||||
select S3C_DEV_FB
|
||||
select S3C_DEV_I2C1
|
||||
select SAMSUNG_DEV_IDE
|
||||
select S3C_DEV_HSMMC
|
||||
select S3C_DEV_HSMMC1
|
||||
select S3C_DEV_HSMMC2
|
||||
select SAMSUNG_DEV_KEYPAD
|
||||
select S3C_DEV_I2C1
|
||||
select S3C_DEV_RTC
|
||||
select SAMSUNG_DEV_TS
|
||||
select S3C_DEV_WDT
|
||||
select HAVE_S3C2410_WATCHDOG
|
||||
select SAMSUNG_DEV_ADC
|
||||
select SAMSUNG_DEV_IDE
|
||||
select SAMSUNG_DEV_KEYPAD
|
||||
select SAMSUNG_DEV_TS
|
||||
select S5PC100_SETUP_FB_24BPP
|
||||
select S5PC100_SETUP_I2C1
|
||||
select S5PC100_SETUP_IDE
|
||||
select S5PC100_SETUP_KEYPAD
|
||||
select S5PC100_SETUP_SDHCI
|
||||
select HAVE_S3C_RTC
|
||||
help
|
||||
Machine support for the Samsung SMDKC100
|
||||
|
||||
|
|
|
@ -10,11 +10,11 @@
|
|||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <plat/gpio-cfg.h>
|
||||
#include <plat/audio.h>
|
||||
|
||||
#include <mach/gpio.h>
|
||||
#include <mach/map.h>
|
||||
#include <mach/dma.h>
|
||||
#include <mach/irqs.h>
|
||||
|
|
|
@ -10,10 +10,10 @@
|
|||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <mach/dma.h>
|
||||
#include <mach/map.h>
|
||||
#include <mach/gpio.h>
|
||||
#include <mach/spi-clocks.h>
|
||||
|
||||
#include <plat/s3c64xx-spi.h>
|
||||
|
|
|
@ -99,6 +99,10 @@
|
|||
|
||||
#define S5PC100_PA_FB (0xEE000000)
|
||||
|
||||
#define S5PC100_PA_FIMC0 (0xEE200000)
|
||||
#define S5PC100_PA_FIMC1 (0xEE300000)
|
||||
#define S5PC100_PA_FIMC2 (0xEE400000)
|
||||
|
||||
#define S5PC100_PA_I2S0 (0xF2000000)
|
||||
#define S5PC100_PA_I2S1 (0xF2100000)
|
||||
#define S5PC100_PA_I2S2 (0xF2200000)
|
||||
|
@ -148,4 +152,8 @@
|
|||
#define SAMSUNG_PA_CFCON S5PC100_PA_CFCON
|
||||
#define SAMSUNG_PA_KEYPAD S5PC100_PA_KEYPAD
|
||||
|
||||
#define S5P_PA_FIMC0 S5PC100_PA_FIMC0
|
||||
#define S5P_PA_FIMC1 S5PC100_PA_FIMC1
|
||||
#define S5P_PA_FIMC2 S5PC100_PA_FIMC2
|
||||
|
||||
#endif /* __ASM_ARCH_C100_MAP_H */
|
||||
|
|
|
@ -20,9 +20,11 @@
|
|||
|
||||
#include <plat/gpio-cfg.h>
|
||||
#include <plat/regs-sdhci.h>
|
||||
#include <plat/sdhci.h>
|
||||
|
||||
void s5pc100_setup_sdhci0_cfg_gpio(struct platform_device *dev, int width)
|
||||
{
|
||||
struct s3c_sdhci_platdata *pdata = dev->dev.platform_data;
|
||||
unsigned int gpio;
|
||||
unsigned int end;
|
||||
unsigned int num;
|
||||
|
@ -47,12 +49,15 @@ void s5pc100_setup_sdhci0_cfg_gpio(struct platform_device *dev, int width)
|
|||
}
|
||||
}
|
||||
|
||||
s3c_gpio_setpull(S5PC100_GPG1(2), S3C_GPIO_PULL_UP);
|
||||
s3c_gpio_cfgpin(S5PC100_GPG1(2), S3C_GPIO_SFN(2));
|
||||
if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) {
|
||||
s3c_gpio_setpull(S5PC100_GPG1(2), S3C_GPIO_PULL_UP);
|
||||
s3c_gpio_cfgpin(S5PC100_GPG1(2), S3C_GPIO_SFN(2));
|
||||
}
|
||||
}
|
||||
|
||||
void s5pc100_setup_sdhci1_cfg_gpio(struct platform_device *dev, int width)
|
||||
{
|
||||
struct s3c_sdhci_platdata *pdata = dev->dev.platform_data;
|
||||
unsigned int gpio;
|
||||
unsigned int end;
|
||||
|
||||
|
@ -64,12 +69,15 @@ void s5pc100_setup_sdhci1_cfg_gpio(struct platform_device *dev, int width)
|
|||
s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
|
||||
}
|
||||
|
||||
s3c_gpio_setpull(S5PC100_GPG2(6), S3C_GPIO_PULL_UP);
|
||||
s3c_gpio_cfgpin(S5PC100_GPG2(6), S3C_GPIO_SFN(2));
|
||||
if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) {
|
||||
s3c_gpio_setpull(S5PC100_GPG2(6), S3C_GPIO_PULL_UP);
|
||||
s3c_gpio_cfgpin(S5PC100_GPG2(6), S3C_GPIO_SFN(2));
|
||||
}
|
||||
}
|
||||
|
||||
void s5pc100_setup_sdhci2_cfg_gpio(struct platform_device *dev, int width)
|
||||
{
|
||||
struct s3c_sdhci_platdata *pdata = dev->dev.platform_data;
|
||||
unsigned int gpio;
|
||||
unsigned int end;
|
||||
|
||||
|
@ -81,6 +89,8 @@ void s5pc100_setup_sdhci2_cfg_gpio(struct platform_device *dev, int width)
|
|||
s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
|
||||
}
|
||||
|
||||
s3c_gpio_setpull(S5PC100_GPG3(6), S3C_GPIO_PULL_UP);
|
||||
s3c_gpio_cfgpin(S5PC100_GPG3(6), S3C_GPIO_SFN(2));
|
||||
if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) {
|
||||
s3c_gpio_setpull(S5PC100_GPG3(6), S3C_GPIO_PULL_UP);
|
||||
s3c_gpio_cfgpin(S5PC100_GPG3(6), S3C_GPIO_SFN(2));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,19 +53,24 @@ config S5PV210_SETUP_SDHCI_GPIO
|
|||
help
|
||||
Common setup code for SDHCI gpio.
|
||||
|
||||
config S5PC110_DEV_ONENAND
|
||||
bool
|
||||
help
|
||||
Compile in platform device definition for OneNAND1 controller
|
||||
|
||||
menu "S5PC110 Machines"
|
||||
|
||||
config MACH_AQUILA
|
||||
bool "Aquila"
|
||||
select CPU_S5PV210
|
||||
select ARCH_SPARSEMEM_ENABLE
|
||||
select S5PV210_SETUP_FB_24BPP
|
||||
select S5PV210_SETUP_SDHCI
|
||||
select S3C_DEV_FB
|
||||
select S5PC110_DEV_ONENAND
|
||||
select S3C_DEV_HSMMC
|
||||
select S3C_DEV_HSMMC1
|
||||
select S3C_DEV_HSMMC2
|
||||
select S5PC110_DEV_ONENAND
|
||||
select S5PV210_SETUP_FB_24BPP
|
||||
select S5PV210_SETUP_SDHCI
|
||||
help
|
||||
Machine support for the Samsung Aquila target based on S5PC110 SoC
|
||||
|
||||
|
@ -73,13 +78,13 @@ config MACH_GONI
|
|||
bool "GONI"
|
||||
select CPU_S5PV210
|
||||
select ARCH_SPARSEMEM_ENABLE
|
||||
select S5PV210_SETUP_FB_24BPP
|
||||
select S5PV210_SETUP_SDHCI
|
||||
select S3C_DEV_FB
|
||||
select S5PC110_DEV_ONENAND
|
||||
select S3C_DEV_HSMMC
|
||||
select S3C_DEV_HSMMC1
|
||||
select S3C_DEV_HSMMC2
|
||||
select S5PC110_DEV_ONENAND
|
||||
select S5PV210_SETUP_FB_24BPP
|
||||
select S5PV210_SETUP_SDHCI
|
||||
help
|
||||
Machine support for Samsung GONI board
|
||||
S5PC110(MCP) is one of package option of S5PV210
|
||||
|
@ -90,11 +95,9 @@ config MACH_SMDKC110
|
|||
select ARCH_SPARSEMEM_ENABLE
|
||||
select S3C_DEV_I2C1
|
||||
select S3C_DEV_I2C2
|
||||
select SAMSUNG_DEV_IDE
|
||||
select S3C_DEV_RTC
|
||||
select S3C_DEV_WDT
|
||||
select HAVE_S3C_RTC
|
||||
select HAVE_S3C2410_WATCHDOG
|
||||
select SAMSUNG_DEV_IDE
|
||||
select S5PV210_SETUP_I2C1
|
||||
select S5PV210_SETUP_I2C2
|
||||
select S5PV210_SETUP_IDE
|
||||
|
@ -104,31 +107,24 @@ config MACH_SMDKC110
|
|||
|
||||
endmenu
|
||||
|
||||
config S5PC110_DEV_ONENAND
|
||||
bool
|
||||
help
|
||||
Compile in platform device definition for OneNAND1 controller
|
||||
|
||||
menu "S5PV210 Machines"
|
||||
|
||||
config MACH_SMDKV210
|
||||
bool "SMDKV210"
|
||||
select CPU_S5PV210
|
||||
select ARCH_SPARSEMEM_ENABLE
|
||||
select SAMSUNG_DEV_ADC
|
||||
select S3C_DEV_HSMMC
|
||||
select S3C_DEV_HSMMC1
|
||||
select S3C_DEV_HSMMC2
|
||||
select S3C_DEV_HSMMC3
|
||||
select S3C_DEV_I2C1
|
||||
select S3C_DEV_I2C2
|
||||
select S3C_DEV_RTC
|
||||
select S3C_DEV_WDT
|
||||
select SAMSUNG_DEV_ADC
|
||||
select SAMSUNG_DEV_IDE
|
||||
select SAMSUNG_DEV_KEYPAD
|
||||
select SAMSUNG_DEV_TS
|
||||
select S3C_DEV_RTC
|
||||
select S3C_DEV_WDT
|
||||
select HAVE_S3C_RTC
|
||||
select HAVE_S3C2410_WATCHDOG
|
||||
select S5PV210_SETUP_I2C1
|
||||
select S5PV210_SETUP_I2C2
|
||||
select S5PV210_SETUP_IDE
|
||||
|
|
|
@ -32,7 +32,9 @@
|
|||
#include <plat/devs.h>
|
||||
#include <plat/clock.h>
|
||||
#include <plat/s5pv210.h>
|
||||
#include <plat/adc-core.h>
|
||||
#include <plat/ata-core.h>
|
||||
#include <plat/fimc-core.h>
|
||||
#include <plat/iic-core.h>
|
||||
#include <plat/keypad-core.h>
|
||||
#include <plat/sdhci.h>
|
||||
|
@ -84,9 +86,6 @@ static void s5pv210_sw_reset(void)
|
|||
|
||||
void __init s5pv210_map_io(void)
|
||||
{
|
||||
#ifdef CONFIG_S3C_DEV_ADC
|
||||
s3c_device_adc.name = "s3c64xx-adc";
|
||||
#endif
|
||||
iotable_init(s5pv210_iodesc, ARRAY_SIZE(s5pv210_iodesc));
|
||||
|
||||
/* initialise device information early */
|
||||
|
@ -95,8 +94,14 @@ void __init s5pv210_map_io(void)
|
|||
s5pv210_default_sdhci2();
|
||||
s5pv210_default_sdhci3();
|
||||
|
||||
s3c_adc_setname("s3c64xx-adc");
|
||||
|
||||
s3c_cfcon_setname("s5pv210-pata");
|
||||
|
||||
s3c_fimc_setname(0, "s5pv210-fimc");
|
||||
s3c_fimc_setname(1, "s5pv210-fimc");
|
||||
s3c_fimc_setname(2, "s5pv210-fimc");
|
||||
|
||||
/* the i2c devices are directly compatible with s3c2440 */
|
||||
s3c_i2c0_setname("s3c2440-i2c");
|
||||
s3c_i2c1_setname("s3c2440-i2c");
|
||||
|
|
|
@ -10,11 +10,11 @@
|
|||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <plat/gpio-cfg.h>
|
||||
#include <plat/audio.h>
|
||||
|
||||
#include <mach/gpio.h>
|
||||
#include <mach/map.h>
|
||||
#include <mach/dma.h>
|
||||
#include <mach/irqs.h>
|
||||
|
|
|
@ -10,11 +10,11 @@
|
|||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <mach/dma.h>
|
||||
#include <mach/map.h>
|
||||
#include <mach/irqs.h>
|
||||
#include <mach/gpio.h>
|
||||
#include <mach/spi-clocks.h>
|
||||
|
||||
#include <plat/s3c64xx-spi.h>
|
||||
|
|
|
@ -65,6 +65,10 @@
|
|||
|
||||
#define S5PV210_PA_FB (0xF8000000)
|
||||
|
||||
#define S5PV210_PA_FIMC0 (0xFB200000)
|
||||
#define S5PV210_PA_FIMC1 (0xFB300000)
|
||||
#define S5PV210_PA_FIMC2 (0xFB400000)
|
||||
|
||||
#define S5PV210_PA_HSMMC(x) (0xEB000000 + ((x) * 0x100000))
|
||||
|
||||
#define S5PV210_PA_VIC0 (0xF2000000)
|
||||
|
@ -109,6 +113,9 @@
|
|||
#define S3C_PA_FB S5PV210_PA_FB
|
||||
#define S3C_PA_RTC S5PV210_PA_RTC
|
||||
#define S3C_PA_WDT S5PV210_PA_WATCHDOG
|
||||
#define S5P_PA_FIMC0 S5PV210_PA_FIMC0
|
||||
#define S5P_PA_FIMC1 S5PV210_PA_FIMC1
|
||||
#define S5P_PA_FIMC2 S5PV210_PA_FIMC2
|
||||
|
||||
#define SAMSUNG_PA_ADC S5PV210_PA_ADC
|
||||
#define SAMSUNG_PA_CFCON S5PV210_PA_CFCON
|
||||
|
|
|
@ -13,9 +13,9 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <mach/regs-fb.h>
|
||||
#include <mach/gpio.h>
|
||||
#include <mach/map.h>
|
||||
#include <plat/fb.h>
|
||||
#include <mach/regs-clock.h>
|
||||
|
|
|
@ -14,10 +14,10 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
struct platform_device; /* don't need the contents */
|
||||
|
||||
#include <mach/gpio.h>
|
||||
#include <plat/iic.h>
|
||||
#include <plat/gpio-cfg.h>
|
||||
|
||||
|
|
|
@ -14,10 +14,10 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
struct platform_device; /* don't need the contents */
|
||||
|
||||
#include <mach/gpio.h>
|
||||
#include <plat/iic.h>
|
||||
#include <plat/gpio-cfg.h>
|
||||
|
||||
|
|
|
@ -14,10 +14,10 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
struct platform_device; /* don't need the contents */
|
||||
|
||||
#include <mach/gpio.h>
|
||||
#include <plat/iic.h>
|
||||
#include <plat/gpio-cfg.h>
|
||||
|
||||
|
|
|
@ -15,15 +15,17 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/mmc/host.h>
|
||||
#include <linux/mmc/card.h>
|
||||
|
||||
#include <mach/gpio.h>
|
||||
#include <plat/gpio-cfg.h>
|
||||
#include <plat/regs-sdhci.h>
|
||||
#include <plat/sdhci.h>
|
||||
|
||||
void s5pv210_setup_sdhci0_cfg_gpio(struct platform_device *dev, int width)
|
||||
{
|
||||
struct s3c_sdhci_platdata *pdata = dev->dev.platform_data;
|
||||
unsigned int gpio;
|
||||
|
||||
/* Set all the necessary GPG0/GPG1 pins to special-function 2 */
|
||||
|
@ -48,12 +50,15 @@ void s5pv210_setup_sdhci0_cfg_gpio(struct platform_device *dev, int width)
|
|||
break;
|
||||
}
|
||||
|
||||
s3c_gpio_setpull(S5PV210_GPG0(2), S3C_GPIO_PULL_UP);
|
||||
s3c_gpio_cfgpin(S5PV210_GPG0(2), S3C_GPIO_SFN(2));
|
||||
if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) {
|
||||
s3c_gpio_setpull(S5PV210_GPG0(2), S3C_GPIO_PULL_UP);
|
||||
s3c_gpio_cfgpin(S5PV210_GPG0(2), S3C_GPIO_SFN(2));
|
||||
}
|
||||
}
|
||||
|
||||
void s5pv210_setup_sdhci1_cfg_gpio(struct platform_device *dev, int width)
|
||||
{
|
||||
struct s3c_sdhci_platdata *pdata = dev->dev.platform_data;
|
||||
unsigned int gpio;
|
||||
|
||||
/* Set all the necessary GPG1[0:1] pins to special-function 2 */
|
||||
|
@ -68,12 +73,15 @@ void s5pv210_setup_sdhci1_cfg_gpio(struct platform_device *dev, int width)
|
|||
s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
|
||||
}
|
||||
|
||||
s3c_gpio_setpull(S5PV210_GPG1(2), S3C_GPIO_PULL_UP);
|
||||
s3c_gpio_cfgpin(S5PV210_GPG1(2), S3C_GPIO_SFN(2));
|
||||
if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) {
|
||||
s3c_gpio_setpull(S5PV210_GPG1(2), S3C_GPIO_PULL_UP);
|
||||
s3c_gpio_cfgpin(S5PV210_GPG1(2), S3C_GPIO_SFN(2));
|
||||
}
|
||||
}
|
||||
|
||||
void s5pv210_setup_sdhci2_cfg_gpio(struct platform_device *dev, int width)
|
||||
{
|
||||
struct s3c_sdhci_platdata *pdata = dev->dev.platform_data;
|
||||
unsigned int gpio;
|
||||
|
||||
/* Set all the necessary GPG2[0:1] pins to special-function 2 */
|
||||
|
@ -99,8 +107,10 @@ void s5pv210_setup_sdhci2_cfg_gpio(struct platform_device *dev, int width)
|
|||
break;
|
||||
}
|
||||
|
||||
s3c_gpio_setpull(S5PV210_GPG2(2), S3C_GPIO_PULL_UP);
|
||||
s3c_gpio_cfgpin(S5PV210_GPG2(2), S3C_GPIO_SFN(2));
|
||||
if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) {
|
||||
s3c_gpio_setpull(S5PV210_GPG2(2), S3C_GPIO_PULL_UP);
|
||||
s3c_gpio_cfgpin(S5PV210_GPG2(2), S3C_GPIO_SFN(2));
|
||||
}
|
||||
}
|
||||
|
||||
void s5pv210_setup_sdhci3_cfg_gpio(struct platform_device *dev, int width)
|
||||
|
|
|
@ -19,3 +19,8 @@ obj-y += clock.o
|
|||
obj-y += irq.o
|
||||
obj-$(CONFIG_S5P_EXT_INT) += irq-eint.o
|
||||
|
||||
# devices
|
||||
|
||||
obj-$(CONFIG_S5P_DEV_FIMC0) += dev-fimc0.o
|
||||
obj-$(CONFIG_S5P_DEV_FIMC1) += dev-fimc1.o
|
||||
obj-$(CONFIG_S5P_DEV_FIMC2) += dev-fimc2.o
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/* linux/arch/arm/plat-s5p/dev-fimc0.c
|
||||
*
|
||||
* Copyright (c) 2010 Samsung Electronics
|
||||
*
|
||||
* Base S5P FIMC0 resource and device definitions
|
||||
*
|
||||
* 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/platform_device.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <mach/map.h>
|
||||
|
||||
static struct resource s5p_fimc0_resource[] = {
|
||||
[0] = {
|
||||
.start = S5P_PA_FIMC0,
|
||||
.end = S5P_PA_FIMC0 + SZ_1M - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = IRQ_FIMC0,
|
||||
.end = IRQ_FIMC0,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
struct platform_device s5p_device_fimc0 = {
|
||||
.name = "s5p-fimc",
|
||||
.id = 0,
|
||||
.num_resources = ARRAY_SIZE(s5p_fimc0_resource),
|
||||
.resource = s5p_fimc0_resource,
|
||||
};
|
|
@ -0,0 +1,36 @@
|
|||
/* linux/arch/arm/plat-s5p/dev-fimc1.c
|
||||
*
|
||||
* Copyright (c) 2010 Samsung Electronics
|
||||
*
|
||||
* Base S5P FIMC1 resource and device definitions
|
||||
*
|
||||
* 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/platform_device.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <mach/map.h>
|
||||
|
||||
static struct resource s5p_fimc1_resource[] = {
|
||||
[0] = {
|
||||
.start = S5P_PA_FIMC1,
|
||||
.end = S5P_PA_FIMC1 + SZ_1M - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = IRQ_FIMC1,
|
||||
.end = IRQ_FIMC1,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
struct platform_device s5p_device_fimc1 = {
|
||||
.name = "s5p-fimc",
|
||||
.id = 1,
|
||||
.num_resources = ARRAY_SIZE(s5p_fimc1_resource),
|
||||
.resource = s5p_fimc1_resource,
|
||||
};
|
|
@ -0,0 +1,36 @@
|
|||
/* linux/arch/arm/plat-s5p/dev-fimc2.c
|
||||
*
|
||||
* Copyright (c) 2010 Samsung Electronics
|
||||
*
|
||||
* Base S5P FIMC2 resource and device definitions
|
||||
*
|
||||
* 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/platform_device.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <mach/map.h>
|
||||
|
||||
static struct resource s5p_fimc2_resource[] = {
|
||||
[0] = {
|
||||
.start = S5P_PA_FIMC2,
|
||||
.end = S5P_PA_FIMC2 + SZ_1M - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = IRQ_FIMC2,
|
||||
.end = IRQ_FIMC2,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
struct platform_device s5p_device_fimc2 = {
|
||||
.name = "s5p-fimc",
|
||||
.id = 2,
|
||||
.num_resources = ARRAY_SIZE(s5p_fimc2_resource),
|
||||
.resource = s5p_fimc2_resource,
|
||||
};
|
|
@ -160,6 +160,11 @@ config S3C_DEV_HSMMC2
|
|||
help
|
||||
Compile in platform device definitions for HSMMC channel 2
|
||||
|
||||
config S3C_DEV_HSMMC3
|
||||
bool
|
||||
help
|
||||
Compile in platform device definitions for HSMMC channel 3
|
||||
|
||||
config S3C_DEV_HWMON
|
||||
bool
|
||||
help
|
||||
|
@ -216,6 +221,11 @@ config SAMSUNG_DEV_ADC
|
|||
help
|
||||
Compile in platform device definition for ADC controller
|
||||
|
||||
config SAMSUNG_DEV_IDE
|
||||
bool
|
||||
help
|
||||
Compile in platform device definitions for IDE
|
||||
|
||||
config S3C64XX_DEV_SPI
|
||||
bool
|
||||
help
|
||||
|
@ -227,6 +237,11 @@ config SAMSUNG_DEV_TS
|
|||
help
|
||||
Common in platform device definitions for touchscreen device
|
||||
|
||||
config SAMSUNG_DEV_KEYPAD
|
||||
bool
|
||||
help
|
||||
Compile in platform device definitions for keypad
|
||||
|
||||
# DMA
|
||||
|
||||
config S3C_DMA
|
||||
|
|
|
@ -30,9 +30,12 @@ obj-$(CONFIG_S3C_ADC) += adc.o
|
|||
|
||||
# devices
|
||||
|
||||
obj-y += platformdata.o
|
||||
|
||||
obj-$(CONFIG_S3C_DEV_HSMMC) += dev-hsmmc.o
|
||||
obj-$(CONFIG_S3C_DEV_HSMMC1) += dev-hsmmc1.o
|
||||
obj-$(CONFIG_S3C_DEV_HSMMC2) += dev-hsmmc2.o
|
||||
obj-$(CONFIG_S3C_DEV_HSMMC3) += dev-hsmmc3.o
|
||||
obj-$(CONFIG_S3C_DEV_HWMON) += dev-hwmon.o
|
||||
obj-y += dev-i2c0.o
|
||||
obj-$(CONFIG_S3C_DEV_I2C1) += dev-i2c1.o
|
||||
|
@ -47,7 +50,9 @@ obj-$(CONFIG_S3C_DEV_ONENAND) += dev-onenand.o
|
|||
obj-$(CONFIG_S3C_DEV_RTC) += dev-rtc.o
|
||||
|
||||
obj-$(CONFIG_SAMSUNG_DEV_ADC) += dev-adc.o
|
||||
obj-$(CONFIG_SAMSUNG_DEV_IDE) += dev-ide.o
|
||||
obj-$(CONFIG_SAMSUNG_DEV_TS) += dev-ts.o
|
||||
obj-$(CONFIG_SAMSUNG_DEV_KEYPAD) += dev-keypad.o
|
||||
|
||||
# DMA support
|
||||
|
||||
|
|
|
@ -60,6 +60,11 @@ void s3c_sdhci0_set_platdata(struct s3c_sdhci_platdata *pd)
|
|||
struct s3c_sdhci_platdata *set = &s3c_hsmmc0_def_platdata;
|
||||
|
||||
set->max_width = pd->max_width;
|
||||
set->cd_type = pd->cd_type;
|
||||
set->ext_cd_init = pd->ext_cd_init;
|
||||
set->ext_cd_cleanup = pd->ext_cd_cleanup;
|
||||
set->ext_cd_gpio = pd->ext_cd_gpio;
|
||||
set->ext_cd_gpio_invert = pd->ext_cd_gpio_invert;
|
||||
|
||||
if (pd->cfg_gpio)
|
||||
set->cfg_gpio = pd->cfg_gpio;
|
||||
|
|
|
@ -60,6 +60,11 @@ void s3c_sdhci1_set_platdata(struct s3c_sdhci_platdata *pd)
|
|||
struct s3c_sdhci_platdata *set = &s3c_hsmmc1_def_platdata;
|
||||
|
||||
set->max_width = pd->max_width;
|
||||
set->cd_type = pd->cd_type;
|
||||
set->ext_cd_init = pd->ext_cd_init;
|
||||
set->ext_cd_cleanup = pd->ext_cd_cleanup;
|
||||
set->ext_cd_gpio = pd->ext_cd_gpio;
|
||||
set->ext_cd_gpio_invert = pd->ext_cd_gpio_invert;
|
||||
|
||||
if (pd->cfg_gpio)
|
||||
set->cfg_gpio = pd->cfg_gpio;
|
||||
|
|
|
@ -61,6 +61,11 @@ void s3c_sdhci2_set_platdata(struct s3c_sdhci_platdata *pd)
|
|||
struct s3c_sdhci_platdata *set = &s3c_hsmmc2_def_platdata;
|
||||
|
||||
set->max_width = pd->max_width;
|
||||
set->cd_type = pd->cd_type;
|
||||
set->ext_cd_init = pd->ext_cd_init;
|
||||
set->ext_cd_cleanup = pd->ext_cd_cleanup;
|
||||
set->ext_cd_gpio = pd->ext_cd_gpio;
|
||||
set->ext_cd_gpio_invert = pd->ext_cd_gpio_invert;
|
||||
|
||||
if (pd->cfg_gpio)
|
||||
set->cfg_gpio = pd->cfg_gpio;
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
/* linux/arch/arm/plat-samsung/dev-hsmmc3.c
|
||||
*
|
||||
* Copyright (c) 2010 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com
|
||||
*
|
||||
* Copyright (c) 2008 Simtec Electronics
|
||||
* Ben Dooks <ben@simtec.co.uk>
|
||||
* http://armlinux.simtec.co.uk/
|
||||
*
|
||||
* Based on arch/arm/plat-samsung/dev-hsmmc1.c
|
||||
*
|
||||
* Samsung device definition for hsmmc device 3
|
||||
*
|
||||
* 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/platform_device.h>
|
||||
#include <linux/mmc/host.h>
|
||||
|
||||
#include <mach/map.h>
|
||||
#include <plat/sdhci.h>
|
||||
#include <plat/devs.h>
|
||||
|
||||
#define S3C_SZ_HSMMC (0x1000)
|
||||
|
||||
static struct resource s3c_hsmmc3_resource[] = {
|
||||
[0] = {
|
||||
.start = S3C_PA_HSMMC3,
|
||||
.end = S3C_PA_HSMMC3 + S3C_SZ_HSMMC - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = IRQ_MMC3,
|
||||
.end = IRQ_MMC3,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
}
|
||||
};
|
||||
|
||||
static u64 s3c_device_hsmmc3_dmamask = 0xffffffffUL;
|
||||
|
||||
struct s3c_sdhci_platdata s3c_hsmmc3_def_platdata = {
|
||||
.max_width = 4,
|
||||
.host_caps = (MMC_CAP_4_BIT_DATA |
|
||||
MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED),
|
||||
};
|
||||
|
||||
struct platform_device s3c_device_hsmmc3 = {
|
||||
.name = "s3c-sdhci",
|
||||
.id = 3,
|
||||
.num_resources = ARRAY_SIZE(s3c_hsmmc3_resource),
|
||||
.resource = s3c_hsmmc3_resource,
|
||||
.dev = {
|
||||
.dma_mask = &s3c_device_hsmmc3_dmamask,
|
||||
.coherent_dma_mask = 0xffffffffUL,
|
||||
.platform_data = &s3c_hsmmc3_def_platdata,
|
||||
},
|
||||
};
|
||||
|
||||
void s3c_sdhci3_set_platdata(struct s3c_sdhci_platdata *pd)
|
||||
{
|
||||
struct s3c_sdhci_platdata *set = &s3c_hsmmc3_def_platdata;
|
||||
|
||||
set->max_width = pd->max_width;
|
||||
set->cd_type = pd->cd_type;
|
||||
set->ext_cd_init = pd->ext_cd_init;
|
||||
set->ext_cd_cleanup = pd->ext_cd_cleanup;
|
||||
set->ext_cd_gpio = pd->ext_cd_gpio;
|
||||
set->ext_cd_gpio_invert = pd->ext_cd_gpio_invert;
|
||||
|
||||
if (pd->cfg_gpio)
|
||||
set->cfg_gpio = pd->cfg_gpio;
|
||||
if (pd->cfg_card)
|
||||
set->cfg_card = pd->cfg_card;
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/* linux/arch/arm/plat-samsung/dev-ide.c
|
||||
*
|
||||
* Copyright (c) 2010 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com
|
||||
*
|
||||
* Samsung CF-ATA device definition.
|
||||
*
|
||||
* 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/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <mach/map.h>
|
||||
#include <plat/ata.h>
|
||||
#include <plat/devs.h>
|
||||
|
||||
static struct resource s3c_cfcon_resource[] = {
|
||||
[0] = {
|
||||
.start = SAMSUNG_PA_CFCON,
|
||||
.end = SAMSUNG_PA_CFCON + SZ_16K - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = IRQ_CFCON,
|
||||
.end = IRQ_CFCON,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
struct platform_device s3c_device_cfcon = {
|
||||
.id = 0,
|
||||
.num_resources = ARRAY_SIZE(s3c_cfcon_resource),
|
||||
.resource = s3c_cfcon_resource,
|
||||
};
|
||||
|
||||
void s3c_ide_set_platdata(struct s3c_ide_platdata *pdata)
|
||||
{
|
||||
s3c_set_platdata(pdata, sizeof(struct s3c_ide_platdata),
|
||||
&s3c_device_cfcon);
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* linux/arch/arm/plat-samsung/dev-keypad.c
|
||||
*
|
||||
* Copyright (C) 2010 Samsung Electronics Co.Ltd
|
||||
* Author: Joonyoung Shim <jy0922.shim@samsung.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <mach/irqs.h>
|
||||
#include <mach/map.h>
|
||||
#include <plat/cpu.h>
|
||||
#include <plat/devs.h>
|
||||
#include <plat/keypad.h>
|
||||
|
||||
static struct resource samsung_keypad_resources[] = {
|
||||
[0] = {
|
||||
.start = SAMSUNG_PA_KEYPAD,
|
||||
.end = SAMSUNG_PA_KEYPAD + 0x20 - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = IRQ_KEYPAD,
|
||||
.end = IRQ_KEYPAD,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
struct platform_device samsung_device_keypad = {
|
||||
.name = "samsung-keypad",
|
||||
.id = -1,
|
||||
.num_resources = ARRAY_SIZE(samsung_keypad_resources),
|
||||
.resource = samsung_keypad_resources,
|
||||
};
|
||||
|
||||
void __init samsung_keypad_set_platdata(struct samsung_keypad_platdata *pd)
|
||||
{
|
||||
struct samsung_keypad_platdata *npd;
|
||||
|
||||
npd = s3c_set_platdata(pd, sizeof(struct samsung_keypad_platdata),
|
||||
&samsung_device_keypad);
|
||||
|
||||
if (!npd->cfg_gpio)
|
||||
npd->cfg_gpio = samsung_keypad_cfg_gpio;
|
||||
}
|
|
@ -21,7 +21,7 @@
|
|||
static struct resource s3c_wdt_resource[] = {
|
||||
[0] = {
|
||||
.start = S3C_PA_WDT,
|
||||
.end = S3C_PA_WDT + SZ_1M - 1,
|
||||
.end = S3C_PA_WDT + SZ_1K,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/io.h>
|
||||
#include <mach/gpio.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <plat/gpio-core.h>
|
||||
#include <plat/gpio-cfg.h>
|
||||
#include <plat/gpio-cfg-helpers.h>
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
/* linux/arch/arm/plat-samsung/include/plat/adc-core.h
|
||||
*
|
||||
* Copyright (c) 2010 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com/
|
||||
*
|
||||
* Samsung ADC Controller core functions
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __ASM_PLAT_ADC_CORE_H
|
||||
#define __ASM_PLAT_ADC_CORE_H __FILE__
|
||||
|
||||
/* These functions are only for use with the core support code, such as
|
||||
* the cpu specific initialisation code
|
||||
*/
|
||||
|
||||
/* re-define device name depending on support. */
|
||||
static inline void s3c_adc_setname(char *name)
|
||||
{
|
||||
#ifdef CONFIG_SAMSUNG_DEV_ADC
|
||||
s3c_device_adc.name = name;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* __ASM_PLAT_ADC_CORE_H */
|
|
@ -0,0 +1,28 @@
|
|||
/* linux/arch/arm/plat-samsung/include/plat/ata-core.h
|
||||
*
|
||||
* Copyright (c) 2010 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com
|
||||
*
|
||||
* Samsung CF-ATA Controller core functions
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __ASM_PLAT_ATA_CORE_H
|
||||
#define __ASM_PLAT_ATA_CORE_H __FILE__
|
||||
|
||||
/* These functions are only for use with the core support code, such as
|
||||
* the cpu specific initialisation code
|
||||
*/
|
||||
|
||||
/* re-define device name depending on support. */
|
||||
static inline void s3c_cfcon_setname(char *name)
|
||||
{
|
||||
#ifdef CONFIG_SAMSUNG_DEV_IDE
|
||||
s3c_device_cfcon.name = name;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* __ASM_PLAT_ATA_CORE_H */
|
|
@ -0,0 +1,36 @@
|
|||
/* linux/arch/arm/plat-samsung/include/plat/ata.h
|
||||
*
|
||||
* Copyright (c) 2010 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com
|
||||
*
|
||||
* Samsung CF-ATA platform_device info
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __ASM_PLAT_ATA_H
|
||||
#define __ASM_PLAT_ATA_H __FILE__
|
||||
|
||||
/**
|
||||
* struct s3c_ide_platdata - S3C IDE driver platform data.
|
||||
* @setup_gpio: Setup the external GPIO pins to the right state for data
|
||||
* transfer in true-ide mode.
|
||||
*/
|
||||
struct s3c_ide_platdata {
|
||||
void (*setup_gpio)(void);
|
||||
};
|
||||
|
||||
/*
|
||||
* s3c_ide_set_platdata() - Setup the platform specifc data for IDE driver.
|
||||
* @pdata: Platform data for IDE driver.
|
||||
*/
|
||||
extern void s3c_ide_set_platdata(struct s3c_ide_platdata *pdata);
|
||||
|
||||
/* architecture-specific IDE configuration */
|
||||
extern void s3c64xx_ide_setup_gpio(void);
|
||||
extern void s5pc100_ide_setup_gpio(void);
|
||||
extern void s5pv210_ide_setup_gpio(void);
|
||||
|
||||
#endif /*__ASM_PLAT_ATA_H */
|
|
@ -54,6 +54,8 @@ extern struct platform_device s3c_device_hwmon;
|
|||
extern struct platform_device s3c_device_hsmmc0;
|
||||
extern struct platform_device s3c_device_hsmmc1;
|
||||
extern struct platform_device s3c_device_hsmmc2;
|
||||
extern struct platform_device s3c_device_hsmmc3;
|
||||
extern struct platform_device s3c_device_cfcon;
|
||||
|
||||
extern struct platform_device s3c_device_spi0;
|
||||
extern struct platform_device s3c_device_spi1;
|
||||
|
@ -100,6 +102,12 @@ extern struct platform_device s5pc100_device_iis0;
|
|||
extern struct platform_device s5pc100_device_iis1;
|
||||
extern struct platform_device s5pc100_device_iis2;
|
||||
|
||||
extern struct platform_device samsung_device_keypad;
|
||||
|
||||
extern struct platform_device s5p_device_fimc0;
|
||||
extern struct platform_device s5p_device_fimc1;
|
||||
extern struct platform_device s5p_device_fimc2;
|
||||
|
||||
/* s3c2440 specific devices */
|
||||
|
||||
#ifdef CONFIG_CPU_S3C2440
|
||||
|
@ -108,3 +116,15 @@ extern struct platform_device s3c_device_camif;
|
|||
extern struct platform_device s3c_device_ac97;
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* s3c_set_platdata() - helper for setting platform data
|
||||
* @pd: The default platform data for this device.
|
||||
* @pdsize: The size of the platform data.
|
||||
* @pdev: Pointer to the device to fill in.
|
||||
*
|
||||
* This helper replaces a number of calls that copy and then set the
|
||||
* platform data of the device.
|
||||
*/
|
||||
extern void *s3c_set_platdata(void *pd, size_t pdsize,
|
||||
struct platform_device *pdev);
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* arch/arm/plat-samsung/include/plat/fimc-core.h
|
||||
*
|
||||
* Copyright 2010 Samsung Electronics Co., Ltd.
|
||||
* Sylwester Nawrocki <s.nawrocki@samsung.com>
|
||||
*
|
||||
* Samsung camera interface driver core functions
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __ASM_PLAT_FIMC_CORE_H
|
||||
#define __ASM_PLAT_FIMC_CORE_H __FILE__
|
||||
|
||||
/*
|
||||
* These functions are only for use with the core support code, such as
|
||||
* the CPU-specific initialization code.
|
||||
*/
|
||||
|
||||
/* Re-define device name to differentiate the subsystem in various SoCs. */
|
||||
static inline void s3c_fimc_setname(int id, char *name)
|
||||
{
|
||||
switch (id) {
|
||||
#ifdef CONFIG_S5P_DEV_FIMC0
|
||||
case 0:
|
||||
s5p_device_fimc0.name = name;
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_S5P_DEV_FIMC1
|
||||
case 1:
|
||||
s5p_device_fimc1.name = name;
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_S5P_DEV_FIMC2
|
||||
case 2:
|
||||
s5p_device_fimc2.name = name;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __ASM_PLAT_FIMC_CORE_H */
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Samsung Platform - Keypad platform data definitions
|
||||
*
|
||||
* Copyright (C) 2010 Samsung Electronics Co.Ltd
|
||||
* Author: Joonyoung Shim <jy0922.shim@samsung.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef __PLAT_SAMSUNG_KEYPAD_H
|
||||
#define __PLAT_SAMSUNG_KEYPAD_H
|
||||
|
||||
#include <linux/input/matrix_keypad.h>
|
||||
|
||||
#define SAMSUNG_MAX_ROWS 8
|
||||
#define SAMSUNG_MAX_COLS 8
|
||||
|
||||
/**
|
||||
* struct samsung_keypad_platdata - Platform device data for Samsung Keypad.
|
||||
* @keymap_data: pointer to &matrix_keymap_data.
|
||||
* @rows: number of keypad row supported.
|
||||
* @cols: number of keypad col supported.
|
||||
* @no_autorepeat: disable key autorepeat.
|
||||
* @wakeup: controls whether the device should be set up as wakeup source.
|
||||
* @cfg_gpio: configure the GPIO.
|
||||
*
|
||||
* Initialisation data specific to either the machine or the platform
|
||||
* for the device driver to use or call-back when configuring gpio.
|
||||
*/
|
||||
struct samsung_keypad_platdata {
|
||||
const struct matrix_keymap_data *keymap_data;
|
||||
unsigned int rows;
|
||||
unsigned int cols;
|
||||
bool no_autorepeat;
|
||||
bool wakeup;
|
||||
|
||||
void (*cfg_gpio)(unsigned int rows, unsigned int cols);
|
||||
};
|
||||
|
||||
/**
|
||||
* samsung_keypad_set_platdata - Set platform data for Samsung Keypad device.
|
||||
* @pd: Platform data to register to device.
|
||||
*
|
||||
* Register the given platform data for use with Samsung Keypad device.
|
||||
* The call will copy the platform data, so the board definitions can
|
||||
* make the structure itself __initdata.
|
||||
*/
|
||||
extern void samsung_keypad_set_platdata(struct samsung_keypad_platdata *pd);
|
||||
|
||||
/* defined by architecture to configure gpio. */
|
||||
extern void samsung_keypad_cfg_gpio(unsigned int rows, unsigned int cols);
|
||||
|
||||
#endif /* __PLAT_SAMSUNG_KEYPAD_H */
|
|
@ -0,0 +1,56 @@
|
|||
/* linux/arch/arm/plat-samsung/include/plat/regs-ata.h
|
||||
*
|
||||
* Copyright (c) 2010 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com
|
||||
*
|
||||
* Samsung CF-ATA register definitions
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __ASM_PLAT_REGS_ATA_H
|
||||
#define __ASM_PLAT_REGS_ATA_H __FILE__
|
||||
|
||||
#define S3C_CFATA_REG(x) (x)
|
||||
|
||||
#define S3C_CFATA_MUX S3C_CFATA_REG(0x0)
|
||||
|
||||
#define S3C_ATA_CTRL S3C_CFATA_REG(0x0)
|
||||
#define S3C_ATA_STATUS S3C_CFATA_REG(0x4)
|
||||
#define S3C_ATA_CMD S3C_CFATA_REG(0x8)
|
||||
#define S3C_ATA_SWRST S3C_CFATA_REG(0xc)
|
||||
#define S3C_ATA_IRQ S3C_CFATA_REG(0x10)
|
||||
#define S3C_ATA_IRQ_MSK S3C_CFATA_REG(0x14)
|
||||
#define S3C_ATA_CFG S3C_CFATA_REG(0x18)
|
||||
|
||||
#define S3C_ATA_MDMA_TIME S3C_CFATA_REG(0x28)
|
||||
#define S3C_ATA_PIO_TIME S3C_CFATA_REG(0x2c)
|
||||
#define S3C_ATA_UDMA_TIME S3C_CFATA_REG(0x30)
|
||||
#define S3C_ATA_XFR_NUM S3C_CFATA_REG(0x34)
|
||||
#define S3C_ATA_XFR_CNT S3C_CFATA_REG(0x38)
|
||||
#define S3C_ATA_TBUF_START S3C_CFATA_REG(0x3c)
|
||||
#define S3C_ATA_TBUF_SIZE S3C_CFATA_REG(0x40)
|
||||
#define S3C_ATA_SBUF_START S3C_CFATA_REG(0x44)
|
||||
#define S3C_ATA_SBUF_SIZE S3C_CFATA_REG(0x48)
|
||||
#define S3C_ATA_CADR_TBUF S3C_CFATA_REG(0x4c)
|
||||
#define S3C_ATA_CADR_SBUF S3C_CFATA_REG(0x50)
|
||||
#define S3C_ATA_PIO_DTR S3C_CFATA_REG(0x54)
|
||||
#define S3C_ATA_PIO_FED S3C_CFATA_REG(0x58)
|
||||
#define S3C_ATA_PIO_SCR S3C_CFATA_REG(0x5c)
|
||||
#define S3C_ATA_PIO_LLR S3C_CFATA_REG(0x60)
|
||||
#define S3C_ATA_PIO_LMR S3C_CFATA_REG(0x64)
|
||||
#define S3C_ATA_PIO_LHR S3C_CFATA_REG(0x68)
|
||||
#define S3C_ATA_PIO_DVR S3C_CFATA_REG(0x6c)
|
||||
#define S3C_ATA_PIO_CSD S3C_CFATA_REG(0x70)
|
||||
#define S3C_ATA_PIO_DAD S3C_CFATA_REG(0x74)
|
||||
#define S3C_ATA_PIO_READY S3C_CFATA_REG(0x78)
|
||||
#define S3C_ATA_PIO_RDATA S3C_CFATA_REG(0x7c)
|
||||
|
||||
#define S3C_CFATA_MUX_TRUEIDE 0x01
|
||||
|
||||
#define S3C_ATA_CFG_SWAP 0x40
|
||||
#define S3C_ATA_CFG_IORDYEN 0x02
|
||||
|
||||
#endif /* __ASM_PLAT_REGS_ATA_H */
|
|
@ -14,6 +14,9 @@
|
|||
#define __ASM_ARCH_REGS_RTC_H __FILE__
|
||||
|
||||
#define S3C2410_RTCREG(x) (x)
|
||||
#define S3C2410_INTP S3C2410_RTCREG(0x30)
|
||||
#define S3C2410_INTP_ALM (1 << 1)
|
||||
#define S3C2410_INTP_TIC (1 << 0)
|
||||
|
||||
#define S3C2410_RTCCON S3C2410_RTCREG(0x40)
|
||||
#define S3C2410_RTCCON_RTCEN (1<<0)
|
||||
|
|
|
@ -20,10 +20,31 @@ struct mmc_host;
|
|||
struct mmc_card;
|
||||
struct mmc_ios;
|
||||
|
||||
enum cd_types {
|
||||
S3C_SDHCI_CD_INTERNAL, /* use mmc internal CD line */
|
||||
S3C_SDHCI_CD_EXTERNAL, /* use external callback */
|
||||
S3C_SDHCI_CD_GPIO, /* use external gpio pin for CD line */
|
||||
S3C_SDHCI_CD_NONE, /* no CD line, use polling to detect card */
|
||||
S3C_SDHCI_CD_PERMANENT, /* no CD line, card permanently wired to host */
|
||||
};
|
||||
|
||||
/**
|
||||
* struct s3c_sdhci_platdata() - Platform device data for Samsung SDHCI
|
||||
* @max_width: The maximum number of data bits supported.
|
||||
* @host_caps: Standard MMC host capabilities bit field.
|
||||
* @cd_type: Type of Card Detection method (see cd_types enum above)
|
||||
* @ext_cd_init: Initialize external card detect subsystem. Called on
|
||||
* sdhci-s3c driver probe when cd_type == S3C_SDHCI_CD_EXTERNAL.
|
||||
* notify_func argument is a callback to the sdhci-s3c driver
|
||||
* that triggers the card detection event. Callback arguments:
|
||||
* dev is pointer to platform device of the host controller,
|
||||
* state is new state of the card (0 - removed, 1 - inserted).
|
||||
* @ext_cd_cleanup: Cleanup external card detect subsystem. Called on
|
||||
* sdhci-s3c driver remove when cd_type == S3C_SDHCI_CD_EXTERNAL.
|
||||
* notify_func argument is the same callback as for ext_cd_init.
|
||||
* @ext_cd_gpio: gpio pin used for external CD line, valid only if
|
||||
* cd_type == S3C_SDHCI_CD_GPIO
|
||||
* @ext_cd_gpio_invert: invert values for external CD gpio line
|
||||
* @cfg_gpio: Configure the GPIO for a specific card bit-width
|
||||
* @cfg_card: Configure the interface for a specific card and speed. This
|
||||
* is necessary the controllers and/or GPIO blocks require the
|
||||
|
@ -37,9 +58,17 @@ struct mmc_ios;
|
|||
struct s3c_sdhci_platdata {
|
||||
unsigned int max_width;
|
||||
unsigned int host_caps;
|
||||
enum cd_types cd_type;
|
||||
|
||||
char **clocks; /* set of clock sources */
|
||||
|
||||
int ext_cd_gpio;
|
||||
bool ext_cd_gpio_invert;
|
||||
int (*ext_cd_init)(void (*notify_func)(struct platform_device *,
|
||||
int state));
|
||||
int (*ext_cd_cleanup)(void (*notify_func)(struct platform_device *,
|
||||
int state));
|
||||
|
||||
void (*cfg_gpio)(struct platform_device *dev, int width);
|
||||
void (*cfg_card)(struct platform_device *dev,
|
||||
void __iomem *regbase,
|
||||
|
@ -58,6 +87,7 @@ struct s3c_sdhci_platdata {
|
|||
extern void s3c_sdhci0_set_platdata(struct s3c_sdhci_platdata *pd);
|
||||
extern void s3c_sdhci1_set_platdata(struct s3c_sdhci_platdata *pd);
|
||||
extern void s3c_sdhci2_set_platdata(struct s3c_sdhci_platdata *pd);
|
||||
extern void s3c_sdhci3_set_platdata(struct s3c_sdhci_platdata *pd);
|
||||
|
||||
/* Default platform data, exported so that per-cpu initialisation can
|
||||
* set the correct one when there are more than one cpu type selected.
|
||||
|
@ -66,6 +96,7 @@ extern void s3c_sdhci2_set_platdata(struct s3c_sdhci_platdata *pd);
|
|||
extern struct s3c_sdhci_platdata s3c_hsmmc0_def_platdata;
|
||||
extern struct s3c_sdhci_platdata s3c_hsmmc1_def_platdata;
|
||||
extern struct s3c_sdhci_platdata s3c_hsmmc2_def_platdata;
|
||||
extern struct s3c_sdhci_platdata s3c_hsmmc3_def_platdata;
|
||||
|
||||
/* Helper function availablity */
|
||||
|
||||
|
@ -80,12 +111,11 @@ extern void s5pv210_setup_sdhci1_cfg_gpio(struct platform_device *, int w);
|
|||
extern void s5pv210_setup_sdhci2_cfg_gpio(struct platform_device *, int w);
|
||||
extern void s5pv210_setup_sdhci3_cfg_gpio(struct platform_device *, int w);
|
||||
|
||||
/* S3C6400 SDHCI setup */
|
||||
/* S3C64XX SDHCI setup */
|
||||
|
||||
#ifdef CONFIG_S3C64XX_SETUP_SDHCI
|
||||
extern char *s3c64xx_hsmmc_clksrcs[4];
|
||||
|
||||
#ifdef CONFIG_S3C_DEV_HSMMC
|
||||
extern void s3c6400_setup_sdhci_cfg_card(struct platform_device *dev,
|
||||
void __iomem *r,
|
||||
struct mmc_ios *ios,
|
||||
|
@ -93,76 +123,62 @@ extern void s3c6400_setup_sdhci_cfg_card(struct platform_device *dev,
|
|||
|
||||
static inline void s3c6400_default_sdhci0(void)
|
||||
{
|
||||
#ifdef CONFIG_S3C_DEV_HSMMC
|
||||
s3c_hsmmc0_def_platdata.clocks = s3c64xx_hsmmc_clksrcs;
|
||||
s3c_hsmmc0_def_platdata.cfg_gpio = s3c64xx_setup_sdhci0_cfg_gpio;
|
||||
s3c_hsmmc0_def_platdata.cfg_card = s3c6400_setup_sdhci_cfg_card;
|
||||
#endif
|
||||
}
|
||||
|
||||
#else
|
||||
static inline void s3c6400_default_sdhci0(void) { }
|
||||
#endif /* CONFIG_S3C_DEV_HSMMC */
|
||||
|
||||
#ifdef CONFIG_S3C_DEV_HSMMC1
|
||||
static inline void s3c6400_default_sdhci1(void)
|
||||
{
|
||||
#ifdef CONFIG_S3C_DEV_HSMMC1
|
||||
s3c_hsmmc1_def_platdata.clocks = s3c64xx_hsmmc_clksrcs;
|
||||
s3c_hsmmc1_def_platdata.cfg_gpio = s3c64xx_setup_sdhci1_cfg_gpio;
|
||||
s3c_hsmmc1_def_platdata.cfg_card = s3c6400_setup_sdhci_cfg_card;
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
static inline void s3c6400_default_sdhci1(void) { }
|
||||
#endif /* CONFIG_S3C_DEV_HSMMC1 */
|
||||
|
||||
#ifdef CONFIG_S3C_DEV_HSMMC2
|
||||
static inline void s3c6400_default_sdhci2(void)
|
||||
{
|
||||
#ifdef CONFIG_S3C_DEV_HSMMC2
|
||||
s3c_hsmmc2_def_platdata.clocks = s3c64xx_hsmmc_clksrcs;
|
||||
s3c_hsmmc2_def_platdata.cfg_gpio = s3c64xx_setup_sdhci2_cfg_gpio;
|
||||
s3c_hsmmc2_def_platdata.cfg_card = s3c6400_setup_sdhci_cfg_card;
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
static inline void s3c6400_default_sdhci2(void) { }
|
||||
#endif /* CONFIG_S3C_DEV_HSMMC2 */
|
||||
|
||||
/* S3C6410 SDHCI setup */
|
||||
|
||||
extern void s3c6410_setup_sdhci_cfg_card(struct platform_device *dev,
|
||||
void __iomem *r,
|
||||
struct mmc_ios *ios,
|
||||
struct mmc_card *card);
|
||||
|
||||
#ifdef CONFIG_S3C_DEV_HSMMC
|
||||
static inline void s3c6410_default_sdhci0(void)
|
||||
{
|
||||
#ifdef CONFIG_S3C_DEV_HSMMC
|
||||
s3c_hsmmc0_def_platdata.clocks = s3c64xx_hsmmc_clksrcs;
|
||||
s3c_hsmmc0_def_platdata.cfg_gpio = s3c64xx_setup_sdhci0_cfg_gpio;
|
||||
s3c_hsmmc0_def_platdata.cfg_card = s3c6410_setup_sdhci_cfg_card;
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
static inline void s3c6410_default_sdhci0(void) { }
|
||||
#endif /* CONFIG_S3C_DEV_HSMMC */
|
||||
|
||||
#ifdef CONFIG_S3C_DEV_HSMMC1
|
||||
static inline void s3c6410_default_sdhci1(void)
|
||||
{
|
||||
#ifdef CONFIG_S3C_DEV_HSMMC1
|
||||
s3c_hsmmc1_def_platdata.clocks = s3c64xx_hsmmc_clksrcs;
|
||||
s3c_hsmmc1_def_platdata.cfg_gpio = s3c64xx_setup_sdhci1_cfg_gpio;
|
||||
s3c_hsmmc1_def_platdata.cfg_card = s3c6410_setup_sdhci_cfg_card;
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
static inline void s3c6410_default_sdhci1(void) { }
|
||||
#endif /* CONFIG_S3C_DEV_HSMMC1 */
|
||||
|
||||
#ifdef CONFIG_S3C_DEV_HSMMC2
|
||||
static inline void s3c6410_default_sdhci2(void)
|
||||
{
|
||||
#ifdef CONFIG_S3C_DEV_HSMMC2
|
||||
s3c_hsmmc2_def_platdata.clocks = s3c64xx_hsmmc_clksrcs;
|
||||
s3c_hsmmc2_def_platdata.cfg_gpio = s3c64xx_setup_sdhci2_cfg_gpio;
|
||||
s3c_hsmmc2_def_platdata.cfg_card = s3c6410_setup_sdhci_cfg_card;
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
static inline void s3c6410_default_sdhci2(void) { }
|
||||
#endif /* CONFIG_S3C_DEV_HSMMC2 */
|
||||
|
||||
#else
|
||||
static inline void s3c6410_default_sdhci0(void) { }
|
||||
|
@ -184,48 +200,42 @@ extern void s5pc100_setup_sdhci0_cfg_card(struct platform_device *dev,
|
|||
struct mmc_ios *ios,
|
||||
struct mmc_card *card);
|
||||
|
||||
#ifdef CONFIG_S3C_DEV_HSMMC
|
||||
static inline void s5pc100_default_sdhci0(void)
|
||||
{
|
||||
#ifdef CONFIG_S3C_DEV_HSMMC
|
||||
s3c_hsmmc0_def_platdata.clocks = s5pc100_hsmmc_clksrcs;
|
||||
s3c_hsmmc0_def_platdata.cfg_gpio = s5pc100_setup_sdhci0_cfg_gpio;
|
||||
s3c_hsmmc0_def_platdata.cfg_card = s5pc100_setup_sdhci0_cfg_card;
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
static inline void s5pc100_default_sdhci0(void) { }
|
||||
#endif /* CONFIG_S3C_DEV_HSMMC */
|
||||
|
||||
#ifdef CONFIG_S3C_DEV_HSMMC1
|
||||
static inline void s5pc100_default_sdhci1(void)
|
||||
{
|
||||
#ifdef CONFIG_S3C_DEV_HSMMC1
|
||||
s3c_hsmmc1_def_platdata.clocks = s5pc100_hsmmc_clksrcs;
|
||||
s3c_hsmmc1_def_platdata.cfg_gpio = s5pc100_setup_sdhci1_cfg_gpio;
|
||||
s3c_hsmmc1_def_platdata.cfg_card = s5pc100_setup_sdhci0_cfg_card;
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
static inline void s5pc100_default_sdhci1(void) { }
|
||||
#endif /* CONFIG_S3C_DEV_HSMMC1 */
|
||||
|
||||
#ifdef CONFIG_S3C_DEV_HSMMC2
|
||||
static inline void s5pc100_default_sdhci2(void)
|
||||
{
|
||||
#ifdef CONFIG_S3C_DEV_HSMMC2
|
||||
s3c_hsmmc2_def_platdata.clocks = s5pc100_hsmmc_clksrcs;
|
||||
s3c_hsmmc2_def_platdata.cfg_gpio = s5pc100_setup_sdhci2_cfg_gpio;
|
||||
s3c_hsmmc2_def_platdata.cfg_card = s5pc100_setup_sdhci0_cfg_card;
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
static inline void s5pc100_default_sdhci2(void) { }
|
||||
#endif /* CONFIG_S3C_DEV_HSMMC1 */
|
||||
|
||||
|
||||
#else
|
||||
static inline void s5pc100_default_sdhci0(void) { }
|
||||
static inline void s5pc100_default_sdhci1(void) { }
|
||||
static inline void s5pc100_default_sdhci2(void) { }
|
||||
|
||||
#endif /* CONFIG_S5PC100_SETUP_SDHCI */
|
||||
|
||||
/* S5PV210 SDHCI setup */
|
||||
|
||||
/* S5PC110 SDHCI setup */
|
||||
#ifdef CONFIG_S5PV210_SETUP_SDHCI
|
||||
extern char *s5pv210_hsmmc_clksrcs[4];
|
||||
|
||||
|
@ -234,58 +244,48 @@ extern void s5pv210_setup_sdhci_cfg_card(struct platform_device *dev,
|
|||
struct mmc_ios *ios,
|
||||
struct mmc_card *card);
|
||||
|
||||
#ifdef CONFIG_S3C_DEV_HSMMC
|
||||
static inline void s5pv210_default_sdhci0(void)
|
||||
{
|
||||
#ifdef CONFIG_S3C_DEV_HSMMC
|
||||
s3c_hsmmc0_def_platdata.clocks = s5pv210_hsmmc_clksrcs;
|
||||
s3c_hsmmc0_def_platdata.cfg_gpio = s5pv210_setup_sdhci0_cfg_gpio;
|
||||
s3c_hsmmc0_def_platdata.cfg_card = s5pv210_setup_sdhci_cfg_card;
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
static inline void s5pv210_default_sdhci0(void) { }
|
||||
#endif /* CONFIG_S3C_DEV_HSMMC */
|
||||
|
||||
#ifdef CONFIG_S3C_DEV_HSMMC1
|
||||
static inline void s5pv210_default_sdhci1(void)
|
||||
{
|
||||
#ifdef CONFIG_S3C_DEV_HSMMC1
|
||||
s3c_hsmmc1_def_platdata.clocks = s5pv210_hsmmc_clksrcs;
|
||||
s3c_hsmmc1_def_platdata.cfg_gpio = s5pv210_setup_sdhci1_cfg_gpio;
|
||||
s3c_hsmmc1_def_platdata.cfg_card = s5pv210_setup_sdhci_cfg_card;
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
static inline void s5pv210_default_sdhci1(void) { }
|
||||
#endif /* CONFIG_S3C_DEV_HSMMC1 */
|
||||
|
||||
#ifdef CONFIG_S3C_DEV_HSMMC2
|
||||
static inline void s5pv210_default_sdhci2(void)
|
||||
{
|
||||
#ifdef CONFIG_S3C_DEV_HSMMC2
|
||||
s3c_hsmmc2_def_platdata.clocks = s5pv210_hsmmc_clksrcs;
|
||||
s3c_hsmmc2_def_platdata.cfg_gpio = s5pv210_setup_sdhci2_cfg_gpio;
|
||||
s3c_hsmmc2_def_platdata.cfg_card = s5pv210_setup_sdhci_cfg_card;
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
static inline void s5pv210_default_sdhci2(void) { }
|
||||
#endif /* CONFIG_S3C_DEV_HSMMC2 */
|
||||
|
||||
#ifdef CONFIG_S3C_DEV_HSMMC3
|
||||
static inline void s5pv210_default_sdhci3(void)
|
||||
{
|
||||
#ifdef CONFIG_S3C_DEV_HSMMC3
|
||||
s3c_hsmmc3_def_platdata.clocks = s5pv210_hsmmc_clksrcs;
|
||||
s3c_hsmmc3_def_platdata.cfg_gpio = s5pv210_setup_sdhci3_cfg_gpio;
|
||||
s3c_hsmmc3_def_platdata.cfg_card = s5pv210_setup_sdhci_cfg_card;
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
static inline void s5pv210_default_sdhci3(void) { }
|
||||
#endif /* CONFIG_S3C_DEV_HSMMC3 */
|
||||
|
||||
#else
|
||||
static inline void s5pv210_default_sdhci0(void) { }
|
||||
static inline void s5pv210_default_sdhci1(void) { }
|
||||
static inline void s5pv210_default_sdhci2(void) { }
|
||||
static inline void s5pv210_default_sdhci3(void) { }
|
||||
#endif /* CONFIG_S5PC100_SETUP_SDHCI */
|
||||
|
||||
|
||||
|
||||
#endif /* CONFIG_S5PV210_SETUP_SDHCI */
|
||||
|
||||
#endif /* __PLAT_S3C_SDHCI_H */
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
/* linux/arch/arm/plat-samsung/platformdata.c
|
||||
*
|
||||
* Copyright 2010 Ben Dooks <ben-linux <at> fluff.org>
|
||||
*
|
||||
* Helper for platform data setting
|
||||
*
|
||||
* 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/string.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <plat/devs.h>
|
||||
|
||||
void __init *s3c_set_platdata(void *pd, size_t pdsize,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
void *npd;
|
||||
|
||||
if (!pd) {
|
||||
/* too early to use dev_name(), may not be registered */
|
||||
printk(KERN_ERR "%s: no platform data supplied\n", pdev->name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
npd = kmemdup(pd, pdsize, GFP_KERNEL);
|
||||
if (!npd) {
|
||||
printk(KERN_ERR "%s: cannot clone platform data\n", pdev->name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pdev->dev.platform_data = npd;
|
||||
return npd;
|
||||
}
|
|
@ -1315,10 +1315,14 @@ static bool kbd_match(struct input_handler *handler, struct input_dev *dev)
|
|||
if (test_bit(EV_SND, dev->evbit))
|
||||
return true;
|
||||
|
||||
if (test_bit(EV_KEY, dev->evbit))
|
||||
if (test_bit(EV_KEY, dev->evbit)) {
|
||||
for (i = KEY_RESERVED; i < BTN_MISC; i++)
|
||||
if (test_bit(i, dev->keybit))
|
||||
return true;
|
||||
for (i = KEY_BRL_DOT1; i <= KEY_BRL_DOT10; i++)
|
||||
if (test_bit(i, dev->keybit))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -1586,6 +1586,7 @@ static const struct hid_device_id hid_ignore_list[] = {
|
|||
{ HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC5UH) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC4UM) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0001) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0002) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0003) },
|
||||
|
|
|
@ -198,6 +198,7 @@
|
|||
|
||||
#define USB_VENDOR_ID_ETT 0x0664
|
||||
#define USB_DEVICE_ID_TC5UH 0x0309
|
||||
#define USB_DEVICE_ID_TC4UM 0x0306
|
||||
|
||||
#define USB_VENDOR_ID_EZKEY 0x0518
|
||||
#define USB_DEVICE_ID_BTC_8193 0x0002
|
||||
|
|
|
@ -534,6 +534,9 @@ mapped:
|
|||
input_set_abs_params(input, usage->code, a, b, (b - a) >> 8, (b - a) >> 4);
|
||||
else input_set_abs_params(input, usage->code, a, b, 0, 0);
|
||||
|
||||
/* use a larger default input buffer for MT devices */
|
||||
if (usage->code == ABS_MT_POSITION_X && input->hint_events_per_packet == 0)
|
||||
input_set_events_per_packet(input, 60);
|
||||
}
|
||||
|
||||
if (usage->type == EV_ABS &&
|
||||
|
|
|
@ -521,12 +521,19 @@ config I2C_PXA_SLAVE
|
|||
is necessary for systems where the PXA may be a target on the
|
||||
I2C bus.
|
||||
|
||||
config HAVE_S3C2410_I2C
|
||||
bool
|
||||
help
|
||||
This will include I2C support for Samsung SoCs. If you want to
|
||||
include I2C support for any machine, kindly select this in the
|
||||
respective Kconfig file.
|
||||
|
||||
config I2C_S3C2410
|
||||
tristate "S3C2410 I2C Driver"
|
||||
depends on ARCH_S3C2410 || ARCH_S3C64XX
|
||||
depends on HAVE_S3C2410_I2C
|
||||
help
|
||||
Say Y here to include support for I2C controller in the
|
||||
Samsung S3C2410 based System-on-Chip devices.
|
||||
Samsung SoCs.
|
||||
|
||||
config I2C_S6000
|
||||
tristate "S6000 I2C support"
|
||||
|
|
|
@ -10,7 +10,8 @@
|
|||
|
||||
#define EVDEV_MINOR_BASE 64
|
||||
#define EVDEV_MINORS 32
|
||||
#define EVDEV_BUFFER_SIZE 64
|
||||
#define EVDEV_MIN_BUFFER_SIZE 64U
|
||||
#define EVDEV_BUF_PACKETS 8
|
||||
|
||||
#include <linux/poll.h>
|
||||
#include <linux/sched.h>
|
||||
|
@ -23,7 +24,6 @@
|
|||
#include "input-compat.h"
|
||||
|
||||
struct evdev {
|
||||
int exist;
|
||||
int open;
|
||||
int minor;
|
||||
struct input_handle handle;
|
||||
|
@ -33,16 +33,18 @@ struct evdev {
|
|||
spinlock_t client_lock; /* protects client_list */
|
||||
struct mutex mutex;
|
||||
struct device dev;
|
||||
bool exist;
|
||||
};
|
||||
|
||||
struct evdev_client {
|
||||
struct input_event buffer[EVDEV_BUFFER_SIZE];
|
||||
int head;
|
||||
int tail;
|
||||
spinlock_t buffer_lock; /* protects access to buffer, head and tail */
|
||||
struct fasync_struct *fasync;
|
||||
struct evdev *evdev;
|
||||
struct list_head node;
|
||||
int bufsize;
|
||||
struct input_event buffer[];
|
||||
};
|
||||
|
||||
static struct evdev *evdev_table[EVDEV_MINORS];
|
||||
|
@ -52,11 +54,15 @@ static void evdev_pass_event(struct evdev_client *client,
|
|||
struct input_event *event)
|
||||
{
|
||||
/*
|
||||
* Interrupts are disabled, just acquire the lock
|
||||
* Interrupts are disabled, just acquire the lock.
|
||||
* Make sure we don't leave with the client buffer
|
||||
* "empty" by having client->head == client->tail.
|
||||
*/
|
||||
spin_lock(&client->buffer_lock);
|
||||
client->buffer[client->head++] = *event;
|
||||
client->head &= EVDEV_BUFFER_SIZE - 1;
|
||||
do {
|
||||
client->buffer[client->head++] = *event;
|
||||
client->head &= client->bufsize - 1;
|
||||
} while (client->head == client->tail);
|
||||
spin_unlock(&client->buffer_lock);
|
||||
|
||||
if (event->type == EV_SYN)
|
||||
|
@ -242,11 +248,21 @@ static int evdev_release(struct inode *inode, struct file *file)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int evdev_compute_buffer_size(struct input_dev *dev)
|
||||
{
|
||||
unsigned int n_events =
|
||||
max(dev->hint_events_per_packet * EVDEV_BUF_PACKETS,
|
||||
EVDEV_MIN_BUFFER_SIZE);
|
||||
|
||||
return roundup_pow_of_two(n_events);
|
||||
}
|
||||
|
||||
static int evdev_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct evdev *evdev;
|
||||
struct evdev_client *client;
|
||||
int i = iminor(inode) - EVDEV_MINOR_BASE;
|
||||
unsigned int bufsize;
|
||||
int error;
|
||||
|
||||
if (i >= EVDEV_MINORS)
|
||||
|
@ -263,12 +279,17 @@ static int evdev_open(struct inode *inode, struct file *file)
|
|||
if (!evdev)
|
||||
return -ENODEV;
|
||||
|
||||
client = kzalloc(sizeof(struct evdev_client), GFP_KERNEL);
|
||||
bufsize = evdev_compute_buffer_size(evdev->handle.dev);
|
||||
|
||||
client = kzalloc(sizeof(struct evdev_client) +
|
||||
bufsize * sizeof(struct input_event),
|
||||
GFP_KERNEL);
|
||||
if (!client) {
|
||||
error = -ENOMEM;
|
||||
goto err_put_evdev;
|
||||
}
|
||||
|
||||
client->bufsize = bufsize;
|
||||
spin_lock_init(&client->buffer_lock);
|
||||
client->evdev = evdev;
|
||||
evdev_attach_client(evdev, client);
|
||||
|
@ -334,7 +355,7 @@ static int evdev_fetch_next_event(struct evdev_client *client,
|
|||
have_event = client->head != client->tail;
|
||||
if (have_event) {
|
||||
*event = client->buffer[client->tail++];
|
||||
client->tail &= EVDEV_BUFFER_SIZE - 1;
|
||||
client->tail &= client->bufsize - 1;
|
||||
}
|
||||
|
||||
spin_unlock_irq(&client->buffer_lock);
|
||||
|
@ -382,10 +403,15 @@ static unsigned int evdev_poll(struct file *file, poll_table *wait)
|
|||
{
|
||||
struct evdev_client *client = file->private_data;
|
||||
struct evdev *evdev = client->evdev;
|
||||
unsigned int mask;
|
||||
|
||||
poll_wait(file, &evdev->wait, wait);
|
||||
return ((client->head == client->tail) ? 0 : (POLLIN | POLLRDNORM)) |
|
||||
(evdev->exist ? 0 : (POLLHUP | POLLERR));
|
||||
|
||||
mask = evdev->exist ? POLLOUT | POLLWRNORM : POLLHUP | POLLERR;
|
||||
if (client->head != client->tail)
|
||||
mask |= POLLIN | POLLRDNORM;
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
|
@ -665,6 +691,10 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
|
|||
sizeof(struct input_absinfo))))
|
||||
return -EFAULT;
|
||||
|
||||
/* We can't change number of reserved MT slots */
|
||||
if (t == ABS_MT_SLOT)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Take event lock to ensure that we are not
|
||||
* changing device parameters in the middle
|
||||
|
@ -768,7 +798,7 @@ static void evdev_remove_chrdev(struct evdev *evdev)
|
|||
static void evdev_mark_dead(struct evdev *evdev)
|
||||
{
|
||||
mutex_lock(&evdev->mutex);
|
||||
evdev->exist = 0;
|
||||
evdev->exist = false;
|
||||
mutex_unlock(&evdev->mutex);
|
||||
}
|
||||
|
||||
|
@ -817,7 +847,7 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
|
|||
init_waitqueue_head(&evdev->wait);
|
||||
|
||||
dev_set_name(&evdev->dev, "event%d", minor);
|
||||
evdev->exist = 1;
|
||||
evdev->exist = true;
|
||||
evdev->minor = minor;
|
||||
|
||||
evdev->handle.dev = input_get_device(dev);
|
||||
|
|
|
@ -33,25 +33,6 @@ MODULE_LICENSE("GPL");
|
|||
|
||||
#define INPUT_DEVICES 256
|
||||
|
||||
/*
|
||||
* EV_ABS events which should not be cached are listed here.
|
||||
*/
|
||||
static unsigned int input_abs_bypass_init_data[] __initdata = {
|
||||
ABS_MT_TOUCH_MAJOR,
|
||||
ABS_MT_TOUCH_MINOR,
|
||||
ABS_MT_WIDTH_MAJOR,
|
||||
ABS_MT_WIDTH_MINOR,
|
||||
ABS_MT_ORIENTATION,
|
||||
ABS_MT_POSITION_X,
|
||||
ABS_MT_POSITION_Y,
|
||||
ABS_MT_TOOL_TYPE,
|
||||
ABS_MT_BLOB_ID,
|
||||
ABS_MT_TRACKING_ID,
|
||||
ABS_MT_PRESSURE,
|
||||
0
|
||||
};
|
||||
static unsigned long input_abs_bypass[BITS_TO_LONGS(ABS_CNT)];
|
||||
|
||||
static LIST_HEAD(input_dev_list);
|
||||
static LIST_HEAD(input_handler_list);
|
||||
|
||||
|
@ -181,6 +162,56 @@ static void input_stop_autorepeat(struct input_dev *dev)
|
|||
#define INPUT_PASS_TO_DEVICE 2
|
||||
#define INPUT_PASS_TO_ALL (INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE)
|
||||
|
||||
static int input_handle_abs_event(struct input_dev *dev,
|
||||
unsigned int code, int *pval)
|
||||
{
|
||||
bool is_mt_event;
|
||||
int *pold;
|
||||
|
||||
if (code == ABS_MT_SLOT) {
|
||||
/*
|
||||
* "Stage" the event; we'll flush it later, when we
|
||||
* get actiual touch data.
|
||||
*/
|
||||
if (*pval >= 0 && *pval < dev->mtsize)
|
||||
dev->slot = *pval;
|
||||
|
||||
return INPUT_IGNORE_EVENT;
|
||||
}
|
||||
|
||||
is_mt_event = code >= ABS_MT_FIRST && code <= ABS_MT_LAST;
|
||||
|
||||
if (!is_mt_event) {
|
||||
pold = &dev->abs[code];
|
||||
} else if (dev->mt) {
|
||||
struct input_mt_slot *mtslot = &dev->mt[dev->slot];
|
||||
pold = &mtslot->abs[code - ABS_MT_FIRST];
|
||||
} else {
|
||||
/*
|
||||
* Bypass filtering for multitouch events when
|
||||
* not employing slots.
|
||||
*/
|
||||
pold = NULL;
|
||||
}
|
||||
|
||||
if (pold) {
|
||||
*pval = input_defuzz_abs_event(*pval, *pold,
|
||||
dev->absfuzz[code]);
|
||||
if (*pold == *pval)
|
||||
return INPUT_IGNORE_EVENT;
|
||||
|
||||
*pold = *pval;
|
||||
}
|
||||
|
||||
/* Flush pending "slot" event */
|
||||
if (is_mt_event && dev->slot != dev->abs[ABS_MT_SLOT]) {
|
||||
dev->abs[ABS_MT_SLOT] = dev->slot;
|
||||
input_pass_event(dev, EV_ABS, ABS_MT_SLOT, dev->slot);
|
||||
}
|
||||
|
||||
return INPUT_PASS_TO_HANDLERS;
|
||||
}
|
||||
|
||||
static void input_handle_event(struct input_dev *dev,
|
||||
unsigned int type, unsigned int code, int value)
|
||||
{
|
||||
|
@ -196,12 +227,12 @@ static void input_handle_event(struct input_dev *dev,
|
|||
|
||||
case SYN_REPORT:
|
||||
if (!dev->sync) {
|
||||
dev->sync = 1;
|
||||
dev->sync = true;
|
||||
disposition = INPUT_PASS_TO_HANDLERS;
|
||||
}
|
||||
break;
|
||||
case SYN_MT_REPORT:
|
||||
dev->sync = 0;
|
||||
dev->sync = false;
|
||||
disposition = INPUT_PASS_TO_HANDLERS;
|
||||
break;
|
||||
}
|
||||
|
@ -233,21 +264,9 @@ static void input_handle_event(struct input_dev *dev,
|
|||
break;
|
||||
|
||||
case EV_ABS:
|
||||
if (is_event_supported(code, dev->absbit, ABS_MAX)) {
|
||||
if (is_event_supported(code, dev->absbit, ABS_MAX))
|
||||
disposition = input_handle_abs_event(dev, code, &value);
|
||||
|
||||
if (test_bit(code, input_abs_bypass)) {
|
||||
disposition = INPUT_PASS_TO_HANDLERS;
|
||||
break;
|
||||
}
|
||||
|
||||
value = input_defuzz_abs_event(value,
|
||||
dev->abs[code], dev->absfuzz[code]);
|
||||
|
||||
if (dev->abs[code] != value) {
|
||||
dev->abs[code] = value;
|
||||
disposition = INPUT_PASS_TO_HANDLERS;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case EV_REL:
|
||||
|
@ -298,7 +317,7 @@ static void input_handle_event(struct input_dev *dev,
|
|||
}
|
||||
|
||||
if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
|
||||
dev->sync = 0;
|
||||
dev->sync = false;
|
||||
|
||||
if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
|
||||
dev->event(dev, type, code, value);
|
||||
|
@ -527,13 +546,31 @@ void input_close_device(struct input_handle *handle)
|
|||
}
|
||||
EXPORT_SYMBOL(input_close_device);
|
||||
|
||||
/*
|
||||
* Simulate keyup events for all keys that are marked as pressed.
|
||||
* The function must be called with dev->event_lock held.
|
||||
*/
|
||||
static void input_dev_release_keys(struct input_dev *dev)
|
||||
{
|
||||
int code;
|
||||
|
||||
if (is_event_supported(EV_KEY, dev->evbit, EV_MAX)) {
|
||||
for (code = 0; code <= KEY_MAX; code++) {
|
||||
if (is_event_supported(code, dev->keybit, KEY_MAX) &&
|
||||
__test_and_clear_bit(code, dev->key)) {
|
||||
input_pass_event(dev, EV_KEY, code, 0);
|
||||
}
|
||||
}
|
||||
input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Prepare device for unregistering
|
||||
*/
|
||||
static void input_disconnect_device(struct input_dev *dev)
|
||||
{
|
||||
struct input_handle *handle;
|
||||
int code;
|
||||
|
||||
/*
|
||||
* Mark device as going away. Note that we take dev->mutex here
|
||||
|
@ -552,15 +589,7 @@ static void input_disconnect_device(struct input_dev *dev)
|
|||
* generate events even after we done here but they will not
|
||||
* reach any handlers.
|
||||
*/
|
||||
if (is_event_supported(EV_KEY, dev->evbit, EV_MAX)) {
|
||||
for (code = 0; code <= KEY_MAX; code++) {
|
||||
if (is_event_supported(code, dev->keybit, KEY_MAX) &&
|
||||
__test_and_clear_bit(code, dev->key)) {
|
||||
input_pass_event(dev, EV_KEY, code, 0);
|
||||
}
|
||||
}
|
||||
input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
|
||||
}
|
||||
input_dev_release_keys(dev);
|
||||
|
||||
list_for_each_entry(handle, &dev->h_list, d_node)
|
||||
handle->open = 0;
|
||||
|
@ -684,7 +713,7 @@ int input_set_keycode(struct input_dev *dev,
|
|||
unsigned int scancode, unsigned int keycode)
|
||||
{
|
||||
unsigned long flags;
|
||||
int old_keycode;
|
||||
unsigned int old_keycode;
|
||||
int retval;
|
||||
|
||||
if (keycode > KEY_MAX)
|
||||
|
@ -1278,6 +1307,7 @@ static void input_dev_release(struct device *device)
|
|||
struct input_dev *dev = to_input_dev(device);
|
||||
|
||||
input_ff_destroy(dev);
|
||||
input_mt_destroy_slots(dev);
|
||||
kfree(dev);
|
||||
|
||||
module_put(THIS_MODULE);
|
||||
|
@ -1433,6 +1463,15 @@ static int input_dev_resume(struct device *dev)
|
|||
|
||||
mutex_lock(&input_dev->mutex);
|
||||
input_dev_reset(input_dev, true);
|
||||
|
||||
/*
|
||||
* Keys that have been pressed at suspend time are unlikely
|
||||
* to be still pressed when we resume.
|
||||
*/
|
||||
spin_lock_irq(&input_dev->event_lock);
|
||||
input_dev_release_keys(input_dev);
|
||||
spin_unlock_irq(&input_dev->event_lock);
|
||||
|
||||
mutex_unlock(&input_dev->mutex);
|
||||
|
||||
return 0;
|
||||
|
@ -1517,6 +1556,45 @@ void input_free_device(struct input_dev *dev)
|
|||
}
|
||||
EXPORT_SYMBOL(input_free_device);
|
||||
|
||||
/**
|
||||
* input_mt_create_slots() - create MT input slots
|
||||
* @dev: input device supporting MT events and finger tracking
|
||||
* @num_slots: number of slots used by the device
|
||||
*
|
||||
* This function allocates all necessary memory for MT slot handling
|
||||
* in the input device, and adds ABS_MT_SLOT to the device capabilities.
|
||||
*/
|
||||
int input_mt_create_slots(struct input_dev *dev, unsigned int num_slots)
|
||||
{
|
||||
if (!num_slots)
|
||||
return 0;
|
||||
|
||||
dev->mt = kcalloc(num_slots, sizeof(struct input_mt_slot), GFP_KERNEL);
|
||||
if (!dev->mt)
|
||||
return -ENOMEM;
|
||||
|
||||
dev->mtsize = num_slots;
|
||||
input_set_abs_params(dev, ABS_MT_SLOT, 0, num_slots - 1, 0, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(input_mt_create_slots);
|
||||
|
||||
/**
|
||||
* input_mt_destroy_slots() - frees the MT slots of the input device
|
||||
* @dev: input device with allocated MT slots
|
||||
*
|
||||
* This function is only needed in error path as the input core will
|
||||
* automatically free the MT slots when the device is destroyed.
|
||||
*/
|
||||
void input_mt_destroy_slots(struct input_dev *dev)
|
||||
{
|
||||
kfree(dev->mt);
|
||||
dev->mt = NULL;
|
||||
dev->mtsize = 0;
|
||||
}
|
||||
EXPORT_SYMBOL(input_mt_destroy_slots);
|
||||
|
||||
/**
|
||||
* input_set_capability - mark device as capable of a certain event
|
||||
* @dev: device that is capable of emitting or accepting event
|
||||
|
@ -1926,20 +2004,10 @@ static const struct file_operations input_fops = {
|
|||
.open = input_open_file,
|
||||
};
|
||||
|
||||
static void __init input_init_abs_bypass(void)
|
||||
{
|
||||
const unsigned int *p;
|
||||
|
||||
for (p = input_abs_bypass_init_data; *p; p++)
|
||||
input_abs_bypass[BIT_WORD(*p)] |= BIT_MASK(*p);
|
||||
}
|
||||
|
||||
static int __init input_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
input_init_abs_bypass();
|
||||
|
||||
err = class_register(&input_class);
|
||||
if (err) {
|
||||
printk(KERN_ERR "input: unable to register input_dev class\n");
|
||||
|
|
|
@ -37,7 +37,6 @@ MODULE_LICENSE("GPL");
|
|||
#define JOYDEV_BUFFER_SIZE 64
|
||||
|
||||
struct joydev {
|
||||
int exist;
|
||||
int open;
|
||||
int minor;
|
||||
struct input_handle handle;
|
||||
|
@ -46,6 +45,7 @@ struct joydev {
|
|||
spinlock_t client_lock; /* protects client_list */
|
||||
struct mutex mutex;
|
||||
struct device dev;
|
||||
bool exist;
|
||||
|
||||
struct js_corr corr[ABS_CNT];
|
||||
struct JS_DATA_SAVE_TYPE glue;
|
||||
|
@ -760,7 +760,7 @@ static void joydev_remove_chrdev(struct joydev *joydev)
|
|||
static void joydev_mark_dead(struct joydev *joydev)
|
||||
{
|
||||
mutex_lock(&joydev->mutex);
|
||||
joydev->exist = 0;
|
||||
joydev->exist = false;
|
||||
mutex_unlock(&joydev->mutex);
|
||||
}
|
||||
|
||||
|
@ -817,10 +817,9 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
|
|||
init_waitqueue_head(&joydev->wait);
|
||||
|
||||
dev_set_name(&joydev->dev, "js%d", minor);
|
||||
joydev->exist = 1;
|
||||
joydev->exist = true;
|
||||
joydev->minor = minor;
|
||||
|
||||
joydev->exist = 1;
|
||||
joydev->handle.dev = input_get_device(dev);
|
||||
joydev->handle.name = dev_name(&joydev->dev);
|
||||
joydev->handle.handler = handler;
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
* 2005 Dominic Cerquetti <binary1230@yahoo.com>
|
||||
* 2006 Adam Buchbinder <adam.buchbinder@gmail.com>
|
||||
* 2007 Jan Kratochvil <honza@jikos.cz>
|
||||
* 2010 Christoph Fritz <chf.fritz@googlemail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
|
@ -88,6 +89,9 @@
|
|||
but we map them to axes when possible to simplify things */
|
||||
#define MAP_DPAD_TO_BUTTONS (1 << 0)
|
||||
#define MAP_TRIGGERS_TO_BUTTONS (1 << 1)
|
||||
#define MAP_STICKS_TO_NULL (1 << 2)
|
||||
#define DANCEPAD_MAP_CONFIG (MAP_DPAD_TO_BUTTONS | \
|
||||
MAP_TRIGGERS_TO_BUTTONS | MAP_STICKS_TO_NULL)
|
||||
|
||||
#define XTYPE_XBOX 0
|
||||
#define XTYPE_XBOX360 1
|
||||
|
@ -102,6 +106,10 @@ static int triggers_to_buttons;
|
|||
module_param(triggers_to_buttons, bool, S_IRUGO);
|
||||
MODULE_PARM_DESC(triggers_to_buttons, "Map triggers to buttons rather than axes for unknown pads");
|
||||
|
||||
static int sticks_to_null;
|
||||
module_param(sticks_to_null, bool, S_IRUGO);
|
||||
MODULE_PARM_DESC(sticks_to_null, "Do not map sticks at all for unknown pads");
|
||||
|
||||
static const struct xpad_device {
|
||||
u16 idVendor;
|
||||
u16 idProduct;
|
||||
|
@ -114,7 +122,7 @@ static const struct xpad_device {
|
|||
{ 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", 0, XTYPE_XBOX },
|
||||
{ 0x045e, 0x0287, "Microsoft Xbox Controller S", 0, XTYPE_XBOX },
|
||||
{ 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
|
||||
{ 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
|
||||
{ 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", DANCEPAD_MAP_CONFIG, XTYPE_XBOX },
|
||||
{ 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX },
|
||||
{ 0x046d, 0xc242, "Logitech Chillstream Controller", 0, XTYPE_XBOX360 },
|
||||
{ 0x046d, 0xca84, "Logitech Xbox Cordless Controller", 0, XTYPE_XBOX },
|
||||
|
@ -151,6 +159,7 @@ static const struct xpad_device {
|
|||
{ 0x045e, 0x028e, "Microsoft X-Box 360 pad", 0, XTYPE_XBOX360 },
|
||||
{ 0x1bad, 0x0003, "Harmonix Rock Band Drumkit", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
|
||||
{ 0x0f0d, 0x0016, "Hori Real Arcade Pro.EX", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
|
||||
{ 0x0f0d, 0x000d, "Hori Fighting Stick EX2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
|
||||
{ 0xffff, 0xffff, "Chinese-made Xbox Controller", 0, XTYPE_XBOX },
|
||||
{ 0x0000, 0x0000, "Generic X-Box pad", 0, XTYPE_UNKNOWN }
|
||||
};
|
||||
|
@ -158,7 +167,7 @@ static const struct xpad_device {
|
|||
/* buttons shared with xbox and xbox360 */
|
||||
static const signed short xpad_common_btn[] = {
|
||||
BTN_A, BTN_B, BTN_X, BTN_Y, /* "analog" buttons */
|
||||
BTN_START, BTN_BACK, BTN_THUMBL, BTN_THUMBR, /* start/back/sticks */
|
||||
BTN_START, BTN_SELECT, BTN_THUMBL, BTN_THUMBR, /* start/back/sticks */
|
||||
-1 /* terminating entry */
|
||||
};
|
||||
|
||||
|
@ -168,10 +177,10 @@ static const signed short xpad_btn[] = {
|
|||
-1 /* terminating entry */
|
||||
};
|
||||
|
||||
/* used when dpad is mapped to nuttons */
|
||||
/* used when dpad is mapped to buttons */
|
||||
static const signed short xpad_btn_pad[] = {
|
||||
BTN_LEFT, BTN_RIGHT, /* d-pad left, right */
|
||||
BTN_0, BTN_1, /* d-pad up, down (XXX names??) */
|
||||
BTN_TRIGGER_HAPPY1, BTN_TRIGGER_HAPPY2, /* d-pad left, right */
|
||||
BTN_TRIGGER_HAPPY3, BTN_TRIGGER_HAPPY4, /* d-pad up, down */
|
||||
-1 /* terminating entry */
|
||||
};
|
||||
|
||||
|
@ -279,17 +288,19 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
|
|||
{
|
||||
struct input_dev *dev = xpad->dev;
|
||||
|
||||
/* left stick */
|
||||
input_report_abs(dev, ABS_X,
|
||||
(__s16) le16_to_cpup((__le16 *)(data + 12)));
|
||||
input_report_abs(dev, ABS_Y,
|
||||
~(__s16) le16_to_cpup((__le16 *)(data + 14)));
|
||||
if (!(xpad->mapping & MAP_STICKS_TO_NULL)) {
|
||||
/* left stick */
|
||||
input_report_abs(dev, ABS_X,
|
||||
(__s16) le16_to_cpup((__le16 *)(data + 12)));
|
||||
input_report_abs(dev, ABS_Y,
|
||||
~(__s16) le16_to_cpup((__le16 *)(data + 14)));
|
||||
|
||||
/* right stick */
|
||||
input_report_abs(dev, ABS_RX,
|
||||
(__s16) le16_to_cpup((__le16 *)(data + 16)));
|
||||
input_report_abs(dev, ABS_RY,
|
||||
~(__s16) le16_to_cpup((__le16 *)(data + 18)));
|
||||
/* right stick */
|
||||
input_report_abs(dev, ABS_RX,
|
||||
(__s16) le16_to_cpup((__le16 *)(data + 16)));
|
||||
input_report_abs(dev, ABS_RY,
|
||||
~(__s16) le16_to_cpup((__le16 *)(data + 18)));
|
||||
}
|
||||
|
||||
/* triggers left/right */
|
||||
if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) {
|
||||
|
@ -302,10 +313,11 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
|
|||
|
||||
/* digital pad */
|
||||
if (xpad->mapping & MAP_DPAD_TO_BUTTONS) {
|
||||
input_report_key(dev, BTN_LEFT, data[2] & 0x04);
|
||||
input_report_key(dev, BTN_RIGHT, data[2] & 0x08);
|
||||
input_report_key(dev, BTN_0, data[2] & 0x01); /* up */
|
||||
input_report_key(dev, BTN_1, data[2] & 0x02); /* down */
|
||||
/* dpad as buttons (left, right, up, down) */
|
||||
input_report_key(dev, BTN_TRIGGER_HAPPY1, data[2] & 0x04);
|
||||
input_report_key(dev, BTN_TRIGGER_HAPPY2, data[2] & 0x08);
|
||||
input_report_key(dev, BTN_TRIGGER_HAPPY3, data[2] & 0x01);
|
||||
input_report_key(dev, BTN_TRIGGER_HAPPY4, data[2] & 0x02);
|
||||
} else {
|
||||
input_report_abs(dev, ABS_HAT0X,
|
||||
!!(data[2] & 0x08) - !!(data[2] & 0x04));
|
||||
|
@ -315,7 +327,7 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
|
|||
|
||||
/* start/back buttons and stick press left/right */
|
||||
input_report_key(dev, BTN_START, data[2] & 0x10);
|
||||
input_report_key(dev, BTN_BACK, data[2] & 0x20);
|
||||
input_report_key(dev, BTN_SELECT, data[2] & 0x20);
|
||||
input_report_key(dev, BTN_THUMBL, data[2] & 0x40);
|
||||
input_report_key(dev, BTN_THUMBR, data[2] & 0x80);
|
||||
|
||||
|
@ -349,11 +361,11 @@ static void xpad360_process_packet(struct usb_xpad *xpad,
|
|||
|
||||
/* digital pad */
|
||||
if (xpad->mapping & MAP_DPAD_TO_BUTTONS) {
|
||||
/* dpad as buttons (right, left, down, up) */
|
||||
input_report_key(dev, BTN_LEFT, data[2] & 0x04);
|
||||
input_report_key(dev, BTN_RIGHT, data[2] & 0x08);
|
||||
input_report_key(dev, BTN_0, data[2] & 0x01); /* up */
|
||||
input_report_key(dev, BTN_1, data[2] & 0x02); /* down */
|
||||
/* dpad as buttons (left, right, up, down) */
|
||||
input_report_key(dev, BTN_TRIGGER_HAPPY1, data[2] & 0x04);
|
||||
input_report_key(dev, BTN_TRIGGER_HAPPY2, data[2] & 0x08);
|
||||
input_report_key(dev, BTN_TRIGGER_HAPPY3, data[2] & 0x01);
|
||||
input_report_key(dev, BTN_TRIGGER_HAPPY4, data[2] & 0x02);
|
||||
} else {
|
||||
input_report_abs(dev, ABS_HAT0X,
|
||||
!!(data[2] & 0x08) - !!(data[2] & 0x04));
|
||||
|
@ -363,7 +375,7 @@ static void xpad360_process_packet(struct usb_xpad *xpad,
|
|||
|
||||
/* start/back buttons */
|
||||
input_report_key(dev, BTN_START, data[2] & 0x10);
|
||||
input_report_key(dev, BTN_BACK, data[2] & 0x20);
|
||||
input_report_key(dev, BTN_SELECT, data[2] & 0x20);
|
||||
|
||||
/* stick press left/right */
|
||||
input_report_key(dev, BTN_THUMBL, data[2] & 0x40);
|
||||
|
@ -378,17 +390,19 @@ static void xpad360_process_packet(struct usb_xpad *xpad,
|
|||
input_report_key(dev, BTN_TR, data[3] & 0x02);
|
||||
input_report_key(dev, BTN_MODE, data[3] & 0x04);
|
||||
|
||||
/* left stick */
|
||||
input_report_abs(dev, ABS_X,
|
||||
(__s16) le16_to_cpup((__le16 *)(data + 6)));
|
||||
input_report_abs(dev, ABS_Y,
|
||||
~(__s16) le16_to_cpup((__le16 *)(data + 8)));
|
||||
if (!(xpad->mapping & MAP_STICKS_TO_NULL)) {
|
||||
/* left stick */
|
||||
input_report_abs(dev, ABS_X,
|
||||
(__s16) le16_to_cpup((__le16 *)(data + 6)));
|
||||
input_report_abs(dev, ABS_Y,
|
||||
~(__s16) le16_to_cpup((__le16 *)(data + 8)));
|
||||
|
||||
/* right stick */
|
||||
input_report_abs(dev, ABS_RX,
|
||||
(__s16) le16_to_cpup((__le16 *)(data + 10)));
|
||||
input_report_abs(dev, ABS_RY,
|
||||
~(__s16) le16_to_cpup((__le16 *)(data + 12)));
|
||||
/* right stick */
|
||||
input_report_abs(dev, ABS_RX,
|
||||
(__s16) le16_to_cpup((__le16 *)(data + 10)));
|
||||
input_report_abs(dev, ABS_RY,
|
||||
~(__s16) le16_to_cpup((__le16 *)(data + 12)));
|
||||
}
|
||||
|
||||
/* triggers left/right */
|
||||
if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) {
|
||||
|
@ -814,6 +828,8 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
|
|||
xpad->mapping |= MAP_DPAD_TO_BUTTONS;
|
||||
if (triggers_to_buttons)
|
||||
xpad->mapping |= MAP_TRIGGERS_TO_BUTTONS;
|
||||
if (sticks_to_null)
|
||||
xpad->mapping |= MAP_STICKS_TO_NULL;
|
||||
}
|
||||
|
||||
xpad->dev = input_dev;
|
||||
|
@ -830,16 +846,20 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
|
|||
input_dev->open = xpad_open;
|
||||
input_dev->close = xpad_close;
|
||||
|
||||
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
|
||||
input_dev->evbit[0] = BIT_MASK(EV_KEY);
|
||||
|
||||
/* set up standard buttons and axes */
|
||||
if (!(xpad->mapping & MAP_STICKS_TO_NULL)) {
|
||||
input_dev->evbit[0] |= BIT_MASK(EV_ABS);
|
||||
/* set up axes */
|
||||
for (i = 0; xpad_abs[i] >= 0; i++)
|
||||
xpad_set_up_abs(input_dev, xpad_abs[i]);
|
||||
}
|
||||
|
||||
/* set up standard buttons */
|
||||
for (i = 0; xpad_common_btn[i] >= 0; i++)
|
||||
__set_bit(xpad_common_btn[i], input_dev->keybit);
|
||||
|
||||
for (i = 0; xpad_abs[i] >= 0; i++)
|
||||
xpad_set_up_abs(input_dev, xpad_abs[i]);
|
||||
|
||||
/* Now set up model-specific ones */
|
||||
/* set up model-specific ones */
|
||||
if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX360W) {
|
||||
for (i = 0; xpad360_btn[i] >= 0; i++)
|
||||
__set_bit(xpad360_btn[i], input_dev->keybit);
|
||||
|
|
|
@ -297,6 +297,18 @@ config KEYBOARD_MAX7359
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called max7359_keypad.
|
||||
|
||||
config KEYBOARD_MCS
|
||||
tristate "MELFAS MCS Touchkey"
|
||||
depends on I2C
|
||||
help
|
||||
Say Y here if you have the MELFAS MCS5000/5080 touchkey controller
|
||||
chip in your system.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called mcs_touchkey.
|
||||
|
||||
config KEYBOARD_IMX
|
||||
tristate "IMX keypad support"
|
||||
depends on ARCH_MXC
|
||||
|
@ -342,6 +354,15 @@ config KEYBOARD_PXA930_ROTARY
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called pxa930_rotary.
|
||||
|
||||
config KEYBOARD_SAMSUNG
|
||||
tristate "Samsung keypad support"
|
||||
depends on SAMSUNG_DEV_KEYPAD
|
||||
help
|
||||
Say Y here if you want to use the Samsung keypad.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called samsung-keypad.
|
||||
|
||||
config KEYBOARD_STOWAWAY
|
||||
tristate "Stowaway keyboard"
|
||||
select SERIO
|
||||
|
|
|
@ -26,12 +26,14 @@ obj-$(CONFIG_KEYBOARD_LOCOMO) += locomokbd.o
|
|||
obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o
|
||||
obj-$(CONFIG_KEYBOARD_MATRIX) += matrix_keypad.o
|
||||
obj-$(CONFIG_KEYBOARD_MAX7359) += max7359_keypad.o
|
||||
obj-$(CONFIG_KEYBOARD_MCS) += mcs_touchkey.o
|
||||
obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o
|
||||
obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o
|
||||
obj-$(CONFIG_KEYBOARD_OPENCORES) += opencores-kbd.o
|
||||
obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keypad.o
|
||||
obj-$(CONFIG_KEYBOARD_PXA930_ROTARY) += pxa930_rotary.o
|
||||
obj-$(CONFIG_KEYBOARD_QT2160) += qt2160.o
|
||||
obj-$(CONFIG_KEYBOARD_SAMSUNG) += samsung-keypad.o
|
||||
obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o
|
||||
obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o
|
||||
obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <linux/i2c/adp5588.h>
|
||||
|
@ -54,6 +55,10 @@
|
|||
|
||||
#define KEYP_MAX_EVENT 10
|
||||
|
||||
#define MAXGPIO 18
|
||||
#define ADP_BANK(offs) ((offs) >> 3)
|
||||
#define ADP_BIT(offs) (1u << ((offs) & 0x7))
|
||||
|
||||
/*
|
||||
* Early pre 4.0 Silicon required to delay readout by at least 25ms,
|
||||
* since the Event Counter Register updated 25ms after the interrupt
|
||||
|
@ -67,6 +72,16 @@ struct adp5588_kpad {
|
|||
struct delayed_work work;
|
||||
unsigned long delay;
|
||||
unsigned short keycode[ADP5588_KEYMAPSIZE];
|
||||
const struct adp5588_gpi_map *gpimap;
|
||||
unsigned short gpimapsize;
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
unsigned char gpiomap[MAXGPIO];
|
||||
bool export_gpio;
|
||||
struct gpio_chip gc;
|
||||
struct mutex gpio_lock; /* Protect cached dir, dat_out */
|
||||
u8 dat_out[3];
|
||||
u8 dir[3];
|
||||
#endif
|
||||
};
|
||||
|
||||
static int adp5588_read(struct i2c_client *client, u8 reg)
|
||||
|
@ -84,12 +99,222 @@ static int adp5588_write(struct i2c_client *client, u8 reg, u8 val)
|
|||
return i2c_smbus_write_byte_data(client, reg, val);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
static int adp5588_gpio_get_value(struct gpio_chip *chip, unsigned off)
|
||||
{
|
||||
struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
|
||||
unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
|
||||
unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
|
||||
|
||||
return !!(adp5588_read(kpad->client, GPIO_DAT_STAT1 + bank) & bit);
|
||||
}
|
||||
|
||||
static void adp5588_gpio_set_value(struct gpio_chip *chip,
|
||||
unsigned off, int val)
|
||||
{
|
||||
struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
|
||||
unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
|
||||
unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
|
||||
|
||||
mutex_lock(&kpad->gpio_lock);
|
||||
|
||||
if (val)
|
||||
kpad->dat_out[bank] |= bit;
|
||||
else
|
||||
kpad->dat_out[bank] &= ~bit;
|
||||
|
||||
adp5588_write(kpad->client, GPIO_DAT_OUT1 + bank,
|
||||
kpad->dat_out[bank]);
|
||||
|
||||
mutex_unlock(&kpad->gpio_lock);
|
||||
}
|
||||
|
||||
static int adp5588_gpio_direction_input(struct gpio_chip *chip, unsigned off)
|
||||
{
|
||||
struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
|
||||
unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
|
||||
unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&kpad->gpio_lock);
|
||||
|
||||
kpad->dir[bank] &= ~bit;
|
||||
ret = adp5588_write(kpad->client, GPIO_DIR1 + bank, kpad->dir[bank]);
|
||||
|
||||
mutex_unlock(&kpad->gpio_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adp5588_gpio_direction_output(struct gpio_chip *chip,
|
||||
unsigned off, int val)
|
||||
{
|
||||
struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
|
||||
unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
|
||||
unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&kpad->gpio_lock);
|
||||
|
||||
kpad->dir[bank] |= bit;
|
||||
|
||||
if (val)
|
||||
kpad->dat_out[bank] |= bit;
|
||||
else
|
||||
kpad->dat_out[bank] &= ~bit;
|
||||
|
||||
ret = adp5588_write(kpad->client, GPIO_DAT_OUT1 + bank,
|
||||
kpad->dat_out[bank]);
|
||||
ret |= adp5588_write(kpad->client, GPIO_DIR1 + bank,
|
||||
kpad->dir[bank]);
|
||||
|
||||
mutex_unlock(&kpad->gpio_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devinit adp5588_build_gpiomap(struct adp5588_kpad *kpad,
|
||||
const struct adp5588_kpad_platform_data *pdata)
|
||||
{
|
||||
bool pin_used[MAXGPIO];
|
||||
int n_unused = 0;
|
||||
int i;
|
||||
|
||||
memset(pin_used, 0, sizeof(pin_used));
|
||||
|
||||
for (i = 0; i < pdata->rows; i++)
|
||||
pin_used[i] = true;
|
||||
|
||||
for (i = 0; i < pdata->cols; i++)
|
||||
pin_used[i + GPI_PIN_COL_BASE - GPI_PIN_BASE] = true;
|
||||
|
||||
for (i = 0; i < kpad->gpimapsize; i++)
|
||||
pin_used[kpad->gpimap[i].pin - GPI_PIN_BASE] = true;
|
||||
|
||||
for (i = 0; i < MAXGPIO; i++)
|
||||
if (!pin_used[i])
|
||||
kpad->gpiomap[n_unused++] = i;
|
||||
|
||||
return n_unused;
|
||||
}
|
||||
|
||||
static int __devinit adp5588_gpio_add(struct adp5588_kpad *kpad)
|
||||
{
|
||||
struct device *dev = &kpad->client->dev;
|
||||
const struct adp5588_kpad_platform_data *pdata = dev->platform_data;
|
||||
const struct adp5588_gpio_platform_data *gpio_data = pdata->gpio_data;
|
||||
int i, error;
|
||||
|
||||
if (!gpio_data)
|
||||
return 0;
|
||||
|
||||
kpad->gc.ngpio = adp5588_build_gpiomap(kpad, pdata);
|
||||
if (kpad->gc.ngpio == 0) {
|
||||
dev_info(dev, "No unused gpios left to export\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
kpad->export_gpio = true;
|
||||
|
||||
kpad->gc.direction_input = adp5588_gpio_direction_input;
|
||||
kpad->gc.direction_output = adp5588_gpio_direction_output;
|
||||
kpad->gc.get = adp5588_gpio_get_value;
|
||||
kpad->gc.set = adp5588_gpio_set_value;
|
||||
kpad->gc.can_sleep = 1;
|
||||
|
||||
kpad->gc.base = gpio_data->gpio_start;
|
||||
kpad->gc.label = kpad->client->name;
|
||||
kpad->gc.owner = THIS_MODULE;
|
||||
|
||||
mutex_init(&kpad->gpio_lock);
|
||||
|
||||
error = gpiochip_add(&kpad->gc);
|
||||
if (error) {
|
||||
dev_err(dev, "gpiochip_add failed, err: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
for (i = 0; i <= ADP_BANK(MAXGPIO); i++) {
|
||||
kpad->dat_out[i] = adp5588_read(kpad->client,
|
||||
GPIO_DAT_OUT1 + i);
|
||||
kpad->dir[i] = adp5588_read(kpad->client, GPIO_DIR1 + i);
|
||||
}
|
||||
|
||||
if (gpio_data->setup) {
|
||||
error = gpio_data->setup(kpad->client,
|
||||
kpad->gc.base, kpad->gc.ngpio,
|
||||
gpio_data->context);
|
||||
if (error)
|
||||
dev_warn(dev, "setup failed, %d\n", error);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __devexit adp5588_gpio_remove(struct adp5588_kpad *kpad)
|
||||
{
|
||||
struct device *dev = &kpad->client->dev;
|
||||
const struct adp5588_kpad_platform_data *pdata = dev->platform_data;
|
||||
const struct adp5588_gpio_platform_data *gpio_data = pdata->gpio_data;
|
||||
int error;
|
||||
|
||||
if (!kpad->export_gpio)
|
||||
return;
|
||||
|
||||
if (gpio_data->teardown) {
|
||||
error = gpio_data->teardown(kpad->client,
|
||||
kpad->gc.base, kpad->gc.ngpio,
|
||||
gpio_data->context);
|
||||
if (error)
|
||||
dev_warn(dev, "teardown failed %d\n", error);
|
||||
}
|
||||
|
||||
error = gpiochip_remove(&kpad->gc);
|
||||
if (error)
|
||||
dev_warn(dev, "gpiochip_remove failed %d\n", error);
|
||||
}
|
||||
#else
|
||||
static inline int adp5588_gpio_add(struct adp5588_kpad *kpad)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void adp5588_gpio_remove(struct adp5588_kpad *kpad)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
static void adp5588_report_events(struct adp5588_kpad *kpad, int ev_cnt)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < ev_cnt; i++) {
|
||||
int key = adp5588_read(kpad->client, Key_EVENTA + i);
|
||||
int key_val = key & KEY_EV_MASK;
|
||||
|
||||
if (key_val >= GPI_PIN_BASE && key_val <= GPI_PIN_END) {
|
||||
for (j = 0; j < kpad->gpimapsize; j++) {
|
||||
if (key_val == kpad->gpimap[j].pin) {
|
||||
input_report_switch(kpad->input,
|
||||
kpad->gpimap[j].sw_evt,
|
||||
key & KEY_EV_PRESSED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
input_report_key(kpad->input,
|
||||
kpad->keycode[key_val - 1],
|
||||
key & KEY_EV_PRESSED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void adp5588_work(struct work_struct *work)
|
||||
{
|
||||
struct adp5588_kpad *kpad = container_of(work,
|
||||
struct adp5588_kpad, work.work);
|
||||
struct i2c_client *client = kpad->client;
|
||||
int i, key, status, ev_cnt;
|
||||
int status, ev_cnt;
|
||||
|
||||
status = adp5588_read(client, INT_STAT);
|
||||
|
||||
|
@ -99,12 +324,7 @@ static void adp5588_work(struct work_struct *work)
|
|||
if (status & KE_INT) {
|
||||
ev_cnt = adp5588_read(client, KEY_LCK_EC_STAT) & KEC;
|
||||
if (ev_cnt) {
|
||||
for (i = 0; i < ev_cnt; i++) {
|
||||
key = adp5588_read(client, Key_EVENTA + i);
|
||||
input_report_key(kpad->input,
|
||||
kpad->keycode[(key & KEY_EV_MASK) - 1],
|
||||
key & KEY_EV_PRESSED);
|
||||
}
|
||||
adp5588_report_events(kpad, ev_cnt);
|
||||
input_sync(kpad->input);
|
||||
}
|
||||
}
|
||||
|
@ -128,8 +348,10 @@ static irqreturn_t adp5588_irq(int irq, void *handle)
|
|||
|
||||
static int __devinit adp5588_setup(struct i2c_client *client)
|
||||
{
|
||||
struct adp5588_kpad_platform_data *pdata = client->dev.platform_data;
|
||||
const struct adp5588_kpad_platform_data *pdata = client->dev.platform_data;
|
||||
const struct adp5588_gpio_platform_data *gpio_data = pdata->gpio_data;
|
||||
int i, ret;
|
||||
unsigned char evt_mode1 = 0, evt_mode2 = 0, evt_mode3 = 0;
|
||||
|
||||
ret = adp5588_write(client, KP_GPIO1, KP_SEL(pdata->rows));
|
||||
ret |= adp5588_write(client, KP_GPIO2, KP_SEL(pdata->cols) & 0xFF);
|
||||
|
@ -144,6 +366,32 @@ static int __devinit adp5588_setup(struct i2c_client *client)
|
|||
for (i = 0; i < KEYP_MAX_EVENT; i++)
|
||||
ret |= adp5588_read(client, Key_EVENTA);
|
||||
|
||||
for (i = 0; i < pdata->gpimapsize; i++) {
|
||||
unsigned short pin = pdata->gpimap[i].pin;
|
||||
|
||||
if (pin <= GPI_PIN_ROW_END) {
|
||||
evt_mode1 |= (1 << (pin - GPI_PIN_ROW_BASE));
|
||||
} else {
|
||||
evt_mode2 |= ((1 << (pin - GPI_PIN_COL_BASE)) & 0xFF);
|
||||
evt_mode3 |= ((1 << (pin - GPI_PIN_COL_BASE)) >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
if (pdata->gpimapsize) {
|
||||
ret |= adp5588_write(client, GPI_EM1, evt_mode1);
|
||||
ret |= adp5588_write(client, GPI_EM2, evt_mode2);
|
||||
ret |= adp5588_write(client, GPI_EM3, evt_mode3);
|
||||
}
|
||||
|
||||
if (gpio_data) {
|
||||
for (i = 0; i <= ADP_BANK(MAXGPIO); i++) {
|
||||
int pull_mask = gpio_data->pullup_dis_mask;
|
||||
|
||||
ret |= adp5588_write(client, GPIO_PULL1 + i,
|
||||
(pull_mask >> (8 * i)) & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
ret |= adp5588_write(client, INT_STAT, CMP2_INT | CMP1_INT |
|
||||
OVR_FLOW_INT | K_LCK_INT |
|
||||
GPI_INT | KE_INT); /* Status is W1C */
|
||||
|
@ -158,11 +406,49 @@ static int __devinit adp5588_setup(struct i2c_client *client)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void __devinit adp5588_report_switch_state(struct adp5588_kpad *kpad)
|
||||
{
|
||||
int gpi_stat1 = adp5588_read(kpad->client, GPIO_DAT_STAT1);
|
||||
int gpi_stat2 = adp5588_read(kpad->client, GPIO_DAT_STAT2);
|
||||
int gpi_stat3 = adp5588_read(kpad->client, GPIO_DAT_STAT3);
|
||||
int gpi_stat_tmp, pin_loc;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < kpad->gpimapsize; i++) {
|
||||
unsigned short pin = kpad->gpimap[i].pin;
|
||||
|
||||
if (pin <= GPI_PIN_ROW_END) {
|
||||
gpi_stat_tmp = gpi_stat1;
|
||||
pin_loc = pin - GPI_PIN_ROW_BASE;
|
||||
} else if ((pin - GPI_PIN_COL_BASE) < 8) {
|
||||
gpi_stat_tmp = gpi_stat2;
|
||||
pin_loc = pin - GPI_PIN_COL_BASE;
|
||||
} else {
|
||||
gpi_stat_tmp = gpi_stat3;
|
||||
pin_loc = pin - GPI_PIN_COL_BASE - 8;
|
||||
}
|
||||
|
||||
if (gpi_stat_tmp < 0) {
|
||||
dev_err(&kpad->client->dev,
|
||||
"Can't read GPIO_DAT_STAT switch %d default to OFF\n",
|
||||
pin);
|
||||
gpi_stat_tmp = 0;
|
||||
}
|
||||
|
||||
input_report_switch(kpad->input,
|
||||
kpad->gpimap[i].sw_evt,
|
||||
!(gpi_stat_tmp & (1 << pin_loc)));
|
||||
}
|
||||
|
||||
input_sync(kpad->input);
|
||||
}
|
||||
|
||||
|
||||
static int __devinit adp5588_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct adp5588_kpad *kpad;
|
||||
struct adp5588_kpad_platform_data *pdata = client->dev.platform_data;
|
||||
const struct adp5588_kpad_platform_data *pdata = client->dev.platform_data;
|
||||
struct input_dev *input;
|
||||
unsigned int revid;
|
||||
int ret, i;
|
||||
|
@ -189,6 +475,37 @@ static int __devinit adp5588_probe(struct i2c_client *client,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!pdata->gpimap && pdata->gpimapsize) {
|
||||
dev_err(&client->dev, "invalid gpimap from pdata\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (pdata->gpimapsize > ADP5588_GPIMAPSIZE_MAX) {
|
||||
dev_err(&client->dev, "invalid gpimapsize\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < pdata->gpimapsize; i++) {
|
||||
unsigned short pin = pdata->gpimap[i].pin;
|
||||
|
||||
if (pin < GPI_PIN_BASE || pin > GPI_PIN_END) {
|
||||
dev_err(&client->dev, "invalid gpi pin data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (pin <= GPI_PIN_ROW_END) {
|
||||
if (pin - GPI_PIN_ROW_BASE + 1 <= pdata->rows) {
|
||||
dev_err(&client->dev, "invalid gpi row data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
if (pin - GPI_PIN_COL_BASE + 1 <= pdata->cols) {
|
||||
dev_err(&client->dev, "invalid gpi col data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!client->irq) {
|
||||
dev_err(&client->dev, "no IRQ?\n");
|
||||
return -EINVAL;
|
||||
|
@ -233,6 +550,9 @@ static int __devinit adp5588_probe(struct i2c_client *client,
|
|||
memcpy(kpad->keycode, pdata->keymap,
|
||||
pdata->keymapsize * input->keycodesize);
|
||||
|
||||
kpad->gpimap = pdata->gpimap;
|
||||
kpad->gpimapsize = pdata->gpimapsize;
|
||||
|
||||
/* setup input device */
|
||||
__set_bit(EV_KEY, input->evbit);
|
||||
|
||||
|
@ -243,6 +563,11 @@ static int __devinit adp5588_probe(struct i2c_client *client,
|
|||
__set_bit(kpad->keycode[i] & KEY_MAX, input->keybit);
|
||||
__clear_bit(KEY_RESERVED, input->keybit);
|
||||
|
||||
if (kpad->gpimapsize)
|
||||
__set_bit(EV_SW, input->evbit);
|
||||
for (i = 0; i < kpad->gpimapsize; i++)
|
||||
__set_bit(kpad->gpimap[i].sw_evt, input->swbit);
|
||||
|
||||
error = input_register_device(input);
|
||||
if (error) {
|
||||
dev_err(&client->dev, "unable to register input device\n");
|
||||
|
@ -261,6 +586,13 @@ static int __devinit adp5588_probe(struct i2c_client *client,
|
|||
if (error)
|
||||
goto err_free_irq;
|
||||
|
||||
if (kpad->gpimapsize)
|
||||
adp5588_report_switch_state(kpad);
|
||||
|
||||
error = adp5588_gpio_add(kpad);
|
||||
if (error)
|
||||
goto err_free_irq;
|
||||
|
||||
device_init_wakeup(&client->dev, 1);
|
||||
i2c_set_clientdata(client, kpad);
|
||||
|
||||
|
@ -287,6 +619,7 @@ static int __devexit adp5588_remove(struct i2c_client *client)
|
|||
free_irq(client->irq, kpad);
|
||||
cancel_delayed_work_sync(&kpad->work);
|
||||
input_unregister_device(kpad->input);
|
||||
adp5588_gpio_remove(kpad);
|
||||
kfree(kpad);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -31,6 +31,7 @@ struct gpio_button_data {
|
|||
struct input_dev *input;
|
||||
struct timer_list timer;
|
||||
struct work_struct work;
|
||||
int timer_debounce; /* in msecs */
|
||||
bool disabled;
|
||||
};
|
||||
|
||||
|
@ -109,7 +110,7 @@ static void gpio_keys_disable_button(struct gpio_button_data *bdata)
|
|||
* Disable IRQ and possible debouncing timer.
|
||||
*/
|
||||
disable_irq(gpio_to_irq(bdata->button->gpio));
|
||||
if (bdata->button->debounce_interval)
|
||||
if (bdata->timer_debounce)
|
||||
del_timer_sync(&bdata->timer);
|
||||
|
||||
bdata->disabled = true;
|
||||
|
@ -347,9 +348,9 @@ static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
|
|||
|
||||
BUG_ON(irq != gpio_to_irq(button->gpio));
|
||||
|
||||
if (button->debounce_interval)
|
||||
if (bdata->timer_debounce)
|
||||
mod_timer(&bdata->timer,
|
||||
jiffies + msecs_to_jiffies(button->debounce_interval));
|
||||
jiffies + msecs_to_jiffies(bdata->timer_debounce));
|
||||
else
|
||||
schedule_work(&bdata->work);
|
||||
|
||||
|
@ -383,6 +384,14 @@ static int __devinit gpio_keys_setup_key(struct platform_device *pdev,
|
|||
goto fail3;
|
||||
}
|
||||
|
||||
if (button->debounce_interval) {
|
||||
error = gpio_set_debounce(button->gpio,
|
||||
button->debounce_interval * 1000);
|
||||
/* use timer if gpiolib doesn't provide debounce */
|
||||
if (error < 0)
|
||||
bdata->timer_debounce = button->debounce_interval;
|
||||
}
|
||||
|
||||
irq = gpio_to_irq(button->gpio);
|
||||
if (irq < 0) {
|
||||
error = irq;
|
||||
|
@ -498,7 +507,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
|
|||
fail2:
|
||||
while (--i >= 0) {
|
||||
free_irq(gpio_to_irq(pdata->buttons[i].gpio), &ddata->data[i]);
|
||||
if (pdata->buttons[i].debounce_interval)
|
||||
if (ddata->data[i].timer_debounce)
|
||||
del_timer_sync(&ddata->data[i].timer);
|
||||
cancel_work_sync(&ddata->data[i].work);
|
||||
gpio_free(pdata->buttons[i].gpio);
|
||||
|
@ -526,7 +535,7 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev)
|
|||
for (i = 0; i < pdata->nbuttons; i++) {
|
||||
int irq = gpio_to_irq(pdata->buttons[i].gpio);
|
||||
free_irq(irq, &ddata->data[i]);
|
||||
if (pdata->buttons[i].debounce_interval)
|
||||
if (ddata->data[i].timer_debounce)
|
||||
del_timer_sync(&ddata->data[i].timer);
|
||||
cancel_work_sync(&ddata->data[i].work);
|
||||
gpio_free(pdata->buttons[i].gpio);
|
||||
|
|
|
@ -642,6 +642,7 @@ static int __devinit lm8323_probe(struct i2c_client *client,
|
|||
struct lm8323_platform_data *pdata = client->dev.platform_data;
|
||||
struct input_dev *idev;
|
||||
struct lm8323_chip *lm;
|
||||
int pwm;
|
||||
int i, err;
|
||||
unsigned long tmo;
|
||||
u8 data[2];
|
||||
|
@ -710,8 +711,9 @@ static int __devinit lm8323_probe(struct i2c_client *client,
|
|||
goto fail1;
|
||||
}
|
||||
|
||||
for (i = 0; i < LM8323_NUM_PWMS; i++) {
|
||||
err = init_pwm(lm, i + 1, &client->dev, pdata->pwm_names[i]);
|
||||
for (pwm = 0; pwm < LM8323_NUM_PWMS; pwm++) {
|
||||
err = init_pwm(lm, pwm + 1, &client->dev,
|
||||
pdata->pwm_names[pwm]);
|
||||
if (err < 0)
|
||||
goto fail2;
|
||||
}
|
||||
|
@ -764,9 +766,9 @@ fail4:
|
|||
fail3:
|
||||
device_remove_file(&client->dev, &dev_attr_disable_kp);
|
||||
fail2:
|
||||
while (--i >= 0)
|
||||
if (lm->pwm[i].enabled)
|
||||
led_classdev_unregister(&lm->pwm[i].cdev);
|
||||
while (--pwm >= 0)
|
||||
if (lm->pwm[pwm].enabled)
|
||||
led_classdev_unregister(&lm->pwm[pwm].cdev);
|
||||
fail1:
|
||||
input_free_device(idev);
|
||||
kfree(lm);
|
||||
|
|
|
@ -37,6 +37,7 @@ struct matrix_keypad {
|
|||
spinlock_t lock;
|
||||
bool scan_pending;
|
||||
bool stopped;
|
||||
bool gpio_all_disabled;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -87,8 +88,12 @@ static void enable_row_irqs(struct matrix_keypad *keypad)
|
|||
const struct matrix_keypad_platform_data *pdata = keypad->pdata;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < pdata->num_row_gpios; i++)
|
||||
enable_irq(gpio_to_irq(pdata->row_gpios[i]));
|
||||
if (pdata->clustered_irq > 0)
|
||||
enable_irq(pdata->clustered_irq);
|
||||
else {
|
||||
for (i = 0; i < pdata->num_row_gpios; i++)
|
||||
enable_irq(gpio_to_irq(pdata->row_gpios[i]));
|
||||
}
|
||||
}
|
||||
|
||||
static void disable_row_irqs(struct matrix_keypad *keypad)
|
||||
|
@ -96,8 +101,12 @@ static void disable_row_irqs(struct matrix_keypad *keypad)
|
|||
const struct matrix_keypad_platform_data *pdata = keypad->pdata;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < pdata->num_row_gpios; i++)
|
||||
disable_irq_nosync(gpio_to_irq(pdata->row_gpios[i]));
|
||||
if (pdata->clustered_irq > 0)
|
||||
disable_irq_nosync(pdata->clustered_irq);
|
||||
else {
|
||||
for (i = 0; i < pdata->num_row_gpios; i++)
|
||||
disable_irq_nosync(gpio_to_irq(pdata->row_gpios[i]));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -216,25 +225,58 @@ static void matrix_keypad_stop(struct input_dev *dev)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int matrix_keypad_suspend(struct device *dev)
|
||||
static void matrix_keypad_enable_wakeup(struct matrix_keypad *keypad)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct matrix_keypad *keypad = platform_get_drvdata(pdev);
|
||||
const struct matrix_keypad_platform_data *pdata = keypad->pdata;
|
||||
unsigned int gpio;
|
||||
int i;
|
||||
|
||||
matrix_keypad_stop(keypad->input_dev);
|
||||
if (pdata->clustered_irq > 0) {
|
||||
if (enable_irq_wake(pdata->clustered_irq) == 0)
|
||||
keypad->gpio_all_disabled = true;
|
||||
} else {
|
||||
|
||||
if (device_may_wakeup(&pdev->dev)) {
|
||||
for (i = 0; i < pdata->num_row_gpios; i++) {
|
||||
if (!test_bit(i, keypad->disabled_gpios)) {
|
||||
unsigned int gpio = pdata->row_gpios[i];
|
||||
gpio = pdata->row_gpios[i];
|
||||
|
||||
if (enable_irq_wake(gpio_to_irq(gpio)) == 0)
|
||||
__set_bit(i, keypad->disabled_gpios);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void matrix_keypad_disable_wakeup(struct matrix_keypad *keypad)
|
||||
{
|
||||
const struct matrix_keypad_platform_data *pdata = keypad->pdata;
|
||||
unsigned int gpio;
|
||||
int i;
|
||||
|
||||
if (pdata->clustered_irq > 0) {
|
||||
if (keypad->gpio_all_disabled) {
|
||||
disable_irq_wake(pdata->clustered_irq);
|
||||
keypad->gpio_all_disabled = false;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < pdata->num_row_gpios; i++) {
|
||||
if (test_and_clear_bit(i, keypad->disabled_gpios)) {
|
||||
gpio = pdata->row_gpios[i];
|
||||
disable_irq_wake(gpio_to_irq(gpio));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int matrix_keypad_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct matrix_keypad *keypad = platform_get_drvdata(pdev);
|
||||
|
||||
matrix_keypad_stop(keypad->input_dev);
|
||||
|
||||
if (device_may_wakeup(&pdev->dev))
|
||||
matrix_keypad_enable_wakeup(keypad);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -243,18 +285,9 @@ static int matrix_keypad_resume(struct device *dev)
|
|||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct matrix_keypad *keypad = platform_get_drvdata(pdev);
|
||||
const struct matrix_keypad_platform_data *pdata = keypad->pdata;
|
||||
int i;
|
||||
|
||||
if (device_may_wakeup(&pdev->dev)) {
|
||||
for (i = 0; i < pdata->num_row_gpios; i++) {
|
||||
if (test_and_clear_bit(i, keypad->disabled_gpios)) {
|
||||
unsigned int gpio = pdata->row_gpios[i];
|
||||
|
||||
disable_irq_wake(gpio_to_irq(gpio));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (device_may_wakeup(&pdev->dev))
|
||||
matrix_keypad_disable_wakeup(keypad);
|
||||
|
||||
matrix_keypad_start(keypad->input_dev);
|
||||
|
||||
|
@ -296,17 +329,31 @@ static int __devinit init_matrix_gpio(struct platform_device *pdev,
|
|||
gpio_direction_input(pdata->row_gpios[i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < pdata->num_row_gpios; i++) {
|
||||
err = request_irq(gpio_to_irq(pdata->row_gpios[i]),
|
||||
if (pdata->clustered_irq > 0) {
|
||||
err = request_irq(pdata->clustered_irq,
|
||||
matrix_keypad_interrupt,
|
||||
IRQF_DISABLED |
|
||||
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
|
||||
pdata->clustered_irq_flags,
|
||||
"matrix-keypad", keypad);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev,
|
||||
"Unable to acquire interrupt for GPIO line %i\n",
|
||||
pdata->row_gpios[i]);
|
||||
goto err_free_irqs;
|
||||
"Unable to acquire clustered interrupt\n");
|
||||
goto err_free_rows;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < pdata->num_row_gpios; i++) {
|
||||
err = request_irq(gpio_to_irq(pdata->row_gpios[i]),
|
||||
matrix_keypad_interrupt,
|
||||
IRQF_DISABLED |
|
||||
IRQF_TRIGGER_RISING |
|
||||
IRQF_TRIGGER_FALLING,
|
||||
"matrix-keypad", keypad);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev,
|
||||
"Unable to acquire interrupt "
|
||||
"for GPIO line %i\n",
|
||||
pdata->row_gpios[i]);
|
||||
goto err_free_irqs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -418,11 +465,16 @@ static int __devexit matrix_keypad_remove(struct platform_device *pdev)
|
|||
|
||||
device_init_wakeup(&pdev->dev, 0);
|
||||
|
||||
for (i = 0; i < pdata->num_row_gpios; i++) {
|
||||
free_irq(gpio_to_irq(pdata->row_gpios[i]), keypad);
|
||||
gpio_free(pdata->row_gpios[i]);
|
||||
if (pdata->clustered_irq > 0) {
|
||||
free_irq(pdata->clustered_irq, keypad);
|
||||
} else {
|
||||
for (i = 0; i < pdata->num_row_gpios; i++)
|
||||
free_irq(gpio_to_irq(pdata->row_gpios[i]), keypad);
|
||||
}
|
||||
|
||||
for (i = 0; i < pdata->num_row_gpios; i++)
|
||||
gpio_free(pdata->row_gpios[i]);
|
||||
|
||||
for (i = 0; i < pdata->num_col_gpios; i++)
|
||||
gpio_free(pdata->col_gpios[i]);
|
||||
|
||||
|
|
|
@ -0,0 +1,239 @@
|
|||
/*
|
||||
* mcs_touchkey.c - Touchkey driver for MELFAS MCS5000/5080 controller
|
||||
*
|
||||
* Copyright (C) 2010 Samsung Electronics Co.Ltd
|
||||
* Author: HeungJun Kim <riverful.kim@samsung.com>
|
||||
* Author: Joonyoung Shim <jy0922.shim@samsung.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c/mcs.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
/* MCS5000 Touchkey */
|
||||
#define MCS5000_TOUCHKEY_STATUS 0x04
|
||||
#define MCS5000_TOUCHKEY_STATUS_PRESS 7
|
||||
#define MCS5000_TOUCHKEY_FW 0x0a
|
||||
#define MCS5000_TOUCHKEY_BASE_VAL 0x61
|
||||
|
||||
/* MCS5080 Touchkey */
|
||||
#define MCS5080_TOUCHKEY_STATUS 0x00
|
||||
#define MCS5080_TOUCHKEY_STATUS_PRESS 3
|
||||
#define MCS5080_TOUCHKEY_FW 0x01
|
||||
#define MCS5080_TOUCHKEY_BASE_VAL 0x1
|
||||
|
||||
enum mcs_touchkey_type {
|
||||
MCS5000_TOUCHKEY,
|
||||
MCS5080_TOUCHKEY,
|
||||
};
|
||||
|
||||
struct mcs_touchkey_chip {
|
||||
unsigned int status_reg;
|
||||
unsigned int pressbit;
|
||||
unsigned int press_invert;
|
||||
unsigned int baseval;
|
||||
};
|
||||
|
||||
struct mcs_touchkey_data {
|
||||
struct i2c_client *client;
|
||||
struct input_dev *input_dev;
|
||||
struct mcs_touchkey_chip chip;
|
||||
unsigned int key_code;
|
||||
unsigned int key_val;
|
||||
unsigned short keycodes[];
|
||||
};
|
||||
|
||||
static irqreturn_t mcs_touchkey_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct mcs_touchkey_data *data = dev_id;
|
||||
struct mcs_touchkey_chip *chip = &data->chip;
|
||||
struct i2c_client *client = data->client;
|
||||
struct input_dev *input = data->input_dev;
|
||||
unsigned int key_val;
|
||||
unsigned int pressed;
|
||||
int val;
|
||||
|
||||
val = i2c_smbus_read_byte_data(client, chip->status_reg);
|
||||
if (val < 0) {
|
||||
dev_err(&client->dev, "i2c read error [%d]\n", val);
|
||||
goto out;
|
||||
}
|
||||
|
||||
pressed = (val & (1 << chip->pressbit)) >> chip->pressbit;
|
||||
if (chip->press_invert)
|
||||
pressed ^= chip->press_invert;
|
||||
|
||||
/* key_val is 0 when released, so we should use key_val of press. */
|
||||
if (pressed) {
|
||||
key_val = val & (0xff >> (8 - chip->pressbit));
|
||||
if (!key_val)
|
||||
goto out;
|
||||
key_val -= chip->baseval;
|
||||
data->key_code = data->keycodes[key_val];
|
||||
data->key_val = key_val;
|
||||
}
|
||||
|
||||
input_event(input, EV_MSC, MSC_SCAN, data->key_val);
|
||||
input_report_key(input, data->key_code, pressed);
|
||||
input_sync(input);
|
||||
|
||||
dev_dbg(&client->dev, "key %d %d %s\n", data->key_val, data->key_code,
|
||||
pressed ? "pressed" : "released");
|
||||
|
||||
out:
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int __devinit mcs_touchkey_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
const struct mcs_platform_data *pdata;
|
||||
struct mcs_touchkey_data *data;
|
||||
struct input_dev *input_dev;
|
||||
unsigned int fw_reg;
|
||||
int fw_ver;
|
||||
int error;
|
||||
int i;
|
||||
|
||||
pdata = client->dev.platform_data;
|
||||
if (!pdata) {
|
||||
dev_err(&client->dev, "no platform data defined\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
data = kzalloc(sizeof(struct mcs_touchkey_data) +
|
||||
sizeof(data->keycodes[0]) * (pdata->key_maxval + 1),
|
||||
GFP_KERNEL);
|
||||
input_dev = input_allocate_device();
|
||||
if (!data || !input_dev) {
|
||||
dev_err(&client->dev, "Failed to allocate memory\n");
|
||||
error = -ENOMEM;
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
data->client = client;
|
||||
data->input_dev = input_dev;
|
||||
|
||||
if (id->driver_data == MCS5000_TOUCHKEY) {
|
||||
data->chip.status_reg = MCS5000_TOUCHKEY_STATUS;
|
||||
data->chip.pressbit = MCS5000_TOUCHKEY_STATUS_PRESS;
|
||||
data->chip.baseval = MCS5000_TOUCHKEY_BASE_VAL;
|
||||
fw_reg = MCS5000_TOUCHKEY_FW;
|
||||
} else {
|
||||
data->chip.status_reg = MCS5080_TOUCHKEY_STATUS;
|
||||
data->chip.pressbit = MCS5080_TOUCHKEY_STATUS_PRESS;
|
||||
data->chip.press_invert = 1;
|
||||
data->chip.baseval = MCS5080_TOUCHKEY_BASE_VAL;
|
||||
fw_reg = MCS5080_TOUCHKEY_FW;
|
||||
}
|
||||
|
||||
fw_ver = i2c_smbus_read_byte_data(client, fw_reg);
|
||||
if (fw_ver < 0) {
|
||||
error = fw_ver;
|
||||
dev_err(&client->dev, "i2c read error[%d]\n", error);
|
||||
goto err_free_mem;
|
||||
}
|
||||
dev_info(&client->dev, "Firmware version: %d\n", fw_ver);
|
||||
|
||||
input_dev->name = "MELPAS MCS Touchkey";
|
||||
input_dev->id.bustype = BUS_I2C;
|
||||
input_dev->dev.parent = &client->dev;
|
||||
input_dev->evbit[0] = BIT_MASK(EV_KEY);
|
||||
if (!pdata->no_autorepeat)
|
||||
input_dev->evbit[0] |= BIT_MASK(EV_REP);
|
||||
input_dev->keycode = data->keycodes;
|
||||
input_dev->keycodesize = sizeof(data->keycodes[0]);
|
||||
input_dev->keycodemax = pdata->key_maxval + 1;
|
||||
|
||||
for (i = 0; i < pdata->keymap_size; i++) {
|
||||
unsigned int val = MCS_KEY_VAL(pdata->keymap[i]);
|
||||
unsigned int code = MCS_KEY_CODE(pdata->keymap[i]);
|
||||
|
||||
data->keycodes[val] = code;
|
||||
__set_bit(code, input_dev->keybit);
|
||||
}
|
||||
|
||||
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
|
||||
input_set_drvdata(input_dev, data);
|
||||
|
||||
if (pdata->cfg_pin)
|
||||
pdata->cfg_pin();
|
||||
|
||||
error = request_threaded_irq(client->irq, NULL, mcs_touchkey_interrupt,
|
||||
IRQF_TRIGGER_FALLING, client->dev.driver->name, data);
|
||||
if (error) {
|
||||
dev_err(&client->dev, "Failed to register interrupt\n");
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
error = input_register_device(input_dev);
|
||||
if (error)
|
||||
goto err_free_irq;
|
||||
|
||||
i2c_set_clientdata(client, data);
|
||||
return 0;
|
||||
|
||||
err_free_irq:
|
||||
free_irq(client->irq, data);
|
||||
err_free_mem:
|
||||
input_free_device(input_dev);
|
||||
kfree(data);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int __devexit mcs_touchkey_remove(struct i2c_client *client)
|
||||
{
|
||||
struct mcs_touchkey_data *data = i2c_get_clientdata(client);
|
||||
|
||||
free_irq(client->irq, data);
|
||||
input_unregister_device(data->input_dev);
|
||||
kfree(data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id mcs_touchkey_id[] = {
|
||||
{ "mcs5000_touchkey", MCS5000_TOUCHKEY },
|
||||
{ "mcs5080_touchkey", MCS5080_TOUCHKEY },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, mcs_touchkey_id);
|
||||
|
||||
static struct i2c_driver mcs_touchkey_driver = {
|
||||
.driver = {
|
||||
.name = "mcs_touchkey",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = mcs_touchkey_probe,
|
||||
.remove = __devexit_p(mcs_touchkey_remove),
|
||||
.id_table = mcs_touchkey_id,
|
||||
};
|
||||
|
||||
static int __init mcs_touchkey_init(void)
|
||||
{
|
||||
return i2c_add_driver(&mcs_touchkey_driver);
|
||||
}
|
||||
|
||||
static void __exit mcs_touchkey_exit(void)
|
||||
{
|
||||
i2c_del_driver(&mcs_touchkey_driver);
|
||||
}
|
||||
|
||||
module_init(mcs_touchkey_init);
|
||||
module_exit(mcs_touchkey_exit);
|
||||
|
||||
/* Module information */
|
||||
MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
|
||||
MODULE_AUTHOR("HeungJun Kim <riverful.kim@samsung.com>");
|
||||
MODULE_DESCRIPTION("Touchkey driver for MELFAS MCS5000/5080 controller");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,491 @@
|
|||
/*
|
||||
* Samsung keypad driver
|
||||
*
|
||||
* Copyright (C) 2010 Samsung Electronics Co.Ltd
|
||||
* Author: Joonyoung Shim <jy0922.shim@samsung.com>
|
||||
* Author: Donghwa Lee <dh09.lee@samsung.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sched.h>
|
||||
#include <plat/keypad.h>
|
||||
|
||||
#define SAMSUNG_KEYIFCON 0x00
|
||||
#define SAMSUNG_KEYIFSTSCLR 0x04
|
||||
#define SAMSUNG_KEYIFCOL 0x08
|
||||
#define SAMSUNG_KEYIFROW 0x0c
|
||||
#define SAMSUNG_KEYIFFC 0x10
|
||||
|
||||
/* SAMSUNG_KEYIFCON */
|
||||
#define SAMSUNG_KEYIFCON_INT_F_EN (1 << 0)
|
||||
#define SAMSUNG_KEYIFCON_INT_R_EN (1 << 1)
|
||||
#define SAMSUNG_KEYIFCON_DF_EN (1 << 2)
|
||||
#define SAMSUNG_KEYIFCON_FC_EN (1 << 3)
|
||||
#define SAMSUNG_KEYIFCON_WAKEUPEN (1 << 4)
|
||||
|
||||
/* SAMSUNG_KEYIFSTSCLR */
|
||||
#define SAMSUNG_KEYIFSTSCLR_P_INT_MASK (0xff << 0)
|
||||
#define SAMSUNG_KEYIFSTSCLR_R_INT_MASK (0xff << 8)
|
||||
#define SAMSUNG_KEYIFSTSCLR_R_INT_OFFSET 8
|
||||
#define S5PV210_KEYIFSTSCLR_P_INT_MASK (0x3fff << 0)
|
||||
#define S5PV210_KEYIFSTSCLR_R_INT_MASK (0x3fff << 16)
|
||||
#define S5PV210_KEYIFSTSCLR_R_INT_OFFSET 16
|
||||
|
||||
/* SAMSUNG_KEYIFCOL */
|
||||
#define SAMSUNG_KEYIFCOL_MASK (0xff << 0)
|
||||
#define S5PV210_KEYIFCOLEN_MASK (0xff << 8)
|
||||
|
||||
/* SAMSUNG_KEYIFROW */
|
||||
#define SAMSUNG_KEYIFROW_MASK (0xff << 0)
|
||||
#define S5PV210_KEYIFROW_MASK (0x3fff << 0)
|
||||
|
||||
/* SAMSUNG_KEYIFFC */
|
||||
#define SAMSUNG_KEYIFFC_MASK (0x3ff << 0)
|
||||
|
||||
enum samsung_keypad_type {
|
||||
KEYPAD_TYPE_SAMSUNG,
|
||||
KEYPAD_TYPE_S5PV210,
|
||||
};
|
||||
|
||||
struct samsung_keypad {
|
||||
struct input_dev *input_dev;
|
||||
struct clk *clk;
|
||||
void __iomem *base;
|
||||
wait_queue_head_t wait;
|
||||
bool stopped;
|
||||
int irq;
|
||||
unsigned int row_shift;
|
||||
unsigned int rows;
|
||||
unsigned int cols;
|
||||
unsigned int row_state[SAMSUNG_MAX_COLS];
|
||||
unsigned short keycodes[];
|
||||
};
|
||||
|
||||
static int samsung_keypad_is_s5pv210(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
enum samsung_keypad_type type =
|
||||
platform_get_device_id(pdev)->driver_data;
|
||||
|
||||
return type == KEYPAD_TYPE_S5PV210;
|
||||
}
|
||||
|
||||
static void samsung_keypad_scan(struct samsung_keypad *keypad,
|
||||
unsigned int *row_state)
|
||||
{
|
||||
struct device *dev = keypad->input_dev->dev.parent;
|
||||
unsigned int col;
|
||||
unsigned int val;
|
||||
|
||||
for (col = 0; col < keypad->cols; col++) {
|
||||
if (samsung_keypad_is_s5pv210(dev)) {
|
||||
val = S5PV210_KEYIFCOLEN_MASK;
|
||||
val &= ~(1 << col) << 8;
|
||||
} else {
|
||||
val = SAMSUNG_KEYIFCOL_MASK;
|
||||
val &= ~(1 << col);
|
||||
}
|
||||
|
||||
writel(val, keypad->base + SAMSUNG_KEYIFCOL);
|
||||
mdelay(1);
|
||||
|
||||
val = readl(keypad->base + SAMSUNG_KEYIFROW);
|
||||
row_state[col] = ~val & ((1 << keypad->rows) - 1);
|
||||
}
|
||||
|
||||
/* KEYIFCOL reg clear */
|
||||
writel(0, keypad->base + SAMSUNG_KEYIFCOL);
|
||||
}
|
||||
|
||||
static bool samsung_keypad_report(struct samsung_keypad *keypad,
|
||||
unsigned int *row_state)
|
||||
{
|
||||
struct input_dev *input_dev = keypad->input_dev;
|
||||
unsigned int changed;
|
||||
unsigned int pressed;
|
||||
unsigned int key_down = 0;
|
||||
unsigned int val;
|
||||
unsigned int col, row;
|
||||
|
||||
for (col = 0; col < keypad->cols; col++) {
|
||||
changed = row_state[col] ^ keypad->row_state[col];
|
||||
key_down |= row_state[col];
|
||||
if (!changed)
|
||||
continue;
|
||||
|
||||
for (row = 0; row < keypad->rows; row++) {
|
||||
if (!(changed & (1 << row)))
|
||||
continue;
|
||||
|
||||
pressed = row_state[col] & (1 << row);
|
||||
|
||||
dev_dbg(&keypad->input_dev->dev,
|
||||
"key %s, row: %d, col: %d\n",
|
||||
pressed ? "pressed" : "released", row, col);
|
||||
|
||||
val = MATRIX_SCAN_CODE(row, col, keypad->row_shift);
|
||||
|
||||
input_event(input_dev, EV_MSC, MSC_SCAN, val);
|
||||
input_report_key(input_dev,
|
||||
keypad->keycodes[val], pressed);
|
||||
}
|
||||
input_sync(keypad->input_dev);
|
||||
}
|
||||
|
||||
memcpy(keypad->row_state, row_state, sizeof(keypad->row_state));
|
||||
|
||||
return key_down;
|
||||
}
|
||||
|
||||
static irqreturn_t samsung_keypad_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct samsung_keypad *keypad = dev_id;
|
||||
unsigned int row_state[SAMSUNG_MAX_COLS];
|
||||
unsigned int val;
|
||||
bool key_down;
|
||||
|
||||
do {
|
||||
val = readl(keypad->base + SAMSUNG_KEYIFSTSCLR);
|
||||
/* Clear interrupt. */
|
||||
writel(~0x0, keypad->base + SAMSUNG_KEYIFSTSCLR);
|
||||
|
||||
samsung_keypad_scan(keypad, row_state);
|
||||
|
||||
key_down = samsung_keypad_report(keypad, row_state);
|
||||
if (key_down)
|
||||
wait_event_timeout(keypad->wait, keypad->stopped,
|
||||
msecs_to_jiffies(50));
|
||||
|
||||
} while (key_down && !keypad->stopped);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void samsung_keypad_start(struct samsung_keypad *keypad)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
/* Tell IRQ thread that it may poll the device. */
|
||||
keypad->stopped = false;
|
||||
|
||||
clk_enable(keypad->clk);
|
||||
|
||||
/* Enable interrupt bits. */
|
||||
val = readl(keypad->base + SAMSUNG_KEYIFCON);
|
||||
val |= SAMSUNG_KEYIFCON_INT_F_EN | SAMSUNG_KEYIFCON_INT_R_EN;
|
||||
writel(val, keypad->base + SAMSUNG_KEYIFCON);
|
||||
|
||||
/* KEYIFCOL reg clear. */
|
||||
writel(0, keypad->base + SAMSUNG_KEYIFCOL);
|
||||
}
|
||||
|
||||
static void samsung_keypad_stop(struct samsung_keypad *keypad)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
/* Signal IRQ thread to stop polling and disable the handler. */
|
||||
keypad->stopped = true;
|
||||
wake_up(&keypad->wait);
|
||||
disable_irq(keypad->irq);
|
||||
|
||||
/* Clear interrupt. */
|
||||
writel(~0x0, keypad->base + SAMSUNG_KEYIFSTSCLR);
|
||||
|
||||
/* Disable interrupt bits. */
|
||||
val = readl(keypad->base + SAMSUNG_KEYIFCON);
|
||||
val &= ~(SAMSUNG_KEYIFCON_INT_F_EN | SAMSUNG_KEYIFCON_INT_R_EN);
|
||||
writel(val, keypad->base + SAMSUNG_KEYIFCON);
|
||||
|
||||
clk_disable(keypad->clk);
|
||||
|
||||
/*
|
||||
* Now that chip should not generate interrupts we can safely
|
||||
* re-enable the handler.
|
||||
*/
|
||||
enable_irq(keypad->irq);
|
||||
}
|
||||
|
||||
static int samsung_keypad_open(struct input_dev *input_dev)
|
||||
{
|
||||
struct samsung_keypad *keypad = input_get_drvdata(input_dev);
|
||||
|
||||
samsung_keypad_start(keypad);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void samsung_keypad_close(struct input_dev *input_dev)
|
||||
{
|
||||
struct samsung_keypad *keypad = input_get_drvdata(input_dev);
|
||||
|
||||
samsung_keypad_stop(keypad);
|
||||
}
|
||||
|
||||
static int __devinit samsung_keypad_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct samsung_keypad_platdata *pdata;
|
||||
const struct matrix_keymap_data *keymap_data;
|
||||
struct samsung_keypad *keypad;
|
||||
struct resource *res;
|
||||
struct input_dev *input_dev;
|
||||
unsigned int row_shift;
|
||||
unsigned int keymap_size;
|
||||
int error;
|
||||
|
||||
pdata = pdev->dev.platform_data;
|
||||
if (!pdata) {
|
||||
dev_err(&pdev->dev, "no platform data defined\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
keymap_data = pdata->keymap_data;
|
||||
if (!keymap_data) {
|
||||
dev_err(&pdev->dev, "no keymap data defined\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!pdata->rows || pdata->rows > SAMSUNG_MAX_ROWS)
|
||||
return -EINVAL;
|
||||
|
||||
if (!pdata->cols || pdata->cols > SAMSUNG_MAX_COLS)
|
||||
return -EINVAL;
|
||||
|
||||
/* initialize the gpio */
|
||||
if (pdata->cfg_gpio)
|
||||
pdata->cfg_gpio(pdata->rows, pdata->cols);
|
||||
|
||||
row_shift = get_count_order(pdata->cols);
|
||||
keymap_size = (pdata->rows << row_shift) * sizeof(keypad->keycodes[0]);
|
||||
|
||||
keypad = kzalloc(sizeof(*keypad) + keymap_size, GFP_KERNEL);
|
||||
input_dev = input_allocate_device();
|
||||
if (!keypad || !input_dev) {
|
||||
error = -ENOMEM;
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
error = -ENODEV;
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
keypad->base = ioremap(res->start, resource_size(res));
|
||||
if (!keypad->base) {
|
||||
error = -EBUSY;
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
keypad->clk = clk_get(&pdev->dev, "keypad");
|
||||
if (IS_ERR(keypad->clk)) {
|
||||
dev_err(&pdev->dev, "failed to get keypad clk\n");
|
||||
error = PTR_ERR(keypad->clk);
|
||||
goto err_unmap_base;
|
||||
}
|
||||
|
||||
keypad->input_dev = input_dev;
|
||||
keypad->row_shift = row_shift;
|
||||
keypad->rows = pdata->rows;
|
||||
keypad->cols = pdata->cols;
|
||||
init_waitqueue_head(&keypad->wait);
|
||||
|
||||
input_dev->name = pdev->name;
|
||||
input_dev->id.bustype = BUS_HOST;
|
||||
input_dev->dev.parent = &pdev->dev;
|
||||
input_set_drvdata(input_dev, keypad);
|
||||
|
||||
input_dev->open = samsung_keypad_open;
|
||||
input_dev->close = samsung_keypad_close;
|
||||
|
||||
input_dev->evbit[0] = BIT_MASK(EV_KEY);
|
||||
if (!pdata->no_autorepeat)
|
||||
input_dev->evbit[0] |= BIT_MASK(EV_REP);
|
||||
|
||||
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
|
||||
|
||||
input_dev->keycode = keypad->keycodes;
|
||||
input_dev->keycodesize = sizeof(keypad->keycodes[0]);
|
||||
input_dev->keycodemax = pdata->rows << row_shift;
|
||||
|
||||
matrix_keypad_build_keymap(keymap_data, row_shift,
|
||||
input_dev->keycode, input_dev->keybit);
|
||||
|
||||
keypad->irq = platform_get_irq(pdev, 0);
|
||||
if (keypad->irq < 0) {
|
||||
error = keypad->irq;
|
||||
goto err_put_clk;
|
||||
}
|
||||
|
||||
error = request_threaded_irq(keypad->irq, NULL, samsung_keypad_irq,
|
||||
IRQF_ONESHOT, dev_name(&pdev->dev), keypad);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "failed to register keypad interrupt\n");
|
||||
goto err_put_clk;
|
||||
}
|
||||
|
||||
error = input_register_device(keypad->input_dev);
|
||||
if (error)
|
||||
goto err_free_irq;
|
||||
|
||||
device_init_wakeup(&pdev->dev, pdata->wakeup);
|
||||
platform_set_drvdata(pdev, keypad);
|
||||
return 0;
|
||||
|
||||
err_free_irq:
|
||||
free_irq(keypad->irq, keypad);
|
||||
err_put_clk:
|
||||
clk_put(keypad->clk);
|
||||
err_unmap_base:
|
||||
iounmap(keypad->base);
|
||||
err_free_mem:
|
||||
input_free_device(input_dev);
|
||||
kfree(keypad);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int __devexit samsung_keypad_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct samsung_keypad *keypad = platform_get_drvdata(pdev);
|
||||
|
||||
device_init_wakeup(&pdev->dev, 0);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
input_unregister_device(keypad->input_dev);
|
||||
|
||||
/*
|
||||
* It is safe to free IRQ after unregistering device because
|
||||
* samsung_keypad_close will shut off interrupts.
|
||||
*/
|
||||
free_irq(keypad->irq, keypad);
|
||||
|
||||
clk_put(keypad->clk);
|
||||
|
||||
iounmap(keypad->base);
|
||||
kfree(keypad);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static void samsung_keypad_toggle_wakeup(struct samsung_keypad *keypad,
|
||||
bool enable)
|
||||
{
|
||||
struct device *dev = keypad->input_dev->dev.parent;
|
||||
unsigned int val;
|
||||
|
||||
clk_enable(keypad->clk);
|
||||
|
||||
val = readl(keypad->base + SAMSUNG_KEYIFCON);
|
||||
if (enable) {
|
||||
val |= SAMSUNG_KEYIFCON_WAKEUPEN;
|
||||
if (device_may_wakeup(dev))
|
||||
enable_irq_wake(keypad->irq);
|
||||
} else {
|
||||
val &= ~SAMSUNG_KEYIFCON_WAKEUPEN;
|
||||
if (device_may_wakeup(dev))
|
||||
disable_irq_wake(keypad->irq);
|
||||
}
|
||||
writel(val, keypad->base + SAMSUNG_KEYIFCON);
|
||||
|
||||
clk_disable(keypad->clk);
|
||||
}
|
||||
|
||||
static int samsung_keypad_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct samsung_keypad *keypad = platform_get_drvdata(pdev);
|
||||
struct input_dev *input_dev = keypad->input_dev;
|
||||
|
||||
mutex_lock(&input_dev->mutex);
|
||||
|
||||
if (input_dev->users)
|
||||
samsung_keypad_stop(keypad);
|
||||
|
||||
samsung_keypad_toggle_wakeup(keypad, true);
|
||||
|
||||
mutex_unlock(&input_dev->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int samsung_keypad_resume(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct samsung_keypad *keypad = platform_get_drvdata(pdev);
|
||||
struct input_dev *input_dev = keypad->input_dev;
|
||||
|
||||
mutex_lock(&input_dev->mutex);
|
||||
|
||||
samsung_keypad_toggle_wakeup(keypad, false);
|
||||
|
||||
if (input_dev->users)
|
||||
samsung_keypad_start(keypad);
|
||||
|
||||
mutex_unlock(&input_dev->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops samsung_keypad_pm_ops = {
|
||||
.suspend = samsung_keypad_suspend,
|
||||
.resume = samsung_keypad_resume,
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct platform_device_id samsung_keypad_driver_ids[] = {
|
||||
{
|
||||
.name = "samsung-keypad",
|
||||
.driver_data = KEYPAD_TYPE_SAMSUNG,
|
||||
}, {
|
||||
.name = "s5pv210-keypad",
|
||||
.driver_data = KEYPAD_TYPE_S5PV210,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, samsung_keypad_driver_ids);
|
||||
|
||||
static struct platform_driver samsung_keypad_driver = {
|
||||
.probe = samsung_keypad_probe,
|
||||
.remove = __devexit_p(samsung_keypad_remove),
|
||||
.driver = {
|
||||
.name = "samsung-keypad",
|
||||
.owner = THIS_MODULE,
|
||||
#ifdef CONFIG_PM
|
||||
.pm = &samsung_keypad_pm_ops,
|
||||
#endif
|
||||
},
|
||||
.id_table = samsung_keypad_driver_ids,
|
||||
};
|
||||
|
||||
static int __init samsung_keypad_init(void)
|
||||
{
|
||||
return platform_driver_register(&samsung_keypad_driver);
|
||||
}
|
||||
module_init(samsung_keypad_init);
|
||||
|
||||
static void __exit samsung_keypad_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&samsung_keypad_driver);
|
||||
}
|
||||
module_exit(samsung_keypad_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Samsung keypad driver");
|
||||
MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
|
||||
MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:samsung-keypad");
|
|
@ -327,6 +327,17 @@ config INPUT_PCF8574
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called pcf8574_keypad.
|
||||
|
||||
config INPUT_PWM_BEEPER
|
||||
tristate "PWM beeper support"
|
||||
depends on HAVE_PWM
|
||||
help
|
||||
Say Y here to get support for PWM based beeper devices.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called pwm-beeper.
|
||||
|
||||
config INPUT_GPIO_ROTARY_ENCODER
|
||||
tristate "Rotary encoders connected to GPIO pins"
|
||||
depends on GPIOLIB && GENERIC_GPIO
|
||||
|
@ -390,4 +401,41 @@ config INPUT_PCAP
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called pcap_keys.
|
||||
|
||||
config INPUT_ADXL34X
|
||||
tristate "Analog Devices ADXL34x Three-Axis Digital Accelerometer"
|
||||
default n
|
||||
help
|
||||
Say Y here if you have a Accelerometer interface using the
|
||||
ADXL345/6 controller, and your board-specific initialization
|
||||
code includes that in its table of devices.
|
||||
|
||||
This driver can use either I2C or SPI communication to the
|
||||
ADXL345/6 controller. Select the appropriate method for
|
||||
your system.
|
||||
|
||||
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 adxl34x.
|
||||
|
||||
config INPUT_ADXL34X_I2C
|
||||
tristate "support I2C bus connection"
|
||||
depends on INPUT_ADXL34X && I2C
|
||||
default y
|
||||
help
|
||||
Say Y here if you have ADXL345/6 hooked to an I2C bus.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called adxl34x-i2c.
|
||||
|
||||
config INPUT_ADXL34X_SPI
|
||||
tristate "support SPI bus connection"
|
||||
depends on INPUT_ADXL34X && SPI
|
||||
default y
|
||||
help
|
||||
Say Y here if you have ADXL345/6 hooked to a SPI bus.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called adxl34x-spi.
|
||||
|
||||
endif
|
||||
|
|
|
@ -8,6 +8,9 @@ obj-$(CONFIG_INPUT_88PM860X_ONKEY) += 88pm860x_onkey.o
|
|||
obj-$(CONFIG_INPUT_AD714X) += ad714x.o
|
||||
obj-$(CONFIG_INPUT_AD714X_I2C) += ad714x-i2c.o
|
||||
obj-$(CONFIG_INPUT_AD714X_SPI) += ad714x-spi.o
|
||||
obj-$(CONFIG_INPUT_ADXL34X) += adxl34x.o
|
||||
obj-$(CONFIG_INPUT_ADXL34X_I2C) += adxl34x-i2c.o
|
||||
obj-$(CONFIG_INPUT_ADXL34X_SPI) += adxl34x-spi.o
|
||||
obj-$(CONFIG_INPUT_APANEL) += apanel.o
|
||||
obj-$(CONFIG_INPUT_ATI_REMOTE) += ati_remote.o
|
||||
obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o
|
||||
|
@ -26,6 +29,7 @@ obj-$(CONFIG_INPUT_PCF50633_PMU) += pcf50633-input.o
|
|||
obj-$(CONFIG_INPUT_PCF8574) += pcf8574_keypad.o
|
||||
obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o
|
||||
obj-$(CONFIG_INPUT_POWERMATE) += powermate.o
|
||||
obj-$(CONFIG_INPUT_PWM_BEEPER) += pwm-beeper.o
|
||||
obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o
|
||||
obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o
|
||||
obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o
|
||||
|
|
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
* ADLX345/346 Three-Axis Digital Accelerometers (I2C Interface)
|
||||
*
|
||||
* Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* Copyright (C) 2009 Michael Hennerich, Analog Devices Inc.
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/input.h> /* BUS_I2C */
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include "adxl34x.h"
|
||||
|
||||
static int adxl34x_smbus_read(struct device *dev, unsigned char reg)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
|
||||
return i2c_smbus_read_byte_data(client, reg);
|
||||
}
|
||||
|
||||
static int adxl34x_smbus_write(struct device *dev,
|
||||
unsigned char reg, unsigned char val)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
|
||||
return i2c_smbus_write_byte_data(client, reg, val);
|
||||
}
|
||||
|
||||
static int adxl34x_smbus_read_block(struct device *dev,
|
||||
unsigned char reg, int count,
|
||||
void *buf)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
|
||||
return i2c_smbus_read_i2c_block_data(client, reg, count, buf);
|
||||
}
|
||||
|
||||
static int adxl34x_i2c_read_block(struct device *dev,
|
||||
unsigned char reg, int count,
|
||||
void *buf)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
int ret;
|
||||
|
||||
ret = i2c_master_send(client, ®, 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = i2c_master_recv(client, buf, count);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (ret != count)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct adxl34x_bus_ops adxl34x_smbus_bops = {
|
||||
.bustype = BUS_I2C,
|
||||
.write = adxl34x_smbus_write,
|
||||
.read = adxl34x_smbus_read,
|
||||
.read_block = adxl34x_smbus_read_block,
|
||||
};
|
||||
|
||||
static const struct adxl34x_bus_ops adxl34x_i2c_bops = {
|
||||
.bustype = BUS_I2C,
|
||||
.write = adxl34x_smbus_write,
|
||||
.read = adxl34x_smbus_read,
|
||||
.read_block = adxl34x_i2c_read_block,
|
||||
};
|
||||
|
||||
static int __devinit adxl34x_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct adxl34x *ac;
|
||||
int error;
|
||||
|
||||
error = i2c_check_functionality(client->adapter,
|
||||
I2C_FUNC_SMBUS_BYTE_DATA);
|
||||
if (!error) {
|
||||
dev_err(&client->dev, "SMBUS Byte Data not Supported\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ac = adxl34x_probe(&client->dev, client->irq, false,
|
||||
i2c_check_functionality(client->adapter,
|
||||
I2C_FUNC_SMBUS_READ_I2C_BLOCK) ?
|
||||
&adxl34x_smbus_bops : &adxl34x_i2c_bops);
|
||||
if (IS_ERR(ac))
|
||||
return PTR_ERR(ac);
|
||||
|
||||
i2c_set_clientdata(client, ac);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devexit adxl34x_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
struct adxl34x *ac = i2c_get_clientdata(client);
|
||||
|
||||
return adxl34x_remove(ac);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int adxl34x_i2c_suspend(struct i2c_client *client, pm_message_t message)
|
||||
{
|
||||
struct adxl34x *ac = i2c_get_clientdata(client);
|
||||
|
||||
adxl34x_suspend(ac);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adxl34x_i2c_resume(struct i2c_client *client)
|
||||
{
|
||||
struct adxl34x *ac = i2c_get_clientdata(client);
|
||||
|
||||
adxl34x_resume(ac);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
# define adxl34x_i2c_suspend NULL
|
||||
# define adxl34x_i2c_resume NULL
|
||||
#endif
|
||||
|
||||
static const struct i2c_device_id adxl34x_id[] = {
|
||||
{ "adxl34x", 0 },
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, adxl34x_id);
|
||||
|
||||
static struct i2c_driver adxl34x_driver = {
|
||||
.driver = {
|
||||
.name = "adxl34x",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = adxl34x_i2c_probe,
|
||||
.remove = __devexit_p(adxl34x_i2c_remove),
|
||||
.suspend = adxl34x_i2c_suspend,
|
||||
.resume = adxl34x_i2c_resume,
|
||||
.id_table = adxl34x_id,
|
||||
};
|
||||
|
||||
static int __init adxl34x_i2c_init(void)
|
||||
{
|
||||
return i2c_add_driver(&adxl34x_driver);
|
||||
}
|
||||
module_init(adxl34x_i2c_init);
|
||||
|
||||
static void __exit adxl34x_i2c_exit(void)
|
||||
{
|
||||
i2c_del_driver(&adxl34x_driver);
|
||||
}
|
||||
module_exit(adxl34x_i2c_exit);
|
||||
|
||||
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
|
||||
MODULE_DESCRIPTION("ADXL345/346 Three-Axis Digital Accelerometer I2C Bus Driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* ADLX345/346 Three-Axis Digital Accelerometers (SPI Interface)
|
||||
*
|
||||
* Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* Copyright (C) 2009 Michael Hennerich, Analog Devices Inc.
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/input.h> /* BUS_SPI */
|
||||
#include <linux/module.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/types.h>
|
||||
#include "adxl34x.h"
|
||||
|
||||
#define MAX_SPI_FREQ_HZ 5000000
|
||||
#define MAX_FREQ_NO_FIFODELAY 1500000
|
||||
#define ADXL34X_CMD_MULTB (1 << 6)
|
||||
#define ADXL34X_CMD_READ (1 << 7)
|
||||
#define ADXL34X_WRITECMD(reg) (reg & 0x3F)
|
||||
#define ADXL34X_READCMD(reg) (ADXL34X_CMD_READ | (reg & 0x3F))
|
||||
#define ADXL34X_READMB_CMD(reg) (ADXL34X_CMD_READ | ADXL34X_CMD_MULTB \
|
||||
| (reg & 0x3F))
|
||||
|
||||
static int adxl34x_spi_read(struct device *dev, unsigned char reg)
|
||||
{
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
unsigned char cmd;
|
||||
|
||||
cmd = ADXL34X_READCMD(reg);
|
||||
|
||||
return spi_w8r8(spi, cmd);
|
||||
}
|
||||
|
||||
static int adxl34x_spi_write(struct device *dev,
|
||||
unsigned char reg, unsigned char val)
|
||||
{
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
unsigned char buf[2];
|
||||
|
||||
buf[0] = ADXL34X_WRITECMD(reg);
|
||||
buf[1] = val;
|
||||
|
||||
return spi_write(spi, buf, sizeof(buf));
|
||||
}
|
||||
|
||||
static int adxl34x_spi_read_block(struct device *dev,
|
||||
unsigned char reg, int count,
|
||||
void *buf)
|
||||
{
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
ssize_t status;
|
||||
|
||||
reg = ADXL34X_READMB_CMD(reg);
|
||||
status = spi_write_then_read(spi, ®, 1, buf, count);
|
||||
|
||||
return (status < 0) ? status : 0;
|
||||
}
|
||||
|
||||
static const struct adxl34x_bus_ops adx134x_spi_bops = {
|
||||
.bustype = BUS_SPI,
|
||||
.write = adxl34x_spi_write,
|
||||
.read = adxl34x_spi_read,
|
||||
.read_block = adxl34x_spi_read_block,
|
||||
};
|
||||
|
||||
static int __devinit adxl34x_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
struct adxl34x *ac;
|
||||
|
||||
/* don't exceed max specified SPI CLK frequency */
|
||||
if (spi->max_speed_hz > MAX_SPI_FREQ_HZ) {
|
||||
dev_err(&spi->dev, "SPI CLK %d Hz too fast\n", spi->max_speed_hz);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ac = adxl34x_probe(&spi->dev, spi->irq,
|
||||
spi->max_speed_hz > MAX_FREQ_NO_FIFODELAY,
|
||||
&adx134x_spi_bops);
|
||||
|
||||
if (IS_ERR(ac))
|
||||
return PTR_ERR(ac);
|
||||
|
||||
spi_set_drvdata(spi, ac);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devexit adxl34x_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
struct adxl34x *ac = dev_get_drvdata(&spi->dev);
|
||||
|
||||
return adxl34x_remove(ac);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int adxl34x_spi_suspend(struct spi_device *spi, pm_message_t message)
|
||||
{
|
||||
struct adxl34x *ac = dev_get_drvdata(&spi->dev);
|
||||
|
||||
adxl34x_suspend(ac);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adxl34x_spi_resume(struct spi_device *spi)
|
||||
{
|
||||
struct adxl34x *ac = dev_get_drvdata(&spi->dev);
|
||||
|
||||
adxl34x_resume(ac);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
# define adxl34x_spi_suspend NULL
|
||||
# define adxl34x_spi_resume NULL
|
||||
#endif
|
||||
|
||||
static struct spi_driver adxl34x_driver = {
|
||||
.driver = {
|
||||
.name = "adxl34x",
|
||||
.bus = &spi_bus_type,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = adxl34x_spi_probe,
|
||||
.remove = __devexit_p(adxl34x_spi_remove),
|
||||
.suspend = adxl34x_spi_suspend,
|
||||
.resume = adxl34x_spi_resume,
|
||||
};
|
||||
|
||||
static int __init adxl34x_spi_init(void)
|
||||
{
|
||||
return spi_register_driver(&adxl34x_driver);
|
||||
}
|
||||
module_init(adxl34x_spi_init);
|
||||
|
||||
static void __exit adxl34x_spi_exit(void)
|
||||
{
|
||||
spi_unregister_driver(&adxl34x_driver);
|
||||
}
|
||||
module_exit(adxl34x_spi_exit);
|
||||
|
||||
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
|
||||
MODULE_DESCRIPTION("ADXL345/346 Three-Axis Digital Accelerometer SPI Bus Driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,915 @@
|
|||
/*
|
||||
* ADXL345/346 Three-Axis Digital Accelerometers
|
||||
*
|
||||
* Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* Copyright (C) 2009 Michael Hennerich, Analog Devices Inc.
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/input/adxl34x.h>
|
||||
|
||||
#include "adxl34x.h"
|
||||
|
||||
/* ADXL345/6 Register Map */
|
||||
#define DEVID 0x00 /* R Device ID */
|
||||
#define THRESH_TAP 0x1D /* R/W Tap threshold */
|
||||
#define OFSX 0x1E /* R/W X-axis offset */
|
||||
#define OFSY 0x1F /* R/W Y-axis offset */
|
||||
#define OFSZ 0x20 /* R/W Z-axis offset */
|
||||
#define DUR 0x21 /* R/W Tap duration */
|
||||
#define LATENT 0x22 /* R/W Tap latency */
|
||||
#define WINDOW 0x23 /* R/W Tap window */
|
||||
#define THRESH_ACT 0x24 /* R/W Activity threshold */
|
||||
#define THRESH_INACT 0x25 /* R/W Inactivity threshold */
|
||||
#define TIME_INACT 0x26 /* R/W Inactivity time */
|
||||
#define ACT_INACT_CTL 0x27 /* R/W Axis enable control for activity and */
|
||||
/* inactivity detection */
|
||||
#define THRESH_FF 0x28 /* R/W Free-fall threshold */
|
||||
#define TIME_FF 0x29 /* R/W Free-fall time */
|
||||
#define TAP_AXES 0x2A /* R/W Axis control for tap/double tap */
|
||||
#define ACT_TAP_STATUS 0x2B /* R Source of tap/double tap */
|
||||
#define BW_RATE 0x2C /* R/W Data rate and power mode control */
|
||||
#define POWER_CTL 0x2D /* R/W Power saving features control */
|
||||
#define INT_ENABLE 0x2E /* R/W Interrupt enable control */
|
||||
#define INT_MAP 0x2F /* R/W Interrupt mapping control */
|
||||
#define INT_SOURCE 0x30 /* R Source of interrupts */
|
||||
#define DATA_FORMAT 0x31 /* R/W Data format control */
|
||||
#define DATAX0 0x32 /* R X-Axis Data 0 */
|
||||
#define DATAX1 0x33 /* R X-Axis Data 1 */
|
||||
#define DATAY0 0x34 /* R Y-Axis Data 0 */
|
||||
#define DATAY1 0x35 /* R Y-Axis Data 1 */
|
||||
#define DATAZ0 0x36 /* R Z-Axis Data 0 */
|
||||
#define DATAZ1 0x37 /* R Z-Axis Data 1 */
|
||||
#define FIFO_CTL 0x38 /* R/W FIFO control */
|
||||
#define FIFO_STATUS 0x39 /* R FIFO status */
|
||||
#define TAP_SIGN 0x3A /* R Sign and source for tap/double tap */
|
||||
/* Orientation ADXL346 only */
|
||||
#define ORIENT_CONF 0x3B /* R/W Orientation configuration */
|
||||
#define ORIENT 0x3C /* R Orientation status */
|
||||
|
||||
/* DEVIDs */
|
||||
#define ID_ADXL345 0xE5
|
||||
#define ID_ADXL346 0xE6
|
||||
|
||||
/* INT_ENABLE/INT_MAP/INT_SOURCE Bits */
|
||||
#define DATA_READY (1 << 7)
|
||||
#define SINGLE_TAP (1 << 6)
|
||||
#define DOUBLE_TAP (1 << 5)
|
||||
#define ACTIVITY (1 << 4)
|
||||
#define INACTIVITY (1 << 3)
|
||||
#define FREE_FALL (1 << 2)
|
||||
#define WATERMARK (1 << 1)
|
||||
#define OVERRUN (1 << 0)
|
||||
|
||||
/* ACT_INACT_CONTROL Bits */
|
||||
#define ACT_ACDC (1 << 7)
|
||||
#define ACT_X_EN (1 << 6)
|
||||
#define ACT_Y_EN (1 << 5)
|
||||
#define ACT_Z_EN (1 << 4)
|
||||
#define INACT_ACDC (1 << 3)
|
||||
#define INACT_X_EN (1 << 2)
|
||||
#define INACT_Y_EN (1 << 1)
|
||||
#define INACT_Z_EN (1 << 0)
|
||||
|
||||
/* TAP_AXES Bits */
|
||||
#define SUPPRESS (1 << 3)
|
||||
#define TAP_X_EN (1 << 2)
|
||||
#define TAP_Y_EN (1 << 1)
|
||||
#define TAP_Z_EN (1 << 0)
|
||||
|
||||
/* ACT_TAP_STATUS Bits */
|
||||
#define ACT_X_SRC (1 << 6)
|
||||
#define ACT_Y_SRC (1 << 5)
|
||||
#define ACT_Z_SRC (1 << 4)
|
||||
#define ASLEEP (1 << 3)
|
||||
#define TAP_X_SRC (1 << 2)
|
||||
#define TAP_Y_SRC (1 << 1)
|
||||
#define TAP_Z_SRC (1 << 0)
|
||||
|
||||
/* BW_RATE Bits */
|
||||
#define LOW_POWER (1 << 4)
|
||||
#define RATE(x) ((x) & 0xF)
|
||||
|
||||
/* POWER_CTL Bits */
|
||||
#define PCTL_LINK (1 << 5)
|
||||
#define PCTL_AUTO_SLEEP (1 << 4)
|
||||
#define PCTL_MEASURE (1 << 3)
|
||||
#define PCTL_SLEEP (1 << 2)
|
||||
#define PCTL_WAKEUP(x) ((x) & 0x3)
|
||||
|
||||
/* DATA_FORMAT Bits */
|
||||
#define SELF_TEST (1 << 7)
|
||||
#define SPI (1 << 6)
|
||||
#define INT_INVERT (1 << 5)
|
||||
#define FULL_RES (1 << 3)
|
||||
#define JUSTIFY (1 << 2)
|
||||
#define RANGE(x) ((x) & 0x3)
|
||||
#define RANGE_PM_2g 0
|
||||
#define RANGE_PM_4g 1
|
||||
#define RANGE_PM_8g 2
|
||||
#define RANGE_PM_16g 3
|
||||
|
||||
/*
|
||||
* Maximum value our axis may get in full res mode for the input device
|
||||
* (signed 13 bits)
|
||||
*/
|
||||
#define ADXL_FULLRES_MAX_VAL 4096
|
||||
|
||||
/*
|
||||
* Maximum value our axis may get in fixed res mode for the input device
|
||||
* (signed 10 bits)
|
||||
*/
|
||||
#define ADXL_FIXEDRES_MAX_VAL 512
|
||||
|
||||
/* FIFO_CTL Bits */
|
||||
#define FIFO_MODE(x) (((x) & 0x3) << 6)
|
||||
#define FIFO_BYPASS 0
|
||||
#define FIFO_FIFO 1
|
||||
#define FIFO_STREAM 2
|
||||
#define FIFO_TRIGGER 3
|
||||
#define TRIGGER (1 << 5)
|
||||
#define SAMPLES(x) ((x) & 0x1F)
|
||||
|
||||
/* FIFO_STATUS Bits */
|
||||
#define FIFO_TRIG (1 << 7)
|
||||
#define ENTRIES(x) ((x) & 0x3F)
|
||||
|
||||
/* TAP_SIGN Bits ADXL346 only */
|
||||
#define XSIGN (1 << 6)
|
||||
#define YSIGN (1 << 5)
|
||||
#define ZSIGN (1 << 4)
|
||||
#define XTAP (1 << 3)
|
||||
#define YTAP (1 << 2)
|
||||
#define ZTAP (1 << 1)
|
||||
|
||||
/* ORIENT_CONF ADXL346 only */
|
||||
#define ORIENT_DEADZONE(x) (((x) & 0x7) << 4)
|
||||
#define ORIENT_DIVISOR(x) ((x) & 0x7)
|
||||
|
||||
/* ORIENT ADXL346 only */
|
||||
#define ADXL346_2D_VALID (1 << 6)
|
||||
#define ADXL346_2D_ORIENT(x) (((x) & 0x3) >> 4)
|
||||
#define ADXL346_3D_VALID (1 << 3)
|
||||
#define ADXL346_3D_ORIENT(x) ((x) & 0x7)
|
||||
#define ADXL346_2D_PORTRAIT_POS 0 /* +X */
|
||||
#define ADXL346_2D_PORTRAIT_NEG 1 /* -X */
|
||||
#define ADXL346_2D_LANDSCAPE_POS 2 /* +Y */
|
||||
#define ADXL346_2D_LANDSCAPE_NEG 3 /* -Y */
|
||||
|
||||
#define ADXL346_3D_FRONT 3 /* +X */
|
||||
#define ADXL346_3D_BACK 4 /* -X */
|
||||
#define ADXL346_3D_RIGHT 2 /* +Y */
|
||||
#define ADXL346_3D_LEFT 5 /* -Y */
|
||||
#define ADXL346_3D_TOP 1 /* +Z */
|
||||
#define ADXL346_3D_BOTTOM 6 /* -Z */
|
||||
|
||||
#undef ADXL_DEBUG
|
||||
|
||||
#define ADXL_X_AXIS 0
|
||||
#define ADXL_Y_AXIS 1
|
||||
#define ADXL_Z_AXIS 2
|
||||
|
||||
#define AC_READ(ac, reg) ((ac)->bops->read((ac)->dev, reg))
|
||||
#define AC_WRITE(ac, reg, val) ((ac)->bops->write((ac)->dev, reg, val))
|
||||
|
||||
struct axis_triple {
|
||||
int x;
|
||||
int y;
|
||||
int z;
|
||||
};
|
||||
|
||||
struct adxl34x {
|
||||
struct device *dev;
|
||||
struct input_dev *input;
|
||||
struct mutex mutex; /* reentrant protection for struct */
|
||||
struct adxl34x_platform_data pdata;
|
||||
struct axis_triple swcal;
|
||||
struct axis_triple hwcal;
|
||||
struct axis_triple saved;
|
||||
char phys[32];
|
||||
unsigned orient2d_saved;
|
||||
unsigned orient3d_saved;
|
||||
bool disabled; /* P: mutex */
|
||||
bool opened; /* P: mutex */
|
||||
bool suspended; /* P: mutex */
|
||||
bool fifo_delay;
|
||||
int irq;
|
||||
unsigned model;
|
||||
unsigned int_mask;
|
||||
|
||||
const struct adxl34x_bus_ops *bops;
|
||||
};
|
||||
|
||||
static const struct adxl34x_platform_data adxl34x_default_init = {
|
||||
.tap_threshold = 35,
|
||||
.tap_duration = 3,
|
||||
.tap_latency = 20,
|
||||
.tap_window = 20,
|
||||
.tap_axis_control = ADXL_TAP_X_EN | ADXL_TAP_Y_EN | ADXL_TAP_Z_EN,
|
||||
.act_axis_control = 0xFF,
|
||||
.activity_threshold = 6,
|
||||
.inactivity_threshold = 4,
|
||||
.inactivity_time = 3,
|
||||
.free_fall_threshold = 8,
|
||||
.free_fall_time = 0x20,
|
||||
.data_rate = 8,
|
||||
.data_range = ADXL_FULL_RES,
|
||||
|
||||
.ev_type = EV_ABS,
|
||||
.ev_code_x = ABS_X, /* EV_REL */
|
||||
.ev_code_y = ABS_Y, /* EV_REL */
|
||||
.ev_code_z = ABS_Z, /* EV_REL */
|
||||
|
||||
.ev_code_tap = {BTN_TOUCH, BTN_TOUCH, BTN_TOUCH}, /* EV_KEY {x,y,z} */
|
||||
.power_mode = ADXL_AUTO_SLEEP | ADXL_LINK,
|
||||
.fifo_mode = FIFO_STREAM,
|
||||
.watermark = 0,
|
||||
};
|
||||
|
||||
static void adxl34x_get_triple(struct adxl34x *ac, struct axis_triple *axis)
|
||||
{
|
||||
short buf[3];
|
||||
|
||||
ac->bops->read_block(ac->dev, DATAX0, DATAZ1 - DATAX0 + 1, buf);
|
||||
|
||||
mutex_lock(&ac->mutex);
|
||||
ac->saved.x = (s16) le16_to_cpu(buf[0]);
|
||||
axis->x = ac->saved.x;
|
||||
|
||||
ac->saved.y = (s16) le16_to_cpu(buf[1]);
|
||||
axis->y = ac->saved.y;
|
||||
|
||||
ac->saved.z = (s16) le16_to_cpu(buf[2]);
|
||||
axis->z = ac->saved.z;
|
||||
mutex_unlock(&ac->mutex);
|
||||
}
|
||||
|
||||
static void adxl34x_service_ev_fifo(struct adxl34x *ac)
|
||||
{
|
||||
struct adxl34x_platform_data *pdata = &ac->pdata;
|
||||
struct axis_triple axis;
|
||||
|
||||
adxl34x_get_triple(ac, &axis);
|
||||
|
||||
input_event(ac->input, pdata->ev_type, pdata->ev_code_x,
|
||||
axis.x - ac->swcal.x);
|
||||
input_event(ac->input, pdata->ev_type, pdata->ev_code_y,
|
||||
axis.y - ac->swcal.y);
|
||||
input_event(ac->input, pdata->ev_type, pdata->ev_code_z,
|
||||
axis.z - ac->swcal.z);
|
||||
}
|
||||
|
||||
static void adxl34x_report_key_single(struct input_dev *input, int key)
|
||||
{
|
||||
input_report_key(input, key, true);
|
||||
input_sync(input);
|
||||
input_report_key(input, key, false);
|
||||
}
|
||||
|
||||
static void adxl34x_send_key_events(struct adxl34x *ac,
|
||||
struct adxl34x_platform_data *pdata, int status, int press)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = ADXL_X_AXIS; i <= ADXL_Z_AXIS; i++) {
|
||||
if (status & (1 << (ADXL_Z_AXIS - i)))
|
||||
input_report_key(ac->input,
|
||||
pdata->ev_code_tap[i], press);
|
||||
}
|
||||
}
|
||||
|
||||
static void adxl34x_do_tap(struct adxl34x *ac,
|
||||
struct adxl34x_platform_data *pdata, int status)
|
||||
{
|
||||
adxl34x_send_key_events(ac, pdata, status, true);
|
||||
input_sync(ac->input);
|
||||
adxl34x_send_key_events(ac, pdata, status, false);
|
||||
}
|
||||
|
||||
static irqreturn_t adxl34x_irq(int irq, void *handle)
|
||||
{
|
||||
struct adxl34x *ac = handle;
|
||||
struct adxl34x_platform_data *pdata = &ac->pdata;
|
||||
int int_stat, tap_stat, samples, orient, orient_code;
|
||||
|
||||
/*
|
||||
* ACT_TAP_STATUS should be read before clearing the interrupt
|
||||
* Avoid reading ACT_TAP_STATUS in case TAP detection is disabled
|
||||
*/
|
||||
|
||||
if (pdata->tap_axis_control & (TAP_X_EN | TAP_Y_EN | TAP_Z_EN))
|
||||
tap_stat = AC_READ(ac, ACT_TAP_STATUS);
|
||||
else
|
||||
tap_stat = 0;
|
||||
|
||||
int_stat = AC_READ(ac, INT_SOURCE);
|
||||
|
||||
if (int_stat & FREE_FALL)
|
||||
adxl34x_report_key_single(ac->input, pdata->ev_code_ff);
|
||||
|
||||
if (int_stat & OVERRUN)
|
||||
dev_dbg(ac->dev, "OVERRUN\n");
|
||||
|
||||
if (int_stat & (SINGLE_TAP | DOUBLE_TAP)) {
|
||||
adxl34x_do_tap(ac, pdata, tap_stat);
|
||||
|
||||
if (int_stat & DOUBLE_TAP)
|
||||
adxl34x_do_tap(ac, pdata, tap_stat);
|
||||
}
|
||||
|
||||
if (pdata->ev_code_act_inactivity) {
|
||||
if (int_stat & ACTIVITY)
|
||||
input_report_key(ac->input,
|
||||
pdata->ev_code_act_inactivity, 1);
|
||||
if (int_stat & INACTIVITY)
|
||||
input_report_key(ac->input,
|
||||
pdata->ev_code_act_inactivity, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* ORIENTATION SENSING ADXL346 only
|
||||
*/
|
||||
if (pdata->orientation_enable) {
|
||||
orient = AC_READ(ac, ORIENT);
|
||||
if ((pdata->orientation_enable & ADXL_EN_ORIENTATION_2D) &&
|
||||
(orient & ADXL346_2D_VALID)) {
|
||||
|
||||
orient_code = ADXL346_2D_ORIENT(orient);
|
||||
/* Report orientation only when it changes */
|
||||
if (ac->orient2d_saved != orient_code) {
|
||||
ac->orient2d_saved = orient_code;
|
||||
adxl34x_report_key_single(ac->input,
|
||||
pdata->ev_codes_orient_2d[orient_code]);
|
||||
}
|
||||
}
|
||||
|
||||
if ((pdata->orientation_enable & ADXL_EN_ORIENTATION_3D) &&
|
||||
(orient & ADXL346_3D_VALID)) {
|
||||
|
||||
orient_code = ADXL346_3D_ORIENT(orient) - 1;
|
||||
/* Report orientation only when it changes */
|
||||
if (ac->orient3d_saved != orient_code) {
|
||||
ac->orient3d_saved = orient_code;
|
||||
adxl34x_report_key_single(ac->input,
|
||||
pdata->ev_codes_orient_3d[orient_code]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (int_stat & (DATA_READY | WATERMARK)) {
|
||||
|
||||
if (pdata->fifo_mode)
|
||||
samples = ENTRIES(AC_READ(ac, FIFO_STATUS)) + 1;
|
||||
else
|
||||
samples = 1;
|
||||
|
||||
for (; samples > 0; samples--) {
|
||||
adxl34x_service_ev_fifo(ac);
|
||||
/*
|
||||
* To ensure that the FIFO has
|
||||
* completely popped, there must be at least 5 us between
|
||||
* the end of reading the data registers, signified by the
|
||||
* transition to register 0x38 from 0x37 or the CS pin
|
||||
* going high, and the start of new reads of the FIFO or
|
||||
* reading the FIFO_STATUS register. For SPI operation at
|
||||
* 1.5 MHz or lower, the register addressing portion of the
|
||||
* transmission is sufficient delay to ensure the FIFO has
|
||||
* completely popped. It is necessary for SPI operation
|
||||
* greater than 1.5 MHz to de-assert the CS pin to ensure a
|
||||
* total of 5 us, which is at most 3.4 us at 5 MHz
|
||||
* operation.
|
||||
*/
|
||||
if (ac->fifo_delay && (samples > 1))
|
||||
udelay(3);
|
||||
}
|
||||
}
|
||||
|
||||
input_sync(ac->input);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void __adxl34x_disable(struct adxl34x *ac)
|
||||
{
|
||||
/*
|
||||
* A '0' places the ADXL34x into standby mode
|
||||
* with minimum power consumption.
|
||||
*/
|
||||
AC_WRITE(ac, POWER_CTL, 0);
|
||||
}
|
||||
|
||||
static void __adxl34x_enable(struct adxl34x *ac)
|
||||
{
|
||||
AC_WRITE(ac, POWER_CTL, ac->pdata.power_mode | PCTL_MEASURE);
|
||||
}
|
||||
|
||||
void adxl34x_suspend(struct adxl34x *ac)
|
||||
{
|
||||
mutex_lock(&ac->mutex);
|
||||
|
||||
if (!ac->suspended && !ac->disabled && ac->opened)
|
||||
__adxl34x_disable(ac);
|
||||
|
||||
ac->suspended = true;
|
||||
|
||||
mutex_unlock(&ac->mutex);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adxl34x_suspend);
|
||||
|
||||
void adxl34x_resume(struct adxl34x *ac)
|
||||
{
|
||||
mutex_lock(&ac->mutex);
|
||||
|
||||
if (ac->suspended && !ac->disabled && ac->opened)
|
||||
__adxl34x_enable(ac);
|
||||
|
||||
ac->suspended = false;
|
||||
|
||||
mutex_unlock(&ac->mutex);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adxl34x_resume);
|
||||
|
||||
static ssize_t adxl34x_disable_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct adxl34x *ac = dev_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%u\n", ac->disabled);
|
||||
}
|
||||
|
||||
static ssize_t adxl34x_disable_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct adxl34x *ac = dev_get_drvdata(dev);
|
||||
unsigned long val;
|
||||
int error;
|
||||
|
||||
error = strict_strtoul(buf, 10, &val);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
mutex_lock(&ac->mutex);
|
||||
|
||||
if (!ac->suspended && ac->opened) {
|
||||
if (val) {
|
||||
if (!ac->disabled)
|
||||
__adxl34x_disable(ac);
|
||||
} else {
|
||||
if (ac->disabled)
|
||||
__adxl34x_enable(ac);
|
||||
}
|
||||
}
|
||||
|
||||
ac->disabled = !!val;
|
||||
|
||||
mutex_unlock(&ac->mutex);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(disable, 0664, adxl34x_disable_show, adxl34x_disable_store);
|
||||
|
||||
static ssize_t adxl34x_calibrate_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct adxl34x *ac = dev_get_drvdata(dev);
|
||||
ssize_t count;
|
||||
|
||||
mutex_lock(&ac->mutex);
|
||||
count = sprintf(buf, "%d,%d,%d\n",
|
||||
ac->hwcal.x * 4 + ac->swcal.x,
|
||||
ac->hwcal.y * 4 + ac->swcal.y,
|
||||
ac->hwcal.z * 4 + ac->swcal.z);
|
||||
mutex_unlock(&ac->mutex);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t adxl34x_calibrate_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct adxl34x *ac = dev_get_drvdata(dev);
|
||||
|
||||
/*
|
||||
* Hardware offset calibration has a resolution of 15.6 mg/LSB.
|
||||
* We use HW calibration and handle the remaining bits in SW. (4mg/LSB)
|
||||
*/
|
||||
|
||||
mutex_lock(&ac->mutex);
|
||||
ac->hwcal.x -= (ac->saved.x / 4);
|
||||
ac->swcal.x = ac->saved.x % 4;
|
||||
|
||||
ac->hwcal.y -= (ac->saved.y / 4);
|
||||
ac->swcal.y = ac->saved.y % 4;
|
||||
|
||||
ac->hwcal.z -= (ac->saved.z / 4);
|
||||
ac->swcal.z = ac->saved.z % 4;
|
||||
|
||||
AC_WRITE(ac, OFSX, (s8) ac->hwcal.x);
|
||||
AC_WRITE(ac, OFSY, (s8) ac->hwcal.y);
|
||||
AC_WRITE(ac, OFSZ, (s8) ac->hwcal.z);
|
||||
mutex_unlock(&ac->mutex);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(calibrate, 0664,
|
||||
adxl34x_calibrate_show, adxl34x_calibrate_store);
|
||||
|
||||
static ssize_t adxl34x_rate_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct adxl34x *ac = dev_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%u\n", RATE(ac->pdata.data_rate));
|
||||
}
|
||||
|
||||
static ssize_t adxl34x_rate_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct adxl34x *ac = dev_get_drvdata(dev);
|
||||
unsigned long val;
|
||||
int error;
|
||||
|
||||
error = strict_strtoul(buf, 10, &val);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
mutex_lock(&ac->mutex);
|
||||
|
||||
ac->pdata.data_rate = RATE(val);
|
||||
AC_WRITE(ac, BW_RATE,
|
||||
ac->pdata.data_rate |
|
||||
(ac->pdata.low_power_mode ? LOW_POWER : 0));
|
||||
|
||||
mutex_unlock(&ac->mutex);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(rate, 0664, adxl34x_rate_show, adxl34x_rate_store);
|
||||
|
||||
static ssize_t adxl34x_autosleep_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct adxl34x *ac = dev_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%u\n",
|
||||
ac->pdata.power_mode & (PCTL_AUTO_SLEEP | PCTL_LINK) ? 1 : 0);
|
||||
}
|
||||
|
||||
static ssize_t adxl34x_autosleep_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct adxl34x *ac = dev_get_drvdata(dev);
|
||||
unsigned long val;
|
||||
int error;
|
||||
|
||||
error = strict_strtoul(buf, 10, &val);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
mutex_lock(&ac->mutex);
|
||||
|
||||
if (val)
|
||||
ac->pdata.power_mode |= (PCTL_AUTO_SLEEP | PCTL_LINK);
|
||||
else
|
||||
ac->pdata.power_mode &= ~(PCTL_AUTO_SLEEP | PCTL_LINK);
|
||||
|
||||
if (!ac->disabled && !ac->suspended && ac->opened)
|
||||
AC_WRITE(ac, POWER_CTL, ac->pdata.power_mode | PCTL_MEASURE);
|
||||
|
||||
mutex_unlock(&ac->mutex);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(autosleep, 0664,
|
||||
adxl34x_autosleep_show, adxl34x_autosleep_store);
|
||||
|
||||
static ssize_t adxl34x_position_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct adxl34x *ac = dev_get_drvdata(dev);
|
||||
ssize_t count;
|
||||
|
||||
mutex_lock(&ac->mutex);
|
||||
count = sprintf(buf, "(%d, %d, %d)\n",
|
||||
ac->saved.x, ac->saved.y, ac->saved.z);
|
||||
mutex_unlock(&ac->mutex);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(position, S_IRUGO, adxl34x_position_show, NULL);
|
||||
|
||||
#ifdef ADXL_DEBUG
|
||||
static ssize_t adxl34x_write_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct adxl34x *ac = dev_get_drvdata(dev);
|
||||
unsigned long val;
|
||||
int error;
|
||||
|
||||
/*
|
||||
* This allows basic ADXL register write access for debug purposes.
|
||||
*/
|
||||
error = strict_strtoul(buf, 16, &val);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
mutex_lock(&ac->mutex);
|
||||
AC_WRITE(ac, val >> 8, val & 0xFF);
|
||||
mutex_unlock(&ac->mutex);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(write, 0664, NULL, adxl34x_write_store);
|
||||
#endif
|
||||
|
||||
static struct attribute *adxl34x_attributes[] = {
|
||||
&dev_attr_disable.attr,
|
||||
&dev_attr_calibrate.attr,
|
||||
&dev_attr_rate.attr,
|
||||
&dev_attr_autosleep.attr,
|
||||
&dev_attr_position.attr,
|
||||
#ifdef ADXL_DEBUG
|
||||
&dev_attr_write.attr,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group adxl34x_attr_group = {
|
||||
.attrs = adxl34x_attributes,
|
||||
};
|
||||
|
||||
static int adxl34x_input_open(struct input_dev *input)
|
||||
{
|
||||
struct adxl34x *ac = input_get_drvdata(input);
|
||||
|
||||
mutex_lock(&ac->mutex);
|
||||
|
||||
if (!ac->suspended && !ac->disabled)
|
||||
__adxl34x_enable(ac);
|
||||
|
||||
ac->opened = true;
|
||||
|
||||
mutex_unlock(&ac->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void adxl34x_input_close(struct input_dev *input)
|
||||
{
|
||||
struct adxl34x *ac = input_get_drvdata(input);
|
||||
|
||||
mutex_lock(&ac->mutex);
|
||||
|
||||
if (!ac->suspended && !ac->disabled)
|
||||
__adxl34x_disable(ac);
|
||||
|
||||
ac->opened = false;
|
||||
|
||||
mutex_unlock(&ac->mutex);
|
||||
}
|
||||
|
||||
struct adxl34x *adxl34x_probe(struct device *dev, int irq,
|
||||
bool fifo_delay_default,
|
||||
const struct adxl34x_bus_ops *bops)
|
||||
{
|
||||
struct adxl34x *ac;
|
||||
struct input_dev *input_dev;
|
||||
const struct adxl34x_platform_data *pdata;
|
||||
int err, range, i;
|
||||
unsigned char revid;
|
||||
|
||||
if (!irq) {
|
||||
dev_err(dev, "no IRQ?\n");
|
||||
err = -ENODEV;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
ac = kzalloc(sizeof(*ac), GFP_KERNEL);
|
||||
input_dev = input_allocate_device();
|
||||
if (!ac || !input_dev) {
|
||||
err = -ENOMEM;
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
ac->fifo_delay = fifo_delay_default;
|
||||
|
||||
pdata = dev->platform_data;
|
||||
if (!pdata) {
|
||||
dev_dbg(dev,
|
||||
"No platfrom data: Using default initialization\n");
|
||||
pdata = &adxl34x_default_init;
|
||||
}
|
||||
|
||||
ac->pdata = *pdata;
|
||||
pdata = &ac->pdata;
|
||||
|
||||
ac->input = input_dev;
|
||||
ac->disabled = true;
|
||||
ac->dev = dev;
|
||||
ac->irq = irq;
|
||||
ac->bops = bops;
|
||||
|
||||
mutex_init(&ac->mutex);
|
||||
|
||||
input_dev->name = "ADXL34x accelerometer";
|
||||
revid = ac->bops->read(dev, DEVID);
|
||||
|
||||
switch (revid) {
|
||||
case ID_ADXL345:
|
||||
ac->model = 345;
|
||||
break;
|
||||
case ID_ADXL346:
|
||||
ac->model = 346;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "Failed to probe %s\n", input_dev->name);
|
||||
err = -ENODEV;
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
snprintf(ac->phys, sizeof(ac->phys), "%s/input0", dev_name(dev));
|
||||
|
||||
input_dev->phys = ac->phys;
|
||||
input_dev->dev.parent = dev;
|
||||
input_dev->id.product = ac->model;
|
||||
input_dev->id.bustype = bops->bustype;
|
||||
input_dev->open = adxl34x_input_open;
|
||||
input_dev->close = adxl34x_input_close;
|
||||
|
||||
input_set_drvdata(input_dev, ac);
|
||||
|
||||
__set_bit(ac->pdata.ev_type, input_dev->evbit);
|
||||
|
||||
if (ac->pdata.ev_type == EV_REL) {
|
||||
__set_bit(REL_X, input_dev->relbit);
|
||||
__set_bit(REL_Y, input_dev->relbit);
|
||||
__set_bit(REL_Z, input_dev->relbit);
|
||||
} else {
|
||||
/* EV_ABS */
|
||||
__set_bit(ABS_X, input_dev->absbit);
|
||||
__set_bit(ABS_Y, input_dev->absbit);
|
||||
__set_bit(ABS_Z, input_dev->absbit);
|
||||
|
||||
if (pdata->data_range & FULL_RES)
|
||||
range = ADXL_FULLRES_MAX_VAL; /* Signed 13-bit */
|
||||
else
|
||||
range = ADXL_FIXEDRES_MAX_VAL; /* Signed 10-bit */
|
||||
|
||||
input_set_abs_params(input_dev, ABS_X, -range, range, 3, 3);
|
||||
input_set_abs_params(input_dev, ABS_Y, -range, range, 3, 3);
|
||||
input_set_abs_params(input_dev, ABS_Z, -range, range, 3, 3);
|
||||
}
|
||||
|
||||
__set_bit(EV_KEY, input_dev->evbit);
|
||||
__set_bit(pdata->ev_code_tap[ADXL_X_AXIS], input_dev->keybit);
|
||||
__set_bit(pdata->ev_code_tap[ADXL_Y_AXIS], input_dev->keybit);
|
||||
__set_bit(pdata->ev_code_tap[ADXL_Z_AXIS], input_dev->keybit);
|
||||
|
||||
if (pdata->ev_code_ff) {
|
||||
ac->int_mask = FREE_FALL;
|
||||
__set_bit(pdata->ev_code_ff, input_dev->keybit);
|
||||
}
|
||||
|
||||
if (pdata->ev_code_act_inactivity)
|
||||
__set_bit(pdata->ev_code_act_inactivity, input_dev->keybit);
|
||||
|
||||
ac->int_mask |= ACTIVITY | INACTIVITY;
|
||||
|
||||
if (pdata->watermark) {
|
||||
ac->int_mask |= WATERMARK;
|
||||
if (!FIFO_MODE(pdata->fifo_mode))
|
||||
ac->pdata.fifo_mode |= FIFO_STREAM;
|
||||
} else {
|
||||
ac->int_mask |= DATA_READY;
|
||||
}
|
||||
|
||||
if (pdata->tap_axis_control & (TAP_X_EN | TAP_Y_EN | TAP_Z_EN))
|
||||
ac->int_mask |= SINGLE_TAP | DOUBLE_TAP;
|
||||
|
||||
if (FIFO_MODE(pdata->fifo_mode) == FIFO_BYPASS)
|
||||
ac->fifo_delay = false;
|
||||
|
||||
ac->bops->write(dev, POWER_CTL, 0);
|
||||
|
||||
err = request_threaded_irq(ac->irq, NULL, adxl34x_irq,
|
||||
IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
|
||||
dev_name(dev), ac);
|
||||
if (err) {
|
||||
dev_err(dev, "irq %d busy?\n", ac->irq);
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
err = sysfs_create_group(&dev->kobj, &adxl34x_attr_group);
|
||||
if (err)
|
||||
goto err_free_irq;
|
||||
|
||||
err = input_register_device(input_dev);
|
||||
if (err)
|
||||
goto err_remove_attr;
|
||||
|
||||
AC_WRITE(ac, THRESH_TAP, pdata->tap_threshold);
|
||||
AC_WRITE(ac, OFSX, pdata->x_axis_offset);
|
||||
ac->hwcal.x = pdata->x_axis_offset;
|
||||
AC_WRITE(ac, OFSY, pdata->y_axis_offset);
|
||||
ac->hwcal.y = pdata->y_axis_offset;
|
||||
AC_WRITE(ac, OFSZ, pdata->z_axis_offset);
|
||||
ac->hwcal.z = pdata->z_axis_offset;
|
||||
AC_WRITE(ac, THRESH_TAP, pdata->tap_threshold);
|
||||
AC_WRITE(ac, DUR, pdata->tap_duration);
|
||||
AC_WRITE(ac, LATENT, pdata->tap_latency);
|
||||
AC_WRITE(ac, WINDOW, pdata->tap_window);
|
||||
AC_WRITE(ac, THRESH_ACT, pdata->activity_threshold);
|
||||
AC_WRITE(ac, THRESH_INACT, pdata->inactivity_threshold);
|
||||
AC_WRITE(ac, TIME_INACT, pdata->inactivity_time);
|
||||
AC_WRITE(ac, THRESH_FF, pdata->free_fall_threshold);
|
||||
AC_WRITE(ac, TIME_FF, pdata->free_fall_time);
|
||||
AC_WRITE(ac, TAP_AXES, pdata->tap_axis_control);
|
||||
AC_WRITE(ac, ACT_INACT_CTL, pdata->act_axis_control);
|
||||
AC_WRITE(ac, BW_RATE, RATE(ac->pdata.data_rate) |
|
||||
(pdata->low_power_mode ? LOW_POWER : 0));
|
||||
AC_WRITE(ac, DATA_FORMAT, pdata->data_range);
|
||||
AC_WRITE(ac, FIFO_CTL, FIFO_MODE(pdata->fifo_mode) |
|
||||
SAMPLES(pdata->watermark));
|
||||
|
||||
if (pdata->use_int2) {
|
||||
/* Map all INTs to INT2 */
|
||||
AC_WRITE(ac, INT_MAP, ac->int_mask | OVERRUN);
|
||||
} else {
|
||||
/* Map all INTs to INT1 */
|
||||
AC_WRITE(ac, INT_MAP, 0);
|
||||
}
|
||||
|
||||
if (ac->model == 346 && ac->pdata.orientation_enable) {
|
||||
AC_WRITE(ac, ORIENT_CONF,
|
||||
ORIENT_DEADZONE(ac->pdata.deadzone_angle) |
|
||||
ORIENT_DIVISOR(ac->pdata.divisor_length));
|
||||
|
||||
ac->orient2d_saved = 1234;
|
||||
ac->orient3d_saved = 1234;
|
||||
|
||||
if (pdata->orientation_enable & ADXL_EN_ORIENTATION_3D)
|
||||
for (i = 0; i < ARRAY_SIZE(pdata->ev_codes_orient_3d); i++)
|
||||
__set_bit(pdata->ev_codes_orient_3d[i],
|
||||
input_dev->keybit);
|
||||
|
||||
if (pdata->orientation_enable & ADXL_EN_ORIENTATION_2D)
|
||||
for (i = 0; i < ARRAY_SIZE(pdata->ev_codes_orient_2d); i++)
|
||||
__set_bit(pdata->ev_codes_orient_2d[i],
|
||||
input_dev->keybit);
|
||||
} else {
|
||||
ac->pdata.orientation_enable = 0;
|
||||
}
|
||||
|
||||
AC_WRITE(ac, INT_ENABLE, ac->int_mask | OVERRUN);
|
||||
|
||||
ac->pdata.power_mode &= (PCTL_AUTO_SLEEP | PCTL_LINK);
|
||||
|
||||
return ac;
|
||||
|
||||
err_remove_attr:
|
||||
sysfs_remove_group(&dev->kobj, &adxl34x_attr_group);
|
||||
err_free_irq:
|
||||
free_irq(ac->irq, ac);
|
||||
err_free_mem:
|
||||
input_free_device(input_dev);
|
||||
kfree(ac);
|
||||
err_out:
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adxl34x_probe);
|
||||
|
||||
int adxl34x_remove(struct adxl34x *ac)
|
||||
{
|
||||
sysfs_remove_group(&ac->dev->kobj, &adxl34x_attr_group);
|
||||
free_irq(ac->irq, ac);
|
||||
input_unregister_device(ac->input);
|
||||
dev_dbg(ac->dev, "unregistered accelerometer\n");
|
||||
kfree(ac);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adxl34x_remove);
|
||||
|
||||
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
|
||||
MODULE_DESCRIPTION("ADXL345/346 Three-Axis Digital Accelerometer Driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* ADXL345/346 Three-Axis Digital Accelerometers (I2C/SPI Interface)
|
||||
*
|
||||
* Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* Copyright (C) 2009 Michael Hennerich, Analog Devices Inc.
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#ifndef _ADXL34X_H_
|
||||
#define _ADXL34X_H_
|
||||
|
||||
struct device;
|
||||
struct adxl34x;
|
||||
|
||||
struct adxl34x_bus_ops {
|
||||
u16 bustype;
|
||||
int (*read)(struct device *, unsigned char);
|
||||
int (*read_block)(struct device *, unsigned char, int, void *);
|
||||
int (*write)(struct device *, unsigned char, unsigned char);
|
||||
};
|
||||
|
||||
void adxl34x_suspend(struct adxl34x *ac);
|
||||
void adxl34x_resume(struct adxl34x *ac);
|
||||
struct adxl34x *adxl34x_probe(struct device *dev, int irq,
|
||||
bool fifo_delay_default,
|
||||
const struct adxl34x_bus_ops *bops);
|
||||
int adxl34x_remove(struct adxl34x *ac);
|
||||
|
||||
#endif
|
|
@ -21,6 +21,8 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
|
@ -60,12 +62,11 @@ static acpi_status acpi_atlas_button_handler(u32 function,
|
|||
input_report_key(input_dev, atlas_keymap[code], key_down);
|
||||
input_sync(input_dev);
|
||||
|
||||
status = 0;
|
||||
status = AE_OK;
|
||||
} else {
|
||||
printk(KERN_WARNING "atlas: shrugged on unexpected function"
|
||||
":function=%x,address=%lx,value=%x\n",
|
||||
pr_warn("shrugged on unexpected function: function=%x,address=%lx,value=%x\n",
|
||||
function, (unsigned long)address, (u32)*value);
|
||||
status = -EINVAL;
|
||||
status = AE_BAD_PARAMETER;
|
||||
}
|
||||
|
||||
return status;
|
||||
|
@ -79,7 +80,7 @@ static int atlas_acpi_button_add(struct acpi_device *device)
|
|||
|
||||
input_dev = input_allocate_device();
|
||||
if (!input_dev) {
|
||||
printk(KERN_ERR "atlas: unable to allocate input device\n");
|
||||
pr_err("unable to allocate input device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
@ -102,7 +103,7 @@ static int atlas_acpi_button_add(struct acpi_device *device)
|
|||
|
||||
err = input_register_device(input_dev);
|
||||
if (err) {
|
||||
printk(KERN_ERR "atlas: couldn't register input device\n");
|
||||
pr_err("couldn't register input device\n");
|
||||
input_free_device(input_dev);
|
||||
return err;
|
||||
}
|
||||
|
@ -112,12 +113,12 @@ static int atlas_acpi_button_add(struct acpi_device *device)
|
|||
0x81, &acpi_atlas_button_handler,
|
||||
&acpi_atlas_button_setup, device);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
printk(KERN_ERR "Atlas: Error installing addr spc handler\n");
|
||||
pr_err("error installing addr spc handler\n");
|
||||
input_unregister_device(input_dev);
|
||||
status = -EINVAL;
|
||||
err = -EINVAL;
|
||||
}
|
||||
|
||||
return status;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int atlas_acpi_button_remove(struct acpi_device *device, int type)
|
||||
|
@ -126,14 +127,12 @@ static int atlas_acpi_button_remove(struct acpi_device *device, int type)
|
|||
|
||||
status = acpi_remove_address_space_handler(device->handle,
|
||||
0x81, &acpi_atlas_button_handler);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
printk(KERN_ERR "Atlas: Error removing addr spc handler\n");
|
||||
status = -EINVAL;
|
||||
}
|
||||
if (ACPI_FAILURE(status))
|
||||
pr_err("error removing addr spc handler\n");
|
||||
|
||||
input_unregister_device(input_dev);
|
||||
|
||||
return status;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct acpi_device_id atlas_device_ids[] = {
|
||||
|
@ -145,6 +144,7 @@ MODULE_DEVICE_TABLE(acpi, atlas_device_ids);
|
|||
static struct acpi_driver atlas_acpi_driver = {
|
||||
.name = ACPI_ATLAS_NAME,
|
||||
.class = ACPI_ATLAS_CLASS,
|
||||
.owner = THIS_MODULE,
|
||||
.ids = atlas_device_ids,
|
||||
.ops = {
|
||||
.add = atlas_acpi_button_add,
|
||||
|
@ -154,18 +154,10 @@ static struct acpi_driver atlas_acpi_driver = {
|
|||
|
||||
static int __init atlas_acpi_init(void)
|
||||
{
|
||||
int result;
|
||||
|
||||
if (acpi_disabled)
|
||||
return -ENODEV;
|
||||
|
||||
result = acpi_bus_register_driver(&atlas_acpi_driver);
|
||||
if (result < 0) {
|
||||
printk(KERN_ERR "Atlas ACPI: Unable to register driver\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return acpi_bus_register_driver(&atlas_acpi_driver);
|
||||
}
|
||||
|
||||
static void __exit atlas_acpi_exit(void)
|
||||
|
|
|
@ -0,0 +1,199 @@
|
|||
/*
|
||||
* Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
|
||||
* PWM beeper driver
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/input.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pwm.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
struct pwm_beeper {
|
||||
struct input_dev *input;
|
||||
struct pwm_device *pwm;
|
||||
unsigned long period;
|
||||
};
|
||||
|
||||
#define HZ_TO_NANOSECONDS(x) (1000000000UL/(x))
|
||||
|
||||
static int pwm_beeper_event(struct input_dev *input,
|
||||
unsigned int type, unsigned int code, int value)
|
||||
{
|
||||
int ret = 0;
|
||||
struct pwm_beeper *beeper = input_get_drvdata(input);
|
||||
unsigned long period;
|
||||
|
||||
if (type != EV_SND || value < 0)
|
||||
return -EINVAL;
|
||||
|
||||
switch (code) {
|
||||
case SND_BELL:
|
||||
value = value ? 1000 : 0;
|
||||
break;
|
||||
case SND_TONE:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (value == 0) {
|
||||
pwm_config(beeper->pwm, 0, 0);
|
||||
pwm_disable(beeper->pwm);
|
||||
} else {
|
||||
period = HZ_TO_NANOSECONDS(value);
|
||||
ret = pwm_config(beeper->pwm, period / 2, period);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = pwm_enable(beeper->pwm);
|
||||
if (ret)
|
||||
return ret;
|
||||
beeper->period = period;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit pwm_beeper_probe(struct platform_device *pdev)
|
||||
{
|
||||
unsigned long pwm_id = (unsigned long)pdev->dev.platform_data;
|
||||
struct pwm_beeper *beeper;
|
||||
int error;
|
||||
|
||||
beeper = kzalloc(sizeof(*beeper), GFP_KERNEL);
|
||||
if (!beeper)
|
||||
return -ENOMEM;
|
||||
|
||||
beeper->pwm = pwm_request(pwm_id, "pwm beeper");
|
||||
|
||||
if (IS_ERR(beeper->pwm)) {
|
||||
error = PTR_ERR(beeper->pwm);
|
||||
dev_err(&pdev->dev, "Failed to request pwm device: %d\n", error);
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
beeper->input = input_allocate_device();
|
||||
if (!beeper->input) {
|
||||
dev_err(&pdev->dev, "Failed to allocate input device\n");
|
||||
error = -ENOMEM;
|
||||
goto err_pwm_free;
|
||||
}
|
||||
beeper->input->dev.parent = &pdev->dev;
|
||||
|
||||
beeper->input->name = "pwm-beeper";
|
||||
beeper->input->phys = "pwm/input0";
|
||||
beeper->input->id.bustype = BUS_HOST;
|
||||
beeper->input->id.vendor = 0x001f;
|
||||
beeper->input->id.product = 0x0001;
|
||||
beeper->input->id.version = 0x0100;
|
||||
|
||||
beeper->input->evbit[0] = BIT(EV_SND);
|
||||
beeper->input->sndbit[0] = BIT(SND_TONE) | BIT(SND_BELL);
|
||||
|
||||
beeper->input->event = pwm_beeper_event;
|
||||
|
||||
input_set_drvdata(beeper->input, beeper);
|
||||
|
||||
error = input_register_device(beeper->input);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "Failed to register input device: %d\n", error);
|
||||
goto err_input_free;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, beeper);
|
||||
|
||||
return 0;
|
||||
|
||||
err_input_free:
|
||||
input_free_device(beeper->input);
|
||||
err_pwm_free:
|
||||
pwm_free(beeper->pwm);
|
||||
err_free:
|
||||
kfree(beeper);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int __devexit pwm_beeper_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct pwm_beeper *beeper = platform_get_drvdata(pdev);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
input_unregister_device(beeper->input);
|
||||
|
||||
pwm_disable(beeper->pwm);
|
||||
pwm_free(beeper->pwm);
|
||||
|
||||
kfree(beeper);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int pwm_beeper_suspend(struct device *dev)
|
||||
{
|
||||
struct pwm_beeper *beeper = dev_get_drvdata(dev);
|
||||
|
||||
if (beeper->period)
|
||||
pwm_disable(beeper->pwm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pwm_beeper_resume(struct device *dev)
|
||||
{
|
||||
struct pwm_beeper *beeper = dev_get_drvdata(dev);
|
||||
|
||||
if (beeper->period) {
|
||||
pwm_config(beeper->pwm, beeper->period / 2, beeper->period);
|
||||
pwm_enable(beeper->pwm);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(pwm_beeper_pm_ops,
|
||||
pwm_beeper_suspend, pwm_beeper_resume);
|
||||
|
||||
#define PWM_BEEPER_PM_OPS (&pwm_beeper_pm_ops)
|
||||
#else
|
||||
#define PWM_BEEPER_PM_OPS NULL
|
||||
#endif
|
||||
|
||||
static struct platform_driver pwm_beeper_driver = {
|
||||
.probe = pwm_beeper_probe,
|
||||
.remove = __devexit_p(pwm_beeper_remove),
|
||||
.driver = {
|
||||
.name = "pwm-beeper",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = PWM_BEEPER_PM_OPS,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init pwm_beeper_init(void)
|
||||
{
|
||||
return platform_driver_register(&pwm_beeper_driver);
|
||||
}
|
||||
module_init(pwm_beeper_init);
|
||||
|
||||
static void __exit pwm_beeper_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&pwm_beeper_driver);
|
||||
}
|
||||
module_exit(pwm_beeper_exit);
|
||||
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_DESCRIPTION("PWM beeper driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:pwm-beeper");
|
|
@ -52,7 +52,7 @@ static irqreturn_t powerbutton_irq(int irq, void *_pwr)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int __devinit twl4030_pwrbutton_probe(struct platform_device *pdev)
|
||||
static int __init twl4030_pwrbutton_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct input_dev *pwr;
|
||||
int irq = platform_get_irq(pdev, 0);
|
||||
|
@ -95,7 +95,7 @@ free_input_dev:
|
|||
return err;
|
||||
}
|
||||
|
||||
static int __devexit twl4030_pwrbutton_remove(struct platform_device *pdev)
|
||||
static int __exit twl4030_pwrbutton_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct input_dev *pwr = platform_get_drvdata(pdev);
|
||||
int irq = platform_get_irq(pdev, 0);
|
||||
|
@ -106,9 +106,8 @@ static int __devexit twl4030_pwrbutton_remove(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
struct platform_driver twl4030_pwrbutton_driver = {
|
||||
.probe = twl4030_pwrbutton_probe,
|
||||
.remove = __devexit_p(twl4030_pwrbutton_remove),
|
||||
static struct platform_driver twl4030_pwrbutton_driver = {
|
||||
.remove = __exit_p(twl4030_pwrbutton_remove),
|
||||
.driver = {
|
||||
.name = "twl4030_pwrbutton",
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -117,7 +116,8 @@ struct platform_driver twl4030_pwrbutton_driver = {
|
|||
|
||||
static int __init twl4030_pwrbutton_init(void)
|
||||
{
|
||||
return platform_driver_register(&twl4030_pwrbutton_driver);
|
||||
return platform_driver_probe(&twl4030_pwrbutton_driver,
|
||||
twl4030_pwrbutton_probe);
|
||||
}
|
||||
module_init(twl4030_pwrbutton_init);
|
||||
|
||||
|
|
|
@ -1347,7 +1347,7 @@ static int __init wb_module_init(void)
|
|||
|
||||
err = map_bios();
|
||||
if (err)
|
||||
return err;
|
||||
goto err_free_keymap;
|
||||
|
||||
err = platform_driver_register(&wistron_driver);
|
||||
if (err)
|
||||
|
@ -1371,6 +1371,8 @@ static int __init wb_module_init(void)
|
|||
platform_driver_unregister(&wistron_driver);
|
||||
err_unmap_bios:
|
||||
unmap_bios();
|
||||
err_free_keymap:
|
||||
kfree(keymap);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -312,6 +312,8 @@ static void setup_events_to_report(struct input_dev *input_dev,
|
|||
__set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
|
||||
__set_bit(BTN_TOOL_QUADTAP, input_dev->keybit);
|
||||
__set_bit(BTN_LEFT, input_dev->keybit);
|
||||
|
||||
input_set_events_per_packet(input_dev, 60);
|
||||
}
|
||||
|
||||
/* report button data as logical button state */
|
||||
|
@ -580,23 +582,30 @@ exit:
|
|||
*/
|
||||
static int bcm5974_start_traffic(struct bcm5974 *dev)
|
||||
{
|
||||
if (bcm5974_wellspring_mode(dev, true)) {
|
||||
int error;
|
||||
|
||||
error = bcm5974_wellspring_mode(dev, true);
|
||||
if (error) {
|
||||
dprintk(1, "bcm5974: mode switch failed\n");
|
||||
goto error;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
if (usb_submit_urb(dev->bt_urb, GFP_KERNEL))
|
||||
goto error;
|
||||
error = usb_submit_urb(dev->bt_urb, GFP_KERNEL);
|
||||
if (error)
|
||||
goto err_reset_mode;
|
||||
|
||||
if (usb_submit_urb(dev->tp_urb, GFP_KERNEL))
|
||||
error = usb_submit_urb(dev->tp_urb, GFP_KERNEL);
|
||||
if (error)
|
||||
goto err_kill_bt;
|
||||
|
||||
return 0;
|
||||
|
||||
err_kill_bt:
|
||||
usb_kill_urb(dev->bt_urb);
|
||||
error:
|
||||
return -EIO;
|
||||
err_reset_mode:
|
||||
bcm5974_wellspring_mode(dev, false);
|
||||
err_out:
|
||||
return error;
|
||||
}
|
||||
|
||||
static void bcm5974_pause_traffic(struct bcm5974 *dev)
|
||||
|
|
|
@ -502,7 +502,9 @@ static void synaptics_process_packet(struct psmouse *psmouse)
|
|||
}
|
||||
input_report_abs(dev, ABS_PRESSURE, hw.z);
|
||||
|
||||
input_report_abs(dev, ABS_TOOL_WIDTH, finger_width);
|
||||
if (SYN_CAP_PALMDETECT(priv->capabilities))
|
||||
input_report_abs(dev, ABS_TOOL_WIDTH, finger_width);
|
||||
|
||||
input_report_key(dev, BTN_TOOL_FINGER, num_fingers == 1);
|
||||
input_report_key(dev, BTN_LEFT, hw.left);
|
||||
input_report_key(dev, BTN_RIGHT, hw.right);
|
||||
|
@ -602,7 +604,9 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
|
|||
input_set_abs_params(dev, ABS_Y,
|
||||
YMIN_NOMINAL, priv->y_max ?: YMAX_NOMINAL, 0, 0);
|
||||
input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
|
||||
__set_bit(ABS_TOOL_WIDTH, dev->absbit);
|
||||
|
||||
if (SYN_CAP_PALMDETECT(priv->capabilities))
|
||||
input_set_abs_params(dev, ABS_TOOL_WIDTH, 0, 15, 0, 0);
|
||||
|
||||
__set_bit(EV_KEY, dev->evbit);
|
||||
__set_bit(BTN_TOUCH, dev->keybit);
|
||||
|
|
|
@ -57,7 +57,6 @@ struct mousedev_hw_data {
|
|||
};
|
||||
|
||||
struct mousedev {
|
||||
int exist;
|
||||
int open;
|
||||
int minor;
|
||||
struct input_handle handle;
|
||||
|
@ -66,6 +65,7 @@ struct mousedev {
|
|||
spinlock_t client_lock; /* protects client_list */
|
||||
struct mutex mutex;
|
||||
struct device dev;
|
||||
bool exist;
|
||||
|
||||
struct list_head mixdev_node;
|
||||
int mixdev_open;
|
||||
|
@ -765,10 +765,15 @@ static unsigned int mousedev_poll(struct file *file, poll_table *wait)
|
|||
{
|
||||
struct mousedev_client *client = file->private_data;
|
||||
struct mousedev *mousedev = client->mousedev;
|
||||
unsigned int mask;
|
||||
|
||||
poll_wait(file, &mousedev->wait, wait);
|
||||
return ((client->ready || client->buffer) ? (POLLIN | POLLRDNORM) : 0) |
|
||||
(mousedev->exist ? 0 : (POLLHUP | POLLERR));
|
||||
|
||||
mask = mousedev->exist ? POLLOUT | POLLWRNORM : POLLHUP | POLLERR;
|
||||
if (client->ready || client->buffer)
|
||||
mask |= POLLIN | POLLRDNORM;
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
static const struct file_operations mousedev_fops = {
|
||||
|
@ -802,7 +807,7 @@ static void mousedev_remove_chrdev(struct mousedev *mousedev)
|
|||
static void mousedev_mark_dead(struct mousedev *mousedev)
|
||||
{
|
||||
mutex_lock(&mousedev->mutex);
|
||||
mousedev->exist = 0;
|
||||
mousedev->exist = false;
|
||||
mutex_unlock(&mousedev->mutex);
|
||||
}
|
||||
|
||||
|
@ -862,7 +867,7 @@ static struct mousedev *mousedev_create(struct input_dev *dev,
|
|||
dev_set_name(&mousedev->dev, "mouse%d", minor);
|
||||
|
||||
mousedev->minor = minor;
|
||||
mousedev->exist = 1;
|
||||
mousedev->exist = true;
|
||||
mousedev->handle.dev = input_get_device(dev);
|
||||
mousedev->handle.name = dev_name(&mousedev->dev);
|
||||
mousedev->handle.handler = handler;
|
||||
|
|
|
@ -52,81 +52,6 @@ static inline void i8042_platform_exit(void)
|
|||
{
|
||||
}
|
||||
|
||||
#elif defined(CONFIG_SPRUCE)
|
||||
|
||||
#define I8042_KBD_IRQ 22
|
||||
#define I8042_AUX_IRQ 21
|
||||
|
||||
#define I8042_KBD_PHYS_DESC "spruceps2/serio0"
|
||||
#define I8042_AUX_PHYS_DESC "spruceps2/serio1"
|
||||
#define I8042_MUX_PHYS_DESC "spruceps2/serio%d"
|
||||
|
||||
#define I8042_COMMAND_REG 0xff810000
|
||||
#define I8042_DATA_REG 0xff810001
|
||||
|
||||
static inline int i8042_read_data(void)
|
||||
{
|
||||
unsigned long kbd_data;
|
||||
|
||||
__raw_writel(0x00000088, 0xff500008);
|
||||
eieio();
|
||||
|
||||
__raw_writel(0x03000000, 0xff50000c);
|
||||
eieio();
|
||||
|
||||
asm volatile("lis 7,0xff88 \n\
|
||||
lswi 6,7,0x8 \n\
|
||||
mr %0,6"
|
||||
: "=r" (kbd_data) :: "6", "7");
|
||||
|
||||
__raw_writel(0x00000000, 0xff50000c);
|
||||
eieio();
|
||||
|
||||
return (unsigned char)(kbd_data >> 24);
|
||||
}
|
||||
|
||||
static inline int i8042_read_status(void)
|
||||
{
|
||||
unsigned long kbd_status;
|
||||
|
||||
__raw_writel(0x00000088, 0xff500008);
|
||||
eieio();
|
||||
|
||||
__raw_writel(0x03000000, 0xff50000c);
|
||||
eieio();
|
||||
|
||||
asm volatile("lis 7,0xff88 \n\
|
||||
ori 7,7,0x8 \n\
|
||||
lswi 6,7,0x8 \n\
|
||||
mr %0,6"
|
||||
: "=r" (kbd_status) :: "6", "7");
|
||||
|
||||
__raw_writel(0x00000000, 0xff50000c);
|
||||
eieio();
|
||||
|
||||
return (unsigned char)(kbd_status >> 24);
|
||||
}
|
||||
|
||||
static inline void i8042_write_data(int val)
|
||||
{
|
||||
*((unsigned char *)0xff810000) = (char)val;
|
||||
}
|
||||
|
||||
static inline void i8042_write_command(int val)
|
||||
{
|
||||
*((unsigned char *)0xff810001) = (char)val;
|
||||
}
|
||||
|
||||
static inline int i8042_platform_init(void)
|
||||
{
|
||||
i8042_reset = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void i8042_platform_exit(void)
|
||||
{
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include "i8042-io.h"
|
||||
|
|
|
@ -861,9 +861,6 @@ static int i8042_controller_selftest(void)
|
|||
unsigned char param;
|
||||
int i = 0;
|
||||
|
||||
if (!i8042_reset)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* We try this 5 times; on some really fragile systems this does not
|
||||
* take the first time...
|
||||
|
@ -1020,7 +1017,8 @@ static void i8042_controller_reset(void)
|
|||
* Reset the controller if requested.
|
||||
*/
|
||||
|
||||
i8042_controller_selftest();
|
||||
if (i8042_reset)
|
||||
i8042_controller_selftest();
|
||||
|
||||
/*
|
||||
* Restore the original control register setting.
|
||||
|
@ -1093,24 +1091,12 @@ static void i8042_dritek_enable(void)
|
|||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
/*
|
||||
* Here we try to restore the original BIOS settings to avoid
|
||||
* upsetting it.
|
||||
*/
|
||||
|
||||
static int i8042_pm_reset(struct device *dev)
|
||||
{
|
||||
i8042_controller_reset();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Here we try to reset everything back to a state we had
|
||||
* before suspending.
|
||||
*/
|
||||
|
||||
static int i8042_pm_restore(struct device *dev)
|
||||
static int i8042_controller_resume(bool force_reset)
|
||||
{
|
||||
int error;
|
||||
|
||||
|
@ -1118,9 +1104,11 @@ static int i8042_pm_restore(struct device *dev)
|
|||
if (error)
|
||||
return error;
|
||||
|
||||
error = i8042_controller_selftest();
|
||||
if (error)
|
||||
return error;
|
||||
if (i8042_reset || force_reset) {
|
||||
error = i8042_controller_selftest();
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Restore original CTR value and disable all ports
|
||||
|
@ -1162,6 +1150,28 @@ static int i8042_pm_restore(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Here we try to restore the original BIOS settings to avoid
|
||||
* upsetting it.
|
||||
*/
|
||||
|
||||
static int i8042_pm_reset(struct device *dev)
|
||||
{
|
||||
i8042_controller_reset();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i8042_pm_resume(struct device *dev)
|
||||
{
|
||||
/*
|
||||
* On resume from S2R we always try to reset the controller
|
||||
* to bring it in a sane state. (In case of S2D we expect
|
||||
* BIOS to reset the controller for us.)
|
||||
*/
|
||||
return i8042_controller_resume(true);
|
||||
}
|
||||
|
||||
static int i8042_pm_thaw(struct device *dev)
|
||||
{
|
||||
i8042_interrupt(0, NULL);
|
||||
|
@ -1169,9 +1179,14 @@ static int i8042_pm_thaw(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int i8042_pm_restore(struct device *dev)
|
||||
{
|
||||
return i8042_controller_resume(false);
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops i8042_pm_ops = {
|
||||
.suspend = i8042_pm_reset,
|
||||
.resume = i8042_pm_restore,
|
||||
.resume = i8042_pm_resume,
|
||||
.thaw = i8042_pm_thaw,
|
||||
.poweroff = i8042_pm_reset,
|
||||
.restore = i8042_pm_restore,
|
||||
|
@ -1389,9 +1404,11 @@ static int __init i8042_probe(struct platform_device *dev)
|
|||
|
||||
i8042_platform_device = dev;
|
||||
|
||||
error = i8042_controller_selftest();
|
||||
if (error)
|
||||
return error;
|
||||
if (i8042_reset) {
|
||||
error = i8042_controller_selftest();
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
|
||||
error = i8042_controller_init();
|
||||
if (error)
|
||||
|
|
|
@ -158,6 +158,39 @@ static int wacom_ptu_irq(struct wacom_wac *wacom)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int wacom_dtu_irq(struct wacom_wac *wacom)
|
||||
{
|
||||
struct wacom_features *features = &wacom->features;
|
||||
char *data = wacom->data;
|
||||
struct input_dev *input = wacom->input;
|
||||
int prox = data[1] & 0x20, pressure;
|
||||
|
||||
dbg("wacom_dtu_irq: received report #%d", data[0]);
|
||||
|
||||
if (prox) {
|
||||
/* Going into proximity select tool */
|
||||
wacom->tool[0] = (data[1] & 0x0c) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
|
||||
if (wacom->tool[0] == BTN_TOOL_PEN)
|
||||
wacom->id[0] = STYLUS_DEVICE_ID;
|
||||
else
|
||||
wacom->id[0] = ERASER_DEVICE_ID;
|
||||
}
|
||||
input_report_key(input, BTN_STYLUS, data[1] & 0x02);
|
||||
input_report_key(input, BTN_STYLUS2, data[1] & 0x10);
|
||||
input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2]));
|
||||
input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4]));
|
||||
pressure = ((data[7] & 0x01) << 8) | data[6];
|
||||
if (pressure < 0)
|
||||
pressure = features->pressure_max + pressure + 1;
|
||||
input_report_abs(input, ABS_PRESSURE, pressure);
|
||||
input_report_key(input, BTN_TOUCH, data[1] & 0x05);
|
||||
if (!prox) /* out-prox */
|
||||
wacom->id[0] = 0;
|
||||
input_report_key(input, wacom->tool[0], prox);
|
||||
input_report_abs(input, ABS_MISC, wacom->id[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int wacom_graphire_irq(struct wacom_wac *wacom)
|
||||
{
|
||||
struct wacom_features *features = &wacom->features;
|
||||
|
@ -845,6 +878,10 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
|
|||
sync = wacom_ptu_irq(wacom_wac);
|
||||
break;
|
||||
|
||||
case DTU:
|
||||
sync = wacom_dtu_irq(wacom_wac);
|
||||
break;
|
||||
|
||||
case INTUOS:
|
||||
case INTUOS3S:
|
||||
case INTUOS3:
|
||||
|
@ -1030,6 +1067,7 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
|
|||
|
||||
case PL:
|
||||
case PTU:
|
||||
case DTU:
|
||||
__set_bit(BTN_TOOL_PEN, input_dev->keybit);
|
||||
__set_bit(BTN_STYLUS, input_dev->keybit);
|
||||
__set_bit(BTN_STYLUS2, input_dev->keybit);
|
||||
|
@ -1155,6 +1193,10 @@ static const struct wacom_features wacom_features_0xC6 =
|
|||
{ "Wacom Cintiq 12WX", WACOM_PKGLEN_INTUOS, 53020, 33440, 1023, 63, WACOM_BEE };
|
||||
static const struct wacom_features wacom_features_0xC7 =
|
||||
{ "Wacom DTU1931", WACOM_PKGLEN_GRAPHIRE, 37832, 30305, 511, 0, PL };
|
||||
static const struct wacom_features wacom_features_0xCE =
|
||||
{ "Wacom DTU2231", WACOM_PKGLEN_GRAPHIRE, 47864, 27011, 511, 0, DTU };
|
||||
static const struct wacom_features wacom_features_0xF0 =
|
||||
{ "Wacom DTU1631", WACOM_PKGLEN_GRAPHIRE, 34623, 19553, 511, 0, DTU };
|
||||
static const struct wacom_features wacom_features_0xCC =
|
||||
{ "Wacom Cintiq 21UX2", WACOM_PKGLEN_INTUOS, 87200, 65600, 2047, 63, WACOM_21UX2 };
|
||||
static const struct wacom_features wacom_features_0x90 =
|
||||
|
@ -1234,6 +1276,8 @@ const struct usb_device_id wacom_ids[] = {
|
|||
{ USB_DEVICE_WACOM(0xC5) },
|
||||
{ USB_DEVICE_WACOM(0xC6) },
|
||||
{ USB_DEVICE_WACOM(0xC7) },
|
||||
{ USB_DEVICE_WACOM(0xCE) },
|
||||
{ USB_DEVICE_WACOM(0xF0) },
|
||||
{ USB_DEVICE_WACOM(0xCC) },
|
||||
{ USB_DEVICE_WACOM(0x90) },
|
||||
{ USB_DEVICE_WACOM(0x93) },
|
||||
|
|
|
@ -43,6 +43,7 @@ enum {
|
|||
WACOM_G4,
|
||||
PTU,
|
||||
PL,
|
||||
DTU,
|
||||
INTUOS,
|
||||
INTUOS3S,
|
||||
INTUOS3,
|
||||
|
|
|
@ -55,37 +55,36 @@ config TOUCHSCREEN_AD7877
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called ad7877.
|
||||
|
||||
config TOUCHSCREEN_AD7879_I2C
|
||||
tristate "AD7879 based touchscreens: AD7879-1 I2C Interface"
|
||||
depends on I2C
|
||||
select TOUCHSCREEN_AD7879
|
||||
config TOUCHSCREEN_AD7879
|
||||
tristate "Analog Devices AD7879-1/AD7889-1 touchscreen interface"
|
||||
help
|
||||
Say Y here if you have a touchscreen interface using the
|
||||
AD7879-1/AD7889-1 controller, and your board-specific
|
||||
initialization code includes that in its table of I2C devices.
|
||||
Say Y here if you want to support a touchscreen interface using
|
||||
the AD7879-1/AD7889-1 controller.
|
||||
|
||||
If unsure, say N (but it's safe to say "Y").
|
||||
You should select a bus connection too.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called ad7879.
|
||||
|
||||
config TOUCHSCREEN_AD7879_I2C
|
||||
tristate "support I2C bus connection"
|
||||
depends on TOUCHSCREEN_AD7879 && I2C
|
||||
help
|
||||
Say Y here if you have AD7879-1/AD7889-1 hooked to an I2C bus.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called ad7879-i2c.
|
||||
|
||||
config TOUCHSCREEN_AD7879_SPI
|
||||
tristate "AD7879 based touchscreens: AD7879 SPI Interface"
|
||||
depends on SPI_MASTER && TOUCHSCREEN_AD7879_I2C = n
|
||||
select TOUCHSCREEN_AD7879
|
||||
tristate "support SPI bus connection"
|
||||
depends on TOUCHSCREEN_AD7879 && SPI_MASTER
|
||||
help
|
||||
Say Y here if you have a touchscreen interface using the
|
||||
AD7879/AD7889 controller, and your board-specific initialization
|
||||
code includes that in its table of SPI devices.
|
||||
Say Y here if you have AD7879-1/AD7889-1 hooked to a SPI bus.
|
||||
|
||||
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 ad7879.
|
||||
|
||||
config TOUCHSCREEN_AD7879
|
||||
tristate
|
||||
default n
|
||||
module will be called ad7879-spi.
|
||||
|
||||
config TOUCHSCREEN_BITSY
|
||||
tristate "Compaq iPAQ H3600 (Bitsy) touchscreen"
|
||||
|
@ -99,6 +98,20 @@ config TOUCHSCREEN_BITSY
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called h3600_ts_input.
|
||||
|
||||
config TOUCHSCREEN_CY8CTMG110
|
||||
tristate "cy8ctmg110 touchscreen"
|
||||
depends on I2C
|
||||
depends on GPIOLIB
|
||||
|
||||
help
|
||||
Say Y here if you have a cy8ctmg110 capacitive touchscreen on
|
||||
an AAVA device.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called cy8ctmg110_ts.
|
||||
|
||||
config TOUCHSCREEN_DA9034
|
||||
tristate "Touchscreen support for Dialog Semiconductor DA9034"
|
||||
depends on PMIC_DA903X
|
||||
|
@ -292,6 +305,18 @@ config TOUCHSCREEN_PENMOUNT
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called penmount.
|
||||
|
||||
config TOUCHSCREEN_QT602240
|
||||
tristate "QT602240 I2C Touchscreen"
|
||||
depends on I2C
|
||||
help
|
||||
Say Y here if you have the AT42QT602240/ATMXT224 I2C touchscreen
|
||||
connected to your system.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called qt602240_ts.
|
||||
|
||||
config TOUCHSCREEN_MIGOR
|
||||
tristate "Renesas MIGO-R touchscreen"
|
||||
depends on SH_MIGOR && I2C
|
||||
|
@ -540,9 +565,9 @@ config TOUCHSCREEN_USB_ZYTRONIC
|
|||
bool "Zytronic controller" if EMBEDDED
|
||||
depends on TOUCHSCREEN_USB_COMPOSITE
|
||||
|
||||
config TOUCHSCREEN_USB_ETT_TC5UH
|
||||
config TOUCHSCREEN_USB_ETT_TC45USB
|
||||
default y
|
||||
bool "ET&T TC5UH touchscreen controler support" if EMBEDDED
|
||||
bool "ET&T USB series TC4UM/TC5UH touchscreen controler support" if EMBEDDED
|
||||
depends on TOUCHSCREEN_USB_COMPOSITE
|
||||
|
||||
config TOUCHSCREEN_USB_NEXIO
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче