linux-moblin: add 2.6.33.2 kernel from MeeGo 1.0

Signed-off-by: Joshua Lock <josh@linux.intel.com>
This commit is contained in:
Joshua Lock 2010-05-18 14:51:13 +01:00
parent 5e07bc9128
commit 5e8c7c54a9
99 changed files with 277877 additions and 0 deletions

View File

@ -0,0 +1,124 @@
#
# This file is an overlay over config-generic.
# Only options different from config-generic
# belong here!!!
#
CONFIG_LOCALVERSION="-menlow"
CONFIG_INTEL_MENLOW=y
# CONFIG_DRM_MRST_AAVA is not set
CONFIG_DRM_MRST_CDK=y
CONFIG_IMG_DOES_NOT_SUPPORT_MENLOW=y
CONFIG_AGP=y
CONFIG_DRM=y
# MRST Poulsbo gfx driver
CONFIG_DRM_MRST=y
CONFIG_PVR_RELEASE="release"
CONFIG_PVR_SERVICES4=y
CONFIG_PVR_XOPEN_SOURCE=600
CONFIG_PVR2D_VALIDATE_INPUT_PARAMS=y
CONFIG_PVR_DISPLAY_CONTROLLER="mrstlfb"
CONFIG_PVR_SGX_CORE_REV=121
CONFIG_PVR_SUPPORT_SVRINIT=y
CONFIG_PVR_SUPPORT_SGX=y
CONFIG_PVR_SUPPORT_PERCONTEXT_PB=y
CONFIG_PVR_SUPPORT_LINUX_X86_WRITECOMBINE=y
CONFIG_PVR_TRANSFER_QUEUE=y
CONFIG_PVR_SUPPORT_DRI_DRM=y
CONFIG_PVR_SYS_USING_INTERRUPTS=y
CONFIG_PVR_SUPPORT_HW_RECOVERY=y
CONFIG_PVR_SUPPORT_POWER_MANAGEMENT=y
CONFIG_PVR_SECURE_HANDLES=y
CONFIG_PVR_USE_PTHREADS=y
CONFIG_PVR_SUPPORT_SGX_EVENT_OBJECT=y
CONFIG_PVR_SUPPORT_SGX_HWPERF=y
CONFIG_PVR_SUPPORT_SGX_LOW_LATENCY_SCHEDULING=y
CONFIG_PVR_SUPPORT_LINUX_X86_PAT=y
CONFIG_PVR_PROC_USE_SEQ_FILE=y
CONFIG_PVR_SUPPORT_SGX535=y
# CONFIG_PVR_SUPPORT_CACHEFLUSH_ON_ALLOC is not set
# CONFIG_PVR_SUPPORT_MEMINFO_IDS is not set
CONFIG_PVR_SUPPORT_CACHE_LINE_FLUSH=y
CONFIG_PVR_SUPPORT_CPU_CACHED_BUFFERS=y
CONFIG_PVR_DEBUG_MESA_OGL_TRACE=y
# CONFIG_VGASTATE is not set
CONFIG_VIDEO_OUTPUT_CONTROL=y
CONFIG_FB=y
CONFIG_FIRMWARE_EDID=y
# CONFIG_FB_DDC is not set
CONFIG_FB_BOOT_VESA_SUPPORT=y
CONFIG_FB_CFB_FILLRECT=y
CONFIG_FB_CFB_COPYAREA=y
CONFIG_FB_CFB_IMAGEBLIT=y
# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
# CONFIG_FB_SYS_FILLRECT is not set
# CONFIG_FB_SYS_COPYAREA is not set
# CONFIG_FB_SYS_IMAGEBLIT is not set
# CONFIG_FB_FOREIGN_ENDIAN is not set
# CONFIG_FB_SYS_FOPS is not set
# CONFIG_FB_SVGALIB is not set
# CONFIG_FB_MACMODES is not set
# CONFIG_FB_BACKLIGHT is not set
CONFIG_FB_MODE_HELPERS=y
# CONFIG_FB_TILEBLITTING is not set
#
# Frame buffer hardware drivers
#
# CONFIG_FB_CIRRUS is not set
# CONFIG_FB_PM2 is not set
# CONFIG_FB_CYBER2000 is not set
# CONFIG_FB_ARC is not set
# CONFIG_FB_ASILIANT is not set
# CONFIG_FB_IMSTT is not set
# CONFIG_FB_VGA16 is not set
CONFIG_FB_VESA=y
# CONFIG_FB_N411 is not set
# CONFIG_FB_HGA is not set
# CONFIG_FB_S1D13XXX is not set
# CONFIG_FB_NVIDIA is not set
# CONFIG_FB_RIVA is not set
# CONFIG_FB_LE80578 is not set
# CONFIG_FB_MATROX is not set
# CONFIG_FB_RADEON is not set
# CONFIG_FB_ATY128 is not set
# CONFIG_FB_ATY is not set
# CONFIG_FB_S3 is not set
# CONFIG_FB_SAVAGE is not set
# CONFIG_FB_SIS is not set
# CONFIG_FB_VIA is not set
# CONFIG_FB_NEOMAGIC is not set
# CONFIG_FB_KYRO is not set
# CONFIG_FB_3DFX is not set
# CONFIG_FB_VOODOO1 is not set
# CONFIG_FB_VT8623 is not set
# CONFIG_FB_TRIDENT is not set
# CONFIG_FB_ARK is not set
# CONFIG_FB_PM3 is not set
# CONFIG_FB_CARMINE is not set
# CONFIG_FB_GEODE is not set
# CONFIG_FB_VIRTUAL is not set
# CONFIG_FB_METRONOME is not set
# CONFIG_FB_MB862XX is not set
# CONFIG_FB_BROADSHEET is not set
CONFIG_BACKLIGHT_LCD_SUPPORT=y
CONFIG_LCD_CLASS_DEVICE=y
# CONFIG_LCD_ILI9320 is not set
CONFIG_LCD_PLATFORM=y
CONFIG_BACKLIGHT_CLASS_DEVICE=y
CONFIG_BACKLIGHT_GENERIC=y
# CONFIG_BACKLIGHT_PROGEAR is not set
# CONFIG_BACKLIGHT_MBP_NVIDIA is not set
# CONFIG_BACKLIGHT_SAHARA is not set
#
# Display device support
#
CONFIG_DISPLAY_SUPPORT=y
# CONFIG_DRM_I915 is not set
# CONFIG_DRM_I915_KMS is not set

View File

@ -0,0 +1,73 @@
CONFIG_LOCALVERSION="-netbook"
CONFIG_ACER_WMI=y
CONFIG_EEEPC_LAPTOP=m
CONFIG_SAMSUNG_LAPTOP=m
CONFIG_R8169=y
# CONFIG_R8169_VLAN is not set
CONFIG_ATL1E=y
CONFIG_ATL1C=m
CONFIG_ATH5K=y
# CONFIG_ATH5K_DEBUG is not set
CONFIG_RT2860=m
CONFIG_RTL8187SE=m
CONFIG_INTEL_MENLOW=y
CONFIG_DRM_MGA=m
CONFIG_DRM_I915_KMS=y
CONFIG_FRAMEBUFFER_CONSOLE=y
CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
CONFIG_FONTS=y
CONFIG_FONT_8x8=y
CONFIG_FONT_6x11=y
CONFIG_FONT_7x14=y
# CONFIG_FONT_PEARL_8x8 is not set
# CONFIG_FONT_ACORN_8x8 is not set
# CONFIG_FONT_MINI_4x6 is not set
# CONFIG_FONT_SUN8x16 is not set
# CONFIG_FONT_SUN12x22 is not set
CONFIG_FONT_10x18=y
#
# Enable KVM
#
CONFIG_VIRTUALIZATION=y
CONFIG_KVM=m
CONFIG_KVM_INTEL=m
# CONFIG_KVM_AMD is not set
# CONFIG_KVM_TRACE is not set
# CONFIG_VIRTIO_PCI is not set
# CONFIG_VIRTIO_BALLOON is not set
#
# For VMWARE support
#
CONFIG_FUSION_SPI=y
CONFIG_SND_ENS1371=m
CONFIG_HOTPLUG_PCI=y
CONFIG_HOTPLUG_PCI_PCIE=m
CONFIG_HOTPLUG_PCI_ACPI=m
CONFIG_HOTPLUG_PCI_ACPI_IBM=m
#
# Enable eCryptfs
#
CONFIG_KEYS=y
# CONFIG_KEYS_DEBUG_PROC_KEYS is not set
CONFIG_ECRYPT_FS=m

View File

@ -0,0 +1,147 @@
From 8642463d981c93d188814b11fdc81e17719aab05 Mon Sep 17 00:00:00 2001
From: Yong Wang <yong.y.wang@intel.com>
Date: Fri, 5 Feb 2010 10:07:51 +0800
Subject: [PATCH] kbuild: add a "nonintconfig" option to the Makefile
Add a "nonintconfig" option to the Makefile needed for
unattended builds.
This patch is from Arjan ven de Ven <arjan@linux.intel.com>
Signed-off-by: Yong Wang <yong.y.wang@intel.com>
---
scripts/kconfig/Makefile | 5 +++++
scripts/kconfig/conf.c | 36 ++++++++++++++++++++++++++++++++----
2 files changed, 37 insertions(+), 4 deletions(-)
diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile
index 999e8a7..fb3cdee 100644
--- a/scripts/kconfig/Makefile
+++ b/scripts/kconfig/Makefile
@@ -30,6 +30,11 @@ silentoldconfig: $(obj)/conf
$(Q)mkdir -p include/generated
$< -s $(Kconfig)
+nonint_oldconfig: $(obj)/conf
+ $< -b $(Kconfig)
+loose_nonint_oldconfig: $(obj)/conf
+ $< -B $(Kconfig)
+
localmodconfig: $(obj)/streamline_config.pl $(obj)/conf
$(Q)perl $< $(srctree) $(Kconfig) > .tmp.config
$(Q)if [ -f .config ]; then \
diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c
index 9960d1c..bf6a528 100644
--- a/scripts/kconfig/conf.c
+++ b/scripts/kconfig/conf.c
@@ -23,6 +23,8 @@ enum {
ask_all,
ask_new,
ask_silent,
+ dont_ask,
+ dont_ask_dont_tell,
set_default,
set_yes,
set_mod,
@@ -38,6 +40,8 @@ static int conf_cnt;
static char line[128];
static struct menu *rootEntry;
+static int return_value = 0;
+
static void print_help(struct menu *menu)
{
struct gstr help = str_new();
@@ -360,7 +364,10 @@ static void conf(struct menu *menu)
switch (prop->type) {
case P_MENU:
- if (input_mode == ask_silent && rootEntry != menu) {
+ if ((input_mode == ask_silent ||
+ input_mode == dont_ask ||
+ input_mode == dont_ask_dont_tell) &&
+ rootEntry != menu) {
check_conf(menu);
return;
}
@@ -418,12 +425,21 @@ static void check_conf(struct menu *menu)
if (sym && !sym_has_value(sym)) {
if (sym_is_changable(sym) ||
(sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) {
+ if (input_mode == dont_ask ||
+ input_mode == dont_ask_dont_tell) {
+ if (input_mode == dont_ask &&
+ sym->name && !sym_is_choice_value(sym)) {
+ fprintf(stderr,"CONFIG_%s\n",sym->name);
+ ++return_value;
+ }
+ } else {
if (!conf_cnt++)
printf(_("*\n* Restart config...\n*\n"));
rootEntry = menu_get_parent_menu(menu);
conf(rootEntry);
}
}
+ }
for (child = menu->list; child; child = child->next)
check_conf(child);
@@ -439,7 +455,7 @@ int main(int ac, char **av)
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
- while ((opt = getopt(ac, av, "osdD:nmyrh")) != -1) {
+ while ((opt = getopt(ac, av, "osbBdD:nmyrh")) != -1) {
switch (opt) {
case 'o':
input_mode = ask_silent;
@@ -448,6 +464,12 @@ int main(int ac, char **av)
input_mode = ask_silent;
sync_kconfig = 1;
break;
+ case 'b':
+ input_mode = dont_ask;
+ break;
+ case 'B':
+ input_mode = dont_ask_dont_tell;
+ break;
case 'd':
input_mode = set_default;
break;
@@ -525,6 +547,8 @@ int main(int ac, char **av)
case ask_silent:
case ask_all:
case ask_new:
+ case dont_ask:
+ case dont_ask_dont_tell:
conf_read(NULL);
break;
case set_no:
@@ -586,12 +610,16 @@ int main(int ac, char **av)
conf(&rootmenu);
input_mode = ask_silent;
/* fall through */
+ case dont_ask:
+ case dont_ask_dont_tell:
case ask_silent:
/* Update until a loop caused no more changes */
do {
conf_cnt = 0;
check_conf(&rootmenu);
- } while (conf_cnt);
+ } while (conf_cnt &&
+ (input_mode != dont_ask &&
+ input_mode != dont_ask_dont_tell));
break;
}
@@ -613,5 +641,5 @@ int main(int ac, char **av)
exit(1);
}
}
- return 0;
+ return return_value;
}
--
1.5.5.1

View File

@ -0,0 +1,60 @@
commit 0f592e33934bf6108e33e34f00b425f98ee833ef
Author: Matthew Garrett <mjg@redhat.com>
Date: Wed Jul 8 19:04:23 2009 +0100
usb: Allow drivers to enable USB autosuspend on a per-device basis
USB autosuspend is currently only enabled by default for hubs. On other
hardware the decision is made by userspace. This is unnecessary in cases
where we know that the hardware supports autosuspend, so this patch adds
a function to allow drivers to enable it at probe time.
Signed-off-by: Matthew Garrett <mjg@redhat.com>
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 60a45f1..06d24df 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -1648,6 +1648,20 @@ void usb_autopm_put_interface_async(struct usb_interface *intf)
EXPORT_SYMBOL_GPL(usb_autopm_put_interface_async);
/**
+ * usb_device_autosuspend_enable - enable autosuspend on a device
+ * @udev: the usb_device to be autosuspended
+ *
+ * This routine should be called by an interface driver when it knows that
+ * the device in question supports USB autosuspend.
+ *
+ */
+void usb_device_autosuspend_enable(struct usb_device *udev)
+{
+ udev->autosuspend_disabled = 0;
+}
+EXPORT_SYMBOL_GPL(usb_device_autosuspend_enable);
+
+/**
* usb_autopm_get_interface - increment a USB interface's PM-usage counter
* @intf: the usb_interface whose counter should be incremented
*
diff --git a/include/linux/usb.h b/include/linux/usb.h
index e101a2d..dd47590 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -540,6 +540,7 @@ extern struct usb_device *usb_find_device(u16 vendor_id, u16 product_id);
/* USB autosuspend and autoresume */
#ifdef CONFIG_USB_SUSPEND
+extern void usb_device_autosuspend_enable(struct usb_device *udev);
extern int usb_autopm_get_interface(struct usb_interface *intf);
extern void usb_autopm_put_interface(struct usb_interface *intf);
extern int usb_autopm_get_interface_async(struct usb_interface *intf);
@@ -563,6 +564,9 @@ static inline void usb_mark_last_busy(struct usb_device *udev)
#else
+static inline void usb_device_autosuspend_enable(struct usb_device *udev)
+{ }
+
static inline int usb_autopm_get_interface(struct usb_interface *intf)
{ return 0; }
static inline int usb_autopm_get_interface_async(struct usb_interface *intf)

View File

@ -0,0 +1,11 @@
--- linux-2.6.33/drivers/bluetooth/btusb.c~ 2010-02-24 13:52:17.000000000 -0500
+++ linux-2.6.33/drivers/bluetooth/btusb.c 2010-03-23 14:36:48.301179380 -0400
@@ -1020,6 +1020,8 @@
return err;
}
+ usb_device_autosuspend_enable(data->udev);
+
usb_set_intfdata(intf, data);
return 0;

View File

@ -0,0 +1,19 @@
commit 9d4c919bcfa794c054cc33155c7e3c53ac2c5684
Author: Matthew Garrett <mjg@redhat.com>
Date: Sun Jul 19 02:24:49 2009 +0100
Enable autosuspend on UVC by default
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c
index 89927b7..8de516b 100644
--- a/drivers/media/video/uvc/uvc_driver.c
+++ b/drivers/media/video/uvc/uvc_driver.c
@@ -1647,6 +1647,8 @@ static int uvc_probe(struct usb_interface *intf,
"supported.\n", ret);
}
+ usb_device_autosuspend_enable(udev);
+
uvc_trace(UVC_TRACE_PROBE, "UVC device initialized.\n");
return 0;

View File

@ -0,0 +1,47 @@
From dce8113d033975f56630cf6d2a6a908cfb66059d Mon Sep 17 00:00:00 2001
From: Arjan van de Ven <arjan@linux.intel.com>
Date: Sun, 20 Jul 2008 13:12:16 -0700
Subject: [PATCH] fastboot: remove "wait for all devices before mounting root" delay
In the non-initrd case, we wait for all devices to finish their
probing before we try to mount the rootfs.
In practice, this means that we end up waiting 2 extra seconds for
the PS/2 mouse probing even though the root holding device has been
ready since a long time.
The previous two patches in this series made the RAID autodetect code
do it's own "wait for probing to be done" code, and added
"wait and retry" functionality in case the root device isn't actually
available.
These two changes should make it safe to remove the delay itself,
and this patch does this. On my test laptop, this reduces the boot time
by 2 seconds (kernel time goes from 3.9 to 1.9 seconds).
Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
---
---
init/do_mounts.c | 3 +++
1 file changed, 3 insertions(+)
Index: linux-2.6.29/init/do_mounts.c
===================================================================
--- linux-2.6.29.orig/init/do_mounts.c
+++ linux-2.6.29/init/do_mounts.c
@@ -370,6 +370,7 @@ void __init prepare_namespace(void)
ssleep(root_delay);
}
+#if 0
/*
* wait for the known devices to complete their probing
*
@@ -378,6 +379,8 @@ void __init prepare_namespace(void)
* for the touchpad of a laptop to initialize.
*/
wait_for_device_probe();
+#endif
+ async_synchronize_full();
md_run_setup();

View File

@ -0,0 +1,50 @@
From 5872557a54f440d8cf046714508898b173885399 Mon Sep 17 00:00:00 2001
From: Yong Wang <yong.y.wang@intel.com>
Date: Fri, 5 Feb 2010 11:19:36 +0800
Subject: [PATCH] linux-2.6.29-kms-after-sata.patch
This patch is from Arjan ven de Ven <arjan@linux.intel.com>
Signed-off-by: Yong Wang <yong.y.wang@intel.com>
---
drivers/Makefile | 15 ++++++++-------
1 files changed, 8 insertions(+), 7 deletions(-)
diff --git a/drivers/Makefile b/drivers/Makefile
index 6ee53c7..5dc6dd3 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -26,15 +26,8 @@ obj-$(CONFIG_REGULATOR) += regulator/
# default.
obj-y += char/
-# gpu/ comes after char for AGP vs DRM startup
-obj-y += gpu/
-
obj-$(CONFIG_CONNECTOR) += connector/
-# i810fb and intelfb depend on char/agp/
-obj-$(CONFIG_FB_I810) += video/i810/
-obj-$(CONFIG_FB_INTEL) += video/intelfb/
-
obj-y += serial/
obj-$(CONFIG_PARPORT) += parport/
obj-y += base/ block/ misc/ mfd/
@@ -46,6 +39,14 @@ obj-$(CONFIG_ATA) += ata/
obj-$(CONFIG_MTD) += mtd/
obj-$(CONFIG_SPI) += spi/
obj-y += net/
+
+# gpu/ comes after char for AGP vs DRM startup
+obj-y += gpu/
+
+# i810fb and intelfb depend on char/agp/
+obj-$(CONFIG_FB_I810) += video/i810/
+obj-$(CONFIG_FB_INTEL) += video/intelfb/
+
obj-$(CONFIG_ATM) += atm/
obj-$(CONFIG_FUSION) += message/
obj-$(CONFIG_FIREWIRE) += firewire/
--
1.5.5.1

View File

@ -0,0 +1,58 @@
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index a51573d..3dcf5cc 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -102,6 +102,7 @@ struct intel_output {
int type;
struct i2c_adapter *i2c_bus;
struct i2c_adapter *ddc_bus;
+ struct edid *edid;
bool load_detect_temp;
bool needs_tv_clock;
void *dev_priv;
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index 3118ce2..fa0299e 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -716,6 +716,7 @@ static void intel_lvds_destroy(struct drm_connector *connector)
acpi_lid_notifier_unregister(&dev_priv->lid_notifier);
drm_sysfs_connector_remove(connector);
drm_connector_cleanup(connector);
+ kfree(intel_output->edid);
kfree(connector);
}
@@ -1189,5 +1190,6 @@ failed:
intel_i2c_destroy(intel_output->ddc_bus);
drm_connector_cleanup(connector);
drm_encoder_cleanup(encoder);
+ kfree(intel_output->edid);
kfree(intel_output);
}
diff --git a/drivers/gpu/drm/i915/intel_modes.c b/drivers/gpu/drm/i915/intel_modes.c
index 67e2f46..5ac537f 100644
--- a/drivers/gpu/drm/i915/intel_modes.c
+++ b/drivers/gpu/drm/i915/intel_modes.c
@@ -74,6 +74,10 @@ int intel_ddc_get_modes(struct intel_output *intel_output)
int ret = 0;
intel_i2c_quirk_set(intel_output->base.dev, true);
+ if (intel_output->edid && intel_output->type == INTEL_OUTPUT_LVDS) {
+ printk(KERN_INFO "Skipping EDID probe due to cached edid\n");
+ return ret;
+ }
edid = drm_get_edid(&intel_output->base, intel_output->ddc_bus);
intel_i2c_quirk_set(intel_output->base.dev, false);
if (edid) {
@@ -81,7 +85,10 @@ int intel_ddc_get_modes(struct intel_output *intel_output)
edid);
ret = drm_add_edid_modes(&intel_output->base, edid);
intel_output->base.display_info.raw_edid = NULL;
- kfree(edid);
+ if (intel_output->type == INTEL_OUTPUT_LVDS)
+ intel_output->edid = edid;
+ else
+ kfree(edid);
}
return ret;

View File

@ -0,0 +1,137 @@
From 5da92dfa0047f40221e96162c768cd12e063fa0c Mon Sep 17 00:00:00 2001
From: Yong Wang <yong.y.wang@intel.com>
Date: Fri, 5 Feb 2010 10:22:01 +0800
Subject: [PATCH] linux-2.6.29-kms-run-async.patch
This patch is from Arjan ven de Ven <arjan@linux.intel.com>
Signed-off-by: Yong Wang <yong.y.wang@intel.com>
---
drivers/gpu/drm/drm_crtc_helper.c | 22 ++++++++++++++++++++--
drivers/gpu/drm/drm_drv.c | 4 ++++
drivers/gpu/drm/i915/i915_dma.c | 2 +-
include/drm/drmP.h | 1 +
include/drm/drm_crtc_helper.h | 1 +
5 files changed, 27 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index 7d0f00a..1f814b4 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -29,6 +29,8 @@
* Jesse Barnes <jesse.barnes@intel.com>
*/
+#include <linux/async.h>
+
#include "drmP.h"
#include "drm_crtc.h"
#include "drm_crtc_helper.h"
@@ -54,6 +56,8 @@ static void drm_mode_validate_flag(struct drm_connector *connector,
return;
}
+LIST_HEAD(drm_async_list);
+
/**
* drm_helper_probe_connector_modes - get complete set of display modes
* @dev: DRM device
@@ -1002,6 +1006,7 @@ bool drm_helper_plugged_event(struct drm_device *dev)
/* FIXME: send hotplug event */
return true;
}
+
/**
* drm_initial_config - setup a sane initial connector configuration
* @dev: DRM device
@@ -1037,13 +1042,26 @@ bool drm_helper_initial_config(struct drm_device *dev)
drm_setup_crtcs(dev);
- /* alert the driver fb layer */
dev->mode_config.funcs->fb_changed(dev);
-
return 0;
}
EXPORT_SYMBOL(drm_helper_initial_config);
+static void drm_helper_initial_config_helper(void *ptr, async_cookie_t cookie)
+{
+ struct drm_device *dev = ptr;
+ drm_helper_initial_config(dev);
+}
+
+void drm_helper_initial_config_async(struct drm_device *dev)
+{
+ async_schedule_domain(drm_helper_initial_config_helper,
+ dev, &drm_async_list);
+}
+EXPORT_SYMBOL(drm_helper_initial_config_async);
+
+
+
static int drm_helper_choose_encoder_dpms(struct drm_encoder *encoder)
{
int dpms = DRM_MODE_DPMS_OFF;
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 766c468..1a0bf76 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -49,6 +49,7 @@
#include <linux/debugfs.h>
#include "drmP.h"
#include "drm_core.h"
+#include <linux/async.h>
static int drm_version(struct drm_device *dev, void *data,
@@ -292,6 +293,9 @@ void drm_exit(struct drm_driver *driver)
struct drm_device *dev, *tmp;
DRM_DEBUG("\n");
+ /* make sure all async DRM operations are finished */
+ async_synchronize_full_domain(&drm_async_list);
+
if (driver->driver_features & DRIVER_MODESET) {
pci_unregister_driver(&driver->pci_driver);
} else {
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index e660ac0..3ffce27 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1274,7 +1274,7 @@ static int i915_load_modeset_init(struct drm_device *dev,
I915_WRITE(INSTPM, (1 << 5) | (1 << 21));
- drm_helper_initial_config(dev);
+ drm_helper_initial_config_async(dev);
return 0;
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index ffac157..4bbd7b5 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -323,6 +323,7 @@ struct drm_vma_entry {
pid_t pid;
};
+extern struct list_head drm_async_list;
/**
* DMA buffer.
*/
diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h
index b29e201..38ed420 100644
--- a/include/drm/drm_crtc_helper.h
+++ b/include/drm/drm_crtc_helper.h
@@ -98,6 +98,7 @@ extern int drm_helper_probe_single_connector_modes(struct drm_connector *connect
extern void drm_helper_disable_unused_functions(struct drm_device *dev);
extern int drm_helper_hotplug_stage_two(struct drm_device *dev);
extern bool drm_helper_initial_config(struct drm_device *dev);
+extern void drm_helper_initial_config_async(struct drm_device *dev);
extern int drm_crtc_helper_set_config(struct drm_mode_set *set);
extern bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
struct drm_display_mode *mode,
--
1.5.5.1

View File

@ -0,0 +1,22 @@
From: Arjan van de Ven <arjan@linux.intel.com>
Date: Fri, 23 Jan 2009
Small fix changing error msg to info msg in acer wmi driver
---
---
drivers/platform/x86/acer-wmi.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
Index: linux-2.6.29/drivers/platform/x86/acer-wmi.c
===================================================================
--- linux-2.6.29.orig/drivers/platform/x86/acer-wmi.c
+++ linux-2.6.29/drivers/platform/x86/acer-wmi.c
@@ -1290,7 +1290,7 @@ static int __init acer_wmi_init(void)
AMW0_find_mailled();
if (!interface) {
- printk(ACER_ERR "No or unsupported WMI interface, unable to "
+ printk(ACER_INFO "No or unsupported WMI interface, unable to "
"load\n");
return -ENODEV;
}

View File

@ -0,0 +1,96 @@
From 4d690855d6bdc15b753ac3c21bf507ad94d46aac Mon Sep 17 00:00:00 2001
From: Arjan van de Ven <arjan@linux.intel.com>
Date: Sun, 21 Sep 2008 11:58:27 -0700
Subject: [PATCH] superreadahead patch
---
fs/ext3/ioctl.c | 3 +++
fs/ext3/super.c | 1 +
include/linux/ext3_fs.h | 1 +
include/linux/fs.h | 2 ++
4 files changed, 7 insertions(+), 0 deletions(-)
diff --git a/fs/ext3/ioctl.c b/fs/ext3/ioctl.c
index 8897481..08f4854 100644
--- a/fs/ext3/ioctl.c
+++ b/fs/ext3/ioctl.c
@@ -276,6 +276,9 @@ group_add_out:
mnt_drop_write(filp->f_path.mnt);
return err;
}
+ case EXT3_IOC_INODE_JIFFIES: {
+ return inode->created_when;
+ }
default:
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index 524b349..e6e8514 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -466,6 +466,7 @@ static struct inode *ext3_alloc_inode(struct super_block *sb)
return NULL;
ei->i_block_alloc_info = NULL;
ei->vfs_inode.i_version = 1;
+ ei->vfs_inode.created_when = jiffies;
atomic_set(&ei->i_datasync_tid, 0);
atomic_set(&ei->i_sync_tid, 0);
return &ei->vfs_inode;
diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h
index 634a5e5..84d5394 100644
--- a/include/linux/ext3_fs.h
+++ b/include/linux/ext3_fs.h
@@ -250,6 +250,7 @@ struct ext3_new_group_data {
#endif
#define EXT3_IOC_GETRSVSZ _IOR('f', 5, long)
#define EXT3_IOC_SETRSVSZ _IOW('f', 6, long)
+#define EXT3_IOC_INODE_JIFFIES _IOR('f', 19, long)
/*
* ioctl commands in 32 bit emulation
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 0872372..078e3fd 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -781,6 +781,8 @@ struct inode {
struct posix_acl *i_default_acl;
#endif
void *i_private; /* fs or device private pointer */
+
+ unsigned long created_when; /* jiffies of creation time */
};
/*
--
1.6.0.6
--- vanilla-2.6.32-rc7/fs/btrfs/inode.c~ 2009-11-13 11:15:48.000000000 -0800
+++ vanilla-2.6.32-rc7/fs/btrfs/inode.c 2009-11-13 11:15:48.000000000 -0800
@@ -5181,6 +5181,7 @@
ei->outstanding_extents = 0;
ei->reserved_extents = 0;
ei->root = NULL;
+ ei->vfs_inode.created_when = jiffies;
spin_lock_init(&ei->accounting_lock);
btrfs_ordered_inode_tree_init(&ei->ordered_tree);
INIT_LIST_HEAD(&ei->i_orphan);
--- vanilla-2.6.32-rc7/fs/btrfs/ioctl.c~ 2009-11-13 11:16:58.000000000 -0800
+++ vanilla-2.6.32-rc7/fs/btrfs/ioctl.c 2009-11-13 11:16:58.000000000 -0800
@@ -1298,6 +1298,8 @@
return 0;
}
+#define EXT3_IOC_INODE_JIFFIES _IOR('f', 19, long)
+
long btrfs_ioctl(struct file *file, unsigned int
cmd, unsigned long arg)
{
@@ -1337,6 +1338,8 @@
case BTRFS_IOC_SYNC:
btrfs_sync_fs(file->f_dentry->d_sb, 1);
return 0;
+ case EXT3_IOC_INODE_JIFFIES:
+ return fdentry(file)->d_inode->created_when;
}
return -ENOTTY;

View File

@ -0,0 +1,14 @@
KERN_ERR is not appropriate for a printk level of a successful operation
--- linux-2.6.30/drivers/hid/hid-wacom.c~ 2009-09-04 10:37:20.000000000 -0700
+++ linux-2.6.30/drivers/hid/hid-wacom.c 2009-09-04 10:37:20.000000000 -0700
@@ -244,7 +244,7 @@
ret = hid_register_driver(&wacom_driver);
if (ret)
printk(KERN_ERR "can't register wacom driver\n");
- printk(KERN_ERR "wacom driver registered\n");
+ printk(KERN_INFO "wacom driver registered\n");
return ret;
}

View File

@ -0,0 +1,284 @@
From f62ff8c98080b4a9e66f82f793145b863b4e183a Mon Sep 17 00:00:00 2001
From: Arjan van de Ven <arjan@linux.intel.com>
Date: Fri, 13 Nov 2009 16:54:37 -0800
Subject: [PATCH] libata: Add ALPM power state accounting to the AHCI driver
PowerTOP wants to be able to show the user how effective the ALPM link
power management is for the user. ALPM is worth around 0.5W on a quiet
link; PowerTOP wants to be able to find cases where the "quiet link" isn't
actually quiet.
This patch adds state accounting functionality to the AHCI driver for
PowerTOP to use.
The parts of the patch are
1) the sysfs logic of exposing the stats for each state in sysfs
2) the basic accounting logic that gets update on link change interrupts
(or when the user accesses the info from sysfs)
3) a "accounting enable" flag; in order to get the accounting to work,
the driver needs to get phyrdy interrupts on link status changes.
Normally and currently this is disabled by the driver when ALPM is
on (to reduce overhead); when PowerTOP is running this will need
to be on to get usable statistics... hence the sysfs tunable.
The PowerTOP output currently looks like this:
Recent SATA AHCI link activity statistics
Active Partial Slumber Device name
0.5% 99.5% 0.0% host0
(work to resolve "host0" to a more human readable name is in progress)
Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
---
drivers/ata/ahci.c | 175 +++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 173 insertions(+), 2 deletions(-)
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index a3241a1..448d684 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -72,6 +72,21 @@ MODULE_PARM_DESC(ignore_sss, "Ignore staggered spinup flag (0=don't ignore, 1=ig
static int ahci_enable_alpm(struct ata_port *ap,
enum link_pm policy);
static void ahci_disable_alpm(struct ata_port *ap);
+
+static ssize_t ahci_alpm_show_active(struct device *dev,
+ struct device_attribute *attr, char *buf);
+static ssize_t ahci_alpm_show_slumber(struct device *dev,
+ struct device_attribute *attr, char *buf);
+static ssize_t ahci_alpm_show_partial(struct device *dev,
+ struct device_attribute *attr, char *buf);
+
+static ssize_t ahci_alpm_show_accounting(struct device *dev,
+ struct device_attribute *attr, char *buf);
+
+static ssize_t ahci_alpm_set_accounting(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count);
+
static ssize_t ahci_led_show(struct ata_port *ap, char *buf);
static ssize_t ahci_led_store(struct ata_port *ap, const char *buf,
size_t size);
@@ -289,6 +304,13 @@ struct ahci_host_priv {
u32 em_loc; /* enclosure management location */
};
+enum ahci_port_states {
+ AHCI_PORT_NOLINK = 0,
+ AHCI_PORT_ACTIVE = 1,
+ AHCI_PORT_PARTIAL = 2,
+ AHCI_PORT_SLUMBER = 3
+};
+
struct ahci_port_priv {
struct ata_link *active_link;
struct ahci_cmd_hdr *cmd_slot;
@@ -304,6 +326,14 @@ struct ahci_port_priv {
u32 intr_mask; /* interrupts to enable */
/* enclosure management info per PM slot */
struct ahci_em_priv em_priv[EM_MAX_SLOTS];
+
+ /* ALPM accounting state and stats */
+ unsigned int accounting_active:1;
+ u64 active_jiffies;
+ u64 partial_jiffies;
+ u64 slumber_jiffies;
+ int previous_state;
+ int previous_jiffies;
};
static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
@@ -359,6 +389,12 @@ DEVICE_ATTR(ahci_host_cap2, S_IRUGO, ahci_show_host_cap2, NULL);
DEVICE_ATTR(ahci_host_version, S_IRUGO, ahci_show_host_version, NULL);
DEVICE_ATTR(ahci_port_cmd, S_IRUGO, ahci_show_port_cmd, NULL);
+DEVICE_ATTR(ahci_alpm_active, S_IRUGO, ahci_alpm_show_active, NULL);
+DEVICE_ATTR(ahci_alpm_partial, S_IRUGO, ahci_alpm_show_partial, NULL);
+DEVICE_ATTR(ahci_alpm_slumber, S_IRUGO, ahci_alpm_show_slumber, NULL);
+DEVICE_ATTR(ahci_alpm_accounting, S_IRUGO | S_IWUSR,
+ ahci_alpm_show_accounting, ahci_alpm_set_accounting);
+
static struct device_attribute *ahci_shost_attrs[] = {
&dev_attr_link_power_management_policy,
&dev_attr_em_message_type,
@@ -367,6 +403,10 @@ static struct device_attribute *ahci_shost_attrs[] = {
&dev_attr_ahci_host_cap2,
&dev_attr_ahci_host_version,
&dev_attr_ahci_port_cmd,
+ &dev_attr_ahci_alpm_active,
+ &dev_attr_ahci_alpm_partial,
+ &dev_attr_ahci_alpm_slumber,
+ &dev_attr_ahci_alpm_accounting,
NULL
};
@@ -1165,9 +1205,14 @@ static int ahci_enable_alpm(struct ata_port *ap,
* getting woken up due to spurious phy ready interrupts
* TBD - Hot plug should be done via polling now, is
* that even supported?
+ *
+ * However, when accounting_active is set, we do want
+ * the interrupts for accounting purposes.
*/
- pp->intr_mask &= ~PORT_IRQ_PHYRDY;
- writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
+ if (!pp->accounting_active) {
+ pp->intr_mask &= ~PORT_IRQ_PHYRDY;
+ writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
+ }
/*
* Set a flag to indicate that we should ignore all PhyRdy
@@ -2157,6 +2202,141 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
ata_port_abort(ap);
}
+static int get_current_alpm_state(struct ata_port *ap)
+{
+ u32 status = 0;
+
+ ahci_scr_read(&ap->link, SCR_STATUS, &status);
+
+ /* link status is in bits 11-8 */
+ status = status >> 8;
+ status = status & 0x7;
+
+ if (status == 6)
+ return AHCI_PORT_SLUMBER;
+ if (status == 2)
+ return AHCI_PORT_PARTIAL;
+ if (status == 1)
+ return AHCI_PORT_ACTIVE;
+ return AHCI_PORT_NOLINK;
+}
+
+static void account_alpm_stats(struct ata_port *ap)
+{
+ struct ahci_port_priv *pp;
+
+ int new_state;
+ u64 new_jiffies, jiffies_delta;
+
+ if (ap == NULL)
+ return;
+ pp = ap->private_data;
+ if (!pp) return;
+
+ new_state = get_current_alpm_state(ap);
+ new_jiffies = jiffies;
+
+ jiffies_delta = new_jiffies - pp->previous_jiffies;
+
+ switch (pp->previous_state) {
+ case AHCI_PORT_NOLINK:
+ pp->active_jiffies = 0;
+ pp->partial_jiffies = 0;
+ pp->slumber_jiffies = 0;
+ break;
+ case AHCI_PORT_ACTIVE:
+ pp->active_jiffies += jiffies_delta;
+ break;
+ case AHCI_PORT_PARTIAL:
+ pp->partial_jiffies += jiffies_delta;
+ break;
+ case AHCI_PORT_SLUMBER:
+ pp->slumber_jiffies += jiffies_delta;
+ break;
+ default:
+ break;
+ }
+ pp->previous_state = new_state;
+ pp->previous_jiffies = new_jiffies;
+}
+
+static ssize_t ahci_alpm_show_active(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct ata_port *ap = ata_shost_to_port(shost);
+ struct ahci_port_priv *pp;
+
+ if (!ap)
+ return;
+ pp = ap->private_data;
+ account_alpm_stats(ap);
+
+ return sprintf(buf, "%u\n", jiffies_to_msecs(pp->active_jiffies));
+}
+
+static ssize_t ahci_alpm_show_partial(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct ata_port *ap = ata_shost_to_port(shost);
+ struct ahci_port_priv *pp = ap->private_data;
+
+ account_alpm_stats(ap);
+
+ return sprintf(buf, "%u\n", jiffies_to_msecs(pp->partial_jiffies));
+}
+
+static ssize_t ahci_alpm_show_slumber(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct ata_port *ap = ata_shost_to_port(shost);
+ struct ahci_port_priv *pp = ap->private_data;
+
+ account_alpm_stats(ap);
+
+ return sprintf(buf, "%u\n", jiffies_to_msecs(pp->slumber_jiffies));
+}
+
+
+static ssize_t ahci_alpm_show_accounting(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct ata_port *ap = ata_shost_to_port(shost);
+ struct ahci_port_priv *pp = ap->private_data;
+
+ return sprintf(buf, "%u\n", pp->accounting_active);
+}
+
+static ssize_t ahci_alpm_set_accounting(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long flags;
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct ata_port *ap = ata_shost_to_port(shost);
+ struct ahci_port_priv *pp = ap->private_data;
+ void __iomem *port_mmio = ahci_port_base(ap);
+
+ if (!pp)
+ return 1;
+ if (buf[0] == '0')
+ pp->accounting_active = 0;
+ if (buf[0] == '1')
+ pp->accounting_active = 1;
+
+ /* we need to enable the PHYRDY interrupt when we want accounting */
+ if (pp->accounting_active) {
+ spin_lock_irqsave(ap->lock, flags);
+ pp->intr_mask |= PORT_IRQ_PHYRDY;
+ writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
+ spin_unlock_irqrestore(ap->lock, flags);
+ }
+ return count;
+}
+
static void ahci_port_intr(struct ata_port *ap)
{
void __iomem *port_mmio = ahci_port_base(ap);
@@ -2182,6 +2352,7 @@ static void ahci_port_intr(struct ata_port *ap)
if ((hpriv->flags & AHCI_HFLAG_NO_HOTPLUG) &&
(status & PORT_IRQ_PHYRDY)) {
status &= ~PORT_IRQ_PHYRDY;
+ account_alpm_stats(ap);
ahci_scr_write(&ap->link, SCR_ERROR, ((1 << 16) | (1 << 18)));
}
--
1.6.0.6

View File

@ -0,0 +1,53 @@
From: Yong Wang <yong.y.wang@intel.com>
Date: Thu Mar 11 15:31:50 2010 +0800
Subject: [PATCH] ahci: Fix accounting oops on dummy port
Not all ports are implemented in AHCI mode on some machines.
If this is the case, it results in NULL pointer dereference
when doing alpm accounting. Skip such dummy ports.
Signed-off-by: Yong Wang <yong.y.wang@intel.com>
---
drivers/ata/ahci.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -2283,8 +2283,8 @@ static ssize_t ahci_alpm_show_active(str
struct ata_port *ap = ata_shost_to_port(shost);
struct ahci_port_priv *pp;
- if (!ap)
- return;
+ if (!ap || ata_port_is_dummy(ap))
+ return 0;
pp = ap->private_data;
account_alpm_stats(ap);
@@ -2298,6 +2298,8 @@ static ssize_t ahci_alpm_show_partial(st
struct ata_port *ap = ata_shost_to_port(shost);
struct ahci_port_priv *pp = ap->private_data;
+ if (!ap || ata_port_is_dummy(ap))
+ return 0;
account_alpm_stats(ap);
return sprintf(buf, "%u\n", jiffies_to_msecs(pp->partial_jiffies));
@@ -2310,6 +2312,8 @@ static ssize_t ahci_alpm_show_slumber(st
struct ata_port *ap = ata_shost_to_port(shost);
struct ahci_port_priv *pp = ap->private_data;
+ if (!ap || ata_port_is_dummy(ap))
+ return 0;
account_alpm_stats(ap);
return sprintf(buf, "%u\n", jiffies_to_msecs(pp->slumber_jiffies));
@@ -2323,6 +2327,8 @@ static ssize_t ahci_alpm_show_accounting
struct ata_port *ap = ata_shost_to_port(shost);
struct ahci_port_priv *pp = ap->private_data;
+ if (!ap || ata_port_is_dummy(ap))
+ return 0;
return sprintf(buf, "%u\n", pp->accounting_active);
}

View File

@ -0,0 +1,41 @@
From b766d59f044858ed3d149e97619a0bf5cc2873f3 Mon Sep 17 00:00:00 2001
From: Priya Vijayan <priya.vijayan@intel.com>
Date: Tue, 27 Apr 2010 13:23:28 -0700
Subject: [PATCH] workaround for aava KOSKI
Signed-off-by: Priya Vijayan <priya.vijayan@intel.com>
---
drivers/i2c/busses/i2c-mrst.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/drivers/i2c/busses/i2c-mrst.c b/drivers/i2c/busses/i2c-mrst.c
index e591a90..0737f42 100644
--- a/drivers/i2c/busses/i2c-mrst.c
+++ b/drivers/i2c/busses/i2c-mrst.c
@@ -217,6 +217,7 @@ static int mrst_i2c_disable(struct i2c_adapter *adap)
dev_dbg(&adap->dev, "i2c is busy, count is %d\n", count);
if (count++ > 10000)
return -EBUSY;
+ udelay(10);
}
/* Set IC_ENABLE to 0 */
@@ -468,6 +469,7 @@ static int xfer_read(struct i2c_adapter *adap, unsigned char *buf, int length)
reg_val = mrst_i2c_read(i2c->base + IC_STATUS);
if (count++ > MAX_T_POLL_COUNT)
goto read_loop;
+ udelay(10);
}
reg_val = mrst_i2c_read(i2c->base + IC_DATA_CMD);
@@ -522,6 +524,7 @@ static int xfer_write(struct i2c_adapter *adap,
while ((reg_val & bit_get) == 0) {
if (count++ > MAX_T_POLL_COUNT)
goto write_loop;
+ udelay(10);
reg_val = mrst_i2c_read(i2c->base + IC_STATUS);
}
--
1.6.2.2

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,48 @@
We should only send SIOCGIWAP event to notify wpa_supplicant about a lost
link, not to tell it about our disassociation being done. If we send such
event in both cases, this driver will drag wpa_supplicant into an infinite
loop.
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
---
drivers/staging/rt2860/sta/assoc.c | 6 ++++--
drivers/staging/rt2860/sta_ioctl.c | 6 ++++++
2 files changed, 10 insertions(+), 2 deletions(-)
--
Index: b/drivers/staging/rt2860/sta/assoc.c
===================================================================
--- a/drivers/staging/rt2860/sta/assoc.c 2010-01-05 11:25:22.000000000 +0100
+++ b/drivers/staging/rt2860/sta/assoc.c 2010-01-05 18:09:34.000000000 +0100
@@ -818,10 +818,11 @@ void MlmeDisassocReqAction(struct rt_rtm
COPY_MAC_ADDR(pAd->StaCfg.DisassocSta, pDisassocReq->Addr);
RTMPSetTimer(&pAd->MlmeAux.DisassocTimer, Timeout); /* in mSec */
- pAd->Mlme.AssocMachine.CurrState = DISASSOC_WAIT_RSP;
- RtmpOSWrielessEventSend(pAd, SIOCGIWAP, -1, NULL, NULL, 0);
+ pAd->Mlme.AssocMachine.CurrState = DISASSOC_WAIT_RSP;
+ if (INFRA_ON(pAd) || ADHOC_ON(pAd))
+ RtmpOSWrielessEventSend(pAd, SIOCGIWAP, -1, NULL, NULL, 0);
}
/*
Index: b/drivers/staging/rt2860/sta_ioctl.c
===================================================================
--- a/drivers/staging/rt2860/sta_ioctl.c 2010-01-05 11:25:22.000000000 +0100
+++ b/drivers/staging/rt2860/sta_ioctl.c 2010-01-05 12:55:16.000000000 +0100
@@ -602,6 +602,12 @@ int rt_ioctl_siwap(struct net_device *de
DBGPRINT(RT_DEBUG_TRACE,
("MLME busy, reset MLME state machine!\n"));
}
+
+ /* No need to set our BSSID if it's not changing */
+ if (!memcmp(pAdapter->CommonCfg.Bssid, ap_addr->sa_data, ETH_ALEN) ||
+ !memcmp(pAdapter->MlmeAux.Bssid, ap_addr->sa_data, ETH_ALEN))
+ return 0;
+
/* tell CNTL state machine to call NdisMSetInformationComplete() after completing */
/* this request, because this request is initiated by NDIS. */
pAdapter->MlmeAux.CurrReqIsFromNdis = FALSE;

View File

@ -0,0 +1,24 @@
When no SSID is set, the reconnect decision should entirely be left to
userspace. The driver should not decide which AP to associate with based on
arbitrary policies.
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
---
drivers/staging/rt2860/common/mlme.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
Index: b/drivers/staging/rt2860/common/mlme.c
===================================================================
--- a/drivers/staging/rt2860/common/mlme.c 2010-01-05 11:25:22.000000000 +0100
+++ b/drivers/staging/rt2860/common/mlme.c 2010-01-05 13:10:32.000000000 +0100
@@ -1554,7 +1554,8 @@ void MlmeAutoReconnectLastSSID(struct rt
else if ((pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) &&
(MlmeValidateSSID
(pAd->MlmeAux.AutoReconnectSsid,
- pAd->MlmeAux.AutoReconnectSsidLen) == TRUE)) {
+ pAd->MlmeAux.AutoReconnectSsidLen) == TRUE) &&
+ (pAd->MlmeAux.AutoReconnectSsidLen != 0)) {
struct rt_ndis_802_11_ssid OidSsid;
OidSsid.SsidLength = pAd->MlmeAux.AutoReconnectSsidLen;
NdisMoveMemory(OidSsid.Ssid, pAd->MlmeAux.AutoReconnectSsid,

View File

@ -0,0 +1,23 @@
diff -uNr linux-2.6.32.orig/sound/drivers/timbi2s.c linux-2.6.32.new/sound/drivers/timbi2s.c
--- linux-2.6.32.orig/sound/drivers/timbi2s.c 2010-02-10 10:48:58.000000000 -0800
+++ linux-2.6.32.new/sound/drivers/timbi2s.c 2010-02-10 10:51:46.000000000 -0800
@@ -30,6 +30,10 @@
#include <sound/initval.h>
#include <sound/timbi2s.h>
+static int index = SNDRV_DEFAULT_IDX1;
+module_param(index, int, 0444);
+MODULE_PARM_DESC(index, "Index value for Timberdale I2S.");
+
#define DRIVER_NAME "timb-i2s"
#define MAX_BUSSES 10
@@ -645,7 +649,7 @@
goto out;
}
- err = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+ err = snd_card_create(index, SNDRV_DEFAULT_STR1,
THIS_MODULE, sizeof(struct timbi2s) +
sizeof(struct timbi2s_bus) * pdata->num_busses, &card);
if (err)

View File

@ -0,0 +1,120 @@
From f56c995174cf42d84fdad06beebacd56e700b05d Mon Sep 17 00:00:00 2001
From: Arjan van de Ven <arjan@linux.intel.com>
Date: Sun, 25 Oct 2009 15:37:04 -0700
Subject: [PATCH] vfs: Add a trace point in the mark_inode_dirty function
PowerTOP would like to be able to show who is keeping the disk
busy by dirtying data. The most logical spot for this is in the vfs
in the mark_inode_dirty() function, doing this on the block level
is not possible because by the time the IO hits the block layer the
guilty party can no longer be found ("kjournald" and "pdflush" are not
useful answers to "who caused this file to be dirty).
The trace point follows the same logic/style as the block_dump code
and pretty much dumps the same data, just not to dmesg (and thus to
/var/log/messages) but via the trace events streams.
Signed-of-by: Arjan van de Ven <arjan@linux.intel.com>
---
fs/fs-writeback.c | 4 +++
fs/inode.c | 4 +++
include/trace/events/vfs.h | 53 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 61 insertions(+), 0 deletions(-)
create mode 100644 include/trace/events/vfs.h
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index 9d5360c..af31caf 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -25,6 +25,7 @@
#include <linux/blkdev.h>
#include <linux/backing-dev.h>
#include <linux/buffer_head.h>
+#include <trace/events/vfs.h>
#include "internal.h"
#define inode_to_bdi(inode) ((inode)->i_mapping->backing_dev_info)
@@ -1061,6 +1062,9 @@ void __mark_inode_dirty(struct inode *inode, int flags)
sb->s_op->dirty_inode(inode);
}
+ if (flags & (I_DIRTY_SYNC | I_DIRTY_DATASYNC | I_DIRTY_PAGES))
+ trace_dirty_inode(inode, current);
+
/*
* make sure that changes are seen by all cpus before we test i_state
* -- mikulas
diff --git a/fs/inode.c b/fs/inode.c
index 4d8e3be..a61e8ba 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -1624,3 +1624,7 @@ void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev)
inode->i_ino);
}
EXPORT_SYMBOL(init_special_inode);
+
+#define CREATE_TRACE_POINTS
+#include <trace/events/vfs.h>
+
diff --git a/include/trace/events/vfs.h b/include/trace/events/vfs.h
new file mode 100644
index 0000000..21cf9fb
--- /dev/null
+++ b/include/trace/events/vfs.h
@@ -0,0 +1,53 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM vfs
+
+#if !defined(_TRACE_VFS_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_VFS_H
+
+/*
+ * Tracepoint for dirtying an inode:
+ */
+TRACE_EVENT(dirty_inode,
+
+ TP_PROTO(struct inode *inode, struct task_struct *task),
+
+ TP_ARGS(inode, task),
+
+ TP_STRUCT__entry(
+ __array( char, comm, TASK_COMM_LEN )
+ __field( pid_t, pid )
+ __array( char, dev, 16 )
+ __array( char, file, 32 )
+ ),
+
+ TP_fast_assign(
+ if (inode->i_ino || strcmp(inode->i_sb->s_id, "bdev")) {
+ struct dentry *dentry;
+ const char *name = "?";
+
+ dentry = d_find_alias(inode);
+ if (dentry) {
+ spin_lock(&dentry->d_lock);
+ name = (const char *) dentry->d_name.name;
+ }
+
+ memcpy(__entry->comm, task->comm, TASK_COMM_LEN);
+ __entry->pid = task->pid;
+ strlcpy(__entry->file, name, 32);
+ strlcpy(__entry->dev, inode->i_sb->s_id, 16);
+
+ if (dentry) {
+ spin_unlock(&dentry->d_lock);
+ dput(dentry);
+ }
+ }
+ ),
+
+ TP_printk("task=%i (%s) file=%s dev=%s",
+ __entry->pid, __entry->comm, __entry->file, __entry->dev)
+);
+
+#endif /* _TRACE_VFS_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
--
1.6.0.6

View File

@ -0,0 +1,218 @@
From d0021b252eaf65ca07ed14f0d66425dd9ccab9a6 Mon Sep 17 00:00:00 2001
From: Neil Horman <nhorman@tuxdriver.com>
Date: Wed, 3 Mar 2010 08:31:23 +0000
Subject: [PATCH] tipc: Fix oops on send prior to entering networked mode (v3)
Patch-mainline: 2.6.34
Fix TIPC to disallow sending to remote addresses prior to entering NET_MODE
user programs can oops the kernel by sending datagrams via AF_TIPC prior to
entering networked mode. The following backtrace has been observed:
ID: 13459 TASK: ffff810014640040 CPU: 0 COMMAND: "tipc-client"
[exception RIP: tipc_node_select_next_hop+90]
RIP: ffffffff8869d3c3 RSP: ffff81002d9a5ab8 RFLAGS: 00010202
RAX: 0000000000000001 RBX: 0000000000000001 RCX: 0000000000000001
RDX: 0000000000000000 RSI: 0000000000000001 RDI: 0000000001001001
RBP: 0000000001001001 R8: 0074736575716552 R9: 0000000000000000
R10: ffff81003fbd0680 R11: 00000000000000c8 R12: 0000000000000008
R13: 0000000000000001 R14: 0000000000000001 R15: ffff810015c6ca00
ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018
RIP: 0000003cbd8d49a3 RSP: 00007fffc84e0be8 RFLAGS: 00010206
RAX: 000000000000002c RBX: ffffffff8005d116 RCX: 0000000000000000
RDX: 0000000000000008 RSI: 00007fffc84e0c00 RDI: 0000000000000003
RBP: 0000000000000000 R8: 00007fffc84e0c10 R9: 0000000000000010
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
R13: 00007fffc84e0d10 R14: 0000000000000000 R15: 00007fffc84e0c30
ORIG_RAX: 000000000000002c CS: 0033 SS: 002b
What happens is that, when the tipc module in inserted it enters a standalone
node mode in which communication to its own address is allowed <0.0.0> but not
to other addresses, since the appropriate data structures have not been
allocated yet (specifically the tipc_net pointer). There is nothing stopping a
client from trying to send such a message however, and if that happens, we
attempt to dereference tipc_net.zones while the pointer is still NULL, and
explode. The fix is pretty straightforward. Since these oopses all arise from
the dereference of global pointers prior to their assignment to allocated
values, and since these allocations are small (about 2k total), lets convert
these pointers to static arrays of the appropriate size. All the accesses to
these bits consider 0/NULL to be a non match when searching, so all the lookups
still work properly, and there is no longer a chance of a bad dererence
anywhere. As a bonus, this lets us eliminate the setup/teardown routines for
those pointers, and elimnates the need to preform any locking around them to
prevent access while their being allocated/freed.
I've updated the tipc_net structure to behave this way to fix the exact reported
problem, and also fixed up the tipc_bearers and media_list arrays to fix an
obvious simmilar problem that arises from issuing tipc-config commands to
manipulate bearers/links prior to entering networked mode
I've tested this for a few hours by running the sanity tests and stress test
with the tipcutils suite, and nothing has fallen over. There have been a few
lockdep warnings, but those were there before, and can be addressed later, as
they didn't actually result in any deadlock.
Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
CC: Allan Stephens <allan.stephens@windriver.com>
CC: David S. Miller <davem@davemloft.net>
CC: tipc-discussion@lists.sourceforge.net
bearer.c | 37 ++++++-------------------------------
bearer.h | 2 +-
net.c | 25 ++++---------------------
3 files changed, 11 insertions(+), 53 deletions(-)
Signed-off-by: David S. Miller <davem@davemloft.net>
Acked-by: Yong Wang <yong.y.wang@intel.com>
---
net/tipc/bearer.c | 37 ++++++-------------------------------
net/tipc/bearer.h | 2 +-
net/tipc/net.c | 25 ++++---------------------
3 files changed, 11 insertions(+), 53 deletions(-)
diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
index 327011f..7809137 100644
--- a/net/tipc/bearer.c
+++ b/net/tipc/bearer.c
@@ -45,10 +45,10 @@
#define MAX_ADDR_STR 32
-static struct media *media_list = NULL;
+static struct media media_list[MAX_MEDIA];
static u32 media_count = 0;
-struct bearer *tipc_bearers = NULL;
+struct bearer tipc_bearers[MAX_BEARERS];
/**
* media_name_valid - validate media name
@@ -108,9 +108,11 @@ int tipc_register_media(u32 media_type,
int res = -EINVAL;
write_lock_bh(&tipc_net_lock);
- if (!media_list)
- goto exit;
+ if (tipc_mode != TIPC_NET_MODE) {
+ warn("Media <%s> rejected, not in networked mode yet\n", name);
+ goto exit;
+ }
if (!media_name_valid(name)) {
warn("Media <%s> rejected, illegal name\n", name);
goto exit;
@@ -660,33 +662,10 @@ int tipc_disable_bearer(const char *name)
-int tipc_bearer_init(void)
-{
- int res;
-
- write_lock_bh(&tipc_net_lock);
- tipc_bearers = kcalloc(MAX_BEARERS, sizeof(struct bearer), GFP_ATOMIC);
- media_list = kcalloc(MAX_MEDIA, sizeof(struct media), GFP_ATOMIC);
- if (tipc_bearers && media_list) {
- res = 0;
- } else {
- kfree(tipc_bearers);
- kfree(media_list);
- tipc_bearers = NULL;
- media_list = NULL;
- res = -ENOMEM;
- }
- write_unlock_bh(&tipc_net_lock);
- return res;
-}
-
void tipc_bearer_stop(void)
{
u32 i;
- if (!tipc_bearers)
- return;
-
for (i = 0; i < MAX_BEARERS; i++) {
if (tipc_bearers[i].active)
tipc_bearers[i].publ.blocked = 1;
@@ -695,10 +674,6 @@ void tipc_bearer_stop(void)
if (tipc_bearers[i].active)
bearer_disable(tipc_bearers[i].publ.name);
}
- kfree(tipc_bearers);
- kfree(media_list);
- tipc_bearers = NULL;
- media_list = NULL;
media_count = 0;
}
diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h
index ca57348..000228e 100644
--- a/net/tipc/bearer.h
+++ b/net/tipc/bearer.h
@@ -114,7 +114,7 @@ struct bearer_name {
struct link;
-extern struct bearer *tipc_bearers;
+extern struct bearer tipc_bearers[];
void tipc_media_addr_printf(struct print_buf *pb, struct tipc_media_addr *a);
struct sk_buff *tipc_media_get_names(void);
diff --git a/net/tipc/net.c b/net/tipc/net.c
index 7906608..f25b1cd 100644
--- a/net/tipc/net.c
+++ b/net/tipc/net.c
@@ -116,7 +116,8 @@
*/
DEFINE_RWLOCK(tipc_net_lock);
-struct network tipc_net = { NULL };
+struct _zone *tipc_zones[256] = { NULL, };
+struct network tipc_net = { tipc_zones };
struct tipc_node *tipc_net_select_remote_node(u32 addr, u32 ref)
{
@@ -158,28 +159,12 @@ void tipc_net_send_external_routes(u32 dest)
}
}
-static int net_init(void)
-{
- memset(&tipc_net, 0, sizeof(tipc_net));
- tipc_net.zones = kcalloc(tipc_max_zones + 1, sizeof(struct _zone *), GFP_ATOMIC);
- if (!tipc_net.zones) {
- return -ENOMEM;
- }
- return 0;
-}
-
static void net_stop(void)
{
u32 z_num;
- if (!tipc_net.zones)
- return;
-
- for (z_num = 1; z_num <= tipc_max_zones; z_num++) {
+ for (z_num = 1; z_num <= tipc_max_zones; z_num++)
tipc_zone_delete(tipc_net.zones[z_num]);
- }
- kfree(tipc_net.zones);
- tipc_net.zones = NULL;
}
static void net_route_named_msg(struct sk_buff *buf)
@@ -282,9 +267,7 @@ int tipc_net_start(u32 addr)
tipc_named_reinit();
tipc_port_reinit();
- if ((res = tipc_bearer_init()) ||
- (res = net_init()) ||
- (res = tipc_cltr_init()) ||
+ if ((res = tipc_cltr_init()) ||
(res = tipc_bclink_init())) {
return res;
}
--
1.5.5.1

View File

@ -0,0 +1,320 @@
From d96b241bd2ad42b6c49d5f6435c69b23818f001e Mon Sep 17 00:00:00 2001
From: Felipe Balbi <felipe.balbi@nokia.com>
Date: Tue, 5 Jan 2010 16:10:13 +0200
Subject: [PATCH 9/10] USB: gadget: introduce g_nokia gadget driver
Patch-mainline: 2.6.34
Git-commit: f358f5b40af67caf28b627889d007294614170b2
g_nokia is the gadget driver implementing
WMCDC Wireless Handset Control Model for the N900
device.
Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/usb/gadget/Kconfig | 10 +
drivers/usb/gadget/Makefile | 2
drivers/usb/gadget/nokia.c | 259 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 271 insertions(+)
create mode 100644 drivers/usb/gadget/nokia.c
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -828,6 +828,16 @@
Say "y" to link the driver statically, or "m" to build a
dynamically linked module.
+config USB_G_NOKIA
+ tristate "Nokia composite gadget"
+ depends on PHONET
+ help
+ The Nokia composite gadget provides support for acm, obex
+ and phonet in only one composite gadget driver.
+
+ It's only really useful for N900 hardware. If you're building
+ a kernel for N900, say Y or M here. If unsure, say N.
+
config USB_G_MULTI
tristate "Multifunction Composite Gadget (EXPERIMENTAL)"
depends on BLOCK && NET
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -44,6 +44,7 @@
g_cdc-objs := cdc2.o
g_multi-objs := multi.o
g_still_image-objs := still_image.o
+g_nokia-objs := nokia.o
obj-$(CONFIG_USB_ZERO) += g_zero.o
obj-$(CONFIG_USB_AUDIO) += g_audio.o
@@ -57,6 +58,7 @@
obj-$(CONFIG_USB_CDC_COMPOSITE) += g_cdc.o
obj-$(CONFIG_USB_G_MULTI) += g_multi.o
obj-$(CONFIG_USB_STILL_IMAGE) += g_still_image.o
+obj-$(CONFIG_USB_G_NOKIA) += g_nokia.o
ifeq ($(CONFIG_USB_GADGET_DEBUG),y)
EXTRA_CFLAGS += -DDMA_PPB_MODE
--- /dev/null
+++ b/drivers/usb/gadget/nokia.c
@@ -0,0 +1,259 @@
+/*
+ * nokia.c -- Nokia Composite Gadget Driver
+ *
+ * Copyright (C) 2008-2010 Nokia Corporation
+ * Contact: Felipe Balbi <felipe.balbi@nokia.com>
+ *
+ * This gadget driver borrows from serial.c which is:
+ *
+ * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com)
+ * Copyright (C) 2008 by David Brownell
+ * Copyright (C) 2008 by Nokia Corporation
+ *
+ * This software is distributed under the terms of the GNU General
+ * Public License ("GPL") as published by the Free Software Foundation,
+ * version 2 of that License.
+ */
+
+#include <linux/kernel.h>
+#include <linux/utsname.h>
+#include <linux/device.h>
+
+#include "u_serial.h"
+#include "u_ether.h"
+#include "u_phonet.h"
+#include "gadget_chips.h"
+
+/* Defines */
+
+#define NOKIA_VERSION_NUM 0x0211
+#define NOKIA_LONG_NAME "N900 (PC-Suite Mode)"
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Kbuild is not very cooperative with respect to linking separately
+ * compiled library objects into one module. So for now we won't use
+ * separate compilation ... ensuring init/exit sections work to shrink
+ * the runtime footprint, and giving us at least some parts of what
+ * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
+ */
+#include "composite.c"
+#include "usbstring.c"
+#include "config.c"
+#include "epautoconf.c"
+
+#include "u_serial.c"
+#include "f_acm.c"
+#include "f_ecm.c"
+#include "f_obex.c"
+#include "f_serial.c"
+#include "f_phonet.c"
+#include "u_ether.c"
+
+/*-------------------------------------------------------------------------*/
+
+#define NOKIA_VENDOR_ID 0x0421 /* Nokia */
+#define NOKIA_PRODUCT_ID 0x01c8 /* Nokia Gadget */
+
+/* string IDs are assigned dynamically */
+
+#define STRING_MANUFACTURER_IDX 0
+#define STRING_PRODUCT_IDX 1
+#define STRING_DESCRIPTION_IDX 2
+
+static char manufacturer_nokia[] = "Nokia";
+static const char product_nokia[] = NOKIA_LONG_NAME;
+static const char description_nokia[] = "PC-Suite Configuration";
+
+static struct usb_string strings_dev[] = {
+ [STRING_MANUFACTURER_IDX].s = manufacturer_nokia,
+ [STRING_PRODUCT_IDX].s = NOKIA_LONG_NAME,
+ [STRING_DESCRIPTION_IDX].s = description_nokia,
+ { } /* end of list */
+};
+
+static struct usb_gadget_strings stringtab_dev = {
+ .language = 0x0409, /* en-us */
+ .strings = strings_dev,
+};
+
+static struct usb_gadget_strings *dev_strings[] = {
+ &stringtab_dev,
+ NULL,
+};
+
+static struct usb_device_descriptor device_desc = {
+ .bLength = USB_DT_DEVICE_SIZE,
+ .bDescriptorType = USB_DT_DEVICE,
+ .bcdUSB = __constant_cpu_to_le16(0x0200),
+ .bDeviceClass = USB_CLASS_COMM,
+ .idVendor = __constant_cpu_to_le16(NOKIA_VENDOR_ID),
+ .idProduct = __constant_cpu_to_le16(NOKIA_PRODUCT_ID),
+ /* .iManufacturer = DYNAMIC */
+ /* .iProduct = DYNAMIC */
+ .bNumConfigurations = 1,
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* Module */
+MODULE_DESCRIPTION("Nokia composite gadget driver for N900");
+MODULE_AUTHOR("Felipe Balbi");
+MODULE_LICENSE("GPL");
+
+/*-------------------------------------------------------------------------*/
+
+static u8 hostaddr[ETH_ALEN];
+
+static int __init nokia_bind_config(struct usb_configuration *c)
+{
+ int status = 0;
+
+ status = phonet_bind_config(c);
+ if (status)
+ printk(KERN_DEBUG "could not bind phonet config\n");
+
+ status = obex_bind_config(c, 0);
+ if (status)
+ printk(KERN_DEBUG "could not bind obex config %d\n", 0);
+
+ status = obex_bind_config(c, 1);
+ if (status)
+ printk(KERN_DEBUG "could not bind obex config %d\n", 0);
+
+ status = acm_bind_config(c, 2);
+ if (status)
+ printk(KERN_DEBUG "could not bind acm config\n");
+
+ status = ecm_bind_config(c, hostaddr);
+ if (status)
+ printk(KERN_DEBUG "could not bind ecm config\n");
+
+ return status;
+}
+
+static struct usb_configuration nokia_config_500ma_driver = {
+ .label = "Bus Powered",
+ .bind = nokia_bind_config,
+ .bConfigurationValue = 1,
+ /* .iConfiguration = DYNAMIC */
+ .bmAttributes = USB_CONFIG_ATT_ONE,
+ .bMaxPower = 250, /* 500mA */
+};
+
+static struct usb_configuration nokia_config_100ma_driver = {
+ .label = "Self Powered",
+ .bind = nokia_bind_config,
+ .bConfigurationValue = 2,
+ /* .iConfiguration = DYNAMIC */
+ .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
+ .bMaxPower = 50, /* 100 mA */
+};
+
+static int __init nokia_bind(struct usb_composite_dev *cdev)
+{
+ int gcnum;
+ struct usb_gadget *gadget = cdev->gadget;
+ int status;
+
+ status = gphonet_setup(cdev->gadget);
+ if (status < 0)
+ goto err_phonet;
+
+ status = gserial_setup(cdev->gadget, 3);
+ if (status < 0)
+ goto err_serial;
+
+ status = gether_setup(cdev->gadget, hostaddr);
+ if (status < 0)
+ goto err_ether;
+
+ status = usb_string_id(cdev);
+ if (status < 0)
+ goto err_usb;
+ strings_dev[STRING_MANUFACTURER_IDX].id = status;
+
+ device_desc.iManufacturer = status;
+
+ status = usb_string_id(cdev);
+ if (status < 0)
+ goto err_usb;
+ strings_dev[STRING_PRODUCT_IDX].id = status;
+
+ device_desc.iProduct = status;
+
+ /* config description */
+ status = usb_string_id(cdev);
+ if (status < 0)
+ goto err_usb;
+ strings_dev[STRING_DESCRIPTION_IDX].id = status;
+
+ nokia_config_500ma_driver.iConfiguration = status;
+ nokia_config_100ma_driver.iConfiguration = status;
+
+ /* set up other descriptors */
+ gcnum = usb_gadget_controller_number(gadget);
+ if (gcnum >= 0)
+ device_desc.bcdDevice = cpu_to_le16(NOKIA_VERSION_NUM);
+ else {
+ /* this should only work with hw that supports altsettings
+ * and several endpoints, anything else, panic.
+ */
+ pr_err("nokia_bind: controller '%s' not recognized\n",
+ gadget->name);
+ goto err_usb;
+ }
+
+ /* finaly register the configuration */
+ status = usb_add_config(cdev, &nokia_config_500ma_driver);
+ if (status < 0)
+ goto err_usb;
+
+ status = usb_add_config(cdev, &nokia_config_100ma_driver);
+ if (status < 0)
+ goto err_usb;
+
+ dev_info(&gadget->dev, "%s\n", NOKIA_LONG_NAME);
+
+ return 0;
+
+err_usb:
+ gether_cleanup();
+err_ether:
+ gserial_cleanup();
+err_serial:
+ gphonet_cleanup();
+err_phonet:
+ return status;
+}
+
+static int __exit nokia_unbind(struct usb_composite_dev *cdev)
+{
+ gphonet_cleanup();
+ gserial_cleanup();
+ gether_cleanup();
+
+ return 0;
+}
+
+static struct usb_composite_driver nokia_driver = {
+ .name = "g_nokia",
+ .dev = &device_desc,
+ .strings = dev_strings,
+ .bind = nokia_bind,
+ .unbind = __exit_p(nokia_unbind),
+};
+
+static int __init nokia_init(void)
+{
+ return usb_composite_register(&nokia_driver);
+}
+module_init(nokia_init);
+
+static void __exit nokia_cleanup(void)
+{
+ usb_composite_unregister(&nokia_driver);
+}
+module_exit(nokia_cleanup);
+

View File

@ -0,0 +1,85 @@
From 76ca24d389a3f5eaf11d94efab15d5bef11a0a74 Mon Sep 17 00:00:00 2001
From: Felipe Balbi <felipe.balbi@nokia.com>
Date: Thu, 17 Dec 2009 13:01:36 +0200
Subject: [PATCH 10/10] USB: otg: add notifier support
Patch-mainline: 2.6.34
Git-commit: e9a20171dfa0aa134d2211126d1310f2daea52cf
The notifier will be used to communicate usb events
to other drivers like the charger chip.
This can be used as source of information to kick
usb charger detection as described by the USB
Battery Charging Specification 1.1 and/or to
pass bMaxPower field of selected usb_configuration
to charger chip in order to use that information
as input current on the charging profile
setup.
Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
include/linux/usb/otg.h | 25 +++++++++++++++++++++++++
1 files changed, 25 insertions(+), 0 deletions(-)
diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
index 52bb917..6c0b676 100644
--- a/include/linux/usb/otg.h
+++ b/include/linux/usb/otg.h
@@ -9,6 +9,8 @@
#ifndef __LINUX_USB_OTG_H
#define __LINUX_USB_OTG_H
+#include <linux/notifier.h>
+
/* OTG defines lots of enumeration states before device reset */
enum usb_otg_state {
OTG_STATE_UNDEFINED = 0,
@@ -33,6 +35,14 @@ enum usb_otg_state {
OTG_STATE_A_VBUS_ERR,
};
+enum usb_xceiv_events {
+ USB_EVENT_NONE, /* no events or cable disconnected */
+ USB_EVENT_VBUS, /* vbus valid event */
+ USB_EVENT_ID, /* id was grounded */
+ USB_EVENT_CHARGER, /* usb dedicated charger */
+ USB_EVENT_ENUMERATED, /* gadget driver enumerated */
+};
+
#define USB_OTG_PULLUP_ID (1 << 0)
#define USB_OTG_PULLDOWN_DP (1 << 1)
#define USB_OTG_PULLDOWN_DM (1 << 2)
@@ -70,6 +80,9 @@ struct otg_transceiver {
struct otg_io_access_ops *io_ops;
void __iomem *io_priv;
+ /* for notification of usb_xceiv_events */
+ struct blocking_notifier_head notifier;
+
/* to pass extra port status to the root hub */
u16 port_status;
u16 port_change;
@@ -203,6 +216,18 @@ otg_start_srp(struct otg_transceiver *otg)
return otg->start_srp(otg);
}
+/* notifiers */
+static inline int
+otg_register_notifier(struct otg_transceiver *otg, struct notifier_block *nb)
+{
+ return blocking_notifier_chain_register(&otg->notifier, nb);
+}
+
+static inline void
+otg_unregister_notifier(struct otg_transceiver *otg, struct notifier_block *nb)
+{
+ blocking_notifier_chain_unregister(&otg->notifier, nb);
+}
/* for OTG controller drivers (and maybe other stuff) */
extern int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num);
--
1.6.0.4

View File

@ -0,0 +1,366 @@
From ff4cd0510defa74c5b9b3c1bd5c5a02b8af53fd1 Mon Sep 17 00:00:00 2001
From: Priya Vijayan <priya.vijayan@intel.com>
Date: Tue, 27 Apr 2010 14:43:04 -0700
Subject: [PATCH] Touch driver and configs for Cando dual touch panels
Added support for the Cando dual touch panels, found in the Lenovo S10-3t.
Signed-off-by: Stephane Chatty <chatty@enac.fr>
Tested-by: Priya Vijayan <priya.vijayan@intel.com>
Tested-by: Florian Echtler <floe@butterbrot.org>
Signed-off-by: Priya Vijayan <priya.vijayan@intel.com>
---
drivers/hid/Kconfig | 6 +
drivers/hid/Makefile | 1 +
drivers/hid/hid-cando.c | 268 +++++++++++++++++++++++++++++++++++++++++++++++
drivers/hid/hid-core.c | 1 +
drivers/hid/hid-ids.h | 3 +
include/linux/hid.h | 2 +-
6 files changed, 280 insertions(+), 1 deletions(-)
create mode 100644 drivers/hid/hid-cando.c
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 24d90ea..37fb241 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -80,6 +80,12 @@ config HID_BELKIN
---help---
Support for Belkin Flip KVM and Wireless keyboard.
+config HID_CANDO
+ tristate "Cando dual touch panel"
+ depends on USB_HID
+ ---help---
+ Support for Cando dual touch panel.
+
config HID_CHERRY
tristate "Cherry" if EMBEDDED
depends on USB_HID
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 0de2dff..b05f921 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -22,6 +22,7 @@ endif
obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o
obj-$(CONFIG_HID_APPLE) += hid-apple.o
obj-$(CONFIG_HID_BELKIN) += hid-belkin.o
+obj-$(CONFIG_HID_CANDO) += hid-cando.o
obj-$(CONFIG_HID_CHERRY) += hid-cherry.o
obj-$(CONFIG_HID_CHICONY) += hid-chicony.o
obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o
diff --git a/drivers/hid/hid-cando.c b/drivers/hid/hid-cando.c
new file mode 100644
index 0000000..ed8c093
--- /dev/null
+++ b/drivers/hid/hid-cando.c
@@ -0,0 +1,268 @@
+/*
+ * HID driver for Cando dual-touch panels
+ *
+ * Copyright (c) 2010 Stephane Chatty <chatty@enac.fr>
+ *
+ */
+
+/*
+ * 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/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
+MODULE_DESCRIPTION("Cando dual-touch panel");
+MODULE_LICENSE("GPL");
+
+#include "hid-ids.h"
+
+struct cando_data {
+ __u16 x, y;
+ __u8 id;
+ __s8 oldest; /* id of the oldest finger in previous frame */
+ bool valid; /* valid finger data, or just placeholder? */
+ bool first; /* is this the first finger in this frame? */
+ __s8 firstid; /* id of the first finger in the frame */
+ __u16 firstx, firsty; /* (x, y) of the first finger in the frame */
+};
+
+static int cando_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ switch (usage->hid & HID_USAGE_PAGE) {
+
+ case HID_UP_GENDESK:
+ switch (usage->hid) {
+ case HID_GD_X:
+ hid_map_usage(hi, usage, bit, max,
+ EV_ABS, ABS_MT_POSITION_X);
+ /* touchscreen emulation */
+ input_set_abs_params(hi->input, ABS_X,
+ field->logical_minimum,
+ field->logical_maximum, 0, 0);
+ return 1;
+ case HID_GD_Y:
+ hid_map_usage(hi, usage, bit, max,
+ EV_ABS, ABS_MT_POSITION_Y);
+ /* touchscreen emulation */
+ input_set_abs_params(hi->input, ABS_Y,
+ field->logical_minimum,
+ field->logical_maximum, 0, 0);
+ return 1;
+ }
+ return 0;
+
+ case HID_UP_DIGITIZER:
+ switch (usage->hid) {
+ case HID_DG_TIPSWITCH:
+ case HID_DG_CONTACTMAX:
+ return -1;
+ case HID_DG_INRANGE:
+ /* touchscreen emulation */
+ hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
+ return 1;
+ case HID_DG_CONTACTID:
+ hid_map_usage(hi, usage, bit, max,
+ EV_ABS, ABS_MT_TRACKING_ID);
+ return 1;
+ }
+ return 0;
+ }
+
+ return 0;
+}
+
+static int cando_input_mapped(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ if (usage->type == EV_KEY || usage->type == EV_ABS)
+ clear_bit(usage->code, *bit);
+
+ return 0;
+}
+
+/*
+ * this function is called when a whole finger has been parsed,
+ * so that it can decide what to send to the input layer.
+ */
+static void cando_filter_event(struct cando_data *td, struct input_dev *input)
+{
+ td->first = !td->first; /* touchscreen emulation */
+
+ if (!td->valid) {
+ /*
+ * touchscreen emulation: if this is the second finger and
+ * the first was valid, the first was the oldest; if the
+ * first was not valid and there was a valid finger in the
+ * previous frame, this is a release.
+ */
+ if (td->first) {
+ td->firstid = -1;
+ } else if (td->firstid >= 0) {
+ input_event(input, EV_ABS, ABS_X, td->firstx);
+ input_event(input, EV_ABS, ABS_Y, td->firsty);
+ td->oldest = td->firstid;
+ } else if (td->oldest >= 0) {
+ input_event(input, EV_KEY, BTN_TOUCH, 0);
+ td->oldest = -1;
+ }
+
+ return;
+ }
+
+ input_event(input, EV_ABS, ABS_MT_TRACKING_ID, td->id);
+ input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x);
+ input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y);
+
+ input_mt_sync(input);
+
+ /*
+ * touchscreen emulation: if there was no touching finger previously,
+ * emit touch event
+ */
+ if (td->oldest < 0) {
+ input_event(input, EV_KEY, BTN_TOUCH, 1);
+ td->oldest = td->id;
+ }
+
+ /*
+ * touchscreen emulation: if this is the first finger, wait for the
+ * second; the oldest is then the second if it was the oldest already
+ * or if there was no first, the first otherwise.
+ */
+ if (td->first) {
+ td->firstx = td->x;
+ td->firsty = td->y;
+ td->firstid = td->id;
+ } else {
+ int x, y, oldest;
+ if (td->id == td->oldest || td->firstid < 0) {
+ x = td->x;
+ y = td->y;
+ oldest = td->id;
+ } else {
+ x = td->firstx;
+ y = td->firsty;
+ oldest = td->firstid;
+ }
+ input_event(input, EV_ABS, ABS_X, x);
+ input_event(input, EV_ABS, ABS_Y, y);
+ td->oldest = oldest;
+ }
+}
+
+
+static int cando_event(struct hid_device *hid, struct hid_field *field,
+ struct hid_usage *usage, __s32 value)
+{
+ struct cando_data *td = hid_get_drvdata(hid);
+
+ if (hid->claimed & HID_CLAIMED_INPUT) {
+ struct input_dev *input = field->hidinput->input;
+
+ switch (usage->hid) {
+ case HID_DG_INRANGE:
+ td->valid = value;
+ break;
+ case HID_DG_CONTACTID:
+ td->id = value;
+ break;
+ case HID_GD_X:
+ td->x = value;
+ break;
+ case HID_GD_Y:
+ td->y = value;
+ cando_filter_event(td, input);
+ break;
+ case HID_DG_TIPSWITCH:
+ /* avoid interference from generic hidinput handling */
+ break;
+
+ default:
+ /* fallback to the generic hidinput handling */
+ return 0;
+ }
+ }
+
+ /* we have handled the hidinput part, now remains hiddev */
+ if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
+ hid->hiddev_hid_event(hid, field, usage, value);
+
+ return 1;
+}
+
+static int cando_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+ int ret;
+ struct cando_data *td;
+
+ td = kmalloc(sizeof(struct cando_data), GFP_KERNEL);
+ if (!td) {
+ dev_err(&hdev->dev, "cannot allocate Cando Touch data\n");
+ return -ENOMEM;
+ }
+ hid_set_drvdata(hdev, td);
+ td->first = false;
+ td->oldest = -1;
+ td->valid = false;
+
+ ret = hid_parse(hdev);
+ if (!ret)
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+
+ if (ret)
+ kfree(td);
+
+ return ret;
+}
+
+static void cando_remove(struct hid_device *hdev)
+{
+ hid_hw_stop(hdev);
+ kfree(hid_get_drvdata(hdev));
+ hid_set_drvdata(hdev, NULL);
+}
+
+static const struct hid_device_id cando_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
+ USB_DEVICE_ID_CANDO_MULTI_TOUCH) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, cando_devices);
+
+static const struct hid_usage_id cando_grabbed_usages[] = {
+ { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
+ { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
+};
+
+static struct hid_driver cando_driver = {
+ .name = "cando-touch",
+ .id_table = cando_devices,
+ .probe = cando_probe,
+ .remove = cando_remove,
+ .input_mapping = cando_input_mapping,
+ .input_mapped = cando_input_mapped,
+ .usage_table = cando_grabbed_usages,
+ .event = cando_event,
+};
+
+static int __init cando_init(void)
+{
+ return hid_register_driver(&cando_driver);
+}
+
+static void __exit cando_exit(void)
+{
+ hid_unregister_driver(&cando_driver);
+}
+
+module_init(cando_init);
+module_exit(cando_exit);
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 8455f3d..b126102 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1291,6 +1291,7 @@ static const struct hid_device_id hid_blacklist[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) },
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 793691f..6865ca2 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -116,6 +116,9 @@
#define USB_VENDOR_ID_BERKSHIRE 0x0c98
#define USB_DEVICE_ID_BERKSHIRE_PCWD 0x1140
+#define USB_VENDOR_ID_CANDO 0x2087
+#define USB_DEVICE_ID_CANDO_MULTI_TOUCH 0x0a01
+
#define USB_VENDOR_ID_CH 0x068e
#define USB_DEVICE_ID_CH_PRO_PEDALS 0x00f2
#define USB_DEVICE_ID_CH_COMBATSTICK 0x00f4
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 8709365..b978c1e 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -663,7 +663,7 @@ struct hid_ll_driver {
/* Applications from HID Usage Tables 4/8/99 Version 1.1 */
/* We ignore a few input applications that are not widely used */
-#define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || (a == 0x00010080) || (a == 0x000c0001) || (a == 0x000d0002))
+#define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || (a == 0x00010080) || (a == 0x000c0001) || ((a >= 0x000d0002) && (a <= 0x000d0006)))
/* HID core API */
--
1.6.2.2

View File

@ -0,0 +1,870 @@
From 03e11a278286392dc20de57a24cadbc16d9aac3a Mon Sep 17 00:00:00 2001
From: Priya Vijayan <priya.vijayan@intel.com>
Date: Tue, 27 Apr 2010 11:23:00 -0700
Subject: [PATCH] Touchscreen driver for Cypress panels
This driver is from aava
Signed-off-by: Priya Vijayan <priya.vijayan@intel.com>
---
drivers/input/touchscreen/Kconfig | 8 +
drivers/input/touchscreen/Makefile | 1 +
drivers/input/touchscreen/cy8ctmg110_ts.c | 815 +++++++++++++++++++++++++++++
3 files changed, 824 insertions(+), 0 deletions(-)
create mode 100644 drivers/input/touchscreen/cy8ctmg110_ts.c
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 6dd2674..5ecf00d 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -103,6 +103,14 @@ config TOUCHSCREEN_CORGI
NOTE: this driver is deprecated, try enable SPI and generic
ADS7846-based touchscreen driver.
+config TOUCHSCREEN_CY8CTMG110
+ tristate "cy8ctmg110 touchscreen"
+ depends on I2C
+ default y
+ help
+ Say Y here if you have a cy8ctmg110 touchscreen capasitive touchscreen
+ If unsure, say N.
+
config TOUCHSCREEN_DA9034
tristate "Touchscreen support for Dialog Semiconductor DA9034"
depends on PMIC_DA903X
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 15ad257..e5b5fae 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o
obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o
obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o
obj-$(CONFIG_TOUCHSCREEN_CORGI) += corgi_ts.o
+obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110) += cy8ctmg110_ts.o
obj-$(CONFIG_TOUCHSCREEN_DYNAPRO) += dynapro.o
obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o
obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o
diff --git a/drivers/input/touchscreen/cy8ctmg110_ts.c b/drivers/input/touchscreen/cy8ctmg110_ts.c
new file mode 100644
index 0000000..5587385
--- /dev/null
+++ b/drivers/input/touchscreen/cy8ctmg110_ts.c
@@ -0,0 +1,815 @@
+/*
+ * cy8ctmg110_ts.c Driver for cypress touch screen controller
+ * Copyright (c) 2009 Aava Mobile
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <asm/io.h>
+#include <linux/i2c.h>
+#include <linux/timer.h>
+#include <linux/gpio.h>
+#include <linux/hrtimer.h>
+
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <asm/ioctl.h>
+#include <asm/ipc_defs.h>
+#include <asm/uaccess.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <asm/ioctl.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+
+
+#define CY8CTMG110_DRIVER_NAME "cy8ctmg110"
+#define CY8CTMG110_DRIVER_NAME_EXT "cy8ctmg110 ext"
+/*#define MOORESTOWN_CDK*/
+/*#define CY8CTMG110_DEBUG_INFO*/
+/*#define POLL_TOUCH_EVENTS*/
+
+
+
+/*HW definations*/
+
+/*Main touch specific*/
+#define CY8CTMG110_I2C_ADDR 0x38
+#define CY8CTMG110_RESET_PIN_GPIO 43
+#define CY8CTMG110_IRQ_PIN_GPIO 59
+
+/*Extended specific*/
+#define CY8CTMG110_I2C_ADDR_EXT 0x39
+#define CY8CTMG110_RESET_PIN_GPIO_EXT 39
+#define CY8CTMG110_IRQ_PIN_GPIO_EXT 31
+
+
+#define CY8CTMG110_TOUCH_LENGHT 9787
+#define CY8CTMG110_SCREEN_LENGHT 8424
+
+
+/*Main Touch coordinates*/
+#define CY8CTMG110_X_MIN 0
+#define CY8CTMG110_Y_MIN 0
+#define CY8CTMG110_X_MAX 864
+#define CY8CTMG110_Y_MAX 480
+
+
+/*cy8ctmg110 registers defination*/
+#define CY8CTMG110_TOUCH_WAKEUP_TIME 0
+#define CY8CTMG110_TOUCH_SLEEP_TIME 2
+#define CY8CTMG110_TOUCH_X1 3
+#define CY8CTMG110_TOUCH_Y1 5
+#define CY8CTMG110_TOUCH_X2 7
+#define CY8CTMG110_TOUCH_Y2 9
+#define CY8CTMG110_FINGERS 11
+#define CY8CTMG110_GESTURE 12
+#define CY8CTMG110_VERSIONID 13 //not supported in touchpanel FW
+#define CY8CTMG110_REG_MAX 13
+
+#ifdef POLL_TOUCH_EVENTS
+ #define CY8CTMG110_POLL_TIMER_DELAY 1000*1000*100
+ #define TOUCH_MAX_I2C_FAILS 50
+#endif
+
+#define CY8CTMG110_POLL_TIMER_DELAY 1000*1000*100
+
+/* Scale factors for coordinates */
+#define X_SCALE_FACTOR 9387/8424
+#define Y_SCALE_FACTOR 97/100
+
+/* For tracing */
+static u16 g_y_trace_coord = 0;
+
+/*if soutcanyon*/
+static bool isSc = false;
+
+
+/*
+ * Touchtype
+ */
+enum touch_type {
+ TOUCH_KOSKI=1,
+ TOUCH_SC,
+ TOUCH_EXT,
+};
+
+/*
+ * The touch position structure.
+ */
+struct ts_event {
+ int x1;
+ int y1;
+ int x2;
+ int y2;
+ bool event_sended;
+};
+
+/*
+ * The touch driver structure.
+ */
+struct cy8ctmg110 {
+ struct input_dev *input;
+ char phys[32];
+ struct ts_event tc;
+ struct i2c_client *client;
+ bool pending;
+ spinlock_t lock;
+ bool initController;
+ bool sleepmode;
+ int irq_gpio;
+ int reset_gpio;
+ char driver_name[20];
+ struct delayed_work work;
+ enum touch_type version_id;
+#ifdef POLL_TOUCH_EVENTS
+ struct hrtimer timer;
+ int i2c_fail_count;
+#endif
+};
+
+/*
+ * cy8ctmg110_poweroff is the routine that is called when touch hardware
+ * will powered off
+ */
+static void cy8ctmg110_power(struct cy8ctmg110 *ts,bool poweron)
+{
+#ifdef CY8CTMG110_DEBUG_INFO
+ printk("%s power:%d\n",ts->driver_name,poweron);
+#endif
+ if (poweron)
+ gpio_direction_output(ts->reset_gpio, 0);
+ else
+ gpio_direction_output(ts->reset_gpio, 1);
+}
+/*
+ * cy8ctmg110_write_req write regs to the i2c devices
+ *
+ */
+static int cy8ctmg110_write_req(struct cy8ctmg110 *tsc,unsigned char reg,unsigned char len,unsigned char *value)
+{
+ struct i2c_client *client = tsc->client;
+ unsigned int ret;
+ unsigned char i2c_data[]={0,0,0,0,0,0};
+#ifdef CY8CTMG110_DEBUG_INFO
+ printk("cy8ctmg110_init_req:\n");
+#endif
+
+ i2c_data[0]=reg;
+ memcpy(i2c_data+1,value,len);
+
+ {
+ struct i2c_msg msg[] = {
+ { client->addr, 0, len+1, i2c_data },
+ };
+
+ ret = i2c_transfer(client->adapter, msg, 1);
+
+ if (ret != 1) {
+ printk("cy8ctmg110 touch : i2c write data cmd failed \n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+/*
+ * get_time
+ *
+ */
+#ifdef CY8CTMG110_DEBUG_INFO
+static inline long cy8ctmg110_get_time(void)
+{
+ struct timeval t;
+ do_gettimeofday(&t);
+ return t.tv_usec;
+}
+#endif
+/*
+ * cy8ctmg110_read_req read regs from i2c devise
+ *
+ */
+static int cy8ctmg110_read_req(struct cy8ctmg110 *tsc,unsigned char *i2c_data,unsigned char len ,unsigned char cmd)
+{
+ struct i2c_client *client = tsc->client;
+ unsigned int ret;
+ unsigned char regs_cmd[2]={0,0};
+#ifdef CY8CTMG110_DEBUG_INFO
+ long starttime = cy8ctmg110_get_time();
+#endif
+ regs_cmd[0]=cmd;
+
+
+ /* first write slave position to i2c devices*/
+ {
+ struct i2c_msg msg1[] = {
+ { client->addr, 0, 1, regs_cmd },
+ };
+
+ ret = i2c_transfer(client->adapter, msg1, 1);
+
+ if (ret != 1) {
+#ifdef POLL_TOUCH_EVENTS
+ tsc->i2c_fail_count++;
+#endif
+ return ret;
+ }
+ }
+
+
+ /* Second read data from position*/
+ {
+ struct i2c_msg msg2[] = {
+ { client->addr, I2C_M_RD, len, i2c_data },
+ };
+
+ ret = i2c_transfer(client->adapter, msg2, 1);
+
+
+ if (ret != 1) {
+#ifdef POLL_TOUCH_EVENTS
+ tsc->i2c_fail_count++;
+#endif
+ return ret;
+ }
+ }
+#ifdef CY8CTMG110_DEBUG_INFO
+ printk("%s time to get data bytes read:%d time:%d\n",tsc->driver_name,len,(cy8ctmg110_get_time()-starttime));
+#endif
+ return 0;
+}
+/*
+ * cy8ctmg110_send_event delevery touch event to the userpace
+ * function use normal input interface
+ */
+static void cy8ctmg110_send_event(void *tsc,int x,int y)
+{
+ struct cy8ctmg110 *ts = tsc;
+ struct input_dev *input = ts->input;
+ u16 x2, y2;
+#ifdef CY8CTMG110_DEBUG_INFO
+ printk("cy8ctmg110_send_event\n");
+#endif
+
+ if(ts->tc.event_sended == false){
+
+ if (ts->client->addr==CY8CTMG110_I2C_ADDR_EXT){
+ /*Extended touchpanel*/
+ input_report_key(input, BTN_TOUCH, 1);
+
+
+ if ( ts->pending == true){
+ input_report_rel(input, REL_Y, (ts->tc.x1-x)*2);
+ input_report_rel(input, REL_X, (y - ts->tc.y1)*3);
+ ts->tc.y1 = y;
+ ts->tc.x1 = x;
+ }
+ else{
+ ts->pending = true;
+ ts->tc.y1 = y;
+ ts->tc.x1 = x;
+ }
+
+
+ }
+ else{
+ /*Main touchpanel*/
+ ts->tc.y1 = y;
+ ts->tc.x1 = x;
+ ts->pending = true;
+ input_report_key(input, BTN_TOUCH, 1);
+
+ x2 = y;
+ y2 = x;
+
+ if (isSc == false){
+ /*Main touchpanel in koski*/
+ x2 = (u16)(y*X_SCALE_FACTOR);
+ y2 = (u16)(x*Y_SCALE_FACTOR);
+ }
+
+ input_report_abs(input, ABS_X, x2);
+ input_report_abs(input, ABS_Y, y2);
+ }
+
+ input_sync(input);
+ if(g_y_trace_coord)
+ printk("%s touch position X:%d (was = %d) Y:%d (was = %d)\n",ts->driver_name, x2, y, y2, x);
+ }
+
+}
+
+/*
+ * cy8ctmg110_touch_pos check touch position from i2c devices
+ *
+ */
+static int cy8ctmg110_touch_pos(struct cy8ctmg110 *tsc)
+{
+ unsigned char reg_p[CY8CTMG110_REG_MAX];
+
+ memset(reg_p,0,CY8CTMG110_REG_MAX);
+
+ /*Reading coordinates*/
+ if (cy8ctmg110_read_req(tsc,reg_p,1,CY8CTMG110_FINGERS)==0){
+
+ /*number of touch*/
+ if (reg_p[0]==0){
+ if (tsc->pending == true){
+ struct input_dev *input = tsc->input;
+
+ input_report_key(input, BTN_TOUCH, 0);
+
+ input_sync(input);
+ tsc->tc.event_sended = true;
+#ifdef CY8CTMG110_DEBUG_INFO
+ printk("cy8ctmg110_send_event ts->pending = true;\n");
+#endif
+ tsc->pending = false;
+ }
+ }
+ else {
+
+ if (cy8ctmg110_read_req(tsc,reg_p,4,CY8CTMG110_TOUCH_X1)==0){
+ int x = 0,y = 0;
+ y = reg_p[2]<<8 | reg_p[3];
+ x = reg_p[0]<<8 | reg_p[1];
+
+ if (tsc->tc.x1 != x || tsc->tc.y1 != y){
+ tsc->tc.event_sended = false;
+ cy8ctmg110_send_event(tsc,x,y);
+ }
+ }
+ }
+ }
+ else{
+#ifdef CY8CTMG110_DEBUG_INFO
+ printk("cy8ctmg110 i2c reading error\n");
+#endif
+ }
+
+ return 0;
+}
+/*
+ * cy8ctmg110_read_versionid delevery touch event to the userpace
+ * function use normal input interface
+ */
+static void cy8ctmg110_read_versionid(void *tsc)
+{
+ struct cy8ctmg110 *ts = tsc;
+ unsigned char reg_p[2];
+
+
+ if (cy8ctmg110_read_req(ts,reg_p,1,CY8CTMG110_VERSIONID)==0){
+ printk("%s id 0x%x\n",ts->driver_name,reg_p[0]);
+
+ /*Ugly hack solution if SC
+ */
+
+ if(ts->client->addr==CY8CTMG110_I2C_ADDR_EXT)
+ isSc = true;
+
+ switch (reg_p[0]){
+ case 0x01:
+ ts->version_id = TOUCH_EXT;
+ break;
+ case 0x02:
+ ts->version_id = TOUCH_SC;
+ break;
+ case 0x03:
+ ts->version_id = TOUCH_KOSKI;
+ break;
+ default:
+ ts->version_id = TOUCH_KOSKI;
+ break;
+ }
+ }
+}
+
+
+#ifdef POLL_TOUCH_EVENTS
+/*
+ * if interup is'n in use the touch positions can reads by polling
+ *
+ */
+static enum hrtimer_restart cy8ctmg110_timer(struct hrtimer *handle)
+{
+ struct cy8ctmg110 *ts = container_of(handle, struct cy8ctmg110, timer);
+ unsigned long flags;
+
+ spin_lock_irqsave(&ts->lock, flags);
+#ifdef CY8CTMG110_DEBUG_INFO
+ printk("cy8ctmg110_timer\n");
+#endif
+
+ cy8ctmg110_touch_pos(ts);
+
+ if (ts->i2c_fail_count<TOUCH_MAX_I2C_FAILS)
+ hrtimer_start(&ts->timer, ktime_set(0, CY8CTMG110_POLL_TIMER_DELAY),
+ HRTIMER_MODE_REL);
+
+ spin_unlock_irqrestore(&ts->lock, flags);
+
+ return HRTIMER_NORESTART;
+}
+#endif
+/*
+ * cy8ctmg110_init_controller set init value to touchcontroller
+ *
+ */
+static bool cy8ctmg110_set_sleepmode(struct cy8ctmg110 *ts)
+{
+ unsigned char reg_p[3];
+
+ if(ts->sleepmode==true){
+ reg_p[0] = 0x00; reg_p[1] =0xff; reg_p[2] =5;
+ }else{
+ reg_p[0] = 0x10;reg_p[1] =0xff;reg_p[2] =0;
+ }
+
+ if (cy8ctmg110_write_req(ts,CY8CTMG110_TOUCH_WAKEUP_TIME,3,reg_p)){
+ return false;
+ }
+ ts->initController = true;
+
+ return true;
+}
+
+
+
+static void cy8ctmg110_work(struct work_struct *work)
+{
+ struct cy8ctmg110 *ts =
+ container_of(to_delayed_work(work), struct cy8ctmg110, work);
+
+ cy8ctmg110_touch_pos(ts);
+}
+
+
+/*
+ * cy8ctmg110_irq_handler irq handling function
+ *
+ */
+static irqreturn_t cy8ctmg110_irq_handler(int irq, void *handle)
+{
+ struct cy8ctmg110 * tsc = (struct cy8ctmg110 *)handle;
+
+#ifdef CY8CTMG110_DEBUG_INFO
+ printk("%s cy8ctmg110_irq_handler\n",tsc->driver_name);
+#endif
+ if (tsc->initController == false){
+ if (cy8ctmg110_set_sleepmode(tsc) == true)
+ tsc->initController = true;
+ }
+ else
+ {
+ schedule_delayed_work(&tsc->work,
+ msecs_to_jiffies(1));
+ }
+
+#ifdef POLL_TOUCH_EVENTS
+ /*if interrupt supported in the touch controller
+ timer polling need to stop*/
+ tsc->i2c_fail_count = TOUCH_MAX_I2C_FAILS;
+#endif
+ return IRQ_HANDLED;
+}
+
+
+static int cy8ctmg110_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct cy8ctmg110 *ts;
+ struct input_dev *input_dev;
+ int err;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_READ_WORD_DATA))
+ return -EIO;
+
+ ts = kzalloc(sizeof(struct cy8ctmg110), GFP_KERNEL);
+ input_dev = input_allocate_device();
+
+ if (!ts || !input_dev) {
+ err = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ ts->client = client;
+ i2c_set_clientdata(client, ts);
+
+ ts->input = input_dev;
+ ts->pending = false;
+ ts->sleepmode = false;
+
+
+ if(client->addr==CY8CTMG110_I2C_ADDR){
+ ts->reset_gpio = CY8CTMG110_RESET_PIN_GPIO;
+ input_dev->name = CY8CTMG110_DRIVER_NAME" Touchscreen";
+ snprintf(ts->driver_name, sizeof(ts->driver_name),"%s", CY8CTMG110_DRIVER_NAME);
+ }
+ else if (client->addr==CY8CTMG110_I2C_ADDR_EXT){
+ ts->reset_gpio = CY8CTMG110_RESET_PIN_GPIO_EXT;
+ input_dev->name = CY8CTMG110_DRIVER_NAME_EXT" Touchscreen";
+ snprintf(ts->driver_name, sizeof(ts->driver_name),"%s", CY8CTMG110_DRIVER_NAME_EXT);
+ }
+
+ snprintf(ts->phys, sizeof(ts->phys),
+ "%s/input0", dev_name(&client->dev));
+
+ INIT_DELAYED_WORK(&ts->work, cy8ctmg110_work);
+
+ input_dev->phys = ts->phys;
+ input_dev->id.bustype = BUS_I2C;
+
+ spin_lock_init(&ts->lock);
+
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) |
+ BIT_MASK(EV_REL) | BIT_MASK(EV_ABS);
+
+ input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+ input_set_capability(input_dev, EV_KEY, KEY_F);
+
+
+ input_set_abs_params(input_dev, ABS_X, CY8CTMG110_X_MIN, CY8CTMG110_X_MAX, 0, 0);
+ input_set_abs_params(input_dev, ABS_Y, CY8CTMG110_Y_MIN, CY8CTMG110_Y_MAX, 0, 0);
+ input_dev->relbit[BIT_WORD(REL_X)] = BIT_MASK(REL_X)| BIT_MASK(REL_Y);
+
+ err = gpio_request(ts->reset_gpio, NULL);
+
+ if (err) {
+ printk("GPIO pin %d failed to request.\n", ts->reset_gpio);
+ goto err_free_thread;
+ }
+
+ cy8ctmg110_power(ts,true);
+
+ ts->initController = false;
+#ifdef POLL_TOUCH_EVENTS
+ ts->i2c_fail_count = 0;
+ hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ ts->timer.function = cy8ctmg110_timer;
+
+ hrtimer_start(&ts->timer, ktime_set(10, 0),
+ HRTIMER_MODE_REL);
+#endif
+ err = gpio_request(client->irq, "touch_irq_key");
+
+ if (err < 0) {
+ printk("%s gpio-keys: failed to request GPIO %d,"
+ " error %d\n",ts->driver_name,client->irq, err);
+ goto err_free_thread;
+ }
+
+ err= gpio_direction_input(client->irq);
+
+ if (err < 0) {
+ pr_err("%s gpio-keys: failed to configure input"
+ " direction for GPIO %d, error %d\n",ts->driver_name,client->irq, err);
+ gpio_free(client->irq);
+ goto err_free_thread;
+ }
+
+ ts->irq_gpio = gpio_to_irq(client->irq);
+
+ if (ts->irq_gpio < 0) {
+ err = ts->irq_gpio;
+ pr_err("cy8ctmg110 gpio-keys: Unable to get irq number"
+ " for GPIO %d, error %d\n",
+ ts->irq_gpio, err);
+ gpio_free(ts->irq_gpio);
+ goto err_free_thread;
+ }
+
+ if (client->addr!=CY8CTMG110_I2C_ADDR_EXT){
+ err = request_irq(ts->irq_gpio, cy8ctmg110_irq_handler,
+ IRQF_TRIGGER_RISING | IRQF_SHARED,
+ "touch_reset_key",
+ ts);
+ }
+
+ if (err < 0) {
+ dev_err(&client->dev, "cy8ctmg110 irq %d busy? error %d\n", ts->irq_gpio ,err);
+ goto err_free_thread;
+ }
+
+ err = input_register_device(input_dev);
+ cy8ctmg110_read_versionid(ts);
+
+ if (err)
+ goto err_free_irq;
+
+ return 0;
+
+ err_free_irq:
+ printk("%s err_free_irq\n",ts->driver_name);
+ free_irq(client->irq, ts);
+ err_free_thread:
+ printk("%s err_free_thread\n",ts->driver_name);
+ err_free_mem:
+ printk("%s err_free_mem\n",ts->driver_name);
+ input_free_device(input_dev);
+ kfree(ts);
+
+ return err;
+}
+/*
+ * cy8ctmg110_suspend
+ *
+ */
+static int cy8ctmg110_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+ if (device_may_wakeup(&client->dev))
+ enable_irq_wake(client->irq);
+
+ return 0;
+}
+/*
+ * cy8ctmg110_resume
+ *
+ */
+static int cy8ctmg110_resume(struct i2c_client *client)
+{
+ if (device_may_wakeup(&client->dev))
+ disable_irq_wake(client->irq);
+
+ return 0;
+}
+/*
+ * cy8ctmg110_remove
+ *
+ */
+static int cy8ctmg110_remove(struct i2c_client *client)
+{
+ struct cy8ctmg110 *ts = i2c_get_clientdata(client);
+
+#ifdef CY8CTMG110_DEBUG_INFO
+ printk("cy8ctmg110_remove\n");
+#endif
+
+ cy8ctmg110_power(ts,false);
+#ifdef POLL_TOUCH_EVENTS
+ hrtimer_cancel(&ts->timer);
+#endif
+
+ free_irq(client->irq, ts);
+ input_unregister_device(ts->input);
+ kfree(ts);
+
+ return 0;
+}
+
+static struct i2c_device_id cy8ctmg110_idtable[] = {
+ { CY8CTMG110_DRIVER_NAME, 1 },
+ { CY8CTMG110_DRIVER_NAME_EXT, 1 },
+ { }
+};
+
+MODULE_DEVICE_TABLE(i2c, cy8ctmg110_idtable);
+
+static struct i2c_driver cy8ctmg110_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = CY8CTMG110_DRIVER_NAME,
+ .bus = &i2c_bus_type,
+ },
+ .id_table = cy8ctmg110_idtable,
+ .probe = cy8ctmg110_probe,
+ .remove = cy8ctmg110_remove,
+ .suspend = cy8ctmg110_suspend,
+ .resume = cy8ctmg110_resume,
+};
+
+
+static int __init cy8ctmg110_init(void)
+{
+ printk("cy8ctmg110_init\n");
+
+ return i2c_add_driver(&cy8ctmg110_driver);
+}
+
+static void __exit cy8ctmg110_exit(void)
+{
+#ifdef CY8CTMG110_DEBUG_INFO
+ printk("cy8ctmg110_exit\n");
+#endif
+ i2c_del_driver(&cy8ctmg110_driver);
+}
+
+module_init(cy8ctmg110_init);
+module_exit(cy8ctmg110_exit);
+
+
+struct i2c_board_info __initdata koski_i2c_board_info2[] = {
+ {
+ I2C_BOARD_INFO(CY8CTMG110_DRIVER_NAME, CY8CTMG110_I2C_ADDR),
+ .irq = CY8CTMG110_IRQ_PIN_GPIO
+ },
+ {
+ I2C_BOARD_INFO(CY8CTMG110_DRIVER_NAME_EXT, CY8CTMG110_I2C_ADDR_EXT),
+ .irq = CY8CTMG110_IRQ_PIN_GPIO_EXT
+ },
+};
+
+
+static int __init koski_i2c_init(void)
+{
+ printk("init koski board\n");
+
+#ifdef MOORESTOWN_CDK
+ /*init koski i2c*/
+ i2c_register_board_info(1, koski_i2c_board_info2,
+ ARRAY_SIZE(koski_i2c_board_info2));
+#else
+ /*init koski i2c*/
+ i2c_register_board_info(0, koski_i2c_board_info2,
+ ARRAY_SIZE(koski_i2c_board_info2));
+#endif
+ return 0;
+}
+
+module_init(koski_i2c_init);
+
+MODULE_AUTHOR("Samuli Konttila <samuli.konttila@aavamobile.com>");
+MODULE_DESCRIPTION("cy8ctmg110 TouchScreen Driver");
+MODULE_LICENSE("GPL v2");
+
+
+// Aava access from sysfs begin
+static ssize_t aava_query_fw_info_func(struct class *class, char *buf)
+{
+ ssize_t status;
+ int i = 0;
+ unsigned char mrst_fw_ver_info[16];
+
+ printk("!!! aava_query_fw_info_func() ENTER\n");
+
+ status = mrst_get_firmware_version(mrst_fw_ver_info);
+ for (i = 0; i < 16; i++){
+ printk("%x\n", mrst_fw_ver_info[i]);
+ buf[i] = mrst_fw_ver_info[i];
+ }
+
+ return 16;
+}
+
+static ssize_t aava_enable_touch_traces_func(struct class *class, \
+ const char *buf, size_t len)
+{
+ ssize_t status;
+ unsigned long value;
+
+ status = strict_strtoul(buf, 0, &value);
+ printk("!!! aava_enable_touch_traces_func() = %d\n", (int)value);
+
+ g_y_trace_coord = value;
+
+ return len;
+}
+
+static struct class_attribute aava_class_attrs[] = {
+ __ATTR(aava_query_fw_info, 0444, aava_query_fw_info_func, NULL),
+ __ATTR(aava_enable_touch_traces, 0200, NULL, aava_enable_touch_traces_func),
+ __ATTR_NULL,
+};
+
+static struct class aava_class = {
+ .name = "aava",
+ .owner = THIS_MODULE,
+
+ .class_attrs = aava_class_attrs,
+};
+
+static int __init aava_sysfs_init(void)
+{
+ int status;
+
+ status = class_register(&aava_class);
+ if (status < 0)
+ return status;
+
+ return status;
+}
+postcore_initcall(aava_sysfs_init);
+// Aava access from sysfs end
--
1.6.2.2

View File

@ -0,0 +1,67 @@
Subject: [3/3] drm/i915: Ignore LVDS EDID when it is unavailabe or invalid
Date: Thu, 04 Mar 2010 08:17:31 -0000
From: Zhenyu Wang <zhenyuw@linux.intel.com>
Patch-mainline: 2.6.34
References: https://patchwork.kernel.org/patch/83556/, BMC# 331
From: Zhao Yakui <yakui.zhao@intel.com>
In course of probing the display mode for LVDS, we will firstly try to
check the EDID for LVDS panel. But on some laptops the EDID is invalid for
the LVDS panel. In such case it will complain the invalida EDID warning
message and print the EDID raw data every time when probing the LVDS mode.
https://bugs.freedesktop.org/show_bug.cgi?id=23099
https://bugs.freedesktop.org/show_bug.cgi?id=26395
Signed-off-by: Zhao Yakui <yakui.zhao@intel.com>
Tested-by: Sitsofe Wheeler <sitsofe@yahoo.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
Acked-by: Yin Kangkai <kangkai.yin@intel.com>
---
drivers/gpu/drm/i915/i915_drv.h | 2 ++
drivers/gpu/drm/i915/intel_lvds.c | 13 +++++++++----
2 files changed, 11 insertions(+), 4 deletions(-)
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -581,6 +581,8 @@ typedef struct drm_i915_private {
/* Reclocking support */
bool render_reclock_avail;
bool lvds_downclock_avail;
+ /* indicate whether the LVDS EDID is OK */
+ bool lvds_edid_ok;
/* indicates the reduced downclock for LVDS*/
int lvds_downclock;
struct work_struct idle_work;
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -680,10 +680,13 @@ static int intel_lvds_get_modes(struct d
struct drm_i915_private *dev_priv = dev->dev_private;
int ret = 0;
- ret = intel_ddc_get_modes(intel_output);
+ if (dev_priv->lvds_edid_ok) {
+ ret = intel_ddc_get_modes(intel_output);
+ if (ret)
+ return ret;
- if (ret)
- return ret;
+ dev_priv->lvds_edid_ok = false;
+ }
/* Didn't get an EDID, so
* Set wide sync ranges so we get all modes
@@ -1097,7 +1100,9 @@ void intel_lvds_init(struct drm_device *
* Attempt to get the fixed panel mode from DDC. Assume that the
* preferred mode is the right one.
*/
- intel_ddc_get_modes(intel_output);
+ dev_priv->lvds_edid_ok = true;
+ if (!intel_ddc_get_modes(intel_output))
+ dev_priv->lvds_edid_ok = false;
list_for_each_entry(scan, &connector->probed_modes, head) {
mutex_lock(&dev->mode_config.mutex);

View File

@ -0,0 +1,76 @@
From 3589c3e0ec88c19c330b88f7d37c8092987866e6 Mon Sep 17 00:00:00 2001
From: Priya Vijayan <priya.vijayan@intel.com>
Date: Fri, 30 Apr 2010 11:11:10 -0700
Subject: [PATCH] Enable hid-dg-contactcount in stantum and cando touch drivers
Enable hid-dg-contact count in stantum and cando touch drivers to be able to use with mtdev driver
Patch-mainline: 2.6.34
Signed-off-by: Priya Vijayan <priya.vijayan@intel.com>
---
drivers/hid/hid-cando.c | 8 ++++++++
drivers/hid/hid-stantum.c | 11 ++++++++++-
2 files changed, 18 insertions(+), 1 deletions(-)
diff --git a/drivers/hid/hid-cando.c b/drivers/hid/hid-cando.c
index ed8c093..42b9980 100644
--- a/drivers/hid/hid-cando.c
+++ b/drivers/hid/hid-cando.c
@@ -64,6 +64,10 @@ static int cando_input_mapping(struct hid_device *hdev, struct hid_input *hi,
case HID_DG_TIPSWITCH:
case HID_DG_CONTACTMAX:
return -1;
+ case HID_DG_CONTACTCOUNT:
+ hid_map_usage(hi, usage, bit, max,
+ EV_ABS, ABS_MT_CONTACT_COUNT);
+ return 1;
case HID_DG_INRANGE:
/* touchscreen emulation */
hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
@@ -169,6 +173,10 @@ static int cando_event(struct hid_device *hid, struct hid_field *field,
struct input_dev *input = field->hidinput->input;
switch (usage->hid) {
+ case HID_DG_CONTACTCOUNT:
+ input_event(input,EV_ABS,ABS_MT_CONTACT_COUNT,value);
+ //input_mt_sync(input);
+ break;
case HID_DG_INRANGE:
td->valid = value;
break;
diff --git a/drivers/hid/hid-stantum.c b/drivers/hid/hid-stantum.c
index bb4430f..ac3df05 100644
--- a/drivers/hid/hid-stantum.c
+++ b/drivers/hid/hid-stantum.c
@@ -64,10 +64,15 @@ static int stantum_input_mapping(struct hid_device *hdev, struct hid_input *hi,
case HID_DG_CONFIDENCE:
case HID_DG_INPUTMODE:
case HID_DG_DEVICEINDEX:
- case HID_DG_CONTACTCOUNT:
+ //case HID_DG_CONTACTCOUNT:
case HID_DG_CONTACTMAX:
return -1;
+ case HID_DG_CONTACTCOUNT:
+ hid_map_usage(hi, usage, bit, max,
+ EV_ABS, ABS_MT_CONTACT_COUNT);
+ return 1;
+
case HID_DG_TIPSWITCH:
/* touchscreen emulation */
hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
@@ -171,6 +176,10 @@ static int stantum_event(struct hid_device *hid, struct hid_field *field,
struct input_dev *input = field->hidinput->input;
switch (usage->hid) {
+ case HID_DG_CONTACTCOUNT:
+ input_event(input,EV_ABS,ABS_MT_CONTACT_COUNT,value);
+ //input_mt_sync(input);
+ break;
case HID_DG_INRANGE:
/* this is the last field in a finger */
stantum_filter_event(sd, input);
--
1.6.2.2

View File

@ -0,0 +1,58 @@
From dd75ba1aee79abfa6948cd3b82a7a7eb97599c91 Mon Sep 17 00:00:00 2001
From: Prajwal Mohan <prajwal.karur.mohan@intel.com>
Date: Fri, 9 Apr 2010 18:18:34 -0700
Subject: [PATCH 106/106] Fixing path for marvell firmware
Patch-mainline: Friday, 9 Apr 2010 18:18:34
---
drivers/net/wireless/libertas/if_sdio.c | 24 ++++++++++++------------
1 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
index 7a73f62..055a581 100644
--- a/drivers/net/wireless/libertas/if_sdio.c
+++ b/drivers/net/wireless/libertas/if_sdio.c
@@ -83,28 +83,28 @@ static struct if_sdio_model if_sdio_models[] = {
{
/* 8385 */
.model = IF_SDIO_MODEL_8385,
- .helper = "sd8385_helper.bin",
- .firmware = "sd8385.bin",
+ .helper = "libertas/sd8385_helper.bin",
+ .firmware = "libertas/sd8385.bin",
},
{
/* 8686 */
.model = IF_SDIO_MODEL_8686,
- .helper = "sd8686_helper.bin",
- .firmware = "sd8686.bin",
+ .helper = "libertas/sd8686_helper.bin",
+ .firmware = "libertas/sd8686.bin",
},
{
/* 8688 */
.model = IF_SDIO_MODEL_8688,
- .helper = "sd8688_helper.bin",
- .firmware = "sd8688.bin",
+ .helper = "libertas/sd8688_helper.bin",
+ .firmware = "libertas/sd8688.bin",
},
};
-MODULE_FIRMWARE("sd8385_helper.bin");
-MODULE_FIRMWARE("sd8385.bin");
-MODULE_FIRMWARE("sd8686_helper.bin");
-MODULE_FIRMWARE("sd8686.bin");
-MODULE_FIRMWARE("sd8688_helper.bin");
-MODULE_FIRMWARE("sd8688.bin");
+MODULE_FIRMWARE("libertas/sd8385_helper.bin");
+MODULE_FIRMWARE("libertas/sd8385.bin");
+MODULE_FIRMWARE("libertas/sd8686_helper.bin");
+MODULE_FIRMWARE("libertas/sd8686.bin");
+MODULE_FIRMWARE("libertas/sd8688_helper.bin");
+MODULE_FIRMWARE("libertas/sd8688.bin");
struct if_sdio_packet {
struct if_sdio_packet *next;
--
1.6.2.5

View File

@ -0,0 +1,30 @@
From 67b3a2d6716bfa9d308b26729a2cdeeffb6e8218 Mon Sep 17 00:00:00 2001
From: Prajwal Mohan <prajwal.karur.mohan@intel.com>
Date: Thu, 13 May 2010 16:39:43 -0700
Subject: [PATCH] dirty hack to fix aava camera sensor issue
Signed-off-by: Prajwal Mohan <prajwal.karur.mohan@intel.com>
Patch-mainline: 2.6.34
---
drivers/media/video/mrstci/mrstov2650/mrstov2650.c | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/drivers/media/video/mrstci/mrstov2650/mrstov2650.c b/drivers/media/video/mrstci/mrstov2650/mrstov2650.c
index 7f0d478..ce24139 100644
--- a/drivers/media/video/mrstci/mrstov2650/mrstov2650.c
+++ b/drivers/media/video/mrstci/mrstov2650/mrstov2650.c
@@ -1111,7 +1111,11 @@ static int ov2650_detect(struct i2c_client *client)
ov2650_wakeup();
ov2650_read(client, OV2650_PID_L, &value);
+ #ifdef CONFIG_MRST_DRM_AAVA
+ if (value != 0x66)
+ #else
if (value != 0x52)
+ #endif
return -ENODEV;
return 0;
--
1.6.2.5

View File

@ -0,0 +1,142 @@
From 5f57d67da87332a9a1ba8fa7a33bf0680e1c76e7 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Mon, 19 Apr 2010 10:37:21 -0700
Subject: [PATCH 1/2] Input: Add support of Synaptics Clickpad device
Patch-mainline: 2.6.34
Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git
Git-commit: 5f57d67da87332a9a1ba8fa7a33bf0680e1c76e7
References: BMC#99
The new type of touchpads can be detected via a new query command
0x0c. The clickpad flags are in cap[0]:4 and cap[1]:0 bits.
When the device is detected, the driver now reports only the left
button as the supported buttons so that X11 driver can detect that
the device is Clickpad. A Clickpad device gives the button events
only as the middle button. The kernel driver morphs to the left
button. The real handling of Clickpad is done rather in X driver
side.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Acked-by: Jian-feng Ding <jian-feng.ding@intel.com>
---
drivers/input/mouse/synaptics.c | 35 ++++++++++++++++++++++++++++++-----
drivers/input/mouse/synaptics.h | 4 ++++
2 files changed, 34 insertions(+), 5 deletions(-)
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index d3f5243..9ab9ff0 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -136,7 +136,8 @@ static int synaptics_capability(struct psmouse *psmouse)
if (synaptics_send_cmd(psmouse, SYN_QUE_CAPABILITIES, cap))
return -1;
priv->capabilities = (cap[0] << 16) | (cap[1] << 8) | cap[2];
- priv->ext_cap = 0;
+ priv->ext_cap = priv->ext_cap_0c = 0;
+
if (!SYN_CAP_VALID(priv->capabilities))
return -1;
@@ -149,7 +150,7 @@ static int synaptics_capability(struct psmouse *psmouse)
if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 1) {
if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB, cap)) {
printk(KERN_ERR "Synaptics claims to have extended capabilities,"
- " but I'm not able to read them.");
+ " but I'm not able to read them.\n");
} else {
priv->ext_cap = (cap[0] << 16) | (cap[1] << 8) | cap[2];
@@ -161,6 +162,16 @@ static int synaptics_capability(struct psmouse *psmouse)
priv->ext_cap &= 0xff0fff;
}
}
+
+ if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 4) {
+ if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB_0C, cap)) {
+ printk(KERN_ERR "Synaptics claims to have extended capability 0x0c,"
+ " but I'm not able to read it.\n");
+ } else {
+ priv->ext_cap_0c = (cap[0] << 16) | (cap[1] << 8) | cap[2];
+ }
+ }
+
return 0;
}
@@ -347,7 +358,15 @@ static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data
hw->left = (buf[0] & 0x01) ? 1 : 0;
hw->right = (buf[0] & 0x02) ? 1 : 0;
- if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) {
+ if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) {
+ /*
+ * Clickpad's button is transmitted as middle button,
+ * however, since it is primary button, we will report
+ * it as BTN_LEFT.
+ */
+ hw->left = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0;
+
+ } else if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) {
hw->middle = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0;
if (hw->w == 2)
hw->scroll = (signed char)(buf[1]);
@@ -592,6 +611,12 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
dev->absres[ABS_X] = priv->x_res;
dev->absres[ABS_Y] = priv->y_res;
+
+ if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) {
+ /* Clickpads report only left button */
+ __clear_bit(BTN_RIGHT, dev->keybit);
+ __clear_bit(BTN_MIDDLE, dev->keybit);
+ }
}
static void synaptics_disconnect(struct psmouse *psmouse)
@@ -696,10 +721,10 @@ int synaptics_init(struct psmouse *psmouse)
priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS;
- printk(KERN_INFO "Synaptics Touchpad, model: %ld, fw: %ld.%ld, id: %#lx, caps: %#lx/%#lx\n",
+ printk(KERN_INFO "Synaptics Touchpad, model: %ld, fw: %ld.%ld, id: %#lx, caps: %#lx/%#lx/%#lx\n",
SYN_ID_MODEL(priv->identity),
SYN_ID_MAJOR(priv->identity), SYN_ID_MINOR(priv->identity),
- priv->model_id, priv->capabilities, priv->ext_cap);
+ priv->model_id, priv->capabilities, priv->ext_cap, priv->ext_cap_0c);
set_input_params(psmouse->dev, priv);
diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h
index f0f40a3..ae37c5d 100644
--- a/drivers/input/mouse/synaptics.h
+++ b/drivers/input/mouse/synaptics.h
@@ -18,6 +18,7 @@
#define SYN_QUE_SERIAL_NUMBER_SUFFIX 0x07
#define SYN_QUE_RESOLUTION 0x08
#define SYN_QUE_EXT_CAPAB 0x09
+#define SYN_QUE_EXT_CAPAB_0C 0x0c
/* synatics modes */
#define SYN_BIT_ABSOLUTE_MODE (1 << 7)
@@ -48,6 +49,8 @@
#define SYN_CAP_VALID(c) ((((c) & 0x00ff00) >> 8) == 0x47)
#define SYN_EXT_CAP_REQUESTS(c) (((c) & 0x700000) >> 20)
#define SYN_CAP_MULTI_BUTTON_NO(ec) (((ec) & 0x00f000) >> 12)
+#define SYN_CAP_PRODUCT_ID(ec) (((ec) & 0xff0000) >> 16)
+#define SYN_CAP_CLICKPAD(ex0c) ((ex0c) & 0x100100)
/* synaptics modes query bits */
#define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7))
@@ -96,6 +99,7 @@ struct synaptics_data {
unsigned long int model_id; /* Model-ID */
unsigned long int capabilities; /* Capabilities */
unsigned long int ext_cap; /* Extended Capabilities */
+ unsigned long int ext_cap_0c; /* Ext Caps from 0x0c query */
unsigned long int identity; /* Identification */
int x_res; /* X resolution in units/mm */
int y_res; /* Y resolution in units/mm */
--
1.6.3.3

View File

@ -0,0 +1,462 @@
Index: linux-2.6.33/drivers/hwmon/Kconfig
===================================================================
--- linux-2.6.33.orig/drivers/hwmon/Kconfig
+++ linux-2.6.33/drivers/hwmon/Kconfig
@@ -63,6 +63,13 @@ config SENSORS_EMC1403
Threshold values can be configured using sysfs.
Data from the different diode are accessible via sysfs.
+config SENSORS_MRST_ANALOG_ACCEL
+ tristate "Moorestown Analog Accelerometer"
+ depends on LNW_IPC
+ help
+ If you say yes here you get support for the Analog Accelerometer Devices
+ x y Z data can be accessed via sysfs.
+
config HWMON_DEBUG_CHIP
bool "Hardware Monitoring Chip debugging messages"
default n
Index: linux-2.6.33/drivers/hwmon/Makefile
===================================================================
--- linux-2.6.33.orig/drivers/hwmon/Makefile
+++ linux-2.6.33/drivers/hwmon/Makefile
@@ -103,6 +103,7 @@ obj-$(CONFIG_SENSORS_ISL29020) += isl290
obj-$(CONFIG_SENSORS_HMC6352) += hmc6352.o
obj-$(CONFIG_SENSORS_LIS331DL) += lis331dl.o
obj-$(CONFIG_SENSORS_EMC1403) += emc1403.o
+obj-$(CONFIG_SENSORS_MRST_ANALOG_ACCEL) += mrst_analog_accel.o
ifeq ($(CONFIG_HWMON_DEBUG_CHIP),y)
EXTRA_CFLAGS += -DDEBUG
Index: linux-2.6.33/drivers/hwmon/mrst_analog_accel.c
===================================================================
--- /dev/null
+++ linux-2.6.33/drivers/hwmon/mrst_analog_accel.c
@@ -0,0 +1,381 @@
+/*
+ * mrst_analog_accel.c - Intel analog accelerometer driver for Moorestown
+ *
+ * Copyright (C) 2009 Intel Corp
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <asm/ipc_defs.h>
+
+MODULE_AUTHOR("Ramesh Agarwal");
+MODULE_DESCRIPTION("Intel Moorestown Analog Accelerometer Driver");
+MODULE_LICENSE("GPL v2");
+
+/* PMIC ADC INTERRUPT REGISTERS */
+#define PMIC_ADC_ACC_REG_ADCINT 0x5F /*ADC interrupt register */
+#define PMIC_ADC_ACC_REG_MADCINT 0x60 /*ADC interrupt mask register */
+
+/* PMIC ADC CONTROL REGISTERS */
+#define PMIC_ADC_ACC_REG_ADCCNTL1 0x61 /*ADC control register */
+#define PMIC_ADC_ACC_REG_ADCCNTL2 0x62 /*ADC gain regs channel 10-17 */
+#define PMIC_ADC_ACC_REG_ADCCNTL3 0x63 /*ADC gain regs channel 18-21 */
+
+/* PMIC Data Register base */
+#define PMIC_ADC_DATA_REG_BASE 0x64
+
+/* PMIC Channel Mapping Register base */
+#define PMIC_ADC_MAPPING_BASE 0xA4
+
+/* Number of PMIC sample registers */
+#define PMIC_ADC_REG_MAX 32 /* Max no of available channel */
+
+#define PMIC_ADC_X_REG_HIGH(index) (PMIC_ADC_DATA_REG_BASE \
+ + (index * 2))
+#define PMIC_ADC_X_REG_LOW(index) (PMIC_ADC_DATA_REG_BASE \
+ + (index * 2) + 1)
+#define PMIC_ADC_Y_REG_HIGH(index) (PMIC_ADC_DATA_REG_BASE \
+ + (index * 2) + 2)
+#define PMIC_ADC_Y_REG_LOW(index) (PMIC_ADC_DATA_REG_BASE \
+ + (index * 2) + 3)
+#define PMIC_ADC_Z_REG_HIGH(index) (PMIC_ADC_DATA_REG_BASE \
+ + (index * 2) + 4)
+#define PMIC_ADC_Z_REG_LOW(index) (PMIC_ADC_DATA_REG_BASE \
+ + (index * 2) + 5)
+
+/* Number of registers to read at a time */
+#define REG_READ_PER_IPC 4 /* Read 4 at a time although the */
+ /* IPC will support max 5 */
+
+#define END_OF_CHANNEL_VALUE 0x1F /* Used to indicate the last */
+ /* channel being used */
+
+/* PMIC ADC channels for Accelero Meter */
+#define PMIC_ADC_ACC_ADC_ACC_CH14 0xE
+#define PMIC_ADC_ACC_ADC_ACC_CH15 0xF
+#define PMIC_ADC_ACC_ADC_ACC_CH16 0x10
+
+static unsigned int mrst_analog_reg_idx;
+
+/* Use IPC to read the value of the register and display
+ * X value
+ */
+static ssize_t
+mrst_analog_accel_x_axis_data_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned int ret_val;
+ struct ipc_pmic_reg_data ipc_data;
+
+ ipc_data.ioc = FALSE; /* No need to generate MSI */
+ ipc_data.num_entries = 2;
+ ipc_data.pmic_reg_data[0].register_address =
+ PMIC_ADC_X_REG_HIGH(mrst_analog_reg_idx); /* X Higher 8 bits */
+ ipc_data.pmic_reg_data[1].register_address =
+ PMIC_ADC_X_REG_LOW(mrst_analog_reg_idx); /* X lower 3 bits */
+ if (ipc_pmic_register_read(&ipc_data) != 0) {
+ printk(KERN_ALERT
+ "\nmrst_analog_accel:PMIC reg read using IPC failed\n");
+ return -1;
+ }
+ ret_val = ipc_data.pmic_reg_data[0].value << 3; /* X higher 8 bits */
+ /* lower 3 bits */
+ ret_val = ret_val | (ipc_data.pmic_reg_data[1].value & 0x07);
+ return sprintf(buf, "%d\n", ret_val);
+}
+
+/* Use IPC to read the value of the register and display
+ * Y value */
+static ssize_t
+mrst_analog_accel_y_axis_data_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned int ret_val;
+ struct ipc_pmic_reg_data ipc_data;
+
+ ipc_data.ioc = FALSE; /* No need to generate MSI */
+ ipc_data.num_entries = 2;
+ ipc_data.pmic_reg_data[0].register_address =
+ PMIC_ADC_Y_REG_HIGH(mrst_analog_reg_idx); /* Y higher 8 bits */
+ ipc_data.pmic_reg_data[1].register_address =
+ PMIC_ADC_Y_REG_LOW(mrst_analog_reg_idx); /* Y lower 3 bits */
+ if (ipc_pmic_register_read(&ipc_data) != 0) {
+ printk(KERN_ALERT
+ "\nmrst_analog_accel:PMIC reg read using IPC failed\n");
+ return -1;
+ }
+ ret_val = ipc_data.pmic_reg_data[0].value << 3; /* Y higher 8 bits */
+ /* Y lower 3 bits */
+ ret_val = ret_val | (ipc_data.pmic_reg_data[1].value & 0x07);
+ return sprintf(buf, "%d\n", ret_val);
+}
+
+/* Use IPC to read the value of the register and display
+ * Z value */
+static ssize_t
+mrst_analog_accel_z_axis_data_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned int ret_val;
+ struct ipc_pmic_reg_data ipc_data;
+
+ ipc_data.ioc = FALSE; /* No need to generate MSI */
+ ipc_data.num_entries = 2;
+ ipc_data.pmic_reg_data[0].register_address =
+ PMIC_ADC_Z_REG_HIGH(mrst_analog_reg_idx);
+ ipc_data.pmic_reg_data[1].register_address =
+ PMIC_ADC_Z_REG_LOW(mrst_analog_reg_idx); /* Z lower 3 bits */
+ if (ipc_pmic_register_read(&ipc_data) != 0) {
+ printk(KERN_ALERT
+ "\nmrst_analog_accel:PMIC reg read using IPC failed\n");
+ return -1;
+ }
+ ret_val = ipc_data.pmic_reg_data[0].value << 3; /* Z higher 8 bits */
+ /* Z lower 3 bits */
+ ret_val = ret_val | (ipc_data.pmic_reg_data[1].value & 0x07);
+ return sprintf(buf, "%d\n", ret_val);
+}
+
+
+static DEVICE_ATTR(acc_x_axis, S_IRUGO,
+ mrst_analog_accel_x_axis_data_show, NULL);
+static DEVICE_ATTR(acc_y_axis, S_IRUGO,
+ mrst_analog_accel_y_axis_data_show, NULL);
+static DEVICE_ATTR(acc_z_axis, S_IRUGO,
+ mrst_analog_accel_z_axis_data_show, NULL);
+
+static struct attribute *mid_att_acc[] = {
+ &dev_attr_acc_x_axis.attr,
+ &dev_attr_acc_y_axis.attr,
+ &dev_attr_acc_z_axis.attr,
+ NULL
+};
+
+static struct attribute_group m_analog_gr = {
+ .name = "mrst_analog_accel",
+ .attrs = mid_att_acc
+};
+
+static int
+mrst_analog_accel_initialize(void)
+{
+ struct ipc_pmic_mod_reg_data ipc_mod_data;
+ struct ipc_pmic_reg_data ipc_data;
+ u8 retval = 0;
+ u8 mad_cntrl = 0; /* MADCINT register value */
+ u8 adc_cntrl2 = 0; /* ADCCNTL2 register value */
+ int i, j;
+
+ /* Initialize the register index to use to be zero */
+ mrst_analog_reg_idx = 0;
+
+ /* check if the ADC is enabled or not
+ * Read ADCCNTL1 registers */
+ ipc_data.ioc = FALSE; /* No need to generate MSI */
+ ipc_data.num_entries = 1;
+ ipc_data.pmic_reg_data[0].register_address =
+ PMIC_ADC_ACC_REG_ADCCNTL1;
+ ipc_data.pmic_reg_data[0].value = 0;
+
+ retval = ipc_pmic_register_read(&ipc_data);
+ if (retval != 0) {
+ printk(KERN_ALERT
+ "\nmrst_analog_accel:PMIC register read failed\n");
+ return retval;
+ }
+
+ adc_cntrl2 = ipc_data.pmic_reg_data[0].value;
+
+ if ((adc_cntrl2 >> 7) & 0x1) {
+ /* If the ADC is enabled find the set of registers to use
+ ** Loop through the channel mapping register to find out the
+ ** first free one
+ */
+ for (i = 0;
+ (i < PMIC_ADC_REG_MAX) && (mrst_analog_reg_idx == 0);
+ i += REG_READ_PER_IPC) {
+
+ ipc_data.num_entries = REG_READ_PER_IPC;
+ ipc_data.ioc = FALSE; /* No need to generate MSI */
+
+ /* Reading 4 regs at a time instead of reading each
+ * reg one by one since IPC is an expensive operation
+ */
+ for (j = 0; j < REG_READ_PER_IPC; j++) {
+ ipc_data.pmic_reg_data[j].register_address =
+ PMIC_ADC_MAPPING_BASE + i + j;
+ ipc_data.pmic_reg_data[j].value = 0;
+ }
+ retval = ipc_pmic_register_read(&ipc_data);
+ if (retval != 0) {
+ printk(KERN_ALERT
+ "\nmrst_analog_accel:PMIC regs read failed\n");
+ return retval;
+ }
+ for (j = 0; j < REG_READ_PER_IPC; j++) {
+ if (ipc_data.pmic_reg_data[j].value
+ == END_OF_CHANNEL_VALUE) {
+ mrst_analog_reg_idx = i + j;
+ break;
+ }
+ }
+ }
+ }
+ /* Check to see if there are enough registers to map the channel */
+ if ((mrst_analog_reg_idx + 3) >= PMIC_ADC_REG_MAX) {
+ printk(KERN_ALERT
+ "\nmrst_analog_accel:Not enough regs to map the channels\n");
+ return -1;
+ }
+
+ /* Update the mapping registers for the accelerometer*/
+ ipc_data.num_entries = 4;
+ ipc_data.ioc = FALSE; /* No need to generate MSI */
+ ipc_data.pmic_reg_data[0].register_address =
+ PMIC_ADC_MAPPING_BASE + mrst_analog_reg_idx;
+ ipc_data.pmic_reg_data[0].value = PMIC_ADC_ACC_ADC_ACC_CH14;
+
+ ipc_data.pmic_reg_data[1].register_address =
+ PMIC_ADC_MAPPING_BASE + mrst_analog_reg_idx + 1;
+ ipc_data.pmic_reg_data[1].value = PMIC_ADC_ACC_ADC_ACC_CH15;
+
+ ipc_data.pmic_reg_data[2].register_address =
+ PMIC_ADC_MAPPING_BASE + mrst_analog_reg_idx + 2;
+ ipc_data.pmic_reg_data[2].value = PMIC_ADC_ACC_ADC_ACC_CH16;
+
+ ipc_data.pmic_reg_data[3].register_address =
+ PMIC_ADC_MAPPING_BASE + mrst_analog_reg_idx + 3 ;
+ ipc_data.pmic_reg_data[3].value = END_OF_CHANNEL_VALUE;
+
+ retval = ipc_pmic_register_write(&ipc_data, FALSE);
+ if (retval != 0) {
+ printk(KERN_ALERT
+ "\nmrst_analog_accel:PMIC reg write failed\n");
+ return retval;
+ }
+
+ /* If the ADC was not enabled, enable it now */
+ if (!(adc_cntrl2 >> 7) & 0x1) {
+ /* Mask the round robin completion interrupt */
+ ipc_mod_data.ioc = FALSE; /* No need to generate MSI */
+ ipc_mod_data.num_entries = 1;
+ mad_cntrl = 0x01;
+ ipc_mod_data.pmic_mod_reg_data[0].register_address =
+ PMIC_ADC_ACC_REG_MADCINT;
+ ipc_mod_data.pmic_mod_reg_data[0].value = mad_cntrl;
+ ipc_mod_data.pmic_mod_reg_data[0].bit_map = 0x01;
+
+ retval = ipc_pmic_register_read_modify(&ipc_mod_data);
+ if (retval != 0) {
+ printk(KERN_ALERT
+ "\nmrst_analog_accel:PMIC reg modify failed\n");
+ return retval;
+ }
+
+ adc_cntrl2 = 0xc6; /*27ms delay,start round robin,
+ enable full power */
+ ipc_data.ioc = FALSE; /* No need to generate MSI */
+ ipc_data.num_entries = 1;
+ ipc_data.pmic_reg_data[0].register_address =
+ PMIC_ADC_ACC_REG_ADCCNTL1;
+ ipc_data.pmic_reg_data[0].value = adc_cntrl2;
+ retval = ipc_pmic_register_write(&ipc_data, FALSE);
+ if (retval != 0)
+ return retval;
+ }
+ return retval;
+}
+
+static struct platform_device *mrst_analog_accel_pdev;
+static struct device *mrst_analog_accel_hwmon;
+
+static int
+mrst_analog_accel_unregister(void)
+{
+
+ printk(KERN_ALERT "\nStart Exit\n\n");
+ sysfs_remove_group(&mrst_analog_accel_hwmon->kobj, &m_analog_gr);
+ hwmon_device_unregister(mrst_analog_accel_hwmon);
+ platform_device_unregister(mrst_analog_accel_pdev);
+ printk(KERN_ALERT "\n\nEnd Exit\n");
+ return 0;
+}
+
+
+static int __init
+mrst_analog_accel_module_init(void)
+{
+ int retval = 0;
+
+ mrst_analog_accel_pdev =
+ platform_device_register_simple("mrst_analog_accel",
+ 0, NULL, 0);
+ if (IS_ERR(mrst_analog_accel_pdev)) {
+ retval = PTR_ERR(mrst_analog_accel_pdev);
+ printk(KERN_ALERT
+ "\nmrst_analog_accel:Registration with the platform failed\n");
+ goto accelero_reg_failed;
+ }
+ printk(KERN_ALERT
+ "\nmrst_analog_accel:Registered with the platform\n");
+
+ retval = mrst_analog_accel_initialize();
+ if (retval == 0) {
+ retval = sysfs_create_group(&mrst_analog_accel_pdev->dev.kobj,
+ &m_analog_gr);
+ if (retval) {
+ printk(KERN_ALERT
+ "\nmrst_analog_accel:device_create_file 1 failed\n");
+ goto accelero_reg_failed;
+ }
+ mrst_analog_accel_hwmon =
+ hwmon_device_register(&mrst_analog_accel_pdev->dev);
+ if (IS_ERR(mrst_analog_accel_hwmon)) {
+ retval = PTR_ERR(mrst_analog_accel_hwmon);
+ mrst_analog_accel_hwmon = NULL;
+ printk(KERN_ALERT
+ "\nmrst_analog_accel:Registration with hwmon failed\n");
+ }
+ } else {
+ printk(KERN_ALERT
+ "\nmrst_analog_accel:Initialization failed: %d\n", retval);
+ }
+
+accelero_reg_failed:
+ return retval;
+}
+
+static void __exit
+mrst_analog_accel_module_exit(void)
+{
+
+ mrst_analog_accel_unregister();
+}
+
+module_init(mrst_analog_accel_module_init);
+module_exit(mrst_analog_accel_module_exit);
Index: linux-2.6.33/drivers/hwmon/lis331dl.c
===================================================================
--- linux-2.6.33.orig/drivers/hwmon/lis331dl.c
+++ linux-2.6.33/drivers/hwmon/lis331dl.c
@@ -186,33 +186,10 @@ invarg:
return -EINVAL;
}
-static ssize_t reboot_mem_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- struct i2c_client *client = to_i2c_client(dev);
- struct acclero_data *data = i2c_get_clientdata(client);
- unsigned int ret_val, set_val;
- unsigned long val;
-
- if (strict_strtoul(buf, 10, &val))
- return -EINVAL;
- ret_val = i2c_smbus_read_byte_data(client, 0x21);
- if (val == ACCEL_MEMORY_REBOOT) {
- mutex_lock(&data->update_lock);
- set_val = (ret_val | (1 << 6)); /* setting the 6th bit */
- i2c_write_current_data(client, 0x21, set_val);
- mutex_unlock(&data->update_lock);
- } else
- return -EINVAL;
- return count;
-}
-
static DEVICE_ATTR(data_rate, S_IRUGO | S_IWUSR,
data_rate_show, data_rate_store);
static DEVICE_ATTR(power_state, S_IRUGO | S_IWUSR,
power_mode_show, power_mode_store);
-static DEVICE_ATTR(reboot_mem, S_IWUSR, NULL,
- reboot_mem_store);
static DEVICE_ATTR(x, S_IRUGO, x_pos_show, NULL);
static DEVICE_ATTR(y, S_IRUGO, y_pos_show, NULL);
static DEVICE_ATTR(z, S_IRUGO, z_pos_show, NULL);
@@ -221,7 +198,6 @@ static DEVICE_ATTR(curr_pos, S_IRUGO, xy
static struct attribute *mid_att_acclero[] = {
&dev_attr_data_rate.attr,
&dev_attr_power_state.attr,
- &dev_attr_reboot_mem.attr,
&dev_attr_x.attr,
&dev_attr_y.attr,
&dev_attr_z.attr,

View File

@ -0,0 +1,900 @@
From 4f7fcea7402d7d788fe959bc9b7ced86af72d806 Mon Sep 17 00:00:00 2001
From: R, Dharageswari <dharageswari.r@intel.com>
Date: Thu, 29 Apr 2010 20:20:22 +0530
Subject: [PATCH] ADR-Post-Beta-0.05.002.03-2/8-Adding Moorestown Audio Drivers: SST header files
This patch adds the common header files.
intel_sst_common.h - This header files is private to SST driver and contain the
common structures like SST ops, SST register offsets, debugging macro,
sst stream definitions, and Shim register definitions.
intel_sst_pvt.c - Utility functions used by SST driver and function
prototypes of common functions are implemented in this file
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
new file: sound/pci/sst/intel_sst_common.h
new file: sound/pci/sst/intel_sst_pvt.c
Patch-mainline: 2.6.35?
---
sound/pci/sst/intel_sst_common.h | 538 ++++++++++++++++++++++++++++++++++++++
sound/pci/sst/intel_sst_pvt.c | 323 +++++++++++++++++++++++
2 files changed, 861 insertions(+), 0 deletions(-)
create mode 100644 sound/pci/sst/intel_sst_common.h
create mode 100644 sound/pci/sst/intel_sst_pvt.c
diff --git a/sound/pci/sst/intel_sst_common.h b/sound/pci/sst/intel_sst_common.h
new file mode 100644
index 0000000..d9a720d
--- /dev/null
+++ b/sound/pci/sst/intel_sst_common.h
@@ -0,0 +1,538 @@
+#ifndef __INTEL_SST_COMMON_H__
+#define __INTEL_SST_COMMON_H__
+/*
+ * intel_sst_common.h - Intel SST Driver for audio engine
+ *
+ * Copyright (C) 2008-10 Intel Corporation
+ * Authors: Vinod Koul <vinod.koul@intel.com>
+ * Harsha Priya <priya.harsha@intel.com>
+ * Dharageswari R <dharageswari.r@intel.com>
+ * KP Jeeja <jeeja.kp@intel.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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * Common private declarations for SST
+ */
+#include <linux/time.h>
+#ifdef CONFIG_MSTWN_POWER_MGMT
+#include <linux/intel_mid.h>
+#endif
+/* #define SND_LOOP_TEST */
+
+#define SST_DRIVER_VERSION "0.05.002.03"
+#define SST_VERSION_NUM 0x050203
+
+/* driver names */
+#define SST_DRV_NAME "intel_sst_driver"
+#define SST_FW_STD_FILENAME "fw_sst.bin"
+
+
+enum sst_states {
+ SST_FW_LOADED = 1,
+ SST_FW_RUNNING,
+ SST_UN_INIT,
+ SST_ERROR,
+};
+
+#define MAX_ACTIVE_STREAM 3
+#define MAX_ENC_STREAM 1
+#define MAX_AM_HANDLES 1
+#define ALLOC_TIMEOUT 5000
+/* SST numbers */
+#define SST_BLOCK_TIMEOUT 5000
+#define TARGET_DEV_BLOCK_TIMEOUT 5000
+
+/* FIXME */
+#define INTEL_SST_MAJOR 255
+#define BLOCK_UNINIT -1
+#define RX_TIMESLOT_UNINIT -1
+/* Chip revision ID */
+
+/*
+#define CHIP_A1_50 0x01
+#define CHIP_A2_50 0x02
+#define CHIP_A2_100 0x03
+*/
+
+/*
+#define DSP_CLOCK_SPEED 100 */ /* 50: 50MHz, 100: 100MHz */
+
+/* SST register map */
+#define SST_CSR 0x00
+#define SST_PISR 0x08
+#define SST_PIMR 0x10
+#define SST_ISRX 0x18
+#define SST_IMRX 0x28
+#define SST_IPCX 0x38 /* IPC IA-SST */
+#define SST_IPCD 0x40 /* IPC SST-IA */
+#define SST_ISRD 0x20 /* dummy register for shim workaround */
+#define SST_SHIM_SIZE 0X44
+
+#define SPI_MODE_ENABLE_BASE_ADDR 0xffae4000
+#define FW_SIGNATURE_SIZE 4
+
+/* PMIC and SST hardware states */
+enum sst_mad_states {
+ SND_MAD_UN_INIT = 0,
+ SND_MAD_INIT_DONE,
+};
+
+/* stream states */
+enum sst_stream_states {
+ STREAM_UN_INIT = 0, /* Freed/Not used stream */
+ STREAM_RUNNING = 1, /* Running */
+ STREAM_PAUSED = 2, /* Paused stream */
+ STREAM_DECODE = 4, /* stream is in decoding only state */
+ STREAM_INIT = 5, /* stream init, waiting for data */
+};
+
+
+enum sst_ram_type{
+ SST_IRAM = 1,
+ SST_DRAM = 2,
+};
+/* SST shim registers to structure mapping */
+union config_status_reg {
+ struct {
+ u32 rsvd0:1;
+ u32 sst_reset:1;
+ u32 hw_rsvd:3;
+ u32 sst_clk:2;
+ u32 bypass:3;
+ u32 run_stall:1;
+ u32 rsvd1:2;
+ u32 strb_cntr_rst:1;
+ u32 rsvd:18;
+ } part;
+ u32 full;
+};
+
+union interrupt_reg {
+ struct {
+ u32 done_interrupt:1;
+ u32 busy_interrupt:1;
+ u32 rsvd:30;
+ } part;
+ u32 full;
+};
+
+union sst_pisr_reg {
+ struct {
+ u32 pssp0:1;
+ u32 pssp1:1;
+ u32 rsvd0:3;
+ u32 dmac:1;
+ u32 rsvd1:26;
+ } part;
+ u32 full;
+};
+
+union sst_pimr_reg {
+ struct {
+ u32 ssp0:1;
+ u32 ssp1:1;
+ u32 rsvd0:3;
+ u32 dmac:1;
+ u32 rsvd1:10;
+ u32 ssp0_sc:1;
+ u32 ssp1_sc:1;
+ u32 rsvd2:3;
+ u32 dmac_sc:1;
+ u32 rsvd3:10;
+ } part;
+ u32 full;
+};
+
+
+struct sst_stream_bufs {
+ struct list_head node;
+ u32 size;
+ const char *addr;
+ u32 data_copied;
+ bool in_use;
+ u32 offset;
+};
+
+struct snd_sst_user_cap_list {
+ unsigned int iov_index; /* index of iov */
+ unsigned long iov_offset; /* offset in iov */
+ unsigned long offset; /* offset in kmem */
+ unsigned long size; /* size copied */
+ struct list_head node;
+};
+/*
+This structure is used to block a user/fw data call to another
+fw/user call
+*/
+struct sst_block {
+ bool condition; /* condition for blocking check */
+ int ret_code; /* ret code when block is released */
+ void *data; /* data to be appsed for block if any */
+ bool on;
+};
+
+enum snd_sst_buf_type {
+ SST_BUF_USER_STATIC = 1,
+ SST_BUF_USER_DYNAMIC,
+ SST_BUF_MMAP_STATIC,
+ SST_BUF_MMAP_DYNAMIC,
+};
+enum snd_src {
+ SST_DRV = 1,
+ MAD_DRV = 2
+};
+/*
+structure that holds the stream information
+*/
+struct stream_info {
+ unsigned int status;
+ unsigned int prev;
+ u8 codec;
+ unsigned int sst_id;
+ unsigned int ops;
+ struct list_head bufs;
+ struct mutex lock; /* mutex */
+ spinlock_t pcm_lock;
+ bool mmapped;
+ unsigned int sg_index; /* current buf Index */
+ unsigned char *cur_ptr; /* Current static bufs */
+ struct snd_sst_buf_entry *buf_entry;
+ struct sst_block data_blk; /* stream ops block */
+ struct sst_block ctrl_blk; /* stream control cmd block */
+ enum snd_sst_buf_type buf_type;
+ void *pcm_substream;
+ void (*period_elapsed) (void *pcm_substream);
+ unsigned int sfreq;
+ void *decode_ibuf, *decode_obuf;
+ unsigned int decode_isize, decode_osize;
+ u8 decode_ibuf_type, decode_obuf_type;
+ unsigned int idecode_alloc;
+ unsigned int need_draining;
+ unsigned int str_type;
+ u32 curr_bytes;
+ u32 cumm_bytes;
+ u32 src; /* hack to remove */
+};
+
+
+
+/*
+this structure is used for blocking the user's alloc calls to
+fw's response to alloc calls
+*/
+struct stream_alloc_block {
+ int sst_id; /* session id of blocked stream */
+ struct sst_block ops_block; /* ops block struture */
+};
+
+#define SST_FW_SIGN "$SST"
+#define SST_FW_LIB_SIGN "$LIB"
+
+/* FW file headers */
+struct fw_header {
+ unsigned char signature[FW_SIGNATURE_SIZE]; /* FW signature */
+ u32 file_size; /* size of fw minus this header */
+ u32 modules; /* # of modules */
+ u32 file_format; /* version of header format */
+ u32 reserved[4];
+};
+
+struct fw_module_header {
+ unsigned char signature[FW_SIGNATURE_SIZE]; /* module signature */
+ u32 mod_size; /* size of module */
+ u32 blocks; /* # of blocks */
+ u32 type; /* codec type, pp lib */
+ u32 entry_point;
+};
+
+struct dma_block_info {
+ enum sst_ram_type type; /* IRAM/DRAM */
+ u32 size; /* Bytes */
+ u32 ram_offset; /* Offset in I/DRAM */
+ u32 rsvd; /* Reserved field */
+};
+
+struct ioctl_pvt_data {
+ int str_id;
+ int pvt_id;
+};
+
+struct sst_ipc_msg_wq {
+ union ipc_header header;
+ char mailbox[SST_MAILBOX_SIZE];
+ struct work_struct wq;
+};
+
+struct mad_ops_wq {
+ int stream_id;
+ enum sst_controls control_op;
+ struct work_struct wq;
+
+};
+
+#define SST_MMAP_PAGES (640*1024 / PAGE_SIZE)
+#define SST_MMAP_STEP (40*1024 / PAGE_SIZE)
+
+/* driver ops */
+struct intel_sst_drv {
+ bool pmic_state;
+ int pmic_vendor;
+ int sst_state;
+/* int chip_rev_id; */
+ void __iomem *shim;
+ void __iomem *mailbox;
+ void __iomem *iram;
+ void __iomem *dram;
+ unsigned int shim_phy_add;
+ struct list_head ipc_dispatch_list;
+ struct work_struct ipc_post_msg_wq;
+ struct sst_ipc_msg_wq ipc_process_msg;
+ struct sst_ipc_msg_wq ipc_process_reply;
+ struct sst_ipc_msg_wq ipc_post_msg;
+ struct mad_ops_wq mad_ops;
+ wait_queue_head_t wait_queue;
+ struct workqueue_struct *mad_wq;
+ struct workqueue_struct *post_msg_wq;
+ struct workqueue_struct *process_msg_wq;
+ struct workqueue_struct *process_reply_wq;
+
+ struct stream_info streams[MAX_NUM_STREAMS];
+ struct stream_alloc_block alloc_block[MAX_ACTIVE_STREAM];
+ struct sst_block tgt_dev_blk, fw_info_blk,
+ vol_info_blk, mute_info_blk, hs_info_blk;
+ struct mutex list_lock;/* mutex for IPC list locking */
+ struct snd_pmic_ops *scard_ops;
+ struct pci_dev *pci;
+ int active_streams[MAX_NUM_STREAMS];
+ void *mmap_mem;
+ struct mutex stream_cnt_lock;
+ unsigned int mmap_len;
+ unsigned int unique_id;
+ unsigned int stream_cnt; /* total streams */
+ unsigned int encoded_cnt; /* enocded streams only */
+ unsigned int am_cnt;
+ unsigned int pb_streams; /* pb streams active */
+ unsigned int cp_streams; /* cp streams active */
+ unsigned int lpe_stalled; /* LPE is stalled or not */
+ unsigned int pmic_port_instance; /*pmic port instance enabled*/
+ int rx_time_slot_status;
+ unsigned int lpaudio_start; /* 1 - LPA stream(MP3 pb) in progress*/
+ unsigned int audio_start; /* 1 - LPA stream(Non-MP3 pb) in progress*/
+};
+
+extern struct intel_sst_drv *sst_drv_ctx;
+
+/* register definitions */
+/*SCU FW Changes*/
+/*#define AUD_CLK_ADDR 0xff11d83c
+#define AUD_CLK_DISABLE 0x80008008
+#define AUD_CLK_50MHZ 0x80008301
+#define AUD_CLK_RATIO_1_2 0x80000301
+#define AUD_CLK_RATIO_8008 0x80008008
+#define AUD_CLK_RATIO_8101 0x80008101
+#define AUD_CLK_RATIO_0101 0x80000101
+#define AUD_SYS_ADDR 0xff11d118
+#define AUD_SYS_RESET 0x7ffffcff
+#define AUD_SYS_SET 0x7fffffff
+#define AUD_SHIM_BASE_ADDR 0xffae8000 */
+/*
+#define AUD_SHIM_RATIO_1_1 0x382
+#define AUD_SHIM_RATIO 0x3a2
+*/
+/*SCU FW Changes*/
+/*#define AUD_CLK_200 0xff11d200
+#define AUD_CLK_204 0xff11d204
+#define AUD_INIT_VAL 0x0*/
+#define CHIP_REV_REG 0xff108000
+#define CHIP_REV_ADDR 0x78
+/*
+#define CHIP_REV_A1 0x0
+#define CHIP_REV_A2 0x3
+#define CLK_50MHZ 50
+#define CLK_100MHZ 100
+*/
+/* misc definitions */
+#define FW_DWNL_ID 0xFF
+#define LOOP1 0x11111111
+#define LOOP2 0x22222222
+#define LOOP3 0x33333333
+#define LOOP4 0x44444444
+
+#define SST_DEFAULT_PMIC_PORT 1 /*audio port*/
+/* NOTE: status will +ve for good cases and -ve for error ones */
+#define MAX_STREAM_FIELD 255
+
+int sst_alloc_stream(char *params, unsigned int stream_ops, u8 codec,
+ unsigned int session_id);
+int sst_alloc_stream_response(unsigned int str_id,
+ struct snd_sst_str_type *type);
+int sst_stalled(void);
+int sst_pause_stream(int id);
+int sst_resume_stream(int id);
+int sst_enable_rx_timeslot(int status);
+int sst_drop_stream(int id);
+int sst_free_stream(int id);
+int sst_play_frame(int streamID);
+int sst_capture_frame(int streamID);
+int sst_set_stream_param(int streamID, struct snd_sst_params *str_param);
+int sst_target_device_select(struct snd_sst_target_device *target_device);
+int sst_decode(int str_id, struct snd_sst_dbufs *dbufs);
+int sst_get_decoded_bytes(int str_id, unsigned long long *bytes);
+int sst_get_fw_info(struct snd_sst_fw_info *info);
+int sst_get_stream_params(int str_id,
+ struct snd_sst_get_stream_params *get_params);
+int sst_drain_stream(int str_id);
+int sst_get_vol(struct snd_sst_vol *set_vol);
+int sst_set_vol(struct snd_sst_vol *set_vol);
+int sst_set_mute(struct snd_sst_mute *set_mute);
+
+
+void sst_post_message(struct work_struct *work);
+void sst_process_message(struct work_struct *work);
+void sst_process_reply(struct work_struct *work);
+void sst_process_mad_ops(struct work_struct *work);
+void sst_process_mad_jack_detection(struct work_struct *work);
+
+int intel_sst_ioctl(struct inode *i_node, struct file *file_ptr,
+ unsigned int cmd, unsigned long arg);
+int intel_sst_open(struct inode *i_node, struct file *file_ptr);
+int intel_sst_release(struct inode *i_node, struct file *file_ptr);
+int intel_sst_read(struct file *file_ptr, char __user *buf,
+ size_t count, loff_t *ppos);
+int intel_sst_write(struct file *file_ptr, const char __user *buf,
+ size_t count, loff_t *ppos);
+int intel_sst_mmap(struct file *fp, struct vm_area_struct *vma);
+ssize_t intel_sst_aio_write(struct kiocb *kiocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t offset);
+ssize_t intel_sst_aio_read(struct kiocb *kiocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t offset);
+
+int sst_load_fw(const struct firmware *fw, void *context);
+int sst_load_library(struct snd_sst_lib_download *lib, u8 ops, u32 pvt_id);
+int sst_spi_mode_enable(void);
+int sst_get_block_stream(struct intel_sst_drv *sst_drv_ctx);
+
+void sst_print_hex(unsigned char *buf, unsigned int size);
+int sst_wait_interruptible(struct intel_sst_drv *sst_drv_ctx,
+ struct sst_block *block);
+int sst_wait_interruptible_timeout(struct intel_sst_drv *sst_drv_ctx,
+ struct sst_block *block, int timeout);
+int sst_wait_timeout(struct intel_sst_drv *sst_drv_ctx,
+ struct stream_alloc_block *block);
+int sst_create_large_msg(struct ipc_post **arg);
+int sst_create_short_msg(struct ipc_post **arg);
+void sst_print_params(struct snd_sst_params *str_params);
+void sst_wake_up_alloc_block(struct intel_sst_drv *sst_drv_ctx,
+ u8 sst_id, int status, void *data);
+void sst_clear_interrupt(void);
+
+/**
+* this function is an inline function that sets the headers before
+* sending a message
+*/
+static inline void sst_fill_header(union ipc_header *header,
+ int msg, int large, int strID)
+{
+ header->part.msg_id = msg;
+ header->part.str_id = strID;
+ header->part.large = large;
+ header->part.done = 0;
+ header->part.busy = 1;
+ header->part.data = 0;
+}
+
+/**
+* this inline function assigns a private id for calls that dont have stream
+* context yet
+*/
+static inline unsigned int sst_assign_pvt_id(struct intel_sst_drv *sst_drv_ctx)
+{
+ sst_drv_ctx->unique_id++;
+ if (sst_drv_ctx->unique_id >= MAX_NUM_STREAMS)
+ sst_drv_ctx->unique_id = 1;
+ return sst_drv_ctx->unique_id;
+}
+
+/**
+* this function initialzes stream context
+*/
+static inline void sst_init_stream(struct stream_info *stream,
+ int codec, int str_type, int sst_id, int ops)
+{
+ stream->status = STREAM_INIT;
+ stream->prev = STREAM_UN_INIT;
+ stream->codec = codec;
+ stream->sst_id = sst_id;
+ stream->str_type = str_type;
+ stream->ops = ops;
+ stream->data_blk.on = false;
+ stream->data_blk.condition = false;
+ stream->data_blk.ret_code = 0;
+ stream->data_blk.data = NULL;
+ stream->ctrl_blk.on = false;
+ stream->ctrl_blk.condition = false;
+ stream->ctrl_blk.ret_code = 0;
+ stream->ctrl_blk.data = NULL;
+ stream->need_draining = false;
+ stream->decode_ibuf = NULL;
+ stream->decode_isize = 0;
+ stream->mmapped = false;
+}
+
+/**
+* this function resets the stream contexts
+*/
+static inline void sst_clean_stream(struct stream_info *stream)
+{
+ struct sst_stream_bufs *bufs = NULL, *_bufs;
+ stream->status = STREAM_UN_INIT;
+ stream->prev = STREAM_UN_INIT;
+ mutex_lock(&stream->lock);
+ list_for_each_entry_safe(bufs, _bufs, &stream->bufs, node) {
+ list_del(&bufs->node);
+ kfree(bufs);
+ }
+ mutex_unlock(&stream->lock);
+
+ if (stream->ops != STREAM_OPS_PLAYBACK_DRM)
+ kfree(stream->decode_ibuf);
+}
+
+/**
+* this function generates events for OSPM
+*/
+static inline int sst_ospm_send_event(int event)
+{
+#ifdef CONFIG_MSTWN_POWER_MGMT
+ return ospm_generate_netlink_event(AUDIO_SUBSYTEM_ID, event);
+#else
+ return 0;
+#endif
+}
+
+/**
+* this function validates the stream id
+*/
+static inline int sst_validate_strid(int str_id)
+{
+ if (str_id <= 0 || str_id >= MAX_NUM_STREAMS)
+ return -EINVAL;
+ else
+ return 0;
+}
+
+#endif /* __INTEL_SST_COMMON_H__ */
diff --git a/sound/pci/sst/intel_sst_pvt.c b/sound/pci/sst/intel_sst_pvt.c
new file mode 100644
index 0000000..95d79be
--- /dev/null
+++ b/sound/pci/sst/intel_sst_pvt.c
@@ -0,0 +1,323 @@
+/*
+ * intel_sst_pvt.c - Intel SST Driver for audio engine
+ *
+ * Copyright (C) 2008-10 Intel Corp
+ * Authors: Vinod Koul <vinod.koul@intel.com>
+ * Harsha Priya <priya.harsha@intel.com>
+ * Dharageswari R <dharageswari.r@intel.com>
+ * KP Jeeja <jeeja.kp@intel.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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This driver exposes the audio engine functionalities to the ALSA
+ * and middleware.
+ *
+ * This file contains all private functions
+ */
+
+#include <linux/cdev.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/syscalls.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/workqueue.h>
+#include <linux/firmware.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <sound/intel_lpe.h>
+#include <sound/intel_sst_ioctl.h>
+#include "intel_sst_fw_ipc.h"
+#include "intel_sst_common.h"
+
+/**
+* this function assigns a block for the calls that dont have stream context yet
+* the blocks are used for waiting on Firmware's response for any operation
+*/
+int sst_get_block_stream(struct intel_sst_drv *sst_drv_ctx)
+{
+ int i;
+
+ for (i = 0; i < MAX_ACTIVE_STREAM; i++) {
+ if (sst_drv_ctx->alloc_block[i].sst_id == BLOCK_UNINIT) {
+ sst_drv_ctx->alloc_block[i].ops_block.condition = false;
+ sst_drv_ctx->alloc_block[i].ops_block.ret_code = 0;
+ sst_drv_ctx->alloc_block[i].sst_id = 0;
+ break;
+ }
+ }
+ if (i == MAX_ACTIVE_STREAM) {
+ printk(KERN_ERR
+ "SST ERR: max alloc_stream reached");
+ i = -EBUSY; /* active stream limit reached */
+ }
+ return i;
+}
+
+/**
+* this function is a debug function that is used to print contents of a buffer
+*/
+void sst_print_hex(unsigned char *buf, unsigned int size)
+{
+ unsigned int i;
+
+ for (i = 0; i < size; i++) {
+ printk(KERN_DEBUG "SST DBG:%02x ", buf[i]);
+ if ((i != 0) && ((i % 8) == 0))
+ printk(KERN_DEBUG "SST DBG:\n");
+ }
+}
+/**
+* this function waits without a timeout (and is interruptable) for a
+* given block event
+*/
+int sst_wait_interruptible(struct intel_sst_drv *sst_drv_ctx,
+ struct sst_block *block)
+{
+ int retval = 0;
+
+ if (!wait_event_interruptible(sst_drv_ctx->wait_queue,
+ block->condition)) {
+ /* event wake */
+ if (block->ret_code < 0) {
+ printk(KERN_ERR
+ "SST ERR: stream failed %d\n"\
+ , block->ret_code);
+ retval = -EBUSY;
+ } else {
+ printk(KERN_DEBUG "SST DBG:event up\n");
+ retval = 0;
+ }
+ } else {
+ printk(KERN_ERR
+ "SST ERR: signal interrupted\n");
+ retval = -EINTR;
+ }
+ return retval;
+
+}
+
+/**
+* this function waits with a timeout value (and is interruptle) on a
+* given block event
+*/
+int sst_wait_interruptible_timeout(
+ struct intel_sst_drv *sst_drv_ctx,
+ struct sst_block *block, int timeout)
+{
+ int retval = 0;
+
+ printk(KERN_DEBUG "SST DBG:waiting....\n");
+ if (wait_event_interruptible_timeout(sst_drv_ctx->wait_queue,
+ block->condition,
+ msecs_to_jiffies(timeout))) {
+ if (block->ret_code < 0) {
+ printk(KERN_ERR
+ "SST ERR: stream failed %d\n"\
+ , block->ret_code);
+ } else
+ printk(KERN_DEBUG "SST DBG:event up\n");
+ retval = block->ret_code;
+ } else {
+ block->on = false;
+ printk(KERN_ERR
+ "SST ERR: timeout occured...\n");
+ /* settign firmware state as uninit so that the
+ firmware will get redownloaded on next request
+ this is because firmare not responding for 5 sec
+ is equalant to some unrecoverable error of FW
+ sst_drv_ctx->sst_state = SST_UN_INIT;*/
+ retval = -EBUSY;
+ }
+ return retval;
+
+}
+
+/**
+* this function waits with on a given block event
+*/
+int sst_wait_timeout(struct intel_sst_drv *sst_drv_ctx,
+ struct stream_alloc_block *block)
+{
+ int retval = 0;
+
+ /* NOTE:
+ Observed that FW processes the alloc msg and replies even
+ before the alloc thread has finished execution */
+ printk(KERN_DEBUG "SST DBG:waiting for %x, +\
+ condition %x \n", block->sst_id,
+ block->ops_block.condition);
+ if (wait_event_interruptible_timeout(sst_drv_ctx->wait_queue,
+ block->ops_block.condition,
+ msecs_to_jiffies(SST_BLOCK_TIMEOUT))) {
+ /* event wake */
+ printk(KERN_DEBUG "SST DBG:Event wake +\
+ ... %x \n", block->ops_block.condition);
+ printk(KERN_DEBUG "SST DBG:message +\
+ ret: %d\n", block->ops_block.ret_code);
+ retval = block->ops_block.ret_code;
+ } else {
+ block->ops_block.on = false;
+ printk(KERN_ERR
+ "SST ERR: Wait timed-out %x \n",\
+ block->ops_block.condition);
+ /* settign firmware state as uninit so that the
+ firmware will get redownloaded on next request
+ this is because firmare not responding for 5 sec
+ is equalant to some unrecoverable error of FW
+ sst_drv_ctx->sst_state = SST_UN_INIT;*/
+ retval = -EBUSY;
+ }
+ return retval;
+
+}
+
+/**
+* this function allocats structures to send a large message to the firmware
+*/
+int sst_create_large_msg(struct ipc_post **arg)
+{
+ struct ipc_post *msg;
+
+ msg = kzalloc(sizeof(struct ipc_post), GFP_ATOMIC);
+ if (!msg) {
+ printk(KERN_ERR
+ "SST ERR: kzalloc msg failed \n");
+ return -ENOMEM;
+ }
+
+ msg->mailbox_data = kzalloc(SST_MAILBOX_SIZE, GFP_ATOMIC);
+ if (!msg->mailbox_data) {
+ kfree(msg);
+ printk(KERN_ERR
+ "SST ERR: kzalloc mailbox_data failed");
+ return -ENOMEM;
+ };
+ *arg = msg;
+ return 0;
+}
+
+/**
+* this function allocats structures to send a short message to the firmware
+*/
+int sst_create_short_msg(struct ipc_post **arg)
+{
+ struct ipc_post *msg;
+
+ msg = kzalloc(sizeof(*msg), GFP_ATOMIC);
+ if (!msg) {
+ printk(KERN_ERR
+ "SST ERR: kzalloc msg failed \n");
+ return -ENOMEM;
+ }
+ msg->mailbox_data = NULL;
+ *arg = msg;
+ return 0;
+}
+
+/**
+* this function is a debug funtion to print the stream parameters
+*/
+void sst_print_params(struct snd_sst_params *str_params)
+{
+ switch (str_params->codec) {
+ case SST_CODEC_TYPE_PCM:
+ printk(KERN_DEBUG "SST DBG:pcm \n");
+ printk(KERN_DEBUG "SST DBG:chan=%d, sfreq = %d, wd_sz = %d \
+ brate = %d buffer_size= 0x%d\
+ period_cnt = %d\n",
+ str_params->sparams.uc.pcm_params.num_chan,
+ str_params->sparams.uc.pcm_params.sfreq,
+ str_params->sparams.uc.pcm_params.pcm_wd_sz,
+ str_params->sparams.uc.pcm_params.brate,
+ // str_params->sparams.uc.pcm_params.frame_size,
+ // str_params->sparams.uc.pcm_params.samples_per_frame,
+ str_params->sparams.uc.pcm_params.buffer_size,
+ str_params->sparams.uc.pcm_params.period_count);
+ break;
+
+ case SST_CODEC_TYPE_MP3:
+ printk(KERN_DEBUG "SST DBG:mp3 \n");
+ printk(KERN_DEBUG "SST DBG:chan=%d, brate=%d, sfreq = %d, wd_sz = %d\n",
+ str_params->sparams.uc.mp3_params.num_chan,
+ str_params->sparams.uc.mp3_params.brate,
+ str_params->sparams.uc.mp3_params.sfreq,
+ str_params->sparams.uc.mp3_params.pcm_wd_sz);
+ break;
+
+ case SST_CODEC_TYPE_AAC:
+ printk(KERN_DEBUG "SST DBG:aac \n");
+ printk(KERN_DEBUG "SST DBG:chan=%d, brate=%d, sfreq = %d, wd_sz = %d,asrate=%d\n",
+ str_params->sparams. uc.aac_params.num_chan,
+ str_params->sparams.uc.aac_params.brate,
+ str_params->sparams.uc.aac_params.sfreq,
+ str_params->sparams.uc.aac_params.pcm_wd_sz,
+ str_params->sparams.uc.aac_params.aac_srate);
+ printk(KERN_DEBUG "SST DBG:mpgid=%d profile=%d, aot = %d\n",
+ str_params->sparams.uc.aac_params.mpg_id,
+ str_params->sparams.uc.aac_params.aac_profile,
+ str_params->sparams.uc.aac_params.aot);
+ break;
+ case SST_CODEC_TYPE_WMA9:
+ printk(KERN_DEBUG "SST DBG:wma type \n");
+ printk(KERN_DEBUG "SST DBG:chan=%d, brate=%d, sfreq = %d, wd_sz = %d, tag=%d\n",
+ str_params->sparams. uc.wma_params.num_chan,
+ str_params->sparams.uc.wma_params.brate,
+ str_params->sparams.uc.wma_params.sfreq,
+ str_params->sparams.uc.wma_params.pcm_wd_sz,
+ str_params->sparams.uc.wma_params.format_tag);
+ printk(KERN_DEBUG "SST DBG:mask=%d, +\
+ b align=%d, enc opt =%d, op align =%d\n",
+ str_params->sparams.uc.wma_params.channel_mask,
+ str_params->sparams.uc.wma_params.block_align,
+ str_params->sparams.uc.wma_params.wma_encode_opt,
+ str_params->sparams.uc.wma_params.op_align);
+ break;
+ default:
+ printk(KERN_DEBUG "SST DBG:other +\
+ codec 0x%x\n", str_params->codec);
+ }
+}
+
+/**
+* this function wakes up a sleeping block event based on the response
+*/
+void sst_wake_up_alloc_block(struct intel_sst_drv *sst_drv_ctx,
+ u8 sst_id, int status, void *data)
+{
+ int i;
+
+ /* Unblock with retval code */
+ for (i = 0; i < MAX_ACTIVE_STREAM; i++) {
+ if (sst_id == sst_drv_ctx->alloc_block[i].sst_id) {
+ sst_drv_ctx->alloc_block[i].ops_block.condition = true;
+ sst_drv_ctx->alloc_block[i].ops_block.ret_code = status;
+ sst_drv_ctx->alloc_block[i].ops_block.data = data;
+ printk(KERN_DEBUG "SST DBG:wake id %d, +\
+ sst_id %d condition %x\n", i,
+ sst_drv_ctx->alloc_block[i].sst_id,
+ sst_drv_ctx->alloc_block[i].ops_block.condition);
+ wake_up(&sst_drv_ctx->wait_queue);
+ break;
+ }
+ }
+}
--
1.6.2.2

View File

@ -0,0 +1,85 @@
From e17c41ab9c34ea8715c2655fcb623b0bb92eaab1 Mon Sep 17 00:00:00 2001
From: R, Dharageswari <dharageswari.r@intel.com>
Date: Thu, 29 Apr 2010 20:30:16 +0530
Subject: [PATCH] ADR-Post-Beta-0.05.002.03-8/8-Moorestown Audio Drivers: Config files
This patch adds the makefiles and Kconfig changes for both SST and MAD drivers
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
modified: sound/pci/Kconfig
modified: sound/pci/Makefile
new file: sound/pci/sst/Makefile
Patch-mainline: 2.6.35?
---
sound/pci/Kconfig | 25 +++++++++++++++++++++++++
sound/pci/Makefile | 3 ++-
sound/pci/sst/Makefile | 9 +++++++++
3 files changed, 36 insertions(+), 1 deletions(-)
create mode 100644 sound/pci/sst/Makefile
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
index 1513d72..e41380d 100644
--- a/sound/pci/Kconfig
+++ b/sound/pci/Kconfig
@@ -8,6 +8,30 @@ menuconfig SND_PCI
Support for sound devices connected via the PCI bus.
if SND_PCI
+config SND_INTEL_SST
+ bool "Moorestown SST (LPE) Driver"
+ depends on X86 && LNW_IPC
+ default y
+ help
+ Say Y here to include support for the Moorestown SST DSP driver
+ On other PC platforms if you are unsure answer 'N'
+
+config SND_INTELMID
+ bool "Moorestown sound card driver"
+ select SND_JACK
+ depends on SND_INTEL_SST && SPI_MRST
+ default y
+ help
+ Say Y here to include support for the Moorestown sound driver.
+ On other PC platforms if you are unsure answer 'N'
+
+config SND_AUDIO_DBG_PRINT
+ bool "Moorestown Audio driver debug printk calls"
+ depends on SND_INTELMID
+ default n
+ help
+ Say Y here to include debug printks calls in the Intel MID driver.
+ If you are unsure say 'N'
config SND_AD1889
tristate "Analog Devices AD1889"
select SND_AC97_CODEC
diff --git a/sound/pci/Makefile b/sound/pci/Makefile
index 5665c1e..541057b 100644
--- a/sound/pci/Makefile
+++ b/sound/pci/Makefile
@@ -77,4 +77,5 @@ obj-$(CONFIG_SND) += \
rme9652/ \
trident/ \
ymfpci/ \
- vx222/
+ vx222/ \
+ sst/
diff --git a/sound/pci/sst/Makefile b/sound/pci/sst/Makefile
new file mode 100644
index 0000000..cf96b11
--- /dev/null
+++ b/sound/pci/sst/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for Intel MID Audio drivers
+#
+EXTRA_CFLAGS=-g -DCONFIG_MRST_RAR_HANDLER
+snd-intel-sst-objs := intel_sst.o intel_sst_ipc.o intel_sst_stream.o intel_sst_interface.o intel_sst_dsp.o intel_sst_pvt.o
+snd-intelmid-objs := intelmid.o intelmid_v0_control.o intelmid_v1_control.o intelmid_v2_control.o intelmid_ctrl.o intelmid_pvt.o
+# Toplevel Module Dependency
+obj-$(CONFIG_SND_INTEL_SST) += snd-intel-sst.o
+obj-$(CONFIG_SND_INTELMID) += snd-intelmid.o
--
1.6.2.2

View File

@ -0,0 +1,465 @@
From b9a664ffe791221bd2d7bc625f8b288d7dc8549a Mon Sep 17 00:00:00 2001
From: Jacob Pan <jacob.jun.pan@intel.com>
Date: Mon, 4 Jan 2010 11:04:34 -0800
Subject: [PATCH 057/104] Ericsson MBM Driver
Signed-off-by: Jacob Pan <jacob.jun.pan@intel.com>
---
drivers/net/usb/Kconfig | 17 ++
drivers/net/usb/Makefile | 1 +
drivers/net/usb/mbm.c | 375 ++++++++++++++++++++++++++++++++++++++++++++
drivers/net/usb/usbnet.c | 3 +
include/linux/usb/usbnet.h | 1 +
5 files changed, 397 insertions(+), 0 deletions(-)
create mode 100644 drivers/net/usb/mbm.c
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index 32d9356..adb6d4c 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -361,6 +361,23 @@ config USB_HSO
To compile this driver as a module, choose M here: the
module will be called hso.
+config USB_NET_MBM
+ tristate "Ericsson Mobile Broadband Module"
+ depends on USB_USBNET
+ select USB_NET_CDCETHER
+ default y
+ help
+ Choose this option to support Mobile Broadband devices from
+ Ericsson MBM, Mobile Broadband Module.
+ This driver should work with at least the following devices:
+ * Ericsson Mobile Broadband Minicard
+ * Ericsson F3507g Wireless Module
+ * Ericsson F3607gw Broadband Module
+ * Dell Wireless 5530 HSPA
+ * Toshiba F3507g
+ * Sony Ericsson EC400
+ * Sony Ericsson MD400
+
config USB_NET_INT51X1
tristate "Intellon PLC based usb adapter"
depends on USB_USBNET
diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile
index e17afb7..82d5f60 100644
--- a/drivers/net/usb/Makefile
+++ b/drivers/net/usb/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_USB_NET_PLUSB) += plusb.o
obj-$(CONFIG_USB_NET_RNDIS_HOST) += rndis_host.o
obj-$(CONFIG_USB_NET_CDC_SUBSET) += cdc_subset.o
obj-$(CONFIG_USB_NET_ZAURUS) += zaurus.o
+obj-$(CONFIG_USB_NET_MBM) += mbm.o
obj-$(CONFIG_USB_NET_MCS7830) += mcs7830.o
obj-$(CONFIG_USB_USBNET) += usbnet.o
obj-$(CONFIG_USB_NET_INT51X1) += int51x1.o
diff --git a/drivers/net/usb/mbm.c b/drivers/net/usb/mbm.c
new file mode 100644
index 0000000..4bb909b
--- /dev/null
+++ b/drivers/net/usb/mbm.c
@@ -0,0 +1,375 @@
+/* -*- linux-c -*-
+ * Copyright (C) 2008 Carl Nordbeck <Carl.Nordbeck@ericsson.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/ctype.h>
+#include <linux/ethtool.h>
+#include <linux/workqueue.h>
+#include <linux/mii.h>
+#include <linux/crc32.h>
+#include <linux/usb.h>
+#include <linux/usb/cdc.h>
+#include <linux/usb/usbnet.h>
+
+#define DRIVER_VERSION "0.03"
+
+/* Bogus speed for bugy HSPA modems */
+#define TX_LINK_SPEED 0x001E8480 /* 2.0 Mbps */
+#define RX_LINK_SPEED 0x006DDD00 /* 7.2 Mbps */
+#define FIX_SPEED 0x00989680 /* 10.0 Mbps */
+
+struct mbm_data {
+ unsigned int rx_speed;
+ unsigned int tx_speed;
+ unsigned int connect;
+};
+
+static const u8 mbm_guid[16] = {
+ 0xa3, 0x17, 0xa8, 0x8b, 0x04, 0x5e, 0x4f, 0x01,
+ 0xa6, 0x07, 0xc0, 0xff, 0xcb, 0x7e, 0x39, 0x2a,
+};
+static void dumpspeed(struct usbnet *dev, __le32 *speeds)
+{
+ struct mbm_data *data = (void *)&dev->data;
+
+ data->rx_speed = __le32_to_cpu(speeds[0]);
+ data->tx_speed = __le32_to_cpu(speeds[1]);
+
+ if (data->rx_speed == FIX_SPEED && data->tx_speed == FIX_SPEED) {
+/* Bogus speed for buggy HSPA modems */
+ dev_info(&dev->udev->dev,
+ "link speeds: %u kbps RX, %u kbps TX\n",
+ RX_LINK_SPEED / 1000, TX_LINK_SPEED / 1000);
+
+ data->rx_speed = RX_LINK_SPEED;
+ data->tx_speed = TX_LINK_SPEED;
+ } else
+ dev_info(&dev->udev->dev,
+ "link speeds: %u kbps RX, %u kbps TX\n",
+ __le32_to_cpu(speeds[0]) / 1000,
+ __le32_to_cpu(speeds[1]) / 1000);
+}
+
+static void mbm_status(struct usbnet *dev, struct urb *urb)
+{
+ struct mbm_data *data = (void *)&dev->data;
+ struct usb_cdc_notification *event;
+
+ if (urb->actual_length < sizeof(*event))
+ return;
+
+ /* SPEED_CHANGE can get split into two 8-byte packets */
+ if (test_and_clear_bit(EVENT_STS_SPLIT, &dev->flags)) {
+ dumpspeed(dev, (__le32 *) urb->transfer_buffer);
+ return;
+ }
+
+ event = urb->transfer_buffer;
+ switch (event->bNotificationType) {
+ case USB_CDC_NOTIFY_NETWORK_CONNECTION:
+ data->connect = event->wValue;
+ if (netif_msg_timer(dev))
+ dev_dbg(&dev->udev->dev, "CDC: carrier %s\n",
+ data->connect ? "on" : "off");
+ if (event->wValue)
+ netif_carrier_on(dev->net);
+ else
+ netif_carrier_off(dev->net);
+ break;
+ case USB_CDC_NOTIFY_SPEED_CHANGE: /* tx/rx rates */
+ if (netif_msg_timer(dev))
+ dev_dbg(&dev->udev->dev, "CDC: speed change (len %d)\n",
+ urb->actual_length);
+ if (urb->actual_length != (sizeof(*event) + 8))
+ set_bit(EVENT_STS_SPLIT, &dev->flags);
+ else
+ dumpspeed(dev, (__le32 *) &event[1]);
+ break;
+ default:
+ dev_err(&dev->udev->dev, "CDC: unexpected notification %02x!\n",
+ event->bNotificationType);
+ break;
+ }
+}
+
+static u8 nibble(unsigned char c)
+{
+ if (likely(isdigit(c)))
+ return c - '0';
+ c = toupper(c);
+ if (likely(isxdigit(c)))
+ return 10 + c - 'A';
+ return 0;
+}
+
+static inline int
+get_ethernet_addr(struct usbnet *dev, struct usb_cdc_ether_desc *e)
+{
+ int tmp, i;
+ unsigned char buf[13];
+
+ tmp = usb_string(dev->udev, e->iMACAddress, buf, sizeof(buf));
+ if (tmp != 12) {
+ dev_dbg(&dev->udev->dev,
+ "bad MAC string %d fetch, %d\n", e->iMACAddress, tmp);
+ if (tmp >= 0)
+ tmp = -EINVAL;
+ return tmp;
+ }
+ for (i = tmp = 0; i < 6; i++, tmp += 2)
+ dev->net->dev_addr[i] =
+ (nibble(buf[tmp]) << 4) + nibble(buf[tmp + 1]);
+ return 0;
+}
+
+static void mbm_get_drvinfo(struct net_device *net,
+ struct ethtool_drvinfo *info)
+{
+ struct usbnet *dev = netdev_priv(net);
+
+ strncpy(info->driver, dev->driver_name, sizeof(info->driver));
+ strncpy(info->version, DRIVER_VERSION, sizeof(info->version));
+ strncpy(info->fw_version, dev->driver_info->description,
+ sizeof(info->fw_version));
+ usb_make_path(dev->udev, info->bus_info, sizeof(info->bus_info));
+}
+
+static struct ethtool_ops mbm_ethtool_ops = {
+ .get_drvinfo = mbm_get_drvinfo,
+ .get_link = usbnet_get_link,
+ .get_msglevel = usbnet_get_msglevel,
+ .set_msglevel = usbnet_set_msglevel,
+ .get_settings = usbnet_get_settings,
+ .set_settings = usbnet_set_settings,
+ .nway_reset = usbnet_nway_reset,
+};
+
+static int mbm_check_connect(struct usbnet *dev)
+{
+ struct mbm_data *data = (void *)&dev->data;
+
+ return !data->connect;
+}
+
+static int mbm_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+ struct cdc_state *info = (void *)&dev->data;
+ struct usb_driver *driver = driver_of(intf);
+ struct usb_interface_descriptor *d = NULL;
+ struct usb_cdc_mdlm_desc *desc = NULL;
+ struct usb_cdc_mdlm_detail_desc *detail = NULL;
+ struct mbm_data *data = NULL;
+
+ u8 *buf = intf->cur_altsetting->extra;
+ int len = intf->cur_altsetting->extralen;
+ int status;
+
+ memset(info, 0, sizeof(*info));
+ info->control = intf;
+ while (len > 3) {
+ if (buf[1] != USB_DT_CS_INTERFACE)
+ goto next_desc;
+
+ switch (buf[2]) {
+ case USB_CDC_MDLM_TYPE:
+ if (info->header)
+ goto bad_desc;
+
+ desc = (void *)buf;
+
+ if (desc->bLength != sizeof(*desc))
+ goto bad_desc;
+
+ if (memcmp(&desc->bGUID, mbm_guid, 16))
+ goto bad_desc;
+ break;
+ case USB_CDC_MDLM_DETAIL_TYPE:
+ if (detail)
+ goto bad_desc;
+
+ detail = (void *)buf;
+
+ if (detail->bGuidDescriptorType == 0) {
+ if (detail->bLength < (sizeof(*detail) + 1))
+ goto bad_desc;
+ }
+ break;
+ case USB_CDC_UNION_TYPE:
+ if (info->u)
+ goto bad_desc;
+
+ info->u = (void *)buf;
+
+ if (info->u->bLength != sizeof(*info->u))
+ goto bad_desc;
+
+ info->control = usb_ifnum_to_if(dev->udev,
+ info->u->
+ bMasterInterface0);
+ info->data =
+ usb_ifnum_to_if(dev->udev,
+ info->u->bSlaveInterface0);
+ if (!info->control || !info->data) {
+ dev_dbg(&intf->dev,
+ "master #%u/%p slave #%u/%p\n",
+ info->u->bMasterInterface0,
+ info->control,
+ info->u->bSlaveInterface0, info->data);
+ goto bad_desc;
+ }
+
+ /* a data interface altsetting does the real i/o */
+ d = &info->data->cur_altsetting->desc;
+ if (d->bInterfaceClass != USB_CLASS_CDC_DATA)
+ goto bad_desc;
+ break;
+ case USB_CDC_ETHERNET_TYPE:
+ if (info->ether)
+ goto bad_desc;
+
+ info->ether = (void *)buf;
+ if (info->ether->bLength != sizeof(*info->ether))
+ goto bad_desc;
+ dev->hard_mtu =
+ le16_to_cpu(info->ether->wMaxSegmentSize);
+ break;
+ }
+next_desc:
+ len -= buf[0]; /* bLength */
+ buf += buf[0];
+ }
+
+ if (!desc || !detail) {
+ dev_dbg(&intf->dev, "missing cdc mdlm %s%sdescriptor\n",
+ desc ? "" : "func ", detail ? "" : "detail ");
+ goto bad_desc;
+ }
+
+ if (!info->u || (!info->ether)) {
+ dev_dbg(&intf->dev, "missing cdc %s%s%sdescriptor\n",
+ info->header ? "" : "header ",
+ info->u ? "" : "union ", info->ether ? "" : "ether ");
+ goto bad_desc;
+ }
+
+ status = usb_driver_claim_interface(driver, info->data, dev);
+ if (status < 0) {
+ dev_dbg(&intf->dev, "Failed claimin interface\n");
+ return status;
+ }
+ status = usbnet_get_endpoints(dev, info->data);
+ if (status < 0) {
+ dev_dbg(&intf->dev, "Failed get endpoints\n");
+ usb_set_intfdata(info->data, NULL);
+ usb_driver_release_interface(driver, info->data);
+ return status;
+ }
+
+ dev->status = NULL;
+ if (info->control->cur_altsetting->desc.bNumEndpoints == 1) {
+ struct usb_endpoint_descriptor *desc;
+
+ dev->status = &info->control->cur_altsetting->endpoint[0];
+ desc = &dev->status->desc;
+ if (!usb_endpoint_is_int_in(desc)
+ || (le16_to_cpu(desc->wMaxPacketSize)
+ < sizeof(struct usb_cdc_notification))
+ || !desc->bInterval) {
+ dev_dbg(&intf->dev, "bad notification endpoint\n");
+ dev->status = NULL;
+ }
+ }
+ usb_set_intfdata(intf, data);
+ dev->net->ethtool_ops = &mbm_ethtool_ops;
+
+ status = get_ethernet_addr(dev, info->ether);
+ if (status < 0) {
+ usb_set_intfdata(info->data, NULL);
+ usb_driver_release_interface(driver_of(intf), info->data);
+ return status;
+ }
+
+ return 0;
+
+bad_desc:
+ dev_info(&dev->udev->dev, "unsupported MDLM descriptors\n");
+ return -ENODEV;
+}
+
+static const struct driver_info mbm_info = {
+ .description = "Mobile Broadband Network Device",
+ .flags = FLAG_MBN,
+ .check_connect = mbm_check_connect,
+ .bind = mbm_bind,
+ .unbind = usbnet_cdc_unbind,
+ .status = mbm_status,
+};
+
+static const struct usb_device_id products[] = {
+ {
+ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_MDLM,
+ USB_CDC_PROTO_NONE),
+ .driver_info = (unsigned long)&mbm_info,
+ },
+
+ {}, /* END */
+};
+
+MODULE_DEVICE_TABLE(usb, products);
+
+int mbm_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ dev_dbg(&intf->dev, "mbm%d_suspend\n", intf->minor);
+ return usbnet_suspend(intf, message);
+}
+
+int mbm_resume(struct usb_interface *intf)
+{
+ dev_dbg(&intf->dev, "mbm%d_resume\n", intf->minor);
+ return usbnet_resume(intf);
+}
+
+static struct usb_driver usbmbm_driver = {
+ .name = "mbm",
+ .id_table = products,
+ .probe = usbnet_probe,
+ .disconnect = usbnet_disconnect,
+ .suspend = mbm_suspend,
+ .resume = mbm_resume,
+ .supports_autosuspend = 1,
+};
+
+static int __init usbmbm_init(void)
+{
+ return usb_register(&usbmbm_driver);
+}
+
+module_init(usbmbm_init);
+
+static void __exit usbmbm_exit(void)
+{
+ usb_deregister(&usbmbm_driver);
+}
+
+module_exit(usbmbm_exit);
+
+MODULE_AUTHOR("Carl Nordbeck");
+MODULE_DESCRIPTION("Ericsson Mobile Broadband");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 035fab0..4733b73 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -1371,6 +1371,9 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
/* WWAN devices should always be named "wwan%d" */
if ((dev->driver_info->flags & FLAG_WWAN) != 0)
strcpy(net->name, "wwan%d");
+ /* MB devices should always be named "mb%d" */
+ if (dev->driver_info->flags & FLAG_MBN)
+ strcpy (net->name, "mb%d");
/* maybe the remote can't receive an Ethernet MTU */
if (net->mtu > (dev->hard_mtu - net->hard_header_len))
diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h
index 8ce6135..e47afbf 100644
--- a/include/linux/usb/usbnet.h
+++ b/include/linux/usb/usbnet.h
@@ -94,6 +94,7 @@ struct driver_info {
#define FLAG_AVOID_UNLINK_URBS 0x0100 /* don't unlink urbs at usbnet_stop() */
#define FLAG_SEND_ZLP 0x0200 /* hw requires ZLPs are sent */
#define FLAG_WWAN 0x0400 /* use "wwan%d" names */
+#define FLAG_MBN 0x0800 /* use "mb%d" names */
#define FLAG_LINK_INTR 0x0800 /* updates link (carrier) status */
--
1.6.2.5

View File

@ -0,0 +1,25 @@
From: Alek Du <alek.du@intel.com>
Date: Mon, 19 Apr 2010 12:39:37 -0800
Subject: [PATCH] ehci: Only enable QH prefetch on Moorestown
Patch-mainline: when mrst code is merged?
Hardware QH prefetch feature is found to be buggy on some none-moorestown
platforms. Disable this feature on other platforms at the moment.
Signed-off-by: Alek Du <alek.du@intel.com>
---
drivers/usb/host/ehci-hcd.c | 2 ++
1 file changed, 2 insertions(+)
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -595,7 +595,9 @@ static int ehci_init(struct usb_hcd *hcd
}
if (HCC_HW_PREFETCH(hcc_params)) {
ehci_dbg(ehci, "HW prefetch capable %d\n", park);
+#ifdef CONFIG_X86_MRST
temp |= (CMD_ASPE | CMD_PSPE);
+#endif
}
if (HCC_CANPARK(hcc_params)) {

View File

@ -0,0 +1,85 @@
From 39fd545bb198f6e17e7e8f730535e3976088cd9f Mon Sep 17 00:00:00 2001
From: Alan Olsen <alan.r.olsen@intel.com>
Date: Fri, 26 Mar 2010 11:59:00 -0700
Subject: [PATCH] GPE fix for sensors
Patch-mainline: 2.6.35?
Signed-off-by: Alan Olsen <alan.r.olsen@intel.com>
---
drivers/hwmon/emc1403.c | 53 ++++++++--------------------------------------
1 files changed, 10 insertions(+), 43 deletions(-)
diff --git a/drivers/hwmon/emc1403.c b/drivers/hwmon/emc1403.c
index 75e3b15..c94d933 100644
--- a/drivers/hwmon/emc1403.c
+++ b/drivers/hwmon/emc1403.c
@@ -33,7 +33,6 @@
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
-#include <linux/gpe.h>
#include <linux/intel_mid.h>
@@ -624,48 +623,16 @@ static int emc1403_probe(struct i2c_client *new_client,
data->therm_irq = t_irq & ~IRQ_TYPE_MASK;
data->alert_irq = a_irq & ~IRQ_TYPE_MASK;
/* interpret irq field */
- if (data->therm_irq == 0x113) {
- if (t_irq & IRQ_TYPE_MASK) {
- /* irq -> GPE_ID */
- res = request_gpe(data->therm_irq,
- (gpio_function_t)therm_interrupt_handler,
- data, DETECT_LEVEL_LOW);
- if (res)
- dev_crit(&new_client->dev, "%s(): cannot \
- register therm gpe \n", __func__);
- } else {
- res = request_irq(data->therm_irq,
- therm_interrupt_handler,
- DETECT_LEVEL_LOW, "emc1403", data);
- if (res)
- dev_crit(&new_client->dev, "%s(): \
- cannot get therm IRQ\n", __func__);
- }
- } else {
- printk(KERN_WARNING"emc1403: IRQ mismatch \
- sent for therm registration");
- }
- if (data->alert_irq == 0x114) {
- if (a_irq & IRQ_TYPE_MASK) {
- /* irq -> GPE_ID */
- res = request_gpe(data->alert_irq,
- (gpio_function_t)alert_interrupt_handler,
- data, DETECT_LEVEL_LOW);
- if (res)
- dev_crit(&new_client->dev, "%s(): \
- cannot register alert gpe \n", __func__);
- } else {
- res = request_irq(data->alert_irq,
- alert_interrupt_handler, DETECT_LEVEL_LOW,
- "emc1403", data);
- if (res)
- dev_crit(&new_client->dev, "%s(): cannot \
+ res = request_irq(data->therm_irq, therm_interrupt_handler,
+ IRQ_TYPE_EDGE_FALLING, "emc1403_therm", data);
+ if (res)
+ dev_crit(&new_client->dev, "%s(): \
+ cannot get therm IRQ\n", __func__);
+ res = request_irq(data->alert_irq, alert_interrupt_handler,
+ IRQ_TYPE_EDGE_FALLING, "emc1403_alert", data);
+ if (res)
+ dev_crit(&new_client->dev, "%s(): cannot \
get alert IRQ\n", __func__);
- }
- } else {
- printk(KERN_WARNING"emc1403: IRQ mismatch \
- sent for alert registration");
- }
#endif
emc1403_set_default_config(new_client);
dev_info(&new_client->dev, "%s EMC1403 Thermal chip found \n",
--
1.6.0.6

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,268 @@
From 60bb8e915a1e55c5a562e59e694d37559d62de92 Mon Sep 17 00:00:00 2001
From: Sreenidhi Gurudatt <sreenidhi.b.gurudatt@intel.com>
Date: Mon, 3 Aug 2009 14:46:37 +0530
Subject: [PATCH 073/104] IPC Host driver for MRSTN. It is disabled by default. This driver implements basic ioctls to support testing of IPC driver from user space. It supports Device firmware upgrade feature to be invoked by user-space application.
modified: drivers/misc/Kconfig
modified: drivers/misc/Makefile
new file: drivers/misc/mrst_test_ipc/Makefile
new file: drivers/misc/mrst_test_ipc/ipc_module.c
Signed-off-by: Sreenidhi Gurudatt <sreenidhi.b.gurudatt@intel.com>
---
drivers/misc/Kconfig | 9 ++
drivers/misc/Makefile | 1 +
drivers/misc/mrst_test_ipc/Makefile | 5 +
drivers/misc/mrst_test_ipc/ipc_module.c | 196 +++++++++++++++++++++++++++++++
4 files changed, 211 insertions(+), 0 deletions(-)
create mode 100644 drivers/misc/mrst_test_ipc/Makefile
create mode 100644 drivers/misc/mrst_test_ipc/ipc_module.c
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index feb9cd9..5a7c342 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -260,6 +260,15 @@ config MRST_RAR_HANDLER
If unsure, say N.
+config MRST_IPC_TEST
+ tristate "IPC driver for testing IPC on Moorestown platform"
+ depends on X86
+ ---help---
+ IPC test driver for Intel Moorestown platform
+ Intel Moorestown platform.
+
+ If unsure, say N.
+
config MRST_VIB
tristate "vibrator driver for Intel Moorestown platform"
help
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 0c24f0f..bce8396 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_TIFM_CORE) += tifm_core.o
obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o
obj-$(CONFIG_PHANTOM) += phantom.o
obj-$(CONFIG_SGI_IOC4) += ioc4.o
+obj-$(CONFIG_MRST_IPC_TEST) += mrst_test_ipc/
obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o
obj-$(CONFIG_KGDB_TESTS) += kgdbts.o
obj-$(CONFIG_SGI_XP) += sgi-xp/
diff --git a/drivers/misc/mrst_test_ipc/Makefile b/drivers/misc/mrst_test_ipc/Makefile
new file mode 100644
index 0000000..047d7db
--- /dev/null
+++ b/drivers/misc/mrst_test_ipc/Makefile
@@ -0,0 +1,5 @@
+
+obj-$(CONFIG_MRST_IPC_TEST) := test_ipc_mrst.o
+
+test_ipc_mrst-y := ipc_module.o \
+
diff --git a/drivers/misc/mrst_test_ipc/ipc_module.c b/drivers/misc/mrst_test_ipc/ipc_module.c
new file mode 100644
index 0000000..51ef8de
--- /dev/null
+++ b/drivers/misc/mrst_test_ipc/ipc_module.c
@@ -0,0 +1,196 @@
+/*
+ * ipc_module.c - Interface for IPC driver funtions exported by IPC driver
+ * interfaces for Moorsetown platform.
+ *
+ * Copyright (C) 2009 Intel Corp
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This driver provides IOCTL interfaces to call IPC driver module for
+ * Moorestown platform.
+ *
+ * Author: Sreenidhi Gurudatt <sreenidhi.b.gurudatt@intel.com>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <linux/fcntl.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <linux/time.h>
+
+#include <asm/ipc_defs.h>
+
+static u32 major;
+#define MAX_FW_SIZE 264192
+
+int init_ipc_driver(void);
+int ipc_ioctl(struct inode *inode, struct file *filp, u32 cmd,
+ unsigned long arg);
+const struct file_operations ipc_fops = {
+ioctl:ipc_ioctl,
+};
+
+
+int ipc_ioctl(struct inode *inode, struct file *filp, u32 cmd,
+ unsigned long arg)
+{
+ u32 upper = 0;
+ struct ipc_pmic_reg_data p_read_reg_data = { 0 };
+ struct ipc_pmic_mod_reg_data p_read_mod_reg_data = { 0 };
+ struct ipc_pmic_reg_data p_write_reg_data = { 0 };
+ u8 ipc_blocking_flag = TRUE;
+
+ int ret_val;
+ /*Device FW upgrade support*/
+ u8 *fw_buf = NULL ;
+
+ switch (cmd) {
+ case IPC_PMIC_REGISTER_READ:
+ {
+ printk(KERN_INFO
+ "ipc_driver IPC_PMIC_REGISTER_READ received\n");
+ ret_val =
+ copy_from_user(&p_read_reg_data,
+ (struct ipc_pmic_reg_data *)arg,
+ sizeof(struct ipc_pmic_reg_data));
+ if (ret_val < 0) {
+ printk(KERN_DEBUG
+ "copy_from_user FAILED!! <%s> function\
+ in <%s> file at <%d> line no\n",\
+ __func__, __FILE__, __LINE__);
+ return E_READ_USER_DATA;
+ }
+
+ ipc_pmic_register_read(&p_read_reg_data);
+ ret_val =
+ copy_to_user((struct ipc_pmic_reg_data *)arg,
+ &p_read_reg_data,
+ sizeof(struct ipc_pmic_reg_data));
+ break;
+ }
+ case IPC_PMIC_REGISTER_READ_MODIFY:
+ {
+ printk(KERN_INFO "ioctl\
+ IPC_PMIC_REGISTER_READ_MODIFY received\n");
+ ret_val =
+ copy_from_user(&p_read_mod_reg_data,
+ (struct ipc_pmic_mod_reg_data *)arg,
+ sizeof(struct ipc_pmic_mod_reg_data));
+ if (ret_val < 0) {
+ printk(KERN_DEBUG
+ "copy_from_user FAILED!! <%s> function\
+ in <%s> file at <%d> line no\n",\
+ __func__, __FILE__, __LINE__);
+ return E_READ_USER_DATA;
+ }
+ ipc_pmic_register_read_modify(&p_read_mod_reg_data);
+ ret_val =
+ copy_to_user((struct ipc_pmic_mod_reg_data *)arg,
+ &p_read_mod_reg_data,
+ sizeof(struct ipc_pmic_mod_reg_data));
+ break;
+ }
+ case IPC_PMIC_REGISTER_WRITE:
+ {
+ ret_val =
+ copy_from_user(&p_write_reg_data,
+ (struct ipc_pmic_reg_data *)arg,
+ sizeof(struct ipc_pmic_reg_data));
+ if (ret_val < 0) {
+ printk(KERN_DEBUG
+ "copy_from_user FAILED!! <%s> function\
+ in <%s> file at <%d> line no\n",\
+ __func__, __FILE__, __LINE__);
+ return E_WRITE_USER_DATA;
+ }
+ ipc_pmic_register_write(&p_write_reg_data,
+ ipc_blocking_flag);
+ ret_val =
+ copy_to_user((struct ipc_pmic_reg_data *)arg,
+ &p_write_reg_data,
+ sizeof(struct ipc_pmic_reg_data));
+ break;
+ }
+ case DEVICE_FW_UPGRADE:
+ {
+ printk(KERN_INFO "ioctl DEVICE_FW_UPGRADE received\n");
+ fw_buf = kmalloc(MAX_FW_SIZE, GFP_KERNEL);
+ if (fw_buf == NULL) {
+ printk(KERN_ERR "ipc_test: kmalloc failed! \n");
+ return -EBUSY;
+ }
+ ret_val = copy_from_user(fw_buf, (u8 *)arg,
+ MAX_FW_SIZE);
+ if (ret_val < 0) {
+ printk(KERN_DEBUG
+ "copy_from_user FAILED!! <%s> function\
+ in <%s> file at <%d> line no\n",\
+ __func__, __FILE__, __LINE__);
+ return -EINVAL;
+ }
+ ipc_device_fw_upgrade(fw_buf, MAX_FW_SIZE);
+ break;
+ }
+ default:
+ {
+ printk(KERN_INFO
+ "ioctl <UNRECOGNIZED> received\n");
+ break;
+ }
+ }
+ return upper;
+}
+
+static int __init ipc_module_init(void)
+{
+ printk(KERN_INFO "Init ipc_module\n");
+
+ major = register_chrdev(0, "mid_ipc", &ipc_fops);
+ if (major < 0) {
+ printk(KERN_ERR "ipc_test : failed to get major\n");
+ return major;
+ }
+
+ init_ipc_driver ( ) ;
+ return SUCCESS;
+
+}
+
+static void __exit ipc_module_exit(void)
+{
+ unregister_chrdev(major, "mid_ipc");
+}
+
+module_init(ipc_module_init);
+module_exit(ipc_module_exit);
+
+MODULE_LICENSE("GPL V2");
+MODULE_DESCRIPTION("Test Driver for MRST IPC driver");
+MODULE_AUTHOR("Sreenidhi Gurudatt")
+
--
1.6.2.5

View File

@ -0,0 +1,839 @@
From 3e65e5210bc3c81a58c60e365ee044f2e6044efc Mon Sep 17 00:00:00 2001
From: Zheng Ba <zheng.ba@intel.com>
Date: Sun, 22 Nov 2009 16:22:31 +0800
Subject: [PATCH 047/104] Full keypad controller driver patch for Beta
This patch adds the keypad support for Moorestown platform.
Changes from Alpha2: solved "CRITICAL" issues marked by Klocwork
HSD sighting 3469242
Signed-off-by: Zheng Ba <zheng.ba@intel.com>
---
drivers/input/keyboard/Kconfig | 7 +
drivers/input/keyboard/Makefile | 1 +
drivers/input/keyboard/mrst_keypad.c | 782 ++++++++++++++++++++++++++++++++++
3 files changed, 790 insertions(+), 0 deletions(-)
create mode 100644 drivers/input/keyboard/mrst_keypad.c
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index f7a4497..4c2bdaf 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -292,6 +292,13 @@ config KEYBOARD_MAX7359
To compile this driver as a module, choose M here: the
module will be called max7359_keypad.
+config KEYBOARD_MRST
+ tristate "MRST keypad support"
+ depends on GPIO_LANGWELL
+ help
+ Say Y if you want to use the mrst keypad
+ depends on GPIO_LANGWELL
+
config KEYBOARD_NEWTON
tristate "Newton keyboard"
select SERIO
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 78654ef..0337f76 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o
obj-$(CONFIG_KEYBOARD_CORGI) += corgikbd.o
obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o
obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o
+obj-$(CONFIG_KEYBOARD_MRST) += mrst_keypad.o
obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o
obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o
obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o
diff --git a/drivers/input/keyboard/mrst_keypad.c b/drivers/input/keyboard/mrst_keypad.c
new file mode 100644
index 0000000..faf3ab7
--- /dev/null
+++ b/drivers/input/keyboard/mrst_keypad.c
@@ -0,0 +1,782 @@
+/*
+ * linux/drivers/input/keyboard/mrst_keypad.c
+ *
+ * Driver for the matrix keypad controller on Moorestown platform.
+ *
+ * Copyright (c) 2009 Intel Corporation.
+ * Created: Sep 18, 2008
+ * Updated: Apr 24, 2009
+ *
+ * Based on pxa27x_keypad.c by Rodolfo Giometti <giometti@linux.it>
+ * pxa27x_keypad.c is based on a previous implementation by Kevin O'Connor
+ * <kevin_at_keconnor.net> and Alex Osborne <bobofdoom@gmail.com> and
+ * on some suggestions by Nicolas Pitre <nico@cam.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#define DRV_NAME "mrst_keypad"
+#define DRV_VERSION "0.0.1"
+#define MRST_KEYPAD_DRIVER_NAME DRV_NAME " " DRV_VERSION
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+
+/*
+ * Keypad Controller registers
+ */
+#define KPC 0x0000 /* Keypad Control register */
+#define KPDK 0x0004 /* Keypad Direct Key register */
+#define KPREC 0x0008 /* Keypad Rotary Encoder register */
+#define KPMK 0x000C /* Keypad Matrix Key register */
+#define KPAS 0x0010 /* Keypad Automatic Scan register */
+
+/* Keypad Automatic Scan Multiple Key Presser register 0-3 */
+#define KPASMKP0 0x0014
+#define KPASMKP1 0x0018
+#define KPASMKP2 0x001C
+#define KPASMKP3 0x0020
+#define KPKDI 0x0024
+
+/* bit definitions */
+#define KPC_MKRN(n) ((((n) - 1) & 0x7) << 26) /* matrix key row number */
+#define KPC_MKCN(n) ((((n) - 1) & 0x7) << 23) /* matrix key col number */
+#define KPC_DKN(n) ((((n) - 1) & 0x7) << 6) /* direct key number */
+
+#define KPC_AS (0x1 << 30) /* Automatic Scan bit */
+#define KPC_ASACT (0x1 << 29) /* Automatic Scan on Activity */
+#define KPC_MI (0x1 << 22) /* Matrix interrupt bit */
+#define KPC_IMKP (0x1 << 21) /* Ignore Multiple Key Press */
+
+#define KPC_MS(n) (0x1 << (13 + (n))) /* Matrix scan line 'n' */
+#define KPC_MS_ALL (0xff << 13)
+
+#define KPC_ME (0x1 << 12) /* Matrix Keypad Enable */
+#define KPC_MIE (0x1 << 11) /* Matrix Interrupt Enable */
+#define KPC_DK_DEB_SEL (0x1 << 9) /* Direct Keypad Debounce Select */
+#define KPC_DI (0x1 << 5) /* Direct key interrupt bit */
+#define KPC_RE_ZERO_DEB (0x1 << 4) /* Rotary Encoder Zero Debounce */
+#define KPC_REE1 (0x1 << 3) /* Rotary Encoder1 Enable */
+#define KPC_REE0 (0x1 << 2) /* Rotary Encoder0 Enable */
+#define KPC_DE (0x1 << 1) /* Direct Keypad Enable */
+#define KPC_DIE (0x1 << 0) /* Direct Keypad interrupt Enable */
+
+#define KPDK_DKP (0x1 << 31)
+#define KPDK_DK(n) ((n) & 0xff)
+
+#define KPREC_OF1 (0x1 << 31)
+#define kPREC_UF1 (0x1 << 30)
+#define KPREC_OF0 (0x1 << 15)
+#define KPREC_UF0 (0x1 << 14)
+
+#define KPREC_RECOUNT0(n) ((n) & 0xff)
+#define KPREC_RECOUNT1(n) (((n) >> 16) & 0xff)
+
+#define KPMK_MKP (0x1 << 31)
+#define KPAS_SO (0x1 << 31)
+#define KPASMKPx_SO (0x1 << 31)
+
+#define KPAS_MUKP(n) (((n) >> 26) & 0x1f)
+#define KPAS_RP(n) (((n) >> 4) & 0xf)
+#define KPAS_CP(n) ((n) & 0xf)
+
+#define KPASMKP_MKC_MASK (0xff)
+
+#define KEYPAD_MATRIX_GPIO_IN_PIN 24
+#define KEYPAD_MATRIX_GPIO_OUT_PIN 32
+#define KEYPAD_DIRECT_GPIO_IN_PIN 40
+
+
+static struct pci_device_id keypad_pci_tbl[] = {
+ {0x8086, 0x0805, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ {0,}
+};
+MODULE_DEVICE_TABLE(pci, keypad_pci_tbl);
+
+#define keypad_readl(off) readl(keypad->mmio_base + (off))
+#define keypad_writel(off, v) writel((v), keypad->mmio_base + (off))
+
+#define MAX_MATRIX_KEY_NUM (8 * 8)
+#define MAX_DIRECT_KEY_NUM (4)
+
+#define MAX_MATRIX_KEY_ROWS (8)
+#define MAX_MATRIX_KEY_COLS (8)
+#define DEBOUNCE_INTERVAL 100
+
+#define KEY_HALFSHUTTER KEY_PROG1
+#define KEY_FULLSHUTTER KEY_CAMERA
+
+static unsigned int mrst_keycode[MAX_MATRIX_KEY_NUM] = {
+ KEY_F, KEY_D, KEY_E, KEY_GRAVE, KEY_C, KEY_R, KEY_4, KEY_V,
+ KEY_NUMLOCK, KEY_LEFTCTRL, KEY_Z, KEY_W, KEY_2, KEY_X, KEY_S, KEY_3,
+ KEY_EQUAL, KEY_N, KEY_H, KEY_U, KEY_7, KEY_M, KEY_J, KEY_8,
+ KEY_6, KEY_5, KEY_APOSTROPHE, KEY_G, KEY_T, KEY_SPACE, KEY_B, KEY_Y,
+ KEY_MINUS, KEY_0, KEY_LEFT, KEY_SEMICOLON, KEY_P, KEY_DOWN, KEY_UP,
+ KEY_BACKSPACE,
+ KEY_L, KEY_K, KEY_I, KEY_SLASH, KEY_COMMA, KEY_O, KEY_9, KEY_DOT,
+ KEY_Q, KEY_TAB, KEY_ESC, KEY_LEFTSHIFT, KEY_CAPSLOCK, KEY_1, KEY_FN,
+ KEY_A,
+ 0, KEY_RIGHTSHIFT, KEY_ENTER, 0, KEY_RIGHT, 0, 0, 0,
+};
+
+/* NumLk key mapping */
+static unsigned int mrst_keycode_numlck[MAX_MATRIX_KEY_NUM] = {
+ KEY_F, KEY_D, KEY_E, KEY_GRAVE, KEY_C, KEY_R, KEY_4, KEY_V,
+ KEY_NUMLOCK, KEY_LEFTCTRL, KEY_Z, KEY_W, KEY_2, KEY_X, KEY_S, KEY_3,
+ KEY_EQUAL, KEY_N, KEY_H, KEY_KP4, KEY_KP7, KEY_KP0, KEY_KP1, KEY_KP8,
+ KEY_6, KEY_5, KEY_APOSTROPHE, KEY_G, KEY_T, KEY_SPACE, KEY_B, KEY_Y,
+ KEY_MINUS, KEY_KPSLASH, KEY_LEFT, KEY_KPMINUS, KEY_KPASTERISK,
+ KEY_DOWN, KEY_UP, KEY_BACKSPACE,
+ KEY_KP3, KEY_KP2, KEY_KP5, KEY_SLASH, KEY_KPDOT, KEY_KP6, KEY_KP9,
+ KEY_KPPLUS,
+ KEY_Q, KEY_TAB, KEY_ESC, KEY_LEFTSHIFT, KEY_CAPSLOCK, KEY_1, KEY_FN,
+ KEY_A,
+ 0, KEY_RIGHTSHIFT, KEY_ENTER, 0, KEY_RIGHT, 0, 0, 0,
+};
+
+/* Fn key mapping */
+static unsigned int mrst_keycode_fn[MAX_MATRIX_KEY_NUM] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ KEY_LEFTBRACE, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, KEY_HOME, 0, 0, KEY_PAGEDOWN, KEY_PAGEUP, 0,
+ 0, 0, 0, KEY_RIGHTBRACE, KEY_LEFTBRACE, 0, 0, KEY_RIGHTBRACE,
+ 0, 0, 0, KEY_LEFTSHIFT, 0, 0, KEY_FN, 0,
+ 0, KEY_RIGHTSHIFT, 0, 0, KEY_END, 0, 0, 0,
+};
+
+/* direct key map */
+static unsigned int mrst_direct_keycode[MAX_DIRECT_KEY_NUM] = {
+ KEY_VOLUMEUP, KEY_VOLUMEDOWN, KEY_HALFSHUTTER, KEY_FULLSHUTTER,
+};
+
+struct mrst_keypad {
+
+ struct input_dev *input_dev;
+ void __iomem *mmio_base;
+
+ unsigned int matrix_key_rows;
+ unsigned int matrix_key_cols;
+ int matrix_key_map_size;
+
+ /* key debounce interval */
+ unsigned int debounce_interval;
+
+ /* matrix key code map */
+ unsigned int matrix_keycodes[MAX_MATRIX_KEY_NUM];
+
+ /* state row bits of each column scan */
+ uint32_t matrix_key_state[MAX_MATRIX_KEY_COLS];
+ uint32_t direct_key_state;
+
+ unsigned int direct_key_mask;
+
+ int direct_key_num;
+
+ unsigned int direct_key_map[MAX_DIRECT_KEY_NUM];
+
+ /* rotary encoders 0 */
+ int enable_rotary0;
+ int rotary0_rel_code;
+ int rotary0_up_key;
+ int rotary0_down_key;
+
+ /* rotary encoders 1 */
+ int enable_rotary1;
+ int rotary1_rel_code;
+ int rotary1_up_key;
+ int rotary1_down_key;
+
+ int rotary_rel_code[2];
+ int rotary_up_key[2];
+ int rotary_down_key[2];
+
+ /* Fn key */
+ int fn;
+
+ /* Number Lock key */
+ int numlck;
+
+ /* FIXME:
+ * Keypad controller likely issues fake interrupts
+ * when direct key status registers were first initialized
+ * This value assures this interrupt will not be proceeded.
+ */
+ int count;
+};
+
+static void mrst_keypad_build_keycode(struct mrst_keypad *keypad)
+{
+ struct input_dev *input_dev = keypad->input_dev;
+ unsigned int *key;
+ int i, code;
+
+ keypad->matrix_key_rows = MAX_MATRIX_KEY_ROWS;
+ keypad->matrix_key_cols = MAX_MATRIX_KEY_COLS;
+ keypad->matrix_key_map_size = MAX_MATRIX_KEY_NUM;
+ keypad->debounce_interval = DEBOUNCE_INTERVAL;
+
+ /* three sets of keycode here */
+ if (keypad->fn)
+ memcpy(keypad->matrix_keycodes, mrst_keycode_fn,
+ sizeof(keypad->matrix_keycodes));
+ else if (keypad->numlck)
+ memcpy(keypad->matrix_keycodes, mrst_keycode_numlck,
+ sizeof(keypad->matrix_keycodes));
+ else
+ memcpy(keypad->matrix_keycodes, mrst_keycode,
+ sizeof(keypad->matrix_keycodes));
+
+ memcpy(keypad->direct_key_map, mrst_direct_keycode,
+ sizeof(keypad->direct_key_map));
+
+ key = &keypad->matrix_keycodes[0];
+ for (i = 0; i < MAX_MATRIX_KEY_NUM; i++, key++) {
+ code = (*key) & 0xffffff;
+ set_bit(code, input_dev->keybit);
+ }
+
+ key = &keypad->direct_key_map[0];
+ for (i = 0; i < MAX_DIRECT_KEY_NUM; i++, key++) {
+ code = (*key) & 0xffffff;
+ set_bit(code, input_dev->keybit);
+ }
+
+ keypad->direct_key_num = MAX_DIRECT_KEY_NUM;
+ keypad->enable_rotary0 = 0;
+ keypad->enable_rotary1 = 0;
+
+}
+
+static inline unsigned int lookup_matrix_keycode(
+ struct mrst_keypad *keypad, int row, int col)
+{
+ return keypad->matrix_keycodes[(row << 3) + col];
+}
+
+static void handle_constant_keypress(struct mrst_keypad *keypad,
+ int num, int col, int row,
+ int state)
+{
+ struct input_dev *dev = keypad->input_dev;
+
+ switch (num) {
+ case 0:
+ if (keypad->fn)
+ keypad->fn = 0;
+ /* Manually release special keys (Fn combinations) */
+ if (test_bit(KEY_LEFTBRACE, dev->key))
+ input_report_key(dev, KEY_LEFTBRACE, 0);
+ if (test_bit(KEY_RIGHTBRACE, dev->key))
+ input_report_key(dev, KEY_RIGHTBRACE, 0);
+ if (test_bit(KEY_HOME, dev->key))
+ input_report_key(dev, KEY_RIGHTBRACE, 0);
+ if (test_bit(KEY_END, dev->key))
+ input_report_key(dev, KEY_END, 0);
+ if (test_bit(KEY_PAGEUP, dev->key))
+ input_report_key(dev, KEY_RIGHTBRACE, 0);
+ if (test_bit(KEY_PAGEDOWN, dev->key))
+ input_report_key(dev, KEY_RIGHTBRACE, 0);
+
+ return;
+
+ case 1:
+ /* if Fn pressed */
+ if (col == 6 && row == 6)
+ keypad->fn = 1;
+ /* key '[' */
+ else if ((col == 0 && row == 2) && state) {
+ keypad->fn = 0;
+ set_bit(KEY_EQUAL, dev->key);
+ dev->repeat_key = KEY_EQUAL;
+ }
+ /* key ']' */
+ else if ((col == 3 && row == 5) && state) {
+ keypad->fn = 0;
+ set_bit(KEY_SLASH, dev->key);
+ dev->repeat_key = KEY_SLASH;
+ }
+ /* key '{' */
+ else if ((col == 4 && row == 5) && state) {
+ keypad->fn = 0;
+ set_bit(KEY_COMMA, dev->key);
+ dev->repeat_key = KEY_COMMA;
+ }
+ /* key '}' */
+ else if ((col == 7 && row == 5) && state) {
+ keypad->fn = 0;
+ set_bit(KEY_DOT, dev->key);
+ dev->repeat_key = KEY_DOT;
+ }
+
+ return;
+ default:
+ ;
+ }
+}
+
+static void mrst_keypad_scan_matrix(struct mrst_keypad *keypad)
+{
+ int row, col, num_keys_pressed = 0;
+ uint32_t new_state[MAX_MATRIX_KEY_COLS];
+ uint32_t kpas = keypad_readl(KPAS);
+ int status;
+
+ num_keys_pressed = KPAS_MUKP(kpas);
+
+ memset(new_state, 0, sizeof(new_state));
+
+ if (num_keys_pressed == 0) {
+ status = keypad->matrix_key_state[0] & (1 << 0);
+ handle_constant_keypress(keypad, num_keys_pressed, 0, 0,
+ status);
+
+ goto scan;
+ }
+
+ if (num_keys_pressed == 1) {
+ col = KPAS_CP(kpas);
+ row = KPAS_RP(kpas);
+
+ /* if invalid row/col, treat as no key pressed */
+ if (col < MAX_MATRIX_KEY_COLS &&
+ row < MAX_MATRIX_KEY_ROWS) {
+
+ /* if NumLk pressed */
+ if (col == 0 && row == 1)
+ keypad->numlck = !keypad->numlck;
+
+ status = keypad->matrix_key_state[col] & (1 << row);
+ handle_constant_keypress(keypad, num_keys_pressed, col,
+ row, status);
+
+ new_state[col] = (1 << row);
+ }
+
+ goto scan;
+ }
+
+ if (num_keys_pressed > 1) {
+ uint32_t kpasmkp0 = keypad_readl(KPASMKP0);
+ uint32_t kpasmkp1 = keypad_readl(KPASMKP1);
+ uint32_t kpasmkp2 = keypad_readl(KPASMKP2);
+ uint32_t kpasmkp3 = keypad_readl(KPASMKP3);
+
+ new_state[0] = kpasmkp0 & KPASMKP_MKC_MASK;
+ new_state[1] = (kpasmkp0 >> 16) & KPASMKP_MKC_MASK;
+ new_state[2] = kpasmkp1 & KPASMKP_MKC_MASK;
+ new_state[3] = (kpasmkp1 >> 16) & KPASMKP_MKC_MASK;
+ new_state[4] = kpasmkp2 & KPASMKP_MKC_MASK;
+ new_state[5] = (kpasmkp2 >> 16) & KPASMKP_MKC_MASK;
+ new_state[6] = kpasmkp3 & KPASMKP_MKC_MASK;
+ new_state[7] = (kpasmkp3 >> 16) & KPASMKP_MKC_MASK;
+
+ /* if Fn is pressed, all SHIFT is ignored, except when {
+ * or } is pressed */
+ if (new_state[6] & 0x40) {
+ keypad->fn = 1;
+ new_state[3] &= ~0x40;
+ new_state[1] &= ~0x80;
+ }
+
+ if (keypad->fn == 1) {
+ /* if { or } pressed */
+ if ((new_state[4] & 0x20) || (new_state[7] & 0x20)) {
+ /* as if LEFTSHIFT is pressed */
+ new_state[3] |= 0x40;
+ /* as if Fn not pressed */
+ new_state[6] &= ~0x40;
+ }
+ /* if [ or ] pressed */
+ if ((new_state[0] & 0x04) || (new_state[3] & 0x20))
+ /* as if Fn not pressed */
+ new_state[6] &= ~0x40;
+ }
+ }
+
+
+scan:
+ /* re-build keycode */
+ mrst_keypad_build_keycode(keypad);
+
+ for (col = 0; col < keypad->matrix_key_cols; col++) {
+ uint32_t bits_changed;
+
+ bits_changed = keypad->matrix_key_state[col] ^ new_state[col];
+ if (bits_changed == 0)
+ continue;
+
+ for (row = 0; row < keypad->matrix_key_rows; row++) {
+ if ((bits_changed & (1 << row)) == 0)
+ continue;
+
+ input_report_key(keypad->input_dev,
+ lookup_matrix_keycode(keypad, row, col),
+ new_state[col] & (1 << row));
+ }
+ }
+ input_sync(keypad->input_dev);
+ memcpy(keypad->matrix_key_state, new_state, sizeof(new_state));
+}
+
+#define DEFAULT_KPREC (0x007f007f)
+
+static inline int rotary_delta(uint32_t kprec)
+{
+ if (kprec & KPREC_OF0)
+ return (kprec & 0xff) + 0x7f;
+ else if (kprec & KPREC_UF0)
+ return (kprec & 0xff) - 0x7f - 0xff;
+ else
+ return (kprec & 0xff) - 0x7f;
+}
+
+static void report_rotary_event(struct mrst_keypad *keypad, int r, int delta)
+{
+ struct input_dev *dev = keypad->input_dev;
+
+ if (delta == 0)
+ return;
+
+ if (keypad->rotary_up_key[r] && keypad->rotary_down_key[r]) {
+ int keycode = (delta > 0) ? keypad->rotary_up_key[r] :
+ keypad->rotary_down_key[r];
+
+ /* simulate a press-n-release */
+ input_report_key(dev, keycode, 1);
+ input_sync(dev);
+ input_report_key(dev, keycode, 0);
+ input_sync(dev);
+ } else {
+ input_report_rel(dev, keypad->rotary_rel_code[r], delta);
+ input_sync(dev);
+ }
+}
+
+static void mrst_keypad_scan_rotary(struct mrst_keypad *keypad)
+{
+ unsigned int kprec;
+
+ /* read and reset to default count value */
+ kprec = keypad_readl(KPREC);
+ keypad_writel(KPREC, DEFAULT_KPREC);
+
+ if (keypad->enable_rotary0)
+ report_rotary_event(keypad, 0, rotary_delta(kprec));
+
+ if (keypad->enable_rotary1)
+ report_rotary_event(keypad, 1, rotary_delta(kprec >> 16));
+}
+
+static void mrst_keypad_scan_direct(struct mrst_keypad *keypad)
+{
+ unsigned int new_state;
+ uint32_t kpdk, bits_changed;
+ int i;
+
+ kpdk = keypad_readl(KPDK);
+
+ if (keypad->enable_rotary0 || keypad->enable_rotary1)
+ mrst_keypad_scan_rotary(keypad);
+
+ if ((keypad->direct_key_map == NULL) || (++keypad->count == 1)) {
+ keypad->direct_key_state = 0;
+ return;
+ }
+
+ new_state = KPDK_DK(kpdk) & keypad->direct_key_mask;
+ new_state = ~new_state;
+ bits_changed = keypad->direct_key_state ^ new_state;
+
+ if (bits_changed == 0)
+ return;
+
+ for (i = 0; i < keypad->direct_key_num; i++) {
+ if (bits_changed & (1 << i)) {
+ input_report_key(keypad->input_dev,
+ keypad->direct_key_map[i],
+ (new_state & (1 << i)));
+ }
+ }
+ input_sync(keypad->input_dev);
+ keypad->direct_key_state = new_state;
+
+}
+
+static irqreturn_t mrst_keypad_irq_handler(int irq, void *dev_id)
+{
+ struct mrst_keypad *keypad = dev_id;
+ unsigned long kpc = keypad_readl(KPC);
+
+ if (kpc & KPC_DI)
+ mrst_keypad_scan_direct(keypad);
+
+ if (kpc & KPC_MI)
+ mrst_keypad_scan_matrix(keypad);
+
+ return IRQ_HANDLED;
+}
+
+static int mrst_keypad_gpio_init(void)
+{
+ int i, err, cnt = 0;
+ int pins = KEYPAD_MATRIX_GPIO_IN_PIN + MAX_MATRIX_KEY_ROWS +
+ MAX_MATRIX_KEY_COLS + MAX_DIRECT_KEY_NUM;
+
+ /* explicitely tell which pins have been occupied... */
+ for (i = KEYPAD_MATRIX_GPIO_IN_PIN; i < pins; i++, cnt++) {
+ err = gpio_request(i, NULL);
+ if (err) {
+ printk(KERN_ERR "GPIO pin %d failed to request.\n", i);
+ goto err_request;
+ }
+ }
+
+ for (i = 0; i < MAX_MATRIX_KEY_ROWS; i++)
+ gpio_direction_input(KEYPAD_MATRIX_GPIO_IN_PIN + i);
+
+ for (i = 0; i < MAX_MATRIX_KEY_COLS; i++)
+ /* __gpio_set_value(KEYPAD_GPIO_OUT_PIN + i, 1); */
+ /* set action is executed in gpio_direction_output() */
+ gpio_direction_output(KEYPAD_MATRIX_GPIO_OUT_PIN + i, 1);
+
+ for (i = 0; i < MAX_DIRECT_KEY_NUM; i++)
+ gpio_direction_input(KEYPAD_DIRECT_GPIO_IN_PIN + i);
+
+ return 0;
+
+err_request:
+ /* free requested pins... */
+ for (i = KEYPAD_MATRIX_GPIO_IN_PIN + cnt - 1;
+ i >= KEYPAD_MATRIX_GPIO_IN_PIN; i--)
+ gpio_free(i);
+ return err;
+}
+
+static void mrst_keypad_config(struct mrst_keypad *keypad)
+{
+ unsigned int mask = 0, direct_key_num = 0;
+ unsigned long kpc = 0;
+
+ /* enable matrix keys with automatic scan */
+ if (keypad->matrix_key_rows && keypad->matrix_key_cols) {
+ kpc |= KPC_ASACT | KPC_MIE | KPC_ME | KPC_MS_ALL;
+ kpc |= KPC_MKRN(keypad->matrix_key_rows) |
+ KPC_MKCN(keypad->matrix_key_cols);
+ }
+
+ /* enable rotary key, debounce interval same as direct keys */
+ if (keypad->enable_rotary0) {
+ mask |= 0x03;
+ direct_key_num = 2;
+ kpc |= KPC_REE0;
+ }
+
+ if (keypad->enable_rotary1) {
+ mask |= 0x0c;
+ direct_key_num = 4;
+ kpc |= KPC_REE1;
+ }
+
+ if (keypad->direct_key_num > direct_key_num)
+ direct_key_num = keypad->direct_key_num;
+
+ keypad->direct_key_mask = ((2 << direct_key_num) - 1) & ~mask;
+
+ /* enable direct key */
+ if (direct_key_num)
+ kpc |= KPC_DE | KPC_DIE | KPC_DKN(direct_key_num);
+
+ keypad_writel(KPC, kpc);
+ keypad_writel(KPREC, DEFAULT_KPREC);
+ keypad_writel(KPKDI, keypad->debounce_interval);
+}
+
+static int mrst_keypad_open(struct input_dev *dev)
+{
+ struct mrst_keypad *keypad = input_get_drvdata(dev);
+ int err;
+
+ err = mrst_keypad_gpio_init();
+ if (err)
+ return err;
+ mrst_keypad_config(keypad);
+
+ return 0;
+}
+
+static void mrst_keypad_close(struct input_dev *dev)
+{
+ int pins = KEYPAD_MATRIX_GPIO_IN_PIN + MAX_MATRIX_KEY_ROWS +
+ MAX_MATRIX_KEY_COLS + MAX_DIRECT_KEY_NUM;
+
+ int i;
+ /* free occupied pins */
+ for (i = KEYPAD_MATRIX_GPIO_IN_PIN; i < pins; i++)
+ gpio_free(i);
+}
+
+static int __devinit mrst_keypad_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct mrst_keypad *keypad;
+ struct input_dev *input_dev;
+ int error;
+
+#ifndef MODULE
+ printk(KERN_INFO MRST_KEYPAD_DRIVER_NAME "\n");
+#endif
+
+ keypad = kzalloc(sizeof(struct mrst_keypad), GFP_KERNEL);
+ if (keypad == NULL) {
+ dev_err(&pdev->dev, "failed to allocate driver data\n");
+ return -ENOMEM;
+ }
+
+ error = pci_enable_device(pdev);
+ if (error || (pdev->irq < 0)) {
+ dev_err(&pdev->dev, "failed to enable device/get irq\n");
+ error = -ENXIO;
+ goto failed_free;
+ }
+
+ error = pci_request_regions(pdev, DRV_NAME);
+ if (error) {
+ dev_err(&pdev->dev, "failed to request I/O memory\n");
+ goto failed_free;
+ }
+
+ keypad->mmio_base = ioremap(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
+ if (keypad->mmio_base == NULL) {
+ dev_err(&pdev->dev, "failed to remap I/O memory\n");
+ error = -ENXIO;
+ goto failed_free_mem;
+ }
+
+ /* Create and register the input driver. */
+ input_dev = input_allocate_device();
+ if (!input_dev) {
+ dev_err(&pdev->dev, "failed to allocate input device\n");
+ error = -ENOMEM;
+ goto failed_free_io;
+ }
+
+ input_dev->name = pci_name(pdev);
+ input_dev->id.bustype = BUS_PCI;
+ input_dev->open = mrst_keypad_open;
+ input_dev->close = mrst_keypad_close;
+ input_dev->dev.parent = &pdev->dev;
+
+ input_dev->keycode = keypad->matrix_keycodes;
+ input_dev->keycodesize = sizeof(unsigned int);
+ input_dev->keycodemax = ARRAY_SIZE(mrst_keycode);
+
+ keypad->input_dev = input_dev;
+ keypad->fn = 0;
+ keypad->numlck = 0;
+ /*FIXME*/keypad->count = 0;
+ input_set_drvdata(input_dev, keypad);
+
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) |
+ BIT_MASK(EV_REL);
+
+ mrst_keypad_build_keycode(keypad);
+ pci_set_drvdata(pdev, keypad);
+
+ error = request_irq(pdev->irq, mrst_keypad_irq_handler, IRQF_SHARED,
+ pci_name(pdev), keypad);
+ if (error) {
+ dev_err(&pdev->dev, "failed to request IRQ\n");
+ goto failed_free_dev;
+ }
+
+ /* Register the input device */
+ error = input_register_device(input_dev);
+ if (error) {
+ dev_err(&pdev->dev, "failed to register input device\n");
+ goto failed_free_irq;
+ }
+
+ printk(KERN_INFO "*** keypad driver load successfully ***\n");
+ return 0;
+
+failed_free_irq:
+ free_irq(pdev->irq, keypad);
+ pci_set_drvdata(pdev, NULL);
+failed_free_dev:
+ input_free_device(input_dev);
+failed_free_io:
+ iounmap(keypad->mmio_base);
+failed_free_mem:
+ pci_release_regions(pdev);
+failed_free:
+ kfree(keypad);
+ return error;
+}
+
+static void __devexit mrst_keypad_remove(struct pci_dev *pdev)
+{
+ struct mrst_keypad *keypad = pci_get_drvdata(pdev);
+ int i;
+ int pins = KEYPAD_MATRIX_GPIO_IN_PIN + MAX_MATRIX_KEY_ROWS +
+ MAX_MATRIX_KEY_COLS + MAX_DIRECT_KEY_NUM;
+
+ for (i = pins - 1; i > KEYPAD_MATRIX_GPIO_IN_PIN; i--)
+ gpio_free(i);
+
+ free_irq(pdev->irq, keypad);
+ input_unregister_device(keypad->input_dev);
+ iounmap(keypad->mmio_base);
+ pci_release_regions(pdev);
+ pci_set_drvdata(pdev, NULL);
+ kfree(keypad);
+}
+
+
+static struct pci_driver mrst_keypad_driver = {
+ .name = DRV_NAME,
+ .id_table = keypad_pci_tbl,
+ .probe = mrst_keypad_probe,
+ .remove = __devexit_p(mrst_keypad_remove),
+#ifdef CONFIG_PM
+ .suspend = NULL,
+ .resume = NULL,
+#endif /* CONFIG_PM */
+};
+
+static int __init mrst_keypad_init(void)
+{
+ return pci_register_driver(&mrst_keypad_driver);
+}
+
+static void __exit mrst_keypad_exit(void)
+{
+ pci_unregister_driver(&mrst_keypad_driver);
+}
+
+module_init(mrst_keypad_init);
+module_exit(mrst_keypad_exit);
+
+MODULE_DESCRIPTION("MRST Keypad Controller Driver");
+MODULE_LICENSE("GPL v2");
--
1.6.2.5

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,35 @@
From 722a639fd2cec44501c04ae32af57fd822c5a2d5 Mon Sep 17 00:00:00 2001
From: Yinghai Lu <yinghai@kernel.org>
Date: Wed, 24 Feb 2010 12:39:37 -0800
Subject: [PATCH] x86, pci: Exclude Moorestown PCI code if CONFIG_X86_MRST=n
If we don't have any Moorestown CPU support compiled in, we don't need
the Moorestown PCI support either.
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
LKML-Reference: <4B858E89.7040807@kernel.org>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Acked-by: Yong Wang <yong.y.wang@intel.com>
Patch-mainline: Patch-mainline: Merged into x86/mrst branch of -tip
---
arch/x86/pci/Makefile | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/arch/x86/pci/Makefile b/arch/x86/pci/Makefile
index 4753ebc..56caf2a 100644
--- a/arch/x86/pci/Makefile
+++ b/arch/x86/pci/Makefile
@@ -13,7 +13,9 @@ obj-$(CONFIG_X86_VISWS) += visws.o
obj-$(CONFIG_X86_NUMAQ) += numaq_32.o
-obj-y += common.o early.o mrst.o
+obj-$(CONFIG_X86_MRST) += mrst.o
+
+obj-y += common.o early.o
obj-y += amd_bus.o
obj-$(CONFIG_X86_64) += bus_numa.o
--
1.5.5.1

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,849 @@
From 10551a86fa76709587b48a644caeb78dd07690be Mon Sep 17 00:00:00 2001
From: Nithish Mahalingam <nithish.mahalingam@intel.com>
Date: Tue, 29 Dec 2009 22:42:48 +0530
Subject: [PATCH 068/104] Adding Intel Moorestown PMIC Battery Driver
PMIC Battery driver provides battery charging and battery gauge functionality
on Intel Moorestown platform.
Signed-off-by: Nithish Mahalingam <nithish.mahalingam@intel.com>
---
drivers/power/Kconfig | 7 +
drivers/power/Makefile | 1 +
drivers/power/pmic_battery.c | 799 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 807 insertions(+), 0 deletions(-)
create mode 100644 drivers/power/pmic_battery.c
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index d4b3d67..6936bc8 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -124,4 +124,11 @@ config CHARGER_PCF50633
help
Say Y to include support for NXP PCF50633 Main Battery Charger.
+config BATTERY_MRSTPMIC
+ tristate "PMIC battery driver for Intel Moorestown platform"
+ depends on SPI_MRST && LNW_IPC && USB_GADGET_LANGWELL
+ help
+ Say Y here to enable battery driver on Intel Moorestown
+ platform.
+
endif # POWER_SUPPLY
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index 573597c..97af4b4 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -31,3 +31,4 @@ obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o
obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o
obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o
obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
+obj-$(CONFIG_BATTERY_MRSTPMIC) += pmic_battery.o
diff --git a/drivers/power/pmic_battery.c b/drivers/power/pmic_battery.c
new file mode 100644
index 0000000..6e3c46a
--- /dev/null
+++ b/drivers/power/pmic_battery.c
@@ -0,0 +1,799 @@
+/*
+ * pmic_battery.c - Intel Moorestown PMIC Battery Driver
+ *
+ * Copyright (C) 2009 Intel Corporation
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * Author: Nithish Mahalingam <nithish.mahalingam@intel.com>
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/jiffies.h>
+#include <linux/param.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/power_supply.h>
+
+#include <asm/ipc_defs.h>
+#include <linux/usb/langwell_udc.h>
+
+
+MODULE_AUTHOR("Nithish Mahalingam <nithish.mahalingam@intel.com>");
+MODULE_DESCRIPTION("Intel Moorestown PMIC Battery Driver");
+MODULE_LICENSE("GPL");
+
+#define DRIVER_NAME "pmic_battery"
+
+/*********************************************************************
+ * Generic defines
+ *********************************************************************/
+
+static int pmicbatteryDebug;
+module_param(pmicbatteryDebug, int, 0444);
+MODULE_PARM_DESC(pmicbatteryDebug,
+ "Flag to enable PMIC Battery debug messages.");
+
+#define PMIC_BATT_DEBUG (pmicbatteryDebug)
+
+#define PMIC_BATT_DRV_INFO_UPDATED 1
+#define PMIC_BATT_PRESENT 1
+#define PMIC_BATT_NOT_PRESENT 0
+#define PMIC_USB_PRESENT PMIC_BATT_PRESENT
+#define PMIC_USB_NOT_PRESENT PMIC_BATT_NOT_PRESENT
+
+/* pmic battery register related */
+#define PMIC_BATT_CHR_SCHRGINT_ADDR 0xD2
+#define PMIC_BATT_CHR_SBATOVP_MASK (1 << 1)
+#define PMIC_BATT_CHR_STEMP_MASK (1 << 2)
+#define PMIC_BATT_CHR_SCOMP_MASK (1 << 3)
+#define PMIC_BATT_CHR_SUSBDET_MASK (1 << 4)
+#define PMIC_BATT_CHR_SBATDET_MASK (1 << 5)
+#define PMIC_BATT_CHR_SDCLMT_MASK (1 << 6)
+#define PMIC_BATT_CHR_SUSBOVP_MASK (1 << 7)
+#define PMIC_BATT_CHR_EXCPT_MASK 0xC6
+#define PMIC_BATT_ADC_ACCCHRG_MASK (1 << 31)
+#define PMIC_BATT_ADC_ACCCHRGVAL_MASK 0x7FFFFFFF
+
+/* pmic ipc related */
+#define PMIC_BATT_CHR_IPC_CMDID 0xEF
+#define PMIC_BATT_CHR_IPC_FCHRG_SUBID 0x4
+#define PMIC_BATT_CHR_IPC_TCHRG_SUBID 0x6
+
+/* internal return values */
+#define BATTSUCCESS 0
+#define EBATTFAIL 1
+#define EBATTERR 2
+
+/* types of battery charging */
+enum batt_charge_type {
+ BATT_USBOTG_500MA_CHARGE,
+ BATT_USBOTG_TRICKLE_CHARGE,
+};
+
+/* valid battery events */
+enum batt_event {
+ BATT_EVENT_BATOVP_EXCPT,
+ BATT_EVENT_USBOVP_EXCPT,
+ BATT_EVENT_TEMP_EXCPT,
+ BATT_EVENT_DCLMT_EXCPT,
+ BATT_EVENT_EXCPT
+};
+
+/* battery cca value */
+struct batt_cca_data {
+ signed int cca_val;
+};
+
+/* battery property structure */
+struct batt_prop_data {
+ unsigned int batt_capacity;
+ char batt_chrg_crnt;
+ char batt_chrg_volt;
+ char batt_chrg_prot;
+ char batt_chrg_prot2;
+ char batt_chrg_timer;
+} __attribute__((packed));
+
+
+/*********************************************************************
+ * Battery properties
+ *********************************************************************/
+
+/*
+ * pmic battery info
+ */
+struct pmic_power_module_info {
+ bool is_dev_info_updated;
+ struct spi_device *spi;
+ /* pmic battery data */
+ unsigned long update_time; /* jiffies when data read */
+ unsigned int usb_is_present;
+ unsigned int batt_is_present;
+ unsigned int batt_health;
+ unsigned int usb_health;
+ unsigned int batt_status;
+ unsigned int batt_charge_now; /* in mAS */
+ unsigned int batt_prev_charge_full; /* in mAS */
+ unsigned int batt_charge_rate; /* in units per second */
+
+ struct power_supply usb;
+ struct power_supply batt;
+ int irq; /* GPE_ID or IRQ# */
+ struct workqueue_struct *monitor_wqueue;
+ struct delayed_work monitor_battery;
+ struct work_struct handler;
+};
+
+static unsigned int delay_time = 2000; /* in ms */
+
+/*
+ * pmic ac properties
+ */
+static enum power_supply_property pmic_usb_props[] = {
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_HEALTH,
+};
+
+/*
+ * pmic battery properties
+ */
+static enum power_supply_property pmic_battery_props[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_HEALTH,
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_CHARGE_NOW,
+ POWER_SUPPLY_PROP_CHARGE_FULL,
+ POWER_SUPPLY_PROP_CHARGE_AVG,
+};
+
+
+/**
+ * pmic_battery_log_event - log battery events
+ * @event: battery event to be logged
+ * Context: can sleep
+ *
+ * There are multiple battery events which may be of interest to users;
+ * this battery function logs the different battery events onto the
+ * kernel log messages.
+ */
+static void pmic_battery_log_event(enum batt_event event)
+{
+ switch (event) {
+ case BATT_EVENT_BATOVP_EXCPT:
+ printk(KERN_WARNING "pmic-battery: battery overvoltage "
+ "condition detected\n");
+ break;
+ case BATT_EVENT_USBOVP_EXCPT:
+ printk(KERN_WARNING "pmic-battery: usb charger overvoltage "
+ "condition detected\n");
+ break;
+ case BATT_EVENT_TEMP_EXCPT:
+ printk(KERN_WARNING "pmic-battery: high battery temperature "
+ "condition detected\n");
+ break;
+ case BATT_EVENT_DCLMT_EXCPT:
+ printk(KERN_WARNING "pmic-battery: over battery charge "
+ " current condition detected\n");
+ break;
+ default:
+ printk(KERN_WARNING "pmic-battery: charger/battery "
+ " exception detected\n");
+ break;
+ }
+}
+
+/**
+ * pmic_battery_read_status - read battery status information
+ * @pbi: device info structure to update the read information
+ * Context: can sleep
+ *
+ * PMIC power source information need to be updated based on the data read
+ * from the PMIC battery registers.
+ *
+ */
+static void pmic_battery_read_status(struct pmic_power_module_info *pbi)
+{
+ unsigned int update_time_intrvl = 0;
+ unsigned int chrg_val = 0;
+ struct ipc_pmic_reg_data pmic_batt_reg = {0};
+ struct ipc_cmd_type pmic_batt_cmd = {0};
+ struct batt_cca_data ccval = {0};
+ struct batt_prop_data batt_prop = {0};
+ int batt_present = 0;
+ int usb_present = 0;
+ int batt_exception = 0;
+
+ /* make sure the last batt_status read happened delay_time before */
+ if (pbi->update_time && time_before(jiffies, pbi->update_time +
+ msecs_to_jiffies(delay_time)))
+ return;
+
+ update_time_intrvl = jiffies_to_msecs(jiffies - pbi->update_time);
+ pbi->update_time = jiffies;
+
+ /* read coulomb counter registers and schrgint register */
+
+ pmic_batt_cmd.ioc = TRUE;
+ pmic_batt_cmd.cmd = IPC_BATT_CCA_READ;
+ if (ipc_config_cmd(pmic_batt_cmd, sizeof(struct batt_cca_data),
+ &ccval)) {
+ dev_warn(&pbi->spi->dev, "%s(): ipc config cmd failed\n",
+ __func__);
+ return;
+ }
+
+ pmic_batt_reg.ioc = TRUE;
+ pmic_batt_reg.pmic_reg_data[0].register_address =
+ PMIC_BATT_CHR_SCHRGINT_ADDR;
+ pmic_batt_reg.num_entries = 1;
+
+ if (ipc_pmic_register_read(&pmic_batt_reg)) {
+ dev_warn(&pbi->spi->dev, "%s(): ipc pmic read failed\n",
+ __func__);
+ return;
+ }
+
+ /*
+ * set pmic_power_module_info members based on pmic register values
+ * read.
+ */
+
+ /* set batt_is_present */
+ if (pmic_batt_reg.pmic_reg_data[0].value &
+ PMIC_BATT_CHR_SBATDET_MASK) {
+ pbi->batt_is_present = PMIC_BATT_PRESENT;
+ batt_present = 1;
+ } else {
+ pbi->batt_is_present = PMIC_BATT_NOT_PRESENT;
+ pbi->batt_health = POWER_SUPPLY_HEALTH_UNKNOWN;
+ pbi->batt_status = POWER_SUPPLY_STATUS_UNKNOWN;
+ }
+
+ /* set batt_health */
+ if (batt_present) {
+ if (pmic_batt_reg.pmic_reg_data[0].value &
+ PMIC_BATT_CHR_SBATOVP_MASK) {
+ pbi->batt_health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+ pbi->batt_status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ pmic_battery_log_event(BATT_EVENT_BATOVP_EXCPT);
+ batt_exception = 1;
+ } else if (pmic_batt_reg.pmic_reg_data[0].value &
+ PMIC_BATT_CHR_SDCLMT_MASK) {
+ pbi->batt_health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+ pbi->batt_status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ pmic_battery_log_event(BATT_EVENT_DCLMT_EXCPT);
+ batt_exception = 1;
+ } else if (pmic_batt_reg.pmic_reg_data[0].value &
+ PMIC_BATT_CHR_STEMP_MASK) {
+ pbi->batt_health = POWER_SUPPLY_HEALTH_OVERHEAT;
+ pbi->batt_status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ pmic_battery_log_event(BATT_EVENT_TEMP_EXCPT);
+ batt_exception = 1;
+ } else {
+ pbi->batt_health = POWER_SUPPLY_HEALTH_GOOD;
+ }
+ }
+
+ /* set usb_is_present */
+ if (pmic_batt_reg.pmic_reg_data[0].value &
+ PMIC_BATT_CHR_SUSBDET_MASK) {
+ pbi->usb_is_present = PMIC_USB_PRESENT;
+ usb_present = 1;
+ } else {
+ pbi->usb_is_present = PMIC_USB_NOT_PRESENT;
+ pbi->usb_health = POWER_SUPPLY_HEALTH_UNKNOWN;
+ }
+
+ if (usb_present) {
+ if (pmic_batt_reg.pmic_reg_data[0].value &
+ PMIC_BATT_CHR_SUSBOVP_MASK) {
+ pbi->usb_health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+ pmic_battery_log_event(BATT_EVENT_USBOVP_EXCPT);
+ } else {
+ pbi->usb_health = POWER_SUPPLY_HEALTH_GOOD;
+ }
+ }
+
+ chrg_val = ccval.cca_val & PMIC_BATT_ADC_ACCCHRGVAL_MASK;
+
+ /* set batt_prev_charge_full to battery capacity the first time */
+ if (!pbi->is_dev_info_updated) {
+ pmic_batt_cmd.ioc = TRUE;
+ pmic_batt_cmd.cmd = IPC_BATT_GET_PROP;
+ if (ipc_config_cmd(pmic_batt_cmd,
+ sizeof(struct batt_prop_data), &batt_prop)) {
+ dev_warn(&pbi->spi->dev, "%s(): ipc config cmd "
+ "failed\n", __func__);
+ return;
+ }
+ pbi->batt_prev_charge_full = batt_prop.batt_capacity;
+ }
+
+ /* set batt_status */
+ if ((batt_present) && (!batt_exception)) {
+ if (pmic_batt_reg.pmic_reg_data[0].value &
+ PMIC_BATT_CHR_SCOMP_MASK) {
+ pbi->batt_status = POWER_SUPPLY_STATUS_FULL;
+ pbi->batt_prev_charge_full = chrg_val;
+ } else if (ccval.cca_val & PMIC_BATT_ADC_ACCCHRG_MASK) {
+ pbi->batt_status = POWER_SUPPLY_STATUS_DISCHARGING;
+ } else {
+ pbi->batt_status = POWER_SUPPLY_STATUS_CHARGING;
+ }
+ }
+
+ /* set batt_charge_rate */
+ if ((pbi->is_dev_info_updated) && (batt_present) && (!batt_exception)) {
+ if (pbi->batt_status == POWER_SUPPLY_STATUS_DISCHARGING) {
+ if (pbi->batt_charge_now - chrg_val) {
+ pbi->batt_charge_rate = ((pbi->batt_charge_now -
+ chrg_val) * 1000 * 60) /
+ update_time_intrvl;
+ }
+ } else if (pbi->batt_status == POWER_SUPPLY_STATUS_CHARGING) {
+ if (chrg_val - pbi->batt_charge_now) {
+ pbi->batt_charge_rate = ((chrg_val -
+ pbi->batt_charge_now) * 1000 * 60) /
+ update_time_intrvl;
+ }
+ } else
+ pbi->batt_charge_rate = 0;
+ } else {
+ pbi->batt_charge_rate = -1;
+ }
+
+ /* batt_charge_now */
+ if ((batt_present) && (!batt_exception))
+ pbi->batt_charge_now = chrg_val;
+ else
+ pbi->batt_charge_now = -1;
+
+ pbi->is_dev_info_updated = PMIC_BATT_DRV_INFO_UPDATED;
+}
+
+/**
+ * pmic_usb_get_property - usb power source get property
+ * @psy: usb power supply context
+ * @psp: usb power source property
+ * @val: usb power source property value
+ * Context: can sleep
+ *
+ * PMIC usb power source property needs to be provided to power_supply
+ * subsytem for it to provide the information to users.
+ */
+static int pmic_usb_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct pmic_power_module_info *pbi = container_of(psy,
+ struct pmic_power_module_info, usb);
+
+ /* update pmic_power_module_info members */
+ pmic_battery_read_status(pbi);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_PRESENT:
+ val->intval = pbi->usb_is_present;
+ break;
+ case POWER_SUPPLY_PROP_HEALTH:
+ val->intval = pbi->usb_health;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * pmic_battery_get_property - battery power source get property
+ * @psy: battery power supply context
+ * @psp: battery power source property
+ * @val: battery power source property value
+ * Context: can sleep
+ *
+ * PMIC battery power source property needs to be provided to power_supply
+ * subsytem for it to provide the information to users.
+ */
+static int pmic_battery_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct pmic_power_module_info *pbi = container_of(psy,
+ struct pmic_power_module_info, batt);
+
+ /* update pmic_power_module_info members */
+ pmic_battery_read_status(pbi);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ val->intval = pbi->batt_status;
+ break;
+ case POWER_SUPPLY_PROP_HEALTH:
+ val->intval = pbi->batt_health;
+ break;
+ case POWER_SUPPLY_PROP_PRESENT:
+ val->intval = pbi->batt_is_present;
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_NOW:
+ val->intval = pbi->batt_charge_now;
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_FULL:
+ val->intval = pbi->batt_prev_charge_full;
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_AVG:
+ val->intval = pbi->batt_charge_rate;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * pmic_battery_monitor - monitor battery status
+ * @work: work structure
+ * Context: can sleep
+ *
+ * PMIC battery status needs to be monitored for any change
+ * and information needs to be frequently updated.
+ */
+static void pmic_battery_monitor(struct work_struct *work)
+{
+ struct pmic_power_module_info *pbi = container_of(work,
+ struct pmic_power_module_info, monitor_battery.work);
+
+ /* update pmic_power_module_info members */
+ pmic_battery_read_status(pbi);
+ queue_delayed_work(pbi->monitor_wqueue, &pbi->monitor_battery, HZ * 10);
+}
+
+/**
+ * pmic_battery_set_charger - set battery charger
+ * @pbi: device info structure
+ * @chrg: charge mode to set battery charger in
+ * Context: can sleep
+ *
+ * PMIC battery charger needs to be enabled based on the usb charge
+ * capabilities connected to the platform.
+ */
+static int pmic_battery_set_charger(struct pmic_power_module_info *pbi,
+ enum batt_charge_type chrg)
+{
+ int retval;
+
+ /* set usblmt bits and chrgcntl register bits appropriately */
+ switch (chrg) {
+ case BATT_USBOTG_500MA_CHARGE:
+ retval = lnw_ipc_single_cmd(PMIC_BATT_CHR_IPC_CMDID,
+ PMIC_BATT_CHR_IPC_FCHRG_SUBID, 0, 0);
+ break;
+ case BATT_USBOTG_TRICKLE_CHARGE:
+ retval = lnw_ipc_single_cmd(PMIC_BATT_CHR_IPC_CMDID,
+ PMIC_BATT_CHR_IPC_TCHRG_SUBID, 0, 0);
+ break;
+ default:
+ dev_warn(&pbi->spi->dev, "%s(): out of range usb charger "
+ "charge detected\n", __func__);
+ return -EBATTFAIL;
+ }
+
+ if (retval) {
+ dev_warn(&pbi->spi->dev, "%s(): ipc pmic read failed\n",
+ __func__);
+ return -EBATTFAIL;
+ }
+
+ return BATTSUCCESS;
+}
+
+/**
+ * pmic_battery_interrupt_handler - pmic battery interrupt handler
+ * Context: interrupt context
+ *
+ * PMIC battery interrupt handler which will be called with either
+ * battery full condition occurs or usb otg & battery connect
+ * condition occurs.
+ */
+static irqreturn_t pmic_battery_interrupt_handler(int id, void *dev)
+{
+ struct pmic_power_module_info *pbi =
+ (struct pmic_power_module_info *)dev;
+
+ schedule_work(&pbi->handler);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * pmic_battery_handle_intrpt - pmic battery service interrupt
+ * @work: work structure
+ * Context: can sleep
+ *
+ * PMIC battery needs to either update the battery status as full
+ * if it detects battery full condition caused the interrupt or needs
+ * to enable battery charger if it detects usb and battery detect
+ * caused the source of interrupt.
+ */
+static void pmic_battery_handle_intrpt(struct work_struct *work)
+{
+ struct ipc_pmic_reg_data pmic_batt_reg = {0};
+ struct pmic_power_module_info *pbi = container_of(work,
+ struct pmic_power_module_info, handler);
+ int power = 0;
+ enum batt_charge_type chrg;
+ int retval = 0;
+
+ /* check if pmic_power_module_info is initialized */
+ if (!pbi)
+ return;
+
+ /* read schrgint register to interpret cause of interrupt */
+ pmic_batt_reg.ioc = TRUE;
+ pmic_batt_reg.pmic_reg_data[0].register_address =
+ PMIC_BATT_CHR_SCHRGINT_ADDR;
+ pmic_batt_reg.num_entries = 1;
+
+ if (ipc_pmic_register_read(&pmic_batt_reg)) {
+ dev_warn(&pbi->spi->dev, "%s(): ipc pmic read failed\n",
+ __func__);
+ return;
+ }
+
+ /* find the cause of the interrupt */
+
+ if (pmic_batt_reg.pmic_reg_data[0].value & PMIC_BATT_CHR_SBATDET_MASK) {
+ pbi->batt_is_present = PMIC_BATT_PRESENT;
+ } else {
+ pbi->batt_is_present = PMIC_BATT_NOT_PRESENT;
+ pbi->batt_health = POWER_SUPPLY_HEALTH_UNKNOWN;
+ pbi->batt_status = POWER_SUPPLY_STATUS_UNKNOWN;
+ return;
+ }
+
+ if (pmic_batt_reg.pmic_reg_data[0].value &
+ PMIC_BATT_CHR_EXCPT_MASK) {
+ pbi->batt_health = POWER_SUPPLY_HEALTH_UNKNOWN;
+ pbi->batt_status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ pbi->usb_health = POWER_SUPPLY_HEALTH_UNKNOWN;
+ pmic_battery_log_event(BATT_EVENT_EXCPT);
+ return;
+ } else {
+ pbi->batt_health = POWER_SUPPLY_HEALTH_GOOD;
+ pbi->usb_health = POWER_SUPPLY_HEALTH_GOOD;
+ }
+
+ if (pmic_batt_reg.pmic_reg_data[0].value & PMIC_BATT_CHR_SCOMP_MASK) {
+ struct ipc_cmd_type pmic_batt_cmd = {0};
+ struct batt_cca_data ccval = {0};
+
+ pbi->batt_status = POWER_SUPPLY_STATUS_FULL;
+ pmic_batt_cmd.ioc = TRUE;
+ pmic_batt_cmd.cmd = IPC_BATT_CCA_READ;
+ if (ipc_config_cmd(pmic_batt_cmd,
+ sizeof(struct batt_cca_data), &ccval)) {
+ dev_warn(&pbi->spi->dev, "%s(): ipc config cmd "
+ "failed\n", __func__);
+ return;
+ }
+ pbi->batt_prev_charge_full = ccval.cca_val &
+ PMIC_BATT_ADC_ACCCHRGVAL_MASK;
+ return;
+ }
+
+ if (pmic_batt_reg.pmic_reg_data[0].value & PMIC_BATT_CHR_SUSBDET_MASK) {
+ pbi->usb_is_present = PMIC_USB_PRESENT;
+ } else {
+ pbi->usb_is_present = PMIC_USB_NOT_PRESENT;
+ pbi->usb_health = POWER_SUPPLY_HEALTH_UNKNOWN;
+ return;
+ }
+
+ /* setup battery charging */
+
+ /* check usb otg power capability and set charger accordingly */
+ retval = langwell_udc_maxpower(&power);
+ if (retval) {
+ dev_warn(&pbi->spi->dev, "%s(): usb otg power query failed "
+ "with error code %d\n", __func__, retval);
+ return;
+ }
+
+ if (power >= 500)
+ chrg = BATT_USBOTG_500MA_CHARGE;
+ else
+ chrg = BATT_USBOTG_TRICKLE_CHARGE;
+
+ /* enable battery charging */
+ if (pmic_battery_set_charger(pbi, chrg)) {
+ dev_warn(&pbi->spi->dev, "%s(): failed to setup battery "
+ "charging\n", __func__);
+ return;
+ }
+
+ if (PMIC_BATT_DEBUG)
+ printk(KERN_INFO "pmic-battery: %s() - setting up battery "
+ "charger successful\n", __func__);
+}
+
+/**
+ * pmic_battery_probe - pmic battery initialize
+ * @spi: pmic battery spi structure
+ * Context: can sleep
+ *
+ * PMIC battery initializes its internal data structue and other
+ * infrastructure components for it to work as expected.
+ */
+static int pmic_battery_probe(struct spi_device *spi)
+{
+ int retval = 0;
+ struct pmic_power_module_info *pbi = 0;
+
+ if (PMIC_BATT_DEBUG)
+ printk(KERN_INFO "pmic-battery: %s() - found pmic battery "
+ "device\n", __func__);
+
+ pbi = kzalloc(sizeof(*pbi), GFP_KERNEL);
+ if (!pbi) {
+ dev_err(&spi->dev, "%s(): memory allocation failed\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ pbi->spi = spi;
+ pbi->irq = spi->irq;
+ dev_set_drvdata(&spi->dev, pbi);
+
+ /* initialize all required framework before enabling interrupts */
+ INIT_WORK(&pbi->handler, (void *)pmic_battery_handle_intrpt);
+ INIT_DELAYED_WORK(&pbi->monitor_battery, pmic_battery_monitor);
+ pbi->monitor_wqueue =
+ create_singlethread_workqueue(dev_name(&spi->dev));
+ if (!pbi->monitor_wqueue) {
+ dev_err(&spi->dev, "%s(): wqueue init failed\n", __func__);
+ retval = -ESRCH;
+ goto wqueue_failed;
+ }
+
+ /* register interrupt */
+ retval = request_irq(pbi->irq, pmic_battery_interrupt_handler,
+ 0, DRIVER_NAME, pbi);
+ if (retval) {
+ dev_err(&spi->dev, "%s(): cannot get IRQ\n", __func__);
+ goto requestirq_failed;
+ }
+
+ /* register pmic-batt with power supply subsystem */
+ pbi->batt.name = "pmic-batt";
+ pbi->batt.type = POWER_SUPPLY_TYPE_BATTERY;
+ pbi->batt.properties = pmic_battery_props;
+ pbi->batt.num_properties = ARRAY_SIZE(pmic_battery_props);
+ pbi->batt.get_property = pmic_battery_get_property;
+ retval = power_supply_register(&spi->dev, &pbi->batt);
+ if (retval) {
+ dev_err(&spi->dev, "%s(): failed to register pmic battery "
+ "device with power supply subsystem\n",
+ __func__);
+ goto power_reg_failed;
+ }
+
+ if (PMIC_BATT_DEBUG)
+ printk(KERN_INFO "pmic-battery: %s() - pmic battery device "
+ "registration with power supply subsystem "
+ "successful\n", __func__);
+
+ queue_delayed_work(pbi->monitor_wqueue, &pbi->monitor_battery, HZ * 1);
+
+ /* register pmic-usb with power supply subsystem */
+ pbi->usb.name = "pmic-usb";
+ pbi->usb.type = POWER_SUPPLY_TYPE_USB;
+ pbi->usb.properties = pmic_usb_props;
+ pbi->usb.num_properties = ARRAY_SIZE(pmic_usb_props);
+ pbi->usb.get_property = pmic_usb_get_property;
+ retval = power_supply_register(&spi->dev, &pbi->usb);
+ if (retval) {
+ dev_err(&spi->dev, "%s(): failed to register pmic usb "
+ "device with power supply subsystem\n",
+ __func__);
+ goto power_reg_failed_1;
+ }
+
+ if (PMIC_BATT_DEBUG)
+ printk(KERN_INFO "pmic-battery: %s() - pmic usb device "
+ "registration with power supply subsystem successful\n",
+ __func__);
+
+ return retval;
+
+power_reg_failed_1:
+ power_supply_unregister(&pbi->batt);
+power_reg_failed:
+ cancel_rearming_delayed_workqueue(pbi->monitor_wqueue,
+ &pbi->monitor_battery);
+requestirq_failed:
+ destroy_workqueue(pbi->monitor_wqueue);
+wqueue_failed:
+ kfree(pbi);
+
+ return retval;
+}
+
+/**
+ * pmic_battery_remove - pmic battery finalize
+ * @spi: pmic battery spi device structure
+ * Context: can sleep
+ *
+ * PMIC battery finalizes its internal data structue and other
+ * infrastructure components that it initialized in
+ * pmic_battery_probe.
+ */
+static int pmic_battery_remove(struct spi_device *spi)
+{
+ struct pmic_power_module_info *pbi = dev_get_drvdata(&spi->dev);
+
+ if (pbi) {
+ free_irq(pbi->irq, pbi);
+
+ cancel_rearming_delayed_workqueue(pbi->monitor_wqueue,
+ &pbi->monitor_battery);
+ destroy_workqueue(pbi->monitor_wqueue);
+
+ power_supply_unregister(&pbi->usb);
+ power_supply_unregister(&pbi->batt);
+
+ flush_scheduled_work();
+
+ kfree(pbi);
+ }
+
+ return 0;
+}
+
+
+/*********************************************************************
+ * Driver initialisation and finalization
+ *********************************************************************/
+
+static struct spi_driver pmic_battery_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = pmic_battery_probe,
+ .remove = __devexit_p(pmic_battery_remove),
+};
+
+
+static int __init pmic_battery_module_init(void)
+{
+ return spi_register_driver(&pmic_battery_driver);
+}
+
+static void __exit pmic_battery_module_exit(void)
+{
+ spi_unregister_driver(&pmic_battery_driver);
+}
+
+module_init(pmic_battery_module_init);
+module_exit(pmic_battery_module_exit);
--
1.6.2.5

View File

@ -0,0 +1,285 @@
From e11104658a3b8eabbb4eb74b38645a4f114b745d Mon Sep 17 00:00:00 2001
From: Kalhan Trisal <kalhan.trisal@intel.com>
Date: Fri, 4 Sep 2009 18:10:52 -0400
Subject: [PATCH 075/104] Thermal patch for emc1403 driver
Thermal driver will handle event generation even if alert handler is called multiple time due to GPE->GPIO changes. The IRQ has become now shared and the handler will be called on every event as shared with other devices also.
Signed-off-by: Kalhan Trisal <kalhan.trisal@intel.com>
---
drivers/hwmon/Kconfig | 2 +-
drivers/hwmon/emc1403.c | 128 +++++++++++++++++++++--------------------------
2 files changed, 58 insertions(+), 72 deletions(-)
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 55637c3..c8fefbc 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -55,7 +55,7 @@ config SENSORS_LIS331DL
config SENSORS_EMC1403
tristate "SMSC EMC1403 Thermal"
- depends on I2C_MRST && GPE && GPIO_MAX7315 && MSTWN_POWER_MGMT
+ depends on I2C
help
If you say yes here you get support for the SMSC Devices
EMC1403 temperature monitoring chip.
diff --git a/drivers/hwmon/emc1403.c b/drivers/hwmon/emc1403.c
index 45cf5d0..75e3b15 100644
--- a/drivers/hwmon/emc1403.c
+++ b/drivers/hwmon/emc1403.c
@@ -44,8 +44,7 @@ MODULE_LICENSE("GPL v2");
/* To support the interrupt mechanism for moorestown interrupt flag is added
* If the flag is not enabled it support generic emc1403 chip */
-#if defined(CONFIG_GPIO_LNWPMIC) && defined(CONFIG_GPIO_MAX7315) \
- && defined(CONFIG_MSTWN_POWER_MGMT)
+#if defined(CONFIG_GPIO_LANGWELL_PMIC) && defined(CONFIG_MSTWN_POWER_MGMT)
#define MOORESTOWN_INTERRUPT_ENABLE
#endif
@@ -335,40 +334,6 @@ static ssize_t store_power_state(struct device *dev,
return count;
}
-static ssize_t show_mode(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct i2c_client *client = to_i2c_client(dev);
- int ret_val;
-
- ret_val = i2c_read_current_data(client, 0x03);
- ret_val = ret_val & 0x80;
- if (ret_val == 0x80)
- ret_val = 1;
- return sprintf(buf, "%x", ret_val);
-}
-
-static ssize_t store_mode(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- struct i2c_client *client = to_i2c_client(dev);
- unsigned long val = 0;
- char curr_val;
-
- if (strict_strtoul(buf, 10, &val))
- return -EINVAL;
-
- curr_val = i2c_read_current_data(client, 0x03);
- if (val == INTERRUPT_MODE_ENABLE)
- curr_val = curr_val & 0x7F;
- else if (val == INTERRUPT_MODE_DISABLE)
- curr_val = curr_val | 0x80;
- else
- return -EINVAL;
- i2c_write_current_data(client, 0x03, curr_val);
- return count;
-}
-
static SENSOR_DEVICE_ATTR_2(temp1_min, S_IRUGO | S_IWUSR,
show_temp_auto_offset, store_temp_auto_offset, 0, 1);
static SENSOR_DEVICE_ATTR_2(temp1_max, S_IRUGO | S_IWUSR,
@@ -398,7 +363,6 @@ static DEVICE_ATTR(status, S_IRUGO, show_status_reg, NULL);
static DEVICE_ATTR(power_state, S_IRUGO | S_IWUSR,
show_power_state, store_power_state);
-static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, show_mode, store_mode);
static struct attribute *mid_att_thermal[] = {
&sensor_dev_attr_temp1_min.dev_attr.attr,
@@ -416,7 +380,6 @@ static struct attribute *mid_att_thermal[] = {
&dev_attr_hyster.attr,
&dev_attr_status.attr,
&dev_attr_power_state.attr,
- &dev_attr_mode.attr,
NULL
};
@@ -449,102 +412,124 @@ static irqreturn_t alert_interrupt_handler(int id, void *dev)
return IRQ_HANDLED;
}
+
/* when the device raise the interrupt we mask the interrupt
* bit for that device as the status register is R-C
* so that till thermal governor doesnot take action we need
* not to send continuous events */
static int interrupt_status(struct i2c_client *client, u8 diode_reg_val,
- u8 *status, u8 event)
+ u8 *mask_status, u8 event, u8 *status)
{
- u8 crit_st = 0, set_mask = 0;
+ u8 crit_st = 0, set_mask = 0, event_status = 0;
set_mask = i2c_read_current_data(client, 0x1F);
if (diode_reg_val & THM_CHAN_TEMP[3]) {
- set_mask = (set_mask | 0x02);
- crit_st = (crit_st | 2);
+ if (set_mask & TEMP2)
+ event_status = event_status | TEMP2;
+ else
+ set_mask = set_mask | 0x02;
+ crit_st = crit_st | 2;
}
if (diode_reg_val & THM_CHAN_TEMP[2]) {
- set_mask = (set_mask | 0x04);
- crit_st = (crit_st | 4);
+ if (set_mask & TEMP3)
+ event_status = event_status | TEMP3;
+ else
+ set_mask = set_mask | 0x04;
+ crit_st = crit_st | 4;
}
if (diode_reg_val & THM_CHAN_TEMP[4]) {
- set_mask = (set_mask | 0x01);
- crit_st = (crit_st | 1);
+ if (set_mask & TEMP1)
+ event_status = event_status | TEMP1;
+ else
+ set_mask = set_mask | 0x01;
+ crit_st = crit_st | 1;
}
if (event == ALERT_EVENT)
- i2c_smbus_write_byte_data(client, 0x1F, set_mask);
- *status = crit_st;
+ i2c_smbus_write_byte_data(client, 0x1f, set_mask);
+ *mask_status = crit_st;
+ *status = event_status;
return 0;
}
static void ospm_event(int event_id, int sensor_id, int curr_temp)
{
if (event_id == THERM_EVENT) {
- printk(KERN_ALERT "emc1403: Sensor Id = %d crit event \
+ printk(KERN_ALERT "emc1403: sensor id = %d crit event \
temp = %d \n", sensor_id, curr_temp);
ospm_generate_netlink_event(sensor_id,
OSPM_EVENT_THERMAL_CRITICAL);
}
if (event_id == HIGH_EVENT) {
- printk(KERN_ALERT "emc1403: Sensor Id = %d AUX1 event \
+ printk(KERN_ALERT "emc1403: sensor id = %d aux1 event \
temp = %d \n", sensor_id, curr_temp);
ospm_generate_netlink_event(sensor_id,
OSPM_EVENT_THERMAL_AUX1);
}
if (event_id == LOW_EVENT) {
- printk(KERN_ALERT "emc1403: Sensor Id = %d AUX0 event \
+ printk(KERN_ALERT "emc1403: sensor id = %d aux0 event \
temp = %d \n", sensor_id, curr_temp);
ospm_generate_netlink_event(sensor_id,
OSPM_EVENT_THERMAL_AUX0);
}
if (event_id == FAULT_EVENT) {
- printk(KERN_ALERT "emc1403: Sensor Id = %d Fault event \
+ printk(KERN_ALERT "emc1403: sensor id = %d fault event \
temp = %d \n", sensor_id, curr_temp);
ospm_generate_netlink_event(sensor_id,
OSPM_EVENT_THERMAL_DEV_FAULT);
}
}
-static void send_event(struct i2c_client *client, int status, int event_id)
+static void send_event(struct i2c_client *client, int status, u8 mask_event,
+ int event_id)
{
int ret_val;
if (status & TEMP1) {
- ret_val = i2c_read_current_data(client, THM_REG_CURR_TEMP[0]);
- ospm_event(event_id, TEMP_DEV_ID1, ret_val);
+ if (!(TEMP1 & mask_event)) {
+ ret_val = i2c_read_current_data(client,
+ THM_REG_CURR_TEMP[0]);
+ ospm_event(event_id, TEMP_DEV_ID1, ret_val);
+ }
}
if (status & TEMP2) {
- ret_val = i2c_read_current_data(client, THM_REG_CURR_TEMP[1]);
- ospm_event(event_id, TEMP_DEV_ID2, ret_val);
+ if (!(TEMP2 & mask_event)) {
+ ret_val = i2c_read_current_data(client,
+ THM_REG_CURR_TEMP[1]);
+ ospm_event(event_id, TEMP_DEV_ID2, ret_val);
+ }
}
if (status & TEMP3) {
- ret_val = i2c_read_current_data(client, THM_REG_CURR_TEMP[2]);
- ospm_event(event_id, TEMP_DEV_ID3, ret_val);
+ if (!(TEMP3 & mask_event)) {
+ ret_val = i2c_read_current_data(client,
+ THM_REG_CURR_TEMP[2]);
+ ospm_event(event_id, TEMP_DEV_ID3, ret_val);
+ }
}
}
static void therm_handle_intrpt(struct work_struct *work)
{
- u8 status, reg_val;
+ u8 status, reg_val, mask_status;
struct thermal_data *data = container_of(work,
struct thermal_data, therm_handler);
/* check if therm_module_info is initialized */
if (!data)
return;
- /* Which DIODE has raised the interrupt 0x1B
- internal/External1/External2 */
+ /* which diode has raised the interrupt 0x1b
+ internal/external1/external2 */
reg_val = i2c_smbus_read_byte_data(data->client,
THM_STAT_REG_TEMP[0]);
- interrupt_status(data->client, reg_val, &status, THERM_EVENT);
- send_event(data->client, status, THERM_EVENT);
+ interrupt_status(data->client, reg_val, &status, THERM_EVENT,
+ &mask_status);
+ send_event(data->client, status, 0, THERM_EVENT);
}
static void alert_handle_intrpt(struct work_struct *work)
{
int sta_reg_val, reg_val;
- u8 status;
+ u8 status, mask_status;
struct thermal_data *data = container_of(work,
struct thermal_data, alert_handler);
if (!data)
@@ -557,25 +542,26 @@ static void alert_handle_intrpt(struct work_struct *work)
internal/External1/External2 */
sta_reg_val = i2c_smbus_read_byte_data(data->client,
THM_STAT_REG_TEMP[1]);
+ /*chek if the mask is already enabled then donot send the event again*/
interrupt_status(data->client, sta_reg_val, &status,
- ALERT_EVENT);
- send_event(data->client, status, HIGH_EVENT);
+ ALERT_EVENT, &mask_status);
+ send_event(data->client, status, mask_status, HIGH_EVENT);
}
/* Low status bit is set */
if (reg_val & THM_CHAN_TEMP[1]) {
sta_reg_val = i2c_smbus_read_byte_data(data->client,
THM_STAT_REG_TEMP[2]);
interrupt_status(data->client, sta_reg_val, &status,
- ALERT_EVENT);
- send_event(data->client, status, LOW_EVENT);
+ ALERT_EVENT, &mask_status);
+ send_event(data->client, status, mask_status, LOW_EVENT);
}
/* Fault status bit is set */
if (reg_val & THM_CHAN_TEMP[2]) {
sta_reg_val = i2c_smbus_read_byte_data(data->client,
THM_STAT_REG_TEMP[3]);
interrupt_status(data->client, sta_reg_val, &status,
- ALERT_EVENT);
- send_event(data->client, status, FAULT_EVENT);
+ ALERT_EVENT, &mask_status);
+ send_event(data->client, status, mask_status, FAULT_EVENT);
}
}
#endif
--
1.6.2.5

View File

@ -0,0 +1,996 @@
From f7ba5de3af0c7d3abd7624676e07752e5d8b7ebd Mon Sep 17 00:00:00 2001
From: Jacob Pan <jacob.jun.pan@intel.com>
Date: Fri, 4 Dec 2009 10:57:07 -0800
Subject: [PATCH 040/104] MRST: touch screen driver
---
drivers/input/touchscreen/Kconfig | 9 +
drivers/input/touchscreen/Makefile | 2 +
drivers/input/touchscreen/mrstouch.c | 947 ++++++++++++++++++++++++++++++++++
3 files changed, 958 insertions(+), 0 deletions(-)
create mode 100644 drivers/input/touchscreen/mrstouch.c
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index dfafc76..6dd2674 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -577,4 +577,13 @@ config TOUCHSCREEN_PCAP
To compile this driver as a module, choose M here: the
module will be called pcap_ts.
+
+config TOUCHSCREEN_MRSTOUCH
+ tristate "Intel Moorstown Resistive touchscreen"
+ depends on LNW_IPC
+ default y
+ help
+ Say Y here if you have a Intel Moorstown based Touchscreen
+ If unsure, say N.
+
endif
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index d61a3b4..15ad257 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -45,3 +45,5 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_ATMEL) += atmel-wm97xx.o
obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o
obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o
obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o
+obj-$(CONFIG_TOUCHSCREEN_MRSTOUCH) += mrstouch.o
+
diff --git a/drivers/input/touchscreen/mrstouch.c b/drivers/input/touchscreen/mrstouch.c
new file mode 100644
index 0000000..f6aba7d
--- /dev/null
+++ b/drivers/input/touchscreen/mrstouch.c
@@ -0,0 +1,947 @@
+/*
+ * mrstouch.c - Intel Moorestown Resistive Touch Screen Driver
+ *
+ * Copyright (C) 2008 Intel Corp
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; ifnot, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Questions/Comments/Bug fixes to Sreedhara (sreedhara.ds@intel.com)
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/param.h>
+#include <linux/spi/spi.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <asm/ipc_defs.h>
+
+MODULE_AUTHOR("Sreedhara Murthy. D.S, sreedhara.ds@intel.com");
+MODULE_DESCRIPTION("Intel Moorestown Resistive Touch Screen Driver");
+MODULE_LICENSE("GPL");
+
+#if defined(MRSTOUCH_DEBUG)
+#define mrstouch_debug(fmt, args...)\
+ do { \
+ printk(KERN_DEBUG "\n[MRSTOUCH(%d)] - ", __LINE__); \
+ printk(KERN_DEBUG fmt, ##args); \
+ } while (0);
+#else
+#define mrstouch_debug(fmt, args...)
+#endif
+
+#define mrstouch_error(fmt, args...)\
+ do { \
+ printk(KERN_ERR "\n[MRSTOUCH(%d)] - ", __LINE__); \
+ printk(KERN_ERR fmt, ##args); \
+ } while (0);
+
+/* PMIC Interrupt registers */
+#define PMIC_REG_ID1 0x00 /*PMIC ID1 register */
+
+/* PMIC Interrupt registers */
+#define PMIC_REG_INT 0x04 /*PMIC interrupt register */
+#define PMIC_REG_MINT 0x05 /*PMIC interrupt mask register */
+
+/* ADC Interrupt registers */
+#define PMIC_REG_ADCINT 0x5F /*ADC interrupt register */
+#define PMIC_REG_MADCINT 0x60 /*ADC interrupt mask register */
+
+/* ADC Control registers */
+#define PMIC_REG_ADCCNTL1 0x61 /*ADC control register */
+
+/* ADC Channel Selection registers */
+#define PMICADDR0 0xA4
+#define END_OF_CHANNEL 0x1F
+
+/* ADC Result register */
+#define PMIC_REG_ADCSNS0H 0x64
+
+/* ADC channels for touch screen */
+#define MRST_TS_CHAN10 0xA /* Touch screen X+ connection */
+#define MRST_TS_CHAN11 0xB /* Touch screen X- connection */
+#define MRST_TS_CHAN12 0xC /* Touch screen Y+ connection */
+#define MRST_TS_CHAN13 0xD /* Touch screen Y- connection */
+
+/* Touch screen coordinate constants */
+#define TOUCH_PRESSURE 5
+#define TOUCH_PRESSURE_FS 100
+
+#define XMOVE_LIMIT 5
+#define YMOVE_LIMIT 5
+#define XYMOVE_CNT 3
+
+#define MAX_10BIT ((1<<10)-1)
+
+/* Touch screen channel BIAS constants */
+#define XBIAS 0x20
+#define YBIAS 0x40
+#define ZBIAS 0x80
+
+/* Touch screen coordinates */
+#define MIN_X 10
+#define MAX_X 1024
+#define MIN_Y 10
+#define MAX_Y 1024
+#define WAIT_ADC_COMPLETION 10
+
+/* PMIC ADC round robin delays */
+#define ADC_LOOP_DELAY0 0x0 /* Continuous loop */
+#define ADC_LOOP_DELAY1 0x1 /* 4.5 ms approximate */
+
+/* PMIC Vendor Identifiers */
+#define PMIC_VENDOR_FS 0 /* PMIC vendor FreeScale */
+#define PMIC_VENDOR_MAXIM 1 /* PMIC vendor MAXIM */
+#define PMIC_VENDOR_NEC 2 /* PMIC vendor NEC */
+#define MRSTOUCH_MAX_CHANNELS 32 /* Maximum ADC channels */
+
+/* Touch screen device structure */
+struct mrstouch_dev {
+ struct spi_device *spi; /* SPI device associated with touch screen */
+ struct input_dev *input; /* input device for touchscreen*/
+ char phys[32]; /* Device name */
+ struct task_struct *pendet_thrd; /* PENDET interrupt handler */
+ struct semaphore lock; /* Sync between interrupt and PENDET handler */
+ bool busy; /* Busy flag */
+ u16 asr; /* Address selection register */
+ int irq; /* Touch screen IRQ # */
+ uint vendor; /* PMIC vendor */
+ uint rev; /* PMIC revision */
+ bool suspended; /* Device suspended status */
+ bool disabled; /* Device disabled status */
+ u16 x; /* X coordinate */
+ u16 y; /* Y coordinate */
+ bool pendown; /* PEN position */
+} ;
+
+
+/* Global Pointer to Touch screen device */
+static struct mrstouch_dev *mrstouchdevp;
+
+/* Utility to read PMIC ID */
+static int mrstouch_pmic_id(uint *vendor, uint *rev)
+{
+ int err;
+ struct ipc_pmic_reg_data ipcbuf;
+
+ ipcbuf.ioc = 1;
+ ipcbuf.num_entries = 1;
+ ipcbuf.pmic_reg_data[0].register_address = PMIC_REG_ID1;
+
+ err = ipc_pmic_register_read(&ipcbuf);
+ if (err)
+ return -1;
+
+ *vendor = (ipcbuf.pmic_reg_data[0].value) & 0x7;
+ *rev = (ipcbuf.pmic_reg_data[0].value >> 3) & 0x7;
+
+ return 0;
+}
+
+/*
+ * Parse ADC channels to find end of the channel configured by other ADC user
+ * NEC and MAXIM requires 4 channels and FreeScale needs 18 channels
+ */
+static int mrstouch_chan_parse(void)
+{
+ int err, i, j, chan, found;
+ struct ipc_pmic_reg_data ipcbuf;
+
+ ipcbuf.ioc = 1;
+
+ found = -1;
+ ipcbuf.num_entries = 4;
+
+ for (i = 0; i < MRSTOUCH_MAX_CHANNELS; i++) {
+ if (found >= 0)
+ break;
+
+ for (j = 0; j <= 3; j++)
+ ipcbuf.pmic_reg_data[j].register_address = PMICADDR0+i;
+
+ err = ipc_pmic_register_read(&ipcbuf);
+ if (err)
+ return -1;
+
+ for (j = 0; j < ipcbuf.num_entries; j++) {
+ chan = ipcbuf.pmic_reg_data[j].value;
+ if (chan == END_OF_CHANNEL) {
+ found = i;
+ break;
+ }
+ }
+ }
+
+ if (found < 0)
+ return 0;
+
+ if (mrstouchdevp->vendor == PMIC_VENDOR_FS) {
+ if (found && found > (MRSTOUCH_MAX_CHANNELS - 18))
+ return -1;
+ } else {
+ if (found && found > (MRSTOUCH_MAX_CHANNELS - 4))
+ return -1;
+ }
+ return found;
+}
+
+/* Utility to enable/disable pendet.
+ * pendet set to true enables PENDET interrupt
+ * pendet set to false disables PENDET interrupt
+ * Also clears RND mask bit
+*/
+static void pendet_enable(bool pendet)
+{
+ u8 adccntrl1 = 0;
+ u8 pendet_enabled = 0;
+ int retry = 0;
+ struct ipc_pmic_reg_data ipcbuf;
+
+ ipcbuf.ioc = 1;
+
+ ipcbuf.num_entries = 1;
+ ipcbuf.pmic_reg_data[0].register_address = PMIC_REG_ADCCNTL1;
+ ipc_pmic_register_read(&ipcbuf);
+ adccntrl1 = ipcbuf.pmic_reg_data[0].value;
+
+ if (pendet)
+ adccntrl1 |= 0x20; /* Enable pendet */
+ else
+ adccntrl1 &= 0xDF; /* Disable pendet */
+
+ ipcbuf.num_entries = 2;
+ ipcbuf.pmic_reg_data[0].register_address = PMIC_REG_MADCINT;
+ ipcbuf.pmic_reg_data[0].value = 0x0;
+ ipcbuf.pmic_reg_data[1].register_address = PMIC_REG_ADCCNTL1;
+ ipcbuf.pmic_reg_data[1].value = adccntrl1;
+ ipc_pmic_register_write(&ipcbuf, 1);
+
+ if (!pendet)
+ return;
+
+
+ /*
+ * Sometimes even after ipc_pmic_register_write success
+ * the PMIC register value is not updated. Retry few iterations
+ * to enable pendet.
+ */
+ ipcbuf.num_entries = 1;
+ ipcbuf.pmic_reg_data[0].register_address = PMIC_REG_ADCCNTL1;
+ ipc_pmic_register_read(&ipcbuf);
+ pendet_enabled = (ipcbuf.pmic_reg_data[0].value >> 5) & 0x01;
+
+ retry = 0;
+ while (!pendet_enabled) {
+ retry++;
+ msleep(10);
+ ipcbuf.pmic_reg_data[0].register_address = PMIC_REG_ADCCNTL1;
+ ipcbuf.pmic_reg_data[0].value = adccntrl1;
+ ipc_pmic_register_write(&ipcbuf, 1);
+
+ ipcbuf.pmic_reg_data[0].register_address = PMIC_REG_ADCCNTL1;
+ ipc_pmic_register_read(&ipcbuf);
+ pendet_enabled = (ipcbuf.pmic_reg_data[0].value >> 5) & 0x01;
+ if (retry >= 10) {
+ printk(KERN_ERR "Touch screen disabled\n");
+ break;
+ }
+ }
+}
+
+
+/* To read PMIC ADC touch screen result
+ * Reads ADC storage registers for higher 7 and lower 3 bits
+ * converts the two readings to single value and turns off gain bit
+ */
+static int mrstouch_ts_chan_read(u16 offset, u16 chan, u16 *vp, u16 *vm)
+{
+ int err, count;
+ u16 result;
+ struct ipc_pmic_reg_data ipcbuf;
+
+ ipcbuf.ioc = 1;
+ ipcbuf.num_entries = 4;
+
+ result = PMIC_REG_ADCSNS0H + offset;
+
+ if (chan == MRST_TS_CHAN12)
+ result += 4;
+
+ for (count = 0; count <= 3; count++)
+ ipcbuf.pmic_reg_data[count].register_address = result++;
+
+ err = ipc_pmic_register_read(&ipcbuf);
+ if (err)
+ return -1;
+
+ *vp = ipcbuf.pmic_reg_data[0].value << 3; /* Higher 7 bits */
+ *vp |= ipcbuf.pmic_reg_data[1].value & 0x7; /* Lower 3 bits */
+ *vp &= 0x3FF;
+
+ *vm = ipcbuf.pmic_reg_data[2].value << 3; /* Higher 7 bits */
+ *vm |= ipcbuf.pmic_reg_data[3].value & 0x7; /* Lower 3 bits */
+ *vm &= 0x3FF;
+
+ return 0;
+}
+
+/* To configure touch screen channels
+ * Writes touch screen channels to ADC address selection registers
+ */
+static int mrstouch_ts_chan_set(uint offset)
+{
+ int err, count;
+ u16 chan;
+ struct ipc_pmic_reg_data ipcbuf;
+
+ ipcbuf.ioc = 1;
+ ipcbuf.num_entries = 5;
+
+ chan = PMICADDR0 + offset;
+ for (count = 0; count <= 3; count++) {
+ ipcbuf.pmic_reg_data[count].register_address = chan++;
+ ipcbuf.pmic_reg_data[count].value = MRST_TS_CHAN10 + count;
+ }
+ ipcbuf.pmic_reg_data[count].register_address = chan;
+ ipcbuf.pmic_reg_data[count].value = END_OF_CHANNEL;
+
+ err = ipc_pmic_register_write(&ipcbuf, 1);
+ if (err)
+ return -1;
+
+ return 0;
+}
+
+/* Initialize ADC */
+static int mrstouch_adc_init(struct mrstouch_dev *tsdev)
+{
+ int err, start;
+ struct ipc_pmic_mod_reg_data ipcbuf;
+
+ err = mrstouch_pmic_id(&tsdev->vendor, &tsdev->rev);
+ if (err) {
+ printk(KERN_ERR "Error in reading PMIC Id");
+ return err;
+ }
+
+ start = mrstouch_chan_parse();
+ if (start == -1) {
+ printk(KERN_ERR "Error in parse channels");
+ return start;
+ }
+
+ tsdev->asr = start;
+
+ mrstouch_debug("Channel offset(%d): 0x%X\n", tsdev->asr, tsdev->vendor);
+
+ /* ADC power on, start, enable PENDET and set loop delay
+ * ADC loop delay is set to 4.5 ms approximately
+ * Loop delay more than this results in jitter in adc readings
+ * Setting loop delay to 0 (continous loop) in MAXIM stops PENDET
+ * interrupt generation sometimes.
+ */
+ ipcbuf.ioc = 1;
+ ipcbuf.num_entries = 2;
+ ipcbuf.pmic_mod_reg_data[0].register_address = PMIC_REG_ADCCNTL1;
+ ipcbuf.pmic_mod_reg_data[0].bit_map = 0xE7;
+
+ ipcbuf.pmic_mod_reg_data[1].register_address = PMIC_REG_MADCINT;
+ ipcbuf.pmic_mod_reg_data[1].bit_map = 0x03;
+
+ if (tsdev->vendor == PMIC_VENDOR_FS) {
+ ipcbuf.pmic_mod_reg_data[0].value = 0xE0 | ADC_LOOP_DELAY0;
+ ipcbuf.pmic_mod_reg_data[1].value = 0x5;
+ } else {
+ /* NEC and MAXIm not consistent with loop delay 0 */
+ ipcbuf.pmic_mod_reg_data[0].value = 0xE0 | ADC_LOOP_DELAY1;
+ ipcbuf.pmic_mod_reg_data[1].value = 0x0;
+
+ /* configure touch screen channels */
+ err = mrstouch_ts_chan_set(tsdev->asr);
+ if (err)
+ return err;
+ }
+
+ err = ipc_pmic_register_read_modify(&ipcbuf);
+
+ return err;
+}
+
+/* Reports x,y coordinates to event subsystem */
+static void mrstouch_report_xy(u16 x, u16 y, u16 z)
+{
+ int xdiff, ydiff;
+
+ if (mrstouchdevp->pendown && z <= TOUCH_PRESSURE) {
+ /* Pen removed, report button release */
+ mrstouch_debug("BTN REL(%d)", z);
+ input_report_key(mrstouchdevp->input, BTN_TOUCH, 0);
+ mrstouchdevp->pendown = false;
+ }
+
+ xdiff = abs(x - mrstouchdevp->x);
+ ydiff = abs(y - mrstouchdevp->y);
+
+ /*
+ if x and y values changes for XYMOVE_CNT readings it is considered
+ as stylus is moving. This is required to differentiate between stylus
+ movement and jitter
+ */
+ if (x < MIN_X || x > MAX_X || y < MIN_Y || y > MAX_Y) {
+ /* Spurious values, release button if touched and return */
+ if (mrstouchdevp->pendown) {
+ mrstouch_debug("BTN REL(%d)", z);
+ input_report_key(mrstouchdevp->input, BTN_TOUCH, 0);
+ mrstouchdevp->pendown = false;
+ }
+ return;
+ } else if (xdiff >= XMOVE_LIMIT || ydiff >= YMOVE_LIMIT) {
+ mrstouchdevp->x = x;
+ mrstouchdevp->y = y;
+
+ input_report_abs(mrstouchdevp->input, ABS_X, x);
+ input_report_abs(mrstouchdevp->input, ABS_Y, y);
+ input_sync(mrstouchdevp->input);
+ }
+
+
+ if (!mrstouchdevp->pendown && z > TOUCH_PRESSURE) {
+ /* Pen touched, report button touch */
+ mrstouch_debug("BTN TCH(%d, %d, %d)", x, y, z);
+ input_report_key(mrstouchdevp->input, BTN_TOUCH, 1);
+ mrstouchdevp->pendown = true;
+ }
+}
+
+
+/* Utility to start ADC, used by freescale handler */
+static int pendet_mask(void)
+{
+ int err = 0;
+ struct ipc_pmic_mod_reg_data ipcbuf;
+
+ ipcbuf.ioc = 1;
+ ipcbuf.num_entries = 1;
+ ipcbuf.pmic_mod_reg_data[1].register_address = PMIC_REG_MADCINT;
+ ipcbuf.pmic_mod_reg_data[1].bit_map = 0x02;
+ ipcbuf.pmic_mod_reg_data[1].value = 0x01;
+
+ err = ipc_pmic_register_read_modify(&ipcbuf);
+
+ return err;
+}
+
+/* Utility to stop ADC, used by freescale handler */
+static int pendet_umask(void)
+{
+ int err = 0;
+ struct ipc_pmic_mod_reg_data ipcbuf;
+
+ ipcbuf.ioc = 1;
+ ipcbuf.num_entries = 1;
+ ipcbuf.pmic_mod_reg_data[1].register_address = PMIC_REG_MADCINT;
+ ipcbuf.pmic_mod_reg_data[1].bit_map = 0x02;
+ ipcbuf.pmic_mod_reg_data[1].value = 0x0;
+
+ err = ipc_pmic_register_read_modify(&ipcbuf);
+
+ return err;
+}
+
+/* Utility to read ADC, used by freescale handler */
+static int mrstouch_pmic_fs_adc_read(struct mrstouch_dev *tsdev)
+{
+ int err;
+ u16 x, y, z, result;
+ struct ipc_pmic_reg_data ipcbuf;
+
+ result = PMIC_REG_ADCSNS0H + tsdev->asr;
+
+ ipcbuf.ioc = 1;
+ ipcbuf.num_entries = 4;
+ ipcbuf.pmic_reg_data[0].register_address = result + 4;
+ ipcbuf.pmic_reg_data[1].register_address = result + 5;
+ ipcbuf.pmic_reg_data[2].register_address = result + 16;
+ ipcbuf.pmic_reg_data[3].register_address = result + 17;
+
+ err = ipc_pmic_register_read(&ipcbuf);
+ if (err)
+ goto ipc_error;
+
+ x = ipcbuf.pmic_reg_data[0].value << 3; /* Higher 7 bits */
+ x |= ipcbuf.pmic_reg_data[1].value & 0x7; /* Lower 3 bits */
+ x &= 0x3FF;
+
+ y = ipcbuf.pmic_reg_data[2].value << 3; /* Higher 7 bits */
+ y |= ipcbuf.pmic_reg_data[3].value & 0x7; /* Lower 3 bits */
+ y &= 0x3FF;
+
+ /* Read Z value */
+ ipcbuf.num_entries = 2;
+ ipcbuf.pmic_reg_data[0].register_address = result + 28;
+ ipcbuf.pmic_reg_data[1].register_address = result + 29;
+
+ err = ipc_pmic_register_read(&ipcbuf);
+ if (err)
+ goto ipc_error;
+
+ z = ipcbuf.pmic_reg_data[0].value << 3; /* Higher 7 bits */
+ z |= ipcbuf.pmic_reg_data[1].value & 0x7; /* Lower 3 bits */
+ z &= 0x3FF;
+
+#if defined(MRSTOUCH_PRINT_XYZP)
+ mrstouch_debug("X: %d, Y: %d, Z: %d", x, y, z);
+#endif
+
+ if (z >= TOUCH_PRESSURE_FS) {
+ mrstouch_report_xy(x, y, TOUCH_PRESSURE - 1); /* Pen Removed */
+ return TOUCH_PRESSURE - 1;
+ } else {
+ mrstouch_report_xy(x, y, TOUCH_PRESSURE + 1); /* Pen Touched */
+ return TOUCH_PRESSURE + 1;
+ }
+
+ return 0;
+
+ipc_error:
+ printk(KERN_ERR "IPC Error: %s", __func__);
+ return -1;
+}
+
+/* To handle free scale pmic pendet interrupt */
+static int pmic0_pendet(void *data)
+{
+ int err, count;
+ u16 chan;
+ unsigned int touched;
+ struct ipc_pmic_reg_data ipcbuf;
+ struct mrstouch_dev *tsdev = (struct mrstouch_dev *)data;
+
+ chan = PMICADDR0 + tsdev->asr;
+
+ ipcbuf.ioc = 1;
+ /* Set X BIAS */
+ ipcbuf.num_entries = 5;
+ for (count = 0; count <= 3; count++) {
+ ipcbuf.pmic_reg_data[count].register_address = chan++;
+ ipcbuf.pmic_reg_data[count].value = 0x2A;
+ }
+ ipcbuf.pmic_reg_data[count].register_address = chan++; /* Dummy */
+ ipcbuf.pmic_reg_data[count].value = 0;
+
+ err = ipc_pmic_register_write(&ipcbuf, 1);
+ if (err)
+ goto ipc_error;
+
+ msleep(WAIT_ADC_COMPLETION);
+
+ /* Set Y BIAS */
+ ipcbuf.num_entries = 5;
+ for (count = 0; count <= 3; count++) {
+ ipcbuf.pmic_reg_data[count].register_address = chan++;
+ ipcbuf.pmic_reg_data[count].value = 0x4A;
+ }
+ ipcbuf.pmic_reg_data[count].register_address = chan++; /* Dummy */
+ ipcbuf.pmic_reg_data[count].value = 0;
+
+ err = ipc_pmic_register_write(&ipcbuf, 1);
+ if (err)
+ goto ipc_error;
+
+ msleep(WAIT_ADC_COMPLETION);
+
+ /* Set Z BIAS */
+ chan += 2;
+ ipcbuf.num_entries = 4;
+ for (count = 0; count <= 3; count++) {
+ ipcbuf.pmic_reg_data[count].register_address = chan++;
+ ipcbuf.pmic_reg_data[count].value = 0x8A;
+ }
+
+ err = ipc_pmic_register_write(&ipcbuf, 1);
+ if (err)
+ goto ipc_error;
+
+ msleep(WAIT_ADC_COMPLETION);
+
+ /*Read touch screen channels till pen removed
+ * Freescale reports constant value of z for all points
+ * z is high when screen is not touched and low when touched
+ * Map high z value to not touched and low z value to pen touched
+ */
+ touched = mrstouch_pmic_fs_adc_read(tsdev);
+ while (touched > TOUCH_PRESSURE) {
+ touched = mrstouch_pmic_fs_adc_read(tsdev);
+ msleep(WAIT_ADC_COMPLETION);
+ }
+
+ /* Clear all TS channels */
+ chan = PMICADDR0 + tsdev->asr;
+ ipcbuf.ioc = 1;
+ ipcbuf.num_entries = 5;
+ for (count = 0; count <= 4; count++) {
+ ipcbuf.pmic_reg_data[count].register_address = chan++;
+ ipcbuf.pmic_reg_data[count].value = 0x0;
+ }
+ err = ipc_pmic_register_write(&ipcbuf, 1);
+ if (err)
+ goto ipc_error;
+
+ for (count = 0; count <= 4; count++) {
+ ipcbuf.pmic_reg_data[count].register_address = chan++;
+ ipcbuf.pmic_reg_data[count].value = 0x0;
+ }
+ err = ipc_pmic_register_write(&ipcbuf, 1);
+ if (err)
+ goto ipc_error;
+
+ chan += 2;
+ for (count = 0; count <= 4; count++) {
+ ipcbuf.pmic_reg_data[count].register_address = chan++;
+ ipcbuf.pmic_reg_data[count].value = 0x0;
+ }
+ err = ipc_pmic_register_write(&ipcbuf, 1);
+ if (err)
+ goto ipc_error;
+
+ return 0;
+
+ipc_error:
+ printk(KERN_ERR "IPC Error: %s", __func__);
+ return -1;
+}
+
+
+/* To enable X, Y and Z bias values
+ * Enables YPYM for X channels and XPXM for Y channels
+ */
+static int mrstouch_ts_bias_set(uint offset, uint bias)
+{
+ int err, count;
+ u16 chan, start;
+ struct ipc_pmic_reg_data ipcbuf;
+
+ chan = PMICADDR0 + offset;
+ start = MRST_TS_CHAN10;
+
+ ipcbuf.ioc = 1;
+ ipcbuf.num_entries = 4;
+
+ for (count = 0; count <= 3; count++) {
+ ipcbuf.pmic_reg_data[count].register_address = chan++;
+ ipcbuf.pmic_reg_data[count].value = bias | (start + count);
+ }
+
+ err = ipc_pmic_register_write(&ipcbuf, 1);
+ if (err)
+ return -1;
+
+ return 0;
+}
+
+/* To read touch screen channel values */
+static int mrstouch_adc_read(struct mrstouch_dev *tsdev)
+{
+ int err;
+ u16 xp, xm, yp, ym, zp, zm;
+
+ /* configure Y bias for X channels */
+ err = mrstouch_ts_bias_set(tsdev->asr, YBIAS);
+ if (err)
+ goto ipc_error;
+
+ msleep(WAIT_ADC_COMPLETION);
+
+ /* read x+ and x- channels */
+ err = mrstouch_ts_chan_read(tsdev->asr, MRST_TS_CHAN10, &xp, &xm);
+ if (err)
+ goto ipc_error;
+
+ /* configure x bias for y channels */
+ err = mrstouch_ts_bias_set(tsdev->asr, XBIAS);
+ if (err)
+ goto ipc_error;
+
+ msleep(WAIT_ADC_COMPLETION);
+
+ /* read y+ and y- channels */
+ err = mrstouch_ts_chan_read(tsdev->asr, MRST_TS_CHAN12, &yp, &ym);
+ if (err)
+ goto ipc_error;
+
+ /* configure z bias for x and y channels */
+ err = mrstouch_ts_bias_set(tsdev->asr, ZBIAS);
+ if (err)
+ goto ipc_error;
+
+ msleep(WAIT_ADC_COMPLETION);
+
+ /* read z+ and z- channels */
+ err = mrstouch_ts_chan_read(tsdev->asr, MRST_TS_CHAN10, &zp, &zm);
+ if (err)
+ goto ipc_error;
+
+#if defined(MRSTOUCH_PRINT_XYZP)
+ printk(KERN_INFO "X+: %d, Y+: %d, Z+: %d\n", xp, yp, zp);
+#endif
+
+#if defined(MRSTOUCH_PRINT_XYZM)
+ printk(KERN_INFO "X-: %d, Y-: %d, Z-: %d\n", xm, ym, zm);
+#endif
+
+ mrstouch_report_xy(xp, yp, zp); /* report x and y to eventX */
+
+ return zp;
+
+ipc_error:
+ printk(KERN_ERR "IPC Error: %s", __func__);
+ return -1;
+}
+
+/* PENDET interrupt handler function for NEC and MAXIM */
+static void pmic12_pendet(void *data)
+{
+ unsigned int touched;
+ struct mrstouch_dev *tsdev = (struct mrstouch_dev *)data;
+
+ /* read touch screen channels till pen removed */
+ touched = mrstouch_adc_read(tsdev);
+ while (touched > TOUCH_PRESSURE) {
+ msleep(WAIT_ADC_COMPLETION);
+ touched = mrstouch_adc_read(tsdev);
+ }
+}
+
+/* Handler to process PENDET interrupt */
+int mrstouch_pendet(void *data)
+{
+ struct mrstouch_dev *tsdev = (struct mrstouch_dev *)data;
+ while (1) {
+ /* Wait for PENDET interrupt */
+ if (down_interruptible(&tsdev->lock)) {
+ msleep(WAIT_ADC_COMPLETION);
+ continue;
+ }
+
+ if (tsdev->busy)
+ return 0;
+
+ tsdev->busy = true;
+
+ if (mrstouchdevp->vendor == PMIC_VENDOR_NEC ||
+ mrstouchdevp->vendor == PMIC_VENDOR_MAXIM) {
+ /* PENDET must be disabled in NEC before reading ADC */
+ pendet_enable(false); /* Disbale PENDET */
+ pmic12_pendet(mrstouchdevp);
+ pendet_enable(true); /*Enable PENDET */
+ } else if (mrstouchdevp->vendor == PMIC_VENDOR_FS) {
+ pendet_umask(); /* Stop ADC */
+ pmic0_pendet(mrstouchdevp);
+ pendet_mask(); /* Stop ADC */
+ } else
+ printk(KERN_ERR "Unknown PMIC, Not supported\n");
+
+ tsdev->busy = false;
+
+ }
+ return 0;
+}
+
+/* PENDET interrupt handler */
+static irqreturn_t pendet_intr_handler(int irq, void *handle)
+{
+ struct mrstouch_dev *tsdev = (struct mrstouch_dev *)handle;
+
+ up(&tsdev->lock);
+ return IRQ_HANDLED;
+}
+
+/* Intializes input device and registers with input subsystem */
+static int ts_input_dev_init(struct mrstouch_dev *tsdev, struct spi_device *spi)
+{
+ int err = 0;
+
+ mrstouch_debug("%s", __func__);
+
+ tsdev->input = input_allocate_device();
+ if (!tsdev->input) {
+ mrstouch_error("%s", "Input dev allocation failed");
+ return -1;
+ }
+
+ tsdev->input->name = "mrst_touchscreen";
+ snprintf(tsdev->phys, sizeof(tsdev->phys),
+ "%s/input0", dev_name(&spi->dev));
+ tsdev->input->phys = tsdev->phys;
+ tsdev->input->dev.parent = &spi->dev;
+
+ tsdev->input->id.vendor = tsdev->vendor;
+ tsdev->input->id.version = tsdev->rev;
+
+ tsdev->input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+ tsdev->input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+ input_set_abs_params(tsdev->input, ABS_X, MIN_X, MIN_Y, 0, 0);
+ input_set_abs_params(tsdev->input, ABS_Y, MIN_X, MIN_Y, 0, 0);
+
+ err = input_register_device(tsdev->input);
+ if (err) {
+ mrstouch_error("%s", "Input dev registration failed");
+ input_free_device(tsdev->input);
+ return -1;
+ }
+
+ mrstouch_debug("%s", "mrstouch initialized");
+
+ return 0;
+
+}
+
+/* Probe function for touch screen driver */
+static int __devinit mrstouch_probe(struct spi_device *mrstouch_spi)
+{
+ int err;
+ unsigned int myirq;
+ struct mrstouch_dev *tsdev;
+
+ mrstouch_debug("%s(%p)", __func__, mrstouch_spi);
+
+ mrstouchdevp = NULL;
+ myirq = mrstouch_spi->irq;
+
+ if (!mrstouch_spi->irq) {
+ mrstouch_error("%s(%d)", "No IRQ", myirq);
+ return -1;
+ }
+
+ tsdev = kzalloc(sizeof(struct mrstouch_dev), GFP_KERNEL);
+ if (!tsdev) {
+ mrstouch_error("%s", "ERROR: Memory failure");
+ return -ENOMEM;
+ }
+
+ tsdev->irq = myirq;
+ mrstouchdevp = tsdev;
+
+ if (mrstouch_adc_init(tsdev) != 0) {
+ mrstouch_error("%s", "ADC init failed");
+ goto mrstouch_err_free_mem;
+ }
+
+ dev_set_drvdata(&mrstouch_spi->dev, tsdev);
+ tsdev->spi = mrstouch_spi;
+
+ err = ts_input_dev_init(tsdev, mrstouch_spi);
+ if (err != 0) {
+ mrstouch_error("%s", "ts_input_dev_init failed");
+ goto mrstouch_err_free_mem;
+ }
+
+ sema_init(&tsdev->lock, 1);
+ if (down_interruptible(&tsdev->lock)) {
+ mrstouch_error("%s", "tsdev->lock Error");
+ goto mrstouch_err_free_mem;
+ }
+
+ mrstouch_debug("Requesting IRQ-%d", myirq);
+ err = request_irq(myirq, pendet_intr_handler,
+ 0, "mrstouch", tsdev);
+ if (err) {
+ mrstouch_error("IRQ Request Failed - %d", err);
+ goto mrstouch_err_free_mem;
+ }
+
+ tsdev->pendet_thrd = kthread_run(mrstouch_pendet,
+ (void *)tsdev, "pendet handler");
+ if (IS_ERR(tsdev->pendet_thrd)) {
+ dev_err(&tsdev->spi->dev, "kthread_run failed \n");
+ goto mrstouch_err_free_mem;
+ }
+
+ mrstouch_debug("%s", "Driver initialized");
+
+ return 0;
+
+ mrstouch_err_free_mem:
+ kfree(tsdev);
+ return -1;
+}
+
+static int mrstouch_suspend(struct spi_device *spi, pm_message_t msg)
+{
+ mrstouch_debug("%s", __func__);
+ mrstouchdevp->suspended = 1;
+ return 0;
+}
+
+static int mrstouch_resume(struct spi_device *spi)
+{
+ mrstouch_debug("%s", __func__);
+ mrstouchdevp->suspended = 0;
+ return 0;
+}
+
+static int mrstouch_remove(struct spi_device *spi)
+{
+ mrstouch_debug("%s", __func__);
+ free_irq(mrstouchdevp->irq, mrstouchdevp);
+ input_unregister_device(mrstouchdevp->input);
+ input_free_device(mrstouchdevp->input);
+ kfree(mrstouchdevp);
+ if (mrstouchdevp->pendet_thrd)
+ kthread_stop(mrstouchdevp->pendet_thrd);
+ return 0;
+}
+
+static struct spi_driver mrstouch_driver = {
+ .driver = {
+ .name = "pmic_touch",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = mrstouch_probe,
+ .suspend = mrstouch_suspend,
+ .resume = mrstouch_resume,
+ .remove = mrstouch_remove,
+};
+
+static int __init mrstouch_module_init(void)
+{
+ int err;
+
+ mrstouch_debug("%s", __func__);
+ err = spi_register_driver(&mrstouch_driver);
+ if (err) {
+ mrstouch_debug("%s(%d)", "SPI PENDET failed", err);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void __exit mrstouch_module_exit(void)
+{
+ mrstouch_debug("%s", __func__);
+ spi_unregister_driver(&mrstouch_driver);
+ return;
+}
+
+module_init(mrstouch_module_init);
+module_exit(mrstouch_module_exit);
--
1.6.2.5

View File

@ -0,0 +1,398 @@
From 6317c631cb1fd32f34da98a945747781d5a8906d Mon Sep 17 00:00:00 2001
From: Priya Vijayan <priya.vijayan@intel.com>
Date: Tue, 4 May 2010 14:21:37 -0700
Subject: [PATCH] Add mtdev driver and configs
Add multi-touch driver and configs for event devices.
This module is from He Min <min.he@intel.com>
Code modifications and configs from Priya Vijayan <priya.vijayan@intel.com>
Patch-mainline: 2.6.34
Signed-off-by: Priya Vijayan <priya.vijayan@intel.com>
---
drivers/input/Kconfig | 9 ++
drivers/input/Makefile | 1 +
drivers/input/input.c | 1 +
drivers/input/mtdev.c | 307 ++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/input.h | 1 +
5 files changed, 319 insertions(+), 0 deletions(-)
create mode 100644 drivers/input/mtdev.c
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
index 07c2cd4..0264508 100644
--- a/drivers/input/Kconfig
+++ b/drivers/input/Kconfig
@@ -135,6 +135,15 @@ config INPUT_EVDEV
To compile this driver as a module, choose M here: the
module will be called evdev.
+config INPUT_MTDEV
+ tristate "Multitouch interface"
+ help
+ Say Y here if you want to enable Multi-touch input driver for event devices
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here:the
+ module will be called mtdev.
+
config INPUT_EVBUG
tristate "Event debugging"
help
diff --git a/drivers/input/Makefile b/drivers/input/Makefile
index 7ad212d..96a4d94 100644
--- a/drivers/input/Makefile
+++ b/drivers/input/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o
obj-$(CONFIG_INPUT_JOYDEV) += joydev.o
obj-$(CONFIG_INPUT_EVDEV) += evdev.o
obj-$(CONFIG_INPUT_EVBUG) += evbug.o
+obj-$(CONFIG_INPUT_MTDEV) += mtdev.o
obj-$(CONFIG_INPUT_KEYBOARD) += keyboard/
obj-$(CONFIG_INPUT_MOUSE) += mouse/
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 86cb2d2..b589dec 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -47,6 +47,7 @@ static unsigned int input_abs_bypass_init_data[] __initdata = {
ABS_MT_BLOB_ID,
ABS_MT_TRACKING_ID,
ABS_MT_PRESSURE,
+ ABS_MT_CONTACT_COUNT,
0
};
static unsigned long input_abs_bypass[BITS_TO_LONGS(ABS_CNT)];
diff --git a/drivers/input/mtdev.c b/drivers/input/mtdev.c
new file mode 100644
index 0000000..8b01220
--- /dev/null
+++ b/drivers/input/mtdev.c
@@ -0,0 +1,312 @@
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/wait.h>
+#include <linux/kthread.h>
+
+#define MTDEV_MAX_POINTERS 5
+
+#ifndef ABS_MT_PRESSURE
+#define ABS_MT_PRESSURE 0x3a
+#endif
+#ifndef ABS_MT_CONTACT_COUNT
+#define ABS_MT_CONTACT_COUNT 0x3b
+#endif
+
+struct mtdev_input_dev
+{
+ struct input_dev* input_dev;
+ int id;
+ bool ready;
+ int x;
+ int y;
+ int z;
+ int touch;
+};
+
+struct mtdev_dev
+{
+ int count;
+ int last_count;
+ wait_queue_head_t wq;
+ struct input_handle handle;
+ struct mtdev_input_dev devs[MTDEV_MAX_POINTERS];
+};
+
+//id==-1 means to find an empty slot
+static int find_match_id(struct mtdev_dev * mtdev,int id)
+{
+ int i=0;
+
+ for (i=0;i<MTDEV_MAX_POINTERS;i++)
+ {
+ if(mtdev->devs[i].id==id)
+ {
+ return i;
+ }
+ }
+ return -1;
+}
+
+
+static int mtdev_kt(void *data)
+{
+ struct mtdev_dev *mtdev=(struct mtdev_dev*)data;
+ int i=0;
+ int err=0;
+ printk("mtdev_kt entered\n");
+ if(!mtdev)
+ return -1;
+ //wait_event_interruptible(mtdev->wq,kthread_should_stop());
+ for(;i<MTDEV_MAX_POINTERS;i++)
+ {
+ struct input_dev *pdev=NULL;
+ pdev=mtdev->devs[i].input_dev;
+
+ err=input_register_device(pdev);
+ if(err)
+ {
+ printk("error in register mtdev %d\n",err);
+ return err;
+ }
+ else
+ printk("successfully registered input %d\n",i);
+ mtdev->devs[i].ready=true;
+
+ }
+ return 0;
+}
+
+static void mtdev_event(struct input_handle * handle,
+ unsigned int type, unsigned int code, int value)
+{
+ static int i=0;
+ //int err=0;
+ int j=0;
+ struct mtdev_dev *mtdev=handle->private;
+ //printk("mtdev_event %x %x %x\n",type,code,value);
+ if(!mtdev->devs[1].ready||!mtdev->devs[0].ready)
+ return;
+ if(type==EV_ABS)
+ {
+ switch(code)
+ {
+ case ABS_MT_CONTACT_COUNT:
+ if(value!=0)
+ {
+ //we start from the first point
+ i=0;
+ //printk("mtdev:contact count is %d\n",value);
+ }
+ else if(value>MTDEV_MAX_POINTERS)
+ {
+ value=MTDEV_MAX_POINTERS;
+ }
+
+ //found last release fingers and send release event
+ for(j=0;j<MTDEV_MAX_POINTERS;j++)
+ {
+ if(mtdev->devs[j].touch==0
+ &&mtdev->devs[j].id!=-1)
+ {
+ input_report_key(mtdev->devs[j].input_dev,BTN_TOUCH,0);
+ input_sync(mtdev->devs[j].input_dev);
+ printk("%d id %d released\n",j,mtdev->devs[j].id);
+ mtdev->devs[j].id=-1;
+ }
+ mtdev->devs[j].touch=0;
+ }
+ mtdev->count=value;
+
+ mtdev->last_count=value;
+
+ break;
+ case ABS_MT_TRACKING_ID:
+ {
+ i=find_match_id(mtdev,value);
+ if(i==-1||i>=MTDEV_MAX_POINTERS)
+ {
+ i=find_match_id(mtdev,-1);
+ if(i==-1||i>=MTDEV_MAX_POINTERS)
+ {
+ printk("no empty slot for id %d\n",value);
+ break;
+ }
+ else
+ {
+ //newly pressed
+ mtdev->devs[i].touch=2;
+ mtdev->devs[i].id=value;
+ printk("found slot %d for id %d\n",i,value);
+ break;
+ }
+ }
+ //printk("found slot %d for id%d\n",i,value);
+ //keep the point
+ mtdev->devs[i].touch=1;
+
+ }
+ break;
+ case ABS_MT_POSITION_X:
+ if(i<MTDEV_MAX_POINTERS&&i!=-1)
+ mtdev->devs[i].x=value;
+ //printk("mt x :%d\n",value);
+ break;
+ case ABS_MT_POSITION_Y:
+ if(i<MTDEV_MAX_POINTERS&&i!=-1)
+ mtdev->devs[i].y=value;
+ //printk("mt y :%d\n",value);
+ break;
+ case ABS_MT_PRESSURE:
+ if(i<MTDEV_MAX_POINTERS&&i!=-1)
+ mtdev->devs[i].z=value;
+ break;
+ default:
+ break;
+ }
+ }
+ else if(type == EV_SYN && code == SYN_MT_REPORT)
+ {
+ if(i<MTDEV_MAX_POINTERS&&i!=-1)
+ {
+ if(mtdev->devs[i].touch==2)
+ {
+ input_report_key(mtdev->devs[i].input_dev,BTN_TOUCH,1);
+
+ }
+ input_report_abs(mtdev->devs[i].input_dev,ABS_X,mtdev->devs[i].x);
+ input_report_abs(mtdev->devs[i].input_dev,ABS_Y,mtdev->devs[i].y);
+ input_report_abs(mtdev->devs[i].input_dev,ABS_PRESSURE,mtdev->devs[i].z);
+ input_sync(mtdev->devs[i].input_dev);
+ //printk("mtdev_event %d id %d (%d,%d,%d)\n",i,mtdev->devs[i].id,mtdev->devs[i].x,mtdev->devs[i].y,mtdev->devs[i].z);
+ //i++;
+ }
+ }
+
+}
+/*
+ * grab all the input of mt device, create new single touch input devices
+ *
+ */
+static int mtdev_connect(struct input_handler *handler, struct input_dev *dev,
+ const struct input_device_id *id)
+{
+ struct mtdev_dev* mtdev;
+ struct task_struct * task=NULL;
+ int i=0;
+ int err=0;
+ printk("mtdev_connect\n");
+ mtdev=kzalloc(sizeof(struct mtdev_dev),GFP_KERNEL);
+ if(!mtdev)
+ return -ENOMEM;
+ mtdev->handle.dev=input_get_device(dev);
+ mtdev->handle.name="mtdev";
+ mtdev->handle.handler=handler;
+ mtdev->handle.private=mtdev;
+ mtdev->count=0;
+ mtdev->last_count=0;
+ init_waitqueue_head(&mtdev->wq);
+ for(;i<MTDEV_MAX_POINTERS;i++)
+ {
+ //we just store the data here, and will register it
+ //when the first event comes
+ struct input_dev *pdev=NULL;
+ mtdev->devs[i].ready=false;
+ mtdev->devs[i].id=-1;
+ mtdev->devs[i].touch=-1;
+ mtdev->devs[i].input_dev=input_allocate_device();
+ if(!mtdev->devs[i].input_dev)
+ return -ENOMEM;
+ pdev=mtdev->devs[i].input_dev;
+ memcpy(pdev->evbit,dev->evbit,sizeof(pdev->evbit));
+ memcpy(pdev->keybit,dev->keybit,sizeof(pdev->keybit));
+ memcpy(pdev->absbit,dev->absbit,sizeof(pdev->absbit));
+
+ memcpy(pdev->abs,dev->abs,sizeof(pdev->abs));
+ memcpy(pdev->absmax,dev->absmax,sizeof(pdev->absmax));
+ memcpy(pdev->absmin,dev->absmin,sizeof(pdev->absmin));
+
+ pdev->name="mtdev virtual input";
+ }
+
+ //create a thread to create the new input devices
+ //because there's a mutex,which may cause dead lock
+ task=kthread_run(mtdev_kt,mtdev,"mtdev thread");
+ if(!task)
+ printk("error !!!!\n");
+ else
+ printk("kthread created OK\n");
+
+
+ err=input_grab_device(&mtdev->handle);
+ if(err)
+ {
+ printk("error in grab device %d\n",err);
+ return err;
+ }
+ else
+ printk("successfully grab device \n");
+
+ wake_up_all(&mtdev->wq);
+ return 0;
+}
+
+static void mtdev_disconnect(struct input_handle *handle)
+{
+ printk("mtdev_disconnect\n");
+ input_release_device(handle);
+}
+
+static const struct input_device_id mtdev_ids[] = {
+ {
+ .flags=INPUT_DEVICE_ID_MATCH_VENDOR|INPUT_DEVICE_ID_MATCH_PRODUCT,
+ .vendor=0x1f87,
+ .product=0x0002,
+ },
+ {
+ .flags=INPUT_DEVICE_ID_MATCH_VENDOR|INPUT_DEVICE_ID_MATCH_PRODUCT,
+ .vendor=0x1f87,
+ .product=0x0001,
+ },
+ {
+ .flags=INPUT_DEVICE_ID_MATCH_VENDOR|INPUT_DEVICE_ID_MATCH_PRODUCT,
+ .vendor=0x0483,
+ .product=0x3261,
+ },
+ {
+ .flags=INPUT_DEVICE_ID_MATCH_VENDOR|INPUT_DEVICE_ID_MATCH_PRODUCT,
+ .vendor=0x2087,
+ .product=0x0a01,
+ },
+ {},
+};
+
+MODULE_DEVICE_TABLE(input,mtdev_ids);
+
+static struct input_handler mtdev_handler = {
+ .event = mtdev_event,
+ .connect = mtdev_connect,
+ .disconnect = mtdev_disconnect,
+ .name = "mtdev",
+ .id_table = mtdev_ids,
+};
+
+
+static int __init mtdev_init(void)
+{
+ return input_register_handler(&mtdev_handler);
+}
+
+static void __exit mtdev_exit(void)
+{
+ input_unregister_handler(&mtdev_handler);
+}
+
+module_init(mtdev_init);
+module_exit(mtdev_exit);
+
+MODULE_AUTHOR("He Min <min.he@intel.com>");
+MODULE_DESCRIPTION("Multi-touch input driver event devices");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/input.h b/include/linux/input.h
index 663208a..55bf8bc 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -662,6 +662,7 @@ struct input_absinfo {
#define ABS_MT_BLOB_ID 0x38 /* Group a set of packets as a blob */
#define ABS_MT_TRACKING_ID 0x39 /* Unique ID of initiated contact */
#define ABS_MT_PRESSURE 0x3a /* Pressure on contact area */
+#define ABS_MT_CONTACT_COUNT 0x3b /* Contact count */
#define ABS_MAX 0x3f
#define ABS_CNT (ABS_MAX+1)
--
1.6.2.2

View File

@ -0,0 +1,48 @@
>From 6f9df3bc6571d6545c552151f408d69265e15f92 Mon Sep 17 00:00:00 2001
From: Arjan van de Ven <arjan@linux.intel.com>
Date: Sun, 18 Apr 2010 10:25:19 -0700
Subject: [PATCH 1/7] sched: add a comment to get_cpu_idle_time_us()
Patch-mainline: in -mm tree as of 19 Apr 2010
The exported function get_cpu_idle_time_us() has no comment
describing it; add a kerneldoc comment
Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
---
kernel/time/tick-sched.c | 14 ++++++++++++++
1 files changed, 14 insertions(+), 0 deletions(-)
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index f992762..54dc155 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -179,6 +179,20 @@ static ktime_t tick_nohz_start_idle(struct tick_sched *ts)
return now;
}
+/**
+ * get_cpu_idle_time_us - get the total idle time of a cpu
+ * @cpu: CPU number to query
+ * @last_update_time: variable to store update time in
+ *
+ * Return the cummulative idle time (since boot) for a given
+ * CPU, in microseconds. The idle time returned includes
+ * the iowait time (unlike what "top" and co report).
+ *
+ * This time is measured via accounting rather than sampling,
+ * and is as accurate as ktime_get() is.
+ *
+ * This function returns -1 if NOHZ is not enabled.
+ */
u64 get_cpu_idle_time_us(int cpu, u64 *last_update_time)
{
struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu);
--
1.6.2.5
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

View File

@ -0,0 +1,78 @@
>From 166b7526ccfea8b44626b6023ff5b0a8eb869bb3 Mon Sep 17 00:00:00 2001
From: Arjan van de Ven <arjan@linux.intel.com>
Date: Sun, 18 Apr 2010 10:33:02 -0700
Subject: [PATCH 2/7] sched: introduce a function to update the idle statistics
Patch-mainline: in -mm tree as of 19 Apr 2010
Currently, two places update the idle statistics (and more to
come later in this series).
This patch creates a helper function for updating these statistics.
Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
---
kernel/time/tick-sched.c | 29 +++++++++++++++++++----------
1 files changed, 19 insertions(+), 10 deletions(-)
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index 54dc155..ca2211d 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -150,14 +150,25 @@ static void tick_nohz_update_jiffies(ktime_t now)
touch_softlockup_watchdog();
}
-static void tick_nohz_stop_idle(int cpu, ktime_t now)
+/*
+ * Updates the per cpu time idle statistics counters
+ */
+static void update_ts_time_stats(struct tick_sched *ts, ktime_t now)
{
- struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu);
ktime_t delta;
- delta = ktime_sub(now, ts->idle_entrytime);
ts->idle_lastupdate = now;
- ts->idle_sleeptime = ktime_add(ts->idle_sleeptime, delta);
+ if (ts->idle_active) {
+ delta = ktime_sub(now, ts->idle_entrytime);
+ ts->idle_sleeptime = ktime_add(ts->idle_sleeptime, delta);
+ }
+}
+
+static void tick_nohz_stop_idle(int cpu, ktime_t now)
+{
+ struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu);
+
+ update_ts_time_stats(ts, now);
ts->idle_active = 0;
sched_clock_idle_wakeup_event(0);
@@ -165,14 +176,12 @@ static void tick_nohz_stop_idle(int cpu, ktime_t now)
static ktime_t tick_nohz_start_idle(struct tick_sched *ts)
{
- ktime_t now, delta;
+ ktime_t now;
now = ktime_get();
- if (ts->idle_active) {
- delta = ktime_sub(now, ts->idle_entrytime);
- ts->idle_lastupdate = now;
- ts->idle_sleeptime = ktime_add(ts->idle_sleeptime, delta);
- }
+
+ update_ts_time_stats(ts, now);
+
ts->idle_entrytime = now;
ts->idle_active = 1;
sched_clock_idle_sleep_event();
--
1.6.2.5
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

View File

@ -0,0 +1,62 @@
>From 60851b131900af03bf013afef69f3bcdbb04f1d6 Mon Sep 17 00:00:00 2001
From: Arjan van de Ven <arjan@linux.intel.com>
Date: Sun, 18 Apr 2010 10:41:30 -0700
Subject: [PATCH 3/7] sched: update the idle statistics in get_cpu_idle_time_us()
Patch-mainline: in -mm tree as of 19 Apr 2010
Right now, get_cpu_idle_time_us() only reports the idle statistics
upto the point the CPU entered last idle; not what is valid right now.
This patch adds an update of the idle statistics to get_cpu_idle_time_us(),
so that calling this function always returns statistics that are accurate
at the point of the call.
This includes resetting the start of the idle time for accounting purposes
to avoid double accounting.
Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
---
kernel/time/tick-sched.c | 7 ++++++-
1 files changed, 6 insertions(+), 1 deletions(-)
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index ca2211d..7dbad2f 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -161,6 +161,7 @@ static void update_ts_time_stats(struct tick_sched *ts, ktime_t now)
if (ts->idle_active) {
delta = ktime_sub(now, ts->idle_entrytime);
ts->idle_sleeptime = ktime_add(ts->idle_sleeptime, delta);
+ ts->idle_entrytime = now;
}
}
@@ -205,14 +206,18 @@ static ktime_t tick_nohz_start_idle(struct tick_sched *ts)
u64 get_cpu_idle_time_us(int cpu, u64 *last_update_time)
{
struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu);
+ ktime_t now;
if (!tick_nohz_enabled)
return -1;
+ now = ktime_get();
+ update_ts_time_stats(ts, now);
+
if (ts->idle_active)
*last_update_time = ktime_to_us(ts->idle_lastupdate);
else
- *last_update_time = ktime_to_us(ktime_get());
+ *last_update_time = ktime_to_us(now);
return ktime_to_us(ts->idle_sleeptime);
}
--
1.6.2.5
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

View File

@ -0,0 +1,89 @@
>From e75d6cd203e43ea4c5e9919f19e2882c066491b8 Mon Sep 17 00:00:00 2001
From: Arjan van de Ven <arjan@linux.intel.com>
Date: Sun, 18 Apr 2010 10:47:02 -0700
Subject: [PATCH 4/7] sched: fold updating of the last update time into update_ts_time_stats()
Patch-mainline: in -mm tree as of 19 Apr 2010
This patch folds the updating of the last_update_time into the
update_ts_time_stats() function, and updates the callers.
This allows for further cleanups that are done in the next patch.
Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
---
kernel/time/tick-sched.c | 22 +++++++++++-----------
1 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index 7dbad2f..ac54543 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -153,7 +153,8 @@ static void tick_nohz_update_jiffies(ktime_t now)
/*
* Updates the per cpu time idle statistics counters
*/
-static void update_ts_time_stats(struct tick_sched *ts, ktime_t now)
+static void
+update_ts_time_stats(struct tick_sched *ts, ktime_t now, u64 *last_update_time)
{
ktime_t delta;
@@ -163,13 +164,19 @@ static void update_ts_time_stats(struct tick_sched *ts, ktime_t now)
ts->idle_sleeptime = ktime_add(ts->idle_sleeptime, delta);
ts->idle_entrytime = now;
}
+
+ if (ts->idle_active && last_update_time)
+ *last_update_time = ktime_to_us(ts->idle_lastupdate);
+ else
+ *last_update_time = ktime_to_us(now);
+
}
static void tick_nohz_stop_idle(int cpu, ktime_t now)
{
struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu);
- update_ts_time_stats(ts, now);
+ update_ts_time_stats(ts, now, NULL);
ts->idle_active = 0;
sched_clock_idle_wakeup_event(0);
@@ -181,7 +188,7 @@ static ktime_t tick_nohz_start_idle(struct tick_sched *ts)
now = ktime_get();
- update_ts_time_stats(ts, now);
+ update_ts_time_stats(ts, now, NULL);
ts->idle_entrytime = now;
ts->idle_active = 1;
@@ -206,18 +213,11 @@ static ktime_t tick_nohz_start_idle(struct tick_sched *ts)
u64 get_cpu_idle_time_us(int cpu, u64 *last_update_time)
{
struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu);
- ktime_t now;
if (!tick_nohz_enabled)
return -1;
- now = ktime_get();
- update_ts_time_stats(ts, now);
-
- if (ts->idle_active)
- *last_update_time = ktime_to_us(ts->idle_lastupdate);
- else
- *last_update_time = ktime_to_us(now);
+ update_ts_time_stats(ts, ktime_get(), last_update_time);
return ktime_to_us(ts->idle_sleeptime);
}
--
1.6.2.5
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

View File

@ -0,0 +1,63 @@
>From 526a9f347d5a953f37b67b4b2afb39d7b4d77a92 Mon Sep 17 00:00:00 2001
From: Arjan van de Ven <arjan@linux.intel.com>
Date: Sun, 18 Apr 2010 10:49:30 -0700
Subject: [PATCH 5/7] sched: eliminate the ts->idle_lastupdate field
Patch-mainline: in -mm tree as of 19 Apr 2010
Now that the only user of ts->idle_lastupdate is update_ts_time_stats(),
the entire field can be eliminated.
In update_ts_time_stats(), idle_lastupdate is first set to "now",
and a few lines later, the only user is an if() statement that
assigns a variable either to "now" or to ts->idle_lastupdate,
which has the value of "now" at that point.
Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
---
include/linux/tick.h | 1 -
kernel/time/tick-sched.c | 5 +----
2 files changed, 1 insertions(+), 5 deletions(-)
diff --git a/include/linux/tick.h b/include/linux/tick.h
index d2ae79e..0343eed 100644
--- a/include/linux/tick.h
+++ b/include/linux/tick.h
@@ -60,7 +60,6 @@ struct tick_sched {
ktime_t idle_waketime;
ktime_t idle_exittime;
ktime_t idle_sleeptime;
- ktime_t idle_lastupdate;
ktime_t sleep_length;
unsigned long last_jiffies;
unsigned long next_jiffies;
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index ac54543..326f5f8 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -158,16 +158,13 @@ update_ts_time_stats(struct tick_sched *ts, ktime_t now, u64 *last_update_time)
{
ktime_t delta;
- ts->idle_lastupdate = now;
if (ts->idle_active) {
delta = ktime_sub(now, ts->idle_entrytime);
ts->idle_sleeptime = ktime_add(ts->idle_sleeptime, delta);
ts->idle_entrytime = now;
}
- if (ts->idle_active && last_update_time)
- *last_update_time = ktime_to_us(ts->idle_lastupdate);
- else
+ if (last_update_time)
*last_update_time = ktime_to_us(now);
}
--
1.6.2.5
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

View File

@ -0,0 +1,122 @@
>From c4dd11703034f2ecbc3180603663fab14c292d7c Mon Sep 17 00:00:00 2001
From: Arjan van de Ven <arjan@linux.intel.com>
Date: Sun, 18 Apr 2010 10:57:43 -0700
Subject: [PATCH 6/7] sched: introduce get_cpu_iowait_time_us()
Patch-mainline: in -mm tree as of 19 Apr 2010
For the ondemand cpufreq governor, it is desired that the iowait
time is microaccounted in a similar way as idle time is.
This patch introduces the infrastructure to account and expose
this information via the get_cpu_iowait_time_us() function.
Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
---
include/linux/tick.h | 4 ++++
kernel/time/tick-sched.c | 28 ++++++++++++++++++++++++++++
kernel/time/timer_list.c | 1 +
3 files changed, 33 insertions(+), 0 deletions(-)
diff --git a/include/linux/tick.h b/include/linux/tick.h
index 0343eed..4aa3703 100644
--- a/include/linux/tick.h
+++ b/include/linux/tick.h
@@ -42,6 +42,7 @@ enum tick_nohz_mode {
* @idle_waketime: Time when the idle was interrupted
* @idle_exittime: Time when the idle state was left
* @idle_sleeptime: Sum of the time slept in idle with sched tick stopped
+ * @iowait_sleeptime: Sum of the time slept in idle with sched tick stopped, with IO outstanding
* @sleep_length: Duration of the current idle sleep
* @do_timer_lst: CPU was the last one doing do_timer before going idle
*/
@@ -60,6 +61,7 @@ struct tick_sched {
ktime_t idle_waketime;
ktime_t idle_exittime;
ktime_t idle_sleeptime;
+ ktime_t iowait_sleeptime;
ktime_t sleep_length;
unsigned long last_jiffies;
unsigned long next_jiffies;
@@ -123,6 +125,7 @@ extern void tick_nohz_stop_sched_tick(int inidle);
extern void tick_nohz_restart_sched_tick(void);
extern ktime_t tick_nohz_get_sleep_length(void);
extern u64 get_cpu_idle_time_us(int cpu, u64 *last_update_time);
+extern u64 get_cpu_iowait_time_us(int cpu, u64 *last_update_time);
# else
static inline void tick_nohz_stop_sched_tick(int inidle) { }
static inline void tick_nohz_restart_sched_tick(void) { }
@@ -133,6 +136,7 @@ static inline ktime_t tick_nohz_get_sleep_length(void)
return len;
}
static inline u64 get_cpu_idle_time_us(int cpu, u64 *unused) { return -1; }
+static inline u64 get_cpu_iowait(int cpu, u64 *unused) { return -1; }
# endif /* !NO_HZ */
#endif
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index 326f5f8..a6104a8 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -161,6 +161,8 @@ update_ts_time_stats(struct tick_sched *ts, ktime_t now, u64 *last_update_time)
if (ts->idle_active) {
delta = ktime_sub(now, ts->idle_entrytime);
ts->idle_sleeptime = ktime_add(ts->idle_sleeptime, delta);
+ if (nr_iowait_cpu() > 0)
+ ts->iowait_sleeptime = ktime_add(ts->iowait_sleeptime, delta);
ts->idle_entrytime = now;
}
@@ -220,6 +222,32 @@ u64 get_cpu_idle_time_us(int cpu, u64 *last_update_time)
}
EXPORT_SYMBOL_GPL(get_cpu_idle_time_us);
+/*
+ * get_cpu_iowait_time_us - get the total iowait time of a cpu
+ * @cpu: CPU number to query
+ * @last_update_time: variable to store update time in
+ *
+ * Return the cummulative iowait time (since boot) for a given
+ * CPU, in microseconds.
+ *
+ * This time is measured via accounting rather than sampling,
+ * and is as accurate as ktime_get() is.
+ *
+ * This function returns -1 if NOHZ is not enabled.
+ */
+u64 get_cpu_iowait_time_us(int cpu, u64 *last_update_time)
+{
+ struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu);
+
+ if (!tick_nohz_enabled)
+ return -1;
+
+ update_ts_time_stats(ts, ktime_get(), last_update_time);
+
+ return ktime_to_us(ts->iowait_sleeptime);
+}
+EXPORT_SYMBOL_GPL(get_cpu_iowait_time_us);
+
/**
* tick_nohz_stop_sched_tick - stop the idle tick from the idle task
*
diff --git a/kernel/time/timer_list.c b/kernel/time/timer_list.c
index 1a4a7dd..ab8f5e3 100644
--- a/kernel/time/timer_list.c
+++ b/kernel/time/timer_list.c
@@ -176,6 +176,7 @@ static void print_cpu(struct seq_file *m, int cpu, u64 now)
P_ns(idle_waketime);
P_ns(idle_exittime);
P_ns(idle_sleeptime);
+ P_ns(iowait_sleeptime);
P(last_jiffies);
P(next_jiffies);
P_ns(idle_expires);
--
1.6.2.5
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

View File

@ -0,0 +1,114 @@
>From 27966bedabea83c4f3ae77507eceb746b1f6ebae Mon Sep 17 00:00:00 2001
From: Arjan van de Ven <arjan@linux.intel.com>
Date: Sun, 18 Apr 2010 11:15:56 -0700
Subject: [PATCH 7/7] ondemand: Solve the big performance issue with ondemand during disk IO
Patch-mainline: in -mm tree as of 19 Apr 2010
The ondemand cpufreq governor uses CPU busy time (e.g. not-idle time) as
a measure for scaling the CPU frequency up or down.
If the CPU is busy, the CPU frequency scales up, if it's idle, the CPU
frequency scales down. Effectively, it uses the CPU busy time as proxy
variable for the more nebulous "how critical is performance right now"
question.
This algorithm falls flat on its face in the light of workloads where
you're alternatingly disk and CPU bound, such as the ever popular
"git grep", but also things like startup of programs and maildir using
email clients... much to the chagarin of Andrew Morton.
This patch changes the ondemand algorithm to count iowait time as busy,
not idle, time. As shown in the breakdown cases above, iowait is performance
critical often, and by counting iowait, the proxy variable becomes a more
accurate representation of the "how critical is performance" question.
The problem and fix are both verified with the "perf timechar" tool.
Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
---
drivers/cpufreq/cpufreq_ondemand.c | 30 ++++++++++++++++++++++++++++--
1 files changed, 28 insertions(+), 2 deletions(-)
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index bd444dc..ed472f8 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -73,6 +73,7 @@ enum {DBS_NORMAL_SAMPLE, DBS_SUB_SAMPLE};
struct cpu_dbs_info_s {
cputime64_t prev_cpu_idle;
+ cputime64_t prev_cpu_iowait;
cputime64_t prev_cpu_wall;
cputime64_t prev_cpu_nice;
struct cpufreq_policy *cur_policy;
@@ -148,6 +149,16 @@ static inline cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall)
return idle_time;
}
+static inline cputime64_t get_cpu_iowait_time(unsigned int cpu, cputime64_t *wall)
+{
+ u64 iowait_time = get_cpu_iowait_time_us(cpu, wall);
+
+ if (iowait_time == -1ULL)
+ return 0;
+
+ return iowait_time;
+}
+
/*
* Find right freq to be set now with powersave_bias on.
* Returns the freq_hi to be used right now and will set freq_hi_jiffies,
@@ -470,14 +481,15 @@ static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
for_each_cpu(j, policy->cpus) {
struct cpu_dbs_info_s *j_dbs_info;
- cputime64_t cur_wall_time, cur_idle_time;
- unsigned int idle_time, wall_time;
+ cputime64_t cur_wall_time, cur_idle_time, cur_iowait_time;
+ unsigned int idle_time, wall_time, iowait_time;
unsigned int load, load_freq;
int freq_avg;
j_dbs_info = &per_cpu(od_cpu_dbs_info, j);
cur_idle_time = get_cpu_idle_time(j, &cur_wall_time);
+ cur_iowait_time = get_cpu_iowait_time(j, &cur_wall_time);
wall_time = (unsigned int) cputime64_sub(cur_wall_time,
j_dbs_info->prev_cpu_wall);
@@ -487,6 +499,10 @@ static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
j_dbs_info->prev_cpu_idle);
j_dbs_info->prev_cpu_idle = cur_idle_time;
+ iowait_time = (unsigned int) cputime64_sub(cur_iowait_time,
+ j_dbs_info->prev_cpu_iowait);
+ j_dbs_info->prev_cpu_iowait = cur_iowait_time;
+
if (dbs_tuners_ins.ignore_nice) {
cputime64_t cur_nice;
unsigned long cur_nice_jiffies;
@@ -504,6 +520,16 @@ static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
idle_time += jiffies_to_usecs(cur_nice_jiffies);
}
+ /*
+ * For the purpose of ondemand, waiting for disk IO is an
+ * indication that you're performance critical, and not that
+ * the system is actually idle. So subtract the iowait time
+ * from the cpu idle time.
+ */
+
+ if (idle_time >= iowait_time)
+ idle_time -= iowait_time;
+
if (unlikely(!wall_time || wall_time < idle_time))
continue;
--
1.6.2.5
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,36 @@
diff --git a/drivers/staging/rt2860/rt_linux.c b/drivers/staging/rt2860/rt_linux.c
index 9357fb2..7e0b6c0 100644
--- a/drivers/staging/rt2860/rt_linux.c
+++ b/drivers/staging/rt2860/rt_linux.c
@@ -28,7 +28,7 @@
#include <linux/sched.h>
#include "rt_config.h"
-unsigned long RTDebugLevel = RT_DEBUG_ERROR;
+unsigned long RTDebugLevel = RT_DEBUG_OFF;
/* for wireless system event message */
char const *pWirelessSysEventText[IW_SYS_EVENT_TYPE_NUM] = {
diff --git a/drivers/staging/rt2860/rt_linux.h b/drivers/staging/rt2860/rt_linux.h
index f85508d..92ce551 100644
--- a/drivers/staging/rt2860/rt_linux.h
+++ b/drivers/staging/rt2860/rt_linux.h
@@ -425,16 +425,9 @@ do{ \
#define DBGPRINT(Level, Fmt) DBGPRINT_RAW(Level, Fmt)
-#define DBGPRINT_ERR(Fmt) \
-{ \
- printk("ERROR! "); \
- printk Fmt; \
-}
+#define DBGPRINT_ERR(Fmt)
-#define DBGPRINT_S(Status, Fmt) \
-{ \
- printk Fmt; \
-}
+#define DBGPRINT_S(Status, Fmt)
#else
#define DBGPRINT(Level, Fmt)

View File

@ -0,0 +1,714 @@
From f7e13f4d9a7a9025244b37a3ad188af7dae841d9 Mon Sep 17 00:00:00 2001
From: Stephane Chatty <chatty@enac.fr>
Date: Fri, 9 Apr 2010 15:33:54 -0700
Subject: [PATCH 105/105] Stantum and Mosart multitouch drivers
HID Driver and configs for Stantum and Mosart multitouch panels.
Patch-mainline: 2.6.34
Signed-off-by: Stephane Chatty <chatty@enac.fr>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Signed-off-by: Priya Vijayan <priya.vijayan@intel.com>
---
drivers/hid/Kconfig | 12 ++
drivers/hid/Makefile | 3 +-
drivers/hid/hid-core.c | 7 +-
drivers/hid/hid-ids.h | 15 ++-
drivers/hid/hid-mosart.c | 274 +++++++++++++++++++++++++++++++++++++++++++
drivers/hid/hid-stantum.c | 285 +++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 590 insertions(+), 6 deletions(-)
create mode 100644 drivers/hid/hid-mosart.c
create mode 100644 drivers/hid/hid-stantum.c
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 37fb241..55906bc 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -203,6 +203,12 @@ config HID_MONTEREY
---help---
Support for Monterey Genius KB29E.
+config HID_MOSART
+ tristate "MosArt"
+ depends on USB_HID
+ ---help---
+ Support for MosArt dual-touch panels.
+
config HID_NTRIG
tristate "NTrig" if EMBEDDED
depends on USB_HID
@@ -247,6 +253,12 @@ config HID_SONY
---help---
Support for Sony PS3 controller.
+config HID_STANTUM
+ tristate "Stantum"
+ depends on USB_HID
+ ---help---
+ Support for Stantum multitouch panel.
+
config HID_SUNPLUS
tristate "Sunplus" if EMBEDDED
depends on USB_HID
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index b05f921..bbda0b0 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -34,12 +34,14 @@ obj-$(CONFIG_HID_KYE) += hid-kye.o
obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o
obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o
obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o
+obj-$(CONFIG_HID_MOSART) += hid-mosart.o
obj-$(CONFIG_HID_NTRIG) += hid-ntrig.o
obj-$(CONFIG_HID_PANTHERLORD) += hid-pl.o
obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o
obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o
obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o
obj-$(CONFIG_HID_SONY) += hid-sony.o
+obj-$(CONFIG_HID_STANTUM) += hid-stantum.o
obj-$(CONFIG_HID_SUNPLUS) += hid-sunplus.o
obj-$(CONFIG_HID_GREENASIA) += hid-gaff.o
obj-$(CONFIG_HID_THRUSTMASTER) += hid-tmff.o
@@ -51,4 +53,3 @@ obj-$(CONFIG_HID_WACOM) += hid-wacom.o
obj-$(CONFIG_USB_HID) += usbhid/
obj-$(CONFIG_USB_MOUSE) += usbhid/
obj-$(CONFIG_USB_KBD) += usbhid/
-
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index b126102..fbf6f3e 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1342,6 +1342,9 @@ static const struct hid_device_id hid_blacklist[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, USB_DEVICE_ID_MTP) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM2, USB_DEVICE_ID_MTP2) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_STMICRO, USB_DEVICE_ID_STMICRO_MTP1) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) },
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) },
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) },
@@ -1544,8 +1546,9 @@ static const struct hid_device_id hid_ignore_list[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24) },
{ HID_USB_DEVICE(USB_VENDOR_ID_AIRCABLE, USB_DEVICE_ID_AIRCABLE1) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232) },
- { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM)},
- { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM2)},
+ { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_T91MT)},
+ { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM)},
+ { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM2)},
{ HID_USB_DEVICE(USB_VENDOR_ID_AVERMEDIA, USB_DEVICE_ID_AVER_FM_MR800) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CIDC, 0x0103) },
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 6865ca2..92c8a78 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -96,9 +96,12 @@
#define USB_DEVICE_ID_APPLE_ATV_IRCONTROL 0x8241
#define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242
-#define USB_VENDOR_ID_ASUS 0x0b05
-#define USB_DEVICE_ID_ASUS_LCM 0x1726
-#define USB_DEVICE_ID_ASUS_LCM2 0x175b
+#define USB_VENDOR_ID_ASUS 0x0486
+#define USB_DEVICE_ID_ASUS_T91MT 0x0185
+
+#define USB_VENDOR_ID_ASUSTEK 0x0b05
+#define USB_DEVICE_ID_ASUSTEK_LCM 0x1726
+#define USB_DEVICE_ID_ASUSTEK_LCM2 0x175b
#define USB_VENDOR_ID_ATEN 0x0557
#define USB_DEVICE_ID_ATEN_UC100KM 0x2004
@@ -399,6 +402,15 @@
#define USB_DEVICE_ID_SOUNDGRAPH_IMON_FIRST 0x0034
#define USB_DEVICE_ID_SOUNDGRAPH_IMON_LAST 0x0046
+#define USB_VENDOR_ID_STANTUM 0x1f87
+#define USB_DEVICE_ID_MTP 0x0002
+
+#define USB_VENDOR_ID_STANTUM2 0x1f87
+#define USB_DEVICE_ID_MTP2 0x0001
+
+#define USB_VENDOR_ID_STMICRO 0x0483
+#define USB_DEVICE_ID_STMICRO_MTP1 0x3261
+
#define USB_VENDOR_ID_SUN 0x0430
#define USB_DEVICE_ID_RARITAN_KVM_DONGLE 0xcdab
diff --git a/drivers/hid/hid-mosart.c b/drivers/hid/hid-mosart.c
new file mode 100644
index 0000000..e91437c
--- /dev/null
+++ b/drivers/hid/hid-mosart.c
@@ -0,0 +1,274 @@
+/*
+ * HID driver for the multitouch panel on the ASUS EeePC T91MT
+ *
+ * Copyright (c) 2009-2010 Stephane Chatty <chatty@enac.fr>
+ * Copyright (c) 2010 Teemu Tuominen <teemu.tuominen@cybercom.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/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include "usbhid/usbhid.h"
+
+MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
+MODULE_DESCRIPTION("MosArt dual-touch panel");
+MODULE_LICENSE("GPL");
+
+#include "hid-ids.h"
+
+struct mosart_data {
+ __u16 x, y;
+ __u8 id;
+ bool valid; /* valid finger data, or just placeholder? */
+ bool first; /* is this the first finger in this frame? */
+ bool activity_now; /* at least one active finger in this frame? */
+ bool activity; /* at least one active finger previously? */
+};
+
+static int mosart_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ switch (usage->hid & HID_USAGE_PAGE) {
+
+ case HID_UP_GENDESK:
+ switch (usage->hid) {
+ case HID_GD_X:
+ hid_map_usage(hi, usage, bit, max,
+ EV_ABS, ABS_MT_POSITION_X);
+ /* touchscreen emulation */
+ input_set_abs_params(hi->input, ABS_X,
+ field->logical_minimum,
+ field->logical_maximum, 0, 0);
+ return 1;
+ case HID_GD_Y:
+ hid_map_usage(hi, usage, bit, max,
+ EV_ABS, ABS_MT_POSITION_Y);
+ /* touchscreen emulation */
+ input_set_abs_params(hi->input, ABS_Y,
+ field->logical_minimum,
+ field->logical_maximum, 0, 0);
+ return 1;
+ }
+ return 0;
+
+ case HID_UP_DIGITIZER:
+ switch (usage->hid) {
+ case HID_DG_CONFIDENCE:
+ case HID_DG_TIPSWITCH:
+ case HID_DG_INPUTMODE:
+ case HID_DG_DEVICEINDEX:
+ case HID_DG_CONTACTCOUNT:
+ case HID_DG_CONTACTMAX:
+ case HID_DG_TIPPRESSURE:
+ case HID_DG_WIDTH:
+ case HID_DG_HEIGHT:
+ return -1;
+ case HID_DG_INRANGE:
+ /* touchscreen emulation */
+ hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
+ return 1;
+
+ case HID_DG_CONTACTID:
+ hid_map_usage(hi, usage, bit, max,
+ EV_ABS, ABS_MT_TRACKING_ID);
+ return 1;
+
+ }
+ return 0;
+
+ case 0xff000000:
+ /* ignore HID features */
+ return -1;
+ }
+
+ return 0;
+}
+
+static int mosart_input_mapped(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ if (usage->type == EV_KEY || usage->type == EV_ABS)
+ clear_bit(usage->code, *bit);
+
+ return 0;
+}
+
+/*
+ * this function is called when a whole finger has been parsed,
+ * so that it can decide what to send to the input layer.
+ */
+static void mosart_filter_event(struct mosart_data *td, struct input_dev *input)
+{
+ td->first = !td->first; /* touchscreen emulation */
+
+ if (!td->valid) {
+ /*
+ * touchscreen emulation: if no finger in this frame is valid
+ * and there previously was finger activity, this is a release
+ */
+ if (!td->first && !td->activity_now && td->activity) {
+ input_event(input, EV_KEY, BTN_TOUCH, 0);
+ td->activity = false;
+ }
+ return;
+ }
+
+ input_event(input, EV_ABS, ABS_MT_TRACKING_ID, td->id);
+ input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x);
+ input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y);
+
+ input_mt_sync(input);
+ td->valid = false;
+
+ /* touchscreen emulation: if first active finger in this frame... */
+ if (!td->activity_now) {
+ /* if there was no previous activity, emit touch event */
+ if (!td->activity) {
+ input_event(input, EV_KEY, BTN_TOUCH, 1);
+ td->activity = true;
+ }
+ td->activity_now = true;
+ /* and in any case this is our preferred finger */
+ input_event(input, EV_ABS, ABS_X, td->x);
+ input_event(input, EV_ABS, ABS_Y, td->y);
+ }
+}
+
+
+static int mosart_event(struct hid_device *hid, struct hid_field *field,
+ struct hid_usage *usage, __s32 value)
+{
+ struct mosart_data *td = hid_get_drvdata(hid);
+
+ if (hid->claimed & HID_CLAIMED_INPUT) {
+ struct input_dev *input = field->hidinput->input;
+ switch (usage->hid) {
+ case HID_DG_INRANGE:
+ td->valid = !!value;
+ break;
+ case HID_GD_X:
+ td->x = value;
+ break;
+ case HID_GD_Y:
+ td->y = value;
+ mosart_filter_event(td, input);
+ break;
+ case HID_DG_CONTACTID:
+ td->id = value;
+ break;
+ case HID_DG_CONTACTCOUNT:
+ /* touch emulation: this is the last field in a frame */
+ td->first = false;
+ td->activity_now = false;
+ break;
+ case HID_DG_CONFIDENCE:
+ case HID_DG_TIPSWITCH:
+ /* avoid interference from generic hidinput handling */
+ break;
+
+ default:
+ /* fallback to the generic hidinput handling */
+ return 0;
+ }
+ }
+
+ /* we have handled the hidinput part, now remains hiddev */
+ if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
+ hid->hiddev_hid_event(hid, field, usage, value);
+
+ return 1;
+}
+
+static int mosart_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+ int ret;
+ struct mosart_data *td;
+
+
+ td = kmalloc(sizeof(struct mosart_data), GFP_KERNEL);
+ if (!td) {
+ dev_err(&hdev->dev, "cannot allocate MosArt data\n");
+ return -ENOMEM;
+ }
+ td->valid = false;
+ td->activity = false;
+ td->activity_now = false;
+ td->first = false;
+ hid_set_drvdata(hdev, td);
+
+ /* currently, it's better to have one evdev device only */
+#if 0
+ hdev->quirks |= HID_QUIRK_MULTI_INPUT;
+#endif
+
+ ret = hid_parse(hdev);
+ if (ret == 0)
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+
+ if (ret == 0) {
+ struct hid_report_enum *re = hdev->report_enum
+ + HID_FEATURE_REPORT;
+ struct hid_report *r = re->report_id_hash[7];
+
+ r->field[0]->value[0] = 0x02;
+ usbhid_submit_report(hdev, r, USB_DIR_OUT);
+ } else
+ kfree(td);
+
+ return ret;
+}
+
+static void mosart_remove(struct hid_device *hdev)
+{
+ hid_hw_stop(hdev);
+ kfree(hid_get_drvdata(hdev));
+ hid_set_drvdata(hdev, NULL);
+}
+
+static const struct hid_device_id mosart_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_T91MT) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, mosart_devices);
+
+static const struct hid_usage_id mosart_grabbed_usages[] = {
+ { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
+ { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
+};
+
+static struct hid_driver mosart_driver = {
+ .name = "mosart",
+ .id_table = mosart_devices,
+ .probe = mosart_probe,
+ .remove = mosart_remove,
+ .input_mapping = mosart_input_mapping,
+ .input_mapped = mosart_input_mapped,
+ .usage_table = mosart_grabbed_usages,
+ .event = mosart_event,
+};
+
+static int __init mosart_init(void)
+{
+ return hid_register_driver(&mosart_driver);
+}
+
+static void __exit mosart_exit(void)
+{
+ hid_unregister_driver(&mosart_driver);
+}
+
+module_init(mosart_init);
+module_exit(mosart_exit);
+
diff --git a/drivers/hid/hid-stantum.c b/drivers/hid/hid-stantum.c
new file mode 100644
index 0000000..bb4430f
--- /dev/null
+++ b/drivers/hid/hid-stantum.c
@@ -0,0 +1,286 @@
+/*
+ * HID driver for Stantum multitouch panels
+ *
+ * Copyright (c) 2009 Stephane Chatty <chatty@enac.fr>
+ *
+ */
+
+/*
+ * 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/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
+MODULE_DESCRIPTION("Stantum HID multitouch panels");
+MODULE_LICENSE("GPL");
+
+#include "hid-ids.h"
+
+struct stantum_data {
+ __s32 x, y, z, w, h; /* x, y, pressure, width, height */
+ __u16 id; /* touch id */
+ bool valid; /* valid finger data, or just placeholder? */
+ bool first; /* first finger in the HID packet? */
+ bool activity; /* at least one active finger so far? */
+};
+
+static int stantum_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ switch (usage->hid & HID_USAGE_PAGE) {
+
+ case HID_UP_GENDESK:
+ switch (usage->hid) {
+ case HID_GD_X:
+ hid_map_usage(hi, usage, bit, max,
+ EV_ABS, ABS_MT_POSITION_X);
+ /* touchscreen emulation */
+ input_set_abs_params(hi->input, ABS_X,
+ field->logical_minimum,
+ field->logical_maximum, 0, 0);
+ return 1;
+ case HID_GD_Y:
+ hid_map_usage(hi, usage, bit, max,
+ EV_ABS, ABS_MT_POSITION_Y);
+ /* touchscreen emulation */
+ input_set_abs_params(hi->input, ABS_Y,
+ field->logical_minimum,
+ field->logical_maximum, 0, 0);
+ return 1;
+ }
+ return 0;
+
+ case HID_UP_DIGITIZER:
+ switch (usage->hid) {
+ case HID_DG_INRANGE:
+ case HID_DG_CONFIDENCE:
+ case HID_DG_INPUTMODE:
+ case HID_DG_DEVICEINDEX:
+ case HID_DG_CONTACTCOUNT:
+ case HID_DG_CONTACTMAX:
+ return -1;
+
+ case HID_DG_TIPSWITCH:
+ /* touchscreen emulation */
+ hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
+ return 1;
+
+ case HID_DG_WIDTH:
+ hid_map_usage(hi, usage, bit, max,
+ EV_ABS, ABS_MT_TOUCH_MAJOR);
+ return 1;
+ case HID_DG_HEIGHT:
+ hid_map_usage(hi, usage, bit, max,
+ EV_ABS, ABS_MT_TOUCH_MINOR);
+ input_set_abs_params(hi->input, ABS_MT_ORIENTATION,
+ 1, 1, 0, 0);
+ return 1;
+ case HID_DG_TIPPRESSURE:
+ hid_map_usage(hi, usage, bit, max,
+ EV_ABS, ABS_MT_PRESSURE);
+ return 1;
+
+ case HID_DG_CONTACTID:
+ hid_map_usage(hi, usage, bit, max,
+ EV_ABS, ABS_MT_TRACKING_ID);
+ return 1;
+
+ }
+ return 0;
+
+ case 0xff000000:
+ /* no input-oriented meaning */
+ return -1;
+ }
+
+ return 0;
+}
+
+static int stantum_input_mapped(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ if (usage->type == EV_KEY || usage->type == EV_ABS)
+ clear_bit(usage->code, *bit);
+
+ return 0;
+}
+
+/*
+ * this function is called when a whole finger has been parsed,
+ * so that it can decide what to send to the input layer.
+ */
+static void stantum_filter_event(struct stantum_data *sd,
+ struct input_dev *input)
+{
+ bool wide;
+
+ if (!sd->valid) {
+ /*
+ * touchscreen emulation: if the first finger is not valid and
+ * there previously was finger activity, this is a release
+ */
+ if (sd->first && sd->activity) {
+ input_event(input, EV_KEY, BTN_TOUCH, 0);
+ sd->activity = false;
+ }
+ return;
+ }
+
+ input_event(input, EV_ABS, ABS_MT_TRACKING_ID, sd->id);
+ input_event(input, EV_ABS, ABS_MT_POSITION_X, sd->x);
+ input_event(input, EV_ABS, ABS_MT_POSITION_Y, sd->y);
+
+ wide = (sd->w > sd->h);
+ input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide);
+ input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, wide ? sd->w : sd->h);
+ input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, wide ? sd->h : sd->w);
+
+ input_event(input, EV_ABS, ABS_MT_PRESSURE, sd->z);
+
+ input_mt_sync(input);
+ sd->valid = false;
+
+ /* touchscreen emulation */
+ if (sd->first) {
+ if (!sd->activity) {
+ input_event(input, EV_KEY, BTN_TOUCH, 1);
+ sd->activity = true;
+ }
+ input_event(input, EV_ABS, ABS_X, sd->x);
+ input_event(input, EV_ABS, ABS_Y, sd->y);
+ }
+ sd->first = false;
+}
+
+
+static int stantum_event(struct hid_device *hid, struct hid_field *field,
+ struct hid_usage *usage, __s32 value)
+{
+ struct stantum_data *sd = hid_get_drvdata(hid);
+
+ if (hid->claimed & HID_CLAIMED_INPUT) {
+ struct input_dev *input = field->hidinput->input;
+
+ switch (usage->hid) {
+ case HID_DG_INRANGE:
+ /* this is the last field in a finger */
+ stantum_filter_event(sd, input);
+ break;
+ case HID_DG_WIDTH:
+ sd->w = value;
+ break;
+ case HID_DG_HEIGHT:
+ sd->h = value;
+ break;
+ case HID_GD_X:
+ sd->x = value;
+ break;
+ case HID_GD_Y:
+ sd->y = value;
+ break;
+ case HID_DG_TIPPRESSURE:
+ sd->z = value;
+ break;
+ case HID_DG_CONTACTID:
+ sd->id = value;
+ break;
+ case HID_DG_CONFIDENCE:
+ sd->valid = !!value;
+ break;
+ case 0xff000002:
+ /* this comes only before the first finger */
+ sd->first = true;
+ break;
+
+ default:
+ /* ignore the others */
+ return 1;
+ }
+ }
+
+ /* we have handled the hidinput part, now remains hiddev */
+ if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
+ hid->hiddev_hid_event(hid, field, usage, value);
+
+ return 1;
+}
+
+static int stantum_probe(struct hid_device *hdev,
+ const struct hid_device_id *id)
+{
+ int ret;
+ struct stantum_data *sd;
+
+ sd = kmalloc(sizeof(struct stantum_data), GFP_KERNEL);
+ if (!sd) {
+ dev_err(&hdev->dev, "cannot allocate Stantum data\n");
+ return -ENOMEM;
+ }
+ sd->valid = false;
+ sd->first = false;
+ sd->activity = false;
+ hid_set_drvdata(hdev, sd);
+
+ ret = hid_parse(hdev);
+ if (!ret)
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+
+ if (ret)
+ kfree(sd);
+
+ return ret;
+}
+
+static void stantum_remove(struct hid_device *hdev)
+{
+ hid_hw_stop(hdev);
+ kfree(hid_get_drvdata(hdev));
+ hid_set_drvdata(hdev, NULL);
+}
+
+static const struct hid_device_id stantum_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, USB_DEVICE_ID_MTP) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM2, USB_DEVICE_ID_MTP2) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_STMICRO, USB_DEVICE_ID_STMICRO_MTP1) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, stantum_devices);
+
+static const struct hid_usage_id stantum_grabbed_usages[] = {
+ { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
+ { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
+};
+
+static struct hid_driver stantum_driver = {
+ .name = "stantum",
+ .id_table = stantum_devices,
+ .probe = stantum_probe,
+ .remove = stantum_remove,
+ .input_mapping = stantum_input_mapping,
+ .input_mapped = stantum_input_mapped,
+ .usage_table = stantum_grabbed_usages,
+ .event = stantum_event,
+};
+
+static int __init stantum_init(void)
+{
+ return hid_register_driver(&stantum_driver);
+}
+
+static void __exit stantum_exit(void)
+{
+ hid_unregister_driver(&stantum_driver);
+}
+
+module_init(stantum_init);
+module_exit(stantum_exit);
+
--
1.6.2.2

View File

@ -0,0 +1,813 @@
From 635f44cfde6c057a2ecbb8c9d9a67225e53b6545 Mon Sep 17 00:00:00 2001
From: Roger Quadros <roger.quadros@nokia.com>
Date: Wed, 10 Mar 2010 17:32:44 +0200
Subject: [PATCH 3/10] OMAP: DSS2: Add ACX565AKM Panel Driver
From: Roger Quadros <roger.quadros@nokia.com>
Patch-mainline: 2.6.35?
Git-repo: http://www.gitorious.org/linux-omap-dss2/linux/commit/4f2308f3be2fe631412ea85a80c91414c3bfe730
This is the panel used on Nokia N900
Signed-off-by: Roger Quadros <roger.quadros@nokia.com>
---
drivers/video/omap2/displays/Kconfig | 6 +
drivers/video/omap2/displays/Makefile | 1 +
drivers/video/omap2/displays/panel-acx565akm.c | 760 ++++++++++++++++++++++++
3 files changed, 767 insertions(+), 0 deletions(-)
create mode 100644 drivers/video/omap2/displays/panel-acx565akm.c
diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig
index b12a59c..1f5b7d1 100644
--- a/drivers/video/omap2/displays/Kconfig
+++ b/drivers/video/omap2/displays/Kconfig
@@ -19,4 +19,10 @@ config PANEL_TAAL
help
Taal DSI command mode panel from TPO.
+config PANEL_ACX565AKM
+ tristate "ACX565AKM Panel"
+ depends on OMAP2_DSS_SDI
+ select BACKLIGHT_CLASS_DEVICE
+ help
+ This is the LCD panel used on Nokia N900
endmenu
diff --git a/drivers/video/omap2/displays/Makefile b/drivers/video/omap2/displays/Makefile
index 9556464..0af16b7 100644
--- a/drivers/video/omap2/displays/Makefile
+++ b/drivers/video/omap2/displays/Makefile
@@ -2,3 +2,4 @@ obj-$(CONFIG_PANEL_GENERIC) += panel-generic.o
obj-$(CONFIG_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o
obj-$(CONFIG_PANEL_TAAL) += panel-taal.o
+obj-$(CONFIG_PANEL_ACX565AKM) += panel-acx565akm.o
diff --git a/drivers/video/omap2/displays/panel-acx565akm.c b/drivers/video/omap2/displays/panel-acx565akm.c
new file mode 100644
index 0000000..27e9847
--- /dev/null
+++ b/drivers/video/omap2/displays/panel-acx565akm.c
@@ -0,0 +1,760 @@
+/*
+ * Support for ACX565AKM LCD Panel used on Nokia N900
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Original Driver Author: Imre Deak <imre.deak@nokia.com>
+ * Based on panel-generic.c by Tomi Valkeinen <tomi.valkeinen@nokia.com>
+ * Adapted to new DSS2 framework: Roger Quadros <roger.quadros@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/spi/spi.h>
+#include <linux/jiffies.h>
+#include <linux/sched.h>
+#include <linux/backlight.h>
+#include <linux/fb.h>
+
+#include <plat/display.h>
+
+#define MIPID_CMD_READ_DISP_ID 0x04
+#define MIPID_CMD_READ_RED 0x06
+#define MIPID_CMD_READ_GREEN 0x07
+#define MIPID_CMD_READ_BLUE 0x08
+#define MIPID_CMD_READ_DISP_STATUS 0x09
+#define MIPID_CMD_RDDSDR 0x0F
+#define MIPID_CMD_SLEEP_IN 0x10
+#define MIPID_CMD_SLEEP_OUT 0x11
+#define MIPID_CMD_DISP_OFF 0x28
+#define MIPID_CMD_DISP_ON 0x29
+#define MIPID_CMD_WRITE_DISP_BRIGHTNESS 0x51
+#define MIPID_CMD_READ_DISP_BRIGHTNESS 0x52
+#define MIPID_CMD_WRITE_CTRL_DISP 0x53
+
+#define CTRL_DISP_BRIGHTNESS_CTRL_ON (1 << 5)
+#define CTRL_DISP_AMBIENT_LIGHT_CTRL_ON (1 << 4)
+#define CTRL_DISP_BACKLIGHT_ON (1 << 2)
+#define CTRL_DISP_AUTO_BRIGHTNESS_ON (1 << 1)
+
+#define MIPID_CMD_READ_CTRL_DISP 0x54
+#define MIPID_CMD_WRITE_CABC 0x55
+#define MIPID_CMD_READ_CABC 0x56
+
+#define MIPID_VER_LPH8923 3
+#define MIPID_VER_LS041Y3 4
+#define MIPID_VER_L4F00311 8
+#define MIPID_VER_ACX565AKM 9
+
+struct acx565akm_device {
+ char *name;
+ int enabled;
+ int model;
+ int revision;
+ u8 display_id[3];
+ unsigned has_bc:1;
+ unsigned has_cabc:1;
+ unsigned cabc_mode;
+ unsigned long hw_guard_end; /* next value of jiffies
+ when we can issue the
+ next sleep in/out command */
+ unsigned long hw_guard_wait; /* max guard time in jiffies */
+
+ struct spi_device *spi;
+ struct mutex mutex;
+
+ struct omap_dss_device *dssdev;
+ struct backlight_device *bl_dev;
+};
+
+static struct acx565akm_device acx_dev;
+static int acx565akm_bl_update_status(struct backlight_device *dev);
+
+/*--------------------MIPID interface-----------------------------*/
+
+static void acx565akm_transfer(struct acx565akm_device *md, int cmd,
+ const u8 *wbuf, int wlen, u8 *rbuf, int rlen)
+{
+ struct spi_message m;
+ struct spi_transfer *x, xfer[5];
+ int r;
+
+ BUG_ON(md->spi == NULL);
+
+ spi_message_init(&m);
+
+ memset(xfer, 0, sizeof(xfer));
+ x = &xfer[0];
+
+ cmd &= 0xff;
+ x->tx_buf = &cmd;
+ x->bits_per_word = 9;
+ x->len = 2;
+
+ if (rlen > 1 && wlen == 0) {
+ /*
+ * Between the command and the response data there is a
+ * dummy clock cycle. Add an extra bit after the command
+ * word to account for this.
+ */
+ x->bits_per_word = 10;
+ cmd <<= 1;
+ }
+ spi_message_add_tail(x, &m);
+
+ if (wlen) {
+ x++;
+ x->tx_buf = wbuf;
+ x->len = wlen;
+ x->bits_per_word = 9;
+ spi_message_add_tail(x, &m);
+ }
+
+ if (rlen) {
+ x++;
+ x->rx_buf = rbuf;
+ x->len = rlen;
+ spi_message_add_tail(x, &m);
+ }
+
+ r = spi_sync(md->spi, &m);
+ if (r < 0)
+ dev_dbg(&md->spi->dev, "spi_sync %d\n", r);
+}
+
+static inline void acx565akm_cmd(struct acx565akm_device *md, int cmd)
+{
+ acx565akm_transfer(md, cmd, NULL, 0, NULL, 0);
+}
+
+static inline void acx565akm_write(struct acx565akm_device *md,
+ int reg, const u8 *buf, int len)
+{
+ acx565akm_transfer(md, reg, buf, len, NULL, 0);
+}
+
+static inline void acx565akm_read(struct acx565akm_device *md,
+ int reg, u8 *buf, int len)
+{
+ acx565akm_transfer(md, reg, NULL, 0, buf, len);
+}
+
+static void hw_guard_start(struct acx565akm_device *md, int guard_msec)
+{
+ md->hw_guard_wait = msecs_to_jiffies(guard_msec);
+ md->hw_guard_end = jiffies + md->hw_guard_wait;
+}
+
+static void hw_guard_wait(struct acx565akm_device *md)
+{
+ unsigned long wait = md->hw_guard_end - jiffies;
+
+ if ((long)wait > 0 && wait <= md->hw_guard_wait) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(wait);
+ }
+}
+
+/*----------------------MIPID wrappers----------------------------*/
+
+static void set_sleep_mode(struct acx565akm_device *md, int on)
+{
+ int cmd;
+
+ if (on)
+ cmd = MIPID_CMD_SLEEP_IN;
+ else
+ cmd = MIPID_CMD_SLEEP_OUT;
+ /*
+ * We have to keep 120msec between sleep in/out commands.
+ * (8.2.15, 8.2.16).
+ */
+ hw_guard_wait(md);
+ acx565akm_cmd(md, cmd);
+ hw_guard_start(md, 120);
+}
+
+static void set_display_state(struct acx565akm_device *md, int enabled)
+{
+ int cmd = enabled ? MIPID_CMD_DISP_ON : MIPID_CMD_DISP_OFF;
+
+ acx565akm_cmd(md, cmd);
+}
+
+static int panel_enabled(struct acx565akm_device *md)
+{
+ u32 disp_status;
+ int enabled;
+
+ acx565akm_read(md, MIPID_CMD_READ_DISP_STATUS, (u8 *)&disp_status, 4);
+ disp_status = __be32_to_cpu(disp_status);
+ enabled = (disp_status & (1 << 17)) && (disp_status & (1 << 10));
+ dev_dbg(&md->spi->dev,
+ "LCD panel %senabled by bootloader (status 0x%04x)\n",
+ enabled ? "" : "not ", disp_status);
+ return enabled;
+}
+
+static int panel_detect(struct acx565akm_device *md)
+{
+ acx565akm_read(md, MIPID_CMD_READ_DISP_ID, md->display_id, 3);
+ dev_dbg(&md->spi->dev, "MIPI display ID: %02x%02x%02x\n",
+ md->display_id[0], md->display_id[1], md->display_id[2]);
+
+ switch (md->display_id[0]) {
+ case 0x10:
+ md->model = MIPID_VER_ACX565AKM;
+ md->name = "acx565akm";
+ md->has_bc = 1;
+ md->has_cabc = 1;
+ break;
+ case 0x29:
+ md->model = MIPID_VER_L4F00311;
+ md->name = "l4f00311";
+ break;
+ case 0x45:
+ md->model = MIPID_VER_LPH8923;
+ md->name = "lph8923";
+ break;
+ case 0x83:
+ md->model = MIPID_VER_LS041Y3;
+ md->name = "ls041y3";
+ break;
+ default:
+ md->name = "unknown";
+ dev_err(&md->spi->dev, "invalid display ID\n");
+ return -ENODEV;
+ }
+
+ md->revision = md->display_id[1];
+
+ dev_info(&md->spi->dev, "omapfb: %s rev %02x LCD detected\n",
+ md->name, md->revision);
+
+ return 0;
+}
+
+/*----------------------Backlight Control-------------------------*/
+
+static void enable_backlight_ctrl(struct acx565akm_device *md, int enable)
+{
+ u16 ctrl;
+
+ acx565akm_read(md, MIPID_CMD_READ_CTRL_DISP, (u8 *)&ctrl, 1);
+ if (enable) {
+ ctrl |= CTRL_DISP_BRIGHTNESS_CTRL_ON |
+ CTRL_DISP_BACKLIGHT_ON;
+ } else {
+ ctrl &= ~(CTRL_DISP_BRIGHTNESS_CTRL_ON |
+ CTRL_DISP_BACKLIGHT_ON);
+ }
+
+ ctrl |= 1 << 8;
+ acx565akm_write(md, MIPID_CMD_WRITE_CTRL_DISP, (u8 *)&ctrl, 2);
+}
+
+static void set_cabc_mode(struct acx565akm_device *md, unsigned mode)
+{
+ u16 cabc_ctrl;
+
+ md->cabc_mode = mode;
+ if (!md->enabled)
+ return;
+ cabc_ctrl = 0;
+ acx565akm_read(md, MIPID_CMD_READ_CABC, (u8 *)&cabc_ctrl, 1);
+ cabc_ctrl &= ~3;
+ cabc_ctrl |= (1 << 8) | (mode & 3);
+ acx565akm_write(md, MIPID_CMD_WRITE_CABC, (u8 *)&cabc_ctrl, 2);
+}
+
+static unsigned get_cabc_mode(struct acx565akm_device *md)
+{
+ return md->cabc_mode;
+}
+
+static unsigned get_hw_cabc_mode(struct acx565akm_device *md)
+{
+ u8 cabc_ctrl;
+
+ acx565akm_read(md, MIPID_CMD_READ_CABC, &cabc_ctrl, 1);
+ return cabc_ctrl & 3;
+}
+
+static void acx565akm_set_brightness(struct acx565akm_device *md, int level)
+{
+ int bv;
+
+ bv = level | (1 << 8);
+ acx565akm_write(md, MIPID_CMD_WRITE_DISP_BRIGHTNESS, (u8 *)&bv, 2);
+
+ if (level)
+ enable_backlight_ctrl(md, 1);
+ else
+ enable_backlight_ctrl(md, 0);
+}
+
+static int acx565akm_get_actual_brightness(struct acx565akm_device *md)
+{
+ u8 bv;
+
+ acx565akm_read(md, MIPID_CMD_READ_DISP_BRIGHTNESS, &bv, 1);
+
+ return bv;
+}
+
+
+static int acx565akm_bl_update_status(struct backlight_device *dev)
+{
+ struct acx565akm_device *md = dev_get_drvdata(&dev->dev);
+ int r;
+ int level;
+
+ dev_dbg(&md->spi->dev, "%s\n", __func__);
+
+ mutex_lock(&md->mutex);
+
+ if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
+ dev->props.power == FB_BLANK_UNBLANK)
+ level = dev->props.brightness;
+ else
+ level = 0;
+
+ r = 0;
+ if (md->has_bc)
+ acx565akm_set_brightness(md, level);
+ else if (md->dssdev->set_backlight)
+ r = md->dssdev->set_backlight(md->dssdev, level);
+ else
+ r = -ENODEV;
+
+ mutex_unlock(&md->mutex);
+
+ return r;
+}
+
+static int acx565akm_bl_get_intensity(struct backlight_device *dev)
+{
+ struct acx565akm_device *md = dev_get_drvdata(&dev->dev);
+
+ dev_dbg(&dev->dev, "%s\n", __func__);
+
+ if (!md->has_bc && md->dssdev->set_backlight == NULL)
+ return -ENODEV;
+
+ if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
+ dev->props.power == FB_BLANK_UNBLANK) {
+ if (md->has_bc)
+ return acx565akm_get_actual_brightness(md);
+ else
+ return dev->props.brightness;
+ }
+
+ return 0;
+}
+
+static struct backlight_ops acx565akm_bl_ops = {
+ .get_brightness = acx565akm_bl_get_intensity,
+ .update_status = acx565akm_bl_update_status,
+};
+
+/*--------------------Auto Brightness control via Sysfs---------------------*/
+
+static const char *cabc_modes[] = {
+ "off", /* always used when CABC is not supported */
+ "ui",
+ "still-image",
+ "moving-image",
+};
+
+static ssize_t show_cabc_mode(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct acx565akm_device *md = dev_get_drvdata(dev);
+ const char *mode_str;
+ int mode;
+ int len;
+
+ if (!md->has_cabc)
+ mode = 0;
+ else
+ mode = get_cabc_mode(md);
+ mode_str = "unknown";
+ if (mode >= 0 && mode < ARRAY_SIZE(cabc_modes))
+ mode_str = cabc_modes[mode];
+ len = snprintf(buf, PAGE_SIZE, "%s\n", mode_str);
+
+ return len < PAGE_SIZE - 1 ? len : PAGE_SIZE - 1;
+}
+
+static ssize_t store_cabc_mode(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct acx565akm_device *md = dev_get_drvdata(dev);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(cabc_modes); i++) {
+ const char *mode_str = cabc_modes[i];
+ int cmp_len = strlen(mode_str);
+
+ if (count > 0 && buf[count - 1] == '\n')
+ count--;
+ if (count != cmp_len)
+ continue;
+
+ if (strncmp(buf, mode_str, cmp_len) == 0)
+ break;
+ }
+
+ if (i == ARRAY_SIZE(cabc_modes))
+ return -EINVAL;
+
+ if (!md->has_cabc && i != 0)
+ return -EINVAL;
+
+ mutex_lock(&md->mutex);
+ set_cabc_mode(md, i);
+ mutex_unlock(&md->mutex);
+
+ return count;
+}
+
+static ssize_t show_cabc_available_modes(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct acx565akm_device *md = dev_get_drvdata(dev);
+ int len;
+ int i;
+
+ if (!md->has_cabc)
+ return snprintf(buf, PAGE_SIZE, "%s\n", cabc_modes[0]);
+
+ for (i = 0, len = 0;
+ len < PAGE_SIZE && i < ARRAY_SIZE(cabc_modes); i++)
+ len += snprintf(&buf[len], PAGE_SIZE - len, "%s%s%s",
+ i ? " " : "", cabc_modes[i],
+ i == ARRAY_SIZE(cabc_modes) - 1 ? "\n" : "");
+
+ return len < PAGE_SIZE ? len : PAGE_SIZE - 1;
+}
+
+static DEVICE_ATTR(cabc_mode, S_IRUGO | S_IWUSR,
+ show_cabc_mode, store_cabc_mode);
+static DEVICE_ATTR(cabc_available_modes, S_IRUGO,
+ show_cabc_available_modes, NULL);
+
+static struct attribute *bldev_attrs[] = {
+ &dev_attr_cabc_mode.attr,
+ &dev_attr_cabc_available_modes.attr,
+ NULL,
+};
+
+static struct attribute_group bldev_attr_group = {
+ .attrs = bldev_attrs,
+};
+
+/*---------------------------ACX Panel----------------------------*/
+
+static struct omap_video_timings acx_panel_timings = {
+ .x_res = 800,
+ .y_res = 480,
+ .pixel_clock = 24000,
+ .hfp = 28,
+ .hsw = 4,
+ .hbp = 24,
+ .vfp = 3,
+ .vsw = 3,
+ .vbp = 4,
+};
+
+static int acx_panel_probe(struct omap_dss_device *dssdev)
+{
+ int r;
+ struct acx565akm_device *md = &acx_dev;
+ struct backlight_device *bldev;
+ int max_brightness, brightness;
+
+ dev_dbg(&dssdev->dev, "%s\n", __func__);
+ dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
+ OMAP_DSS_LCD_IHS;
+ /* FIXME AC bias ? */
+ dssdev->panel.timings = acx_panel_timings;
+ dssdev->panel.recommended_bpp = 16;
+
+ if (dssdev->platform_enable)
+ dssdev->platform_enable(dssdev);
+ /*
+ * After reset we have to wait 5 msec before the first
+ * command can be sent.
+ */
+ msleep(5);
+
+ md->enabled = panel_enabled(md);
+
+ r = panel_detect(md);
+ if (r) {
+ dev_err(&dssdev->dev, "%s panel detect error\n", __func__);
+ if (!md->enabled && dssdev->platform_disable)
+ dssdev->platform_disable(dssdev);
+ return r;
+ }
+
+ mutex_lock(&acx_dev.mutex);
+ acx_dev.dssdev = dssdev;
+ mutex_unlock(&acx_dev.mutex);
+
+ if (!md->enabled) {
+ if (dssdev->platform_disable)
+ dssdev->platform_disable(dssdev);
+ }
+
+ /*------- Backlight control --------*/
+
+ bldev = backlight_device_register("acx565akm", &md->spi->dev,
+ md, &acx565akm_bl_ops);
+ md->bl_dev = bldev;
+ if (md->has_cabc) {
+ r = sysfs_create_group(&bldev->dev.kobj, &bldev_attr_group);
+ if (r) {
+ dev_err(&bldev->dev,
+ "%s failed to create sysfs files\n", __func__);
+ backlight_device_unregister(bldev);
+ return r;
+ }
+ md->cabc_mode = get_hw_cabc_mode(md);
+ }
+
+ bldev->props.fb_blank = FB_BLANK_UNBLANK;
+ bldev->props.power = FB_BLANK_UNBLANK;
+
+ if (md->has_bc)
+ max_brightness = 255;
+ else
+ max_brightness = dssdev->max_backlight_level;
+
+ if (md->has_bc)
+ brightness = acx565akm_get_actual_brightness(md);
+ else if (dssdev->get_backlight)
+ brightness = dssdev->get_backlight(dssdev);
+ else
+ brightness = 0;
+
+ bldev->props.max_brightness = max_brightness;
+ bldev->props.brightness = brightness;
+
+ acx565akm_bl_update_status(bldev);
+ return 0;
+}
+
+static void acx_panel_remove(struct omap_dss_device *dssdev)
+{
+ struct acx565akm_device *md = &acx_dev;
+
+ dev_dbg(&dssdev->dev, "%s\n", __func__);
+ sysfs_remove_group(&md->bl_dev->dev.kobj, &bldev_attr_group);
+ backlight_device_unregister(md->bl_dev);
+ mutex_lock(&acx_dev.mutex);
+ acx_dev.dssdev = NULL;
+ mutex_unlock(&acx_dev.mutex);
+}
+
+static int acx_panel_power_on(struct omap_dss_device *dssdev)
+{
+ struct acx565akm_device *md = &acx_dev;
+ int r;
+
+ dev_dbg(&dssdev->dev, "%s\n", __func__);
+
+ mutex_lock(&md->mutex);
+
+ if (dssdev->platform_enable) {
+ r = dssdev->platform_enable(dssdev);
+ if (r)
+ return r;
+ }
+
+ if (md->enabled) {
+ dev_dbg(&md->spi->dev, "panel already enabled\n");
+ mutex_unlock(&md->mutex);
+ return 0;
+ }
+
+ /*
+ * We have to meet all the following delay requirements:
+ * 1. tRW: reset pulse width 10usec (7.12.1)
+ * 2. tRT: reset cancel time 5msec (7.12.1)
+ * 3. Providing PCLK,HS,VS signals for 2 frames = ~50msec worst
+ * case (7.6.2)
+ * 4. 120msec before the sleep out command (7.12.1)
+ */
+ msleep(120);
+
+ set_sleep_mode(md, 0);
+ md->enabled = 1;
+
+ /* 5msec between sleep out and the next command. (8.2.16) */
+ msleep(5);
+ set_display_state(md, 1);
+ set_cabc_mode(md, md->cabc_mode);
+
+ mutex_unlock(&md->mutex);
+
+ return acx565akm_bl_update_status(md->bl_dev);
+}
+
+static void acx_panel_power_off(struct omap_dss_device *dssdev)
+{
+ struct acx565akm_device *md = &acx_dev;
+
+ dev_dbg(&dssdev->dev, "%s\n", __func__);
+
+ mutex_lock(&md->mutex);
+
+ if (!md->enabled) {
+ mutex_unlock(&md->mutex);
+ return;
+ }
+ set_display_state(md, 0);
+ set_sleep_mode(md, 1);
+ md->enabled = 0;
+ /*
+ * We have to provide PCLK,HS,VS signals for 2 frames (worst case
+ * ~50msec) after sending the sleep in command and asserting the
+ * reset signal. We probably could assert the reset w/o the delay
+ * but we still delay to avoid possible artifacts. (7.6.1)
+ */
+ msleep(50);
+
+ if (dssdev->platform_disable)
+ dssdev->platform_disable(dssdev);
+
+ mutex_unlock(&md->mutex);
+}
+
+static int acx_panel_enable(struct omap_dss_device *dssdev)
+{
+ int r;
+
+ dev_dbg(&dssdev->dev, "%s\n", __func__);
+ r = acx_panel_power_on(dssdev);
+
+ if (r)
+ return r;
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+ return 0;
+}
+
+static void acx_panel_disable(struct omap_dss_device *dssdev)
+{
+ dev_dbg(&dssdev->dev, "%s\n", __func__);
+ acx_panel_power_off(dssdev);
+ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+}
+
+static int acx_panel_suspend(struct omap_dss_device *dssdev)
+{
+ dev_dbg(&dssdev->dev, "%s\n", __func__);
+ acx_panel_power_off(dssdev);
+ dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
+ return 0;
+}
+
+static int acx_panel_resume(struct omap_dss_device *dssdev)
+{
+ int r;
+
+ dev_dbg(&dssdev->dev, "%s\n", __func__);
+ r = acx_panel_power_on(dssdev);
+ if (r)
+ return r;
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+ return 0;
+}
+
+static struct omap_dss_driver acx_panel_driver = {
+ .probe = acx_panel_probe,
+ .remove = acx_panel_remove,
+
+ .enable = acx_panel_enable,
+ .disable = acx_panel_disable,
+ .suspend = acx_panel_suspend,
+ .resume = acx_panel_resume,
+
+ .driver = {
+ .name = "panel-acx565akm",
+ .owner = THIS_MODULE,
+ },
+};
+
+/*--------------------SPI probe-------------------------*/
+
+static int acx565akm_spi_probe(struct spi_device *spi)
+{
+ struct acx565akm_device *md = &acx_dev;
+
+ dev_dbg(&spi->dev, "%s\n", __func__);
+
+ spi->mode = SPI_MODE_3;
+ md->spi = spi;
+ mutex_init(&md->mutex);
+ dev_set_drvdata(&spi->dev, md);
+
+ omap_dss_register_driver(&acx_panel_driver);
+
+ return 0;
+}
+
+static int acx565akm_spi_remove(struct spi_device *spi)
+{
+ struct acx565akm_device *md = dev_get_drvdata(&spi->dev);
+
+ dev_dbg(&md->spi->dev, "%s\n", __func__);
+ omap_dss_unregister_driver(&acx_panel_driver);
+
+ return 0;
+}
+
+static struct spi_driver acx565akm_spi_driver = {
+ .driver = {
+ .name = "acx565akm",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = acx565akm_spi_probe,
+ .remove = __devexit_p(acx565akm_spi_remove),
+};
+
+static int __init acx565akm_init(void)
+{
+ return spi_register_driver(&acx565akm_spi_driver);
+}
+
+static void __exit acx565akm_exit(void)
+{
+ spi_unregister_driver(&acx565akm_spi_driver);
+}
+
+module_init(acx565akm_init);
+module_exit(acx565akm_exit);
+
+MODULE_AUTHOR("Nokia Corporation");
+MODULE_DESCRIPTION("acx565akm LCD Driver");
+MODULE_LICENSE("GPL");
--
1.6.0.4

View File

@ -0,0 +1,107 @@
From 8fe1805debbf54143073a2f85e8568ed7b9ca38b Mon Sep 17 00:00:00 2001
From: Roger Quadros <roger.quadros@nokia.com>
Date: Wed, 17 Mar 2010 12:35:19 +0000
Subject: [PATCH 1/10] OMAP: DSS2: Add Kconfig option for DPI display type
From: Roger Quadros <roger.quadros@nokia.com>
Patch-mainline: 2.6.35?
Git-repo: http://www.gitorious.org/linux-omap-dss2/linux/commit/36b33efe80eb07e3447107c2bdba3c674c10a41a
This allows us to disable DPI on systems that do not have it
Signed-off-by: Roger Quadros <roger.quadros@nokia.com>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@nokia.com>
---
drivers/video/omap2/dss/Kconfig | 6 ++++++
drivers/video/omap2/dss/Makefile | 3 ++-
drivers/video/omap2/dss/core.c | 4 ++++
drivers/video/omap2/dss/display.c | 4 ++++
4 files changed, 16 insertions(+), 1 deletions(-)
diff --git a/drivers/video/omap2/dss/Kconfig b/drivers/video/omap2/dss/Kconfig
index c63ce76..cbe8ea0 100644
--- a/drivers/video/omap2/dss/Kconfig
+++ b/drivers/video/omap2/dss/Kconfig
@@ -32,6 +32,12 @@ config OMAP2_DSS_COLLECT_IRQ_STATS
help
Collect DSS IRQ statistics, printable via debugfs
+config OMAP2_DSS_DPI
+ bool "DPI support"
+ default y
+ help
+ DPI Interface. This is the Parallel Display Interface.
+
config OMAP2_DSS_RFBI
bool "RFBI support"
default n
diff --git a/drivers/video/omap2/dss/Makefile b/drivers/video/omap2/dss/Makefile
index 980c72c..d71b5d9 100644
--- a/drivers/video/omap2/dss/Makefile
+++ b/drivers/video/omap2/dss/Makefile
@@ -1,5 +1,6 @@
obj-$(CONFIG_OMAP2_DSS) += omapdss.o
-omapdss-y := core.o dss.o dispc.o dpi.o display.o manager.o overlay.o
+omapdss-y := core.o dss.o dispc.o display.o manager.o overlay.o
+omapdss-$(CONFIG_OMAP2_DSS_DPI) += dpi.o
omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o
omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o
omapdss-$(CONFIG_OMAP2_DSS_SDI) += sdi.o
diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c
index 82918ee..0988781 100644
--- a/drivers/video/omap2/dss/core.c
+++ b/drivers/video/omap2/dss/core.c
@@ -473,11 +473,13 @@ static int omap_dss_probe(struct platform_device *pdev)
}
#endif
+#ifdef CONFIG_OMAP2_DSS_DPI
r = dpi_init();
if (r) {
DSSERR("Failed to initialize dpi\n");
goto fail0;
}
+#endif
r = dispc_init();
if (r) {
@@ -548,7 +550,9 @@ static int omap_dss_remove(struct platform_device *pdev)
venc_exit();
#endif
dispc_exit();
+#ifdef CONFIG_OMAP2_DSS_DPI
dpi_exit();
+#endif
#ifdef CONFIG_OMAP2_DSS_RFBI
rfbi_exit();
#endif
diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c
index 3b92b84..2150f12 100644
--- a/drivers/video/omap2/dss/display.c
+++ b/drivers/video/omap2/dss/display.c
@@ -405,7 +405,9 @@ void dss_init_device(struct platform_device *pdev,
int r;
switch (dssdev->type) {
+#ifdef CONFIG_OMAP2_DSS_DPI
case OMAP_DISPLAY_TYPE_DPI:
+#endif
#ifdef CONFIG_OMAP2_DSS_RFBI
case OMAP_DISPLAY_TYPE_DBI:
#endif
@@ -430,9 +432,11 @@ void dss_init_device(struct platform_device *pdev,
dssdev->wait_vsync = default_wait_vsync;
switch (dssdev->type) {
+#ifdef CONFIG_OMAP2_DSS_DPI
case OMAP_DISPLAY_TYPE_DPI:
r = dpi_init_display(dssdev);
break;
+#endif
#ifdef CONFIG_OMAP2_DSS_RFBI
case OMAP_DISPLAY_TYPE_DBI:
r = rfbi_init_display(dssdev);
--
1.6.0.4

View File

@ -0,0 +1,118 @@
From 4111c672962a8df130b294961ab552fef6a498d9 Mon Sep 17 00:00:00 2001
From: Roger Quadros <roger.quadros@nokia.com>
Date: Wed, 17 Mar 2010 12:35:21 +0000
Subject: [PATCH 2/10] OMAP: DSS2: Use vdds_sdi regulator supply in SDI
From: Roger Quadros <roger.quadros@nokia.com>
Patch-mainline: 2.6.35?
Git-repo: http://www.gitorious.org/linux-omap-dss2/linux/commit/1d5c6663d92b37539617d833e6049e5dd21751c4
This patch enables the use of vdds_sdi regulator in SDI subsystem.
We can disable the vdds_sdi voltage when not in use to save
power.
Signed-off-by: Roger Quadros <roger.quadros@nokia.com>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@nokia.com>
---
drivers/video/omap2/dss/core.c | 2 +-
drivers/video/omap2/dss/dss.h | 2 +-
drivers/video/omap2/dss/sdi.c | 17 ++++++++++++++++-
3 files changed, 18 insertions(+), 3 deletions(-)
diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c
index 0988781..97f929b 100644
--- a/drivers/video/omap2/dss/core.c
+++ b/drivers/video/omap2/dss/core.c
@@ -495,7 +495,7 @@ static int omap_dss_probe(struct platform_device *pdev)
#endif
if (cpu_is_omap34xx()) {
#ifdef CONFIG_OMAP2_DSS_SDI
- r = sdi_init(skip_init);
+ r = sdi_init(pdev, skip_init);
if (r) {
DSSERR("Failed to initialize SDI\n");
goto fail0;
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h
index 2bcb124..8490bdf 100644
--- a/drivers/video/omap2/dss/dss.h
+++ b/drivers/video/omap2/dss/dss.h
@@ -231,7 +231,7 @@ int dss_calc_clock_div(bool is_tft, unsigned long req_pck,
struct dispc_clock_info *dispc_cinfo);
/* SDI */
-int sdi_init(bool skip_init);
+int sdi_init(struct platform_device *pdev, bool skip_init);
void sdi_exit(void);
int sdi_init_display(struct omap_dss_device *display);
diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c
index c24f307..025c56c 100644
--- a/drivers/video/omap2/dss/sdi.c
+++ b/drivers/video/omap2/dss/sdi.c
@@ -23,6 +23,8 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
#include <plat/display.h>
#include "dss.h"
@@ -30,6 +32,7 @@
static struct {
bool skip_init;
bool update_enabled;
+ struct regulator *vdds_sdi_reg;
} sdi;
static void sdi_basic_init(void)
@@ -63,6 +66,10 @@ static int sdi_display_enable(struct omap_dss_device *dssdev)
goto err1;
}
+ r = regulator_enable(sdi.vdds_sdi_reg);
+ if (r)
+ goto err1;
+
/* In case of skip_init sdi_init has already enabled the clocks */
if (!sdi.skip_init)
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
@@ -136,6 +143,7 @@ err3:
dispc_enable_lcd_out(0);
err2:
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+ regulator_disable(sdi.vdds_sdi_reg);
err1:
omap_dss_stop_device(dssdev);
err0:
@@ -164,6 +172,8 @@ static void sdi_display_disable(struct omap_dss_device *dssdev)
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+ regulator_disable(sdi.vdds_sdi_reg);
+
omap_dss_stop_device(dssdev);
}
@@ -258,11 +268,16 @@ int sdi_init_display(struct omap_dss_device *dssdev)
return 0;
}
-int sdi_init(bool skip_init)
+int sdi_init(struct platform_device *pdev, bool skip_init)
{
/* we store this for first display enable, then clear it */
sdi.skip_init = skip_init;
+ sdi.vdds_sdi_reg = regulator_get(&pdev->dev, "vdds_sdi");
+ if (IS_ERR(sdi.vdds_sdi_reg)) {
+ DSSERR("can't get VDDS_SDI regulator\n");
+ return PTR_ERR(sdi.vdds_sdi_reg);
+ }
/*
* Enable clocks already here, otherwise there would be a toggle
* of them until sdi_display_enable is called.
--
1.6.0.4

View File

@ -0,0 +1,207 @@
From 2377c3d6cf49c057bd2237fbabf429a9b243c663 Mon Sep 17 00:00:00 2001
From: Roger Quadros <roger.quadros@nokia.com>
Date: Wed, 10 Mar 2010 15:30:05 +0200
Subject: [PATCH 4/10] OMAP: RX51: Add LCD Panel support
From: Roger Quadros <roger.quadros@nokia.com>
Patch-mainline: 2.6.35?
Git-repo: http://www.gitorious.org/linux-omap-dss2/linux/commit/c296146d9fe00624cbb34da56c6b2927ef9bbbad
Adds basic support for LCD Panel on Nokia N900
Signed-off-by: Roger Quadros <roger.quadros@nokia.com>
---
arch/arm/mach-omap2/Makefile | 1 +
arch/arm/mach-omap2/board-rx51-peripherals.c | 13 +++
arch/arm/mach-omap2/board-rx51-video.c | 107 ++++++++++++++++++++++++++
arch/arm/mach-omap2/board-rx51.c | 2 +
4 files changed, 123 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/mach-omap2/board-rx51-video.c
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index b32678b..05e7c9c 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -89,6 +89,7 @@ obj-$(CONFIG_MACH_NOKIA_N8X0) += board-n8x0.o
obj-$(CONFIG_MACH_NOKIA_RX51) += board-rx51.o \
board-rx51-sdram.o \
board-rx51-peripherals.o \
+ board-rx51-video.o \
mmc-twl4030.o
obj-$(CONFIG_MACH_OMAP_ZOOM2) += board-zoom2.o \
board-zoom-peripherals.o \
diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c
index acafdbc..7bae364 100644
--- a/arch/arm/mach-omap2/board-rx51-peripherals.c
+++ b/arch/arm/mach-omap2/board-rx51-peripherals.c
@@ -45,6 +45,7 @@
/* list all spi devices here */
enum {
RX51_SPI_WL1251,
+ RX51_SPI_MIPID, /* LCD panel */
};
static struct wl12xx_platform_data wl1251_pdata;
@@ -54,6 +55,11 @@ static struct omap2_mcspi_device_config wl1251_mcspi_config = {
.single_channel = 1,
};
+static struct omap2_mcspi_device_config mipid_mcspi_config = {
+ .turbo_mode = 0,
+ .single_channel = 1,
+};
+
static struct spi_board_info rx51_peripherals_spi_board_info[] __initdata = {
[RX51_SPI_WL1251] = {
.modalias = "wl1251",
@@ -64,6 +70,13 @@ static struct spi_board_info rx51_peripherals_spi_board_info[] __initdata = {
.controller_data = &wl1251_mcspi_config,
.platform_data = &wl1251_pdata,
},
+ [RX51_SPI_MIPID] = {
+ .modalias = "acx565akm",
+ .bus_num = 1,
+ .chip_select = 2,
+ .max_speed_hz = 6000000,
+ .controller_data = &mipid_mcspi_config,
+ },
};
#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
diff --git a/arch/arm/mach-omap2/board-rx51-video.c b/arch/arm/mach-omap2/board-rx51-video.c
new file mode 100644
index 0000000..e4a9d4c
--- /dev/null
+++ b/arch/arm/mach-omap2/board-rx51-video.c
@@ -0,0 +1,107 @@
+/*
+ * linux/arch/arm/mach-omap2/board-rx51-video.c
+ *
+ * Copyright (C) 2010 Nokia
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/mm.h>
+
+#include <asm/mach-types.h>
+#include <plat/mux.h>
+#include <plat/display.h>
+#include <plat/vram.h>
+#include <plat/mcspi.h>
+
+#include "mux.h"
+
+#define RX51_LCD_RESET_GPIO 90
+
+#if defined(CONFIG_FB_OMAP2) || defined(CONFIG_FB_OMAP2_MODULE)
+
+static int rx51_lcd_enable(struct omap_dss_device *dssdev)
+{
+ gpio_set_value(dssdev->reset_gpio, 1);
+ return 0;
+}
+
+static void rx51_lcd_disable(struct omap_dss_device *dssdev)
+{
+ gpio_set_value(dssdev->reset_gpio, 0);
+}
+
+static struct omap_dss_device rx51_lcd_device = {
+ .name = "lcd",
+ .driver_name = "panel-acx565akm",
+ .type = OMAP_DISPLAY_TYPE_SDI,
+ .phy.sdi.datapairs = 2,
+ .reset_gpio = RX51_LCD_RESET_GPIO,
+ .platform_enable = rx51_lcd_enable,
+ .platform_disable = rx51_lcd_disable,
+};
+
+static struct omap_dss_device *rx51_dss_devices[] = {
+ &rx51_lcd_device,
+};
+
+static struct omap_dss_board_info rx51_dss_board_info = {
+ .num_devices = ARRAY_SIZE(rx51_dss_devices),
+ .devices = rx51_dss_devices,
+ .default_device = &rx51_lcd_device,
+};
+
+struct platform_device rx51_display_device = {
+ .name = "omapdss",
+ .id = -1,
+ .dev = {
+ .platform_data = &rx51_dss_board_info,
+ },
+};
+
+static struct platform_device *rx51_video_devices[] __initdata = {
+ &rx51_display_device,
+};
+
+static int __init rx51_video_init(void)
+{
+ if (!machine_is_nokia_rx51())
+ return 0;
+
+ if (omap_mux_init_gpio(RX51_LCD_RESET_GPIO, OMAP_PIN_OUTPUT)) {
+ pr_err("%s cannot configure MUX for LCD RESET\n", __func__);
+ return 0;
+ }
+
+ if (gpio_request(RX51_LCD_RESET_GPIO, "LCD ACX565AKM reset")) {
+ pr_err("%s failed to get LCD Reset GPIO\n", __func__);
+ return 0;
+ }
+
+ gpio_direction_output(RX51_LCD_RESET_GPIO, 1);
+
+ platform_add_devices(rx51_video_devices,
+ ARRAY_SIZE(rx51_video_devices));
+ return 0;
+}
+
+subsys_initcall(rx51_video_init);
+
+void __init rx51_video_mem_init(void)
+{
+ /*
+ * GFX 864x480x32bpp
+ * VID1/2 1280x720x32bpp double buffered
+ */
+ omap_vram_set_sdram_vram(PAGE_ALIGN(864 * 480 * 4) +
+ 2 * PAGE_ALIGN(1280 * 720 * 4 * 2), 0);
+}
+
+#endif /* defined(CONFIG_FB_OMAP2) || defined(CONFIG_FB_OMAP2_MODULE) */
diff --git a/arch/arm/mach-omap2/board-rx51.c b/arch/arm/mach-omap2/board-rx51.c
index 67bb347..f1f81cf 100644
--- a/arch/arm/mach-omap2/board-rx51.c
+++ b/arch/arm/mach-omap2/board-rx51.c
@@ -32,6 +32,7 @@
#include "mux.h"
struct omap_sdrc_params *rx51_get_sdram_timings(void);
+extern void rx51_video_mem_init(void);
static struct omap_lcd_config rx51_lcd_config = {
.ctrl_name = "internal",
@@ -93,6 +94,7 @@ static void __init rx51_init(void)
static void __init rx51_map_io(void)
{
omap2_set_globals_343x();
+ rx51_video_mem_init();
omap2_map_common_io();
}
--
1.6.0.4

View File

@ -0,0 +1,64 @@
From 186ac697a023e7b95db72433fb8d4e8a9553826d Mon Sep 17 00:00:00 2001
From: Roger Quadros <roger.quadros@nokia.com>
Date: Mon, 22 Mar 2010 17:16:25 +0200
Subject: [PATCH 6/10] OMAP: RX51: Add Touch Controller in SPI board info
From: Roger Quadros <roger.quadros@nokia.com>
Patch-mainline: 2.6.35?
Git-repo: http://www.gitorious.org/linux-omap-dss2/linux/commit/a77ee8b332b62f3b10ffc15b27b889adf50cd013
The Touch controller and LCD Panel share the same SPI bus 1.
So, we need to define the touch controller in the SPI board info
else, the SPI bus will be contended due to invalid state of
Touch controller's Chip Select thus preventing the LCD panel
from working.
Signed-off-by: Roger Quadros <roger.quadros@nokia.com>
---
arch/arm/mach-omap2/board-rx51-peripherals.c | 15 +++++++++++++++
1 files changed, 15 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c
index 6a41a0a..bdb1c54 100644
--- a/arch/arm/mach-omap2/board-rx51-peripherals.c
+++ b/arch/arm/mach-omap2/board-rx51-peripherals.c
@@ -46,6 +46,7 @@
enum {
RX51_SPI_WL1251,
RX51_SPI_MIPID, /* LCD panel */
+ RX51_SPI_TSC2005, /* Touch Controller */
};
static struct wl12xx_platform_data wl1251_pdata;
@@ -60,6 +61,11 @@ static struct omap2_mcspi_device_config mipid_mcspi_config = {
.single_channel = 1,
};
+static struct omap2_mcspi_device_config tsc2005_mcspi_config = {
+ .turbo_mode = 0,
+ .single_channel = 1,
+};
+
static struct spi_board_info rx51_peripherals_spi_board_info[] __initdata = {
[RX51_SPI_WL1251] = {
.modalias = "wl1251",
@@ -77,6 +83,15 @@ static struct spi_board_info rx51_peripherals_spi_board_info[] __initdata = {
.max_speed_hz = 6000000,
.controller_data = &mipid_mcspi_config,
},
+ [RX51_SPI_TSC2005] = {
+ .modalias = "tsc2005",
+ .bus_num = 1,
+ .chip_select = 0,
+ /* .irq = OMAP_GPIO_IRQ(RX51_TSC2005_IRQ_GPIO),*/
+ .max_speed_hz = 6000000,
+ .controller_data = &tsc2005_mcspi_config,
+ /* .platform_data = &tsc2005_config,*/
+ },
};
#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
--
1.6.0.4

View File

@ -0,0 +1,54 @@
From 48c56cb077e21cf56f0673c9010dde7be4c1bd88 Mon Sep 17 00:00:00 2001
From: Roger Quadros <roger.quadros@nokia.com>
Date: Fri, 12 Mar 2010 16:14:22 +0200
Subject: [PATCH 5/10] OMAP: RX51: Add "vdds_sdi" supply voltage for SDI
From: Roger Quadros <roger.quadros@nokia.com>
Patch-mainline: 2.6.35?
Git-repo: http://www.gitorious.org/linux-omap-dss2/linux/commit/659550d7f54a2620ba2cc1a98273793ce97de230
The SDI Display subsystem needs access to the vdds_sdi supply
regulator. This is TWL4030's VAUX1 supply on RX-51.
Signed-off-by: Roger Quadros <roger.quadros@nokia.com>
---
arch/arm/mach-omap2/board-rx51-peripherals.c | 15 +++++++++++++++
1 files changed, 15 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c
index 7bae364..6a41a0a 100644
--- a/arch/arm/mach-omap2/board-rx51-peripherals.c
+++ b/arch/arm/mach-omap2/board-rx51-peripherals.c
@@ -256,6 +256,19 @@ static struct regulator_consumer_supply rx51_vsim_supply = {
.supply = "vmmc_aux",
};
+#if defined(CONFIG_FB_OMAP2) || defined(CONFIG_FB_OMAP2_MODULE)
+extern struct platform_device rx51_display_device;
+#endif
+
+static struct regulator_consumer_supply rx51_vaux1_consumers[] = {
+#if defined(CONFIG_FB_OMAP2) || defined(CONFIG_FB_OMAP2_MODULE)
+ {
+ .supply = "vdds_sdi",
+ .dev = &rx51_display_device.dev,
+ },
+#endif
+};
+
static struct regulator_init_data rx51_vaux1 = {
.constraints = {
.name = "V28",
@@ -266,6 +279,8 @@ static struct regulator_init_data rx51_vaux1 = {
.valid_ops_mask = REGULATOR_CHANGE_MODE
| REGULATOR_CHANGE_STATUS,
},
+ .num_consumer_supplies = ARRAY_SIZE(rx51_vaux1_consumers),
+ .consumer_supplies = rx51_vaux1_consumers,
};
static struct regulator_init_data rx51_vaux2 = {
--
1.6.0.4

View File

@ -0,0 +1,804 @@
From c0960b696fbccc83925134aec007801073bcac54 Mon Sep 17 00:00:00 2001
From: Lauri Leukkunen <lauri.leukkunen@nokia.com>
Date: Fri, 12 Mar 2010 16:54:33 +0000
Subject: [PATCH 7/10] input: touchscreen: introduce tsc2005 driver
Patch-mainline: 2.6.35?
Discussions: http://www.mail-archive.com/linux-omap@vger.kernel.org/msg26748.html
Introduce a driver for the Texas Instruments TSC2005 touchscreen
controller (http://focus.ti.com/docs/prod/folders/print/tsc2005.html).
The patch is based on a driver by Lauri Leukkunen, with modifications
by David Brownell, Phil Carmody, Imre Deak, Hiroshi DOYU, Ari Kauppi,
Tony Lindgren, Jarkko Nikula, Eero Nurkkala and Roman Tereshonkov.
Signed-off-by: Lauri Leukkunen <lauri.leukkunen@nokia.com>
[aaro.koskinen@nokia.com: patch description, rebasing & cleanup]
Signed-off-by: Aaro Koskinen <aaro.koskinen@nokia.com>
Cc: David Brownell <dbrownell@users.sourceforge.net>
Cc: Phil Carmody <ext-phil.2.carmody@nokia.com>
Cc: Imre Deak <imre.deak@nokia.com>
Cc: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
Cc: Ari Kauppi <Ext-Ari.Kauppi@nokia.com>
Cc: Tony Lindgren <tony@atomide.com>
Cc: Jarkko Nikula <jhnikula@gmail.com>
Cc: Eero Nurkkala <ext-eero.nurkkala@nokia.com>
Cc: Roman Tereshonkov <roman.tereshonkov@nokia.com>
---
drivers/input/touchscreen/Kconfig | 11 +
drivers/input/touchscreen/Makefile | 1 +
drivers/input/touchscreen/tsc2005.c | 678 +++++++++++++++++++++++++++++++++++
include/linux/spi/tsc2005.h | 41 +++
4 files changed, 731 insertions(+), 0 deletions(-)
create mode 100644 drivers/input/touchscreen/tsc2005.c
create mode 100644 include/linux/spi/tsc2005.h
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index dfafc76..72c1797 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -548,6 +548,17 @@ config TOUCHSCREEN_TOUCHIT213
To compile this driver as a module, choose M here: the
module will be called touchit213.
+config TOUCHSCREEN_TSC2005
+ tristate "TSC2005 based touchscreens"
+ depends on SPI_MASTER
+ help
+ Say Y here if you have a TSC2005 based touchscreen.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tsc2005.
+
config TOUCHSCREEN_TSC2007
tristate "TSC2007 based touchscreens"
depends on I2C
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index d61a3b4..61fa8b5 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -33,6 +33,7 @@ obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o
+obj-$(CONFIG_TOUCHSCREEN_TSC2005) += tsc2005.o
obj-$(CONFIG_TOUCHSCREEN_TSC2007) += tsc2007.o
obj-$(CONFIG_TOUCHSCREEN_UCB1400) += ucb1400_ts.o
obj-$(CONFIG_TOUCHSCREEN_WACOM_W8001) += wacom_w8001.o
diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c
new file mode 100644
index 0000000..27ee361
--- /dev/null
+++ b/drivers/input/touchscreen/tsc2005.c
@@ -0,0 +1,678 @@
+/*
+ * TSC2005 touchscreen driver
+ *
+ * Copyright (C) 2006-2010 Nokia Corporation
+ *
+ * Author: Lauri Leukkunen <lauri.leukkunen@nokia.com>
+ * based on TSC2301 driver by Klaus K. Pedersen <klaus.k.pedersen@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/tsc2005.h>
+
+/*
+ * The touchscreen interface operates as follows:
+ *
+ * 1) Pen is pressed against the touchscreen.
+ * 2) TSC2005 performs AD conversion.
+ * 3) After the conversion is done TSC2005 drives DAV line down.
+ * 4) GPIO IRQ is received and tsc2005_irq_thread() is scheduled.
+ * 5) tsc2005_irq_thread() queues up an spi transfer to fetch the x, y, z1, z2
+ * values.
+ * 6) tsc2005_irq_thread() reports coordinates to input layer and sets up
+ * tsc2005_penup_timer() to be called after TSC2005_PENUP_TIME_MS (40ms).
+ * 7) When the penup timer expires, there have not been touch or DAV interrupts
+ * during the last 40ms which means the pen has been lifted.
+ *
+ * ESD recovery via a hardware reset is done if the TSC2005 doesn't respond
+ * after a configurable period (in ms) of activity. If esd_timeout is 0, the
+ * watchdog is disabled.
+ */
+
+/* control byte 1 */
+#define TSC2005_CMD 0x80
+#define TSC2005_CMD_NORMAL 0x00
+#define TSC2005_CMD_STOP 0x01
+#define TSC2005_CMD_12BIT 0x04
+
+/* control byte 0 */
+#define TSC2005_REG_READ 0x0001
+#define TSC2005_REG_PND0 0x0002
+#define TSC2005_REG_X 0x0000
+#define TSC2005_REG_Y 0x0008
+#define TSC2005_REG_Z1 0x0010
+#define TSC2005_REG_Z2 0x0018
+#define TSC2005_REG_TEMP_HIGH 0x0050
+#define TSC2005_REG_CFR0 0x0060
+#define TSC2005_REG_CFR1 0x0068
+#define TSC2005_REG_CFR2 0x0070
+
+/* configuration register 0 */
+#define TSC2005_CFR0_PRECHARGE_276US 0x0040
+#define TSC2005_CFR0_STABTIME_1MS 0x0300
+#define TSC2005_CFR0_CLOCK_1MHZ 0x1000
+#define TSC2005_CFR0_RESOLUTION12 0x2000
+#define TSC2005_CFR0_PENMODE 0x8000
+#define TSC2005_CFR0_INITVALUE (TSC2005_CFR0_STABTIME_1MS | \
+ TSC2005_CFR0_CLOCK_1MHZ | \
+ TSC2005_CFR0_RESOLUTION12 | \
+ TSC2005_CFR0_PRECHARGE_276US | \
+ TSC2005_CFR0_PENMODE)
+
+/* bits common to both read and write of configuration register 0 */
+#define TSC2005_CFR0_RW_MASK 0x3fff
+
+/* configuration register 1 */
+#define TSC2005_CFR1_BATCHDELAY_4MS 0x0003
+#define TSC2005_CFR1_INITVALUE TSC2005_CFR1_BATCHDELAY_4MS
+
+/* configuration register 2 */
+#define TSC2005_CFR2_MAVE_Z 0x0004
+#define TSC2005_CFR2_MAVE_Y 0x0008
+#define TSC2005_CFR2_MAVE_X 0x0010
+#define TSC2005_CFR2_AVG_7 0x0800
+#define TSC2005_CFR2_MEDIUM_15 0x3000
+#define TSC2005_CFR2_INITVALUE (TSC2005_CFR2_MAVE_X | \
+ TSC2005_CFR2_MAVE_Y | \
+ TSC2005_CFR2_MAVE_Z | \
+ TSC2005_CFR2_MEDIUM_15 | \
+ TSC2005_CFR2_AVG_7)
+
+#define MAX_12BIT 0xfff
+#define TSC2005_SPI_MAX_SPEED_HZ 10000000
+#define TSC2005_PENUP_TIME_MS 40
+
+struct tsc2005_spi_rd {
+ struct spi_transfer spi_xfer;
+ u32 spi_tx;
+ u32 spi_rx;
+};
+
+struct tsc2005 {
+ struct spi_device *spi;
+
+ struct spi_message spi_read_msg;
+ struct tsc2005_spi_rd spi_x;
+ struct tsc2005_spi_rd spi_y;
+ struct tsc2005_spi_rd spi_z1;
+ struct tsc2005_spi_rd spi_z2;
+
+ struct input_dev *idev;
+ char phys[32];
+
+ struct mutex mutex;
+
+ struct timer_list penup_timer;
+ struct work_struct penup_work;
+
+ unsigned int esd_timeout;
+ struct timer_list esd_timer;
+ struct work_struct esd_work;
+
+ unsigned int x_plate_ohm;
+
+ bool disabled;
+ unsigned int disable_depth;
+
+ void (*set_reset)(bool enable);
+};
+
+static void tsc2005_cmd(struct tsc2005 *ts, u8 cmd)
+{
+ u8 tx;
+ struct spi_message msg;
+ struct spi_transfer xfer = { 0 };
+
+ tx = TSC2005_CMD | TSC2005_CMD_12BIT | cmd;
+
+ xfer.tx_buf = &tx;
+ xfer.rx_buf = NULL;
+ xfer.len = 1;
+ xfer.bits_per_word = 8;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ spi_sync(ts->spi, &msg);
+}
+
+static void tsc2005_write(struct tsc2005 *ts, u8 reg, u16 value)
+{
+ u32 tx;
+ struct spi_message msg;
+ struct spi_transfer xfer = { 0 };
+
+ tx = (reg | TSC2005_REG_PND0) << 16;
+ tx |= value;
+
+ xfer.tx_buf = &tx;
+ xfer.rx_buf = NULL;
+ xfer.len = 4;
+ xfer.bits_per_word = 24;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ spi_sync(ts->spi, &msg);
+}
+
+static void tsc2005_setup_read(struct tsc2005_spi_rd *rd, u8 reg, bool last)
+{
+ rd->spi_tx = (reg | TSC2005_REG_READ) << 16;
+ rd->spi_xfer.tx_buf = &rd->spi_tx;
+ rd->spi_xfer.rx_buf = &rd->spi_rx;
+ rd->spi_xfer.len = 4;
+ rd->spi_xfer.bits_per_word = 24;
+ rd->spi_xfer.cs_change = !last;
+}
+
+static void tsc2005_read(struct tsc2005 *ts, u8 reg, u16 *value)
+{
+ struct spi_message msg;
+ struct tsc2005_spi_rd spi_rd = { { 0 }, 0, 0 };
+
+ tsc2005_setup_read(&spi_rd, reg, 1);
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&spi_rd.spi_xfer, &msg);
+ spi_sync(ts->spi, &msg);
+ *value = spi_rd.spi_rx;
+}
+
+static void tsc2005_update_pen_state(struct tsc2005 *ts,
+ int x, int y, int pressure)
+{
+ if (pressure) {
+ input_report_abs(ts->idev, ABS_X, x);
+ input_report_abs(ts->idev, ABS_Y, y);
+ }
+ input_report_abs(ts->idev, ABS_PRESSURE, pressure);
+ input_report_key(ts->idev, BTN_TOUCH, !!pressure);
+ input_sync(ts->idev);
+ dev_dbg(&ts->spi->dev, "point(%4d,%4d), pressure (%4d)\n", x, y,
+ pressure);
+}
+
+static irqreturn_t tsc2005_irq_handler(int irq, void *dev_id)
+{
+ struct tsc2005 *ts = dev_id;
+
+ /* update the penup timer only if it's pending */
+ mod_timer_pending(&ts->penup_timer,
+ jiffies + msecs_to_jiffies(TSC2005_PENUP_TIME_MS));
+
+ return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t tsc2005_irq_thread(int irq, void *_ts)
+{
+ struct tsc2005 *ts = _ts;
+ unsigned int pressure;
+ u32 x;
+ u32 y;
+ u32 z1;
+ u32 z2;
+
+ mutex_lock(&ts->mutex);
+
+ if (unlikely(ts->disable_depth))
+ goto out;
+
+ /* read the coordinates */
+ spi_sync(ts->spi, &ts->spi_read_msg);
+ x = ts->spi_x.spi_rx;
+ y = ts->spi_y.spi_rx;
+ z1 = ts->spi_z1.spi_rx;
+ z2 = ts->spi_z2.spi_rx;
+
+ /* validate position */
+ if (unlikely(x > MAX_12BIT || y > MAX_12BIT))
+ goto out;
+
+ /* skip coords if the pressure components are out of range */
+ if (unlikely(z1 == 0 || z2 > MAX_12BIT || z1 >= z2))
+ goto out;
+
+ /* compute touch pressure resistance using equation #1 */
+ pressure = x * (z2 - z1) / z1;
+ pressure = pressure * ts->x_plate_ohm / 4096;
+ if (unlikely(pressure > MAX_12BIT))
+ goto out;
+
+ tsc2005_update_pen_state(ts, x, y, pressure);
+
+ /* set the penup timer */
+ mod_timer(&ts->penup_timer,
+ jiffies + msecs_to_jiffies(TSC2005_PENUP_TIME_MS));
+
+ if (!ts->esd_timeout)
+ goto out;
+
+ /* update the watchdog timer */
+ mod_timer(&ts->esd_timer,
+ round_jiffies(jiffies + msecs_to_jiffies(ts->esd_timeout)));
+
+out:
+ mutex_unlock(&ts->mutex);
+ return IRQ_HANDLED;
+}
+
+static void tsc2005_penup_timer(unsigned long data)
+{
+ struct tsc2005 *ts = (struct tsc2005 *)data;
+
+ schedule_work(&ts->penup_work);
+}
+
+static void tsc2005_penup_work(struct work_struct *work)
+{
+ struct tsc2005 *ts = container_of(work, struct tsc2005, penup_work);
+
+ mutex_lock(&ts->mutex);
+ tsc2005_update_pen_state(ts, 0, 0, 0);
+ mutex_unlock(&ts->mutex);
+}
+
+static void tsc2005_start_scan(struct tsc2005 *ts)
+{
+ tsc2005_write(ts, TSC2005_REG_CFR0, TSC2005_CFR0_INITVALUE);
+ tsc2005_write(ts, TSC2005_REG_CFR1, TSC2005_CFR1_INITVALUE);
+ tsc2005_write(ts, TSC2005_REG_CFR2, TSC2005_CFR2_INITVALUE);
+ tsc2005_cmd(ts, TSC2005_CMD_NORMAL);
+}
+
+static void tsc2005_stop_scan(struct tsc2005 *ts)
+{
+ tsc2005_cmd(ts, TSC2005_CMD_STOP);
+}
+
+/* must be called with mutex held */
+static void tsc2005_disable(struct tsc2005 *ts)
+{
+ if (ts->disable_depth++ != 0)
+ return;
+ disable_irq(ts->spi->irq);
+ if (ts->esd_timeout)
+ del_timer_sync(&ts->esd_timer);
+ del_timer_sync(&ts->penup_timer);
+ tsc2005_stop_scan(ts);
+}
+
+/* must be called with mutex held */
+static void tsc2005_enable(struct tsc2005 *ts)
+{
+ if (--ts->disable_depth != 0)
+ return;
+ tsc2005_start_scan(ts);
+ enable_irq(ts->spi->irq);
+ if (!ts->esd_timeout)
+ return;
+ mod_timer(&ts->esd_timer,
+ round_jiffies(jiffies + msecs_to_jiffies(ts->esd_timeout)));
+}
+
+static ssize_t tsc2005_disable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tsc2005 *ts = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%u\n", ts->disabled);
+}
+
+static ssize_t tsc2005_disable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct tsc2005 *ts = dev_get_drvdata(dev);
+ unsigned long res;
+ int i;
+
+ if (strict_strtoul(buf, 10, &res) < 0)
+ return -EINVAL;
+ i = res ? 1 : 0;
+
+ mutex_lock(&ts->mutex);
+ if (i == ts->disabled)
+ goto out;
+ ts->disabled = i;
+ if (i)
+ tsc2005_disable(ts);
+ else
+ tsc2005_enable(ts);
+out:
+ mutex_unlock(&ts->mutex);
+ return count;
+}
+static DEVICE_ATTR(disable, 0664, tsc2005_disable_show, tsc2005_disable_store);
+
+static ssize_t tsc2005_selftest_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct tsc2005 *ts = dev_get_drvdata(dev);
+ u16 temp_high;
+ u16 temp_high_orig;
+ u16 temp_high_test;
+ unsigned int result;
+
+ if (!ts->set_reset) {
+ dev_warn(&ts->spi->dev,
+ "unable to selftest: no reset function\n");
+ result = 0;
+ goto out;
+ }
+
+ mutex_lock(&ts->mutex);
+
+ /*
+ * Test TSC2005 communications via temp high register.
+ */
+ tsc2005_disable(ts);
+ result = 1;
+ tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high_orig);
+ temp_high_test = (temp_high_orig - 1) & MAX_12BIT;
+ tsc2005_write(ts, TSC2005_REG_TEMP_HIGH, temp_high_test);
+ tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high);
+ if (temp_high != temp_high_test) {
+ dev_warn(dev, "selftest failed: %d != %d\n",
+ temp_high, temp_high_test);
+ result = 0;
+ }
+
+ /* hardware reset */
+ ts->set_reset(0);
+ msleep(1); /* only 10us required */
+ ts->set_reset(1);
+ tsc2005_enable(ts);
+
+ /* test that the reset really happened */
+ tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high);
+ if (temp_high != temp_high_orig) {
+ dev_warn(dev, "selftest failed after reset: %d != %d\n",
+ temp_high, temp_high_orig);
+ result = 0;
+ }
+
+ mutex_unlock(&ts->mutex);
+
+out:
+ return sprintf(buf, "%u\n", result);
+}
+static DEVICE_ATTR(selftest, S_IRUGO, tsc2005_selftest_show, NULL);
+
+static void tsc2005_esd_timer(unsigned long data)
+{
+ struct tsc2005 *ts = (struct tsc2005 *)data;
+
+ schedule_work(&ts->esd_work);
+}
+
+static void tsc2005_esd_work(struct work_struct *work)
+{
+ struct tsc2005 *ts = container_of(work, struct tsc2005, esd_work);
+ u16 r;
+
+ mutex_lock(&ts->mutex);
+
+ if (ts->disable_depth)
+ goto out;
+
+ /*
+ * If we cannot read our known value from configuration register 0 then
+ * reset the controller as if from power-up and start scanning again.
+ */
+ tsc2005_read(ts, TSC2005_REG_CFR0, &r);
+ if ((r ^ TSC2005_CFR0_INITVALUE) & TSC2005_CFR0_RW_MASK) {
+ dev_info(&ts->spi->dev, "TSC2005 not responding - resetting\n");
+ ts->set_reset(0);
+ msleep(1); /* only 10us required */
+ ts->set_reset(1);
+ tsc2005_start_scan(ts);
+ }
+
+ /* re-arm the watchdog */
+ mod_timer(&ts->esd_timer,
+ round_jiffies(jiffies + msecs_to_jiffies(ts->esd_timeout)));
+
+out:
+ mutex_unlock(&ts->mutex);
+}
+
+static void __devinit tsc2005_setup_spi_xfer(struct tsc2005 *ts)
+{
+ tsc2005_setup_read(&ts->spi_x, TSC2005_REG_X, 0);
+ tsc2005_setup_read(&ts->spi_y, TSC2005_REG_Y, 0);
+ tsc2005_setup_read(&ts->spi_z1, TSC2005_REG_Z1, 0);
+ tsc2005_setup_read(&ts->spi_z2, TSC2005_REG_Z2, 1);
+
+ spi_message_init(&ts->spi_read_msg);
+ spi_message_add_tail(&ts->spi_x.spi_xfer, &ts->spi_read_msg);
+ spi_message_add_tail(&ts->spi_y.spi_xfer, &ts->spi_read_msg);
+ spi_message_add_tail(&ts->spi_z1.spi_xfer, &ts->spi_read_msg);
+ spi_message_add_tail(&ts->spi_z2.spi_xfer, &ts->spi_read_msg);
+}
+
+static struct attribute *tsc2005_attrs[] = {
+ &dev_attr_disable.attr,
+ &dev_attr_selftest.attr,
+ NULL
+};
+
+static struct attribute_group tsc2005_attr_group = {
+ .attrs = tsc2005_attrs,
+};
+
+static int __devinit tsc2005_setup(struct tsc2005 *ts,
+ struct tsc2005_platform_data *pdata)
+{
+ int r;
+ int fudge_x;
+ int fudge_y;
+ int fudge_p;
+ int p_max;
+ int x_max;
+ int y_max;
+
+ mutex_init(&ts->mutex);
+
+ tsc2005_setup_spi_xfer(ts);
+
+ init_timer(&ts->penup_timer);
+ setup_timer(&ts->penup_timer, tsc2005_penup_timer, (unsigned long)ts);
+ INIT_WORK(&ts->penup_work, tsc2005_penup_work);
+
+ fudge_x = pdata->ts_x_fudge ? : 0;
+ fudge_y = pdata->ts_y_fudge ? : 0;
+ fudge_p = pdata->ts_pressure_fudge ? : 0;
+ x_max = pdata->ts_x_max ? : MAX_12BIT;
+ y_max = pdata->ts_y_max ? : MAX_12BIT;
+ p_max = pdata->ts_pressure_max ? : MAX_12BIT;
+ ts->x_plate_ohm = pdata->ts_x_plate_ohm ? : 0;
+ ts->esd_timeout = pdata->esd_timeout_ms;
+ ts->set_reset = pdata->set_reset;
+
+ ts->idev = input_allocate_device();
+ if (ts->idev == NULL)
+ return -ENOMEM;
+ ts->idev->name = "TSC2005 touchscreen";
+ snprintf(ts->phys, sizeof(ts->phys), "%s/input-ts",
+ dev_name(&ts->spi->dev));
+ ts->idev->phys = ts->phys;
+ ts->idev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY);
+ ts->idev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);
+ ts->idev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+ input_set_abs_params(ts->idev, ABS_X, 0, x_max, fudge_x, 0);
+ input_set_abs_params(ts->idev, ABS_Y, 0, y_max, fudge_y, 0);
+ input_set_abs_params(ts->idev, ABS_PRESSURE, 0, p_max, fudge_p, 0);
+
+ r = request_threaded_irq(ts->spi->irq, tsc2005_irq_handler,
+ tsc2005_irq_thread, IRQF_TRIGGER_RISING,
+ "tsc2005", ts);
+ if (r) {
+ dev_err(&ts->spi->dev, "request_threaded_irq(): %d\n", r);
+ goto err1;
+ }
+ set_irq_wake(ts->spi->irq, 1);
+
+ r = input_register_device(ts->idev);
+ if (r) {
+ dev_err(&ts->spi->dev, "input_register_device(): %d\n", r);
+ goto err2;
+ }
+
+ r = sysfs_create_group(&ts->spi->dev.kobj, &tsc2005_attr_group);
+ if (r)
+ dev_warn(&ts->spi->dev, "sysfs entry creation failed: %d\n", r);
+
+ tsc2005_start_scan(ts);
+
+ if (!ts->esd_timeout || !ts->set_reset)
+ goto done;
+
+ /* start the optional ESD watchdog */
+ setup_timer(&ts->esd_timer, tsc2005_esd_timer, (unsigned long)ts);
+ INIT_WORK(&ts->esd_work, tsc2005_esd_work);
+ mod_timer(&ts->esd_timer,
+ round_jiffies(jiffies + msecs_to_jiffies(ts->esd_timeout)));
+
+done:
+ return 0;
+
+err2:
+ free_irq(ts->spi->irq, ts);
+
+err1:
+ input_free_device(ts->idev);
+ return r;
+}
+
+static int __devinit tsc2005_probe(struct spi_device *spi)
+{
+ struct tsc2005_platform_data *pdata = spi->dev.platform_data;
+ struct tsc2005 *ts;
+ int r;
+
+ if (spi->irq < 0) {
+ dev_dbg(&spi->dev, "no irq\n");
+ return -ENODEV;
+ }
+
+ if (!pdata) {
+ dev_dbg(&spi->dev, "no platform data\n");
+ return -ENODEV;
+ }
+
+ ts = kzalloc(sizeof(*ts), GFP_KERNEL);
+ if (ts == NULL)
+ return -ENOMEM;
+
+ dev_set_drvdata(&spi->dev, ts);
+ ts->spi = spi;
+ spi->dev.power.power_state = PMSG_ON;
+ spi->mode = SPI_MODE_0;
+ spi->bits_per_word = 8;
+ if (!spi->max_speed_hz)
+ spi->max_speed_hz = TSC2005_SPI_MAX_SPEED_HZ;
+ spi_setup(spi);
+
+ r = tsc2005_setup(ts, pdata);
+ if (r)
+ kfree(ts);
+ return r;
+}
+
+static int __devexit tsc2005_remove(struct spi_device *spi)
+{
+ struct tsc2005 *ts = dev_get_drvdata(&spi->dev);
+
+ mutex_lock(&ts->mutex);
+ tsc2005_disable(ts);
+ mutex_unlock(&ts->mutex);
+
+ if (ts->esd_timeout)
+ del_timer_sync(&ts->esd_timer);
+ del_timer_sync(&ts->penup_timer);
+
+ flush_work(&ts->esd_work);
+ flush_work(&ts->penup_work);
+
+ sysfs_remove_group(&ts->spi->dev.kobj, &tsc2005_attr_group);
+ free_irq(ts->spi->irq, ts);
+ input_unregister_device(ts->idev);
+ kfree(ts);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int tsc2005_suspend(struct spi_device *spi, pm_message_t mesg)
+{
+ struct tsc2005 *ts = dev_get_drvdata(&spi->dev);
+
+ mutex_lock(&ts->mutex);
+ tsc2005_disable(ts);
+ mutex_unlock(&ts->mutex);
+
+ return 0;
+}
+
+static int tsc2005_resume(struct spi_device *spi)
+{
+ struct tsc2005 *ts = dev_get_drvdata(&spi->dev);
+
+ mutex_lock(&ts->mutex);
+ tsc2005_enable(ts);
+ mutex_unlock(&ts->mutex);
+
+ return 0;
+}
+#endif
+
+static struct spi_driver tsc2005_driver = {
+ .driver = {
+ .name = "tsc2005",
+ .owner = THIS_MODULE,
+ },
+#ifdef CONFIG_PM
+ .suspend = tsc2005_suspend,
+ .resume = tsc2005_resume,
+#endif
+ .probe = tsc2005_probe,
+ .remove = __devexit_p(tsc2005_remove),
+};
+
+static int __init tsc2005_init(void)
+{
+ printk(KERN_INFO "TSC2005 driver initializing\n");
+ return spi_register_driver(&tsc2005_driver);
+}
+module_init(tsc2005_init);
+
+static void __exit tsc2005_exit(void)
+{
+ spi_unregister_driver(&tsc2005_driver);
+}
+module_exit(tsc2005_exit);
+
+MODULE_AUTHOR("Lauri Leukkunen <lauri.leukkunen@nokia.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:tsc2005");
diff --git a/include/linux/spi/tsc2005.h b/include/linux/spi/tsc2005.h
new file mode 100644
index 0000000..d9b0c84
--- /dev/null
+++ b/include/linux/spi/tsc2005.h
@@ -0,0 +1,41 @@
+/*
+ * This file is part of TSC2005 touchscreen driver
+ *
+ * Copyright (C) 2009-2010 Nokia Corporation
+ *
+ * Contact: Aaro Koskinen <aaro.koskinen@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _LINUX_SPI_TSC2005_H
+#define _LINUX_SPI_TSC2005_H
+
+#include <linux/types.h>
+
+struct tsc2005_platform_data {
+ int ts_pressure_max;
+ int ts_pressure_fudge;
+ int ts_x_max;
+ int ts_x_fudge;
+ int ts_y_max;
+ int ts_y_fudge;
+ int ts_x_plate_ohm;
+ unsigned int esd_timeout_ms;
+ void (*set_reset)(bool enable);
+};
+
+#endif
--
1.6.0.4

View File

@ -0,0 +1,122 @@
From fa1d43818de208bdc2fd789777c538ab4aa7956a Mon Sep 17 00:00:00 2001
From: Aaro Koskinen <Aaro.Koskinen@nokia.com>
Date: Fri, 12 Mar 2010 16:54:34 +0000
Subject: [PATCH 8/10] omap: rx-51: enable tsc2005
Patch-mainline: 2.6.35
Discussions: http://www.mail-archive.com/linux-omap@vger.kernel.org/msg26749.html
Enable TSC2005 touchscreen driver on the RX-51 board.
Signed-off-by: Aaro Koskinen <aaro.koskinen@nokia.com>
---
arch/arm/configs/rx51_defconfig | 1
arch/arm/mach-omap2/board-rx51-peripherals.c | 46 +++++++++++++++++++++++++--
2 files changed, 45 insertions(+), 2 deletions(-)
Index: linux-2.6.33-master/arch/arm/configs/rx51_defconfig
===================================================================
--- linux-2.6.33-master.orig/arch/arm/configs/rx51_defconfig 2010-04-19 17:28:20.000000000 +0300
+++ linux-2.6.33-master/arch/arm/configs/rx51_defconfig 2010-04-19 17:28:28.000000000 +0300
@@ -801,6 +801,7 @@
# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
+CONFIG_TOUCHSCREEN_TSC2005=m
# CONFIG_TOUCHSCREEN_TSC2007 is not set
CONFIG_INPUT_MISC=y
# CONFIG_INPUT_ATI_REMOTE is not set
Index: linux-2.6.33-master/arch/arm/mach-omap2/board-rx51-peripherals.c
===================================================================
--- linux-2.6.33-master.orig/arch/arm/mach-omap2/board-rx51-peripherals.c 2010-04-19 17:28:20.000000000 +0300
+++ linux-2.6.33-master/arch/arm/mach-omap2/board-rx51-peripherals.c 2010-04-19 17:28:28.000000000 +0300
@@ -14,6 +14,7 @@
#include <linux/input.h>
#include <linux/input/matrix_keypad.h>
#include <linux/spi/spi.h>
+#include <linux/spi/tsc2005.h>
#include <linux/spi/wl12xx.h>
#include <linux/i2c.h>
#include <linux/i2c/twl.h>
@@ -42,6 +43,9 @@
#define RX51_WL1251_POWER_GPIO 87
#define RX51_WL1251_IRQ_GPIO 42
+#define RX51_TSC2005_RESET_GPIO 104
+#define RX51_TSC2005_IRQ_GPIO 100
+
/* list all spi devices here */
enum {
RX51_SPI_WL1251,
@@ -50,6 +54,7 @@
};
static struct wl12xx_platform_data wl1251_pdata;
+static struct tsc2005_platform_data tsc2005_pdata;
static struct omap2_mcspi_device_config wl1251_mcspi_config = {
.turbo_mode = 0,
@@ -87,10 +92,10 @@
.modalias = "tsc2005",
.bus_num = 1,
.chip_select = 0,
- /* .irq = OMAP_GPIO_IRQ(RX51_TSC2005_IRQ_GPIO),*/
+ .irq = OMAP_GPIO_IRQ(RX51_TSC2005_IRQ_GPIO),
.max_speed_hz = 6000000,
.controller_data = &tsc2005_mcspi_config,
- /* .platform_data = &tsc2005_config,*/
+ .platform_data = &tsc2005_pdata,
},
};
@@ -708,6 +713,42 @@
#endif
+static struct tsc2005_platform_data tsc2005_pdata = {
+ .ts_pressure_max = 2048,
+ .ts_pressure_fudge = 2,
+ .ts_x_max = 4096,
+ .ts_x_fudge = 4,
+ .ts_y_max = 4096,
+ .ts_y_fudge = 7,
+ .ts_x_plate_ohm = 280,
+ .esd_timeout_ms = 8000,
+};
+
+static void rx51_tsc2005_set_reset(bool enable)
+{
+ gpio_set_value(RX51_TSC2005_RESET_GPIO, enable);
+}
+
+static void __init rx51_init_tsc2005(void)
+{
+ int r;
+
+ r = gpio_request(RX51_TSC2005_IRQ_GPIO, "tsc2005 IRQ");
+ if (r >= 0)
+ gpio_direction_input(RX51_TSC2005_IRQ_GPIO);
+ else
+ printk(KERN_ERR "unable to get %s GPIO\n", "tsc2005 IRQ");
+
+ r = gpio_request(RX51_TSC2005_RESET_GPIO, "tsc2005 reset");
+ if (r >= 0) {
+ gpio_direction_output(RX51_TSC2005_RESET_GPIO, 1);
+ tsc2005_pdata.set_reset = rx51_tsc2005_set_reset;
+ } else {
+ printk(KERN_ERR "unable to get %s GPIO\n", "tsc2005 reset");
+ tsc2005_pdata.esd_timeout_ms = 0;
+ }
+}
+
#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
static struct omap_smc91x_platform_data board_smc91x_data = {
@@ -792,6 +833,7 @@
board_smc91x_init();
rx51_add_gpio_keys();
rx51_init_wl1251();
+ rx51_init_tsc2005();
spi_register_board_info(rx51_peripherals_spi_board_info,
ARRAY_SIZE(rx51_peripherals_spi_board_info));
}

View File

@ -0,0 +1,247 @@
From 4e4f10f6498bc5038c0a110b5f21682fcb5578d7 Mon Sep 17 00:00:00 2001
From: David Woodhouse <dwmw2@infradead.org>
Date: Fri, 2 Apr 2010 01:05:56 +0000
Subject: [PATCH] phylib: Add module table to all existing phy drivers
Patch-mainline: 2.6.35
Git-commit: 8626d3b4328061f5b82b11ae1d6918a0c3602f42
Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6.git
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Yin Kangkai <kangkai.yin@intel.com>
---
drivers/net/phy/bcm63xx.c | 8 ++++++++
drivers/net/phy/broadcom.c | 17 +++++++++++++++++
drivers/net/phy/cicada.c | 8 ++++++++
drivers/net/phy/davicom.c | 9 +++++++++
drivers/net/phy/et1011c.c | 7 +++++++
drivers/net/phy/icplus.c | 7 +++++++
drivers/net/phy/lxt.c | 8 ++++++++
drivers/net/phy/marvell.c | 13 +++++++++++++
drivers/net/phy/national.c | 7 +++++++
drivers/net/phy/qsemi.c | 7 +++++++
drivers/net/phy/realtek.c | 7 +++++++
drivers/net/phy/smsc.c | 11 +++++++++++
drivers/net/phy/ste10Xp.c | 8 ++++++++
drivers/net/phy/vitesse.c | 8 ++++++++
14 files changed, 125 insertions(+)
--- a/drivers/net/phy/bcm63xx.c
+++ b/drivers/net/phy/bcm63xx.c
@@ -130,3 +130,11 @@ static void __exit bcm63xx_phy_exit(void
module_init(bcm63xx_phy_init);
module_exit(bcm63xx_phy_exit);
+
+static struct mdio_device_id bcm63xx_tbl[] = {
+ { 0x00406000, 0xfffffc00 },
+ { 0x002bdc00, 0xfffffc00 },
+ { }
+};
+
+MODULE_DEVICE_TABLE(mdio, bcm64xx_tbl);
--- a/drivers/net/phy/broadcom.c
+++ b/drivers/net/phy/broadcom.c
@@ -21,6 +21,7 @@
#define PHY_ID_BCM50610 0x0143bd60
#define PHY_ID_BCM50610M 0x0143bd70
#define PHY_ID_BCM57780 0x03625d90
+#define PHY_ID_BCMAC131 0x0143bc70
#define BRCM_PHY_MODEL(phydev) \
((phydev)->drv->phy_id & (phydev)->drv->phy_id_mask)
@@ -911,3 +912,19 @@ static void __exit broadcom_exit(void)
module_init(broadcom_init);
module_exit(broadcom_exit);
+
+static struct mdio_device_id broadcom_tbl[] = {
+ { 0x00206070, 0xfffffff0 },
+ { 0x002060e0, 0xfffffff0 },
+ { 0x002060c0, 0xfffffff0 },
+ { 0x002060b0, 0xfffffff0 },
+ { 0x0143bca0, 0xfffffff0 },
+ { 0x0143bcb0, 0xfffffff0 },
+ { PHY_ID_BCM50610, 0xfffffff0 },
+ { PHY_ID_BCM50610M, 0xfffffff0 },
+ { PHY_ID_BCM57780, 0xfffffff0 },
+ { PHY_ID_BCMAC131, 0xfffffff0 },
+ { }
+};
+
+MODULE_DEVICE_TABLE(mdio, broadcom_tbl);
--- a/drivers/net/phy/cicada.c
+++ b/drivers/net/phy/cicada.c
@@ -159,3 +159,11 @@ static void __exit cicada_exit(void)
module_init(cicada_init);
module_exit(cicada_exit);
+
+static struct mdio_device_id cicada_tbl[] = {
+ { 0x000fc410, 0x000ffff0 },
+ { 0x000fc440, 0x000fffc0 },
+ { }
+};
+
+MODULE_DEVICE_TABLE(mdio, cicada_tbl);
--- a/drivers/net/phy/davicom.c
+++ b/drivers/net/phy/davicom.c
@@ -219,3 +219,12 @@ static void __exit davicom_exit(void)
module_init(davicom_init);
module_exit(davicom_exit);
+
+static struct mdio_device_id davicom_tbl[] = {
+ { 0x0181b880, 0x0ffffff0 },
+ { 0x0181b8a0, 0x0ffffff0 },
+ { 0x00181b80, 0x0ffffff0 },
+ { }
+};
+
+MODULE_DEVICE_TABLE(mdio, davicom_tbl);
--- a/drivers/net/phy/et1011c.c
+++ b/drivers/net/phy/et1011c.c
@@ -111,3 +111,10 @@ static void __exit et1011c_exit(void)
module_init(et1011c_init);
module_exit(et1011c_exit);
+
+static struct mdio_device_id et1011c_tbl[] = {
+ { 0x0282f014, 0xfffffff0 },
+ { }
+};
+
+MODULE_DEVICE_TABLE(mdio, et1011c_tbl);
--- a/drivers/net/phy/icplus.c
+++ b/drivers/net/phy/icplus.c
@@ -132,3 +132,10 @@ static void __exit ip175c_exit(void)
module_init(ip175c_init);
module_exit(ip175c_exit);
+
+static struct mdio_device_id icplus_tbl[] = {
+ { 0x02430d80, 0x0ffffff0 },
+ { }
+};
+
+MODULE_DEVICE_TABLE(mdio, icplus_tbl);
--- a/drivers/net/phy/lxt.c
+++ b/drivers/net/phy/lxt.c
@@ -174,3 +174,11 @@ static void __exit lxt_exit(void)
module_init(lxt_init);
module_exit(lxt_exit);
+
+static struct mdio_device_id lxt_tbl[] = {
+ { 0x78100000, 0xfffffff0 },
+ { 0x001378e0, 0xfffffff0 },
+ { }
+};
+
+MODULE_DEVICE_TABLE(mdio, lxt_tbl);
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -611,3 +611,16 @@ static void __exit marvell_exit(void)
module_init(marvell_init);
module_exit(marvell_exit);
+
+static struct mdio_device_id marvell_tbl[] = {
+ { 0x01410c60, 0xfffffff0 },
+ { 0x01410c90, 0xfffffff0 },
+ { 0x01410cc0, 0xfffffff0 },
+ { 0x01410e10, 0xfffffff0 },
+ { 0x01410cb0, 0xfffffff0 },
+ { 0x01410cd0, 0xfffffff0 },
+ { 0x01410e30, 0xfffffff0 },
+ { }
+};
+
+MODULE_DEVICE_TABLE(mdio, marvell_tbl);
--- a/drivers/net/phy/national.c
+++ b/drivers/net/phy/national.c
@@ -153,3 +153,10 @@ MODULE_LICENSE("GPL");
module_init(ns_init);
module_exit(ns_exit);
+
+static struct mdio_device_id ns_tbl[] = {
+ { DP83865_PHY_ID, 0xfffffff0 },
+ { }
+};
+
+MODULE_DEVICE_TABLE(mdio, ns_tbl);
--- a/drivers/net/phy/qsemi.c
+++ b/drivers/net/phy/qsemi.c
@@ -138,3 +138,10 @@ static void __exit qs6612_exit(void)
module_init(qs6612_init);
module_exit(qs6612_exit);
+
+static struct mdio_device_id qs6612_tbl[] = {
+ { 0x00181440, 0xfffffff0 },
+ { }
+};
+
+MODULE_DEVICE_TABLE(mdio, qs6612_tbl);
--- a/drivers/net/phy/realtek.c
+++ b/drivers/net/phy/realtek.c
@@ -78,3 +78,10 @@ static void __exit realtek_exit(void)
module_init(realtek_init);
module_exit(realtek_exit);
+
+static struct mdio_device_id realtek_tbl[] = {
+ { 0x001cc912, 0x001fffff },
+ { }
+};
+
+MODULE_DEVICE_TABLE(mdio, realtek_tbl);
--- a/drivers/net/phy/smsc.c
+++ b/drivers/net/phy/smsc.c
@@ -236,3 +236,14 @@ MODULE_LICENSE("GPL");
module_init(smsc_init);
module_exit(smsc_exit);
+
+static struct mdio_device_id smsc_tbl[] = {
+ { 0x0007c0a0, 0xfffffff0 },
+ { 0x0007c0b0, 0xfffffff0 },
+ { 0x0007c0c0, 0xfffffff0 },
+ { 0x0007c0d0, 0xfffffff0 },
+ { 0x0007c0f0, 0xfffffff0 },
+ { }
+};
+
+MODULE_DEVICE_TABLE(mdio, smsc_tbl);
--- a/drivers/net/phy/ste10Xp.c
+++ b/drivers/net/phy/ste10Xp.c
@@ -132,6 +132,14 @@ static void __exit ste10Xp_exit(void)
module_init(ste10Xp_init);
module_exit(ste10Xp_exit);
+static struct mdio_device_id ste10Xp_tbl[] = {
+ { STE101P_PHY_ID, 0xfffffff0 },
+ { STE100P_PHY_ID, 0xffffffff },
+ { }
+};
+
+MODULE_DEVICE_TABLE(mdio, ste10Xp_tbl);
+
MODULE_DESCRIPTION("STMicroelectronics STe10Xp PHY driver");
MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>");
MODULE_LICENSE("GPL");
--- a/drivers/net/phy/vitesse.c
+++ b/drivers/net/phy/vitesse.c
@@ -191,3 +191,11 @@ static void __exit vsc82xx_exit(void)
module_init(vsc82xx_init);
module_exit(vsc82xx_exit);
+
+static struct mdio_device_id vitesse_tbl[] = {
+ { PHY_ID_VSC8244, 0x000fffc0 },
+ { PHY_ID_VSC8221, 0x000ffff0 },
+ { }
+};
+
+MODULE_DEVICE_TABLE(mdio, vitesse_tbl);

View File

@ -0,0 +1,150 @@
From 8626d3b4328061f5b82b11ae1d6918a0c3602f42 Mon Sep 17 00:00:00 2001
From: David Woodhouse <dwmw2@infradead.org>
Date: Fri, 2 Apr 2010 01:05:27 +0000
Subject: [PATCH] phylib: Support phy module autoloading
Patch-mainline: 2.6.35
Git-commit: 8626d3b4328061f5b82b11ae1d6918a0c3602f42
Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6.git
We don't use the normal hotplug mechanism because it doesn't work. It will
load the module some time after the device appears, but that's not good
enough for us -- we need the driver loaded _immediately_ because otherwise
the NIC driver may just abort and then the phy 'device' goes away.
[bwh: s/phy/mdio/ in module alias, kerneldoc for struct mdio_device_id]
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Acked-by: Andy Fleming <afleming@freescale.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/phy/phy_device.c | 12 ++++++++++++
include/linux/mod_devicetable.h | 26 ++++++++++++++++++++++++++
include/linux/phy.h | 1 +
scripts/mod/file2alias.c | 26 ++++++++++++++++++++++++++
4 files changed, 65 insertions(+), 0 deletions(-)
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index db17945..1a99bb2 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -149,6 +149,7 @@ EXPORT_SYMBOL(phy_scan_fixups);
struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id)
{
struct phy_device *dev;
+
/* We allocate the device, and initialize the
* default values */
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
@@ -179,6 +180,17 @@ struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id)
mutex_init(&dev->lock);
INIT_DELAYED_WORK(&dev->state_queue, phy_state_machine);
+ /* Request the appropriate module unconditionally; don't
+ bother trying to do so only if it isn't already loaded,
+ because that gets complicated. A hotplug event would have
+ done an unconditional modprobe anyway.
+ We don't do normal hotplug because it won't work for MDIO
+ -- because it relies on the device staying around for long
+ enough for the driver to get loaded. With MDIO, the NIC
+ driver will get bored and give up as soon as it finds that
+ there's no driver _already_ loaded. */
+ request_module(MDIO_MODULE_PREFIX MDIO_ID_FMT, MDIO_ID_ARGS(phy_id));
+
return dev;
}
EXPORT_SYMBOL(phy_device_create);
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index f58e9d8..55f1f9c 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -474,4 +474,30 @@ struct platform_device_id {
__attribute__((aligned(sizeof(kernel_ulong_t))));
};
+#define MDIO_MODULE_PREFIX "mdio:"
+
+#define MDIO_ID_FMT "%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d"
+#define MDIO_ID_ARGS(_id) \
+ (_id)>>31, ((_id)>>30) & 1, ((_id)>>29) & 1, ((_id)>>28) & 1, \
+ ((_id)>>27) & 1, ((_id)>>26) & 1, ((_id)>>25) & 1, ((_id)>>24) & 1, \
+ ((_id)>>23) & 1, ((_id)>>22) & 1, ((_id)>>21) & 1, ((_id)>>20) & 1, \
+ ((_id)>>19) & 1, ((_id)>>18) & 1, ((_id)>>17) & 1, ((_id)>>16) & 1, \
+ ((_id)>>15) & 1, ((_id)>>14) & 1, ((_id)>>13) & 1, ((_id)>>12) & 1, \
+ ((_id)>>11) & 1, ((_id)>>10) & 1, ((_id)>>9) & 1, ((_id)>>8) & 1, \
+ ((_id)>>7) & 1, ((_id)>>6) & 1, ((_id)>>5) & 1, ((_id)>>4) & 1, \
+ ((_id)>>3) & 1, ((_id)>>2) & 1, ((_id)>>1) & 1, (_id) & 1
+
+/**
+ * struct mdio_device_id - identifies PHY devices on an MDIO/MII bus
+ * @phy_id: The result of
+ * (mdio_read(&MII_PHYSID1) << 16 | mdio_read(&PHYSID2)) & @phy_id_mask
+ * for this PHY type
+ * @phy_id_mask: Defines the significant bits of @phy_id. A value of 0
+ * is used to terminate an array of struct mdio_device_id.
+ */
+struct mdio_device_id {
+ __u32 phy_id;
+ __u32 phy_id_mask;
+};
+
#endif /* LINUX_MOD_DEVICETABLE_H */
diff --git a/include/linux/phy.h b/include/linux/phy.h
index d9bce4b..987e111 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -24,6 +24,7 @@
#include <linux/mii.h>
#include <linux/timer.h>
#include <linux/workqueue.h>
+#include <linux/mod_devicetable.h>
#include <asm/atomic.h>
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index 220213e..36a60a8 100644
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -796,6 +796,28 @@ static int do_platform_entry(const char *filename,
return 1;
}
+static int do_mdio_entry(const char *filename,
+ struct mdio_device_id *id, char *alias)
+{
+ int i;
+
+ alias += sprintf(alias, MDIO_MODULE_PREFIX);
+
+ for (i = 0; i < 32; i++) {
+ if (!((id->phy_id_mask >> (31-i)) & 1))
+ *(alias++) = '?';
+ else if ((id->phy_id >> (31-i)) & 1)
+ *(alias++) = '1';
+ else
+ *(alias++) = '0';
+ }
+
+ /* Terminate the string */
+ *alias = 0;
+
+ return 1;
+}
+
/* Ignore any prefix, eg. some architectures prepend _ */
static inline int sym_is(const char *symbol, const char *name)
{
@@ -943,6 +965,10 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
do_table(symval, sym->st_size,
sizeof(struct platform_device_id), "platform",
do_platform_entry, mod);
+ else if (sym_is(symname, "__mod_mdio_device_table"))
+ do_table(symval, sym->st_size,
+ sizeof(struct mdio_device_id), "mdio",
+ do_mdio_entry, mod);
free(zeros);
}
--
1.6.5

View File

@ -0,0 +1,52 @@
Toggling the link carrier is a non sense and is the grossest locking I can
think of. Moreover, it's giving a completely inaccurate status to userspace
who could for example decide to turn the interface down on carrier off
detection.
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
---
drivers/staging/rtl8192e/ieee80211/ieee80211_softmac_wx.c | 2 --
drivers/staging/rtl8192e/r8192E_core.c | 1 -
2 files changed, 3 deletions(-)
Index: b/drivers/staging/rtl8192e/ieee80211/ieee80211_softmac_wx.c
===================================================================
--- a/drivers/staging/rtl8192e/ieee80211/ieee80211_softmac_wx.c 2010-01-15 19:31:39.000000000 +0100
+++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_softmac_wx.c 2010-01-15 19:32:07.000000000 +0100
@@ -326,7 +326,6 @@ void ieee80211_wx_sync_scan_wq(struct ie
int b40M = 0;
static int count = 0;
chan = ieee->current_network.channel;
- netif_carrier_off(ieee->dev);
if (ieee->data_hard_stop)
ieee->data_hard_stop(ieee->dev);
@@ -372,7 +371,6 @@ void ieee80211_wx_sync_scan_wq(struct ie
if(ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER)
ieee80211_start_send_beacons(ieee);
- netif_carrier_on(ieee->dev);
count = 0;
up(&ieee->wx_sem);
Index: b/drivers/staging/rtl8192e/r8192E_core.c
===================================================================
--- a/drivers/staging/rtl8192e/r8192E_core.c 2010-01-15 20:03:06.000000000 +0100
+++ b/drivers/staging/rtl8192e/r8192E_core.c 2010-01-15 20:03:11.000000000 +0100
@@ -4046,7 +4046,6 @@ RESET_START:
del_timer_sync(&ieee->associate_timer);
cancel_delayed_work(&ieee->associate_retry_wq);
ieee80211_stop_scan(ieee);
- netif_carrier_off(dev);
up(&ieee->wx_sem);
}
else{
--
Intel Open Source Technology Centre
http://oss.intel.com/
_______________________________________________
Moblin-kernel mailing list
Moblin-kernel@linux.intel.com
http://linux.intel.com/mailman/listinfo/moblin-kernel

View File

@ -0,0 +1,40 @@
If we're not associated, we should not send wireless events to let userspace
know that we just left an ESSID, simply because we havent yet joined it.
If we keep on doing that, wpa_supplicant could receive such events while
actually trying to join an ESSID, and thus decide to stop trying. This leads
to a lot of connection failures as this driver seems to be sending GIWAP
events quite a lot.
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
---
drivers/staging/rtl8192e/ieee80211/ieee80211_softmac.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
Index: b/drivers/staging/rtl8192e/ieee80211/ieee80211_softmac.c
===================================================================
--- a/drivers/staging/rtl8192e/ieee80211/ieee80211_softmac.c 2010-01-15 16:57:48.000000000 +0100
+++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_softmac.c 2010-01-15 19:31:56.000000000 +0100
@@ -2726,11 +2726,12 @@ void ieee80211_disassociate(struct ieee8
if(IS_DOT11D_ENABLE(ieee))
Dot11d_Reset(ieee);
#endif
- ieee->state = IEEE80211_NOLINK;
ieee->is_set_key = false;
ieee->link_change(ieee->dev);
//HTSetConnectBwMode(ieee, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT);
- notify_wx_assoc_event(ieee);
+ if (ieee->state == IEEE80211_LINKED)
+ notify_wx_assoc_event(ieee);
+ ieee->state = IEEE80211_NOLINK;
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
--
Intel Open Source Technology Centre
http://oss.intel.com/
_______________________________________________
Moblin-kernel mailing list
Moblin-kernel@linux.intel.com
http://linux.intel.com/mailman/listinfo/moblin-kernel

View File

@ -0,0 +1,41 @@
Getting a probe response after sending a probe request to a specific SSID
doesnt mean we're trying to associate with this SSID.
wpa_supplicant should be the only one deciding when to join an SSID, not the
kernel.
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
---
drivers/staging/rtl8192e/ieee80211/ieee80211_rx.c | 4 ----
1 file changed, 4 deletions(-)
Index: b/drivers/staging/rtl8192e/ieee80211/ieee80211_rx.c
===================================================================
--- a/drivers/staging/rtl8192e/ieee80211/ieee80211_rx.c 2010-01-15 16:56:47.000000000 +0100
+++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_rx.c 2010-01-15 16:57:03.000000000 +0100
@@ -2716,8 +2716,6 @@ static inline void ieee80211_process_pro
#endif
memcpy(target, &network, sizeof(*target));
list_add_tail(&target->list, &ieee->network_list);
- if(ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE)
- ieee80211_softmac_new_net(ieee,&network);
} else {
IEEE80211_DEBUG_SCAN("Updating '%s' (" MAC_FMT ") via %s.\n",
escape_essid(target->ssid,
@@ -2744,8 +2742,6 @@ static inline void ieee80211_process_pro
//YJ,add,080819,for hidden ap,end
update_network(target, &network);
- if(renew && (ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE))
- ieee80211_softmac_new_net(ieee,&network);
}
spin_unlock_irqrestore(&ieee->lock, flags);
--
Intel Open Source Technology Centre
http://oss.intel.com/
_______________________________________________
Moblin-kernel mailing list
Moblin-kernel@linux.intel.com
http://linux.intel.com/mailman/listinfo/moblin-kernel

View File

@ -0,0 +1,108 @@
require linux-moblin.inc
PR = "r0"
DEFAULT_PREFERENCE = "-1"
DEFAULT_PREFERENCE_netbook = "1"
SRC_URI = "${KERNELORG_MIRROR}/pub/linux/kernel/v2.6/linux-${PV}.tar.bz2 \
file://linux-2.6.29-dont-wait-for-mouse.patch;patch=1 \
file://linux-2.6.29-kms-after-sata.patch;patch=1 \
file://linux-2.6.29-kms-edid-cache.patch;patch=1 \
file://linux-2.6.29-kms-run-async.patch;patch=1 \
file://linux-2.6.29-silence-acer-message.patch;patch=1 \
file://linux-2.6.29-sreadahead.patch;patch=1 \
file://linux-2.6.31-silence-wacom.patch;patch=1 \
# file://linux-2.6.33-ahci-alpm-accounting.patch;patch=1 \
# file://linux-2.6.33-ahci-fix-oops-on-dummy-port.patch;patch=1 \
# file://linux-2.6.33-i2c-workaround-for-aava-koski-touchscreen.patch;patch=1 \
file://linux-2.6.33-rc8-timberdale.patch;patch=1 \
file://linux-2.6.33-rt2860-1-2.patch;patch=1 \
file://linux-2.6.33-rt2860-2-2.patch;patch=1 \
file://linux-2.6.33-timberdale-audio-fix.patch;patch=1 \
file://linux-2.6.33-vfs-tracepoints.patch;patch=1 \
file://linux-2.6.34-cando-dual-touch-driver.patch;patch=1 \
file://linux-2.6.34-CVE-tipc-Fix-oops-on-send-prior-to-entering-networked-mode.patch;patch=1 \
file://linux-2.6.34-cypress-touch-driver.patch;patch=1 \
file://linux-2.6.34-drm-i915-Ignore-LVDS-EDID-when-it-is-unavailabe-or-invalid.patch;patch=1 \
# file://linux-2.6.34-enable-hid-dg-contact-count-stantum-and-cando-touch-drivers.patch;patch=1 \
file://linux-2.6.34-fix-marvell-firmware-path.patch;patch=1 \
# file://linux-2.6.34-hack-to-fix-aava-camera-sensor-issue.patch;patch=1 \
file://linux-2.6.34-input-synaptics-clickpad-support.patch;patch=1 \
# # file://linux-2.6.34-moorestown-aava-specific-changes-no-audio.patch;patch=1 \
# # file://linux-2.6.34-moorestown-analog-accelerometer-driver.patch;patch=1 \
# file://linux-2.6.34-moorestown-audio-driver-6.0-1-8.patch;patch=1 \
# file://linux-2.6.34-moorestown-audio-driver-6.0-2-8.patch;patch=1 \
# file://linux-2.6.34-moorestown-audio-driver-6.0-3-8.patch;patch=1 \
# file://linux-2.6.34-moorestown-audio-driver-6.0-4-8.patch;patch=1 \
# file://linux-2.6.34-moorestown-audio-driver-6.0-5-8.patch;patch=1 \
# file://linux-2.6.34-moorestown-audio-driver-6.0-6-8.patch;patch=1 \
# file://linux-2.6.34-moorestown-audio-driver-6.0-7-8.patch;patch=1 \
# file://linux-2.6.34-moorestown-audio-driver-6.0-8-8.patch;patch=1 \
# # file://linux-2.6.34-moorestown-ericsson-mbm-driver.patch;patch=1 \
# # file://linux-2.6.34-moorestown-fix-hw-qh-prefetch-bug.patch;patch=1 \
# # file://linux-2.6.34-moorestown-gpe-fix-for-sensor.patch;patch=1 \
# # file://linux-2.6.34-moorestown-graphics-changes-for-aava-koski-dv1-hardware.patch;patch=1 \
# # file://linux-2.6.34-moorestown-gtm501l-driver-1.2.patch;patch=1 \
# # file://linux-2.6.34-moorestown-ifxgps-driver.patch;patch=1 \
# file://linux-2.6.34-moorestown-img-graphics-driver-5.3.0.0007.patch;patch=1 \
# # file://linux-2.6.34-moorestown-ipc-host-driver.patch;patch=1 \
# file://linux-2.6.34-moorestown-keypad-driver.patch;patch=1 \
# file://linux-2.6.34-moorestown-langwell-dma-driver-3.0.patch;patch=1 \
# file://linux-2.6.34-moorestown-mmc-driver-1.0.patch;patch=1 \
# file://linux-2.6.34-moorestown-nand-driver-2.0.patch;patch=1 \
# # file://linux-2.6.34-moorestown-only-enable-mrst-pciquirks-on-mrst.patch;patch=1 \
# file://linux-2.6.34-moorestown-platform-enabling.patch;patch=1 \
# file://linux-2.6.34-moorestown-pmic-battery-driver.patch;patch=1 \
# # file://linux-2.6.34-moorestown-rar-handler-driver-3.1.patch;patch=1 \
# file://linux-2.6.34-moorestown-sensor-driver-1.1.patch;patch=1 \
# file://linux-2.6.34-moorestown-spi-slave-controller-driver-1.1.patch;patch=1 \
# file://linux-2.6.34-moorestown-thermal-emc1403-driver.patch;patch=1 \
# file://linux-2.6.34-moorestown-touchscreen-driver.patch;patch=1 \
# file://linux-2.6.34-moorestown-usb-otg-and-still-image-driver.patch;patch=1 \
file://linux-2.6.34-multi-touch-input-driver-for-event-devices.patch;patch=1 \
file://linux-2.6.34-ondemand-fix-1-7.patch;patch=1 \
file://linux-2.6.34-ondemand-fix-2-7.patch;patch=1 \
file://linux-2.6.34-ondemand-fix-3-7.patch;patch=1 \
file://linux-2.6.34-ondemand-fix-4-7.patch;patch=1 \
file://linux-2.6.34-ondemand-fix-5-7.patch;patch=1 \
file://linux-2.6.34-ondemand-fix-6-7.patch;patch=1 \
file://linux-2.6.34-ondemand-fix-7-7.patch;patch=1 \
file://linux-2.6.34-pch-can.patch;patch=1 \
file://linux-2.6.34-pch-dma.patch;patch=1 \
file://linux-2.6.34-pch-gbe.patch;patch=1 \
file://linux-2.6.34-pch-gpio.patch;patch=1 \
file://linux-2.6.34-pch-i2c.patch;patch=1 \
file://linux-2.6.34-pch-ieee1588.patch;patch=1 \
file://linux-2.6.34-pch-pcieqos.patch;patch=1 \
file://linux-2.6.34-pch-spi.patch;patch=1 \
file://linux-2.6.34-pch-uart.patch;patch=1 \
file://linux-2.6.34-pch-usbdev.patch;patch=1 \
file://linux-2.6.34-rt2860-no-debug.patch;patch=1 \
# file://linux-2.6.34-stantum-and-mosart-multitouch-drivers.patch;patch=1 \
# file://linux-2.6.34-USB-gadget-introduce-g_nokia-gadget-driver.patch;patch=1 \
file://linux-2.6.34-USB-otg-add-notifier-support.patch;patch=1 \
file://linux-2.6.35-input-touchscreen-introduce-tsc2005-driver.patch;patch=1 \
# file://linux-2.6.35-moorestown-camera-driver-10.0-1-3.patch;patch=1 \
# file://linux-2.6.35-moorestown-camera-driver-10.0-2-3.patch;patch=1 \
# file://linux-2.6.35-moorestown-camera-driver-10.0-3-3.patch;patch=1 \
file://linux-2.6.35-OMAP-DSS2-Add-ACX565AKM-Panel-Driver.patch;patch=1 \
file://linux-2.6.35-OMAP-DSS2-Add-Kconfig-option-for-DPI-display-type.patch;patch=1 \
file://linux-2.6.35-OMAP-DSS2-Use-vdds_sdi-regulator-supply-in-SDI.patch;patch=1 \
file://linux-2.6.35-OMAP-RX51-Add-LCD-Panel-support.patch;patch=1 \
file://linux-2.6.35-OMAP-RX51-Add-Touch-Controller-in-SPI-board-info.patch;patch=1 \
file://linux-2.6.35-OMAP-RX51-Add-vdds_sdi-supply-voltage-for-SDI.patch;patch=1 \
file://linux-2.6.35-omap-rx-51-enable-tsc2005.patch;patch=1 \
file://linux-2.6.35-phylib-Add-module-table-to-all-existing-phy-drivers.patch;patch=1 \
file://linux-2.6.35-phylib-Support-phy-module-autoloading.patch;patch=1 \
file://linux-2.6-build-nonintconfig.patch;patch=1 \
file://linux-2.6-driver-level-usb-autosuspend.patch;patch=1 \
file://linux-2.6-usb-bt-autosuspend.patch;patch=1 \
file://linux-2.6-usb-uvc-autosuspend.patch;patch=1 \
file://rtl8192_carrier_off.patch;patch=1 \
file://rtl8192_no_autoconnect.patch;patch=1 \
file://rtl8192_no_WAP_unassoc.patch;patch=1 \
# file://defconfig-menlow \
file://defconfig-netbook"
S = "${WORKDIR}/linux-${PV}"