linux-omap: added support for BeagleBUG extension board
authorMarcin Juszkiewicz <marcin@buglabs.net>
Wed, 9 Sep 2009 08:55:18 +0000 (10:55 +0200)
committerMarcin Juszkiewicz <marcin@juszkiewicz.com.pl>
Wed, 9 Sep 2009 09:26:11 +0000 (11:26 +0200)
This is initial version of BeagleBUG extension board support. So far
boards are not available for people outside of BugLabs and Texas
Instruments companies.

Patch adds support for few modules but not all of them will build for
OMAP3 - some are still BUG only.

conf/machine/include/omap3.inc
recipes/linux/linux-omap-2.6.29/beagleboard/defconfig
recipes/linux/linux-omap-2.6.29/beaglebug/beaglebug-full.patch [new file with mode: 0644]
recipes/linux/linux-omap_2.6.29.bb

index 889e0f6..c52cbdd 100644 (file)
@@ -1,7 +1,7 @@
 require conf/machine/include/tune-cortexa8.inc
 PREFERRED_PROVIDER_virtual/kernel = "linux-omap"
 # Increase this everytime you change something in the kernel
-MACHINE_KERNEL_PR = "r44
+MACHINE_KERNEL_PR = "r45
 
 KERNEL_IMAGETYPE = "uImage"
 
index c9f8e99..a1848d5 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.29-omap1
-# Thu Aug 13 12:58:49 2009
+# Wed Sep  9 09:58:54 2009
 #
 CONFIG_ARM=y
 CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -249,6 +249,7 @@ CONFIG_ARM_THUMBEE=y
 # CONFIG_CPU_BPREDICT_DISABLE is not set
 CONFIG_HAS_TLS_REG=y
 # CONFIG_OUTER_CACHE is not set
+CONFIG_ARM_L1_CACHE_SHIFT=6
 
 #
 # Bus support
@@ -272,7 +273,7 @@ CONFIG_PREEMPT=y
 CONFIG_HZ=128
 CONFIG_AEABI=y
 # CONFIG_OABI_COMPAT is not set
-CONFIG_ARCH_FLATMEM_HAS_HOLES=y
+CONFIG_ARCH_HAS_HOLES_MEMORYMODEL=y
 # CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
 # CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
 CONFIG_SELECT_MEMORY_MODEL=y
@@ -2274,6 +2275,25 @@ CONFIG_ANDROID_RAM_CONSOLE_ENABLE_VERBOSE=y
 # CONFIG_ANDROID_RAM_CONSOLE_EARLY_INIT is not set
 CONFIG_ANDROID_TIMED_GPIO=m
 CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_BMI=y
+
+#
+# BMI Hardware Slot support
+#
+CONFIG_OMAP_SLOT=m
+CONFIG_BMI_PIMS=m
+
+#
+# BMI PIMS
+#
+# CONFIG_BUG_FACTORY_TEST is not set
+CONFIG_BMI_GPS=m
+CONFIG_BMI_MDACC=m
+# CONFIG_BMI_AUDIO is not set
+CONFIG_BMI_VH=m
+# CONFIG_BMI_SENSOR is not set
+# CONFIG_BMI_ZB is not set
+CONFIG_BMI_GSM=m
 
 #
 # CBUS support
diff --git a/recipes/linux/linux-omap-2.6.29/beaglebug/beaglebug-full.patch b/recipes/linux/linux-omap-2.6.29/beaglebug/beaglebug-full.patch
new file mode 100644 (file)
index 0000000..f556f42
--- /dev/null
@@ -0,0 +1,35774 @@
+---
+ arch/arm/Kconfig                             |    2 
+ arch/arm/mach-omap2/board-omap3beagle.c      |   52 
+ arch/arm/mach-omap2/mux.c                    |   25 
+ arch/arm/plat-omap/include/mach/mux.h        |    7 
+ drivers/Kconfig                              |    3 
+ drivers/Makefile                             |    1 
+ drivers/bmi/Kconfig                          |   17 
+ drivers/bmi/Makefile                         |    8 
+ drivers/bmi/core/Makefile                    |    7 
+ drivers/bmi/core/core.c                      |  319 +
+ drivers/bmi/core/device.c                    |   35 
+ drivers/bmi/core/driver.c                    |   27 
+ drivers/bmi/core/eeprom.c                    |   32 
+ drivers/bmi/core/slot.c                      |  469 ++
+ drivers/bmi/pims/Kconfig                     |  104 
+ drivers/bmi/pims/Makefile                    |   17 
+ drivers/bmi/pims/camera/Kconfig              |   23 
+ drivers/bmi/pims/camera/Makefile             |   12 
+ drivers/bmi/pims/camera/bmi_ov2640.c         |  929 +++++
+ drivers/bmi/pims/camera/bmi_vs6624.c         |  915 +++++
+ drivers/bmi/pims/camera/bug_camera.c         |  611 +++
+ drivers/bmi/pims/camera/bug_camera.h         |   72 
+ drivers/bmi/pims/camera/ov2640.c             |  301 +
+ drivers/bmi/pims/camera/ov2640.h             |   14 
+ drivers/bmi/pims/camera/vs6624_access.c      |  597 +++
+ drivers/bmi/pims/camera/vs6624_access.h      |   17 
+ drivers/bmi/pims/camera/vs6624_patch.c       |  373 ++
+ drivers/bmi/pims/camera/vs6624_regs.h        |  467 ++
+ drivers/bmi/pims/factory_test/Makefile       |    6 
+ drivers/bmi/pims/factory_test/factory_test.c |  952 +++++
+ drivers/bmi/pims/gps/Makefile                |    6 
+ drivers/bmi/pims/gps/bmi_gps.c               |  468 ++
+ drivers/bmi/pims/gsm/Makefile                |    6 
+ drivers/bmi/pims/gsm/bmi_gsm.c               |  301 +
+ drivers/bmi/pims/lcd/Makefile                |    9 
+ drivers/bmi/pims/lcd/acc.c                   |  114 
+ drivers/bmi/pims/lcd/acc.h                   |   35 
+ drivers/bmi/pims/lcd/bmi_lcd.c               | 1790 ++++++++++
+ drivers/bmi/pims/lcd/bmi_lcd_inf.c           | 1775 ++++++++++
+ drivers/bmi/pims/lcd/bmi_lcd_mi.c            | 1855 +++++++++++
+ drivers/bmi/pims/lcd/bmi_s320x240.c          |  632 +++
+ drivers/bmi/pims/lcd/lcd_ctl.c               |  421 ++
+ drivers/bmi/pims/lcd/lcd_ctl.h               |   87 
+ drivers/bmi/pims/mdacc/Kconfig               |    6 
+ drivers/bmi/pims/mdacc/Makefile              |    9 
+ drivers/bmi/pims/mdacc/acc.c                 |  381 ++
+ drivers/bmi/pims/mdacc/acc.h                 |   54 
+ drivers/bmi/pims/mdacc/avr.c                 |  511 +++
+ drivers/bmi/pims/mdacc/avr.h                 |   54 
+ drivers/bmi/pims/mdacc/cque.c                |  150 
+ drivers/bmi/pims/mdacc/cque.h                |   42 
+ drivers/bmi/pims/mdacc/ctl.c                 |  176 +
+ drivers/bmi/pims/mdacc/ctl.h                 |   43 
+ drivers/bmi/pims/mdacc/md.c                  |  333 ++
+ drivers/bmi/pims/mdacc/md.h                  |   60 
+ drivers/bmi/pims/mdacc/mdacc.c               |  333 ++
+ drivers/bmi/pims/mdacc/mdacc.h               |   43 
+ drivers/bmi/pims/mdacc/mon.c                 |  474 ++
+ drivers/bmi/pims/mdacc/mon.h                 |   61 
+ drivers/bmi/pims/projector/Makefile          |    7 
+ drivers/bmi/pims/projector/bmi_projector.c   |  674 ++++
+ drivers/bmi/pims/projector/ch7024.c          |  476 ++
+ drivers/bmi/pims/projector/ch7024.h          |  166 +
+ drivers/bmi/pims/sensor/Makefile             |    6 
+ drivers/bmi/pims/sensor/bmi_sensor.c         | 4321 ++++++++++++++++++++++++++
+ drivers/bmi/pims/sound/Makefile              |    6 
+ drivers/bmi/pims/sound/bmi_audio.c           | 4434 +++++++++++++++++++++++++++
+ drivers/bmi/pims/vonhippel/Makefile          |    6 
+ drivers/bmi/pims/vonhippel/bmi_vh.c          |  942 +++++
+ drivers/bmi/pims/zb/Makefile                 |    5 
+ drivers/bmi/pims/zb/bmi_zaccel.c             |  684 ++++
+ drivers/bmi/pims/zb/bmi_zaccel.h             |  288 +
+ drivers/bmi/pims/zb/bmi_zigbee.c             | 1296 +++++++
+ drivers/bmi/pims/zb/bmi_zigbee.h             |  194 +
+ drivers/bmi/pims/zb/bmi_znetdev.c            |  977 +++++
+ drivers/bmi/pims/zb/bmi_zprotocol.c          |  619 +++
+ drivers/bmi/slots/Kconfig                    |   21 
+ drivers/bmi/slots/Makefile                   |    6 
+ drivers/bmi/slots/slots_beagle.c             |  267 +
+ drivers/bmi/slots/slots_bug.c                |  231 +
+ include/linux/bmi-ids.h                      |   30 
+ include/linux/bmi.h                          |  142 
+ include/linux/bmi/at24c02.h                  |   26 
+ include/linux/bmi/bmi-bus.h                  |   21 
+ include/linux/bmi/bmi-control.h              |  303 +
+ include/linux/bmi/bmi-eeprom-data.h          |   83 
+ include/linux/bmi/bmi-eeprom-driver.h        |  113 
+ include/linux/bmi/bmi-eeprom.h               |   75 
+ include/linux/bmi/bmi-slot.h                 |   29 
+ include/linux/bmi/bmi_audio.h                |  449 ++
+ include/linux/bmi/bmi_camera.h               |   36 
+ include/linux/bmi/bmi_gps.h                  |   30 
+ include/linux/bmi/bmi_gsm.h                  |   33 
+ include/linux/bmi/bmi_ioctl.h                |   27 
+ include/linux/bmi/bmi_lcd.h                  |   71 
+ include/linux/bmi/bmi_mdacc.h                |  518 +++
+ include/linux/bmi/bmi_projector.h            |   33 
+ include/linux/bmi/bmi_sensor.h               |  673 ++++
+ include/linux/bmi/bmi_vh.h                   |  135 
+ include/linux/bmi/bmi_zb.h                   |   83 
+ include/linux/mod_devicetable.h              |   13 
+ scripts/mod/file2alias.c                     |   20 
+ 102 files changed, 35212 insertions(+)
+
+--- git.orig/arch/arm/Kconfig
++++ git/arch/arm/Kconfig
+@@ -1342,10 +1342,12 @@ source "drivers/regulator/Kconfig"
+ source "drivers/uio/Kconfig"
+ source "drivers/staging/Kconfig"
++source "drivers/bmi/Kconfig"
++
+ if ARCH_OMAP
+ source "drivers/cbus/Kconfig"
+ endif
+ endmenu
+--- git.orig/arch/arm/mach-omap2/board-omap3beagle.c
++++ git/arch/arm/mach-omap2/board-omap3beagle.c
+@@ -23,10 +23,12 @@
+ #include <linux/gpio.h>
+ #include <linux/irq.h>
+ #include <linux/input.h>
+ #include <linux/gpio_keys.h>
++
++#include <linux/spi/spi.h>
+ #include <linux/mtd/mtd.h>
+ #include <linux/mtd/partitions.h>
+ #include <linux/mtd/nand.h>
+ #include <linux/regulator/machine.h>
+@@ -404,10 +406,16 @@ static struct gpio_led gpio_leds[] = {
+       {
+               .name                   = "beagleboard::usr0",
+               .default_trigger        = "heartbeat",
+               .gpio                   = 150,
+       },
++      /*{
++              .name                   = "beagleboard::exp21",
++              .default_trigger        = "heartbeat",
++              .gpio                   = 130,
++      },
++      */
+       {
+               .name                   = "beagleboard::usr1",
+               .default_trigger        = "mmc0",
+               .gpio                   = 149,
+       },
+@@ -537,20 +545,54 @@ static void __init beagle_display_init(v
+       }
+       gpio_direction_output(beagle_display_data_dvi.panel_reset_gpio, 0);
+ }
++
++static struct resource bmi_slot1_resources[] = {
++  [0] = {
++    .start = 161,
++    .flags = IORESOURCE_IRQ,
++  },
++  [1] = {
++    .start = 134,
++    .flags = IORESOURCE_IRQ,
++  },
++};
++
++static struct platform_device bmi_slot_devices[] = {
++  {
++    .name = "omap_bmi_slot",
++    .id = 0,
++    .num_resources = ARRAY_SIZE(bmi_slot1_resources),
++    .resource = bmi_slot1_resources,
++  },
++};
++
++
++static void omap_init_bmi_slots(void)
++{
++  int i;
++
++  for (i = 0; i < ARRAY_SIZE(bmi_slot_devices); i++) {
++    if (platform_device_register(&bmi_slot_devices[i]) < 0)
++      dev_err(&bmi_slot_devices[i].dev,
++            "Unable to register BMI slot\n");
++  }
++}
++
+ static struct omap_board_config_kernel omap3_beagle_config[] __initdata = {
+       { OMAP_TAG_UART,        &omap3_beagle_uart_config },
+ };
+ static struct platform_device *omap3_beagle_devices[] __initdata = {
+       &beagle_dss_device,
+       &leds_gpio,
+       &keys_gpio,
+ };
++
+ static void __init omap3beagle_flash_init(void)
+ {
+       u8 cs = 0;
+       u8 nandcs = GPMC_CS_NUM + 1;
+@@ -598,14 +640,24 @@ static void __init omap3_beagle_init(voi
+       omap_cfg_reg(J25_34XX_GPIO170);
+       omap3beagle_enc28j60_init();
++      omap_cfg_reg(AG4_3530_GPIO134);
++      omap_cfg_reg(K26_34XX_GPIO161);
++      omap_cfg_reg(Y21_3530_GPIO156_OUT);
++      omap_cfg_reg(AF14_34XX_I2C3_SCL);
++      omap_cfg_reg(AG14_34XX_I2C3_SDA);
++      omap_cfg_reg(U21_3530_GPIO159_OUT);
++      gpio_direction_output(156, false);
++      gpio_direction_output(159, false);
++      // BMI Presence and Status
+       usb_musb_init();
+       usb_ehci_init();
+       omap3beagle_flash_init();
+       beagle_display_init();
++      omap_init_bmi_slots();
+ }
+ static void __init omap3_beagle_map_io(void)
+ {
+       omap2_set_globals_343x();
+--- git.orig/arch/arm/mach-omap2/mux.c
++++ git/arch/arm/mach-omap2/mux.c
+@@ -480,14 +480,39 @@ MUX_CFG_34XX("AE6_34XX_GPIO141", 0x16e,
+               OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_INPUT)
+ MUX_CFG_34XX("AF5_34XX_GPIO142", 0x170,
+               OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_INPUT)
+ MUX_CFG_34XX("AE5_34XX_GPIO143", 0x172,
+               OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_INPUT)
++MUX_CFG_34XX("K26_34XX_GPIO161", 0x196,
++              OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_INPUT)
+ MUX_CFG_34XX("H19_34XX_GPIO164_OUT", 0x19c,
+               OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_OUTPUT)
+ MUX_CFG_34XX("J25_34XX_GPIO170", 0x1c6,
+               OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_INPUT)
++
++/*BeagleBoard/BUG-Hybrid specific GPIO stuff*/
++
++MUX_CFG_34XX("AE2_3530_GPIO130", 0x158,
++              OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_OUTPUT)
++/*
++MUX_CFG_34XX("AG5_3530_GPIO131", 0x15A,
++              OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_INPUT)
++MUX_CFG_34XX("AH5_3530_GPIO132", 0x15C,
++              OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_INPUT)
++MUX_CFG_34XX("AH4_3530_GPIO133", 0x15E,
++              OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_INPUT)
++*/
++MUX_CFG_34XX("AG4_3530_GPIO134", 0x160,
++              OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_INPUT)
++MUX_CFG_34XX("AF4_3530_GPIO135", 0x162,
++              OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_INPUT)
++MUX_CFG_34XX("Y21_3530_GPIO156_OUT", 0x18C,
++              OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_OUTPUT)
++MUX_CFG_34XX("AA21_3530_GPIO157", 0x18E,
++              OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_INPUT)
++MUX_CFG_34XX("U21_3530_GPIO159_OUT", 0x192,
++              OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_OUTPUT)
+ };
+ #define OMAP34XX_PINS_SZ      ARRAY_SIZE(omap34xx_pins)
+ #else
+--- git.orig/arch/arm/plat-omap/include/mach/mux.h
++++ git/arch/arm/plat-omap/include/mach/mux.h
+@@ -799,12 +799,19 @@ enum omap34xx_index {
+       AE4_34XX_GPIO136_OUT,
+       AF6_34XX_GPIO140_UP,
+       AE6_34XX_GPIO141,
+       AF5_34XX_GPIO142,
+       AE5_34XX_GPIO143,
++      K26_34XX_GPIO161,
+       H19_34XX_GPIO164_OUT,
+       J25_34XX_GPIO170,
++      AE2_3530_GPIO130,
++      AG4_3530_GPIO134,
++      AF4_3530_GPIO135,
++      Y21_3530_GPIO156_OUT,
++      AA21_3530_GPIO157,
++      U21_3530_GPIO159_OUT
+ };
+ struct omap_mux_cfg {
+       struct pin_config       *pins;
+       unsigned long           size;
+--- git.orig/drivers/Kconfig
++++ git/drivers/Kconfig
+@@ -4,10 +4,12 @@ menu "Device Drivers"
+ source "drivers/base/Kconfig"
+ source "drivers/connector/Kconfig"
++source "drivers/bmi/Kconfig"
++
+ source "drivers/mtd/Kconfig"
+ source "drivers/of/Kconfig"
+ source "drivers/parport/Kconfig"
+@@ -107,6 +109,7 @@ source "drivers/uio/Kconfig"
+ source "drivers/xen/Kconfig"
+ source "drivers/staging/Kconfig"
+ source "drivers/platform/Kconfig"
++
+ endmenu
+--- git.orig/drivers/Makefile
++++ git/drivers/Makefile
+@@ -91,10 +91,11 @@ obj-y                              += lguest/
+ obj-$(CONFIG_CPU_FREQ)                += cpufreq/
+ obj-$(CONFIG_CPU_IDLE)                += cpuidle/
+ obj-y                         += idle/
+ obj-$(CONFIG_MMC)             += mmc/
+ obj-$(CONFIG_MEMSTICK)                += memstick/
++obj-$(CONFIG_BMI)             += bmi/
+ obj-$(CONFIG_NEW_LEDS)                += leds/
+ obj-$(CONFIG_INFINIBAND)      += infiniband/
+ obj-$(CONFIG_SGI_SN)          += sn/
+ obj-y                         += firmware/
+ obj-$(CONFIG_CRYPTO)          += crypto/
+--- /dev/null
++++ git/drivers/bmi/Kconfig
+@@ -0,0 +1,17 @@
++#
++# BMI Infrastructure
++#
++
++menuconfig BMI
++       tristate "BMI"
++       depends on I2C
++       default n
++       ---help---
++         BMI bus infrastructure
++
++if BMI
++
++source drivers/bmi/slots/Kconfig
++source drivers/bmi/pims/Kconfig
++
++endif # BMI
+--- /dev/null
++++ git/drivers/bmi/Makefile
+@@ -0,0 +1,8 @@
++#
++# Makefile for the bmi bus drivers.
++#
++
++obj-$(CONFIG_BMI) += core/
++obj-$(CONFIG_BMI) += slots/
++obj-$(CONFIG_BMI) += pims/
++
+--- /dev/null
++++ git/drivers/bmi/core/Makefile
+@@ -0,0 +1,7 @@
++#
++# Makefile for BMI subsystem core
++#
++
++#bmicore-objs := core.o slot.o
++
++obj-$(CONFIG_BMI) += core.o driver.o slot.o eeprom.o
+--- /dev/null
++++ git/drivers/bmi/core/core.c
+@@ -0,0 +1,319 @@
++#include <linux/module.h>
++#include <linux/err.h>
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/kobject.h>
++#include <linux/bmi.h>
++
++
++static DEFINE_MUTEX(core_lock);
++
++static struct class *bmi_class;
++
++
++struct class* bmi_get_class (void)
++{
++      return bmi_class;
++};
++EXPORT_SYMBOL(bmi_get_class);
++
++
++/**
++ * bmi_device_get - increments the reference count of the bmi device structure
++ * @dev: the device being referenced
++ *
++ * Each live reference to a device should be refcounted.
++ *
++ * Drivers for BMI devices should normally record such references in
++ * their probe() methods, when they bind to a device, and release
++ * them by calling bmi_dev_put(), in their disconnect() methods.
++ *
++ * A pointer to the device with the incremented reference counter is returned.
++ */
++struct bmi_device *bmi_dev_get(struct bmi_device *dev)
++{
++      if (dev)
++              get_device(&dev->dev);
++      return dev;
++}
++
++
++/**
++ * bmi_device_put - release a use of the bmi device structure
++ * @dev: device that's been disconnected
++ *
++ * Must be called when a user of a device is finished with it.  When the last
++ * user of the device calls this function, the memory of the device is freed.
++ */
++void bmi_dev_put(struct bmi_device *dev)
++{
++      if (dev)
++              put_device(&dev->dev);
++}
++
++
++/**
++ * bmi_match_one_id - Tell if a BMI device structure has a matching
++ *                        BMI device id structure
++ * @id: single BMI device id structure to match
++ * @bdev: the BMI device structure to match against
++ *
++ * Returns the matching bmi_device_id structure or %NULL if there is no match.
++ */
++
++static const struct bmi_device_id *bmi_match_one_id(const struct bmi_device_id *id,
++                                              const struct bmi_device *bdev)
++{
++  if ((id->vendor == bdev->vendor) &&
++      (id->product == bdev->product) &&
++      ((id->revision == bdev->revision) || (id->revision == BMI_ANY)))
++    return id;
++  return NULL;
++}
++
++
++/**
++ * bmi_match_id - See if a BMI device matches a given bmi_device_id table
++ * @ids: array of BMI device id structures to search in
++ * @bdev: the BMI device structure to match against.
++ *
++ * Used by a driver to check whether a BMI device present in the
++ * system is in its list of supported devices.  Returns the matching
++ * bmi_device_id structure or %NULL if there is no match.
++ *
++ */
++
++
++const struct bmi_device_id *bmi_match_id(const struct bmi_device_id *ids,
++                                       struct bmi_device *bdev)
++{
++  if (ids) {
++    while (ids->vendor)       {
++      if (bmi_match_one_id(ids, bdev))
++      return ids;
++      ids++;
++    }
++  }
++  return NULL;
++}
++
++/**
++ * bmi_device_match - Tell if a BMI device structure has a matching BMI device id structure
++ * @dev: the BMI device structure to match against
++ * @drv: the device driver to search for matching PCI device id structures
++ *
++ * Used by a driver to check whether a BMI device present in the
++ * system is in its list of supported devices. Returns the matching
++ * bmi_device_id structure or %NULL if there is no match.
++ */
++
++
++static int bmi_device_match(struct device *dev, struct device_driver *driver)
++{
++  struct bmi_device *bmi_dev = to_bmi_device(dev);
++  struct bmi_driver *bmi_drv = to_bmi_driver(driver);
++  const struct bmi_device_id *found_id;
++
++  found_id = bmi_match_id(bmi_drv->id_table, bmi_dev);
++
++  if (found_id)
++    return 1;
++
++  printk(KERN_INFO "BMI: No matching Driver...");
++  return 0;
++}
++
++/*
++ * Uevent Generation for hotplug
++ */
++
++static int bmi_device_uevent(struct device *dev, struct kobj_uevent_env *env)
++{
++  struct bmi_device *bdev = to_bmi_device(dev);
++
++  if (!dev)
++    return -ENODEV;
++
++  if (add_uevent_var(env, "BMIBUS_SLOT=%01X", bdev->slot->slotnum)) {
++    return -ENOMEM;
++  }
++  if (add_uevent_var(env, "BMIBUS_VENDOR=%04X", bdev->vendor)) {
++    return -ENOMEM;
++  }
++  if (add_uevent_var(env, "BMIBUS_PRODUCT=%04X", bdev->product)) {
++    return -ENOMEM;
++  }
++  if (add_uevent_var(env, "BMIBUS_REV=%04X", bdev->revision)) {
++    return -ENOMEM;
++  }
++  if (add_uevent_var(env, "MODALIAS=bmi:v%04Xp%04Xr%04X",
++                   bdev->vendor, bdev->product,
++                   bdev->revision)) {
++    return -ENOMEM;
++  }
++  return 0;
++}
++
++
++struct bmi_device *bmi_alloc_dev(struct bmi_slot *slot)
++{
++  struct bmi_device *dev;
++
++  dev = kzalloc(sizeof(*dev), GFP_KERNEL);
++  if (!dev) {
++    printk(KERN_ERR "BMI: Couldn't Allocate bmi_device structure...\n");
++    return NULL;
++  }
++
++  device_initialize(&dev->dev);
++  dev->dev.bus = &bmi_bus_type;
++  dev_set_name(&dev->dev, "bmi-dev-%d",slot->slotnum);
++  dev->dev.parent = &slot->slotdev;
++  dev->slot = slot;
++
++  return dev;
++}
++
++
++
++/**
++ * __bmi_probe()
++ * @drv: driver to call to check if it wants the BMI device
++ * @bmi_dev: BMI device being probed
++ *
++ * returns 0 on success, else error.
++ * side-effect: bmi_dev->driver is set to drv when drv claims bmi_dev.
++ */
++static int
++__bmi_probe(struct bmi_driver *driver, struct bmi_device *bmi_dev)
++{
++  int error = 0;
++
++  if (!bmi_dev->driver && driver->probe) {
++
++    error = driver->probe(bmi_dev);
++    if (error >= 0) {
++      // bmi_device -> bmi_driver (bmi-bus level )
++      bmi_dev->driver = driver;
++      error = 0;
++    }
++  }
++  return error;
++}
++
++static int bmi_device_probe (struct device *dev)
++{
++  int error = 0;
++  struct bmi_driver *drv;
++  struct bmi_device *bmi_dev;
++
++  //By this time, we have already been match()ed against a driver.
++
++  // device -> device_driver. (driver-core level)
++
++  drv = to_bmi_driver(dev->driver);
++  bmi_dev = to_bmi_device(dev);
++
++
++  bmi_dev_get(bmi_dev);
++
++  error = __bmi_probe(drv, bmi_dev);
++  if (error)
++    bmi_dev_put(bmi_dev);
++  else
++    kobject_uevent(&dev->kobj, KOBJ_ADD);
++
++  return error;
++}
++
++
++
++static int bmi_device_remove (struct device *dev)
++{
++      struct bmi_device * bmi_dev;
++      struct bmi_driver * driver;
++
++      bmi_dev = to_bmi_device(dev);
++      driver = bmi_dev->driver;
++
++      if (driver) {
++              if (driver->remove)
++                      driver->remove(bmi_dev);
++              bmi_dev->driver = NULL;
++      }
++
++      kobject_uevent(&dev->kobj, KOBJ_REMOVE);
++      bmi_dev_put(bmi_dev);
++      return 0;
++}
++
++static void bmi_device_shutdown(struct device * dev)
++{
++  return;
++}
++
++static int bmi_device_suspend (struct device * dev, pm_message_t state)
++{
++  return -1;
++}
++
++static int bmi_device_suspend_late (struct device * dev, pm_message_t state)
++{
++  return -1;
++}
++
++static int bmi_device_resume_early (struct device * dev)
++{
++  return -1;
++}
++
++static int bmi_device_resume (struct device * dev)
++{
++  return -1;
++}
++
++
++
++struct bus_type bmi_bus_type = {
++      .name = "bmi",
++      .match    = bmi_device_match,
++      .uevent   = bmi_device_uevent,
++      .probe    = bmi_device_probe,
++      .remove   = bmi_device_remove,
++      .shutdown = bmi_device_shutdown,
++      .suspend  = bmi_device_suspend,
++      .suspend_late = bmi_device_suspend_late,
++      .resume_early = bmi_device_resume_early,
++      .resume = bmi_device_resume,
++};
++
++static int __init bmi_init(void)
++{
++  int ret = 0;
++
++  ret = bus_register(&bmi_bus_type);
++  if (ret) {
++    printk(KERN_ERR "BMI: (bmi_init) - Bus registration failed...\n");
++    return ret;
++  }
++
++  //  ret = class_register(&bmi_class);
++  bmi_class = class_create(THIS_MODULE, "bmi");
++  if (ret) {
++    printk(KERN_ERR "BMI: (bmi_init) - Failed to register BMI Class...\n");
++    bmi_class = NULL;
++    bus_unregister(&bmi_bus_type);
++  }
++  return ret;
++}
++
++static void __exit bmi_cleanup(void)
++{
++  bmi_class = NULL;
++  bus_unregister(&bmi_bus_type);
++}
++
++//subsys_initcall(bmi_init);
++module_init(bmi_init);
++module_exit(bmi_cleanup);
+--- /dev/null
++++ git/drivers/bmi/core/device.c
+@@ -0,0 +1,35 @@
++
++
++// bmi_device accessors
++static inline int bmi_device_get_status_irq (struct bmi_device *bdev)
++{
++      return (bdev->slot->status_irq);
++}
++
++static inline int bmi_device_get_present_irq (struct bmi_device *bdev)
++{
++      return (bdev->slot->present_irq);
++}
++
++static inline struct i2c_adapter* bmi_device_get_i2c_adapter (struct bmi_device *bdev)
++{
++      return (&bdev->slot->adap);
++}
++
++static inline int bmi_device_get_slot (struct bmi_device *bdev)
++{
++      return (bdev->slot->slotnum);
++}
++
++int bmi_device_present (struct bmi_device *bdev);
++struct bmi_device *bmi_device_get(struct bmi_device *dev);
++void bmi_device_put(struct bmi_device *dev);
++
++int  bmi_device_read_inventory_eeprom ( struct bmi_device *bdev );
++int  bmi_device_init ( struct bmi_device *bdev, struct bmi_info *info, struct bus_type *bmi_bus_type);
++void bmi_device_cleanup( struct bmi_device* bdev);
++int  bmi_device_i2c_setup( struct bmi_device *bdev);
++void bmi_device_i2c_cleanup( struct bmi_device* bdev);
++int  bmi_device_spi_setup( struct bmi_device *bdev, u32 speed, u8 mode, u8 bits_per_word);
++void bmi_device_spi_cleanup( struct bmi_device* bdev);
++struct spi_device *bmi_device_get_spi( struct bmi_device *bdev);
+--- /dev/null
++++ git/drivers/bmi/core/driver.c
+@@ -0,0 +1,27 @@
++#include <linux/bmi.h>
++
++int __bmi_register_driver(struct bmi_driver *drv, struct module *owner)
++{
++      int error;
++
++      /* initialize common driver fields */
++      drv->driver.name = drv->name;
++      drv->driver.bus = &bmi_bus_type;
++      drv->driver.owner = owner;
++
++      /* register with core */
++      error = driver_register(&drv->driver);
++
++      return error;
++}
++
++
++void
++bmi_unregister_driver(struct bmi_driver *drv)
++{
++      driver_unregister(&drv->driver);
++}
++
++EXPORT_SYMBOL(__bmi_register_driver);
++EXPORT_SYMBOL(bmi_unregister_driver);
++
+--- /dev/null
++++ git/drivers/bmi/core/eeprom.c
+@@ -0,0 +1,32 @@
++#include <linux/types.h>
++#include <linux/bmi/bmi-eeprom.h>
++
++
++static inline __u8 bmi_eeprom_checksum (struct bmi_eeprom_data *raw)
++{
++      int i;
++      __u8 sum = 0;
++      __u8 *buf = (__u8*)raw;
++
++      for (i = 0; i < (sizeof (struct bmi_eeprom_data) - 1); i++) {
++              sum ^= *buf++;
++      }
++      return sum;
++}
++
++
++int bmi_eeprom_checksum_validate (struct bmi_eeprom_data *raw)
++{
++      int ret = 0;
++      u8 calcsum;
++
++      calcsum = bmi_eeprom_checksum (raw);
++
++      if (calcsum != raw->checksum) {
++              //Rework: add conditional debug messages here
++              ret = -1;
++      }
++      return ret;
++}
++
++
+--- /dev/null
++++ git/drivers/bmi/core/slot.c
+@@ -0,0 +1,469 @@
++/* Matt Isaacs - Kick ass platform independant BMI implementation */
++
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/module.h>
++#include <linux/completion.h>
++#include <linux/sched.h>
++#include <linux/list.h>
++#include <linux/delay.h>
++#include <linux/mutex.h>
++#include <linux/freezer.h>
++#include <linux/idr.h>
++#include <linux/irq.h>
++#include <linux/interrupt.h>
++#include <linux/platform_device.h>
++#include <linux/bmi.h>
++#include <linux/bmi/bmi-slot.h>
++
++static DEFINE_MUTEX(slot_lock);
++static DEFINE_IDR(bmi_slot_idr);
++
++
++//#include "slot.h"
++
++/*
++struct slot_driver {
++  const char *description;
++
++  irq_return_t        (*irq) (struct bmi_slot);
++  int (*start) (struct bmi_slot);
++  int (*stop) (struct bmi_slot);
++}
++*/
++
++static struct task_struct *kslotd_task;
++
++static DEFINE_SPINLOCK(slot_event_lock);
++static LIST_HEAD(slot_event_list);
++static DECLARE_WAIT_QUEUE_HEAD(kslotd_wait);
++
++static struct i2c_board_info at24c02_info = {
++  I2C_BOARD_INFO("at24c02", 0XA0 >> 1),
++};
++
++static void bmi_slot_work_handler(struct work_struct * work);
++
++struct bmi_slot* bmi_get_slot(int slotnum)
++{
++  struct bmi_slot *slot;
++
++  mutex_lock(&slot_lock);
++  slot = (struct bmi_slot*)idr_find(&bmi_slot_idr, slotnum);
++  if (slot && !try_module_get(slot->owner))
++    slot = NULL;
++
++  mutex_unlock(&slot_lock);
++
++  return slot;
++}
++
++void bmi_slot_power_on (int num)
++{
++  struct bmi_slot *slot = bmi_get_slot(num);
++
++  if (!slot) {
++    printk(KERN_ERR "BMI: Slot %d doesn't exist...\n", num);
++    return;
++  }
++
++  if (slot->actions->power_on)
++    slot->actions->power_on(slot);
++  else
++    printk(KERN_INFO "BMI: Slot %d power is always on...\n", num);
++  return;
++}
++
++void bmi_slot_power_off (int num)
++{
++  struct bmi_slot *slot = bmi_get_slot(num);
++
++  if (!slot) {
++    printk(KERN_ERR "BMI: Slot %d doesn't exist...\n", num);
++    return;
++  }
++
++  if (slot->actions->power_off)
++    slot->actions->power_off(slot);
++  else
++    printk(KERN_INFO "BMI: Slot %d power is always on...\n", num);
++  return;
++}
++
++void bmi_slot_gpio_configure (int num, int gpio)
++{
++  struct bmi_slot *slot = bmi_get_slot(num);
++
++  if (!slot) {
++    printk(KERN_ERR "BMI: Slot %d doesn't exist...\n", num);
++    return;
++  }
++
++  if (slot->actions->gpio_config)
++    slot->actions->gpio_config(slot, gpio);
++  else
++    printk(KERN_INFO "BMI: Slot GPIO not configurable...\n");
++  return;
++
++}
++EXPORT_SYMBOL(bmi_slot_gpio_configure);
++
++int bmi_slot_gpio_get(int num)
++{
++  struct bmi_slot *slot = bmi_get_slot(num);
++
++  if (!slot) {
++    printk(KERN_ERR "BMI: Slot %d doesn't exist...\n", num);
++    return -ENODEV;
++  }
++
++  if (slot->actions->gpio_get)
++    return slot->actions->gpio_get(slot);
++
++  printk(KERN_INFO "BMI: Slot GPIO not writable...\n");
++  return -EIO;
++}
++EXPORT_SYMBOL(bmi_slot_gpio_get);
++
++void bmi_slot_gpio_set(int num, int data)
++{
++  struct bmi_slot *slot = bmi_get_slot(num);
++
++  if (!slot) {
++    printk(KERN_ERR "BMI: Slot %d doesn't exist...\n", num);
++    return;
++  }
++
++  if (slot->actions->gpio_set)
++    slot->actions->gpio_set(slot, data);
++  else
++    printk(KERN_INFO "BMI: Slot GPIO not writable...\n");
++  return;
++}
++EXPORT_SYMBOL(bmi_slot_gpio_set);
++
++void bmi_slot_gpio_write_bit(int num, int gpio, int data)
++{
++  return;
++}
++
++int bmi_slot_gpio_read_bit (int num, int gpio)
++{
++      int gpdat;
++      int bit;
++
++      gpdat = bmi_slot_gpio_get(num);
++      bit = (gpdat & (1 << gpio)) ? 1 : 0;
++      return bit;
++}
++
++
++// NOTE: When a plug-in module is removed, the gpios should be returned to inputs.
++// All requested slot resourece should be released.
++// The slot should be powered down.
++
++void bmi_slot_gpio_configure_all_as_inputs (int slot)
++{
++      return;
++}
++
++
++void bmi_slot_uart_enable  (int num)
++{
++  struct bmi_slot *slot = bmi_get_slot(num);
++
++  if (!slot) {
++    printk(KERN_ERR "BMI: Slot %d doesn't exist...\n", num);
++    return;
++  }
++
++  if (slot->actions->uart_enable)
++    return slot->actions->uart_enable(slot);
++
++  printk(KERN_INFO "BMI: UART always enabled...\n");
++  return;
++}
++EXPORT_SYMBOL(bmi_slot_uart_enable);
++
++void bmi_slot_uart_disable (int num)
++{
++
++      return;
++}
++EXPORT_SYMBOL(bmi_slot_uart_disable);
++
++void bmi_slot_spi_enable  (int num)
++{
++
++      return;
++}
++EXPORT_SYMBOL(bmi_slot_spi_enable);
++
++void bmi_slot_spi_disable (int num)
++{
++      return;
++}
++EXPORT_SYMBOL(bmi_slot_spi_disable);
++
++void bmi_slot_audio_enable  (int num)
++{
++
++      return;
++}
++EXPORT_SYMBOL(bmi_slot_audio_enable);
++
++void bmi_slot_audio_disable (int num)
++{
++
++      return;
++}
++EXPORT_SYMBOL(bmi_slot_audio_disable);
++
++void bmi_slot_battery_enable (int num)
++{
++
++      return;
++}
++EXPORT_SYMBOL(bmi_slot_battery_enable);
++
++void bmi_slot_battery_disable (int num)
++{
++
++      return;
++}
++EXPORT_SYMBOL(bmi_slot_battery_disable);
++
++int bmi_slot_module_present (int num)
++{
++  struct bmi_slot *slot = bmi_get_slot(num);
++  // slot->actions->gpio_set
++  if (slot->actions->present != NULL)
++    return slot->actions->present(slot);
++  else
++    printk(KERN_INFO "BMI: Slot Driver incomplete. No presence detection...\n");
++  return 0;
++}
++
++int bmi_slot_read_eeprom(struct bmi_slot *slot, u8* data)
++{
++  unsigned char i = 0;
++  int ret;
++
++  if (slot->eeprom == NULL) {
++      printk(KERN_INFO "Can't get eeprom client...\n");
++      ret = -EIO;
++  }
++  else {
++    ret = i2c_master_send(slot->eeprom, &i, 1);
++    if (ret == 1)
++      ret = i2c_master_recv(slot->eeprom, data, sizeof(struct bmi_eeprom_data));
++  }
++  return ret;
++}
++
++int bmi_slot_status_irq_state (int slot)
++{
++      int state = 0;
++      return state;
++}
++
++
++#define       DEBOUNCE_DELAY  msecs_to_jiffies(1000)
++
++static irqreturn_t bmi_slot_irq_handler(int irq, void *dev_id)
++{
++  struct bmi_slot *slot = dev_id;
++
++  disable_irq_nosync(irq);
++  printk(KERN_INFO " BMI: IRQ Triggered on slot: %d\n", slot->slotnum);
++  schedule_delayed_work(&slot->work, DEBOUNCE_DELAY);
++  return IRQ_HANDLED;
++}
++
++static void bmi_slot_work_handler(struct work_struct * work)
++{
++  struct bmi_slot *slot;
++  struct bmi_device *bdev;
++  int ret;
++  struct bmi_eeprom_data data;
++  unsigned char* cdat;
++
++  slot = work_to_slot(work);
++
++  mutex_lock(&slot->pres_mutex);
++  if (bmi_slot_module_present(slot->slotnum)) {
++    if (!slot->present) {
++      slot->present = 1;
++      slot->eeprom = i2c_new_device(slot->adap, &at24c02_info);
++
++      ret = bmi_slot_read_eeprom(slot, (u8*)&data);
++
++      if (ret < 0)
++      {
++        printk(KERN_INFO "BMI: EEPROM Trouble on Slot %d...\n",slot->slotnum);
++
++        goto irqenbl;
++      }
++      //Testing stuff here...get rid of this...
++      else
++      printk(KERN_INFO "BMI: EEPROM Found...\n");
++      cdat = (char*)&data;
++      /*for (i = 0; i < 20; i++)
++      printk(KERN_INFO "0x%x\n", cdat[i]);*/
++      printk(KERN_INFO "SLOTS: Vendor:  0x%x\n",(data.vendor_msb<<8) | (data.vendor_lsb));
++      printk(KERN_INFO "SLOTS: Product  0x%x\n",(data.product_msb<<8) | (data.product_lsb));
++      printk(KERN_INFO "SLOTS: Revision 0x%x\n",(data.revision_msb<<8) | (data.revision_lsb));
++
++      //Do new device allocation and hand it over to BMI...
++      bdev = bmi_alloc_dev(slot);
++      bdev->vendor = (data.vendor_msb<<8) | (data.vendor_lsb);
++      bdev->product = (data.product_msb<<8) | (data.product_lsb);
++      bdev->revision = (data.revision_msb<<8) | (data.revision_lsb);
++
++      //Report module plugin so that udev can load appropriate drivers
++      //kobject_uevent (&bdev->dev.kobj, KOBJ_ADD);
++      ret = device_add(&bdev->dev);
++      if (ret) {
++      printk(KERN_ERR "SLOTS: Failed to add device...%d\n",ret);
++      goto irqenbl; //TODO: Memory allocated for by bmi_alloc_dev
++      }
++      slot->bdev = bdev;
++      /*
++      ret = device_attach(&bdev->dev);
++      if (ret != 1) {
++      printk(KERN_ERR "SLOTS: Failed to attach device...%d\n",ret);
++      goto irqenbl; //TODO: Memory allocated for by bmi_alloc_dev must be freed
++      }
++      */
++    }
++    else
++      //spurious insertion event..
++      printk(KERN_INFO "SLOTS: Spurious insertion on Slot %d...\n",slot->slotnum);
++  }
++  else {
++    if (slot->present) {
++      slot->present = 0;
++      printk(KERN_INFO "BMI: Module removed from slot %d...\n", slot->slotnum);
++      if (slot->bdev == NULL) {
++      printk(KERN_ERR "SLOTS: BMI Device NULL...\n");
++      goto del_eeprom;
++      }
++      //Call BMI device removal stuff here...
++      device_del(&slot->bdev->dev);
++      goto del_eeprom;
++    }
++  }
++ irqenbl:
++  mutex_unlock(&slot->pres_mutex);
++  enable_irq(slot->present_irq);
++  return;
++ del_eeprom:
++  i2c_unregister_device(slot->eeprom);
++  slot->bdev = NULL;
++  slot->eeprom = NULL;
++  goto irqenbl;
++
++}
++
++static int bmi_register_slot(struct bmi_slot *slot)
++{
++  int res = 0;
++  struct class *class;
++
++  //  mutex_init(&slot->state_lock);
++  if (unlikely(WARN_ON(!bmi_bus_type.p)))
++    return -EAGAIN;
++  if (slot->actions == NULL) {
++    printk(KERN_INFO "SLOTS: No Slot actions defined...\n");
++    goto unlist;
++  }
++  mutex_init(&slot->pres_mutex);
++  mutex_lock(&slot_lock);
++
++  if (slot->slotdev.parent == NULL) {
++    slot->slotdev.parent = &platform_bus;
++    //debug message here
++  }
++
++  dev_set_name(&slot->slotdev, "bmi-%d", slot->slotnum);
++
++  class = bmi_get_class();
++  if (class == NULL) {
++    printk(KERN_ERR "BMI Class doesn't exist...\n");
++    goto unlist;
++  }
++  res = device_register(&slot->slotdev);
++  if (res) {
++    printk(KERN_ERR "SLOT: Couldn't register slot... %d\n",res);
++    goto unlist;
++    //quit
++  }
++
++  //Request IRQ
++  INIT_DELAYED_WORK(&slot->work, bmi_slot_work_handler);
++
++  printk(KERN_ERR "SLOT: Requesting IRQ...\n");
++  res = request_irq(slot->present_irq, bmi_slot_irq_handler, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING , slot->name, (void*)slot);
++
++  if (res) {
++    printk(KERN_ERR "SLOT: IRQ Request failed...\n");
++    goto unlist;
++  }
++
++ unlock:
++    mutex_unlock(&slot_lock);
++    return res;
++ unlist:
++    idr_remove(&bmi_slot_idr, slot->slotnum);
++    goto unlock;
++
++}
++
++
++int bmi_add_slot(struct bmi_slot *slot)
++{
++  int slotnum = 0;
++  int res = 0;
++
++ retry:
++  if (idr_pre_get(&bmi_slot_idr, GFP_KERNEL) == 0)
++    return -ENOMEM;
++
++  mutex_lock(&slot_lock);
++
++  res = idr_get_new_above(&bmi_slot_idr, slot, 0, &slotnum);
++  mutex_unlock(&slot_lock);
++  if (res < 0) {
++    if (res == -EAGAIN)
++      goto retry;
++    return res;
++  }
++  slot->slotnum = slotnum;
++  return bmi_register_slot(slot);
++}
++EXPORT_SYMBOL(bmi_add_slot);
++
++
++int bmi_del_slot(struct bmi_slot *slot)
++{
++  int res = 0;
++
++  mutex_lock(&slot_lock);
++  if (idr_find(&bmi_slot_idr, slot->slotnum)) {
++    printk(KERN_ERR "BMI: Attempting to delete unregistered slot...\n");
++    res = -EINVAL;
++    goto unlock;
++  }
++
++  disable_irq_nosync(slot->present_irq);
++  free_irq(slot->present_irq, slot);
++  device_unregister(&slot->slotdev);
++  idr_remove(&bmi_slot_idr, slot->slotnum);
++  memset(&slot->slotdev, 0, sizeof(slot->slotdev));
++
++ unlock:
++  mutex_unlock(&slot_lock);
++  return res;
++}
++EXPORT_SYMBOL(bmi_del_slot);
++
+--- /dev/null
++++ git/drivers/bmi/pims/Kconfig
+@@ -0,0 +1,104 @@
++#
++# BMI PIMS
++#
++
++config BMI_PIMS
++      tristate "BMI_PIMS"
++      default n
++      ---help---
++        BMI plug-in module support
++
++        This driver must be built as a module.
++
++menu "BMI PIMS"
++
++config BUG_FACTORY_TEST
++      tristate "BUG_FACTORY_TEST"
++      depends on BMI_PIMS
++      default n
++      ---help---
++        BMI FACTORY Test plug-in module
++
++        This driver can also be built as a module.
++
++config BMI_GPS
++      tristate "BMI_GPS"
++      depends on BMI_PIMS
++      default n
++      ---help---
++        BMI GPS plug-in module
++
++        This driver can also be built as a module.
++
++source "drivers/bmi/pims/mdacc/Kconfig"
++
++config VIDEO_BMI_LCD
++      tristate "BMI Bus LCD Module support"
++      depends on FB_MXC && MACH_BUG
++      default n
++      ---help---
++        This is the BMI bus driver for the LCD Plug-In Module.
++
++config VIDEO_BMI_LCD_S320X240
++      tristate "BMI support for Sharp 320x240 module"
++      depends on FB_MXC && MACH_BUG && VIDEO_BMI_LCD
++      default n
++      ---help---
++        This is the BMI LCD driver for the Sharp 320x240 LCD Plug-In Module.
++
++config VIDEO_BMI_PROJECTOR
++      tristate "BMI Bus PROJECTOR Module support"
++      depends on FB_MXC_PROJECTOR && MACH_BUG
++      default n
++      ---help---
++        This is the BMI bus driver for the PROJECTOR Plug-In Module.
++
++config BMI_AUDIO
++      tristate "BMI Bus Audio Module support"
++      depends on BMI_PIMS
++      default n
++      ---help---
++        This is the BMI bus driver for the Audio Plug-In Module.
++
++        Select M to make a kernel-loadable module.
++
++#source "drivers/bmi/pims/camera/Kconfig"
++
++config BMI_VH
++      tristate "BMI von Hippel Module support"
++      depends on BMI_PIMS
++      default n
++      ---help---
++        BMI von Hippel plug-in module
++
++        This driver can also be built as a module.
++
++config BMI_SENSOR
++        tristate "BMI Sensor Module support"
++        depends on BMI_PIMS
++        default n
++        ---help---
++          BMI Sensor plug-in module
++
++          This driver can also be built as a module.
++
++config BMI_ZB
++      tristate "BMI ZigBee Module support"
++      depends on BMI_PIMS
++      default n
++      ---help---
++        BMI ZigBee plug-in module
++
++        This driver can also be built as a module.
++
++config BMI_GSM
++      tristate "BMI GSM/UMTS Module support"
++      depends on BMI_PIMS
++      default n
++      ---help---
++        BMI von Hippel plug-in module
++
++        This driver can also be built as a module.
++
++endmenu
++
+--- /dev/null
++++ git/drivers/bmi/pims/Makefile
+@@ -0,0 +1,17 @@
++#
++# BMI PIMS
++#
++
++obj-$(CONFIG_BUG_FACTORY_TEST)        += factory_test/
++obj-$(CONFIG_BMI_GPS)         += gps/
++obj-$(CONFIG_BMI_MDACC)               += mdacc/
++obj-$(CONFIG_VIDEO_BMI_LCD)   += lcd/
++obj-$(CONFIG_BMI_CAMERA)      += camera/
++obj-$(CONFIG_BMI_AUDIO)               += sound/
++obj-$(CONFIG_BMI_VH)          += vonhippel/
++obj-$(CONFIG_BMI_GSM)         += gsm/
++obj-$(CONFIG_BMI_SENSOR)      += sensor/
++obj-$(CONFIG_VIDEO_BMI_PROJECTOR)     += projector/
++obj-$(CONFIG_BMI_ZB)          += zb/
++
++
+--- /dev/null
++++ git/drivers/bmi/pims/camera/Kconfig
+@@ -0,0 +1,23 @@
++config BMI_CAMERA
++      tristate "BMI Camera"
++      depends on MACH_BUG
++      default n
++      ---help---
++        This is the BMI Camera driver.
++
++choice
++        prompt "Select Camera"
++        depends on (BMI_CAMERA)
++
++config BMI_CAMERA_VS6624
++        tristate "ST VS6624 camera support"
++        ---help---
++          If you plan to use the ST VS6624 Camera with your BUG system, say Y here.
++
++config BMI_CAMERA_OV2640
++        tristate "Omnivision OV2640 camera support"
++        ---help---
++          If you plan to use the Omnivision OV2640 Camera with your BUG system, say Y here.
++endchoice
++
++
+--- /dev/null
++++ git/drivers/bmi/pims/camera/Makefile
+@@ -0,0 +1,12 @@
++#ifeq ($(CONFIG_MACH_BUG),y)
++#     obj-$(CONFIG_BMI_CAMERA) += bug_v4l2_capture.o
++#endif
++
++obj-$(CONFIG_BMI_CAMERA) += bug_camera.o
++
++bmi_camera_vs6624-objs := bmi_vs6624.o vs6624_access.o
++obj-$(CONFIG_BMI_CAMERA_VS6624) += bmi_camera_vs6624.o
++
++bmi_camera_ov2640-objs := bmi_ov2640.o ov2640.o
++obj-$(CONFIG_BMI_CAMERA_OV2640) += bmi_camera_ov2640.o
++
+--- /dev/null
++++ git/drivers/bmi/pims/camera/bmi_ov2640.c
+@@ -0,0 +1,929 @@
++#include <linux/bmi.h>
++#include <linux/bmi/bmi-control.h>
++#include <linux/bmi/bmi_camera.h>
++#include <linux/delay.h>
++#include <linux/input.h>
++#include <linux/workqueue.h>
++#include "bug_camera.h"
++#include "ov2640.h"
++
++#define BMI_OV2640_VERSION  "1.0"
++
++// BMI device ID table
++static struct bmi_device_id bmi_ov2640_tbl[] =
++{
++      { .match_flags = BMI_DEVICE_ID_MATCH_VENDOR | BMI_DEVICE_ID_MATCH_PRODUCT,
++        .vendor   = BMI_VENDOR_BUG_LABS,
++        .product  = BMI_PRODUCT_CAMERA_OV2640,
++        .revision = BMI_ANY,
++      },
++      { 0, },                               /* terminate list */
++};
++MODULE_DEVICE_TABLE(bmi, bmi_ov2640_tbl);
++
++int   bmi_ov2640_probe(struct bmi_device *bdev);
++void  bmi_ov2640_remove(struct bmi_device *bdev);
++int   bmi_ov2640_suspend(struct bmi_device *bdev);
++int   bmi_ov2640_resume(struct bmi_device *bdev);
++
++// BMI driver structure
++static struct bmi_driver bmi_ov2640_driver =
++{
++      .name = "bmi_ov2640",
++      .id_table = bmi_ov2640_tbl,
++      .probe   = bmi_ov2640_probe,
++      .remove  = bmi_ov2640_remove,
++      };
++
++
++struct bmi_ov2640 {
++      struct bmi_device *bdev;
++      struct bmi_cam    bcam;
++      unsigned int    shutter;     // shutter button save state
++      unsigned int    zoomin;      // zoomin button save state
++      unsigned int    zoomout;     // zoom out button save state
++      unsigned int    flash;       // state of camera FLASH
++      int irq;
++      struct input_dev *idev;
++      struct work_struct work;
++
++};
++
++#define work_to_bmi_ov2640(w)  container_of(w, struct bmi_ov2640, work)
++
++/* IOX Bits Definitions
++
++      IOX Bit 7 CAM_RST*              Output: 0 = Reset, 1 = Normal Operation
++      IOX Bit 6 GRNLED                Output: 0 = Green LED on, 1 = Green LED off
++      IOX Bit 5 SER_SYNC              Output: 0 = Normal Operation, 1 = send SYNC
++      IOX Bit 4 FLASH_TORCH*          Output: 0 = low beam, 1 = high beam
++      IOX Bit 3 STROBE_R              I/O, not used.
++      IOX Bit 2 ZOOMB                 Input: Zoom OUT Button: 0 = depressed, 1 = released
++      IOX Bit 1 ZOOMA                 Input: Zoom IN  Button  0 = depressed, 1 = released
++      IOX Bit 0 GPIO0_SHUTTER*        Input: Shutter Button   0 = depressed, 1 = released
++
++   GPIO  Bits Definitions
++
++      GPIO Bit 3 REDLED               Output: 0 = Red LED on, 1 = Red LED off
++      GPIO Bit 2 FLASHON              Output: 0 = Flash LED off, 1 = Flash LED on
++      GPIO Bit 1 SER_RST*             Output: 0 = Serializer Reset, 1 = Normal Operation
++      GPIO Bit 0 GPIO0_SHUTTER*       Input:  Shutter Button: 0 = depressed, 1 = released
++
++
++*/
++
++
++
++      // I2C Slave Address
++#define BMI_IOX_I2C_ADDRESS   0x71    // 7-bit address
++
++      // I2C IOX register addresses
++#define IOX_INPUT_REG         0x0
++#define IOX_OUTPUT_REG                0x1
++#define IOX_POLARITY_REG      0x2
++#define IOX_CONTROL           0x3
++
++
++// read byte from I2C IO expander
++
++static int ReadByte_IOX(struct i2c_adapter *adap, unsigned char offset, unsigned char *data)
++{
++        int    ret = 0;
++        struct i2c_msg rmsg[2];
++        int    num_msgs;
++
++        /* Read Byte with Pointer */
++
++        rmsg[0].addr = BMI_IOX_I2C_ADDRESS;
++        rmsg[0].flags = 0;          /* write */
++        rmsg[0].len = 1;
++        rmsg[0].buf = &offset;
++
++        rmsg[1].addr = BMI_IOX_I2C_ADDRESS;
++        rmsg[1].flags = I2C_M_RD;   /* read */
++        rmsg[1].len = 1;
++        rmsg[1].buf = data;
++
++        num_msgs = 2;
++        ret = i2c_transfer (adap, rmsg, num_msgs);
++
++        if (ret == 2) {
++                ret = 0;
++        }
++        else {
++              printk (KERN_ERR "ReadByte_IOX() - i2c_transfer failed\n");
++                ret = -1;
++        }
++        return ret;
++}
++
++
++// write byte to I2C IO expander
++static int WriteByte_IOX(struct i2c_adapter *adap, unsigned char offset, unsigned char data)
++{
++        int    ret = 0;
++        struct i2c_msg wmsg[2];
++        int    num_msgs;
++
++        /* Write Byte with Pointer */
++
++        wmsg[0].addr = BMI_IOX_I2C_ADDRESS;
++        wmsg[0].flags = 0;          /* write */
++        wmsg[0].len = 1;
++        wmsg[0].buf = &offset;
++
++        wmsg[1].addr = BMI_IOX_I2C_ADDRESS;
++        wmsg[1].flags = 0;       /* write */
++        wmsg[1].len = 1;
++        wmsg[1].buf = &data;
++
++        num_msgs = 2;
++
++
++        ret = i2c_transfer (adap, wmsg, num_msgs);
++
++        if (ret == 2) {
++                ret = 0;
++        }
++        else {
++                printk (KERN_ERR "WriteByte_IOX() - i2c_transfer() failed.\n");
++                ret = -1;
++        }
++        return ret;
++}
++
++
++/*
++ * Input interrupt handler and support routines
++ */
++
++
++// work handler
++void bmi_ov2640_buttons_work(struct work_struct * work)
++{
++      struct i2c_adapter *adap;
++      struct bmi_ov2640 *pim = work_to_bmi_ov2640(work);
++
++      unsigned char   iox_data;
++      unsigned int    test_value;
++      int sync_flag = 0;
++      int err;
++
++
++      // avoid i2c i/o if camera hardware not present.
++
++      if (bmi_device_present (pim->bdev) == 0) {
++              goto exit;
++      }
++
++      adap = bmi_device_get_i2c_adapter (pim->bdev);
++
++
++      // read IOX data input
++      err = ReadByte_IOX (adap, IOX_INPUT_REG, &iox_data);
++      if (err) {
++              goto exit;
++      }
++
++      // zoom in button
++      test_value = !((iox_data & 0x2) >> 1);
++      if (test_value != pim->zoomin) {
++              pim->zoomin = test_value;
++              input_report_key (pim->idev, BN_ZOOMIN, test_value);
++              sync_flag = 1;
++      }
++
++
++      // zoom out button
++      test_value = !((iox_data & 0x4) >> 2);
++      if (test_value != pim->zoomout) {
++              pim->zoomout = test_value;
++              input_report_key (pim->idev, BN_ZOOMOUT, test_value);
++              sync_flag = 1;
++      }
++
++      if ( sync_flag ) {
++              input_sync (pim->idev);
++      }
++exit:
++      enable_irq (pim->irq);
++      return;
++
++}
++
++
++// interrupt handler
++static irqreturn_t module_irq_handler(int irq, void *dummy)
++{
++      struct bmi_ov2640 *pim = dummy;
++      unsigned int test_value;
++
++      int slot;
++
++      disable_irq_nosync(irq);
++
++      slot = bmi_device_get_slot(pim->bdev);
++
++
++      // shutter button on GPIO
++
++      test_value = !(bmi_read_gpio_data_reg (slot) & 0x1);
++
++      if (!test_value == pim->shutter) {
++              pim->shutter = test_value;
++              input_report_key (pim->idev, BN_SHUTTER, test_value);
++              input_sync (pim->idev);
++      }
++
++      // other buttons on I2C IOX
++      schedule_work (&pim->work);
++      return IRQ_HANDLED;
++}
++
++/*
++ * control functions
++ */
++
++
++// configure IOX IO and states
++void configure_IOX(struct bmi_ov2640 *cam)
++{
++      struct i2c_adapter *adap;
++
++      adap = bmi_device_get_i2c_adapter (cam->bdev);
++
++      WriteByte_IOX (adap, IOX_OUTPUT_REG, 0xC0);           // CAMRST* = 1, GRNLED = Off
++      WriteByte_IOX (adap, IOX_CONTROL,    0x0F);           // IOX[7:4]=OUT, IOX[3:0]=IN
++      return;
++
++}
++
++// configure GPIO IO and states
++void configure_GPIO(struct bmi_ov2640 *cam)
++{
++      // set states before turning on outputs
++
++      int slot;
++
++
++      slot = bmi_device_get_slot (cam->bdev);
++
++      bmi_set_module_gpio_data (slot, 3, 1); // Red LED=OFF
++      bmi_set_module_gpio_data (slot, 2, 0); // Flash LED=OFF
++      bmi_set_module_gpio_data (slot, 1, 0); // SER_RST=0
++
++      // configure direction
++      bmi_set_module_gpio_dir (slot, 3, BMI_GPIO_OUT);
++      bmi_set_module_gpio_dir (slot, 2, BMI_GPIO_OUT);
++      bmi_set_module_gpio_dir (slot, 1, BMI_GPIO_OUT);
++      bmi_set_module_gpio_dir (slot, 0, BMI_GPIO_IN); // SHUTTER
++
++      // This is needed.
++      bmi_set_module_gpio_data (slot, 2, 0);  // Flash LED off.
++      return;
++
++}
++
++// deconfigure IOX and GPIO
++void deconfigure_module(struct bmi_ov2640 *cam)
++{
++      int slot;
++      struct i2c_adapter *adap;
++
++      slot = bmi_device_get_slot (cam->bdev);
++      adap = bmi_device_get_i2c_adapter (cam->bdev);
++
++
++      if ( bmi_device_present (cam->bdev) ) {
++              WriteByte_IOX (adap, IOX_CONTROL, 0xFF);
++      }
++      bmi_set_module_gpio_dir (slot, 3, BMI_GPIO_IN);
++      bmi_set_module_gpio_dir (slot, 2, BMI_GPIO_IN);
++      bmi_set_module_gpio_dir (slot, 1, BMI_GPIO_IN);
++}
++
++
++// configure serializer on plug-in module
++void configure_serializer(struct bmi_ov2640 *cam)
++{
++      int slot = bmi_device_get_slot (cam->bdev);
++      bmi_set_module_gpio_data (slot, 1, 1);           // SER_RST=1
++}
++
++void deconfigure_serializer(struct bmi_ov2640 *cam)
++{
++      int slot = bmi_device_get_slot (cam->bdev);
++      bmi_set_module_gpio_data (slot, 1, 0);          // SER_RST=0
++}
++
++void enable_camera(struct bmi_ov2640 *cam)
++{
++      struct i2c_adapter *adap;
++        unsigned char iox_data;
++
++      adap = bmi_device_get_i2c_adapter (cam->bdev);
++
++        ReadByte_IOX (adap, IOX_OUTPUT_REG, &iox_data);
++
++      iox_data |=  (0x80);      //Set CAM_RST* to 1.
++
++        WriteByte_IOX (adap, IOX_OUTPUT_REG, iox_data);
++      return;
++}
++
++// disable camera on plug-in module
++void disable_camera(struct bmi_ov2640 *cam)
++{
++      struct i2c_adapter *adap;
++        unsigned char iox_data;
++
++      if (cam == NULL)
++        {
++          printk(KERN_INFO "bmi_camera_ov2640: disable_camera: NULL Pointer on cam\n");
++          return;
++        }
++      if (cam->bdev == NULL)
++        {
++          printk(KERN_INFO "bmi_camera_ov2640: disable_camera: NULL Pointer on cam->bdev\n");
++          return;
++        }
++      adap = bmi_device_get_i2c_adapter (cam->bdev);
++
++      if ( bmi_device_present(cam->bdev) ) {
++
++              ReadByte_IOX (adap, IOX_OUTPUT_REG, &iox_data);
++
++              iox_data &= ~(0x80);     //Set CAM_RST* to 0;
++
++              WriteByte_IOX (adap, IOX_OUTPUT_REG, iox_data);
++      }
++      return;
++}
++
++// generate sync
++void generate_camera_sync(struct i2c_adapter *adap)
++{
++      unsigned char iox_data[0];
++
++      ReadByte_IOX (adap, IOX_OUTPUT_REG, iox_data);
++
++      WriteByte_IOX (adap, IOX_OUTPUT_REG, *iox_data | 0x20);// SYNC = 1
++
++      WriteByte_IOX (adap, IOX_OUTPUT_REG, *iox_data & 0xD0);// SYNC = 0
++      udelay(20);                                   // 60 MHz * 1024 = ~17 us sync time
++      return;
++}
++
++void set_sync(struct i2c_adapter *adap)
++{
++      unsigned char iox_data[0];
++
++      ReadByte_IOX (adap, IOX_OUTPUT_REG, iox_data);
++      WriteByte_IOX (adap, IOX_OUTPUT_REG, *iox_data | 0x20);// SYNC = 1
++      return;
++}
++
++void clear_sync(struct i2c_adapter *adap)
++{
++      unsigned char iox_data[0];
++
++      ReadByte_IOX (adap, IOX_OUTPUT_REG, iox_data);
++      WriteByte_IOX (adap, IOX_OUTPUT_REG, *iox_data & 0xD0);// SYNC = 0
++      return;
++}
++
++
++// check serializer lock
++int check_camera_lock(void)
++{
++      return bmi_sensor_lock_status();
++}
++
++void bmi_ov2640_set_color(struct bmi_cam *cam, int bright, int saturation, int red, int green, int blue)
++{
++
++      struct i2c_adapter *adap;
++      struct bmi_ov2640 *bmi_ov2640;
++
++      bmi_ov2640 = container_of(cam, struct bmi_ov2640, bcam);
++      adap = &bmi_ov2640->bdev->adap;
++
++//    ov2640_set_color (adap, bright, saturation, red, green, blue);
++      printk (KERN_ERR "bmi_ov2640_set_color() - NOT IMPLEMENTED.\n");
++      return;
++
++}
++
++void bmi_ov2640_get_color(struct bmi_cam *cam, int *bright, int *saturation, int *red, int *green, int *blue)
++{
++      struct i2c_adapter *adap;
++      struct bmi_ov2640 *bmi_ov2640;
++
++      bmi_ov2640 = container_of(cam, struct bmi_ov2640, bcam);
++      adap = &bmi_ov2640->bdev->adap;
++
++//    ov2640_get_color (adap, bright, saturation, red, green, blue);
++      printk (KERN_ERR "bmi_ov2640_get_color() - NOT IMPLEMENTED.\n");
++      return;
++}
++
++
++
++
++void bmi_ov2640_set_ae_mode (struct bmi_cam *cam, int ae_mode)
++{
++      printk (KERN_ERR "bmi_ov2640_set_ae_mode() - NOT IMPLEMENTED.\n");
++}
++
++
++void bmi_ov2640_get_ae_mode (struct bmi_cam *cam, int *ae_mode)
++{
++      printk (KERN_ERR "bmi_ov2640_set_ae_mode() - NOT IMPLEMENTED.\n");
++}
++
++
++sensor_interface * bmi_ov2640_config (struct bmi_cam *cam, int *frame_rate, int high_quality)
++{
++
++      struct i2c_adapter *adap;
++      struct bmi_ov2640 *bmi_ov2640;
++      int i;
++
++      bmi_ov2640 = container_of(cam, struct bmi_ov2640, bcam);
++      adap = &bmi_ov2640->bdev->adap;
++
++      //Bring up the serial link
++
++      bmi_sensor_active(1);
++      configure_serializer (bmi_ov2640);
++
++      adap = &bmi_ov2640->bdev->adap;
++        set_sync (adap);
++
++        for (i = 0; i < 10; i++) {
++
++                msleep(10);
++
++                if(check_camera_lock()) {
++                        break;
++                }
++                else {
++                        printk(KERN_ERR "bmi_ov2640_config() -  camera serializer did not lock,i = %d\n", i);
++                }
++
++        }
++      clear_sync(adap);
++
++
++        if(!check_camera_lock()) {
++                printk(KERN_ERR "bmi_ov2640_config(): camera serializer NOT LOCKED\n");
++        }
++
++      return &cam->interface;
++
++}
++
++
++sensor_interface * bmi_ov2640_reset (struct bmi_cam *cam)
++{
++      struct i2c_adapter *adap;
++      struct bmi_ov2640 *bmi_ov2640;
++
++      bmi_ov2640 = container_of(cam, struct bmi_ov2640, bcam);
++
++
++      adap = bmi_device_get_i2c_adapter (bmi_ov2640->bdev);
++
++      //disable the serial link
++
++      deconfigure_serializer (bmi_ov2640);
++      bmi_sensor_inactive();
++
++      return &cam->interface;
++}
++
++int bmi_ov2640_activate (struct bmi_cam *cam, struct input_dev *idev)
++{
++      int rc = 0;
++      int i;
++      struct i2c_adapter *adap;
++      struct bmi_ov2640 *bmi_ov2640;
++
++      bmi_ov2640 = container_of(cam, struct bmi_ov2640, bcam);
++
++
++      //bmi_ov2640 struct fields
++      bmi_ov2640->idev = idev;
++
++      bmi_ov2640->shutter  = 0;
++      bmi_ov2640->zoomin   = 0;
++      bmi_ov2640->zoomout  = 0;
++      bmi_ov2640->flash    = 0;
++
++
++      // install button irq_handler
++      if (request_irq(bmi_ov2640->irq, &module_irq_handler, 0, "bmi_cam_button", bmi_ov2640)) {
++              printk (KERN_ERR
++                      "bmi_ov2640_activate() - request_irq (irq = %d) failed.\n",
++                      bmi_ov2640->irq);
++
++                      rc = -EBUSY;
++                      goto exit;
++              }
++
++      //Activate serial link
++      bmi_sensor_active(1);                 // rising edge clock
++      configure_serializer (bmi_ov2640);
++
++      adap = &bmi_ov2640->bdev->adap;
++        set_sync (adap);
++
++
++        for (i = 0; i < 10; i++) {
++
++                msleep(10);
++
++                if(check_camera_lock()) {
++                        break;
++                }
++                else {
++                        printk(KERN_ERR "bmi_ov2640_activate() -  camera serializer did not lock,i = %d\n", i);
++                }
++
++        }
++        clear_sync (adap);
++
++exit:
++      return rc;
++}
++
++int bmi_ov2640_deactivate (struct bmi_cam *cam)
++{
++      struct bmi_ov2640 *bmi_ov2640;
++      bmi_ov2640 = container_of(cam, struct bmi_ov2640, bcam);
++
++      //De-activate serial link
++      deconfigure_serializer (bmi_ov2640);
++      bmi_sensor_inactive();
++
++      //uninstall button irq_handler
++      free_irq(bmi_ov2640->irq, bmi_ov2640);
++      return 0;
++}
++
++
++void bmi_ov2640_link_enable (struct bmi_cam *cam)
++{
++      int i;
++      struct i2c_adapter *adap;
++      struct bmi_ov2640 *bmi_ov2640;
++      bmi_ov2640 = container_of(cam, struct bmi_ov2640, bcam);
++
++      //Activate serial link
++      bmi_sensor_active(1);                 // rising edge clock
++      configure_serializer (bmi_ov2640);
++
++      adap =  bmi_device_get_i2c_adapter (bmi_ov2640->bdev);
++
++        set_sync (adap);
++
++
++      //REWORK: Speed this up. (shorten delay)
++
++        for (i = 0; i < 10; i++) {
++
++                msleep(10);
++
++                if(check_camera_lock()) {
++                        break;
++                }
++                else {
++                        printk(KERN_ERR "bmi_ov2640_activate() -  camera serializer did not lock,i = %d\n", i);
++                }
++
++        }
++        clear_sync (adap);
++      return;
++}
++
++
++void bmi_ov2640_link_disable (struct bmi_cam *cam)
++{
++      struct bmi_ov2640 *bmi_ov2640;
++      bmi_ov2640 = container_of(cam, struct bmi_ov2640, bcam);
++
++
++      //De-activate serial link
++      deconfigure_serializer (bmi_ov2640);
++      bmi_sensor_inactive();
++
++      return;
++}
++
++
++int bmi_ov2640_flash_led_off (struct bmi_cam *cam)
++{
++      struct bmi_ov2640 *bmi_ov2640;
++      struct bmi_device *bdev;
++      int slot;
++
++      bmi_ov2640 = container_of(cam, struct bmi_ov2640, bcam);
++      bdev = bmi_ov2640->bdev;
++
++      slot = bmi_device_get_slot (bdev);
++
++      bmi_set_module_gpio_data (slot, 2, 0);  // Flash LED off.
++      return 0;
++}
++
++int bmi_ov2640_flash_led_on (struct bmi_cam *cam)
++{
++      struct bmi_ov2640 *bmi_ov2640;
++      struct bmi_device *bdev;
++      int slot;
++
++      bmi_ov2640 = container_of(cam, struct bmi_ov2640, bcam);
++      bdev = bmi_ov2640->bdev;
++
++      slot = bmi_device_get_slot (bdev);
++
++      bmi_set_module_gpio_data (slot, 2, 1);  // Flash LED on.
++      return 0;
++}
++
++int bmi_ov2640_flash_high_beam (struct bmi_cam *cam)
++{
++      unsigned char   data;
++      struct bmi_ov2640 *bmi_ov2640;
++      struct i2c_adapter *adap;
++
++      bmi_ov2640 = container_of(cam, struct bmi_ov2640, bcam);
++      adap = bmi_device_get_i2c_adapter (bmi_ov2640->bdev);
++
++      ReadByte_IOX (adap, IOX_INPUT_REG, &data);
++      data |= 0x10;                                   //High Beam
++      WriteByte_IOX (adap, IOX_OUTPUT_REG, data);
++
++      return 0;
++}
++
++int bmi_ov2640_flash_low_beam (struct bmi_cam *cam)
++{
++      unsigned char   data;
++      struct bmi_ov2640 *bmi_ov2640;
++      struct i2c_adapter *adap;
++
++      bmi_ov2640 = container_of(cam, struct bmi_ov2640, bcam);
++      adap = bmi_device_get_i2c_adapter (bmi_ov2640->bdev);
++
++      ReadByte_IOX (adap, IOX_INPUT_REG, &data);
++      data &= ~(0x10);                                // Low Beam
++      WriteByte_IOX (adap, IOX_OUTPUT_REG, data);
++
++      return 0;
++}
++
++int bmi_ov2640_red_led_off (struct bmi_cam *cam)
++{
++      struct bmi_ov2640 *bmi_ov2640;
++      struct bmi_device *bdev;
++      int slot;
++
++      bmi_ov2640 = container_of(cam, struct bmi_ov2640, bcam);
++      bdev = bmi_ov2640->bdev;
++
++      slot = bmi_device_get_slot (bdev);
++
++      bmi_set_module_gpio_data (slot, 3, 1);  // Red LED=OFF
++      return 0;
++}
++
++
++int bmi_ov2640_red_led_on (struct bmi_cam *cam)
++{
++      struct bmi_ov2640 *bmi_ov2640;
++      struct bmi_device *bdev;
++      int slot;
++
++      bmi_ov2640 = container_of(cam, struct bmi_ov2640, bcam);
++      bdev = bmi_ov2640->bdev;
++
++      slot = bmi_device_get_slot (bdev);
++
++      bmi_set_module_gpio_data (slot, 3, 0);  // Red LED=ON
++      return 0;
++}
++
++
++int bmi_ov2640_green_led_off (struct bmi_cam *cam)
++{
++      struct bmi_ov2640 *bmi_ov2640;
++      struct bmi_device *bdev;
++      struct i2c_adapter *adap;
++        unsigned char iox_data;
++
++      bmi_ov2640 = container_of(cam, struct bmi_ov2640, bcam);
++      bdev = bmi_ov2640->bdev;
++
++      adap = bmi_device_get_i2c_adapter (bdev);
++
++      if ( bmi_device_present(bdev) ) {
++
++              ReadByte_IOX (adap, IOX_OUTPUT_REG, &iox_data);
++
++              iox_data |=  (0x40);     //Set GRNLED to 1.(Off)
++
++              WriteByte_IOX (adap, IOX_OUTPUT_REG, iox_data);
++      }
++      return 0;
++}
++
++int bmi_ov2640_green_led_on (struct bmi_cam *cam)
++{
++      struct bmi_ov2640 *bmi_ov2640;
++      struct bmi_device *bdev;
++      struct i2c_adapter *adap;
++        unsigned char iox_data;
++
++      bmi_ov2640 = container_of(cam, struct bmi_ov2640, bcam);
++      bdev = bmi_ov2640->bdev;
++
++      adap = bmi_device_get_i2c_adapter (bdev);
++
++      if ( bmi_device_present(bdev) ) {
++
++              ReadByte_IOX (adap, IOX_OUTPUT_REG, &iox_data);
++
++              iox_data &=  ~(0x40);     //Set GRNLED to 0.(On)
++
++              WriteByte_IOX (adap, IOX_OUTPUT_REG, iox_data & 0xF0);
++      }
++      return 0;
++}
++
++
++int bmi_ov2640_probe(struct bmi_device *bdev)
++{
++
++      int slot = bmi_device_get_slot(bdev);
++
++      // allocate a driver-specific <this> structure
++
++      struct bmi_ov2640 *bmi_ov2640 = kzalloc(sizeof(struct bmi_ov2640), GFP_KERNEL);
++      if (!bmi_ov2640) {
++           return -1;
++      }
++
++      // attach <this> bmi_device structure (so we can find it later).
++
++      bmi_device_set_drvdata(bdev, bmi_ov2640);
++      printk(KERN_INFO "bmi_ov2640: probe: bmi_ov2640 pointer 0x%p \n",bdev->dev.driver_data);
++
++      // initialize bmi_ov2640 struct
++      bmi_ov2640->bdev = bdev;
++
++      // sensor interface struct fields
++
++      bmi_ov2640->bcam.interface.clk_mode   = 0;                // gated
++      bmi_ov2640->bcam.interface.ext_vsync  = 1;                // external vsync
++      bmi_ov2640->bcam.interface.Vsync_pol  = 0;                // non-inverted
++      bmi_ov2640->bcam.interface.Hsync_pol  = 0;                // non-inverted
++      bmi_ov2640->bcam.interface.pixclk_pol = 0;                // non-inverted
++      bmi_ov2640->bcam.interface.data_pol   = 0;                // non-inverted
++      bmi_ov2640->bcam.interface.data_width = 1;                // 8-bits
++      bmi_ov2640->bcam.interface.width      = 1600-1;           // 1280 - SXGA  1600 - UXGA
++      bmi_ov2640->bcam.interface.height     = 1200-1;           // 1024 - SXGA  1200 - UXGA
++
++      bmi_ov2640->bcam.interface.pixel_fmt  = IPU_PIX_FMT_UYVY; // YUV422
++      bmi_ov2640->bcam.interface.mclk       = 12000000;         // frequency/src
++
++      //bmi_camera_sensor struct fields
++
++      bmi_ov2640->bcam.sensor.set_color   = bmi_ov2640_set_color;
++      bmi_ov2640->bcam.sensor.get_color   = bmi_ov2640_get_color;
++      bmi_ov2640->bcam.sensor.set_ae_mode = bmi_ov2640_set_ae_mode;
++      bmi_ov2640->bcam.sensor.get_ae_mode = bmi_ov2640_get_ae_mode;
++      bmi_ov2640->bcam.sensor.config      = bmi_ov2640_config;
++      bmi_ov2640->bcam.sensor.reset       = bmi_ov2640_reset;
++
++      //bmi_camera_link struct fields
++
++      bmi_ov2640->bcam.link.enable        = bmi_ov2640_link_enable;
++      bmi_ov2640->bcam.link.disable       = bmi_ov2640_link_disable;
++
++      //bmi_camera_cntl struct fields
++
++      bmi_ov2640->bcam.cntl.flash_led_off    = bmi_ov2640_flash_led_off;
++      bmi_ov2640->bcam.cntl.flash_led_on     = bmi_ov2640_flash_led_on;
++      bmi_ov2640->bcam.cntl.flash_high_beam  = bmi_ov2640_flash_high_beam;
++      bmi_ov2640->bcam.cntl.flash_low_beam   = bmi_ov2640_flash_low_beam;
++      bmi_ov2640->bcam.cntl.red_led_off      = bmi_ov2640_red_led_off;
++      bmi_ov2640->bcam.cntl.red_led_on       = bmi_ov2640_red_led_on;
++      bmi_ov2640->bcam.cntl.green_led_off    = bmi_ov2640_green_led_off;
++      bmi_ov2640->bcam.cntl.green_led_on     = bmi_ov2640_green_led_on;
++
++
++      //bmi_cam struct fields
++
++      bmi_ov2640->bcam.activate   = bmi_ov2640_activate  ;
++      bmi_ov2640->bcam.deactivate = bmi_ov2640_deactivate;
++
++      //bmi_ov2640 struct fields
++      bmi_ov2640->shutter  = 0;
++      bmi_ov2640->zoomin   = 0;
++      bmi_ov2640->zoomout  = 0;
++      bmi_ov2640->flash    = 0;
++
++      bmi_ov2640->irq = bmi_device_get_status_irq (bdev);
++
++      //initialize struct work_struct
++      INIT_WORK (&bmi_ov2640->work, bmi_ov2640_buttons_work);
++
++       //Power stablization delay
++        mdelay(500);
++
++      //Do one-time hw initialization (e.g. patch)
++
++      // configure IOX
++      configure_IOX (bmi_ov2640);
++
++      // configure GPIO
++      configure_GPIO (bmi_ov2640);
++
++      // chip enable camera
++      enable_camera (bmi_ov2640);
++
++      ov2640_patch (&bmi_ov2640->bdev->adap);
++
++      //register with bug_camera
++
++      //REWORK: check return code
++      register_bug_camera (&bmi_ov2640->bcam, slot);
++
++      return 0;
++}
++
++void bmi_ov2640_remove(struct bmi_device *bdev)
++{
++
++      //get our <this> pointer
++      struct bmi_ov2640 *bmi_ov2640 = (struct bmi_ov2640*)(bmi_device_get_drvdata (bdev));
++      int slot = bmi_device_get_slot (bdev);
++
++      if (bdev == NULL)
++        {
++          printk(KERN_INFO "bmi_ov2640: bmi-ov2640_remove: NULL Pointer on bdev\n");
++          return;
++        }
++      if (bmi_ov2640 == NULL)
++        {
++          printk(KERN_INFO "bmi_ov2640: bmi_ov2640_remove: NULL Pointer on bmi_ov2640\n");
++          printk(KERN_INFO "bmi_ov2640: bmi_ov2640_remove: bdev->epid.vendor: 0x%x\n",bdev->epid.vendor);
++          printk(KERN_INFO "bmi_ov2640: bmi_ov2640_remove: bdev->epid.product: 0x%x\n",bdev->epid.product);
++          printk(KERN_INFO "bmi_ov2640: bmi_ov2640_remove: bdev->epid.revision: 0x%x\n",bdev->epid.revision);
++          printk(KERN_INFO "bmi_ov3640: bmi_ov2640_remove: bmi_ov2640 pointer 0x%p \n",bdev->dev.driver_data);
++          return;
++        }
++      //unregister with bug_camera
++      unregister_bug_camera ( &bmi_ov2640->bcam, slot);
++
++      disable_camera (bmi_ov2640);
++      deconfigure_module (bmi_ov2640);
++
++
++      flush_scheduled_work();
++
++      //de-attach driver-specific struct from bmi_device structure
++      bmi_device_set_drvdata (bdev, 0);
++
++      //free driver-specific structure
++      kfree (bmi_ov2640);
++      return;
++}
++
++
++static __init int bmi_ov2640_init(void)
++{
++       printk("BMI OV2640 Camera Sensor Driver v%s \n", BMI_OV2640_VERSION);
++
++//    Register with BMI bus.
++      return  bmi_register_driver (&bmi_ov2640_driver);
++
++}
++
++static void __exit bmi_ov2640_cleanup(void)
++{
++
++//    UnRegister with BMI bus.
++      bmi_unregister_driver (&bmi_ov2640_driver);
++      return;
++}
++
++
++module_init(bmi_ov2640_init);
++module_exit(bmi_ov2640_cleanup);
++
++MODULE_AUTHOR("EnCADIS Design, Inc.");
++MODULE_DESCRIPTION("OV2640 Camera Driver");
++MODULE_LICENSE("GPL");
++
+--- /dev/null
++++ git/drivers/bmi/pims/camera/bmi_vs6624.c
+@@ -0,0 +1,915 @@
++#include <linux/bmi.h>
++#include <linux/bmi/bmi-control.h>
++#include <linux/bmi/bmi_camera.h>
++#include <linux/delay.h>
++#include <linux/input.h>
++#include <linux/workqueue.h>
++#include "bug_camera.h"
++#include "vs6624_access.h"
++
++
++// BMI device ID table
++static struct bmi_device_id bmi_vs6624_tbl[] =
++{
++      { .match_flags = BMI_DEVICE_ID_MATCH_VENDOR | BMI_DEVICE_ID_MATCH_PRODUCT,
++        .vendor   = BMI_VENDOR_BUG_LABS,
++        .product  = BMI_PRODUCT_CAMERA_VS6624,
++        .revision = BMI_ANY,
++      },
++      { 0, },                               /* terminate list */
++};
++MODULE_DEVICE_TABLE(bmi, bmi_vs6624_tbl);
++
++int   bmi_vs6624_probe(struct bmi_device *bdev);
++void  bmi_vs6624_remove(struct bmi_device *bdev);
++int   bmi_vs6624_suspend(struct bmi_device *bdev);
++int   bmi_vs6624_resume(struct bmi_device *bdev);
++
++// BMI driver structure
++static struct bmi_driver bmi_vs6624_driver =
++{
++      .name = "bmi_vs6624",
++      .id_table = bmi_vs6624_tbl,
++      .probe   = bmi_vs6624_probe,
++      .remove  = bmi_vs6624_remove,
++      };
++
++
++struct bmi_vs6624 {
++      struct bmi_device *bdev;
++      struct bmi_cam    bcam;
++      unsigned int    shutter;     // shutter button save state
++      unsigned int    zoomin;      // zoomin button save state
++      unsigned int    zoomout;     // zoom out button save state
++      unsigned int    flash;       // state of camera FLASH
++      int irq;
++      struct input_dev *idev;
++      struct work_struct work;
++
++};
++
++      // I2C Slave Address
++#define BMI_IOX_I2C_ADDRESS   0x71    // 7-bit address
++
++      // I2C IOX register addresses
++#define IOX_INPUT_REG         0x0
++#define IOX_OUTPUT_REG                0x1
++#define IOX_POLARITY_REG      0x2
++#define IOX_CONTROL           0x3
++
++
++// read byte from I2C IO expander
++
++static int ReadByte_IOX(struct i2c_adapter *adap, unsigned char offset, unsigned char *data)
++{
++        int    ret = 0;
++        struct i2c_msg rmsg[2];
++        int    num_msgs;
++
++        /* Read Byte with Pointer */
++
++        rmsg[0].addr = BMI_IOX_I2C_ADDRESS;
++        rmsg[0].flags = 0;          /* write */
++        rmsg[0].len = 1;
++        rmsg[0].buf = &offset;
++
++        rmsg[1].addr = BMI_IOX_I2C_ADDRESS;
++        rmsg[1].flags = I2C_M_RD;   /* read */
++        rmsg[1].len = 1;
++        rmsg[1].buf = data;
++
++        num_msgs = 2;
++        ret = i2c_transfer (adap, rmsg, num_msgs);
++
++        if (ret == 2) {
++              printk (KERN_ERR "ReadByte_IOX() - data = %02X\n", *data);
++
++                ret = 0;
++        }
++        else {
++                //Rework: add conditional debug messages here
++              printk (KERN_ERR "ReadByte_IOX() - i2c_transfer failed\n");
++                ret = -1;
++        }
++        return ret;
++}
++
++
++// write byte to I2C IO expander
++static int WriteByte_IOX(struct i2c_adapter *adap, unsigned char offset, unsigned char data)
++{
++        int    ret = 0;
++        struct i2c_msg wmsg[2];
++        int    num_msgs;
++
++        /* Write Byte with Pointer */
++
++        wmsg[0].addr = BMI_IOX_I2C_ADDRESS;
++        wmsg[0].flags = 0;          /* write */
++        wmsg[0].len = 1;
++        wmsg[0].buf = &offset;
++
++        wmsg[1].addr = BMI_IOX_I2C_ADDRESS;
++        wmsg[1].flags = 0;       /* write */
++        wmsg[1].len = 1;
++        wmsg[1].buf = &data;
++
++        num_msgs = 2;
++
++
++        ret = i2c_transfer (adap, wmsg, num_msgs);
++
++        if (ret == 2) {
++              printk (KERN_ERR "WriteByte_IOX() - data = %02X\n", data);
++                ret = 0;
++        }
++        else {
++                //Rework: add conditional debug messages here
++
++                printk (KERN_ERR "WriteByte_IOX() - i2c_transfer() failed.\n");
++                ret = -1;
++        }
++        return ret;
++}
++
++
++/*
++ * Input interrupt handler and support routines
++ */
++
++
++// work handler
++void bmi_vs6624_buttons_work(void *arg)
++{
++      struct i2c_adapter *adap;
++      struct bmi_vs6624 *pim = (struct bmi_vs6624*)arg;
++
++      unsigned char   iox_data;
++      unsigned int    test_value;
++      int sync_flag = 0;
++      int err;
++
++      printk (KERN_ERR "bmi_vs6624_buttons_work() - enter\n");
++
++
++      // avoid i2c i/o if camera hardware not present.
++
++      if (bmi_device_present (pim->bdev) == 0) {
++              goto exit;
++      }
++
++      adap = bmi_device_get_i2c_adapter (pim->bdev);
++
++
++      // read IOX data input
++      err = ReadByte_IOX (adap, IOX_INPUT_REG, &iox_data);
++      if (err) {
++              goto exit;
++      }
++
++      // zoom in button
++      test_value = !((iox_data & 0x2) >> 1);
++      if (test_value != pim->zoomin) {
++              printk (KERN_ERR "bmi_vs6624buttons_work() - report ZOOMIN\n");
++              pim->zoomin = test_value;
++              input_report_key (pim->idev, BN_ZOOMIN, test_value);
++              sync_flag = 1;
++      }
++
++
++      // zoom out button
++      test_value = !((iox_data & 0x4) >> 2);
++      if (test_value != pim->zoomout) {
++              printk (KERN_ERR "bmi_vs6624_buttons_work() - report ZOOMOUT\n");
++              pim->zoomout = test_value;
++              input_report_key (pim->idev, BN_ZOOMOUT, test_value);
++              sync_flag = 1;
++      }
++#if 0
++      // flash button
++      test_value = (iox_data & 0x8) >> 3;
++      if (test_value != pim->flash) {
++              printk (KERN_ERR "bmi_vs6624_buttons_work() - report FLASH\n");
++              pim->flash = test_value;
++              input_report_key (pim->idev, BN_FLASH, test_value);
++              sync_flag = 1;
++      }
++#endif
++
++      if ( sync_flag ) {
++              printk (KERN_ERR "bmi_vs6624_buttons_work() - input_sync()ing..\n");
++              input_sync (pim->idev);
++      }
++exit:
++      printk (KERN_ERR "bmi_vs6624_buttons_work() -exit\n");
++      enable_irq (pim->irq);
++      return;
++
++}
++
++
++// interrupt handler
++static irqreturn_t module_irq_handler(int irq, void *dummy)
++{
++      struct bmi_vs6624 *pim = dummy;
++      unsigned int test_value;
++
++      int slot;
++
++      printk (KERN_ERR "module_irq_handler() - enter\n");
++
++      disable_irq_nosync(irq);
++
++      slot = bmi_device_get_slot(pim->bdev);
++
++
++      // shutter button on GPIO
++
++      test_value = !(bmi_read_gpio_data_reg (slot) & 0x1);
++
++      if (!test_value == pim->shutter) {
++              pim->shutter = test_value;
++              printk (KERN_ERR "module_irq_handler() - report SHUTTER\n");
++              input_report_key (pim->idev, BN_SHUTTER, test_value);
++              input_sync (pim->idev);
++      }
++
++      // other buttons on I2C IOX
++      schedule_work (&pim->work);
++      printk (KERN_ERR "module_irq_handler() - exit\n");
++      return IRQ_HANDLED;
++}
++
++/*
++ * control functions
++ */
++
++
++// configure IOX IO and states
++void configure_IOX(struct bmi_vs6624 *cam)
++{
++      struct i2c_adapter *adap;
++
++      adap = bmi_device_get_i2c_adapter (cam->bdev);
++
++      printk (KERN_ERR "configure_IOX() - enter\n");
++
++
++      WriteByte_IOX (adap, IOX_OUTPUT_REG, 0x40);           // CE=0, F_CHG=1,SYNC=0, TORCH=0
++      WriteByte_IOX (adap, IOX_CONTROL, 0x0F);              // IOX[7:4]=OUT, IOX[3:0]=IN
++}
++
++// configure GPIO IO and states
++void configure_GPIO(struct bmi_vs6624 *cam)
++{
++      // set states before turning on outputs
++
++      int slot;
++
++      slot = bmi_device_get_slot (cam->bdev);
++
++      bmi_set_module_gpio_data (slot, 3, 1); // Red LED=OFF
++      bmi_set_module_gpio_data (slot, 2, 1); // Green LED=OFF
++      bmi_set_module_gpio_data (slot, 1, 0); // SER_RST=0
++
++      // configure direction
++      bmi_set_module_gpio_dir (slot, 3, BMI_GPIO_OUT);
++      bmi_set_module_gpio_dir (slot, 2, BMI_GPIO_OUT);
++      bmi_set_module_gpio_dir (slot, 1, BMI_GPIO_OUT);
++      bmi_set_module_gpio_dir (slot, 0, BMI_GPIO_IN); // SHUTTER
++}
++
++// deconfigure IOX and GPIO
++void deconfigure_module(struct bmi_vs6624 *cam)
++{
++      int slot;
++      struct i2c_adapter *adap;
++
++      slot = bmi_device_get_slot (cam->bdev);
++      adap = bmi_device_get_i2c_adapter (cam->bdev);
++
++
++      if ( bmi_device_present (cam->bdev) ) {
++              WriteByte_IOX (adap, IOX_CONTROL, 0xFF);
++      }
++      bmi_set_module_gpio_dir (slot, 3, BMI_GPIO_IN);
++      bmi_set_module_gpio_dir (slot, 2, BMI_GPIO_IN);
++      bmi_set_module_gpio_dir (slot, 1, BMI_GPIO_IN);
++}
++
++
++// configure serializer on plug-in module
++void configure_serializer(struct bmi_vs6624 *cam)
++{
++      int slot = bmi_device_get_slot (cam->bdev);
++      bmi_set_module_gpio_data (slot, 1, 1);           // SER_RST=1
++}
++
++void deconfigure_serializer(struct bmi_vs6624 *cam)
++{
++      int slot = bmi_device_get_slot (cam->bdev);
++      bmi_set_module_gpio_data (slot, 1, 0);          // SER_RST=0
++}
++
++void enable_camera(struct bmi_vs6624 *cam)
++{
++      struct i2c_adapter *adap;
++      unsigned char iox_data;
++
++        printk (KERN_ERR "enable_camera() enter\n");
++
++      adap = bmi_device_get_i2c_adapter (cam->bdev);
++
++        // The first i2c read seems to mess everything up.
++
++        ReadByte_IOX (adap, IOX_OUTPUT_REG, &iox_data);
++        printk (KERN_ERR "enable_camera() iox_data = %02X\n", iox_data);
++
++        WriteByte_IOX (adap, IOX_OUTPUT_REG, iox_data | 0x80);
++        printk (KERN_ERR "enable_camera() exit\n");
++}
++
++// disable camera on plug-in module
++void disable_camera(struct bmi_vs6624 *cam)
++{
++      struct i2c_adapter *adap;
++      unsigned char iox_data;
++
++        printk (KERN_ERR "disable_camera() enter\n");
++
++      adap = bmi_device_get_i2c_adapter (cam->bdev);
++
++      if ( bmi_device_present(cam->bdev) ) {
++
++              ReadByte_IOX (adap, IOX_OUTPUT_REG, &iox_data);
++              WriteByte_IOX (adap, IOX_OUTPUT_REG, iox_data & 0x70);
++      }
++
++        printk (KERN_ERR "disable_camera() exit\n");
++}
++
++// generate sync
++void generate_camera_sync(struct i2c_adapter *adap)
++{
++      unsigned char iox_data[0];
++
++      printk(KERN_INFO "generate_camera_sync() - enter\n");
++      ReadByte_IOX (adap, IOX_OUTPUT_REG, iox_data);
++
++      printk(KERN_INFO "generate_camera_sync() - read  = %02X\n", iox_data[0]);
++      printk(KERN_INFO "generate_camera_sync() - write = %02X\n", *iox_data | 0x20);
++
++      WriteByte_IOX (adap, IOX_OUTPUT_REG, *iox_data | 0x20);// SYNC = 1
++
++      printk(KERN_INFO "generate_camera_sync() - write = %02X\n", *iox_data & 0xD0);
++
++      WriteByte_IOX (adap, IOX_OUTPUT_REG, *iox_data & 0xD0);// SYNC = 0
++      udelay(20);                                   // 60 MHz * 1024 = ~17 us sync time
++
++      printk(KERN_INFO "generate_camera_sync() - exit\n");
++}
++
++void set_sync(struct i2c_adapter *adap)
++{
++      unsigned char iox_data[0];
++
++      printk(KERN_INFO "set_sync() - enter\n");
++
++      ReadByte_IOX (adap, IOX_OUTPUT_REG, iox_data);
++      WriteByte_IOX (adap, IOX_OUTPUT_REG, *iox_data | 0x20);// SYNC = 1
++
++      printk(KERN_INFO "set_sync() - exit\n");
++}
++
++void clear_sync(struct i2c_adapter *adap)
++{
++      unsigned char iox_data[0];
++
++      printk(KERN_INFO "clear_sync() - enter\n");
++
++      ReadByte_IOX (adap, IOX_OUTPUT_REG, iox_data);
++      WriteByte_IOX (adap, IOX_OUTPUT_REG, *iox_data & 0xD0);// SYNC = 0
++
++      printk(KERN_INFO "clear_sync() - exit\n");
++}
++
++
++// check serializer lock
++int check_camera_lock(void)
++{
++      return bmi_sensor_lock_status();
++}
++
++void bmi_vs6624_set_color(struct bmi_cam *cam, int bright, int saturation, int red, int green, int blue)
++{
++
++      struct i2c_adapter *adap;
++      struct bmi_vs6624 *bmi_vs6624;
++
++      bmi_vs6624 = container_of(cam, struct bmi_vs6624, bcam);
++      adap = &bmi_vs6624->bdev->adap;
++
++      vs6624_set_color (adap, bright, saturation, red, green, blue);
++      return;
++
++}
++
++void bmi_vs6624_get_color(struct bmi_cam *cam, int *bright, int *saturation, int *red, int *green, int *blue)
++{
++      struct i2c_adapter *adap;
++      struct bmi_vs6624 *bmi_vs6624;
++
++      bmi_vs6624 = container_of(cam, struct bmi_vs6624, bcam);
++      adap = &bmi_vs6624->bdev->adap;
++
++      vs6624_get_color (adap, bright, saturation, red, green, blue);
++      return;
++}
++
++
++
++
++void bmi_vs6624_set_ae_mode (struct bmi_cam *cam, int ae_mode)
++{
++      printk (KERN_ERR "bmi_vs6624_set_ae_mode() - NOT IMPLEMENTED.\n");
++}
++
++
++void bmi_vs6624_get_ae_mode (struct bmi_cam *cam, int *ae_mode)
++{
++      printk (KERN_ERR "bmi_vs6624_set_ae_mode() - NOT IMPLEMENTED.\n");
++}
++
++
++sensor_interface * bmi_vs6624_config (struct bmi_cam *cam, int *frame_rate, int high_quality)
++{
++      //REWORK: Add code here
++      struct i2c_adapter *adap;
++      struct bmi_vs6624 *bmi_vs6624;
++      int i;
++
++      bmi_vs6624 = container_of(cam, struct bmi_vs6624, bcam);
++      adap = &bmi_vs6624->bdev->adap;
++
++      printk (KERN_ERR "bmi_vs6624_CONFIG() - enter\n");
++
++        if(check_camera_lock()) {
++                printk(KERN_INFO "bmi_vs6624_config(): camera serializer LOCKED\n");
++        }
++        else {
++                printk(KERN_ERR "bmi_vs6624_config(): camera serializer NOT LOCKED\n");
++        }
++
++      //Bring up the serial link
++
++      bmi_sensor_active(1);
++      configure_serializer (bmi_vs6624);
++
++      adap = &bmi_vs6624->bdev->adap;
++        set_sync (adap);
++
++        for (i = 0; i < 10; i++) {
++
++                msleep(10);
++
++                if(check_camera_lock()) {
++                        printk(KERN_INFO "bmi_vs6624_config() - camera serializer locked, i = %d\n", i);
++                        break;
++                }
++                else {
++                        printk(KERN_ERR "bmi_vs6624_config() -  camera serializer did not lock,i = %d\n", i);
++                }
++
++        }
++        clear_sync (adap);
++
++
++        if(check_camera_lock()) {
++
++                printk(KERN_INFO "bmi_vs6624_config(): camera serializer LOCKED\n");
++        }
++        else {
++                printk(KERN_ERR "bmi_vs6624_config(): camera serializer NOT LOCKED\n");
++        }
++
++
++      printk (KERN_ERR "bmi_vs6624_CONFIG() - exit\n");
++      return &cam->interface;
++
++}
++
++
++sensor_interface * bmi_vs6624_reset (struct bmi_cam *cam)
++{
++      //REWORK: Add code here
++      //REWORK: What is a valid soft reset sequence ?
++      struct i2c_adapter *adap;
++      struct bmi_vs6624 *bmi_vs6624;
++
++      printk (KERN_ERR "bmi_vs6624_RESET() - enter\n");
++
++      bmi_vs6624 = container_of(cam, struct bmi_vs6624, bcam);
++
++
++      adap = bmi_device_get_i2c_adapter (bmi_vs6624->bdev);
++
++        if(check_camera_lock()) {
++                printk(KERN_INFO "bmi_vs6624_reset(): camera serializer LOCKED\n");
++        }
++        else {
++                printk(KERN_ERR "bmi_vs6624_reset(): camera serializer NOT LOCKED\n");
++        }
++      //disable the serial link
++
++      deconfigure_serializer (bmi_vs6624);
++      bmi_sensor_inactive();
++
++        if(check_camera_lock()) {
++
++                printk(KERN_INFO "bmi_vs6624_reset(): camera serializer LOCKED\n");
++        }
++        else {
++                printk(KERN_ERR "bmi_vs6624_reset(): camera serializer NOT LOCKED\n");
++        }
++
++      printk (KERN_ERR "bmi_vs6624_RESET() - exit\n");
++
++      return &cam->interface;
++}
++
++int bmi_vs6624_activate (struct bmi_cam *cam, struct input_dev *idev)
++{
++      //REWORK: Add code here
++      int rc = 0;
++      int i;
++      struct i2c_adapter *adap;
++      struct bmi_vs6624 *bmi_vs6624;
++
++      printk (KERN_ERR "int bmi_vs6624_activate () - enter\n");
++
++      bmi_vs6624 = container_of(cam, struct bmi_vs6624, bcam);
++
++
++      //bmi_vs6624 struct fields
++      bmi_vs6624->idev = idev;
++
++      bmi_vs6624->shutter  = 0;
++      bmi_vs6624->zoomin   = 0;
++      bmi_vs6624->zoomout  = 0;
++      bmi_vs6624->flash    = 0;
++
++      printk (KERN_ERR "bmi_vs6624_activate () - irq = %d\n", bmi_vs6624->irq);
++
++      // install button irq_handler
++      if (request_irq(bmi_vs6624->irq, &module_irq_handler, 0, "bmi_cam_button", bmi_vs6624)) {
++              printk (KERN_ERR
++                      "bmi_vs6624_activate() - request_irq (irq = %d) failed.\n",
++                      bmi_vs6624->irq);
++
++                      rc = -EBUSY;
++                      goto exit;
++              }
++
++      //Activate serial link
++      bmi_sensor_active(1);                 // rising edge clock
++      configure_serializer (bmi_vs6624);
++
++      adap = &bmi_vs6624->bdev->adap;
++        set_sync (adap);
++
++
++        for (i = 0; i < 10; i++) {
++
++                msleep(10);
++
++                if(check_camera_lock()) {
++                        printk(KERN_INFO "bmi_vs6624_activate() - camera serializer locked, i = %d\n", i);
++                        break;
++                }
++                else {
++                        printk(KERN_ERR "bmi_vs6624_activate() -  camera serializer did not lock,i = %d\n", i);
++                }
++
++        }
++        clear_sync (adap);
++
++        if(check_camera_lock()) {
++                printk(KERN_INFO "bmi_vs6624_activate(): camera serializer LOCKED\n");
++        }
++        else {
++                printk(KERN_ERR "bmi_vs6624_activate(): camera serializer NOT LOCKED\n");
++        }
++
++
++exit:
++      printk (KERN_ERR "int bmi_vs6624_activate () - exit\n");
++      return rc;
++}
++
++int bmi_vs6624_deactivate (struct bmi_cam *cam)
++{
++      //REWORK: Add code here
++
++      struct bmi_vs6624 *bmi_vs6624;
++      bmi_vs6624 = container_of(cam, struct bmi_vs6624, bcam);
++
++
++      //De-activate serial link
++      deconfigure_serializer (bmi_vs6624);
++      bmi_sensor_inactive();
++
++
++      //uninstall button irq_handler
++      free_irq(bmi_vs6624->irq, bmi_vs6624);
++
++
++      return 0;
++}
++
++
++void bmi_vs6624_link_enable (struct bmi_cam *cam)
++{
++      //REWORK: Add code here
++
++      int i;
++      struct i2c_adapter *adap;
++      struct bmi_vs6624 *bmi_vs6624;
++      bmi_vs6624 = container_of(cam, struct bmi_vs6624, bcam);
++
++      //Activate serial link
++      bmi_sensor_active(1);                 // rising edge clock
++      configure_serializer (bmi_vs6624);
++
++      adap =  bmi_device_get_i2c_adapter (bmi_vs6624->bdev);
++
++        set_sync (adap);
++
++
++      //REWORK: Speed this up. (shorten delay)
++
++        for (i = 0; i < 10; i++) {
++
++                msleep(10);
++
++                if(check_camera_lock()) {
++                        printk(KERN_INFO "bmi_vs6624_activate() - camera serializer locked, i = %d\n", i);
++                        break;
++                }
++                else {
++                        printk(KERN_ERR "bmi_vs6624_activate() -  camera serializer did not lock,i = %d\n", i);
++                }
++
++        }
++        clear_sync (adap);
++
++        if(check_camera_lock()) {
++                printk(KERN_INFO "bmi_vs6624_activate(): camera serializer LOCKED\n");
++        }
++        else {
++                printk(KERN_ERR "bmi_vs6624_activate(): camera serializer NOT LOCKED\n");
++        }
++
++      return;
++}
++
++
++void bmi_vs6624_link_disable (struct bmi_cam *cam)
++{
++      struct bmi_vs6624 *bmi_vs6624;
++      bmi_vs6624 = container_of(cam, struct bmi_vs6624, bcam);
++
++
++      //De-activate serial link
++      deconfigure_serializer (bmi_vs6624);
++      bmi_sensor_inactive();
++
++      return;
++}
++
++
++
++int bmi_vs6624_red_led_off (struct bmi_cam *cam)
++{
++      struct bmi_vs6624 *bmi_vs6624;
++      struct bmi_device *bdev;
++      int slot;
++
++      bmi_vs6624 = container_of(cam, struct bmi_vs6624, bcam);
++      bdev = bmi_vs6624->bdev;
++
++      slot = bmi_device_get_slot (bdev);
++
++      bmi_set_module_gpio_data (slot, 3, 1);  // Red LED=OFF
++      return 0;
++}
++
++
++int bmi_vs6624_red_led_on (struct bmi_cam *cam)
++{
++      struct bmi_vs6624 *bmi_vs6624;
++      struct bmi_device *bdev;
++      int slot;
++
++      bmi_vs6624 = container_of(cam, struct bmi_vs6624, bcam);
++      bdev = bmi_vs6624->bdev;
++
++      slot = bmi_device_get_slot (bdev);
++
++      bmi_set_module_gpio_data (slot, 3, 0);  // Red LED=ON
++      return 0;
++}
++
++
++int bmi_vs6624_green_led_off (struct bmi_cam *cam)
++{
++      struct bmi_vs6624 *bmi_vs6624;
++      struct bmi_device *bdev;
++      int slot;
++
++      bmi_vs6624 = container_of(cam, struct bmi_vs6624, bcam);
++      bdev = bmi_vs6624->bdev;
++
++      slot = bmi_device_get_slot (bdev);
++
++      bmi_set_module_gpio_data (slot, 2, 1);  // Green LED=OFF
++      return 0;
++}
++
++
++int bmi_vs6624_green_led_on (struct bmi_cam *cam)
++{
++      struct bmi_vs6624 *bmi_vs6624;
++      struct bmi_device *bdev;
++      int slot;
++
++      bmi_vs6624 = container_of(cam, struct bmi_vs6624, bcam);
++      bdev = bmi_vs6624->bdev;
++
++      slot = bmi_device_get_slot (bdev);
++
++      bmi_set_module_gpio_data (slot, 2, 0);  // Green LED=ON
++      return 0;
++}
++
++
++int bmi_vs6624_probe(struct bmi_device *bdev)
++{
++
++      //REWORK: Add code here
++
++      int slot = bmi_device_get_slot(bdev);
++
++
++      // allocate a driver-specific <this> structure
++
++      struct bmi_vs6624 *bmi_vs6624 = kzalloc(sizeof(struct bmi_vs6624), GFP_KERNEL);
++      if (!bmi_vs6624) {
++           return -1;
++      }
++
++      // attach <this> bmi_device structure (so we can find it later).
++      bmi_device_set_drvdata(bdev, bmi_vs6624);
++
++
++      // initialize bmi_vs6624 struct
++      bmi_vs6624->bdev = bdev;
++
++      // sensor interface struct fields
++# if 1
++      bmi_vs6624->bcam.interface.clk_mode   = 0;                // gated
++      bmi_vs6624->bcam.interface.ext_vsync  = 1;                // external vsync
++#else
++      bmi_vs6624->bcam.interface.clk_mode   = 2;                // progressive
++      bmi_vs6624->bcam.interface.ext_vsync  = 0;                // internal vsync
++# endif
++      bmi_vs6624->bcam.interface.Vsync_pol  = 0;                // non-inverted
++      bmi_vs6624->bcam.interface.Hsync_pol  = 0;                // non-inverted
++      bmi_vs6624->bcam.interface.pixclk_pol = 0;                // non-inverted
++      bmi_vs6624->bcam.interface.data_pol   = 0;                // non-inverted   MTW=1
++      bmi_vs6624->bcam.interface.data_width = 1;                // 8-bits
++      bmi_vs6624->bcam.interface.width      = 1280-1;           // 1280 - SXGA
++      bmi_vs6624->bcam.interface.height     = 1024-1;           // 1024 - SXGA
++
++      bmi_vs6624->bcam.interface.pixel_fmt  = IPU_PIX_FMT_UYVY; // YUV422
++      bmi_vs6624->bcam.interface.mclk       = 12000000;         // frequency/src
++
++      //bmi_camera_sensor struct fields
++
++      bmi_vs6624->bcam.sensor.set_color   = bmi_vs6624_set_color;
++      bmi_vs6624->bcam.sensor.get_color   = bmi_vs6624_get_color;
++      bmi_vs6624->bcam.sensor.set_ae_mode = bmi_vs6624_set_ae_mode;
++      bmi_vs6624->bcam.sensor.get_ae_mode = bmi_vs6624_get_ae_mode;
++      bmi_vs6624->bcam.sensor.config      = bmi_vs6624_config;
++      bmi_vs6624->bcam.sensor.reset       = bmi_vs6624_reset;
++
++      //bmi_camera_link struct fields
++
++      bmi_vs6624->bcam.link.enable        = bmi_vs6624_link_enable;
++      bmi_vs6624->bcam.link.disable       = bmi_vs6624_link_disable;
++
++      //bmi_camera_cntl struct fields
++
++      bmi_vs6624->bcam.cntl.flash_led_off    = 0;
++      bmi_vs6624->bcam.cntl.flash_led_off    = 0;
++      bmi_vs6624->bcam.cntl.flash_high_beam  = 0;
++      bmi_vs6624->bcam.cntl.flash_low_beam   = 0;
++      bmi_vs6624->bcam.cntl.red_led_off      = bmi_vs6624_red_led_off;
++      bmi_vs6624->bcam.cntl.red_led_on       = bmi_vs6624_red_led_on;
++      bmi_vs6624->bcam.cntl.green_led_off    = bmi_vs6624_green_led_off;
++      bmi_vs6624->bcam.cntl.green_led_on     = bmi_vs6624_green_led_on;
++
++
++      //bmi_cam struct fields
++
++      bmi_vs6624->bcam.activate   = bmi_vs6624_activate  ;
++      bmi_vs6624->bcam.deactivate = bmi_vs6624_deactivate;
++
++      //bmi_vs6624 struct fields
++      bmi_vs6624->shutter  = 0;
++      bmi_vs6624->zoomin   = 0;
++      bmi_vs6624->zoomout  = 0;
++      bmi_vs6624->flash    = 0;
++
++      bmi_vs6624->irq = bmi_device_get_status_irq (bdev);
++
++      //initialize struct work_struct
++      INIT_WORK (&bmi_vs6624->work, bmi_vs6624_buttons_work, bmi_vs6624);
++
++      //Power stablization delay
++      mdelay(500);
++
++      //Do one-time hw initialization (e.g. patch)
++
++      // configure IOX
++      configure_IOX (bmi_vs6624);
++
++      // configure GPIO
++      configure_GPIO (bmi_vs6624);
++
++      // chip enable camera
++      enable_camera (bmi_vs6624);
++
++      vs6624_patch (&bmi_vs6624->bdev->adap);
++
++      //register with bug_camera
++
++      //REWORK: check return code
++      register_bug_camera (&bmi_vs6624->bcam, slot);
++
++      return 0;
++}
++
++void bmi_vs6624_remove(struct bmi_device *bdev)
++{
++      //REWORK: Add code here
++
++
++      //get our <this> pointer
++      struct bmi_vs6624 *bmi_vs6624 = (struct bmi_vs6624*)(bmi_device_get_drvdata (bdev));
++      int slot = bmi_device_get_slot (bdev);
++
++
++      //unregister with bug_camera
++      unregister_bug_camera ( &bmi_vs6624->bcam, slot);
++
++      //REWORK: Avoid I2c access if camera module is not present.
++
++      disable_camera (bmi_vs6624);
++      deconfigure_module (bmi_vs6624);
++
++
++      flush_scheduled_work();
++
++      //de-attach driver-specific struct from bmi_device structure
++      bmi_device_set_drvdata (bdev, 0);
++
++      //free driver-specific structure
++      kfree (bmi_vs6624);
++      return;
++}
++
++
++static __init int bmi_vs6624_init(void)
++{
++
++//    Register with BMI bus.
++      return  bmi_register_driver (&bmi_vs6624_driver);
++
++}
++
++static void __exit bmi_vs6624_cleanup(void)
++{
++
++//    UnRegister with BMI bus.
++      bmi_unregister_driver (&bmi_vs6624_driver);
++      return;
++}
++
++
++module_init(bmi_vs6624_init);
++module_exit(bmi_vs6624_cleanup);
++
++MODULE_AUTHOR("EnCADIS Design, Inc.");
++MODULE_DESCRIPTION("VS6624 Camera Driver");
++MODULE_LICENSE("GPL");
++
+--- /dev/null
++++ git/drivers/bmi/pims/camera/bug_camera.c
+@@ -0,0 +1,611 @@
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/input.h>
++#include <linux/cdev.h>
++#include <linux/bmi/bmi_camera.h>
++#include "bug_camera.h"
++
++#define BUG_CAMERA_VERSION  "1.0"
++
++
++struct cam_ctl
++{
++  int slot;
++  struct cdev cdev;
++  struct device *class_dev;
++};
++
++// private device structure
++struct bug_cam
++{
++      unsigned int    cam_cnt;                //number of cameras present
++      unsigned int    active;                 //active camera slot
++
++      struct bmi_cam  *bcam[4];               //slot-specific behavior
++
++      struct input_dev *input_dev;            // input device
++  struct cam_ctl      cntl[4];                // control character device
++      struct device *class_dev;
++      int             cntl_devno;             // control device number
++      int             open_flag;              // force single open
++};
++
++static struct bug_cam bug_cam;
++
++static int cntl_open (struct inode *, struct file *);
++static int cntl_release (struct inode *, struct file *);
++static int cntl_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
++// control file operations
++
++struct file_operations cam_ctl_fops = {
++      .owner = THIS_MODULE,
++      .ioctl = cntl_ioctl,
++      .open = cntl_open,
++      .release = cntl_release,
++};
++
++/*
++ * control device operations
++ */
++
++static int cam_ctl_major;
++
++int ctl_init (void)
++{
++      dev_t   dev_id;
++      int     retval;
++
++      // alloc char driver with 4 minor numbers
++
++      retval = alloc_chrdev_region(&dev_id, 0, 4, "BUG Camera Control");
++
++      if (retval) {
++              return -1;
++      }
++      cam_ctl_major = MAJOR(dev_id);
++      return 0;
++}
++
++void ctl_clean (void)
++{
++      dev_t dev_id;
++
++      dev_id = MKDEV(cam_ctl_major, 0);
++      unregister_chrdev_region(dev_id, 4);
++      return;
++}
++
++int ctl_probe (struct cam_ctl *cam_ctl, int slot)
++{
++      struct cdev *cdev;
++      dev_t dev_id;
++      int ret;
++      struct class *bmi_class;
++
++      cdev = &cam_ctl->cdev;
++      cdev_init (cdev, &cam_ctl_fops);
++
++      dev_id = MKDEV (cam_ctl_major, slot);
++      ret = cdev_add (cdev, dev_id, 1);
++
++      //Create class device
++      bmi_class = bmi_get_bmi_class ();
++
++      cam_ctl->class_dev = device_create (bmi_class, NULL, MKDEV(cam_ctl_major, slot), cam_ctl, "bmi_cam_ctl_m%i", slot+1);
++
++      if (IS_ERR(cam_ctl->class_dev)) {
++              printk(KERN_ERR "Unable to create "
++                     "class_device for bmi_cam_ctl_m%i; errno = %ld\n",
++                     slot+1, PTR_ERR(cam_ctl->class_dev));
++              cam_ctl->class_dev = NULL;
++      }
++      cam_ctl->slot = slot;
++
++      return ret;
++}
++
++void ctl_remove (struct cam_ctl *cam_ctl, int slot)
++{
++      struct class *bmi_class;
++
++      bmi_class = bmi_get_bmi_class ();
++      device_destroy (bmi_class, MKDEV(cam_ctl_major, slot));
++
++      cam_ctl->class_dev = 0;
++
++      cdev_del (&cam_ctl->cdev);
++      return;
++}
++
++// open
++static int cntl_open(struct inode *inode, struct file *filp)
++{
++      if (bug_cam.open_flag) {
++              return - EBUSY;
++      }
++      bug_cam.open_flag = 1;
++      filp->private_data = &bug_cam;
++      return 0;
++}
++
++// release
++static int cntl_release(struct inode *inode, struct file *filp)
++{
++      bug_cam.open_flag = 0;
++      return 0;
++}
++
++
++
++
++static struct bmi_cam* get_selected (void)
++{
++      struct bmi_cam *bcam;
++
++      if (bug_cam.active == -1) {
++              return 0;
++      }
++
++      bcam =  bug_cam.bcam [bug_cam.active];
++      return bcam;
++
++}
++
++
++static int select_slot (int slot)
++{
++      struct bmi_cam *bcam;
++
++      // validate slot number
++      if ((slot < 0) || slot > 3) {
++
++              printk(KERN_ERR
++                      "bug_camera.c: Invalid value (%d) for camera selection.\n",
++                       slot);
++
++              return -EINVAL;
++      }
++
++      // error if this slot not registered
++      if ( bug_cam.bcam [slot] == NULL ) {
++              return -ENODEV;
++      }
++
++      // abort if this slot already active
++      if (bug_cam.active == slot) {
++              return 0;
++      }
++
++      // if another slot is active, deactivate it.
++      if (bug_cam.active != -1) {
++              bcam =  bug_cam.bcam [bug_cam.active];
++              if ((bcam) && (bcam->deactivate)) {
++                      bcam->deactivate (bcam);
++              }
++      }
++
++      // activate this slot
++      bcam =  bug_cam.bcam [slot];
++      if (bcam->activate) {
++              bcam->activate (bcam, bug_cam.input_dev);
++      }
++      bug_cam.active = slot;
++      return 0;
++}
++
++
++// ioctl
++static int cntl_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
++             unsigned long arg)
++{
++      struct bmi_cam *bcam;
++      int err;
++
++      switch (cmd) {
++
++        // error if no camera selected. (active)
++
++      case BMI_CAM_FLASH_LED_ON:
++
++              bcam =  get_selected();
++              if ((bcam) && (bcam->cntl.flash_led_on)) {
++                      bcam->cntl.flash_led_on (bcam);
++              }
++              return 0;
++
++      case BMI_CAM_FLASH_LED_OFF:
++
++              bcam =  get_selected();
++              if ((bcam) && (bcam->cntl.flash_led_off)) {
++                      bcam->cntl.flash_led_off (bcam);
++              }
++              return 0;
++
++
++      case BMI_CAM_FLASH_HIGH_BEAM:
++
++              bcam =  get_selected();
++              if ((bcam) && (bcam->cntl.flash_high_beam)) {
++                      bcam->cntl.flash_high_beam (bcam);
++              }
++              return 0;
++
++      case BMI_CAM_FLASH_LOW_BEAM:
++
++              bcam =  get_selected();
++              if ((bcam) && (bcam->cntl.flash_low_beam)) {
++                      bcam->cntl.flash_low_beam (bcam);
++              }
++              return 0;
++
++      case BMI_CAM_RED_LED_OFF:
++
++              bcam =  get_selected();
++              if ((bcam) && (bcam->cntl.red_led_off)) {
++                      bcam->cntl.red_led_off (bcam);
++              }
++              return 0;
++
++      case BMI_CAM_RED_LED_ON:
++
++              bcam =  get_selected();
++              if ((bcam) && (bcam->cntl.red_led_on)) {
++                      bcam->cntl.red_led_on (bcam);
++              }
++              return 0;
++
++      case BMI_CAM_GREEN_LED_OFF:
++
++              bcam =  get_selected();
++              if ((bcam) && (bcam->cntl.green_led_off)) {
++                      bcam->cntl.green_led_off (bcam);
++              }
++              return 0;
++
++      case BMI_CAM_GREEN_LED_ON:
++
++              bcam =  get_selected();
++              if ((bcam) && (bcam->cntl.green_led_on)) {
++                      bcam->cntl.green_led_on (bcam);
++              }
++              return 0;
++
++        case BMI_CAM_SELECT:
++
++              err = select_slot (arg);
++              return err;
++
++        case BMI_CAM_GET_SELECTED:
++
++              return (int) bug_cam.active;
++
++        default:
++              return -ENOTTY;
++      }
++      return 0;
++}
++
++
++void bug_camera_set_color(int bright, int saturation, int red, int green, int blue)
++{
++      //delegate to active bmi_cam.
++
++      struct bmi_cam *bcam;
++
++      if (bug_cam.active == -1) {
++              return;
++      }
++
++      bcam =  bug_cam.bcam [bug_cam.active];
++
++      if ((bcam) && (bcam->sensor.set_color)) {
++              bcam->sensor.set_color (bcam, bright, saturation, red, green, blue);
++      }
++      return;
++
++}
++
++void bug_camera_get_color(int *bright, int *saturation, int *red, int *green, int *blue)
++{
++      //delegate to active bmi_cam.
++
++      struct bmi_cam *bcam;
++
++      if (bug_cam.active == -1) {
++              return;
++      }
++
++      bcam =  bug_cam.bcam [bug_cam.active];
++
++      if ((bcam) && (bcam->sensor.get_color)) {
++              bcam->sensor.get_color (bcam, bright, saturation, red, green, blue);
++      }
++      return;
++}
++
++
++
++
++void bug_camera_set_ae_mode (int ae_mode)
++{
++      //delegate to active bmi_cam.
++      printk (KERN_ERR " bug_camera_set_ae_mode() - NOT IMPLEMENTED.\n");
++}
++
++
++void bug_camera_get_ae_mode (int *ae_mode)
++{
++      //delegate to active bmi_cam.
++      printk (KERN_ERR " bug_camera_set_ae_mode() - NOT IMPLEMENTED.\n");
++}
++
++
++sensor_interface * bug_camera_config (int *frame_rate, int high_quality)
++{
++      //delegate to active bmi_cam.
++
++      struct bmi_cam *bcam;
++      sensor_interface *sensor_if = 0;
++
++      if (bug_cam.active == -1) {
++              return 0;
++      }
++
++      bcam =  bug_cam.bcam [bug_cam.active];
++
++      if ((bcam) && (bcam->sensor.config)) {
++              sensor_if = bcam->sensor.config (bcam, frame_rate, high_quality);
++      }
++      return sensor_if;
++}
++
++
++sensor_interface * bug_camera_reset (void)
++{
++
++      //delegate to active bmi_cam.
++
++      struct bmi_cam *bcam;
++      sensor_interface *sensor_if = 0;
++
++      if (bug_cam.active == -1) {
++              return 0;
++      }
++
++      bcam =  bug_cam.bcam [bug_cam.active];
++
++      if ((bcam) && (bcam->sensor.reset)) {
++              sensor_if = bcam->sensor.reset(bcam);
++      }
++      return sensor_if;
++}
++
++void bug_camera_link_enable (void)
++{
++      //delegate to active bmi_cam.
++
++      struct bmi_cam *bcam;
++
++      if (bug_cam.active == -1) {
++              return;
++      }
++
++      bcam =  bug_cam.bcam [bug_cam.active];
++
++      if ((bcam) && (bcam->link.enable)) {
++              bcam->link.enable(bcam);
++      }
++      return;
++}
++
++void bug_camera_link_disable (void)
++{
++      //delegate to active bmi_cam.
++
++      struct bmi_cam *bcam;
++
++      if (bug_cam.active == -1) {
++              return;
++      }
++
++      bcam =  bug_cam.bcam [bug_cam.active];
++
++      if ((bcam) && (bcam->link.disable)) {
++              bcam->link.disable(bcam);
++      }
++      return;
++}
++
++
++// Link point for bug_v4l2_capture
++
++struct camera_sensor camera_sensor_if = {
++
++        set_color:  bug_camera_set_color,
++        get_color:  bug_camera_get_color,
++        config:     bug_camera_config,
++        reset:      bug_camera_reset,
++};
++
++
++struct camera_link camera_link_if = {
++      enable:     bug_camera_link_enable,
++      disable:    bug_camera_link_disable,
++
++};
++
++int register_bug_camera( struct bmi_cam *bcam, int slot)
++{
++      printk (KERN_ERR "register_bug_camera() - slot = %d\n", slot);
++
++      if (!bcam) {
++              return -1;
++      }
++      if ((slot < 0) || (slot > 3)) {
++              return -1;
++      }
++      if ( bug_cam.bcam [slot]) {
++              return -1;
++      }
++      else {
++              bug_cam.bcam [slot] = bcam;
++              bug_cam.cam_cnt += 1;
++      }
++
++      if (ctl_probe(&bug_cam.cntl[slot], slot)) {
++          printk(KERN_ERR "\n");
++        }
++      // Activate this camera if no other is active
++      if ( bug_cam.active == -1) {
++              bug_cam.active = slot;
++              bcam->activate( bcam, bug_cam.input_dev);
++      }
++
++      return 0;
++
++}
++
++int unregister_bug_camera( struct bmi_cam *bcam, int slot)
++{
++
++      if (!bcam) {
++              return -1;
++      }
++      if ((slot < 0) || (slot > 3)) {
++              return -1;
++      }
++      if ( bug_cam.bcam [slot]  != bcam) {
++              return -1;
++      }
++      else {
++              bug_cam.bcam [slot] = 0;
++              bug_cam.cam_cnt -= 1;
++
++              // Deactivate this camera if active
++
++              if (bug_cam.active == slot) {
++                      bcam->deactivate( bcam);
++                      bug_cam.active = -1;
++              }
++
++      }
++      return 0;
++}
++
++static __init int bug_camera_init(void)
++{
++      int err = 0;
++      struct class *bmi_class;
++
++      printk("BUG Camera Driver v%s \n", BUG_CAMERA_VERSION);
++
++      memset (&bug_cam, 0, sizeof(struct bug_cam));
++
++      //No camera is active.
++      bug_cam.active = -1;
++
++      //No cameras registered.
++      bug_cam.cam_cnt = 0;
++
++      // Allocate and Register input device.
++
++      // allocate input device
++      bug_cam.input_dev = input_allocate_device();
++      if (!bug_cam.input_dev) {
++              printk(KERN_ERR "bug_camera_init: Can't allocate input_dev\n");
++              err = -ENOMEM;
++              goto exit;
++      }
++
++      // set up input device
++      bug_cam.input_dev->name = "bug_cam";
++      bug_cam.input_dev->phys = "bug_cam";
++      bug_cam.input_dev->id.bustype = BUS_BMI;
++      //bug_cam.input_dev->private = &bug_cam;
++      bug_cam.input_dev->evbit[0] = BIT(EV_KEY);
++      bug_cam.input_dev->keybit[BIT_WORD(BN_SHUTTER)] = BIT_MASK(BN_SHUTTER)  |
++                                            BIT_MASK(BN_ZOOMIN)  |
++                                            BIT_MASK(BN_ZOOMOUT);
++      // register input device
++      err = input_register_device (bug_cam.input_dev);
++      if (err) {
++              printk(KERN_ERR
++                      "bug_camera_init() - input_register_device failed.\n");
++              input_free_device(bug_cam.input_dev);
++              goto exit;
++      }
++
++      //Register character device.
++      /*
++      // allocate char device number
++      err = alloc_chrdev_region (&bug_cam.cntl_devno, 0, 1,
++                   "bug_camera_control");
++      if (err < 0) {
++              printk(KERN_ERR "bug_camera_init(): alloc_chrdev_region failed.\n");
++              goto err_exit;
++      }
++
++      // init and add control character device
++      cdev_init (&bug_cam.cntl, &cntl_fops);
++
++      err = cdev_add (&bug_cam.cntl, bug_cam.cntl_devno, 1);
++      if (err )  {
++              printk(KERN_ERR "bmi_camera_init(): cdev_add failed\n");
++              goto err_exit2;
++      }
++
++      // create class device
++      bmi_class = bmi_get_bmi_class ();
++
++      bug_cam.class_dev = device_create (bmi_class, NULL, bug_cam.cntl_devno, &bug_cam, "bug_camera_control");
++
++      if (IS_ERR(bug_cam.class_dev)) {
++              printk(KERN_ERR "Unable to create "
++                     "class_device for bug_camera; errno = %ld\n",
++                     PTR_ERR(bug_cam.class_dev));
++              bug_cam.class_dev = NULL;
++              goto err_exit2;
++      }
++      */
++      goto exit;
++
++err_exit2:
++      unregister_chrdev_region (bug_cam.cntl_devno, 1);
++err_exit:
++      input_unregister_device (bug_cam.input_dev);
++exit:
++      return err;
++}
++
++static void __exit bug_camera_clean(void)
++{
++  /*  struct class *bmi_class;
++
++      bmi_class = bmi_get_bmi_class ();
++      device_destroy (bmi_class, bug_cam.cntl_devno);*/
++
++      bug_cam.class_dev = 0;
++      // Unregister character device.
++      unregister_chrdev_region (bug_cam.cntl_devno, 1);
++
++      // Unregister input device.
++      input_unregister_device (bug_cam.input_dev);
++
++//    input_free_device (bug_cam.input_dev);
++      return;
++}
++
++
++module_init(bug_camera_init);
++module_exit(bug_camera_clean);
++
++// Exported symbols
++EXPORT_SYMBOL(camera_sensor_if);
++EXPORT_SYMBOL(camera_link_if);
++EXPORT_SYMBOL(register_bug_camera);
++EXPORT_SYMBOL(unregister_bug_camera);
++
++MODULE_AUTHOR("EnCADIS Design, Inc.");
++MODULE_DESCRIPTION("Bug Camera Driver");
++MODULE_LICENSE("GPL");
++
+--- /dev/null
++++ git/drivers/bmi/pims/camera/bug_camera.h
+@@ -0,0 +1,72 @@
++#ifndef BUG_CAMARA_H
++#define BUG_CAMARA_H
++
++#include <linux/bmi.h>
++#include <mach/bug_v4l2_capture.h>
++
++
++struct bmi_cam;
++struct input_dev;
++
++# if 1
++struct bmi_camera_sensor {
++
++      void (*set_color) (struct bmi_cam *bcam, int bright, int saturation, int red, int green,
++                         int blue);
++
++      void (*get_color) (struct bmi_cam *bcam, int *bright, int *saturation, int *red, int *green,
++                         int *blue);
++
++      void (*set_ae_mode) (struct bmi_cam *bcam, int ae_mode);
++      void (*get_ae_mode) (struct bmi_cam *bcam, int *ae_mode);
++      sensor_interface *(*config) (struct bmi_cam *bcam, int *frame_rate, int high_quality);
++      sensor_interface *(*reset) (struct bmi_cam *bcam);
++};
++
++struct bmi_camera_link {
++
++      void (*enable) (struct bmi_cam *bcam);
++      void (*disable) (struct bmi_cam *bcam);
++
++};
++# endif
++
++struct bmi_camera_cntl {
++
++      int (*flash_led_on) (struct bmi_cam *bcam);
++      int (*flash_led_off) (struct bmi_cam *bcam);
++      int (*flash_high_beam) (struct bmi_cam *bcam);
++      int (*flash_low_beam ) (struct bmi_cam *bcam);
++      int (*red_led_off) (struct bmi_cam *bcam);
++      int (*red_led_on) (struct bmi_cam *bcam);
++      int (*green_led_off) (struct bmi_cam *bcam);
++      int (*green_led_on) (struct bmi_cam *bcam);
++
++};
++
++struct bmi_cam {
++
++      sensor_interface  interface;            // pointer to this struct is returned by config()
++
++      struct bmi_camera_sensor sensor;        // v4l function pointers
++
++      struct bmi_camera_link link;            // bug link control function pointers
++
++      struct bmi_camera_cntl cntl;            // bmi camera control function pointers
++
++
++      int (*activate) (struct bmi_cam *cam, struct input_dev *idev);
++
++      int (*deactivate) (struct bmi_cam *cam);
++
++
++};
++
++
++
++int register_bug_camera( struct bmi_cam *bcam, int slot);
++int unregister_bug_camera( struct bmi_cam *bcam, int slot);
++
++
++#endif
++
+--- /dev/null
++++ git/drivers/bmi/pims/camera/ov2640.c
+@@ -0,0 +1,301 @@
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/ctype.h>
++#include <linux/types.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <linux/i2c.h>
++#include <mach/mxc_i2c.h>
++
++/* I2C Slave Address */
++#define OV2640_I2C_ADDRESS    0x30    // 7-bit address
++
++
++int ov2640_ReadByte(struct i2c_adapter *adap, unsigned char offset, unsigned char *data)
++{
++      int    ret = 0;
++      struct i2c_msg rmsg[2];
++      int    num_msgs;
++
++      /* Read Byte with 8-Bit Pointer */
++
++      rmsg[0].addr = OV2640_I2C_ADDRESS;
++      rmsg[0].flags = 0;          /* write */
++      rmsg[0].len = 1;
++      rmsg[0].buf = &offset;
++
++      rmsg[1].addr = OV2640_I2C_ADDRESS;
++      rmsg[1].flags = I2C_M_RD;   /* read */
++      rmsg[1].len = 1;
++      rmsg[1].buf = data;
++
++      num_msgs = 2;
++
++      ret = i2c_transfer(adap, rmsg, num_msgs);
++
++      if (ret == 2) {
++              ret = 0;
++      }
++      else {
++              printk (KERN_ERR "ov2640_ReadByte() - i2c_transfer failed.\n");
++              //Rework: add conditional debug messages here
++              ret = -1;
++      }
++      return ret;
++}
++
++int ov2640_WriteByte(struct i2c_adapter *adap, unsigned char addr, unsigned char offset, unsigned char data)
++{
++      int ret;
++      struct i2c_msg wmsg;
++      int    num_msgs;
++
++      char   buf[2];
++
++      buf[0] = (char)offset;
++      buf[1] = (char)data;
++
++
++      wmsg.addr = addr >> 1;
++      wmsg.flags = 0;          /* write */
++      wmsg.len = 2;
++      wmsg.buf = buf;
++      num_msgs = 1;
++
++      ret = i2c_transfer (adap, &wmsg, num_msgs);
++
++      if (ret == 1) {
++              ret = 0;
++      }
++      else {
++              printk (KERN_ERR "ov2640_WriteByte() - i2c_transfer failed.\n");
++              //Rework: add conditional debug messages here
++              ret = -1;
++      }
++      return ret;
++}
++
++
++void load_2640_12MHZ_Initial_UXGA_YUV (struct i2c_adapter *adap)
++
++{
++
++      // ;2640_Initial_100206.ovt
++      ov2640_WriteByte (adap, 0x60, 0xff, 0x01);
++      ov2640_WriteByte (adap, 0x60, 0x12, 0x80);
++
++      msleep(1);      // delay 1ms
++
++      ov2640_WriteByte (adap, 0x60, 0xff, 0x00);
++      ov2640_WriteByte (adap, 0x60, 0x2c, 0xff);
++      ov2640_WriteByte (adap, 0x60, 0x2e, 0xdf);
++      ov2640_WriteByte (adap, 0x60, 0xff, 0x01);
++      ov2640_WriteByte (adap, 0x60, 0x3c, 0x32);
++//    ov2640_WriteByte (adap, 0x60, 0x11, 0x01); //7.5fps);
++      ov2640_WriteByte (adap, 0x60, 0x11, 0x00); //7.5fps for 48;
++      ov2640_WriteByte (adap, 0x60, 0x09, 0x02);
++      ov2640_WriteByte (adap, 0x60, 0x04, 0x28);
++      ov2640_WriteByte (adap, 0x60, 0x13, 0xe5);
++      ov2640_WriteByte (adap, 0x60, 0x14, 0x48);
++      ov2640_WriteByte (adap, 0x60, 0x2c, 0x0c);
++      ov2640_WriteByte (adap, 0x60, 0x33, 0x78);
++      ov2640_WriteByte (adap, 0x60, 0x3a, 0x33);
++      ov2640_WriteByte (adap, 0x60, 0x3b, 0xfb);
++      ov2640_WriteByte (adap, 0x60, 0x3e, 0x00);
++      ov2640_WriteByte (adap, 0x60, 0x43, 0x11);
++      ov2640_WriteByte (adap, 0x60, 0x16, 0x10);
++      ov2640_WriteByte (adap, 0x60, 0x39, 0x02);
++      ov2640_WriteByte (adap, 0x60, 0x35, 0x88);
++      ov2640_WriteByte (adap, 0x60, 0x22, 0x0a);
++      ov2640_WriteByte (adap, 0x60, 0x37, 0x40);
++      ov2640_WriteByte (adap, 0x60, 0x23, 0x00);
++      ov2640_WriteByte (adap, 0x60, 0x34, 0xa0);
++      ov2640_WriteByte (adap, 0x60, 0x36, 0x1a);
++      ov2640_WriteByte (adap, 0x60, 0x06, 0x02);
++      ov2640_WriteByte (adap, 0x60, 0x07, 0xc0);
++      ov2640_WriteByte (adap, 0x60, 0x0d, 0xb7);
++      ov2640_WriteByte (adap, 0x60, 0x0e, 0x01);
++      ov2640_WriteByte (adap, 0x60, 0x4c, 0x00);
++      ov2640_WriteByte (adap, 0x60, 0x4a, 0x81);
++      ov2640_WriteByte (adap, 0x60, 0x21, 0x99);
++      ov2640_WriteByte (adap, 0x60, 0x24, 0x3a);
++      ov2640_WriteByte (adap, 0x60, 0x25, 0x32);
++      ov2640_WriteByte (adap, 0x60, 0x26, 0x82);
++      ov2640_WriteByte (adap, 0x60, 0x5c, 0x00);
++      ov2640_WriteByte (adap, 0x60, 0x63, 0x00);
++      ov2640_WriteByte (adap, 0x60, 0x5d, 0x55);
++      ov2640_WriteByte (adap, 0x60, 0x5e, 0x7d);
++      ov2640_WriteByte (adap, 0x60, 0x5f, 0x7d);
++      ov2640_WriteByte (adap, 0x60, 0x60, 0x55);
++      ov2640_WriteByte (adap, 0x60, 0x61, 0x70);
++      ov2640_WriteByte (adap, 0x60, 0x62, 0x80);
++      ov2640_WriteByte (adap, 0x60, 0x7c, 0x05);
++      ov2640_WriteByte (adap, 0x60, 0x20, 0x80);
++      ov2640_WriteByte (adap, 0x60, 0x28, 0x30);
++      ov2640_WriteByte (adap, 0x60, 0x6c, 0x00);
++      ov2640_WriteByte (adap, 0x60, 0x6d, 0x80);
++      ov2640_WriteByte (adap, 0x60, 0x6e, 0x00);
++      ov2640_WriteByte (adap, 0x60, 0x70, 0x02);
++      ov2640_WriteByte (adap, 0x60, 0x71, 0x94);
++      ov2640_WriteByte (adap, 0x60, 0x73, 0xc1);
++//    ov2640_WriteByte (adap, 0x60, 0x3d, 0x28);  //12MHz XVCLK
++      ov2640_WriteByte (adap, 0x60, 0x3d, 0x30);  //12MHz XVCLK -> 48 MHz);
++//    ov2640_WriteByte (adap, 0x60, 0x3d, 0x38);  //12MHz XVCLK -> 24 MHz); //MTW
++      ov2640_WriteByte (adap, 0x60, 0x5a, 0x57);
++      ov2640_WriteByte (adap, 0x60, 0x4f, 0xbb);
++      ov2640_WriteByte (adap, 0x60, 0x50, 0x9c);
++      ov2640_WriteByte (adap, 0x60, 0x12, 0x00);
++      ov2640_WriteByte (adap, 0x60, 0x17, 0x11);
++      ov2640_WriteByte (adap, 0x60, 0x18, 0x76);      //M+
++      ov2640_WriteByte (adap, 0x60, 0x19, 0x01);
++      ov2640_WriteByte (adap, 0x60, 0x1a, 0x97);
++      ov2640_WriteByte (adap, 0x60, 0x32, 0x36);
++
++      ov2640_WriteByte (adap, 0x60, 0xff, 0x00);
++      ov2640_WriteByte (adap, 0x60, 0xe5, 0x7f);
++      ov2640_WriteByte (adap, 0x60, 0xf9, 0xc0);
++      ov2640_WriteByte (adap, 0x60, 0x41, 0x24);
++      ov2640_WriteByte (adap, 0x60, 0xe0, 0x14);
++      ov2640_WriteByte (adap, 0x60, 0x76, 0xff);
++      ov2640_WriteByte (adap, 0x60, 0x33, 0xa0);
++      ov2640_WriteByte (adap, 0x60, 0x42, 0x20);
++      ov2640_WriteByte (adap, 0x60, 0x43, 0x18);
++      ov2640_WriteByte (adap, 0x60, 0x4c, 0x00);
++      ov2640_WriteByte (adap, 0x60, 0x87, 0xd0);
++      ov2640_WriteByte (adap, 0x60, 0x88, 0x3f);
++      ov2640_WriteByte (adap, 0x60, 0xd7, 0x03);
++      ov2640_WriteByte (adap, 0x60, 0xd9, 0x10);
++      ov2640_WriteByte (adap, 0x60, 0xd3, 0x82);
++      ov2640_WriteByte (adap, 0x60, 0xc8, 0x08);
++      ov2640_WriteByte (adap, 0x60, 0xc9, 0x80);
++      ov2640_WriteByte (adap, 0x60, 0x7c, 0x00);
++      ov2640_WriteByte (adap, 0x60, 0x7d, 0x02);
++      ov2640_WriteByte (adap, 0x60, 0x7c, 0x03);
++      ov2640_WriteByte (adap, 0x60, 0x7d, 0x48);
++      ov2640_WriteByte (adap, 0x60, 0x7d, 0x48);
++      ov2640_WriteByte (adap, 0x60, 0x7c, 0x08);
++      ov2640_WriteByte (adap, 0x60, 0x7d, 0x20);
++      ov2640_WriteByte (adap, 0x60, 0x7d, 0x10);
++      ov2640_WriteByte (adap, 0x60, 0x7d, 0x0e);
++      ov2640_WriteByte (adap, 0x60, 0x90, 0x00);
++      ov2640_WriteByte (adap, 0x60, 0x91, 0x0e);
++      ov2640_WriteByte (adap, 0x60, 0x91, 0x1a);
++      ov2640_WriteByte (adap, 0x60, 0x91, 0x31);
++      ov2640_WriteByte (adap, 0x60, 0x91, 0x5a);
++      ov2640_WriteByte (adap, 0x60, 0x91, 0x69);
++      ov2640_WriteByte (adap, 0x60, 0x91, 0x75);
++      ov2640_WriteByte (adap, 0x60, 0x91, 0x7e);
++      ov2640_WriteByte (adap, 0x60, 0x91, 0x88);
++      ov2640_WriteByte (adap, 0x60, 0x91, 0x8f);
++      ov2640_WriteByte (adap, 0x60, 0x91, 0x96);
++      ov2640_WriteByte (adap, 0x60, 0x91, 0xa3);
++      ov2640_WriteByte (adap, 0x60, 0x91, 0xaf);
++      ov2640_WriteByte (adap, 0x60, 0x91, 0xc4);
++      ov2640_WriteByte (adap, 0x60, 0x91, 0xd7);
++      ov2640_WriteByte (adap, 0x60, 0x91, 0xe8);
++      ov2640_WriteByte (adap, 0x60, 0x91, 0x20);
++      ov2640_WriteByte (adap, 0x60, 0x92, 0x00);
++      ov2640_WriteByte (adap, 0x60, 0x93, 0x06);
++      ov2640_WriteByte (adap, 0x60, 0x93, 0xe3);
++      ov2640_WriteByte (adap, 0x60, 0x93, 0x05);
++      ov2640_WriteByte (adap, 0x60, 0x93, 0x05);
++      ov2640_WriteByte (adap, 0x60, 0x93, 0x00);
++      ov2640_WriteByte (adap, 0x60, 0x93, 0x02);
++      ov2640_WriteByte (adap, 0x60, 0x93, 0x00);
++      ov2640_WriteByte (adap, 0x60, 0x93, 0x00);
++      ov2640_WriteByte (adap, 0x60, 0x93, 0x00);
++      ov2640_WriteByte (adap, 0x60, 0x93, 0x00);
++      ov2640_WriteByte (adap, 0x60, 0x93, 0x00);
++      ov2640_WriteByte (adap, 0x60, 0x93, 0x00);
++      ov2640_WriteByte (adap, 0x60, 0x93, 0x00);
++      ov2640_WriteByte (adap, 0x60, 0x96, 0x00);
++      ov2640_WriteByte (adap, 0x60, 0x97, 0x08);
++      ov2640_WriteByte (adap, 0x60, 0x97, 0x19);
++      ov2640_WriteByte (adap, 0x60, 0x97, 0x02);
++      ov2640_WriteByte (adap, 0x60, 0x97, 0x0c);
++      ov2640_WriteByte (adap, 0x60, 0x97, 0x24);
++      ov2640_WriteByte (adap, 0x60, 0x97, 0x30);
++      ov2640_WriteByte (adap, 0x60, 0x97, 0x28);
++      ov2640_WriteByte (adap, 0x60, 0x97, 0x26);
++      ov2640_WriteByte (adap, 0x60, 0x97, 0x02);
++      ov2640_WriteByte (adap, 0x60, 0x97, 0x98);
++      ov2640_WriteByte (adap, 0x60, 0x97, 0x80);
++      ov2640_WriteByte (adap, 0x60, 0x97, 0x00);
++      ov2640_WriteByte (adap, 0x60, 0x97, 0x00);
++      ov2640_WriteByte (adap, 0x60, 0xc3, 0xed);
++      ov2640_WriteByte (adap, 0x60, 0xa4, 0x00);
++      ov2640_WriteByte (adap, 0x60, 0xa8, 0x00);
++      ov2640_WriteByte (adap, 0x60, 0xc5, 0x11);
++      ov2640_WriteByte (adap, 0x60, 0xc6, 0x51);
++      ov2640_WriteByte (adap, 0x60, 0xbf, 0x80);
++      ov2640_WriteByte (adap, 0x60, 0xc7, 0x10);
++      ov2640_WriteByte (adap, 0x60, 0xb6, 0x66);
++      ov2640_WriteByte (adap, 0x60, 0xb8, 0xa5);
++      ov2640_WriteByte (adap, 0x60, 0xb7, 0x64);
++      ov2640_WriteByte (adap, 0x60, 0xb9, 0x7c);
++      ov2640_WriteByte (adap, 0x60, 0xb3, 0xaf);
++      ov2640_WriteByte (adap, 0x60, 0xb4, 0x97);
++      ov2640_WriteByte (adap, 0x60, 0xb5, 0xff);
++      ov2640_WriteByte (adap, 0x60, 0xb0, 0xc5);
++      ov2640_WriteByte (adap, 0x60, 0xb1, 0x94);
++      ov2640_WriteByte (adap, 0x60, 0xb2, 0x0f);
++      ov2640_WriteByte (adap, 0x60, 0xc4, 0x5c);
++//
++      ov2640_WriteByte (adap, 0x60, 0xc0, 0xca); //M+
++      ov2640_WriteByte (adap, 0x60, 0xc1, 0x96);
++      ov2640_WriteByte (adap, 0x60, 0x8c, 0x00);
++      ov2640_WriteByte (adap, 0x60, 0x86, 0x3d); //2M
++      ov2640_WriteByte (adap, 0x60, 0x50, 0x00);
++      ov2640_WriteByte (adap, 0x60, 0x51, 0x90);
++      ov2640_WriteByte (adap, 0x60, 0x52, 0x2c);
++      ov2640_WriteByte (adap, 0x60, 0x53, 0x00);
++      ov2640_WriteByte (adap, 0x60, 0x54, 0x00);
++      ov2640_WriteByte (adap, 0x60, 0x55, 0x88);
++      ov2640_WriteByte (adap, 0x60, 0x57, 0x00);
++      ov2640_WriteByte (adap, 0x60, 0x5a, 0x90);
++      ov2640_WriteByte (adap, 0x60, 0x5b, 0x2c);
++      ov2640_WriteByte (adap, 0x60, 0x5c, 0x05);
++//
++      ov2640_WriteByte (adap, 0x60, 0xc3, 0xed);
++      ov2640_WriteByte (adap, 0x60, 0x7f, 0x00);
++      ov2640_WriteByte (adap, 0x60, 0xda, 0x01); //UYVY
++      ov2640_WriteByte (adap, 0x60, 0xd3, 0x82);
++      ov2640_WriteByte (adap, 0x60, 0xe5, 0x1f);
++      ov2640_WriteByte (adap, 0x60, 0xe1, 0x67);
++      ov2640_WriteByte (adap, 0x60, 0xe0, 0x00);
++      ov2640_WriteByte (adap, 0x60, 0xdd, 0x7f);
++      ov2640_WriteByte (adap, 0x60, 0x05, 0x00);
++//    ov2640_WriteByte (adap, 0x60, 0xff, 0x01);
++}
++
++void load_2640_UXGA(struct i2c_adapter *adap)
++{
++
++//    ;1600x1200
++      ov2640_WriteByte (adap, 0x60, 0xc0, 0xca);      //M+
++      ov2640_WriteByte (adap, 0x60, 0xc1, 0x96);
++      ov2640_WriteByte (adap, 0x60, 0x8c, 0x00);
++      ov2640_WriteByte (adap, 0x60, 0x86, 0x3d);      //2M
++      ov2640_WriteByte (adap, 0x60, 0x50, 0x00);
++      ov2640_WriteByte (adap, 0x60, 0x51, 0x90);
++      ov2640_WriteByte (adap, 0x60, 0x52, 0x2c);
++      ov2640_WriteByte (adap, 0x60, 0x53, 0x00);
++      ov2640_WriteByte (adap, 0x60, 0x54, 0x00);
++      ov2640_WriteByte (adap, 0x60, 0x55, 0x88);
++      ov2640_WriteByte (adap, 0x60, 0x57, 0x00);
++      ov2640_WriteByte (adap, 0x60, 0x5a, 0x90);
++      ov2640_WriteByte (adap, 0x60, 0x5b, 0x2c);
++      ov2640_WriteByte (adap, 0x60, 0x5c, 0x05);
++}
++
++
++
++
++void ov2640_patch (struct i2c_adapter *adap)
++{
++      load_2640_12MHZ_Initial_UXGA_YUV (adap);
++      load_2640_UXGA(adap);
++
++}
++
+--- /dev/null
++++ git/drivers/bmi/pims/camera/ov2640.h
+@@ -0,0 +1,14 @@
++#ifndef VS6624_ACCESS_H
++#define VS6624_ACCESS_H
++
++#include <linux/i2c.h>
++
++void ov2640_patch (struct i2c_adapter *adap);
++
++int vs6624_ReadByte(struct i2c_adapter *adap, unsigned short offset, unsigned char *data);
++int vs6624_WriteByte(struct i2c_adapter *adap, unsigned short offset, unsigned char data);
++int  vs6624_WriteSequence(struct i2c_adapter *adap, const unsigned short array[][2], unsigned short len);
++void vs6624_dump_regs(struct i2c_adapter *adap);
++
++#endif
++
+--- /dev/null
++++ git/drivers/bmi/pims/camera/vs6624_access.c
+@@ -0,0 +1,597 @@
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/ctype.h>
++#include <linux/types.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <linux/i2c.h>
++#include <mach/mxc_i2c.h>
++#include "vs6624_regs.h"
++
++# include "vs6624_patch.c"
++
++
++int vs6624_ReadByte(struct i2c_adapter *adap, unsigned short offset, unsigned char *data)
++{
++      int    ret = 0;
++      struct i2c_msg rmsg[2];
++      int    num_msgs;
++      char   buf[2];
++
++      buf[0] = (offset & 0xFF00) >> 8;
++      buf[1] = (offset & 0x00FF);
++
++      /* Read Byte with 16-Bit Pointer */
++
++      rmsg[0].addr = VS6624_I2C_ADDRESS;
++      rmsg[0].flags = 0;          /* write */
++      rmsg[0].len = 2;
++      rmsg[0].buf = buf;
++
++      rmsg[1].addr = VS6624_I2C_ADDRESS;
++      rmsg[1].flags = I2C_M_RD;   /* read */
++      rmsg[1].len = 1;
++      rmsg[1].buf = data;
++
++      num_msgs = 2;
++
++      ret = i2c_transfer(adap, rmsg, num_msgs);
++
++      if (ret == 2) {
++              ret = 0;
++      }
++      else {
++              printk (KERN_ERR "vs6624_ReadByte() - i2c_transfer failed.\n");
++              //Rework: add conditional debug messages here
++              ret = -1;
++      }
++      return ret;
++}
++
++int vs6624_WriteByte(struct i2c_adapter *adap, unsigned short offset, unsigned char data)
++{
++      int ret;
++      char   buf[2];
++      struct i2c_msg wmsg[2];
++      int    num_msgs;
++
++      buf[0] = (offset & 0xFF00) >> 8;
++      buf[1] = (offset & 0x00FF);
++
++      wmsg[0].addr = VS6624_I2C_ADDRESS;
++      wmsg[0].flags = 0;          /* write */
++      wmsg[0].len = 2;
++      wmsg[0].buf = buf;
++
++      wmsg[1].addr = VS6624_I2C_ADDRESS;
++      wmsg[1].flags = 0;   /* write */
++      wmsg[1].len = 1;
++      wmsg[1].buf = &data;
++
++      num_msgs = 2;
++
++      ret = i2c_transfer (adap, wmsg, num_msgs);
++
++      if (ret == 2) {
++              ret = 0;
++      }
++      else {
++              printk (KERN_ERR "vs6624_WriteByte() - i2c_transfer failed.\n");
++              //Rework: add conditional debug messages here
++              ret = -1;
++      }
++      return ret;
++}
++
++int  vs6624_WriteSequence(struct i2c_adapter *adap, const unsigned short array[][2], unsigned short len)
++{
++      u16 x;
++
++      for (x = 0; x < len; x++)
++              vs6624_WriteByte (adap, array[x][0], (unsigned char) array[x][1]);
++
++      return 0;
++}
++
++
++static unsigned char get_reg(struct i2c_adapter *adap, unsigned short offset)
++{
++        unsigned char buf[1];
++
++        vs6624_ReadByte (adap, offset, &buf[0]);
++
++        return buf[0];
++}
++
++void
++vs6624_set_color(struct i2c_adapter *adap, int bright, int saturation, int red, int green, int blue)
++{
++        switch (saturation) {
++        case 150:
++                vs6624_WriteByte(adap, bColourSaturation0, 0xFF & 0xFF);
++                break;
++        case 75:
++                vs6624_WriteByte(adap, bColourSaturation0, 0xC0 & 0xFF);
++                break;
++        case 50:
++                vs6624_WriteByte(adap, bColourSaturation0, 0x80 & 0xFF);
++                break;
++        case 25:
++                vs6624_WriteByte(adap, bColourSaturation0, 0x40 & 0xFF);
++                break;
++        default:
++                vs6624_WriteByte(adap, bColourSaturation0, 0x78 & 0xFF);
++                break;
++        }
++}
++
++void
++vs6624_get_color(struct i2c_adapter *adap, int *bright, int *saturation, int *red, int *green, int *blue)
++{
++        *saturation = (int) get_reg( adap, bColourSaturation0);
++        switch (*saturation) {
++        case 0xFF:
++                *saturation = 150;
++                break;
++        case 0xC0:
++                *saturation = 75;
++                break;
++        case 0x80:
++                *saturation = 50;
++                break;
++        case 0x40:
++                *saturation = 25;
++                break;
++        default:
++                *saturation = 100;
++                break;
++        }
++}
++
++
++
++static int vs_probe(struct i2c_adapter *adap)
++{
++
++        unsigned char buf[2];
++
++        vs6624_ReadByte (adap, DeviceID_MSB, &buf[0]);
++        vs6624_ReadByte (adap, DeviceID_LSB, &buf[1]);
++
++        if ((((buf[0] & 0xFF) << 8) | (buf[1] & 0xFF)) == VS6624_ID) {
++
++                printk(KERN_INFO "%s: Firmware Version %d.%d \n",
++                SENSOR_NAME, get_reg(adap, bFirmwareVsnMajor), get_reg (adap, bFirmwareVsnMinor));
++                printk(KERN_INFO "%s: Patch Version %d.%d \n",
++                SENSOR_NAME, get_reg(adap, bPatchVsnMajor), get_reg(adap, bPatchVsnMinor));
++
++                return 0;
++        }
++
++        printk (KERN_ERR "vs_probe: No VS6624 found.\n");
++        printk (KERN_ERR "vs_probe: buf[0] = 0x%x\n", (buf[0] & 0xFF) << 8);
++        printk (KERN_ERR "vs_probe: buf[1] = 0x%x\n", (buf[1] & 0xFF));
++        printk (KERN_ERR "vs_probe: DeviceID = %d\n", ((buf[0] & 0xFF) << 8) | (buf[1] & 0xFF));
++
++        return -ENODEV;
++}
++
++void vs6624_patch (struct i2c_adapter *adap)
++{
++        printk (KERN_ERR "vs6624_patch() - enter\n");
++        msleep(100);
++
++        vs6624_WriteByte (adap, PWR_MAN_SETUP_MODE_SELECT, 0x0);
++        msleep(10);
++        vs_probe (adap);
++
++        printk (KERN_ERR "vs6624_patch() - applying patch p1\n");
++        vs6624_WriteSequence (adap, patch_p1, sizeof(patch_p1) / (sizeof(u16) * 2));
++        msleep(50);
++
++        printk (KERN_ERR "vs6624_patch() - applying patch p2\n");
++        vs6624_WriteSequence (adap, patch_p2, sizeof(patch_p2) / (sizeof(u16) * 2));
++
++        vs6624_WriteByte (adap, PWR_MAN_SETUP_MODE_SELECT, 0x2);
++        msleep(100);
++
++        vs6624_WriteByte (adap, PWR_MAN_DIO_ENABLE, 0x1);
++        msleep(1);
++
++        printk(KERN_INFO "MODE: %d \n", get_reg(adap, bState));       //pjg
++
++        vs_probe (adap);
++
++
++        // Flicker correction
++        vs6624_WriteByte (adap, bLightingFrequencyHz, 0x64);       // AC frequency == 100
++
++        // Pan step size
++        vs6624_WriteByte (adap, uwPanStepHSizeMSB0, 0x0);          // H pan step == 15
++        vs6624_WriteByte (adap, uwPanStepHSizeLSB0, 0xf);
++        vs6624_WriteByte (adap, uwPanStepVSizeMSB0, 0x0);          // V pan step == 15
++        vs6624_WriteByte (adap, uwPanStepVSizeLSB0, 0xf);
++
++        vs6624_WriteByte (adap, bSyncCodeSetup, 0x21);             // SYNC //pjg
++        vs6624_WriteByte (adap, bHSyncSetup, 0xF);                 // Active lines only, Automatic //pjg
++        vs6624_WriteByte (adap, bVSyncSetup, 0x7);                 // Active lines only, Automatic //pjg
++
++        vs6624_WriteByte (adap, uwDesiredFrameRate_Num_MSB, 0x0);
++        vs6624_WriteByte (adap, uwDesiredFrameRate_Num_LSB, 0x0F);    // frame rate numerator == 15 MTW
++        vs6624_WriteByte (adap, bDesiredFrameRate_Den, 0x1);          // frame rate denominator == 1
++
++        printk(KERN_INFO "MODE: %d \n", get_reg(adap, bState)); //pjg
++
++        vs6624_WriteByte (adap, uwExternalClockFrequencyMhzNumeratorMSB, 0x0);
++        vs6624_WriteByte (adap, uwExternalClockFrequencyMhzNumeratorLSB, 12);
++        vs6624_WriteByte (adap, bExternalClockFrequencyMhzDenominator, 0x1);
++
++        vs6624_WriteByte (adap, bPClkSetup, 0x85);                    // Pix Clk Mode == free run
++
++        printk(KERN_INFO "MODE: %d \n", get_reg(adap, bState)); //pjg
++        vs6624_WriteByte (adap, bUserCommand, 0x2);   // RUN
++
++        printk(KERN_INFO "MODE: %d \n", get_reg(adap, bState)); //pjg
++        printk (KERN_ERR "vs6624_patch() - writing setup patch\n");
++        vs6624_WriteSequence (adap, patch_run_setup, sizeof(patch_run_setup) / (sizeof(u16) * 2));
++
++
++        printk(KERN_INFO "MODE: %d \n", get_reg(adap, bState)); //pjg
++
++        vs_probe (adap); //pjg
++        printk (KERN_ERR "vs6624_patch() - exit\n");
++      return;
++}
++
++
++
++static int ReadByteV(struct i2c_adapter *adap, unsigned short offset, char* name)
++{
++      unsigned char tmp[1];
++      vs6624_ReadByte(adap, offset, &tmp[0]);
++      printk (KERN_ERR "vs6624 offset = %04X,  data = %02X  %s\n", offset, tmp[0], name);
++      return 0;
++
++}
++
++
++void vs6624_dump_regs(struct i2c_adapter *adap)
++{
++
++      printk (KERN_ERR "vs6624_dump_regs() - enter\n");
++
++      ReadByteV(adap, 0xc044,"PWR_MAN_DIO_ENABLE                          ");
++      ReadByteV(adap, 0x0001,"uwDeviceId                                  ");
++      ReadByteV(adap, 0x0001,"DeviceID_MSB                                ");
++      ReadByteV(adap, 0x0002,"DeviceID_LSB                                ");
++      ReadByteV(adap, 0x0004,"bFirmwareVsnMajor                           ");
++      ReadByteV(adap, 0x0006,"bFirmwareVsnMinor                           ");
++      ReadByteV(adap, 0x0008,"bPatchVsnMajor                      ");
++      ReadByteV(adap, 0x000a,"bPatchVsnMinor                      ");
++      ReadByteV(adap, 0x0180,"bUserCommand                                ");
++      ReadByteV(adap, 0x0186,"bManualNextState                            ");
++      ReadByteV(adap, 0x0200,"bNextState                                  ");
++      ReadByteV(adap, 0x0202,"bState                              ");
++      ReadByteV(adap, 0x0280,"fMeteringOn                                 ");
++      ReadByteV(adap, 0x0282,"fExitOnStable                               ");
++      ReadByteV(adap, 0x0284,"bStreamLength                               ");
++      ReadByteV(adap, 0x0300,"fIsColdStart                                ");
++      ReadByteV(adap, 0x0302,"bNonViewLive_ActivePipeSetupBank            ");
++      ReadByteV(adap, 0x0304,"bSnapShoot_ActivePipeSetupBank      ");
++      ReadByteV(adap, 0x0306,"fSnapShoot_NoWaiting                        ");
++      ReadByteV(adap, 0x0308,"SensorMode                                  ");
++      ReadByteV(adap, 0x0380,"bImageSize0                                 ");
++      ReadByteV(adap, 0x0383,"uwManualHSize0                      ");
++      ReadByteV(adap, 0x0383,"uwManualHSizeMSB0                           ");
++      ReadByteV(adap, 0x0384,"uwManualHSizeLSB0                           ");
++      ReadByteV(adap, 0x0387,"uwManualVSize0                      ");
++      ReadByteV(adap, 0x0387,"uwManualVSizeMSB0                           ");
++      ReadByteV(adap, 0x0388,"uwManualVSizeLSB0                           ");
++      ReadByteV(adap, 0x038b,"uwZoomStepHSize0                            ");
++      ReadByteV(adap, 0x038b,"uwZoomStepHSizeMSB0                         ");
++      ReadByteV(adap, 0x038c,"uwZoomStepHSizeLSB0                         ");
++      ReadByteV(adap, 0x038f,"uwZoomStepVSize0                            ");
++      ReadByteV(adap, 0x038f,"uwZoomStepVSizeMSB0                         ");
++      ReadByteV(adap, 0x0390,"uwZoomStepVSizeLSB0                         ");
++      ReadByteV(adap, 0x0392,"bZoomControl0                               ");
++      ReadByteV(adap, 0x0395,"uwPanStepHSize0                     ");
++      ReadByteV(adap, 0x0395,"uwPanStepHSizeMSB0                          ");
++      ReadByteV(adap, 0x0396,"uwPanStepHSizeLSB0                          ");
++      ReadByteV(adap, 0x0399,"uwPanStepVSize0                     ");
++      ReadByteV(adap, 0x0399,"uwPanStepVSizeMSB0                          ");
++      ReadByteV(adap, 0x039a,"uwPanStepVSizeLSB0                          ");
++      ReadByteV(adap, 0x039c,"bPanControl0                                ");
++      ReadByteV(adap, 0x039e,"bCropControl0                               ");
++      ReadByteV(adap, 0x03a1,"uwManualCropHorizontalStart0                ");
++      ReadByteV(adap, 0x03a5,"uwManualCropHorizontalSize0                 ");
++      ReadByteV(adap, 0x03a9,"uwManualCropVerticalStart0                  ");
++      ReadByteV(adap, 0x03ad,"uwManualCropVerticalSize0                   ");
++      ReadByteV(adap, 0x03a1,"bCropHStartMSB0                     ");
++      ReadByteV(adap, 0x03a2,"bCropHStartLSB0                     ");
++      ReadByteV(adap, 0x03a9,"bCropVStartMSB0                     ");
++      ReadByteV(adap, 0x03aa,"bCropVStartLSB0                     ");
++      ReadByteV(adap, 0x03a5,"bCropHSizeMSB0                      ");
++      ReadByteV(adap, 0x03a6,"bCropHSizeLSB0                      ");
++      ReadByteV(adap, 0x03ad,"bCropVSizeMSB0                      ");
++      ReadByteV(adap, 0x03ae,"bCropVSizeLSB0                      ");
++      ReadByteV(adap, 0x03b0,"bDataFormat0                                ");
++      ReadByteV(adap, 0x03b2,"bBayerOutputAlignment0              ");
++      ReadByteV(adap, 0x03b4,"bContrast0                                  ");
++      ReadByteV(adap, 0x03b6,"bColourSaturation0                          ");
++      ReadByteV(adap, 0x03b8,"bGamma0                             ");
++      ReadByteV(adap, 0x03ba,"fHorizontalMirror0                          ");
++      ReadByteV(adap, 0x03bc,"fVerticalFlip0                      ");
++      ReadByteV(adap, 0x03be,"bChannelID0                                 ");
++      ReadByteV(adap, 0x0400,"bImageSize1                                 ");
++      ReadByteV(adap, 0x0403,"uwManualHSize1                      ");
++      ReadByteV(adap, 0x0407,"uwManualVSize1                      ");
++      ReadByteV(adap, 0x040b,"uwZoomStepHSize1                            ");
++      ReadByteV(adap, 0x040f,"uwZoomStepVSize1                            ");
++      ReadByteV(adap, 0x0412,"bZoomControl1                               ");
++      ReadByteV(adap, 0x0415,"uwPanStepHSize1                     ");
++      ReadByteV(adap, 0x0419,"uwPanStepVSize1                     ");
++      ReadByteV(adap, 0x041c,"bPanControl1                                ");
++      ReadByteV(adap, 0x041e,"bCropControl1                               ");
++      ReadByteV(adap, 0x0421,"uwManualCropHorizontalStart1                ");
++      ReadByteV(adap, 0x0425,"uwManualCropHorizontalSize1                 ");
++      ReadByteV(adap, 0x0429,"uwManualCropVerticalStart1                  ");
++      ReadByteV(adap, 0x042d,"uwManualCropVerticalSize1                   ");
++      ReadByteV(adap, 0x0421,"bCropHStartMSB1                     ");
++      ReadByteV(adap, 0x0422,"bCropHStartLSB1                     ");
++      ReadByteV(adap, 0x0429,"bCropVStartMSB1                     ");
++      ReadByteV(adap, 0x042a,"bCropVStartLSB1                     ");
++      ReadByteV(adap, 0x0425,"bCropHSizeMSB1                      ");
++      ReadByteV(adap, 0x0426,"bCropHSizeLSB1                      ");
++      ReadByteV(adap, 0x042d,"bCropVSizeMSB1                      ");
++      ReadByteV(adap, 0x042e,"bCropVSizeLSB1                      ");
++      ReadByteV(adap, 0x0430,"bDataFormat1                                ");
++      ReadByteV(adap, 0x0432,"bBayerOutputAlignment1              ");
++      ReadByteV(adap, 0x0434,"bContrast1                                  ");
++      ReadByteV(adap, 0x0436,"bColourSaturation1                          ");
++      ReadByteV(adap, 0x0438,"bGamma1                             ");
++      ReadByteV(adap, 0x043a,"fHorizontalMirror1                          ");
++      ReadByteV(adap, 0x043c,"fVerticalFlip1                      ");
++      ReadByteV(adap, 0x043e,"bChannelID1                                 ");
++      ReadByteV(adap, 0x0480,"fEnable                             ");
++      ReadByteV(adap, 0x0482,"bInitialPipeSetupBank                       ");
++      ReadByteV(adap, 0x0500,"CurrentPipeSetupBank                        ");
++      ReadByteV(adap, 0x0580,"bTimeToPowerdown                            ");
++      ReadByteV(adap, 0x058a,"fVRegSleep                                  ");
++      ReadByteV(adap, 0x058c,"fSmoothLineReading                          ");
++      ReadByteV(adap, 0x0605,"uwExternalClockFrequencyMhzNumerator        ");
++      ReadByteV(adap, 0x0605,"uwExternalClockFrequencyMhzNumeratorMSB   ");
++      ReadByteV(adap, 0x0606,"uwExternalClockFrequencyMhzNumeratorLSB   ");
++      ReadByteV(adap, 0x0608,"bExternalClockFrequencyMhzDenominator       ");
++      ReadByteV(adap, 0x0681,"fpExternalClockFrequencyMhz                 ");
++      ReadByteV(adap, 0x0880,"bSysClkMode                                 ");
++      ReadByteV(adap, 0x0882,"bMode                                       ");
++      ReadByteV(adap, 0x0c80,"bLightingFrequencyHz                        ");
++      ReadByteV(adap, 0x0c82,"fFlickerCompatibleFrameLength               ");
++      ReadByteV(adap, 0x0d05,"fpFlickerFreePeriod_us              ");
++      ReadByteV(adap, 0x0d08,"fAntiFlickerEnabled                         ");
++      ReadByteV(adap, 0x0d81,"uwDesiredFrameRate_Num              ");
++      ReadByteV(adap, 0x0d81,"uwDesiredFrameRate_Num_MSB                  ");
++      ReadByteV(adap, 0x0d82,"uwDesiredFrameRate_Num_LSB                  ");
++      ReadByteV(adap, 0x0d84,"bDesiredFrameRate_Den                       ");
++      ReadByteV(adap, 0x0e01,"fpRequestedFrameRate_Hz             ");
++      ReadByteV(adap, 0x0e01,"fpRequestedFrameRate_Hz_MSB                 ");
++      ReadByteV(adap, 0x0e02,"fpRequestedFrameRate_Hz_LSB                 ");
++      ReadByteV(adap, 0x0e05,"fpMaxFrameRate_Hz                           ");
++      ReadByteV(adap, 0x0e09,"fpMinFrameRate_Hz                           ");
++      ReadByteV(adap, 0x0e0c,"fChangePending                      ");
++      ReadByteV(adap, 0x0e0f,"uwRequiredFrameLength_lines                 ");
++      ReadByteV(adap, 0x0e12,"ClipFrameRate                               ");
++      ReadByteV(adap, 0x0e80,"fDisableFrameRateDamper             ");
++      ReadByteV(adap, 0x0e82,"bImpliedGainThresholdLow_num                ");
++      ReadByteV(adap, 0x0e84,"bImpliedGainThresholdLow_den                ");
++      ReadByteV(adap, 0x0e86,"bImpliedGainThresholdHigh_num               ");
++      ReadByteV(adap, 0x0e88,"bImpliedGainThresholdHigh_den               ");
++      ReadByteV(adap, 0x0e8a,"bUserMinimumFrameRate_Hz                    ");
++      ReadByteV(adap, 0x0e8c,"bUserMaximumFrameRate_Hz                    ");
++      ReadByteV(adap, 0x0e8e,"bRelativeChange_num                         ");
++      ReadByteV(adap, 0x0e90,"bRelativeChange_den                         ");
++      ReadByteV(adap, 0x0e92,"fDivorceMinFrameRateFromMaxIntegration    ");
++      ReadByteV(adap, 0x0f01,"fpImpliedGain                               ");
++      ReadByteV(adap, 0x0f05,"uwMaximumFrameLength_lines                  ");
++      ReadByteV(adap, 0x0f09,"uwMinimumFrameLength_lines                  ");
++      ReadByteV(adap, 0x0f0d,"uwFrameLengthChange_lines                   ");
++      ReadByteV(adap, 0x0f11,"fpDesiredAutomaticFrameRate_Hz      ");
++      ReadByteV(adap, 0x0f15,"uwCurrentFrameLength_lines                  ");
++      ReadByteV(adap, 0x0f19,"uwDesiredFrameLength_lines                  ");
++      ReadByteV(adap, 0x0f1c,"fAutomaticFrameRateStable                   ");
++      ReadByteV(adap, 0x0f1e,"fAutomaticFrameRateClip             ");
++      ReadByteV(adap, 0x0f81,"uwXOffset                                   ");
++      ReadByteV(adap, 0x0f85,"uwYOffset                                   ");
++      ReadByteV(adap, 0x0f89,"uwXSize                             ");
++      ReadByteV(adap, 0x0f8d,"uwYSize                             ");
++      ReadByteV(adap, 0x1180,"ExposureControls_bMode              ");
++      ReadByteV(adap, 0x1182,"bExposureMetering                           ");
++      ReadByteV(adap, 0x1184,"bManualExposureTime_s_num                   ");
++      ReadByteV(adap, 0x1186,"bManualExposureTime_s_den                   ");
++      ReadByteV(adap, 0x1189,"fpManualDesiredExposureTime_us      ");
++      ReadByteV(adap, 0x1190,"iExposureCompensation                       ");
++      ReadByteV(adap, 0x1195,"uwDirectModeCoarseIntegration_lines         ");
++      ReadByteV(adap, 0x1199,"uwDirectModeFineIntegration_pixels          ");
++      ReadByteV(adap, 0x119d,"uwDirectModeCodedAnalogGain                 ");
++      ReadByteV(adap, 0x11a1,"fpDirectModeDigitalGain             ");
++      ReadByteV(adap, 0x11a5,"uwFlashGunModeCoarseIntegration_lines       ");
++      ReadByteV(adap, 0x11a9,"uwFlashGunModeFineIntegration_pixels        ");
++      ReadByteV(adap, 0x11ad,"uwFlashGunModeCodedAnalogGain               ");
++      ReadByteV(adap, 0x11b1,"fpFlashGunModeDigitalGain                   ");
++      ReadByteV(adap, 0x11b4,"fFreezeAutoExposure                         ");
++      ReadByteV(adap, 0x11b7,"fpUserMaximumIntegrationTime_us     ");
++      ReadByteV(adap, 0x11bb,"fpRecommendFlashGunAnalogGainThreshold    ");
++      ReadByteV(adap, 0x11be,"fEnableHighClipForDesiredExposureTime       ");
++      ReadByteV(adap, 0x11c0,"bAntiFlickerMode                            ");
++      ReadByteV(adap, 0x1201,"fpMaximumStep                               ");
++      ReadByteV(adap, 0x1205,"fpMinimumStep                               ");
++      ReadByteV(adap, 0x1209,"fpMinimumDesiredExposureTime_us     ");
++      ReadByteV(adap, 0x120d,"fpStepProportion                            ");
++      ReadByteV(adap, 0x1211,"fpMaximumNegativeStepThreshold      ");
++      ReadByteV(adap, 0x1215,"fpRelativeOnTargetStabilityThreshold        ");
++      ReadByteV(adap, 0x1219,"fpDigitalGainFloor                          ");
++      ReadByteV(adap, 0x121d,"fpDigitalGainCeiling                        ");
++      ReadByteV(adap, 0x1221,"fpRelativeIntTimeHysThreshold               ");
++      ReadByteV(adap, 0x1225,"fpRelativeDigitalGainHysThreshold           ");
++      ReadByteV(adap, 0x1229,"fpRelativeCompilationProblemThreshold       ");
++      ReadByteV(adap, 0x122d,"fpRoundUpBunchFudge                         ");
++      ReadByteV(adap, 0x1231,"fpFineClampThreshold                        ");
++      ReadByteV(adap, 0x1235,"fpMaximumManualExposureTime_s               ");
++      ReadByteV(adap, 0x1239,"fpRelativeStabilityThresholdForAutoFocus  ");
++      ReadByteV(adap, 0x123c,"bLeakShift                                  ");
++      ReadByteV(adap, 0x1281,"fpLeakyEnergy                               ");
++      ReadByteV(adap, 0x1285,"fpRelativeStep                      ");
++      ReadByteV(adap, 0x1309,"uwCoarseIntegrationPending_lines            ");
++      ReadByteV(adap, 0x130d,"uwFineIntegrationPending_pixels     ");
++      ReadByteV(adap, 0x1311,"fpAnalogGainPending                         ");
++      ReadByteV(adap, 0x1315,"fpDigitalGainPending                        ");
++      ReadByteV(adap, 0x1319,"fpDesiredExposureTime_us                    ");
++      ReadByteV(adap, 0x131d,"fpCompiledExposureTime_us                   ");
++      ReadByteV(adap, 0x132b,"uwCodedAnalogGainPending                    ");
++      ReadByteV(adap, 0x1480,"bWhiteBalanceMode                           ");
++      ReadByteV(adap, 0x1482,"bManualRedGain                      ");
++      ReadByteV(adap, 0x1484,"bManualGreenGain                            ");
++      ReadByteV(adap, 0x1486,"bManualBlueGain                     ");
++      ReadByteV(adap, 0x148b,"fpFlashRedGain                      ");
++      ReadByteV(adap, 0x148f,"fpFlashGreenGain                            ");
++      ReadByteV(adap, 0x1493,"fpFlashBlueGain                     ");
++      ReadByteV(adap, 0x1500,"bStatus                             ");
++      ReadByteV(adap, 0x1505,"fpRedGain                                   ");
++      ReadByteV(adap, 0x1509,"fpGreenGain                                 ");
++      ReadByteV(adap, 0x150d,"fpBlueGain                                  ");
++      ReadByteV(adap, 0x1581,"fpStableTotalStepThreshold                  ");
++      ReadByteV(adap, 0x1585,"fpMinimumRelativeStep                       ");
++      ReadByteV(adap, 0x1589,"fpMaximumRelativeStep                       ");
++      ReadByteV(adap, 0x1601,"fpRedA                              ");
++      ReadByteV(adap, 0x1605,"fpBlueA                             ");
++      ReadByteV(adap, 0x1609,"fpRedB                              ");
++      ReadByteV(adap, 0x160d,"fpBlueB                             ");
++      ReadByteV(adap, 0x1611,"fpMaximumDistanceAllowedFromLocus           ");
++      ReadByteV(adap, 0x1614,"fEnableConstrainedWhiteBalance      ");
++      ReadByteV(adap, 0x1616,"bACCSRCCtrl                                 ");
++      ReadByteV(adap, 0x1681,"fpOutputRedGain                     ");
++      ReadByteV(adap, 0x1685,"fpOutputGreenGain                           ");
++      ReadByteV(adap, 0x1689,"fpOutputBlueGain                            ");
++      ReadByteV(adap, 0x168c,"fAreGainsConstrained                        ");
++      ReadByteV(adap, 0x1701,"fpGradientOfLocusAB                         ");
++      ReadByteV(adap, 0x1705,"fpDistanceOfInputPointFromLocusAB           ");
++      ReadByteV(adap, 0x1709,"fpConstrainedRedPoint                       ");
++      ReadByteV(adap, 0x170d,"fpConstrainedBluePoint              ");
++      ReadByteV(adap, 0x1880,"bMaxNumberOfFramesToWaitForStability        ");
++      ReadByteV(adap, 0x1900,"fWhiteBalanceStable                         ");
++      ReadByteV(adap, 0x1902,"fExposureStable                     ");
++      ReadByteV(adap, 0x1904,"fDarkCalStable                      ");
++      ReadByteV(adap, 0x1906,"fStable                             ");
++      ReadByteV(adap, 0x1908,"fForcedStablility                           ");
++      ReadByteV(adap, 0x1985,"fpRedTilt                                   ");
++      ReadByteV(adap, 0x1989,"fpGreenTilt                                 ");
++      ReadByteV(adap, 0x198d,"fpBlueTilt                                  ");
++      ReadByteV(adap, 0x1990,"bBlackCorrectionOffset              ");
++      ReadByteV(adap, 0x1a01,"uwSensorAnalogGainFloor             ");
++      ReadByteV(adap, 0x1a05,"uwSensorAnalogGainCeiling                   ");
++      ReadByteV(adap, 0x1a80,"bFlashMode                                  ");
++      ReadByteV(adap, 0x1a83,"uwFlashOffLine                      ");
++      ReadByteV(adap, 0x1b00,"fFlashRecommended                           ");
++      ReadByteV(adap, 0x1b02,"fFlashGrabComplete                          ");
++      ReadByteV(adap, 0x1d01,"uwHorizontalOffset                          ");
++      ReadByteV(adap, 0x1d05,"uwVerticalOffset                            ");
++      ReadByteV(adap, 0x1d08,"iR2RCoefficient                     ");
++      ReadByteV(adap, 0x1d0a,"iR2GRCoefficient                            ");
++      ReadByteV(adap, 0x1d0c,"iR2GBCoefficient                            ");
++      ReadByteV(adap, 0x1d0e,"iR2BCoefficient                     ");
++      ReadByteV(adap, 0x1d10,"iR4RCoefficient                     ");
++      ReadByteV(adap, 0x1d12,"iR4GRCoefficient                            ");
++      ReadByteV(adap, 0x1d14,"iR4GBCoefficient                            ");
++      ReadByteV(adap, 0x1d16,"iR4BCoefficient                     ");
++      ReadByteV(adap, 0x1d80,"ScythefDisableFilter                        ");
++      ReadByteV(adap, 0x1e00,"JackfDisableFilter                          ");
++      ReadByteV(adap, 0x1e80,"bAntiAliasFilterSuppress                    ");
++      ReadByteV(adap, 0x1f00,"ColourMatrixDamperfDisable                  ");
++      ReadByteV(adap, 0x1f03,"fpLowThreshold                      ");
++      ReadByteV(adap, 0x1f07,"fpHighThreshold                     ");
++      ReadByteV(adap, 0x1f0b,"fpMinimumOutput                     ");
++      ReadByteV(adap, 0x1f81,"fpGInR                              ");
++      ReadByteV(adap, 0x1f85,"fpBInR                              ");
++      ReadByteV(adap, 0x1f89,"fpRInG                              ");
++      ReadByteV(adap, 0x1f8d,"fpBInG                              ");
++      ReadByteV(adap, 0x1f91,"fpRInB                              ");
++      ReadByteV(adap, 0x1f95,"fpGInB                              ");
++      ReadByteV(adap, 0x2000,"bUserPeakGain                               ");
++      ReadByteV(adap, 0x2002,"fDisableGainDamping                         ");
++      ReadByteV(adap, 0x2005,"fpDamperLowThreshold_Gain                   ");
++      ReadByteV(adap, 0x2009,"fpDamperHighThreshold_Gain                  ");
++      ReadByteV(adap, 0x200d,"fpMinimumDamperOutput_Gain                  ");
++      ReadByteV(adap, 0x2010,"bUserPeakLoThresh                           ");
++      ReadByteV(adap, 0x2012,"fDisableCoringDamping                       ");
++      ReadByteV(adap, 0x2014,"bUserPeakHiThresh                           ");
++      ReadByteV(adap, 0x2017,"fpDamperLowThreshold_Coring                 ");
++      ReadByteV(adap, 0x201b,"fpDamperHighThreshold_Coring                ");
++      ReadByteV(adap, 0x201f,"fpMinimumDamperOutput_Coring                ");
++      ReadByteV(adap, 0x2022,"bBlockControl                               ");
++      ReadByteV(adap, 0x2280,"fGammaManuCtrl0                     ");
++      ReadByteV(adap, 0x2282,"bRPeakGamma0                                ");
++      ReadByteV(adap, 0x2284,"bGPeakGamma0                                ");
++      ReadByteV(adap, 0x2286,"bBPeakGamma0                                ");
++      ReadByteV(adap, 0x2288,"bRUnPeakGamma0                      ");
++      ReadByteV(adap, 0x228a,"bGUnPeakGamma0                      ");
++      ReadByteV(adap, 0x228c,"bBUnPeakGamma0                      ");
++      ReadByteV(adap, 0x2294,"bYuvSetup  MTW                      ");
++      ReadByteV(adap, 0x2300,"fGammaManuCtrl1                     ");
++      ReadByteV(adap, 0x2302,"bRPeakGamma1                                ");
++      ReadByteV(adap, 0x2304,"bGPeakGamma1                                ");
++      ReadByteV(adap, 0x2306,"bBPeakGamma1                                ");
++      ReadByteV(adap, 0x2308,"bRUnPeakGamma1                      ");
++      ReadByteV(adap, 0x230a,"bGUnPeakGamma1                      ");
++      ReadByteV(adap, 0x230c,"bBUnPeakGamma1                      ");
++      ReadByteV(adap, 0x2381,"uwLumaExcursion0                            ");
++      ReadByteV(adap, 0x2385,"uwLumaMidpointTimes20                       ");
++      ReadByteV(adap, 0x2389,"uwChromaExcursion0                          ");
++      ReadByteV(adap, 0x238d,"uwChromaMidpointTimes20             ");
++      ReadByteV(adap, 0x2401,"uwLumaExcursion1                            ");
++      ReadByteV(adap, 0x2405,"uwLumaMidpointTimes21                       ");
++      ReadByteV(adap, 0x2409,"uwChromaExcursion1                          ");
++      ReadByteV(adap, 0x240d,"uwChromaMidpointTimes21             ");
++      ReadByteV(adap, 0x2480,"FadeToBlackfDisable                         ");
++      ReadByteV(adap, 0x2483,"fpBlackValue                                ");
++      ReadByteV(adap, 0x2487,"fpDamperLowThreshold                        ");
++      ReadByteV(adap, 0x248b,"fpDamperHighThreshold                       ");
++      ReadByteV(adap, 0x248f,"fpDamperOutput                      ");
++      ReadByteV(adap, 0x2580,"bCodeCheckEn                                ");
++      ReadByteV(adap, 0x2582,"bBlankFormat                                ");
++      ReadByteV(adap, 0x2584,"bSyncCodeSetup                      ");
++      ReadByteV(adap, 0x2586,"bHSyncSetup                                 ");
++      ReadByteV(adap, 0x2588,"bVSyncSetup                                 ");
++      ReadByteV(adap, 0x258a,"bPClkSetup                                  ");
++      ReadByteV(adap, 0x258c,"fPclkEn                             ");
++      ReadByteV(adap, 0x258e,"bOpfSpSetup                                 ");
++      ReadByteV(adap, 0x2590,"bBlankData_MSB                      ");
++      ReadByteV(adap, 0x2592,"bBlankData_LSB                      ");
++      ReadByteV(adap, 0x2594,"bRgbSetup                                   ");
++      ReadByteV(adap, 0x2596,"bYuvSetup                                   ");
++      ReadByteV(adap, 0x2598,"bVsyncRisingCoarseH                         ");
++      ReadByteV(adap, 0x259a,"bVsyncRisingCoarseL                         ");
++      ReadByteV(adap, 0x259c,"bVsyncRisingFineH                           ");
++      ReadByteV(adap, 0x259e,"bVsyncRisingFineL                           ");
++      ReadByteV(adap, 0x25a0,"bVsyncFallingCoarseH                        ");
++      ReadByteV(adap, 0x25a2,"bVsyncFallingCoarseL                        ");
++      ReadByteV(adap, 0x25a4,"bVsyncFallingFineH                          ");
++      ReadByteV(adap, 0x25a6,"bVsyncFallingFineL                          ");
++      ReadByteV(adap, 0x25a8,"bHsyncRisingH                               ");
++      ReadByteV(adap, 0x25aa,"bHsyncRisingL                               ");
++      ReadByteV(adap, 0x25ac,"bHsyncFallingH                      ");
++      ReadByteV(adap, 0x25ae,"bHsyncFallingL                      ");
++      ReadByteV(adap, 0x25b0,"bOutputInterface                            ");
++      ReadByteV(adap, 0x25b2,"bCCPExtraData                               ");
++      ReadByteV(adap, 0x2600,"NoRAfDisable                                ");
++      ReadByteV(adap, 0x2602,"bUsage                              ");
++      ReadByteV(adap, 0x2604,"bSplit_Kn                                   ");
++      ReadByteV(adap, 0x2606,"bSplit_Nl                                   ");
++      ReadByteV(adap, 0x2608,"bTight_Green                                ");
++      ReadByteV(adap, 0x260a,"fDisableNoraPromoting                       ");
++      ReadByteV(adap, 0x260d,"DamperLowThreshold                          ");
++      ReadByteV(adap, 0x2611,"DamperHighThreshold                         ");
++      ReadByteV(adap, 0x2615,"MinimumDamperOutput                         ");
++
++      return;
++}
+--- /dev/null
++++ git/drivers/bmi/pims/camera/vs6624_access.h
+@@ -0,0 +1,17 @@
++#ifndef VS6624_ACCESS_H
++#define VS6624_ACCESS_H
++
++#include <linux/i2c.h>
++void vs6624_get_color(struct i2c_adapter *adap, int *bright, int *saturation, int *red, int *green, int *blue);
++void vs6624_set_color(struct i2c_adapter *adap, int bright, int saturation, int red, int green, int blue);
++
++
++
++void vs6624_patch (struct i2c_adapter *adap);
++int vs6624_ReadByte(struct i2c_adapter *adap, unsigned short offset, unsigned char *data);
++int vs6624_WriteByte(struct i2c_adapter *adap, unsigned short offset, unsigned char data);
++int  vs6624_WriteSequence(struct i2c_adapter *adap, const unsigned short array[][2], unsigned short len);
++void vs6624_dump_regs(struct i2c_adapter *adap);
++
++#endif
++
+--- /dev/null
++++ git/drivers/bmi/pims/camera/vs6624_patch.c
+@@ -0,0 +1,373 @@
++static const unsigned short patch_p1[][2] = {
++      {0x8104, 3},
++      {0x8105, 1},
++      {0xc900, 0x03},
++      {0xc904, 0x47},
++      {0xc905, 0x10},
++      {0xc906, 0x80},
++      {0xc907, 0x3a},
++      {0x903a, 0x02},
++      {0x903b, 0x47},
++      {0x903c, 0x15},
++      {0xc908, 0x31},
++      {0xc909, 0xdc},
++      {0xc90a, 0x80},
++      {0xc90b, 0x44},
++      {0x9044, 0x02},
++      {0x9045, 0x31},
++      {0x9046, 0xe2},
++      {0xc90c, 0x07},
++      {0xc90d, 0xe0},
++      {0xc90e, 0x80},
++      {0xc90f, 0x47},
++      {0x9047, 0x90},
++      {0x9048, 0x83},
++      {0x9049, 0x81},
++      {0x904a, 0xe0},
++      {0x904b, 0x60},
++      {0x904c, 0x08},
++      {0x904d, 0x90},
++      {0x904e, 0xc0},
++      {0x904f, 0x43},
++      {0x9050, 0x74},
++      {0x9051, 0x01},
++      {0x9052, 0xf0},
++      {0x9053, 0x80},
++      {0x9054, 0x05},
++      {0x9055, 0xE4},
++      {0x9056, 0x90},
++      {0x9057, 0xc0},
++      {0x9058, 0x43},
++      {0x9059, 0xf0},
++      {0x905a, 0x02},
++      {0x905b, 0x07},
++      {0x905c, 0xec},
++      {0xc910, 0x5d},
++      {0xc911, 0xca},
++      {0xc912, 0x80},
++      {0xc913, 0x5d},
++      {0x905d, 0xa3},
++      {0x905e, 0x04},
++      {0x905f, 0xf0},
++      {0x9060, 0xa3},
++      {0x9061, 0x04},
++      {0x9062, 0xf0},
++      {0x9063, 0x22},
++      {0xc914, 0x72},
++      {0xc915, 0x92},
++      {0xc916, 0x80},
++      {0xc917, 0x64},
++      {0x9064, 0x74},
++      {0x9065, 0x01},
++      {0x9066, 0x02},
++      {0x9067, 0x72},
++      {0x9068, 0x95},
++      {0xc918, 0x47},
++      {0xc919, 0xf2},
++      {0xc91a, 0x81},
++      {0xc91b, 0x69},
++      {0x9169, 0x74},
++      {0x916a, 0x02},
++      {0x916b, 0xf0},
++      {0x916c, 0xec},
++      {0x916d, 0xb4},
++      {0x916e, 0x10},
++      {0x916f, 0x0a},
++      {0x9170, 0x90},
++      {0x9171, 0x80},
++      {0x9172, 0x16},
++      {0x9173, 0xe0},
++      {0x9174, 0x70},
++      {0x9175, 0x04},
++      {0x9176, 0x90},
++      {0x9177, 0xd3},
++      {0x9178, 0xc4},
++      {0x9179, 0xf0},
++      {0x917a, 0x22},
++      {0xc91c, 0x0a},
++      {0xc91d, 0xbe},
++      {0xc91e, 0x80},
++      {0xc91f, 0x73},
++      {0x9073, 0xfc},
++      {0x9074, 0xa3},
++      {0x9075, 0xe0},
++      {0x9076, 0xf5},
++      {0x9077, 0x82},
++      {0x9078, 0x8c},
++      {0x9079, 0x83},
++      {0x907a, 0xa3},
++      {0x907b, 0xa3},
++      {0x907c, 0xe0},
++      {0x907d, 0xfc},
++      {0x907e, 0xa3},
++      {0x907f, 0xe0},
++      {0x9080, 0xc3},
++      {0x9081, 0x9f},
++      {0x9082, 0xff},
++      {0x9083, 0xec},
++      {0x9084, 0x9e},
++      {0x9085, 0xfe},
++      {0x9086, 0x02},
++      {0x9087, 0x0a},
++      {0x9088, 0xea},
++      {0xc920, 0x47},
++      {0xc921, 0x38},
++      {0xc922, 0x80},
++      {0xc923, 0x89},
++      {0x9089, 0xec},
++      {0x908a, 0xd3},
++      {0x908b, 0x94},
++      {0x908c, 0x20},
++      {0x908d, 0x40},
++      {0x908e, 0x01},
++      {0x908f, 0x1c},
++      {0x9090, 0x90},
++      {0x9091, 0xd3},
++      {0x9092, 0xd4},
++      {0x9093, 0xec},
++      {0x9094, 0xf0},
++      {0x9095, 0x02},
++      {0x9096, 0x47},
++      {0x9097, 0x3d},
++      {0xc924, 0x45},
++      {0xc925, 0xca},
++      {0xc926, 0x80},
++      {0xc927, 0x98},
++      {0x9098, 0x12},
++      {0x9099, 0x77},
++      {0x909a, 0xd6},
++      {0x909b, 0x02},
++      {0x909c, 0x45},
++      {0x909d, 0xcd},
++      {0xc928, 0x20},
++      {0xc929, 0xd5},
++      {0xc92a, 0x80},
++      {0xc92b, 0x9e},
++      {0x909e, 0x90},
++      {0x909f, 0x82},
++      {0x90a0, 0x18},
++      {0x90a1, 0xe0},
++      {0x90a2, 0xb4},
++      {0x90a3, 0x03},
++      {0x90a4, 0x0e},
++      {0x90a5, 0x90},
++      {0x90a6, 0x83},
++      {0x90a7, 0xbf},
++      {0x90a8, 0xe0},
++      {0x90a9, 0x60},
++      {0x90aa, 0x08},
++      {0x90ab, 0x90},
++      {0x90ac, 0x81},
++      {0x90ad, 0xfc},
++      {0x90ae, 0xe0},
++      {0x90af, 0xff},
++      {0x90b0, 0xc3},
++      {0x90b1, 0x13},
++      {0x90b2, 0xf0},
++      {0x90b3, 0x90},
++      {0x90b4, 0x81},
++      {0x90b5, 0xfc},
++      {0x90b6, 0xe0},
++      {0x90b7, 0xff},
++      {0x90b8, 0x02},
++      {0x90b9, 0x20},
++      {0x90ba, 0xda},
++      {0xc92c, 0x70},
++      {0xc92d, 0xbc},
++      {0xc92e, 0x80},
++      {0xc92f, 0xbb},
++      {0x90bb, 0x90},
++      {0x90bc, 0x82},
++      {0x90bd, 0x18},
++      {0x90be, 0xe0},
++      {0x90bf, 0xb4},
++      {0x90c0, 0x03},
++      {0x90c1, 0x06},
++      {0x90c2, 0x90},
++      {0x90c3, 0xc1},
++      {0x90c4, 0x06},
++      {0x90c5, 0x74},
++      {0x90c6, 0x05},
++      {0x90c7, 0xf0},
++      {0x90c8, 0x90},
++      {0x90c9, 0xd3},
++      {0x90ca, 0xa0},
++      {0x90cb, 0x02},
++      {0x90cc, 0x70},
++      {0x90cd, 0xbf},
++      {0xc930, 0x72},
++      {0xc931, 0x21},
++      {0xc932, 0x81},
++      {0xc933, 0x3b},
++      {0x913b, 0x7d},
++      {0x913c, 0x02},
++      {0x913d, 0x7f},
++      {0x913e, 0x7b},
++      {0x913f, 0x02},
++      {0x9140, 0x72},
++      {0x9141, 0x25},
++      {0xc934, 0x28},
++      {0xc935, 0xae},
++      {0xc936, 0x80},
++      {0xc937, 0xd2},
++      {0x90d2, 0xf0},
++      {0x90d3, 0x90},
++      {0x90d4, 0xd2},
++      {0x90d5, 0x0a},
++      {0x90d6, 0x02},
++      {0x90d7, 0x28},
++      {0x90d8, 0xb4},
++      {0xc938, 0x28},
++      {0xc939, 0xb1},
++      {0xc93a, 0x80},
++      {0xc93b, 0xd9},
++      {0x90d9, 0x90},
++      {0x90da, 0x83},
++      {0x90db, 0xba},
++      {0x90dc, 0xe0},
++      {0x90dd, 0xff},
++      {0x90de, 0x90},
++      {0x90df, 0xd2},
++      {0x90e0, 0x08},
++      {0x90e1, 0xe0},
++      {0x90e2, 0xe4},
++      {0x90e3, 0xef},
++      {0x90e4, 0xf0},
++      {0x90e5, 0xa3},
++      {0x90e6, 0xe0},
++      {0x90e7, 0x74},
++      {0x90e8, 0xff},
++      {0x90e9, 0xf0},
++      {0x90ea, 0x90},
++      {0x90eb, 0xd2},
++      {0x90ec, 0x0a},
++      {0x90ed, 0x02},
++      {0x90ee, 0x28},
++      {0x90ef, 0xb4},
++      {0xc93c, 0x29},
++      {0xc93d, 0x79},
++      {0xc93e, 0x80},
++      {0xc93f, 0xf0},
++      {0x90f0, 0xf0},
++      {0x90f1, 0x90},
++      {0x90f2, 0xd2},
++      {0x90f3, 0x0e},
++      {0x90f4, 0x02},
++      {0x90f5, 0x29},
++      {0x90f6, 0x7f},
++      {0xc940, 0x29},
++      {0xc941, 0x7c},
++      {0xc942, 0x80},
++      {0xc943, 0xf7},
++      {0x90f7, 0x90},
++      {0x90f8, 0x83},
++      {0x90f9, 0xba},
++      {0x90fa, 0xe0},
++      {0x90fb, 0xff},
++      {0x90fc, 0x90},
++      {0x90fd, 0xd2},
++      {0x90fe, 0x0c},
++      {0x90ff, 0xe0},
++      {0x9100, 0xe4},
++      {0x9101, 0xef},
++      {0x9102, 0xf0},
++      {0x9103, 0xa3},
++      {0x9104, 0xe0},
++      {0x9105, 0x74},
++      {0x9106, 0xff},
++      {0x9107, 0xf0},
++      {0x9108, 0x90},
++      {0x9109, 0xd2},
++      {0x910a, 0x0e},
++      {0x910b, 0x02},
++      {0x910c, 0x29},
++      {0x910d, 0x7f},
++      {0xc944, 0x2a},
++      {0xc945, 0x42},
++      {0xc946, 0x81},
++      {0xc947, 0x0e},
++      {0x910e, 0xf0},
++      {0x910f, 0x90},
++      {0x9110, 0xd2},
++      {0x9111, 0x12},
++      {0x9112, 0x02},
++      {0x9113, 0x2a},
++      {0x9114, 0x48},
++      {0xc948, 0x2a},
++      {0xc949, 0x45},
++      {0xc94a, 0x81},
++      {0xc94b, 0x15},
++      {0x9115, 0x90},
++      {0x9116, 0x83},
++      {0x9117, 0xba},
++      {0x9118, 0xe0},
++      {0x9119, 0xff},
++      {0x911a, 0x90},
++      {0x911b, 0xd2},
++      {0x911c, 0x10},
++      {0x911d, 0xe0},
++      {0x911e, 0xe4},
++      {0x911f, 0xef},
++      {0x9120, 0xf0},
++      {0x9121, 0xa3},
++      {0x9122, 0xe0},
++      {0x9123, 0x74},
++      {0x9124, 0xff},
++      {0x9125, 0xf0},
++      {0x9126, 0x90},
++      {0x9127, 0xd2},
++      {0x9128, 0x12},
++      {0x9129, 0x02},
++      {0x912a, 0x2a},
++      {0x912b, 0x48},
++      {0xc900, 0x01}
++};
++
++static const unsigned short patch_p2[][2] = {
++      {0x806f, 0x01},
++      {0x058c, 0x01}
++};
++
++static const unsigned short patch_run_setup[][2] = {
++      {0x2596, 0x01},         /* U first */
++      {0x1d18, 0x00},         /* Enableconstrainedwhitebalance */
++      {0x200d, 0x3c},         /* Damper PeakGain Output MSB */
++      {0x200e, 0x66},         /* Damper PeakGain Output LSB */
++      {0x1f03, 0x65},         /* Damper Low MSB */
++      {0x1f04, 0xd1},         /* Damper Low LSB */
++      {0x1f07, 0x66},         /* Damper High MSB */
++      {0x1f08, 0x62},         /* Damper High LSB */
++      {0x1f0b, 0x00},         /* Damper Min output MSB */
++      {0x1f0c, 0x00},         /* Damper Min output LSB */
++      {0x2600, 0x00},         /* Nora fDisable */
++      {0x2602, 0x04},         /* Nora usage */
++      {0x260d, 0x63},         /* Damper Low MSB Changed 0x63 to 0x65 */
++      {0x260e, 0xd1},         /* Damper Low LSB */
++      {0x2611, 0x68},         /* Damper High MSB */
++      {0x2612, 0xdd},         /* Damper High LSB */
++      {0x2615, 0x3a},         /* Damper Min output MSB */
++      {0x2616, 0x00},         /* Damper Min output LSB */
++      {0x2480, 0x00},         /* Disable */
++      {0x1d8a, 0x30},         /* MAXWeightHigh */
++      {0x1d91, 0x62},         /* fpDamperLowThresholdHigh MSB */
++      {0x1d92, 0x4a},         /* fpDamperLowThresholdHigh LSB */
++      {0x1d95, 0x65},         /* fpDamperHighThresholdHigh MSB */
++      {0x1d96, 0x0e},         /* fpDamperHighThresholdHigh LSB */
++      {0x1da1, 0x3a},         /* fpMinimumDamperOutputLow MSB */
++      {0x1da2, 0xb8},         /* fpMinimumDamperOutputLow LSB */
++      {0x1e08, 0x06},         /* MAXWeightLow */
++      {0x1e0a, 0x0a},         /* MAXWeightHigh */
++      {0x1601, 0x3a},         /* Red A MSB */
++      {0x1602, 0x14},         /* Red A LSB */
++      {0x1605, 0x3b},         /* Blue A MSB */
++      {0x1606, 0x85},         /* BLue A LSB */
++      {0x1609, 0x3b},         /* RED B MSB */
++      {0x160a, 0x85},         /* RED B LSB */
++      {0x160d, 0x3a},         /* Blue B MSB */
++      {0x160e, 0x14},         /* Blue B LSB */
++      {0x1611, 0x30},         /* Max Distance from Locus MSB */
++      {0x1612, 0x8f},         /* Max Distance from Locus MSB */
++      {0x1614, 0x01}          /* Enable constrainer */
++};
++
++
+--- /dev/null
++++ git/drivers/bmi/pims/camera/vs6624_regs.h
+@@ -0,0 +1,467 @@
++/*
++ * File:         drivers/media/video/mxc/capture/_vs6624.h
++ * Author:       Peter Giacomini <p.giacomini@encadis.com>
++ *
++ *            This is the header file for the ST VS6624 camera on the
++ *            MX31 BUG platform. It is derived from the following
++ *            Blackfin and MX31 sources:
++ *
++ */
++
++/*
++ *                                                    <BLACKFIN>
++ *
++ * Based on:     drivers/media/video/blackfin/vs6624.h
++ * Author:       Michael Hennerich <hennerich@blackfin.uclinux.org>
++ *
++ * Created:
++ * Description:  Command driver for STM VS6624 sensor
++ *
++ *
++ * Modified:
++ *               Copyright 2004-2007 Analog Devices Inc.
++ *
++ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
++ *
++ * 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, see the file COPYING, or write
++ * to the Free Software Foundation, Inc.,
++ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ */
++
++/*
++ *                                                    <MX31>
++ *
++ * Copyright 2004-2006 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*!
++ * @defgroup Camera Sensor Drivers
++ */
++
++/*!
++ * @file mt9v111.h
++ *
++ * @brief MT9V111 Camera Header file
++ *
++ * It include all the defines for bitmaps operations, also two main structure
++ * one for IFP interface structure, other for sensor core registers.
++ *
++ * @ingroup Camera
++ */
++
++#ifndef _VS6624_H
++#define _VS6624_H
++
++/* I2C Slave Address */
++#define VS6624_I2C_ADDRESS    0x10    // 7-bit address
++#define SENSOR_NAME                   "VS6624"
++
++//pjg #define         USE_ITU656
++
++/* VS6624 register definitions */
++#define VS6624_ID                                     624
++#define PWR_MAN_SETUP_MODE_SELECT                             0xc003          /* (7:0) */
++#define PWR_MAN_DIO_ENABLE                                    0xc044          /* (7:0) */
++#define uwDeviceId                                            0x0001          /* (7:0) IndexLo 0x0002 */
++#define DeviceID_MSB                                          0x0001          /* (7:0) */
++#define DeviceID_LSB                                          0x0002          /* (7:0) */
++#define bFirmwareVsnMajor                                     0x0004          /* (7:0) */
++#define bFirmwareVsnMinor                                     0x0006          /* (7:0) */
++#define bPatchVsnMajor                                                0x0008          /* (7:0) */
++#define bPatchVsnMinor                                                0x000a          /* (7:0) */
++
++#define bUserCommand                                          0x0180          /* (7:0) */
++#define bManualNextState                                      0x0186          /* (7:0) */
++
++#define bNextState                                            0x0200          /* (7:0) */
++#define bState                                                        0x0202          /* (7:0) */
++
++#define fMeteringOn                                           0x0280          /* (7:0) */
++#define fExitOnStable                                         0x0282          /* (7:0) */
++#define bStreamLength                                         0x0284          /* (7:0) */
++
++#define fIsColdStart                                          0x0300          /* (7:0) */
++#define bNonViewLive_ActivePipeSetupBank                      0x0302          /* (7:0) */
++#define bSnapShoot_ActivePipeSetupBank                                0x0304          /* (7:0) */
++#define fSnapShoot_NoWaiting                                  0x0306          /* (7:0) */
++#define SensorMode                                            0x0308          /* (7:0) */
++
++#define bImageSize0                                           0x0380          /* (7:0) */
++#define uwManualHSize0                                                0x0383          /* (7:0) IndexLo 0x0384 */
++#define uwManualHSizeMSB0                                     0x0383          /* (7:0) */
++#define uwManualHSizeLSB0                                     0x0384          /* (7:0) */
++#define uwManualVSize0                                                0x0387          /* (7:0) IndexLo 0x0388 */
++#define uwManualVSizeMSB0                                     0x0387          /* (7:0) */
++#define uwManualVSizeLSB0                                     0x0388          /* (7:0) */
++#define uwZoomStepHSize0                                      0x038b          /* (7:0) IndexLo 0x038c */
++#define uwZoomStepHSizeMSB0                                   0x038b          /* (7:0) */
++#define uwZoomStepHSizeLSB0                                   0x038c          /* (7:0) */
++#define uwZoomStepVSize0                                      0x038f          /* (7:0) IndexLo 0x0390 */
++#define uwZoomStepVSizeMSB0                                   0x038f          /* (7:0) */
++#define uwZoomStepVSizeLSB0                                   0x0390          /* (7:0) */
++#define bZoomControl0                                         0x0392          /* (7:0) */
++#define uwPanStepHSize0                                               0x0395          /* (7:0) IndexLo 0x0396 */
++#define uwPanStepHSizeMSB0                                    0x0395          /* (7:0) */
++#define uwPanStepHSizeLSB0                                    0x0396          /* (7:0) */
++#define uwPanStepVSize0                                               0x0399          /* (7:0) IndexLo 0x039a */
++#define uwPanStepVSizeMSB0                                    0x0399          /* (7:0) */
++#define uwPanStepVSizeLSB0                                    0x039a          /* (7:0)             */
++#define bPanControl0                                          0x039c          /* (7:0) */
++#define bCropControl0                                         0x039e          /* (7:0) */
++#define uwManualCropHorizontalStart0                          0x03a1          /* (7:0) IndexLo 0x03a2 */
++#define uwManualCropHorizontalSize0                           0x03a5          /* (7:0) IndexLo 0x03a6 */
++#define uwManualCropVerticalStart0                            0x03a9          /* (7:0) IndexLo 0x03aa */
++#define uwManualCropVerticalSize0                             0x03ad          /* (7:0) IndexLo 0x03ae */
++#define bCropHStartMSB0                                               0x03a1          /* (7:0) */
++#define bCropHStartLSB0                                               0x03a2          /* (7:0) */
++#define bCropVStartMSB0                                               0x03a9          /* (7:0) */
++#define bCropVStartLSB0                                               0x03aa          /* (7:0) */
++#define bCropHSizeMSB0                                                0x03a5          /* (7:0) */
++#define bCropHSizeLSB0                                                0x03a6          /* (7:0) */
++#define bCropVSizeMSB0                                                0x03ad          /* (7:0) */
++#define bCropVSizeLSB0                                                0x03ae          /* (7:0) */
++#define bDataFormat0                                          0x03b0          /* (7:0) */
++#define bBayerOutputAlignment0                                        0x03b2          /* (7:0) */
++#define bContrast0                                            0x03b4          /* (7:0) */
++#define bColourSaturation0                                    0x03b6          /* (7:0) */
++#define bGamma0                                                       0x03b8          /* (7:0) */
++#define fHorizontalMirror0                                    0x03ba          /* (7:0) */
++#define fVerticalFlip0                                                0x03bc          /* (7:0) */
++#define bChannelID0                                           0x03be          /* (7:0) */
++
++#define bImageSize1                                           0x0400          /* (7:0) */
++#define uwManualHSize1                                                0x0403          /* (7:0) IndexLo 0x0404 */
++#define uwManualVSize1                                                0x0407          /* (7:0) IndexLo 0x0408 */
++#define uwZoomStepHSize1                                      0x040b          /* (7:0) IndexLo 0x040c */
++#define uwZoomStepVSize1                                      0x040f          /* (7:0) IndexLo 0x0410 */
++#define bZoomControl1                                         0x0412          /* (7:0) */
++#define uwPanStepHSize1                                               0x0415          /* (7:0) IndexLo 0x0416 */
++#define uwPanStepVSize1                                               0x0419          /* (7:0) IndexLo 0x041a */
++#define bPanControl1                                          0x041c          /* (7:0) */
++#define bCropControl1                                         0x041e          /* (7:0) */
++#define uwManualCropHorizontalStart1                          0x0421          /* (7:0) IndexLo 0x0422 */
++#define uwManualCropHorizontalSize1                           0x0425          /* (7:0) IndexLo 0x0426 */
++#define uwManualCropVerticalStart1                            0x0429          /* (7:0) IndexLo 0x042a */
++#define uwManualCropVerticalSize1                             0x042d          /* (7:0) IndexLo 0x042e */
++#define bCropHStartMSB1                                               0x0421          /* (7:0) */
++#define bCropHStartLSB1                                               0x0422          /* (7:0) */
++#define bCropVStartMSB1                                               0x0429          /* (7:0) */
++#define bCropVStartLSB1                                               0x042a          /* (7:0) */
++#define bCropHSizeMSB1                                                0x0425          /* (7:0) */
++#define bCropHSizeLSB1                                                0x0426          /* (7:0) */
++#define bCropVSizeMSB1                                                0x042d          /* (7:0) */
++#define bCropVSizeLSB1                                                0x042e          /* (7:0) */
++#define bDataFormat1                                          0x0430          /* (7:0) */
++#define bBayerOutputAlignment1                                        0x0432          /* (7:0) */
++#define bContrast1                                            0x0434          /* (7:0) */
++#define bColourSaturation1                                    0x0436          /* (7:0) */
++#define bGamma1                                                       0x0438          /* (7:0) */
++#define fHorizontalMirror1                                    0x043a          /* (7:0) */
++#define fVerticalFlip1                                                0x043c          /* (7:0) */
++#define bChannelID1                                           0x043e          /* (7:0) */
++
++#define fEnable                                                       0x0480          /* (7:0) */
++#define bInitialPipeSetupBank                                 0x0482          /* (7:0) */
++
++#define CurrentPipeSetupBank                                  0x0500          /* (7:0) */
++
++#define bTimeToPowerdown                                      0x0580          /* (7:0) */
++#define fVRegSleep                                            0x058a          /* (7:0) */
++#define fSmoothLineReading                                    0x058c          /* (7:0) */
++
++#define uwExternalClockFrequencyMhzNumerator          0x0605          /* (7:0) IndexLo 0x0606 */
++#define uwExternalClockFrequencyMhzNumeratorMSB               0x0605          /* (7:0) IndexLo 0x0606 */
++#define uwExternalClockFrequencyMhzNumeratorLSB               0x0606          /* (7:0) IndexLo 0x0606 */
++#define bExternalClockFrequencyMhzDenominator         0x0608          /* (7:0) */
++
++#define fpExternalClockFrequencyMhz                           0x0681          /* (7:0) IndexLo 0x0682 */
++
++#define bSysClkMode                                           0x0880          /* (7:0) */
++#define bMode                                                 0x0882          /* (7:0) */
++#define bLightingFrequencyHz                                  0x0c80          /* (7:0) */
++#define fFlickerCompatibleFrameLength                         0x0c82          /* (7:0) */
++
++#define fpFlickerFreePeriod_us                                        0x0d05          /* (7:0) IndexLo 0x0d06 */
++#define fAntiFlickerEnabled                                   0x0d08          /* (7:0) */
++
++#define uwDesiredFrameRate_Num                                        0x0d81          /* (7:0) IndexLo 0x0d82 */
++#define uwDesiredFrameRate_Num_MSB                            0x0d81          /* (7:0) */
++#define uwDesiredFrameRate_Num_LSB                            0x0d82          /* (7:0) */
++#define bDesiredFrameRate_Den                                 0x0d84          /* (7:0) */
++
++#define fpRequestedFrameRate_Hz                                       0x0e01          /* (7:0) IndexLo 0x0e02 */
++#define fpRequestedFrameRate_Hz_MSB                           0x0e01          /* (7:0) */
++#define fpRequestedFrameRate_Hz_LSB                           0x0e02          /* (7:0) */
++#define fpMaxFrameRate_Hz                                     0x0e05          /* (7:0) IndexLo 0x0e06 */
++#define fpMinFrameRate_Hz                                     0x0e09          /* (7:0) IndexLo 0x0e0a */
++#define fChangePending                                                0x0e0c          /* (7:0) */
++#define uwRequiredFrameLength_lines                           0x0e0f          /* (7:0) IndexLo 0x0e10 */
++#define ClipFrameRate                                         0x0e12          /* (7:0) */
++
++#define fDisableFrameRateDamper                                       0x0e80          /* (7:0) */
++#define bImpliedGainThresholdLow_num                          0x0e82          /* (7:0) */
++#define bImpliedGainThresholdLow_den                          0x0e84          /* (7:0) */
++#define bImpliedGainThresholdHigh_num                         0x0e86          /* (7:0) */
++#define bImpliedGainThresholdHigh_den                         0x0e88          /* (7:0) */
++#define bUserMinimumFrameRate_Hz                              0x0e8a          /* (7:0) */
++#define bUserMaximumFrameRate_Hz                              0x0e8c          /* (7:0) */
++#define bRelativeChange_num                                   0x0e8e          /* (7:0) */
++#define bRelativeChange_den                                   0x0e90          /* (7:0) */
++#define fDivorceMinFrameRateFromMaxIntegration                0x0e92          /* (7:0) */
++
++#define fpImpliedGain                                         0x0f01          /* (7:0) IndexLo 0x0f02 */
++#define uwMaximumFrameLength_lines                            0x0f05          /* (7:0) IndexLo 0x0f06 */
++#define uwMinimumFrameLength_lines                            0x0f09          /* (7:0) IndexLo 0x0f0a */
++#define uwFrameLengthChange_lines                             0x0f0d          /* (7:0) IndexLo 0x0f0e */
++#define fpDesiredAutomaticFrameRate_Hz                                0x0f11          /* (7:0) IndexLo 0x0f12 */
++#define uwCurrentFrameLength_lines                            0x0f15          /* (7:0) IndexLo 0x0f16 */
++#define uwDesiredFrameLength_lines                            0x0f19          /* (7:0) IndexLo 0x0f1a */
++#define fAutomaticFrameRateStable                             0x0f1c          /* (7:0) */
++#define fAutomaticFrameRateClip                                       0x0f1e          /* (7:0) */
++
++#define uwXOffset                                             0x0f81          /* (7:0) IndexLo 0x0f82 */
++#define uwYOffset                                             0x0f85          /* (7:0) IndexLo 0x0f86 */
++#define uwXSize                                                       0x0f89          /* (7:0) IndexLo 0x0f8a */
++#define uwYSize                                                       0x0f8d          /* (7:0) IndexLo 0x0f8e */
++
++#define ExposureControls_bMode                                        0x1180          /* (7:0) */
++#define bExposureMetering                                     0x1182          /* (7:0) */
++#define bManualExposureTime_s_num                             0x1184          /* (7:0) */
++#define bManualExposureTime_s_den                             0x1186          /* (7:0) */
++#define fpManualDesiredExposureTime_us                                0x1189          /* (7:0) IndexLo 0x118a */
++#define iExposureCompensation                                 0x1190          /* (7:0) Signed       */
++#define uwDirectModeCoarseIntegration_lines                   0x1195          /* (7:0) IndexLo 0x1196 */
++#define uwDirectModeFineIntegration_pixels                    0x1199          /* (7:0) IndexLo 0x119a */
++#define uwDirectModeCodedAnalogGain                           0x119d          /* (7:0) IndexLo 0x119e */
++#define fpDirectModeDigitalGain                                       0x11a1          /* (7:0) IndexLo 0x11a2 */
++#define uwFlashGunModeCoarseIntegration_lines         0x11a5          /* (7:0) IndexLo 0x11a6 */
++#define uwFlashGunModeFineIntegration_pixels          0x11a9          /* (7:0) IndexLo 0x11aa */
++#define uwFlashGunModeCodedAnalogGain                         0x11ad          /* (7:0) IndexLo 0x11ae */
++#define fpFlashGunModeDigitalGain                             0x11b1          /* (7:0) IndexLo 0x11b2 */
++#define fFreezeAutoExposure                                   0x11b4          /* (7:0) */
++#define fpUserMaximumIntegrationTime_us                               0x11b7          /* (7:0) IndexLo 0x11b8 */
++#define fpRecommendFlashGunAnalogGainThreshold                0x11bb          /* (7:0) IndexLo 0x11bc */
++#define fEnableHighClipForDesiredExposureTime         0x11be          /* (7:0) */
++#define bAntiFlickerMode                                      0x11c0          /* (7:0) */
++
++#define fpMaximumStep                                         0x1201          /* (7:0) IndexLo 0x1202 */
++#define fpMinimumStep                                         0x1205          /* (7:0) IndexLo 0x1206 */
++#define fpMinimumDesiredExposureTime_us                               0x1209          /* (7:0) IndexLo 0x120a */
++#define fpStepProportion                                      0x120d          /* (7:0) IndexLo 0x120e */
++#define fpMaximumNegativeStepThreshold                                0x1211          /* (7:0) IndexLo 0x1212 */
++#define fpRelativeOnTargetStabilityThreshold          0x1215          /* (7:0) IndexLo 0x1216 */
++#define fpDigitalGainFloor                                    0x1219          /* (7:0) IndexLo 0x121a */
++#define fpDigitalGainCeiling                                  0x121d          /* (7:0) IndexLo 0x121e */
++#define fpRelativeIntTimeHysThreshold                         0x1221          /* (7:0) IndexLo 0x1222 */
++#define fpRelativeDigitalGainHysThreshold                     0x1225          /* (7:0) IndexLo 0x1226 */
++#define fpRelativeCompilationProblemThreshold         0x1229          /* (7:0) IndexLo 0x122a */
++#define fpRoundUpBunchFudge                                   0x122d          /* (7:0) IndexLo 0x122e */
++#define fpFineClampThreshold                                  0x1231          /* (7:0) IndexLo 0x1232 */
++#define fpMaximumManualExposureTime_s                         0x1235          /* (7:0) IndexLo 0x1236 */
++#define fpRelativeStabilityThresholdForAutoFocus      0x1239          /*  (7:0) IndexLo 0x123a */
++#define bLeakShift                                            0x123c          /* (7:0) */
++
++#define fpLeakyEnergy                                         0x1281          /* (7:0) IndexLo 0x1282 */
++#define fpRelativeStep                                                0x1285          /* (7:0) IndexLo 0x1286 */
++
++#define uwCoarseIntegrationPending_lines                      0x1309          /* (7:0) IndexLo 0x130a */
++#define uwFineIntegrationPending_pixels                               0x130d          /* (7:0) IndexLo 0x130e */
++#define fpAnalogGainPending                                   0x1311          /* (7:0) IndexLo 0x1312 */
++#define fpDigitalGainPending                                  0x1315          /* (7:0) IndexLo 0x1316 */
++#define fpDesiredExposureTime_us                              0x1319          /* (7:0) IndexLo 0x131a */
++#define fpCompiledExposureTime_us                             0x131d          /* (7:0) IndexLo 0x131e */
++#define uwCodedAnalogGainPending                              0x132b          /* (7:0) IndexLo 0x132c */
++
++#define bWhiteBalanceMode                                     0x1480          /* (7:0) */
++#define bManualRedGain                                                0x1482          /* (7:0) */
++#define bManualGreenGain                                      0x1484          /* (7:0) */
++#define bManualBlueGain                                               0x1486          /* (7:0) */
++#define fpFlashRedGain                                                0x148b          /* (7:0) IndexLo 0x148c */
++#define fpFlashGreenGain                                      0x148f          /* (7:0) IndexLo 0x1490 */
++#define fpFlashBlueGain                                               0x1493          /* (7:0) IndexLo 0x1494 */
++
++#define bStatus                                                       0x1500          /* (7:0) */
++#define fpRedGain                                             0x1505          /* (7:0) IndexLo 0x1506 */
++#define fpGreenGain                                           0x1509          /* (7:0) IndexLo 0x150a */
++#define fpBlueGain                                            0x150d          /* (7:0) IndexLo 0x150e */
++
++#define fpStableTotalStepThreshold                            0x1581          /* (7:0) IndexLo 0x1582 */
++#define fpMinimumRelativeStep                                 0x1585          /* (7:0) IndexLo 0x1586 */
++#define fpMaximumRelativeStep                                 0x1589          /* (7:0) IndexLo 0x158a */
++/*#define fpStepProportion                            0x158d*/        /* (7:0) IndexLo 0x158e */
++
++#define fpRedA                                                        0x1601          /* (7:0) IndexLo 0x1602 */
++#define fpBlueA                                                       0x1605          /* (7:0) IndexLo 0x1606 */
++#define fpRedB                                                        0x1609          /* (7:0) IndexLo 0x160a */
++#define fpBlueB                                                       0x160d          /* (7:0) IndexLo 0x160e */
++#define fpMaximumDistanceAllowedFromLocus                     0x1611          /* (7:0) IndexLo 0x1612 */
++#define fEnableConstrainedWhiteBalance                                0x1614          /* (7:0) */
++#define bACCSRCCtrl                                           0x1616          /* (7:0) */
++
++#define fpOutputRedGain                                               0x1681          /* (7:0) IndexLo 0x1682 */
++#define fpOutputGreenGain                                     0x1685          /* (7:0) IndexLo 0x1686 */
++#define fpOutputBlueGain                                      0x1689          /* (7:0) IndexLo 0x168a */
++#define fAreGainsConstrained                                  0x168c          /* (7:0) */
++
++#define fpGradientOfLocusAB                                   0x1701          /* (7:0) IndexLo 0x1702 */
++#define fpDistanceOfInputPointFromLocusAB                     0x1705          /* (7:0) IndexLo 0x1706 */
++#define fpConstrainedRedPoint                                 0x1709          /* (7:0) IndexLo 0x170a */
++#define fpConstrainedBluePoint                                        0x170d          /* (7:0) IndexLo 0x170e */
++
++#define bMaxNumberOfFramesToWaitForStability          0x1880          /* (7:0) */
++
++#define fWhiteBalanceStable                                   0x1900          /* (7:0) */
++#define fExposureStable                                               0x1902          /* (7:0) */
++#define fDarkCalStable                                                0x1904          /* (7:0) */
++#define fStable                                                       0x1906          /* (7:0) */
++#define fForcedStablility                                     0x1908          /* (7:0) */
++
++#define fpRedTilt                                             0x1985          /* (7:0) IndexLo 0x1986 */
++#define fpGreenTilt                                           0x1989          /* (7:0) IndexLo 0x198a */
++#define fpBlueTilt                                            0x198d          /* (7:0) IndexLo 0x198e */
++#define bBlackCorrectionOffset                                        0x1990          /* (7:0) */
++
++#define uwSensorAnalogGainFloor                                       0x1a01          /* (7:0) IndexLo 0x1a02 */
++#define uwSensorAnalogGainCeiling                             0x1a05          /* (7:0) IndexLo 0x1a06 */
++
++#define bFlashMode                                            0x1a80          /* (7:0) */
++#define uwFlashOffLine                                                0x1a83          /* (7:0) IndexLo 0x1a84 */
++
++#define fFlashRecommended                                     0x1b00          /* (7:0) */
++#define fFlashGrabComplete                                    0x1b02          /* (7:0) */
++
++#define uwHorizontalOffset                                    0x1d01          /* (7:0) IndexLo 0x1d02 */
++#define uwVerticalOffset                                      0x1d05          /* (7:0) IndexLo 0x1d06 */
++#define iR2RCoefficient                                               0x1d08          /* (7:0) Signed       */
++#define iR2GRCoefficient                                      0x1d0a          /* (7:0) Signed       */
++#define iR2GBCoefficient                                      0x1d0c          /* (7:0) Signed       */
++#define iR2BCoefficient                                               0x1d0e          /* (7:0) Signed       */
++#define iR4RCoefficient                                               0x1d10          /* (7:0) Signed       */
++#define iR4GRCoefficient                                      0x1d12          /* (7:0) Signed       */
++#define iR4GBCoefficient                                      0x1d14          /* (7:0) Signed       */
++#define iR4BCoefficient                                               0x1d16          /* (7:0) Signed       */
++
++#define ScythefDisableFilter                                  0x1d80          /* (7:0) */
++#define JackfDisableFilter                                    0x1e00          /* (7:0) */
++
++#define bAntiAliasFilterSuppress                              0x1e80          /* (7:0) */
++
++#define ColourMatrixDamperfDisable                            0x1f00          /* (7:0) */
++#define fpLowThreshold                                                0x1f03          /* (7:0) IndexLo 0x1f04 */
++#define fpHighThreshold                                               0x1f07          /* (7:0) IndexLo 0x1f08 */
++#define fpMinimumOutput                                               0x1f0b          /* (7:0) IndexLo 0x1f0c */
++
++#define fpGInR                                                        0x1f81          /* (7:0) IndexLo 0x1f82 */
++#define fpBInR                                                        0x1f85          /* (7:0) IndexLo 0x1f86 */
++#define fpRInG                                                        0x1f89          /* (7:0) IndexLo 0x1f8a */
++#define fpBInG                                                        0x1f8d          /* (7:0) IndexLo 0x1f8e */
++#define fpRInB                                                        0x1f91          /* (7:0) IndexLo 0x1f92 */
++#define fpGInB                                                        0x1f95          /* (7:0) IndexLo 0x1f96 */
++
++#define bUserPeakGain                                         0x2000          /* (7:0) */
++#define fDisableGainDamping                                   0x2002          /* (7:0) */
++#define fpDamperLowThreshold_Gain                             0x2005          /* (7:0) IndexLo 0x2006 */
++#define fpDamperHighThreshold_Gain                            0x2009          /* (7:0) IndexLo 0x200a */
++#define fpMinimumDamperOutput_Gain                            0x200d          /* (7:0) IndexLo 0x200e */
++#define bUserPeakLoThresh                                     0x2010          /* (7:0) */
++#define fDisableCoringDamping                                 0x2012          /* (7:0) */
++#define bUserPeakHiThresh                                     0x2014          /* (7:0) */
++#define fpDamperLowThreshold_Coring                           0x2017          /* (7:0) IndexLo 0x2018 */
++#define fpDamperHighThreshold_Coring                          0x201b          /* (7:0) IndexLo 0x201c */
++#define fpMinimumDamperOutput_Coring                          0x201f          /* (7:0) IndexLo 0x2020 */
++#define bBlockControl                                         0x2022          /* (7:0) */
++
++#define fGammaManuCtrl0                                               0x2280          /* (7:0) */
++#define bRPeakGamma0                                          0x2282          /* (7:0) */
++#define bGPeakGamma0                                          0x2284          /* (7:0) */
++#define bBPeakGamma0                                          0x2286          /* (7:0) */
++#define bRUnPeakGamma0                                                0x2288          /* (7:0) */
++#define bGUnPeakGamma0                                                0x228a          /* (7:0) */
++#define bBUnPeakGamma0                                                0x228c          /* (7:0) */
++
++#define fGammaManuCtrl1                                               0x2300          /* (7:0) */
++#define bRPeakGamma1                                          0x2302          /* (7:0) */
++#define bGPeakGamma1                                          0x2304          /* (7:0) */
++#define bBPeakGamma1                                          0x2306          /* (7:0) */
++#define bRUnPeakGamma1                                                0x2308          /* (7:0) */
++#define bGUnPeakGamma1                                                0x230a          /* (7:0) */
++#define bBUnPeakGamma1                                                0x230c          /* (7:0) */
++
++#define uwLumaExcursion0                                      0x2381          /* (7:0) IndexLo 0x2382 */
++#define uwLumaMidpointTimes20                                 0x2385          /* (7:0) IndexLo 0x2386 */
++#define uwChromaExcursion0                                    0x2389          /* (7:0) IndexLo 0x238a */
++#define uwChromaMidpointTimes20                                       0x238d          /* (7:0) IndexLo 0x238e */
++
++#define uwLumaExcursion1                                      0x2401          /* (7:0) IndexLo 0x2402 */
++#define uwLumaMidpointTimes21                                 0x2405          /* (7:0) IndexLo 0x2406 */
++#define uwChromaExcursion1                                    0x2409          /* (7:0) IndexLo 0x240a */
++#define uwChromaMidpointTimes21                                       0x240d          /* (7:0) IndexLo 0x240e */
++
++#define FadeToBlackfDisable                                   0x2480          /* (7:0) */
++#define fpBlackValue                                          0x2483          /* (7:0) IndexLo 0x2484 */
++#define fpDamperLowThreshold                                  0x2487          /* (7:0) IndexLo 0x2488 */
++#define fpDamperHighThreshold                                 0x248b          /* (7:0) IndexLo 0x248c */
++#define fpDamperOutput                                                0x248f          /* (7:0) IndexLo 0x2490 */
++
++#define bCodeCheckEn                                          0x2580          /* (7:0) */
++#define bBlankFormat                                          0x2582          /* (7:0) */
++#define bSyncCodeSetup                                                0x2584          /* (7:0) */
++#define bHSyncSetup                                           0x2586          /* (7:0) */
++#define bVSyncSetup                                           0x2588          /* (7:0) */
++#define bPClkSetup                                            0x258a          /* (7:0) */
++#define fPclkEn                                                       0x258c          /* (7:0) */
++#define bOpfSpSetup                                           0x258e          /* (7:0) */
++#define bBlankData_MSB                                                0x2590          /* (7:0) */
++#define bBlankData_LSB                                                0x2592          /* (7:0) */
++#define bRgbSetup                                             0x2594          /* (7:0) */
++#define bYuvSetup                                             0x2596          /* (7:0) */
++#define bVsyncRisingCoarseH                                   0x2598          /* (7:0) */
++#define bVsyncRisingCoarseL                                   0x259a          /* (7:0) */
++#define bVsyncRisingFineH                                     0x259c          /* (7:0) */
++#define bVsyncRisingFineL                                     0x259e          /* (7:0) */
++#define bVsyncFallingCoarseH                                  0x25a0          /* (7:0) */
++#define bVsyncFallingCoarseL                                  0x25a2          /* (7:0) */
++#define bVsyncFallingFineH                                    0x25a4          /* (7:0) */
++#define bVsyncFallingFineL                                    0x25a6          /* (7:0) */
++#define bHsyncRisingH                                         0x25a8          /* (7:0) */
++#define bHsyncRisingL                                         0x25aa          /* (7:0) */
++#define bHsyncFallingH                                                0x25ac          /* (7:0) */
++#define bHsyncFallingL                                                0x25ae          /* (7:0) */
++#define bOutputInterface                                      0x25b0          /* (7:0) */
++#define bCCPExtraData                                         0x25b2          /* (7:0) */
++
++#define NoRAfDisable                                          0x2600          /* (7:0) */
++#define bUsage                                                        0x2602          /* (7:0) */
++#define bSplit_Kn                                             0x2604          /* (7:0) */
++#define bSplit_Nl                                             0x2606          /* (7:0) */
++#define bTight_Green                                          0x2608          /* (7:0) */
++#define fDisableNoraPromoting                                 0x260a          /* (7:0) */
++#define DamperLowThreshold                                    0x260d          /* (7:0) IndexLo 0x260e */
++#define DamperHighThreshold                                   0x2611          /* (7:0) IndexLo 0x2612 */
++#define MinimumDamperOutput                                   0x2615          /* (7:0) IndexLo 0x2616 */
++
++
++
++
++#endif                                /* VS6624_H */
++
+--- /dev/null
++++ git/drivers/bmi/pims/factory_test/Makefile
+@@ -0,0 +1,6 @@
++#
++# BMI PIMS - Factory Test Module
++#
++
++obj-$(CONFIG_BUG_FACTORY_TEST)        += factory_test.o
++
+--- /dev/null
++++ git/drivers/bmi/pims/factory_test/factory_test.c
+@@ -0,0 +1,952 @@
++/*
++ *    factory_test.c
++ *
++ *    BIG factory test board device driver
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*
++ * Include files
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/fs.h>
++#include <linux/cdev.h>
++#include <linux/delay.h>
++#include <linux/ioctl.h>
++#include <linux/i2c.h>
++#include <linux/spi/spi.h>
++#include <asm/uaccess.h>
++#include <asm/io.h>
++#include <asm/arch/mxc_i2c.h>
++#include <linux/bmi.h>
++#include <linux/bmi/bmi-control.h>
++#include <asm/arch/mx31bug_cpld.h>
++#include <asm/arch/gpio.h>
++#include <asm/arch/board-bug.h>
++#include <asm/arch/mx31bug_gpio.h>
++#include <asm/arch/mx31bug_cpld.h>
++#include <../arch/arm/mach-mx3/iomux.h>
++
++#define BUG_FACTORY_TEST_VERSION      "1.0"
++#define BUF_MAX_SIZE                  0x20
++#define FT_ERR                                -1
++#define MX31_GPIO_PORT1                       0
++
++static int major;
++      // IOX I2C transfer structure
++struct iox_i2c_xfer {
++    unsigned char addr;
++    unsigned char offset;
++    unsigned char data;
++} iox_i2c_xfer;
++
++      // SPI transfer structure
++struct spi_xfer {
++    unsigned char addr;
++    unsigned char data[2];
++} spi_xfer;
++
++enum sig_bus {
++    MX31,
++    CPLD
++};
++      // MX31 signals
++enum msig {
++    CTS0,
++    RTS0,
++    CTS3,
++    RTS3,
++    CAM,
++    VSYNC1,
++    I2S_RXD0,
++    I2S_RXD1,
++    I2S_RXD2,
++    I2S_RXD3
++};
++
++      // CPLD signals
++enum csig {
++    GPIO0,
++    GPIO1,
++    GPIO2,
++    GPIO3,
++    PRES0,
++    PRES1,
++    PRES2,
++    PRES3,
++    CAM_IF,
++    CAM_LOCK_STATUS,
++    LCD
++};
++
++      // MX31/CPLD signal structure
++struct mc_signal {
++    enum sig_bus bus;
++    unsigned int signal;
++    unsigned char funct;
++    unsigned int value;
++} mc_signal;
++
++      // IOCTL commands for Factory Test Module
++#define FT_READ_IOX   _IOR('f', 0x1, struct iox_i2c_xfer *)   // read IOX
++#define FT_WRITE_IOX  _IOR('f', 0x2, struct iox_i2c_xfer *)   // write IOX
++#define FT_READ_SPI   _IOR('f', 0x3, struct spi_xfer *)       // read SPI
++#define FT_WRITE_SPI  _IOR('f', 0x4, struct spi_xfer *)       // write SPI
++#define FT_SIGNAL     _IOR('f', 0x5, struct mc_signal *)      // MX31/CPLD signals
++
++      // private device structure
++struct bug_ft
++{
++      struct cdev             cdev;                   // character device (4 minor numbers)
++      unsigned int            active;                 // at lease 1 bdev active
++      struct bmi_device       *bdev[4];               // BMI device per slot
++      int                     open_flag[4];           // force single open on each device
++      struct                  spi_device *spi[4];     // SPI device
++      char                    rbuf[BUF_MAX_SIZE];     // SPI read buffer
++      char                    wbuf[BUF_MAX_SIZE];     // SPI write buffer
++};
++
++static struct bug_ft bug_ft;  // global private data
++
++/*
++ *    SPI function
++ */
++
++static int spi_rw(struct spi_device *spi, u8 * buf, size_t len)
++{
++      struct spi_transfer t = {
++              .tx_buf = (const void *)buf,
++              .rx_buf = buf,
++              .len = len,
++              .cs_change = 0,
++              .delay_usecs = 0,
++      };
++      struct spi_message m;
++
++      spi_message_init(&m);
++
++      spi_message_add_tail(&t, &m);
++      if (spi_sync(spi, &m) != 0 || m.status != 0)
++              return FT_ERR;
++
++      return m.actual_length;
++}
++
++/*!
++ * This function allows writing 1 register on a SPI device.
++ *
++ * @param        buf         pointer on the buffer
++ * @param        count       size of the buffer
++ * @return       This function returns the number of written bytes.
++ */
++static ssize_t spi_write_reg(struct bug_ft *priv, char *buf, int slot)
++{
++      int res = 0;
++
++      memset(priv->wbuf, 0, BUF_MAX_SIZE);
++      priv->wbuf[0] = buf[0];
++      priv->wbuf[1] = buf[1];
++      priv->wbuf[2] = buf[2];
++      priv->wbuf[3] = buf[3];
++      if (res > 0) {
++              return -EFAULT;
++      }
++      res = spi_rw(priv->spi[slot], priv->wbuf, 1);
++
++      return res;
++}
++
++/*!
++ * This function allows reading 1 register from a SPI device.
++ *
++ * @param        buf         pointer on the buffer
++ * @param        off         offset in the buffer
++
++ * @return       This function returns the number of read bytes.
++ */
++static ssize_t spi_read_reg(struct bug_ft *priv, char *buf, int slot)
++{
++      spi_write_reg(priv, buf, slot);
++
++      memset(priv->rbuf, 0, BUF_MAX_SIZE);
++      buf[0] = priv->wbuf[3];
++      buf[1] = priv->wbuf[2];
++      buf[2] = priv->wbuf[1];
++      buf[3] = priv->wbuf[0];
++
++      return 4;
++}
++
++/*
++ *    BMI set up
++ */
++
++      // BMI device ID table
++static struct bmi_device_id bug_ft_tbl[] =
++{
++      {
++              .match_flags = BMI_DEVICE_ID_MATCH_VENDOR | BMI_DEVICE_ID_MATCH_PRODUCT,
++              .vendor   = BMI_VENDOR_BUG_LABS,
++              .product  = BMI_PRODUCT_FACTORY_TEST,
++              .revision = BMI_ANY,
++      },
++      { 0, },                                   /* terminate list */
++};
++MODULE_DEVICE_TABLE(bmi, bug_ft_tbl);
++
++int   bug_ft_probe(struct bmi_device *bdev);
++void  bug_ft_remove(struct bmi_device *bdev);
++
++      // BMI driver structure
++static struct bmi_driver bug_ft_driver =
++{
++      .name = "bug_ft_control",
++      .id_table = bug_ft_tbl,
++      .probe   = bug_ft_probe,
++      .remove  = bug_ft_remove,
++};
++
++/*
++ *    I2C set up
++ *
++ *    IOX A on slots 1 & 3
++ *    IOX B on slots 0 & 4
++ */
++
++      // I2C IOX register addresses
++#define IOX0                  (0xE8)  // I2C port A
++#define IOX1                  (0xEA)  // I2C port A
++#define IOX2                  (0xEC)  // I2C port A
++#define IOX3                  (0xEE)  // I2C port A
++#define IOX4                  (0xE8)  // I2C port B
++#define IOX5                  (0xEA)  // I2C port B
++#define IOX6                  (0xEC)  // I2C port B
++#define IOX7                  (0xEE)  // I2C port B
++
++      // I2C IOX register offset addresses
++#define IOX_INPUT0_REG                0x0
++#define IOX_INPUT1_REG                0x1
++#define IOX_OUTPUT0_REG               0x2
++#define IOX_OUTPUT1_REG               0x3
++#define IOX_POLARITY0_REG     0x4
++#define IOX_POLARITY1_REG     0x5
++#define IOX_CONTROL0          0x6
++#define IOX_CONTROL1          0x7
++
++      // read byte from I2C IO expander
++static int ReadByte_IOX(struct i2c_adapter *adap, unsigned char addr,
++      unsigned char offset, unsigned char *data)
++{
++              int     ret = 0;
++              struct i2c_msg rmsg[2];
++              int     num_msgs;
++
++              rmsg[0].addr = addr;
++              rmsg[0].flags = 0; /* write */
++              rmsg[0].len = 1;
++              rmsg[0].buf = &offset;
++
++              rmsg[1].addr = addr;
++              rmsg[1].flags = I2C_M_RD; /* read */
++              rmsg[1].len = 1;
++              rmsg[1].buf = data;
++
++              num_msgs = 2;
++              ret = i2c_transfer (adap, rmsg, num_msgs);
++
++              if (ret == 2) {
++                      ret = 0;
++              }
++              else {
++                      printk (KERN_ERR "ReadByte_IOX() - i2c_transfer() failed.\n");
++                      ret = FT_ERR;
++              }
++              return ret;
++}
++
++      // write byte to I2C IO expander
++static int WriteByte_IOX(struct i2c_adapter *adap, unsigned char addr,
++      unsigned char offset, unsigned char data)
++{
++              int     ret = 0;
++              struct i2c_msg wmsg[2];
++              int     num_msgs;
++
++              wmsg[0].addr = addr;
++              wmsg[0].flags = 0;  /* write */
++              wmsg[0].len = 1;
++              wmsg[0].buf = &offset;
++
++              wmsg[1].addr = addr;
++              wmsg[1].flags = 0;   /* write */
++              wmsg[1].len = 1;
++              wmsg[1].buf = &data;
++
++              num_msgs = 2;
++
++              ret = i2c_transfer (adap, wmsg, num_msgs);
++
++              if (ret == 2) {
++                      ret = 0;
++              }
++              else {
++                      printk (KERN_ERR "WriteByte_IOX() - i2c_transfer() failed.\n");
++                      ret = FT_ERR;
++              }
++              return ret;
++}
++
++/*
++ * control device operations
++ */
++
++// open
++int bug_ft_open(struct inode *inode, struct file *filp)
++{
++      int slot = MINOR(inode->i_rdev);
++
++      if (bug_ft.open_flag[slot]) {
++              return - EBUSY;
++      }
++      bug_ft.open_flag[slot] = 1;
++      filp->private_data = &bug_ft;
++      return 0;
++}
++
++// release
++int bug_ft_release(struct inode *inode, struct file *filp)
++{
++      int slot = MINOR(inode->i_rdev);
++
++      bug_ft.open_flag[slot] = 0;
++      return 0;
++}
++
++/*
++ * ioctl and support functions
++ */
++
++      // do_mx31_sig
++int do_mx31_sig(struct mc_signal * mc_signal)
++{
++      int read_value;
++
++      switch(mc_signal->signal) {
++              case CTS0:      // GPIO2_7
++                      if(mc_signal->funct != 'W') {
++                              printk("do_mx31_sig(): CTS0 is a Write-Only signal\n");
++                              return -1;
++                      }
++                      iomux_config_mux(MX31_PIN_CTS1, OUTPUTCONFIG_GPIO, INPUTCONFIG_GPIO);
++                      mxc_set_gpio_direction(MX31_PIN_CTS1, 0);
++                      mxc_set_gpio_dataout(MX31_PIN_CTS1, mc_signal->value);
++                      break;
++              case RTS0: // GPIO2_6
++                      if(mc_signal->funct != 'R') {
++                              printk("do_mx31_sig(): RTS0 is a Read-Only signal\n");
++                              return -1;
++                      }
++                      mxc_request_iomux(MX31_PIN_RTS1, OUTPUTCONFIG_FUNC, INPUTCONFIG_GPIO);
++                      read_value = mxc_get_gpio_datain(MX31_PIN_RTS1);
++                      mc_signal->value = read_value;
++                      break;
++              case CTS3: // GPIO3_29
++                      if(mc_signal->funct != 'W') {
++                              printk("do_mx31_sig(): CTS3 is a Write-Only signal\n");
++                              return -1;
++                      }
++                      iomux_config_mux(MX31_PIN_ATA_DIOW, OUTPUTCONFIG_GPIO, INPUTCONFIG_GPIO);
++                      mxc_set_gpio_direction(MX31_PIN_ATA_DIOW, 0);
++                      mxc_set_gpio_dataout(MX31_PIN_ATA_DIOW, mc_signal->value);
++                      break;
++              case RTS3: // GPIO3_27
++                      if(mc_signal->funct != 'R') {
++                              printk("do_mx31_sig(): RTS3 is a Read-Only signal\n");
++                              return -1;
++                      }
++                      mxc_request_iomux(MX31_PIN_ATA_CS1, OUTPUTCONFIG_FUNC, INPUTCONFIG_GPIO);
++                      read_value = mxc_get_gpio_datain(MX31_PIN_ATA_CS1);
++                      mc_signal->value = read_value;
++                      break;
++              case CAM: // camera interface -> GPIO
++                      if(mc_signal->funct != 'R') {
++                              printk("do_mx31_sig(): CAM is a Read-Only signal\n");
++                              return -1;
++                      }
++                      mxc_request_iomux(MX31_PIN_CSI_D8, OUTPUTCONFIG_FUNC, INPUTCONFIG_GPIO);
++                      mxc_request_iomux(MX31_PIN_CSI_D9, OUTPUTCONFIG_FUNC, INPUTCONFIG_GPIO);
++                      mxc_request_iomux(MX31_PIN_CSI_D10, OUTPUTCONFIG_FUNC, INPUTCONFIG_GPIO);
++                      mxc_request_iomux(MX31_PIN_CSI_D11, OUTPUTCONFIG_FUNC, INPUTCONFIG_GPIO);
++                      mxc_request_iomux(MX31_PIN_CSI_D12, OUTPUTCONFIG_FUNC, INPUTCONFIG_GPIO);
++                      mxc_request_iomux(MX31_PIN_CSI_D13, OUTPUTCONFIG_FUNC, INPUTCONFIG_GPIO);
++                      mxc_request_iomux(MX31_PIN_CSI_D14, OUTPUTCONFIG_FUNC, INPUTCONFIG_GPIO);
++                      mxc_request_iomux(MX31_PIN_CSI_D15, OUTPUTCONFIG_FUNC, INPUTCONFIG_GPIO);
++                      mxc_request_iomux(MX31_PIN_CSI_HSYNC, OUTPUTCONFIG_FUNC, INPUTCONFIG_GPIO);
++                      mxc_request_iomux(MX31_PIN_CSI_VSYNC, OUTPUTCONFIG_FUNC, INPUTCONFIG_GPIO);
++
++                      mc_signal->value = mxc_get_gpio_datain(MX31_PIN_CSI_HSYNC) << 9;
++                      mc_signal->value |= mxc_get_gpio_datain(MX31_PIN_CSI_VSYNC) << 8;
++                      mc_signal->value |= mxc_get_gpio_datain(MX31_PIN_CSI_D15) << 7;
++                      mc_signal->value |= mxc_get_gpio_datain(MX31_PIN_CSI_D14) << 6;
++                      mc_signal->value |= mxc_get_gpio_datain(MX31_PIN_CSI_D13) << 5;
++                      mc_signal->value |= mxc_get_gpio_datain(MX31_PIN_CSI_D12) << 4;
++                      mc_signal->value |= mxc_get_gpio_datain(MX31_PIN_CSI_D11) << 3;
++                      mc_signal->value |= mxc_get_gpio_datain(MX31_PIN_CSI_D10) << 2;
++                      mc_signal->value |= mxc_get_gpio_datain(MX31_PIN_CSI_D9) << 1;
++                      mc_signal->value |= mxc_get_gpio_datain(MX31_PIN_CSI_D8);
++
++                      mxc_request_iomux(MX31_PIN_CSI_D8, OUTPUTCONFIG_FUNC, INPUTCONFIG_FUNC);
++                      mxc_request_iomux(MX31_PIN_CSI_D9, OUTPUTCONFIG_FUNC, INPUTCONFIG_FUNC);
++                      mxc_request_iomux(MX31_PIN_CSI_D10, OUTPUTCONFIG_FUNC, INPUTCONFIG_FUNC);
++                      mxc_request_iomux(MX31_PIN_CSI_D11, OUTPUTCONFIG_FUNC, INPUTCONFIG_FUNC);
++                      mxc_request_iomux(MX31_PIN_CSI_D12, OUTPUTCONFIG_FUNC, INPUTCONFIG_FUNC);
++                      mxc_request_iomux(MX31_PIN_CSI_D13, OUTPUTCONFIG_FUNC, INPUTCONFIG_FUNC);
++                      mxc_request_iomux(MX31_PIN_CSI_D14, OUTPUTCONFIG_FUNC, INPUTCONFIG_FUNC);
++                      mxc_request_iomux(MX31_PIN_CSI_D15, OUTPUTCONFIG_FUNC, INPUTCONFIG_FUNC);
++                      mxc_request_iomux(MX31_PIN_CSI_HSYNC, OUTPUTCONFIG_FUNC, INPUTCONFIG_FUNC);
++                      mxc_request_iomux(MX31_PIN_CSI_VSYNC, OUTPUTCONFIG_FUNC, INPUTCONFIG_FUNC);
++                      break;
++              case VSYNC1: // read VSYNC1 state
++                      if(mc_signal->funct != 'R') {
++                              printk("do_mx31_sig(): VSYNC1 is a Read-Only signal\n");
++                              return -1;
++                      }
++                      mxc_request_iomux(MX31_PIN_SRST0, OUTPUTCONFIG_GPIO, INPUTCONFIG_GPIO);
++                      mc_signal->value = mxc_get_gpio_datain(MX31_PIN_SRST0);
++                      mxc_request_iomux(MX31_PIN_SRST0, OUTPUTCONFIG_FUNC, INPUTCONFIG_ALT2);
++                      break;
++              case I2S_RXD0: // GPIO1_20
++              case I2S_RXD2:
++                      if(mc_signal->funct != 'R') {
++                              printk("do_mx31_sig(): I2S_RXD[02] are Read-Only signals\n");
++                              return -1;
++                      }
++                      mxc_request_iomux(MX31_PIN_SRXD4, OUTPUTCONFIG_FUNC, INPUTCONFIG_GPIO);
++                      read_value = mxc_get_gpio_datain(MX31_PIN_SRXD4);
++                      mc_signal->value = read_value;
++                      break;
++              case I2S_RXD1: // GPIO1_22
++              case I2S_RXD3:
++                      if(mc_signal->funct != 'R') {
++                              printk("do_mx31_sig(): I2S_RXD[13] are Read-Only signals\n");
++                              return -1;
++                      }
++                      mxc_request_iomux(MX31_PIN_SRXD5, OUTPUTCONFIG_FUNC, INPUTCONFIG_GPIO);
++                      read_value = mxc_get_gpio_datain(MX31_PIN_SRXD5);
++                      mc_signal->value = read_value;
++                      break;
++              default:
++                      printk("do_mx31_sig(): unknown signal\n");
++                      return -1;
++      }
++      return 0;
++}
++
++      // do_cpld_sig
++int do_cpld_sig(struct mc_signal * mc_signal)
++{
++      int read_value;
++
++      switch(mc_signal->signal) {
++              case GPIO0:
++                      if(mc_signal->funct == 'R') {
++                                      // set GPIO to input
++                              cpld_set_module_gpio_dir(CPLD_M1, 0, CPLD_GPIO_IN);
++                              cpld_set_module_gpio_dir(CPLD_M1, 1, CPLD_GPIO_IN);
++                              cpld_set_module_gpio_dir(CPLD_M1, 2, CPLD_GPIO_IN);
++                              cpld_set_module_gpio_dir(CPLD_M1, 3, CPLD_GPIO_IN);
++                                      // read GPIO
++                              read_value = cpld_read_gpio_data_reg(CPLD_M1);
++                                      // read interrupt
++                              read_value |= cpld_interrupt_status(INT_M1_INT) << 4;
++                              mc_signal->value = read_value;
++                      } else if(mc_signal->funct == 'H') {
++                                      // write GPIO
++                              cpld_set_module_gpio_data(CPLD_M1, 0, mc_signal->value & 0x1);
++                              cpld_set_module_gpio_data(CPLD_M1, 1, (mc_signal->value & 0x2) >> 1);
++                              cpld_set_module_gpio_data(CPLD_M1, 2, (mc_signal->value & 0x4) >> 2);
++                              cpld_set_module_gpio_data(CPLD_M1, 3, (mc_signal->value & 0x8) >> 3);
++                                      // set GPIO to output
++                              cpld_set_module_gpio_dir(CPLD_M1, 0, CPLD_GPIO_OUT);
++                              cpld_set_module_gpio_dir(CPLD_M1, 1, CPLD_GPIO_OUT);
++                              cpld_set_module_gpio_dir(CPLD_M1, 2, CPLD_GPIO_OUT);
++                              cpld_set_module_gpio_dir(CPLD_M1, 3, CPLD_GPIO_OUT);
++                      } else {
++                              printk("do_cpld_sig(): Illegal function for CPLD GPIO\n");
++                              return -1;
++                      }
++                      break;
++              case GPIO1:
++                      if(mc_signal->funct == 'R') {
++                                      // set GPIO to input
++                              cpld_set_module_gpio_dir(CPLD_M2, 0, CPLD_GPIO_IN);
++                              cpld_set_module_gpio_dir(CPLD_M2, 1, CPLD_GPIO_IN);
++                              cpld_set_module_gpio_dir(CPLD_M2, 2, CPLD_GPIO_IN);
++                              cpld_set_module_gpio_dir(CPLD_M2, 3, CPLD_GPIO_IN);
++                                      // read GPIO
++                              read_value = cpld_read_gpio_data_reg(CPLD_M2);
++                                      // read interrupt
++                              read_value |= cpld_interrupt_status(INT_M2_INT) << 4;
++                              mc_signal->value = read_value;
++                      } else if(mc_signal->funct == 'H') {
++                                      // write GPIO
++                              cpld_set_module_gpio_data(CPLD_M2, 0, mc_signal->value & 0x1);
++                              cpld_set_module_gpio_data(CPLD_M2, 1, (mc_signal->value & 0x2) >> 1);
++                              cpld_set_module_gpio_data(CPLD_M2, 2, (mc_signal->value & 0x4) >> 2);
++                              cpld_set_module_gpio_data(CPLD_M2, 3, (mc_signal->value & 0x8) >> 3);
++                                      // set GPIO to output
++                              cpld_set_module_gpio_dir(CPLD_M2, 0, CPLD_GPIO_OUT);
++                              cpld_set_module_gpio_dir(CPLD_M2, 1, CPLD_GPIO_OUT);
++                              cpld_set_module_gpio_dir(CPLD_M2, 2, CPLD_GPIO_OUT);
++                              cpld_set_module_gpio_dir(CPLD_M2, 3, CPLD_GPIO_OUT);
++                      } else {
++                              printk("do_cpld_sig(): Illegal function for CPLD GPIO\n");
++                              return -1;
++                      }
++                      break;
++              case GPIO2:
++                      if(mc_signal->funct == 'R') {
++                                      // set GPIO to input
++                              cpld_set_module_gpio_dir(CPLD_M3, 0, CPLD_GPIO_IN);
++                              cpld_set_module_gpio_dir(CPLD_M3, 1, CPLD_GPIO_IN);
++                              cpld_set_module_gpio_dir(CPLD_M3, 2, CPLD_GPIO_IN);
++                              cpld_set_module_gpio_dir(CPLD_M3, 3, CPLD_GPIO_IN);
++                                      // read GPIO
++                              read_value = cpld_read_gpio_data_reg(CPLD_M3);
++                                      // read interrupt
++                              read_value |= cpld_interrupt_status(INT_M3_INT) << 4;
++                              mc_signal->value = read_value;
++                      } else if(mc_signal->funct == 'H') {
++                                      // write GPIO
++                              cpld_set_module_gpio_data(CPLD_M3, 0, mc_signal->value & 0x1);
++                              cpld_set_module_gpio_data(CPLD_M3, 1, (mc_signal->value & 0x2) >> 1);
++                              cpld_set_module_gpio_data(CPLD_M3, 2, (mc_signal->value & 0x4) >> 2);
++                              cpld_set_module_gpio_data(CPLD_M3, 3, (mc_signal->value & 0x8) >> 3);
++                                      // set GPIO to output
++                              cpld_set_module_gpio_dir(CPLD_M3, 0, CPLD_GPIO_OUT);
++                              cpld_set_module_gpio_dir(CPLD_M3, 1, CPLD_GPIO_OUT);
++                              cpld_set_module_gpio_dir(CPLD_M3, 2, CPLD_GPIO_OUT);
++                              cpld_set_module_gpio_dir(CPLD_M3, 3, CPLD_GPIO_OUT);
++                      } else {
++                              printk("do_cpld_sig(): Illegal function for CPLD GPIO\n");
++                              return -1;
++                      }
++                      break;
++              case GPIO3:
++                      if(mc_signal->funct == 'R') {
++                                      // set GPIO to input
++                              cpld_set_module_gpio_dir(CPLD_M4, 0, CPLD_GPIO_IN);
++                              cpld_set_module_gpio_dir(CPLD_M4, 1, CPLD_GPIO_IN);
++                              cpld_set_module_gpio_dir(CPLD_M4, 2, CPLD_GPIO_IN);
++                              cpld_set_module_gpio_dir(CPLD_M4, 3, CPLD_GPIO_IN);
++                                      // read GPIO
++                              read_value = cpld_read_gpio_data_reg(CPLD_M4);
++                                      // read interrupt
++                              read_value |= cpld_interrupt_status(INT_M4_INT) << 4;
++                              mc_signal->value = read_value;
++                      } else if(mc_signal->funct == 'H') {
++                                      // write GPIO
++                              cpld_set_module_gpio_data(CPLD_M4, 0, mc_signal->value & 0x1);
++                              cpld_set_module_gpio_data(CPLD_M4, 1, (mc_signal->value & 0x2) >> 1);
++                              cpld_set_module_gpio_data(CPLD_M4, 2, (mc_signal->value & 0x4) >> 2);
++                              cpld_set_module_gpio_data(CPLD_M4, 3, (mc_signal->value & 0x8) >> 3);
++                                      // set GPIO to output
++                              cpld_set_module_gpio_dir(CPLD_M4, 0, CPLD_GPIO_OUT);
++                              cpld_set_module_gpio_dir(CPLD_M4, 1, CPLD_GPIO_OUT);
++                              cpld_set_module_gpio_dir(CPLD_M4, 2, CPLD_GPIO_OUT);
++                              cpld_set_module_gpio_dir(CPLD_M4, 3, CPLD_GPIO_OUT);
++                      } else {
++                              return -1;
++                      }
++                      break;
++              case PRES0:
++                      if(mc_signal->funct != 'R') {
++                              printk("do_cpld_sig(): Illegal function for CPLD PRES signal\n");
++                              return -1;
++                      }
++                      read_value = (cpld_read_module_present_status(CPLD_M1) >> 2) & 0x1;
++                      mc_signal->value = read_value;
++                      break;
++              case PRES1:
++                      if(mc_signal->funct != 'R') {
++                              printk("do_cpld_sig(): Illegal function for CPLD PRES signal\n");
++                              return -1;
++                      }
++                      read_value = (cpld_read_module_present_status(CPLD_M2) >> 2) & 0x1;
++                      mc_signal->value = read_value;
++                      break;
++              case PRES2:
++                      if(mc_signal->funct != 'R') {
++                              printk("do_cpld_sig(): Illegal function for CPLD PRES signal\n");
++                              return -1;
++                      }
++                      read_value = (cpld_read_module_present_status(CPLD_M3) >> 2) & 0x1;
++                      mc_signal->value = read_value;
++                      break;
++              case PRES3:
++                      if(mc_signal->funct != 'R') {
++                              printk("do_cpld_sig(): Illegal function for CPLD PRES signal\n");
++                              return -1;
++                      }
++                      read_value = (cpld_read_module_present_status(CPLD_M4) >> 2) & 0x1;
++                      mc_signal->value = read_value;
++                      break;
++              case CAM_IF:
++                      if(mc_signal->funct != 'W') {
++                              printk("do_cpld_sig(): Illegal function for CPLD CAM_IF signal\n");
++                              return -1;
++                      }
++                      cpld_sensor_active(CAM_CLK_RISE);
++                      break;
++              case CAM_LOCK_STATUS:
++                      if(mc_signal->funct != 'R') {
++                              printk("do_cpld_sig(): Illegal function for CPLD CAM_LOCK_STATUS signal\n");
++                              return -1;
++                      }
++                      read_value = (int) __raw_readw(CPLD_BASE_ADDRESS+CPLD_CAM);
++                      read_value = cpld_sensor_lock_status();
++                      mc_signal->value = read_value;
++                      break;
++              case LCD:
++                      if(mc_signal->funct != 'W') {
++                              printk("do_cpld_sig(): Illegal function for CPLD LCD signal\n");
++                              return -1;
++                      }
++                      cpld_lcd_inactive(0);
++                      cpld_lcd_inactive(1);
++                      cpld_lcd_active(0, 0, LCD_MODE_I80);
++                      cpld_lcd_active(1, 0, LCD_MODE_I80);
++                      break;
++              default:
++                      printk("do_cpld_sig(): unknown signal\n");
++                      return -1;
++      }
++      return 0;
++}
++
++      // ioctl
++int bug_ft_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
++                 unsigned long arg)
++{
++      int slot = MINOR(inode->i_rdev);
++      struct bug_ft *bug_ft = (struct bug_ft *) filp->private_data;
++      struct i2c_adapter *adap = &bug_ft->bdev[slot]->adap;
++      unsigned char iox_data[1];
++      struct iox_i2c_xfer iox_i2c_xfer;
++      struct spi_xfer spi_xfer;
++      struct mc_signal mc_signal;
++      u8 buf[4];
++      int ret = 0;
++
++              // error if no ft active.
++      if(bug_ft->active == -1)
++              return -ENODEV;
++
++              // error if no BMI device
++      if(bug_ft->bdev[slot] == 0)
++              return -ENODEV;
++
++              // get I2C transfer structure
++      if((cmd == FT_READ_IOX) || (cmd == FT_WRITE_IOX))
++              if(copy_from_user(&iox_i2c_xfer, (struct iox_i2c_xfer *) arg, sizeof(struct iox_i2c_xfer))) {
++                      printk(KERN_INFO "factory_test ioctl(%d): copy_from_user #1 = %d\n", slot, ret);
++                      return -EFAULT;
++              }
++
++              // get SPI transfer structure
++      if((cmd == FT_READ_SPI) || (cmd == FT_WRITE_SPI))
++              if(copy_from_user(&spi_xfer, (struct spi_xfer *) arg, sizeof(struct spi_xfer))) {
++                      printk(KERN_INFO "factory_test ioctl(%d): copy_from_user #1 = %d\n", slot, ret);
++                      return -EFAULT;
++              }
++
++              // get signal structure
++      if(cmd == FT_SIGNAL)
++              if(copy_from_user(&mc_signal, (struct mc_signal *) arg, sizeof(struct mc_signal))) {
++                      printk(KERN_INFO "factory_test ioctl(%d): copy_from_user #1 = %d\n", slot, ret);
++                      return -EFAULT;
++              }
++
++              // ioctl's
++      switch (cmd) {
++                      // read IOX
++              case FT_READ_IOX:
++                      ret = ReadByte_IOX(adap, iox_i2c_xfer.addr, iox_i2c_xfer.offset, iox_data);
++                      if(ret == 0) {
++                              iox_i2c_xfer.data = *iox_data;
++                              if(copy_to_user((struct iox_i2c_xfer *) arg, &iox_i2c_xfer, sizeof(struct iox_i2c_xfer)))
++                                      ret = -EFAULT;
++                      }
++                      break;
++                      // write IOX
++              case FT_WRITE_IOX:
++                      *iox_data = iox_i2c_xfer.data;
++                      ret = WriteByte_IOX(adap, iox_i2c_xfer.addr, iox_i2c_xfer.offset, *iox_data);
++                      if(ret == 0) {
++                              if(copy_to_user((struct iox_i2c_xfer *) arg, &iox_i2c_xfer, sizeof(struct iox_i2c_xfer))) {
++                                      ret = -EFAULT;
++                              }
++                      }
++                      break;
++                      // read SPI
++              case FT_READ_SPI:
++                              // READ
++                      buf[3] = 0xC0 | ((spi_xfer.addr & 0x3F) >> 1);
++                      buf[2] = 0x00 | ((spi_xfer.addr & 0x1) << 7);
++                      buf[1] = 0x00;
++                      buf[0] = 0x00;
++                      ret = spi_read_reg(bug_ft, buf, slot);
++                      if(ret == 4) {
++                              spi_xfer.data[1] = ((buf[2] & 0x7F) << 1) | ((buf[1] & 0x80) >> 7);
++                              spi_xfer.data[0] = ((buf[1] & 0x7F) << 1) | ((buf[0] & 0x80) >> 7);
++                              if(copy_to_user((struct spi_xfer *) arg, &spi_xfer, sizeof(struct spi_xfer)))
++                                      ret = -EFAULT;
++                              else
++                                      ret = 0;
++                      } else
++                              ret = FT_ERR;
++                      break;
++                      // write SPI
++              case FT_WRITE_SPI:
++                              // EWEN
++                      buf[3] = 0x98;
++                      buf[2] = 0x00;
++                      buf[1] = 0x00;
++                      buf[0] = 0x00;
++                      ret = spi_write_reg(bug_ft, buf, slot);
++                      if(ret != 1) {
++                          ret = FT_ERR;
++                          break;
++                      }
++                              // WRITE
++                      buf[3] = 0xA0 | ((spi_xfer.addr & 0x3F) >> 1);
++                      buf[2] = 0x00 | ((spi_xfer.addr & 0x1) << 7) | (spi_xfer.data[1] >> 1);
++                      buf[1] = ((spi_xfer.data[1] & 0x1) << 7) | (spi_xfer.data[0] >> 1);
++                      buf[0] = spi_xfer.data[0] << 0x7;
++                      ret = spi_write_reg(bug_ft, buf, slot);
++                      if(ret == 1) {
++                              if(copy_to_user((struct spi_xfer *) arg, &spi_xfer, sizeof(struct spi_xfer)))
++                                      ret = -EFAULT;
++                              else
++                                      ret = 0;
++                      } else
++                              ret = FT_ERR;
++
++                      break;
++              case FT_SIGNAL:
++                      if(mc_signal.bus == MX31) {
++                              ret = do_mx31_sig(&mc_signal);
++                              if((mc_signal.funct == 'R') && (ret == 0)) {
++                                      if(copy_to_user((struct mc_signal *) arg, &mc_signal, sizeof(struct mc_signal))) {
++                                              ret = -EFAULT;
++                                      } else {
++                                              ret = 0;
++                                      }
++                              }
++                       } else if(mc_signal.bus == CPLD) {
++                              ret = do_cpld_sig(&mc_signal);
++                              if((mc_signal.funct == 'R') && (ret == 0)) {
++                                      if(copy_to_user((struct mc_signal *) arg, &mc_signal, sizeof(struct mc_signal))) {
++                                              ret = -EFAULT;
++                                      } else {
++                                              ret = 0;
++                                      }
++                              }
++                      } else {
++                              ret = FT_ERR;
++                      }
++                      break;
++              default:
++                      return -ENOTTY;
++      }
++
++      return ret;
++}
++
++/*
++ *    BMI functions
++ */
++
++static const struct file_operations bug_ft_fops = {
++      .owner          = THIS_MODULE,
++      .ioctl          = bug_ft_ioctl,
++      .open           = bug_ft_open,
++      .release        = bug_ft_release,
++};
++
++int bug_ft_probe(struct bmi_device *bdev)
++{
++      int slot = bdev->info->slot;
++      struct cdev *cdev_ptr;
++      dev_t dev_id;
++      int ret;
++      unsigned long speed = 1000000;
++      unsigned char mode = SPI_MODE_2 | SPI_CS_HIGH;
++      unsigned char bits_per_word = 32;
++
++
++      printk(KERN_INFO "factory_test.c: probe slot %d\n", slot);
++
++      cdev_ptr = &bug_ft.cdev;
++      cdev_init(cdev_ptr, &bug_ft_fops);
++
++      dev_id = MKDEV(major, bdev->info->slot);
++      ret = cdev_add(cdev_ptr, dev_id, 1);
++      if(ret)
++          return ret;
++
++      switch(slot) {
++              case 0:
++                      cpld_set_module_gpio_dir(CPLD_M1, 0, CPLD_GPIO_IN);
++                      cpld_set_module_gpio_dir(CPLD_M1, 1, CPLD_GPIO_IN);
++                      cpld_set_module_gpio_dir(CPLD_M1, 2, CPLD_GPIO_IN);
++                      cpld_set_module_gpio_dir(CPLD_M1, 3, CPLD_GPIO_IN);
++                      ret = bmi_device_spi_setup(bdev, speed, mode, bits_per_word);
++                      if (ret) {
++                              printk (KERN_ERR "bug_ft_probe() - bmi_device_spi_setup(0) failed.\n");
++                              return ret;
++                      }
++                      bug_ft.spi[0] = &bdev->spi;
++                      break;
++              case 1:
++                      cpld_set_module_gpio_dir(CPLD_M2, 0, CPLD_GPIO_IN);
++                      cpld_set_module_gpio_dir(CPLD_M2, 1, CPLD_GPIO_IN);
++                      cpld_set_module_gpio_dir(CPLD_M2, 2, CPLD_GPIO_IN);
++                      cpld_set_module_gpio_dir(CPLD_M2, 3, CPLD_GPIO_IN);
++                      ret = bmi_device_spi_setup(bdev, speed, mode, bits_per_word);
++                      if (ret) {
++                              printk (KERN_ERR "bug_ft_probe() - bmi_device_spi_setup(2) failed.\n");
++                              return ret;
++                      }
++                      bug_ft.spi[1] = &bdev->spi;
++                      break;
++              case 2:
++                      cpld_set_module_gpio_dir(CPLD_M3, 0, CPLD_GPIO_IN);
++                      cpld_set_module_gpio_dir(CPLD_M3, 1, CPLD_GPIO_IN);
++                      cpld_set_module_gpio_dir(CPLD_M3, 2, CPLD_GPIO_IN);
++                      cpld_set_module_gpio_dir(CPLD_M3, 3, CPLD_GPIO_IN);
++                      ret = bmi_device_spi_setup(bdev, speed, mode, bits_per_word);
++                      if (ret) {
++                              printk (KERN_ERR "bug_ft_probe() - bmi_device_spi_setup(3) failed.\n");
++                              return ret;
++                      }
++                      bug_ft.spi[2] = &bdev->spi;
++                      break;
++              case 3:
++                      cpld_set_module_gpio_dir(CPLD_M4, 0, CPLD_GPIO_IN);
++                      cpld_set_module_gpio_dir(CPLD_M4, 1, CPLD_GPIO_IN);
++                      cpld_set_module_gpio_dir(CPLD_M4, 2, CPLD_GPIO_IN);
++                      cpld_set_module_gpio_dir(CPLD_M4, 3, CPLD_GPIO_IN);
++                      ret = bmi_device_spi_setup(bdev, speed, mode, bits_per_word);
++                      if (ret) {
++                              printk (KERN_ERR "bug_ft_probe() - bmi_device_spi_setup(3) failed.\n");
++                              return ret;
++                      }
++                      bug_ft.spi[3] = &bdev->spi;
++                      break;
++      }
++      if(ret) {
++              cdev_del(cdev_ptr);
++              return ret;
++      }
++
++      bmi_device_set_drvdata(bdev, &bug_ft);
++
++      bug_ft.bdev[slot] = bdev;
++
++      bug_ft.active = 1;
++
++      return 0;
++}
++
++void bug_ft_remove(struct bmi_device *bdev)
++{
++      struct bug_ft *bug_ft = (struct bug_ft*)(bmi_device_get_drvdata (bdev));
++      int slot = bdev->info->slot;
++      struct cdev *cdev_ptr;
++      dev_t dev_id;
++
++      switch(slot) {
++              case 0:
++                      bmi_device_spi_cleanup(bdev);
++                      break;
++              case 1:
++                      bmi_device_spi_cleanup(bdev);
++                      break;
++              case 2:
++                      bmi_device_spi_cleanup(bdev);
++                      break;
++              case 3:
++                      bmi_device_spi_cleanup(bdev);
++                      break;
++      }
++
++      bug_ft->bdev[slot] = 0;
++
++              //de-attach driver-specific struct from bmi_device structure
++      bmi_device_set_drvdata(&bdev[slot], 0);
++
++      if((bug_ft->bdev[0]==0) && (bug_ft->bdev[1]==0) &&
++              (bug_ft->bdev[2]==0) && (bug_ft->bdev[3]==0)) {
++              bug_ft->active = -1;
++              cdev_ptr = &bug_ft->cdev;
++              dev_id = MKDEV(major, bdev->info->slot);
++              cdev_del(cdev_ptr);
++      }
++
++      return;
++}
++
++/*
++ *    Module functions
++ */
++
++static __init int bug_ft_init(void)
++{
++      dev_t   dev_id;
++      int     retval;
++
++              // No ft is active.
++      bug_ft.active = -1;
++
++              // alloc char driver with 4 minor numbers
++      retval = alloc_chrdev_region(&dev_id, 0, 4, "BUG Factory Test Driver");
++      if (retval) {
++              return -1;
++      }
++
++      major = MAJOR(dev_id);
++
++      printk("factory_test.c: BUG FACTORY TEST Driver v%s (major = %d)\n", BUG_FACTORY_TEST_VERSION, major);
++
++      return  bmi_register_driver(&bug_ft_driver);
++}
++
++static void __exit bug_ft_clean(void)
++{
++      dev_t dev_id = MKDEV(major, 0);
++
++      unregister_chrdev_region(dev_id, 4);
++      bmi_unregister_driver(&bug_ft_driver);
++
++      return;
++}
++
++module_init(bug_ft_init);
++module_exit(bug_ft_clean);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Peter Giacomini <p.giacomini@encadis.com>");
++MODULE_DESCRIPTION("BUG Factory Test board device driver");
++MODULE_SUPPORTED_DEVICE("bug_ft_control");
++
+--- /dev/null
++++ git/drivers/bmi/pims/gps/Makefile
+@@ -0,0 +1,6 @@
++#
++# BMI PIMS
++#
++
++obj-$(CONFIG_BMI_GPS)         += bmi_gps.o
++
+--- /dev/null
++++ git/drivers/bmi/pims/gps/bmi_gps.c
+@@ -0,0 +1,468 @@
++/*
++ *    bmi_gps.c
++ *
++ *    BMI gps device driver
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*
++ * Include files
++ */
++
++
++//REWORK: Which are not needed ?
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/fs.h>
++#include <linux/delay.h>
++#include <linux/i2c.h>
++#include <asm/uaccess.h>
++//#include <mach/mxc_i2c.h>
++#include <linux/bmi.h>
++//#include <linux/bmi/bmi-control.h>
++#include <linux/bmi/bmi_gps.h>
++//#include <mach/mx31bug_cpld.h>
++
++//MTW
++#include <linux/cdev.h>
++
++
++#define BMIGPS_VERSION        "1.1"
++
++
++// private device structure
++struct bmi_gps
++{
++      struct bmi_device   *bdev;      // BMI device
++      struct cdev          cdev;
++      struct device *class_dev;
++      int                  open_flag; // single open flag
++  struct i2c_client *iox;
++};
++
++static struct bmi_gps bmi_gps[4];
++static int major;
++
++/*
++ *    BMI set up
++ */
++
++      // BMI device ID table
++static struct bmi_device_id bmi_gps_tbl[] =
++{
++      {
++              .match_flags = BMI_DEVICE_ID_MATCH_VENDOR | BMI_DEVICE_ID_MATCH_PRODUCT,
++              .vendor   = BMI_VENDOR_BUG_LABS,
++              .product  = BMI_PRODUCT_GPS_J32,
++              .revision = BMI_ANY,
++      },
++      { 0, },                                   /* terminate list */
++};
++MODULE_DEVICE_TABLE(bmi, bmi_gps_tbl);
++
++int   bmi_gps_probe(struct bmi_device *bdev);
++void  bmi_gps_remove(struct bmi_device *bdev);
++
++// BMI driver structure
++static struct bmi_driver bmi_gps_driver =
++{
++      .name = "bmi_gps",
++      .id_table = bmi_gps_tbl,
++      .probe   = bmi_gps_probe,
++      .remove  = bmi_gps_remove,
++};
++
++/*
++ *    I2C set up
++ */
++
++// I2C Slave Address
++#define BMI_IOX_I2C_ADDRESS   0x71    // 7-bit address
++
++// I2C IOX register addresses
++#define IOX_INPUT_REG         0x0
++#define IOX_OUTPUT_REG                0x1
++#define IOX_POLARITY_REG      0x2
++#define IOX_CONTROL           0x3
++
++static struct i2c_board_info iox_info = {
++  I2C_BOARD_INFO("VH_IOX", BMI_IOX_I2C_ADDRESS),
++};
++
++// read byte from I2C IO expander
++
++static int ReadByte_IOX (struct i2c_client *client, unsigned char offset, unsigned char *data)
++{
++      int     ret = 0;
++
++      ret = i2c_master_send(client, &offset, 1);
++      if (ret == 1)
++        ret = i2c_master_recv(client, data, 1);
++      if (ret < 0)
++        printk (KERN_ERR "ReadByte_IOX() - i2c_transfer() failed...%d\n",ret);
++      return ret;
++}
++
++// write byte to I2C IO expander
++static int WriteByte_IOX (struct i2c_client *client, unsigned char offset, unsigned char data)
++{
++      int     ret = 0;
++      unsigned char msg[2];
++
++      msg[0] = offset;
++      msg[1] = data;
++      ret = i2c_master_send(client, msg, sizeof(msg));
++
++      if (ret < 0)
++        printk (KERN_ERR "WriteByte_IOX() - i2c_transfer() failed...%d\n",ret);
++
++      return ret;
++}
++
++
++
++/*
++ * control device operations
++ */
++
++// open
++int cntl_open(struct inode *inode, struct file *file)
++{
++      struct bmi_gps *gps;
++
++      gps = container_of(inode->i_cdev, struct bmi_gps, cdev);
++
++      // Enforce single-open behavior
++
++      if (gps->open_flag) {
++              return -EBUSY;
++      }
++      gps->open_flag = 1;
++
++      // Save gps_dev pointer for later.
++
++      file->private_data = gps;
++      return 0;
++
++}
++
++// release
++int cntl_release(struct inode *inode, struct file *file)
++{
++      struct bmi_gps *gps;
++
++      gps = (struct bmi_gps *)(file->private_data);
++      gps->open_flag = 0;
++      return 0;
++}
++
++// ioctl
++int cntl_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
++                 unsigned long arg)
++{
++      struct i2c_adapter *adap;
++      unsigned char iox_data;
++
++      unsigned char gpio_mask;
++      struct bmi_gps *gps;
++      int slot;
++
++      gps = (struct bmi_gps *)(file->private_data);
++
++      // error if gps not present
++      if(gps->bdev == 0)
++              return -ENODEV;
++
++      slot = gps->bdev->slot->slotnum;
++      adap = gps->bdev->slot->adap;
++
++              // ioctl's
++      gpio_mask = bmi_slot_gpio_get(slot);
++      switch (cmd) {
++      case BMI_GPS_RLEDOFF:
++        bmi_slot_gpio_set (slot, (gpio_mask | RED_LED)); // Red LED=OFF
++              break;
++
++      case BMI_GPS_RLEDON:
++        bmi_slot_gpio_set (slot, (gpio_mask & ~RED_LED)); // Red LED=ON
++              break;
++
++      case BMI_GPS_GLEDOFF:
++              bmi_slot_gpio_set (slot, (gpio_mask | GREEN_LED)); // Greem LED=OFF
++              break;
++
++      case BMI_GPS_GLEDON:
++              bmi_slot_gpio_set (slot, (gpio_mask & ~GREEN_LED)); // Greem LED=ON
++              break;
++
++      case BMI_GPS_SETBOOT:
++              if(ReadByte_IOX (gps->iox, IOX_OUTPUT_REG, &iox_data))
++                      return -ENODEV;
++              iox_data |= 0x08;
++              if(WriteByte_IOX (gps->iox, IOX_OUTPUT_REG, iox_data))
++                      return -ENODEV;
++              if(ReadByte_IOX (gps->iox, IOX_CONTROL, &iox_data))     // IOX[3]=BOOT=0, IOX[4]=WAKEUP=0
++                      return -ENODEV;
++              iox_data |= 0x08;
++              if(WriteByte_IOX (gps->iox, IOX_CONTROL, iox_data))     // IOX[3]=BOOT=0, IOX[4]=WAKEUP=0
++                      return -ENODEV;
++              break;
++
++      case BMI_GPS_CLRBOOT:
++              if(ReadByte_IOX (gps->iox, IOX_OUTPUT_REG, &iox_data))
++                      return -ENODEV;
++              iox_data &= ~0x08;
++              if(WriteByte_IOX (gps->iox, IOX_OUTPUT_REG, iox_data))
++                      return -ENODEV;
++              break;
++
++      case BMI_GPS_SETWAKE:
++              if(ReadByte_IOX (gps->iox, IOX_OUTPUT_REG, &iox_data))
++                      return -ENODEV;
++              iox_data |= 0x10;
++              if(WriteByte_IOX (gps->iox, IOX_OUTPUT_REG, iox_data))
++                      return -ENODEV;
++              if(ReadByte_IOX (gps->iox, IOX_CONTROL, &iox_data))     // IOX[3]=BOOT=0, IOX[4]=WAKEUP=0
++                      return -ENODEV;
++              iox_data |= 0x10;
++              if(WriteByte_IOX (gps->iox, IOX_CONTROL, iox_data))     // IOX[3]=BOOT=0, IOX[4]=WAKEUP=0
++                              return -ENODEV;
++                      break;
++
++      case BMI_GPS_CLRWAKE:
++              if(ReadByte_IOX (gps->iox, IOX_OUTPUT_REG, &iox_data))
++                      return -ENODEV;
++              iox_data &= ~0x10;
++              if(WriteByte_IOX (gps->iox, IOX_OUTPUT_REG, iox_data))
++                      return -ENODEV;
++              break;
++
++      case BMI_GPS_SETRST:
++              bmi_slot_gpio_set (slot, (gpio_mask & ~GPIO_1)); // RST = 0;
++
++              break;
++
++      case BMI_GPS_CLRRST:
++              bmi_slot_gpio_set (slot, (gpio_mask | GPIO_1)); // RST=tristate
++              break;
++
++      case BMI_GPS_GETSTAT:
++              {
++              int read_data;
++
++              if(ReadByte_IOX (gps->iox, IOX_INPUT_REG, &iox_data))
++                      return -ENODEV;
++
++              read_data = iox_data | (bmi_slot_gpio_get(slot) << 8);
++
++              if(put_user(read_data, (int __user *) arg))
++                      return -EFAULT;
++              }
++              break;
++
++      case BMI_GPS_ACTIVE_ANT :
++              if(ReadByte_IOX (gps->iox, IOX_OUTPUT_REG, &iox_data))
++                      return -ENODEV;
++              iox_data &= ~0x40;
++              iox_data |=  0x80;
++              if(WriteByte_IOX (gps->iox, IOX_OUTPUT_REG, iox_data))
++                      return -ENODEV;
++              break;
++
++      case BMI_GPS_PASSIVE_ANT:
++              if(ReadByte_IOX (gps->iox, IOX_OUTPUT_REG, &iox_data))
++                      return -ENODEV;
++              iox_data &= ~0x80;
++              iox_data |=  0x40;
++              if(WriteByte_IOX (gps->iox, IOX_OUTPUT_REG, iox_data))
++                      return -ENODEV;
++              break;
++
++      default:
++              return -ENOTTY;
++      }
++
++      return 0;
++}
++
++// control file operations
++struct file_operations cntl_fops = {
++      .owner = THIS_MODULE,
++      .ioctl = cntl_ioctl,
++      .open = cntl_open,
++      .release = cntl_release,
++};
++
++/*
++ *    Module functions
++ */
++
++/*
++ *    BMI functions
++ */
++
++int bmi_gps_probe(struct bmi_device *bdev)
++{
++      int err;
++      int slot;
++      struct bmi_gps *gps;
++      struct i2c_adapter *adap;
++      struct cdev *cdev;
++      struct class *bmi_class;
++      dev_t dev_id;
++
++      err = 0;
++      slot = bdev->slot->slotnum;
++      adap = bdev->slot->adap;
++      gps = &bmi_gps[slot];
++
++
++      gps->bdev = 0;
++      gps->open_flag = 0;
++
++      //Create 1 minor device
++      cdev = &gps->cdev;
++      cdev_init(cdev, &cntl_fops);
++
++      dev_id = MKDEV(major, slot);
++      err = cdev_add(cdev, dev_id, 1);
++      if (err) {
++              return err;
++      }
++
++      //Create class device
++      bmi_class = bmi_get_class ();
++      gps->class_dev = device_create(bmi_class, NULL, MKDEV(major, slot), gps, "bmi_gps_control_m%i", slot+1);
++
++      if (IS_ERR(gps->class_dev)) {
++              printk(KERN_ERR "Unable to create "
++                     "class_device for bmi_gps_m%i; errno = %ld\n",
++                     slot+1, PTR_ERR(gps->class_dev));
++              gps->class_dev = NULL;
++      }
++
++      //bind driver and bmi_device
++      gps->bdev = bdev;
++      bmi_device_set_drvdata(bdev, gps);
++
++      printk(KERN_INFO "bmi_gps.c: probe slot %d\n", slot);
++
++      // configure IOX - leave ouputs as inputs unless needed
++
++      gps->iox = i2c_new_device(bdev->slot->adap, &iox_info);
++      if (gps->iox == NULL)
++        printk(KERN_ERR "IOX NULL...\n");
++      if(WriteByte_IOX(gps->iox, IOX_OUTPUT_REG, 0x40)) {  //
++              return -ENODEV;
++      }
++      if(WriteByte_IOX(gps->iox, IOX_CONTROL, 0x3F)) {     // IOX[4:3]=OUT, IOX[7:5,2:0]=IN
++              return -ENODEV;
++      }
++
++
++      // Initialize GPIOs (turn LED's on )
++
++//    bmi_slot_gpio_configure_as_output (int slot, int gpio, int data)
++
++      bmi_slot_gpio_configure(slot, RED_LED | GREEN_LED | GPIO_1); // Red, Green LEDS and GPIO_1 outputs
++      bmi_slot_gpio_set(slot, 0);
++
++      //Enable uart transceiver
++      bmi_slot_uart_enable (slot);
++
++      mdelay(275);
++
++      // release reset to J32 device
++      bmi_slot_gpio_set ( slot, RED_LED | GREEN_LED | GPIO_1);        // reset high, Red, Green LEDS off
++
++      return 0;
++}
++
++
++void bmi_gps_remove(struct bmi_device *bdev)
++{
++      int slot;
++      struct bmi_gps *gps;
++      struct class *bmi_class;
++
++      slot = bdev->slot->slotnum;
++      gps = &bmi_gps[slot];
++
++      //Disable uart transceiver
++      bmi_slot_uart_disable (slot);
++      bmi_slot_gpio_configure(slot, 0);
++
++      bmi_class = bmi_get_class ();
++      device_destroy(bmi_class, MKDEV(major, slot));
++
++      gps->class_dev = 0;
++
++      cdev_del (&gps->cdev);
++
++      //de-attach driver-specific struct from bmi_device structure
++      bmi_device_set_drvdata (bdev, 0);
++      gps->bdev = 0;
++
++      return;
++}
++
++
++
++
++
++static void __exit bmi_gps_cleanup(void)
++{
++      dev_t dev_id;
++
++      bmi_unregister_driver (&bmi_gps_driver);
++
++      dev_id = MKDEV(major, 0);
++      unregister_chrdev_region(dev_id, 4);
++      return;
++}
++
++
++
++
++static int __init bmi_gps_init(void)
++{
++      dev_t   dev_id;
++      int     retval;
++
++      // alloc char driver with 4 minor numbers
++
++      retval = alloc_chrdev_region(&dev_id, 0, 4, "BMI GPS Driver");
++
++      if (retval) {
++              return -1;
++      }
++
++      major = MAJOR(dev_id);
++      retval = bmi_register_driver (&bmi_gps_driver);
++
++      if (retval) {
++              unregister_chrdev_region(dev_id, 4);
++              return -1;
++      }
++      printk("bmi_gps.c: BMI_GPS Driver v%s \n", BMIGPS_VERSION);
++
++      return 0;
++}
++
++
++module_init(bmi_gps_init);
++module_exit(bmi_gps_cleanup);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Peter Giacomini <p.giacomini@encadis.com>");
++MODULE_DESCRIPTION("BMI gps device driver");
++MODULE_SUPPORTED_DEVICE("bmi_gps_control");
++
+--- /dev/null
++++ git/drivers/bmi/pims/gsm/Makefile
+@@ -0,0 +1,6 @@
++#
++# BMI PIMS
++#
++
++obj-$(CONFIG_BMI_GSM)         += bmi_gsm.o
++
+--- /dev/null
++++ git/drivers/bmi/pims/gsm/bmi_gsm.c
+@@ -0,0 +1,301 @@
++/*
++ *    bmi_gsm.c
++ *
++ *    BMI GSM device driver
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*
++ * Include files
++ */
++
++#include <linux/input.h>
++#include <linux/kernel.h>
++#include <linux/major.h>
++#include <linux/module.h>
++#include <linux/fs.h>
++#include <linux/cdev.h>
++#include <linux/delay.h>
++#include <linux/jiffies.h>
++#include <linux/timer.h>
++#include <asm/uaccess.h>
++#include <linux/device.h>
++#include <linux/interrupt.h>
++#include <linux/miscdevice.h>
++
++#include <asm/irq.h>
++#include <asm/io.h>
++#include <asm/system.h>
++#include <linux/bmi.h>
++#include <linux/bmi/bmi_gsm.h>
++
++#define DEBUG
++#undef DEBUG
++
++#define BMIGSM_VERSION                "1.0"           // driver version
++
++
++// private device structure
++struct bmi_gsm
++{
++      struct bmi_device       *bdev;                  // BMI device
++      struct cdev             cdev;                   // control device
++      struct device   *class_dev;             // control class device
++  int open_flag;
++};
++
++static struct bmi_gsm bmi_gsm_priv[4];        // per slot device structure
++static int major;             // control device major
++
++/*
++ *    BMI set up
++ */
++
++      // BMI device ID table
++static struct bmi_device_id bmi_gsm_tbl[] =
++{
++      {
++              .match_flags = BMI_DEVICE_ID_MATCH_VENDOR | BMI_DEVICE_ID_MATCH_PRODUCT,
++              .vendor   = BMI_VENDOR_BUG_LABS,
++              .product  = BMI_PRODUCT_GSM,
++              .revision = BMI_ANY,
++      },
++      { 0, },                                   /* terminate list */
++};
++
++MODULE_DEVICE_TABLE(bmi, bmi_gsm_tbl);
++
++
++int   bmi_gsm_probe(struct bmi_device *bdev);
++void  bmi_gsm_remove(struct bmi_device *bdev);
++
++// BMI driver structure
++static struct bmi_driver bmi_gsm_driver =
++{
++      .name = "bmi_gsm",
++      .id_table = bmi_gsm_tbl,
++      .probe   = bmi_gsm_probe,
++      .remove  = bmi_gsm_remove,
++};
++
++
++/*
++ * control device operations
++ */
++
++// open
++int cntl_open(struct inode *inode, struct file *file)
++{
++      struct bmi_gsm *gsmod;
++
++      gsmod = container_of (inode->i_cdev, struct bmi_gsm, cdev);
++
++      // Enforce single-open behavior
++
++      if (gsmod->open_flag) {
++              return -EBUSY;
++      }
++      gsmod->open_flag = 1;
++
++      // Save gsm_dev pointer for later.
++
++      file->private_data = gsmod;
++      return 0;
++
++}
++
++// release
++int cntl_release(struct inode *inode, struct file *file)
++{
++      struct bmi_gsm *gsmod;
++
++      gsmod = (struct bmi_gsm *)(file->private_data);
++      gsmod->open_flag = 0;
++      return 0;
++}
++
++
++// ioctl
++int cntl_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
++                 unsigned long arg)
++{
++  struct bmi_gsm *gsmod;
++  unsigned char temp = 0;
++  int slot;
++
++
++  gsmod = (struct bmi_gsm *)(filp->private_data);
++
++  if(gsmod->bdev == 0)
++    return -ENODEV;
++
++  slot = gsmod->bdev->slot->slotnum;
++
++  // ioctl's
++  temp = bmi_slot_gpio_get(slot);
++  switch (cmd) {
++  case BMI_GSM_RLEDOFF:
++    bmi_slot_gpio_set(slot, temp & (~RED_LED)); // Red LED=OFF
++    break;
++  case BMI_GSM_RLEDON:
++    bmi_slot_gpio_set(slot, temp | RED_LED); // Red LED=ON
++    break;
++  case BMI_GSM_GLEDOFF:
++    bmi_slot_gpio_set(slot, temp & (~GREEN_LED)); // Green LED=OFF
++    break;
++  case BMI_GSM_GLEDON:
++    bmi_slot_gpio_set(slot, temp | GREEN_LED); // Green LED=ON
++    break;
++  }
++  return 0;
++}
++
++// control file operations
++struct file_operations cntl_fops = {
++      .owner = THIS_MODULE,
++      .ioctl = cntl_ioctl,
++      .open = cntl_open,
++      .release = cntl_release,
++};
++
++
++// Probe
++int bmi_gsm_probe(struct bmi_device *bdev)
++{
++  int slot;
++  int status;
++  int temp = 0;
++  dev_t dev_id;
++  struct cdev *cdev;
++  struct class *bmi_class;
++  struct bmi_gsm *gsmod;
++
++
++  slot = bdev->slot->slotnum;
++  gsmod = &bmi_gsm_priv[slot];
++  gsmod->bdev = 0;
++  gsmod->open_flag = 0;
++
++  cdev = &gsmod->cdev;
++  cdev_init(cdev, &cntl_fops);
++  dev_id = MKDEV(major, slot);
++  status = cdev_add(cdev, dev_id, 1);
++  if ( status)
++    return status;
++
++  bmi_class = bmi_get_class();
++  gsmod->class_dev = device_create (bmi_class, NULL, MKDEV(major, slot), NULL, "bmi_gsm_ctl_m%i", slot + 1);
++
++  if (IS_ERR(gsmod->class_dev))
++    {
++      printk(KERN_ERR "Unable to create class device for bmi_gsm_ctl_m%i...", slot + 1);
++      gsmod->class_dev = NULL;
++      cdev_del(&gsmod->cdev);
++      return -ENODEV;
++    }
++
++  // configure GPIO
++
++  // set GPIO direction
++  bmi_slot_gpio_configure (slot, RED_LED | GREEN_LED | GPIO_0);
++
++  // turn LED's on
++  bmi_slot_gpio_set (slot, ~(RED_LED | GREEN_LED | GPIO_0));
++  mdelay(500);
++  // turn LED's off
++  bmi_slot_gpio_set (slot, (RED_LED | GREEN_LED));
++
++  // Check if SIM is present...
++  // gpio_reg = bmi_read_gpio_data_reg(slot);
++  // turn mini-card on
++  printk(KERN_INFO "Turning Sierra Wireless Card On...\n");
++  temp = bmi_slot_gpio_get(slot);
++  bmi_slot_gpio_set(slot, temp & (~GPIO_0));
++
++  // set up bdev/pbmi_gsm pointers
++  gsmod->bdev = bdev;
++  bmi_device_set_drvdata(bdev, &gsmod);
++
++  return 0;
++}
++
++// remove
++void bmi_gsm_remove(struct bmi_device *bdev)
++{
++  int slot;
++  struct bmi_gsm *gsmod;
++  struct class *bmi_class;
++
++  slot = bdev->slot->slotnum;
++
++  gsmod = &bmi_gsm_priv[slot];
++
++  bmi_slot_gpio_configure(slot, 0);
++
++  bmi_class = bmi_get_class ();
++  device_destroy (bmi_class, MKDEV(major, slot));
++
++  gsmod->class_dev = 0;
++
++  cdev_del (&gsmod->cdev);
++
++  // de-attach driver-specific struct from bmi_device structure
++  bmi_device_set_drvdata (bdev, 0);
++  gsmod->bdev = 0;
++
++  //de-attach driver-specific struct from bmi_device structure
++  bmi_device_set_drvdata (bdev, NULL);
++
++  return;
++}
++
++
++static __init int bmi_gsm_init(void)
++{
++
++  dev_t       dev_id;
++  int retval;
++
++  // alloc char driver with 4 minor numbers
++  retval = alloc_chrdev_region (&dev_id, 0, 4, "BMI GSM Driver");
++  if (retval) {
++    return -ENODEV;
++  }
++
++  major = MAJOR(dev_id);
++  retval = bmi_register_driver (&bmi_gsm_driver);
++  if (retval) {
++    unregister_chrdev_region(dev_id, 4);
++    return -ENODEV;
++  }
++
++  printk("bmi_gsm.c: BMI_GSM Driver v%s \n", BMIGSM_VERSION);
++
++  return 0;
++}
++
++static void __exit bmi_gsm_clean(void)
++{
++  dev_t dev_id;
++
++  bmi_unregister_driver (&bmi_gsm_driver);
++
++  dev_id = MKDEV(major, 0);
++  unregister_chrdev_region (dev_id, 4);
++  return;
++}
++
++module_init(bmi_gsm_init);
++module_exit(bmi_gsm_clean);
++
++MODULE_AUTHOR("Matt Isaacs <izzy@buglabs.net>");
++MODULE_DESCRIPTION("BMI gsm device driver");
++MODULE_LICENSE("GPL");
+--- /dev/null
++++ git/drivers/bmi/pims/lcd/Makefile
+@@ -0,0 +1,9 @@
++#
++# BMI PIMS
++#
++
++obj-$(CONFIG_VIDEO_BMI_LCD)                   += bmi_lcd_core.o
++bmi_lcd_core-objs := bmi_lcd.o acc.o
++
++obj-$(CONFIG_VIDEO_BMI_LCD_S320X240)          += bmi_s320x240.o
++
+--- /dev/null
++++ git/drivers/bmi/pims/lcd/acc.c
+@@ -0,0 +1,114 @@
++#include "acc.h"
++#include <asm/uaccess.h>
++#include <linux/bmi.h>
++#include <linux/device.h>
++
++#define BMI_SLOT_NUM 4
++
++static dev_t acc_dev_number;
++
++static struct file_operations acc_fops = {
++  .owner = THIS_MODULE,
++  .open = acc_open,
++  .read = acc_read,
++  .release = acc_release
++};
++
++
++int acc_open(struct inode *inode, struct file *file)
++{
++  struct acc_dev * acc;
++
++  printk(KERN_DEBUG "ACC_OPEN\n");
++
++  acc = container_of(inode->i_cdev, struct acc_dev, cdev);
++
++  file->private_data = acc;
++
++  return 0;
++}
++
++int acc_release(struct inode *inode, struct file *file)
++{
++  printk(KERN_DEBUG "ACC_RELEASE");
++
++  return 0;
++}
++
++int acc_read(struct file *file, char __user  *buf, size_t count, loff_t *ppos)
++{
++  struct acc_dev * acc = file->private_data;
++  int result = 0;
++
++  if(count < 6) {
++    return -EINVAL;
++  }
++
++  if(wait_event_interruptible(acc->wq, acc->flag != 0)) {
++    return -ERESTARTSYS;
++  }
++
++  result = copy_to_user(buf, acc->sample, 6);
++  acc->flag = 0;
++  if(result) {
++    return -EFAULT;
++  }
++
++  return 6;
++}
++
++int acc_init()
++{
++  if(alloc_chrdev_region(&acc_dev_number, 0, BMI_SLOT_NUM, "bmi_lcd_acc") < 0) {
++    printk(KERN_DEBUG "Unable to register accelerometer device\n");
++    return -1;
++  }
++
++  return 0;
++}
++
++int acc_clean()
++{
++  unregister_chrdev_region(MAJOR(acc_dev_number), BMI_SLOT_NUM);
++  return 0;
++}
++
++/* BMI Functions */
++int  acc_probe (struct acc_dev *acc, int slot)
++{
++  struct class * bmi_class;
++  struct cdev * cdev;
++  int ret;
++
++  printk(__FUNCTION__);
++  cdev = &acc->cdev;
++  printk(KERN_DEBUG "\nAbout to cdev_init acc=%p cdev=%p\n acc_fops=%p\n", acc, cdev, &acc_fops);
++  cdev_init(cdev, &acc_fops);
++  printk(KERN_DEBUG "After cdev_init\n");
++
++  ret = cdev_add(cdev, acc_dev_number + slot, 1);
++  printk(KERN_DEBUG "After cdev_add" );
++
++  bmi_class = (struct class *) bmi_get_bmi_class();
++  printk(KERN_DEBUG "After bmi_get_bmi_class" );
++  acc->class_dev = device_create(bmi_class, NULL, acc_dev_number + slot, acc, "bmi_lcd_acc_m%d", slot + 1);
++  printk(KERN_DEBUG "After class_device_create" );
++
++  init_waitqueue_head(&acc->wq);
++  printk(KERN_DEBUG "After init_waitqueue_head" );
++  return ret;
++}
++
++void acc_remove (struct acc_dev *acc, int slot)
++{
++  struct class *bmi_class;
++  int acc_major = MAJOR(acc_dev_number);
++
++  bmi_class = (struct class *) bmi_get_bmi_class();
++  device_destroy (bmi_class, MKDEV(acc_major, slot));
++
++  acc->class_dev = 0;
++
++  cdev_del (&acc->cdev);
++}
++
+--- /dev/null
++++ git/drivers/bmi/pims/lcd/acc.h
+@@ -0,0 +1,35 @@
++#ifndef _ACC_H_
++#define _ACC_H_
++
++#include <linux/kernel.h>
++#include <linux/delay.h>
++#include <linux/module.h>
++#include <linux/cdev.h>
++#include <linux/fs.h>
++
++/* Accelerometer device structure */
++struct acc_dev {
++  struct cdev cdev;
++  u8 sample[6];
++  u8 flag;
++  struct device * class_dev;
++  wait_queue_head_t wq;
++};
++
++
++int acc_open(struct inode *inode, struct file *file);
++
++int acc_release(struct inode *inode, struct file *file);
++
++int acc_read(struct file *file, char __user  *buf, size_t count, loff_t *ppos);
++
++int acc_init(void);
++
++int acc_clean(void);
++
++/*BMI Functions */
++void acc_remove(struct acc_dev *acc, int slot);
++
++int acc_probe(struct acc_dev *acc, int slot);
++
++#endif //_ACC_H_
+--- /dev/null
++++ git/drivers/bmi/pims/lcd/bmi_lcd.c
+@@ -0,0 +1,1790 @@
++/*
++ *    bmi_lcd.c
++ *
++ *    BMI LCD device driver
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*
++ * Include files
++ */
++
++#include <linux/input.h>
++#include <linux/kernel.h>
++#include <linux/major.h>
++#include <linux/module.h>
++#include <linux/fs.h>
++#include <linux/cdev.h>
++#include <linux/delay.h>
++#include <linux/jiffies.h>
++#include <linux/timer.h>
++#include <linux/i2c.h>
++#include <linux/spi/spi.h>
++#include <asm/uaccess.h>
++#include <linux/device.h>
++#include <linux/interrupt.h>
++#include <linux/cdev.h>
++
++#include <asm/irq.h>
++#include <asm/io.h>
++#include <asm/system.h>
++#include <mach/mxc_i2c.h>
++#include <mach/mx31bug_cpld.h>
++#include <linux/bmi.h>
++#include <linux/bmi/bmi-control.h>
++#include <linux/bmi/bmi-slot.h>
++#include <linux/bmi/bmi_lcd.h>
++#include <mach/ipu.h>
++
++#undef ACCELEROMETER
++#define ACCELEROMETER
++
++#ifdef ACCELEROMETER
++#include "acc.h"
++#endif //ACCELEROMETER
++
++#define DEBUG
++#undef DEBUG
++
++#define BMILCD_VERSION                "1.2"           // driver version
++#define BUF_MAX_SIZE          0x20            // spi buffer size
++#define WORK_DELAY            (1)             // interrupt work handler delay
++#define DEBOUNCE              10              // touch screen debounce
++#define X_PLATE                       400             // touch screen X plate resistance //pjg - This is not the correct value
++#define BMI_SLOT_NUM          (4)             // number of BMI slots
++#define MAX_STRG              (40)            // Max string buffer size
++
++#define       VSYNC_DISABLE           0x0
++#define       VSYNC_ENABLE            0x1
++
++      // lcd
++struct lcd_interface {
++      char                    lcd_type[MAX_STRG];     // text description of LCD type
++      u8                      suspended;              // power management state
++      u8                      rotation;               // screen rotation
++      u8                      disp;                   // display number (DISP0 or DISP1)
++      u8                      addr_mode;              // display addressing mode
++      u8                      vsync_mode;             // VSYNC signal enable (VSYNC_ENABLE | VSYNC_DISABLE)
++      u8                      bus_if_type;            // bus type (XY | FullWoBE | FullWithBE)
++      ipu_adc_sig_cfg_t       adc_sig;                // IPU ADC set-up parameters
++      ipu_di_signal_cfg_t     di_sig;                 // IPU DI set-up parameters
++};
++
++
++struct lcd_ctl
++{
++  int slot;
++  struct cdev cdev;
++  struct device *class_dev;
++};
++
++
++static struct lcd_interface s320x240_lcd_interface = {
++      .lcd_type = "MXCFB_SHARP_320X240",
++      .suspended = 0,
++      .rotation = IPU_ROTATE_NONE,
++      .disp = DISP0,
++      .vsync_mode = VSYNC_DISABLE,
++      .bus_if_type = XY,
++      .adc_sig = { 0, 0, 0, 0, 0, 0, 0, 0, IPU_ADC_BURST_WCS, IPU_ADC_IFC_MODE_SYS80_TYPE2,
++                      16, 0, 0, IPU_ADC_SER_NO_RW },
++      .di_sig = { 0,0,0,0,0,0,0,0 },          //pjg - reserved for multiple LCD driver
++};
++
++extern void s320x240_config(int disp);
++extern void s320x240_disp_off(int disp);
++extern void s320x240_disp_on(int disp);
++
++
++struct bmi_lcd;
++
++struct bmi_lcd_ops {
++      void *(*config) (int disp);                             // LCD configuration/initialization
++      void *(*reset) (int slot);                              // LCD reset
++      int *(*suspend) (struct bmi_lcd *blcd);                 // power management
++      int *(*resume) (struct bmi_lcd *blcd);                  // power management
++      int *(*disp_on) (int disp);                             // display on
++      int *(*disp_off) (int disp);                            // display off
++      int (*activate) (struct bmi_lcd *lcd, int slot);        // enable LCD backlight, touchscreen, accelerometer, ...
++      int (*deactivate) (struct bmi_lcd *lcd, int slot);      // disable LCD backlight, touchscreen, accelerometer, ...
++};
++
++struct bmi_lcd_ops s320x240_bmi_lcd_ops;
++
++struct bmi_lcd {
++      struct lcd_interface interface;         // pointer to this struct is returned by config()
++      struct bmi_lcd_ops lcd_ops;             // function pointers
++};
++
++static struct bmi_lcd s320x240_bmi_lcd;
++
++int register_bmi_lcd(struct bmi_lcd *blcd, int slot);
++int unregister_bmi_lcd(struct bmi_lcd *blcd, int slot);
++
++      // private device structure
++struct pbmi_lcd
++{
++      unsigned int            lcd_cnt;                                // number of LCD's present
++      unsigned int            active;                                 // indication of LCD presence
++      unsigned int            activated[BMI_SLOT_NUM];                // indication of LCD presence
++
++      struct bmi_lcd          *blcd[BMI_SLOT_NUM];                    // BMI LCD structure - placeholder for multiple display types
++      struct bmi_device       *bdev[BMI_SLOT_NUM];                    // BMI device per slot
++      unsigned int            interrupt[BMI_SLOT_NUM];                // input device interrupt handlers
++      char                    int_name[MAX_STRG];                     // interrupt name
++
++      struct input_dev        *input_dev[BMI_TS_NUM];                 // input device (touch screen and accelerometer)
++      struct timer_list       timer[BMI_SLOT_NUM];                    // touch timer
++  struct lcd_ctl              ctl_dev[BMI_SLOT_NUM];
++  int pen_down[BMI_SLOT_NUM];
++  int scount[BMI_SLOT_NUM];
++
++      struct spi_device       *spi[BMI_SLOT_NUM];                     // touch screen device interface
++      struct semaphore        sem[BMI_SLOT_NUM];                      // spi semaphore
++      char                    rbuf[BMI_SLOT_NUM][BUF_MAX_SIZE];       // spi read buffer
++      char                    wbuf[BMI_SLOT_NUM][BUF_MAX_SIZE];       // spi write buffer
++
++#ifdef ACCELEROMETER
++  struct acc_dev             acc[BMI_SLOT_NUM];
++#endif
++};
++
++static struct pbmi_lcd pbmi_lcd;      // LCD device sructure
++
++/*
++ *    BMI set up
++ */
++
++      // BMI device ID table
++static struct bmi_device_id bmi_lcd_tbl[] =
++{
++      {
++              .match_flags = BMI_DEVICE_ID_MATCH_VENDOR | BMI_DEVICE_ID_MATCH_PRODUCT,
++              .vendor   = BMI_VENDOR_BUG_LABS,
++              .product  = BMI_PRODUCT_LCD_SHARP_320X240,
++              .revision = BMI_ANY,
++      },
++      { 0, },                                   /* terminate list */
++};
++
++MODULE_DEVICE_TABLE(bmi, bmi_lcd_tbl);
++
++/*printk(KERN_INFO "MDT: 0x%x\n", __mod_bmi_device_table);*/
++
++int   bmi_lcd_probe(struct bmi_device *bdev);
++void  bmi_lcd_remove(struct bmi_device *bdev);
++
++// BMI driver structure
++static struct bmi_driver bmi_lcd_driver =
++{
++      .name = "bmi_lcd",
++      .id_table = bmi_lcd_tbl,
++      .probe   = bmi_lcd_probe,
++      .remove  = bmi_lcd_remove,
++};
++
++//Accelerometer driver structure
++
++
++/*
++ *    I2C set up
++ */
++
++      // I2C Slave Address
++#define BMI_IOX_I2C_ADDRESS   0x71    // 7-bit address
++#define BMI_ACC_I2C_ADDRESS   0x17    // 7-bit address
++
++      // I2C IOX register addresses
++#define IOX_INPUT_REG         0x0     // IOX input data register
++#define IOX_OUTPUT_REG                0x1     // IOX output data register
++#define IOX_POLARITY_REG      0x2     // IOX polarity data register
++#define IOX_CONTROL           0x3     // IOX direction control register
++#define IOX_B1                        (0)     // bit 0 - backlight control
++#define IOX_A1_A2             (1)     // bit 1 - backlight control
++#define IOX_ACC_RST_N         (2)     // bit 2 - acceleromter reset
++#define IOX_VSYNC_EN_N                (3)     // bit 3 - VSYNC output buffer enable
++#define IOX_LCD_RST_N         (4)     // bit 4 - LCD reset
++#define IOX_SERDES_PD_N               (5)     // bit 5 - SERDES power down
++#define IOX_X_INT             (6)     // bit 6 - accelerometer interrupt
++#define IOX_Y_INT             (7)     // bit 7 - accelerometer interrupt
++
++      // I2C ACC register addresses - OKI
++#define ACC_PAGESEL                   0x1E    // device ready status
++      // page 0
++#define ACC_DVRST                     0x01    // device reset
++      #define ACC_DVRST_RST           0x3C    // device reset
++      #define ACC_DVRST_EN            0xC3    // device enable
++#define ACC_PDWN                      0x02    // osc power down
++      #define ACC_PWDN_RST            0x01    // device reset
++      #define ACC_PWDN_EN             0x00    // device enable
++#define ACC_CTRL0                     0x03    // control 0
++      #define ACC_CTRL0_CTSTR         0x40    // control 0 - temp sensor
++      #define ACC_CTRL0_CGSTRNC       0x08    // control 0 - 3-axis/no tilt
++      #define ACC_CTRL0_CGSTRC        0x04    // control 0 - 3-axis/tilt
++      #define ACC_CTRL0_CGAUTO        0x01    // control 0 - auto
++#define ACC_MODE0                     0x05    // control 0
++      #define ACC_MODE0_PDOFF         0x80    // mode 0 - disable auto power down
++      #define ACC_MODE0_RVOFF         0x40    // mode 0 - disable temp compensation
++      #define ACC_MODE0_TMPOFF        0x20    // mode 0 - disable temp measurement
++      #define ACC_MODE0_AGCON         0x10    // mode 0 - enable auto mode pitch and roll
++      #define ACC_MODE0_MAUTO         0x04    // mode 0 - enable auto termination
++      #define ACC_MODE0_GDET00        0x00    // mode 0 - g detection threshold - see ML8953 data sheet
++      #define ACC_MODE0_GDET01        0x01    // mode 0 - g detection threshold - see ML8953 data sheet
++      #define ACC_MODE0_GDET10        0x02    // mode 0 - g detection threshold - see ML8953 data sheet
++#define ACC_MODE1                     0x06    // mode 1
++      #define ACC_MODE1_MOFF          0x20    // mode 1 - disable 3-axis continuous mode
++      #define ACC_MODE1_ZAXIS         0x03    // mode 1 - Z axis
++      #define ACC_MODE1_YAXIS         0x02    // mode 1 - Y axis
++      #define ACC_MODE1_XAXIS         0x01    // mode 1 - X axis
++      #define ACC_MODE1_RAXIS         0x00    // mode 1 - Reference axis
++#define ACC_INTRQ                     0x07    // interrupt request (1 = request)
++#define ACC_INTMSK                    0x08    // interrupt mask (1 = masked)
++      #define ACC_INT_TREQ            0x20    // interrupt - temperature
++      #define ACC_INT_GREQ            0x08    // interrupt - acceleration/no tilt
++      #define ACC_INT_GCREQ           0x04    // interrupt - acceleration/tilt
++      #define ACC_INT_GAREQ           0x01    // interrupt - automatic
++#define ACC_TMDL                      0x09    // timer LSB = (1/6.2 MHz) x 2048 x TMD
++#define ACC_TMDH                      0x0A    // timer MSB
++#define ACC_CFG                               0x0C    // configuration
++      #define ACC_CFG_REGMD           0x80    // address auto-increment
++      #define ACC_CFG_SPI3M_3         0x40    // spi mode = 3-wire
++      #define ACC_CFG_SPI3M_4         0x00    // spi mode = 4-wire
++      #define ACC_CFG_SDOCFG_T        0x10    // sdo mode = totem-pole
++      #define ACC_CFG_SDOCFG_OC       0x00    // sdo mode = open-drain
++      #define ACC_CFG_INT1EN_G        0x08    // interrupt 1 mode = g only
++      #define ACC_CFG_INT1EN_ALL      0x00    // interrupt 1 mode = all
++      #define ACC_CFG_INTLVL          0x04    // interrupt level mode
++      #define ACC_CFG_INT1CFG_T       0x02    // interrupt 1 mode = totem-pole
++      #define ACC_CFG_INT1CFG_OC      0x00    // interrupt 1 mode = open-drain
++      #define ACC_CFG_INT0CFG_T       0x01    // interrupt 0 mode = totem-pole
++      #define ACC_CFG_INT0CFG_OC      0x00    // interrupt 0 mode = open-drain
++#define ACC_INTOTM                    0x0D    // interrupt output conditions
++#define ACC_GAAVE                     0x0E    // Data averaging - automatic mode
++#define ACC_GNAVE                     0x0F    // Data averaging - normal mode
++#define ACC_GDTCT0L                   0x11    // threshold 0 LSB
++#define ACC_GDTCT0H                   0x12    // threshold 0 MSB
++#define ACC_GDTCT1L                   0x13    // threshold 1 LSB
++#define ACC_GDTCT1H                   0x14    // threshold 1 MSB
++#define ACC_CPURDY                    0x15    // device ready status (ready = 0x01)
++      // page 1
++#define ACC_STATUS                    0x01    // measurment status
++      #define ACC_STATUS_ASTS         0x02    // acceleration measurement - automatic modes
++      #define ACC_STATUS_STS          0x01    // acceleration measurement - non-automatic modes
++#define ACC_GAXL                      0x02    // g vector
++#define ACC_GAXH                      0x03    // g vector
++#define ACC_GAYL                      0x04    // g vector
++#define ACC_GAYH                      0x05    // g vector
++#define ACC_GAZL                      0x06    // g vector
++#define ACC_GAZH                      0x07    // g vector
++#define ACC_GASVL                     0x08    // g vector
++#define ACC_GASVH                     0x09    // g vector
++#define ACC_GNXL                        0x0A    // g vector
++#define ACC_GNXH                        0x0B    // g vector
++#define ACC_GNYL                        0x0C    // g vector
++#define ACC_GNYH                        0x0D    // g vector
++#define ACC_GNZL                        0x0E    // g vector
++#define ACC_GNZH                        0x0F    // g vector
++#define ACC_GNSVL                     0x10    // g vector
++#define ACC_GNSVH                     0x11    // g vector
++#define ACC_PITCHL                    0x12    // pitch
++#define ACC_PITCHH                    0x13    // pitch
++#define ACC_ROLLL                     0x14    // roll
++#define ACC_ROLLH                     0x15    // roll
++#define ACC_TEMPL                     0x19    // temperature
++#define ACC_TEMPH                     0x1A    // temperature
++
++      // read byte from I2C IO expander
++static int ReadByte_IOX(struct i2c_adapter *adap, unsigned char offset, unsigned char *data)
++{
++              int     ret = 0;
++              struct i2c_msg rmsg[2];
++              int     num_msgs;
++
++              /* Read Byte with Pointer */
++
++              rmsg[0].addr = BMI_IOX_I2C_ADDRESS;
++              rmsg[0].flags = 0;        /* write */
++              rmsg[0].len = 1;
++              rmsg[0].buf = &offset;
++
++              rmsg[1].addr = BMI_IOX_I2C_ADDRESS;
++              rmsg[1].flags = I2C_M_RD;   /* read */
++              rmsg[1].len = 1;
++              rmsg[1].buf = data;
++
++              num_msgs = 2;
++              ret = i2c_transfer (adap, rmsg, num_msgs);
++
++              if (ret == 2) {
++                      ret = 0;
++              }
++              else {
++                      printk (KERN_ERR "ReadByte_IOX() - i2c_transfer() failed.\n");
++                      ret = -1;
++              }
++              return ret;
++}
++
++      // write byte to I2C IO expander
++static int WriteByte_IOX(struct i2c_adapter *adap, unsigned char offset, unsigned char data)
++{
++              int     ret = 0;
++              struct i2c_msg wmsg[2];
++              int     num_msgs;
++
++              /* Write Byte with Pointer */
++
++              wmsg[0].addr = BMI_IOX_I2C_ADDRESS;
++              wmsg[0].flags = 0;      /* write */
++              wmsg[0].len = 1;
++              wmsg[0].buf = &offset;
++
++              wmsg[1].addr = BMI_IOX_I2C_ADDRESS;
++              wmsg[1].flags = 0;      /* write */
++              wmsg[1].len = 1;
++              wmsg[1].buf = &data;
++
++              num_msgs = 2;
++
++              ret = i2c_transfer (adap, wmsg, num_msgs);
++
++              if (ret == 2) {
++                      ret = 0;
++              }
++              else {
++                      printk (KERN_ERR "WriteByte_IOX() - i2c_transfer() failed.\n");
++                      ret = -1;
++              }
++              return ret;
++}
++
++
++#if defined ACCELEROMETER
++      // read byte from I2C acceleromter
++static int ReadByte_ACC(struct i2c_adapter *adap, unsigned char offset, unsigned char *data)
++{
++              int     ret = 0;
++              struct i2c_msg rmsg[2];
++              int     num_msgs;
++
++              /* Read Byte with Pointer */
++
++              rmsg[0].addr = BMI_ACC_I2C_ADDRESS;
++              rmsg[0].flags = 0;        /* write */
++              rmsg[0].len = 1;
++              rmsg[0].buf = &offset;
++
++              rmsg[1].addr = BMI_ACC_I2C_ADDRESS;
++              rmsg[1].flags = I2C_M_RD;   /* read */
++              rmsg[1].len = 1;
++              rmsg[1].buf = data;
++
++              num_msgs = 2;
++              ret = i2c_transfer (adap, rmsg, num_msgs);
++
++              if (ret == 2) {
++                      ret = 0;
++              }
++              else {
++                      printk (KERN_ERR "ReadByte_ACC() - i2c_transfer() failed.\n");
++                      ret = -1;
++              }
++              return ret;
++}
++
++      // write byte to I2C accelerometer
++static int WriteByte_ACC(struct i2c_adapter *adap, unsigned char offset, unsigned char data)
++{
++              int     ret = 0;
++              struct i2c_msg wmsg[2];
++              int     num_msgs;
++
++              /* Write Byte with Pointer */
++
++              wmsg[0].addr = BMI_ACC_I2C_ADDRESS;
++              wmsg[0].flags = 0;      /* write */
++              wmsg[0].len = 1;
++              wmsg[0].buf = &offset;
++
++              wmsg[1].addr = BMI_ACC_I2C_ADDRESS;
++              wmsg[1].flags = 0;      /* write */
++              wmsg[1].len = 1;
++              wmsg[1].buf = &data;
++
++              num_msgs = 2;
++
++              ret = i2c_transfer (adap, wmsg, num_msgs);
++
++              if (ret == 2) {
++                      ret = 0;
++              }
++              else {
++                      printk (KERN_ERR "WriteByte_ACC() - i2c_transfer() failed.\n");
++                      ret = -1;
++              }
++              return ret;
++}
++#endif        // ACCELEROMETER
++
++/*
++ *    SPI functions
++ */
++
++      // TSC2046 touch screen controller command register bit definitons
++#define SPI_START     0x80    // command start
++#define SPI_AT0               0x00    // read temperature - not supported
++#define SPI_AY                0x10    // read Y
++#define SPI_ABAT      0x20    // read battery - not supported
++#define SPI_AZ1               0x30    // read Z1
++#define SPI_AZ2               0x40    // read Z2
++#define SPI_AX                0x50    // read X
++#define SPI_AAUX      0x60    // read AUX - not supported
++#define SPI_AT1               0x70    // read temperature - not supported
++#define SPI_MODE_12   0x00    // 12-bit mode - Preferred
++#define SPI_MODE_8    0x08    // 8-bit mode
++#define SPI_MODE_DFR  0x00    // differential mode - Preferred
++#define SPI_MODE_SER  0x04    // single ended mode
++#define SPI_PD                0x00    // power down - PENIRQ enabled
++#define SPI_ADC               0x01    // ADC enabled
++#define SPI_REF               0x02    // Vref enabled - unused
++#define SPI_REF_ADC   0x03    // Vref & ADC enabled - unused
++
++      // spi access
++static int spi_rw(struct spi_device *spi, u8 * buf, size_t len)
++{
++      struct spi_transfer t = {
++              .tx_buf = (const void *)buf,
++              .rx_buf = buf,
++              .len = len,
++              .cs_change = 0,
++              .delay_usecs = 0,
++      };
++      struct spi_message m;
++
++      spi_message_init(&m);
++
++      spi_message_add_tail(&t, &m);
++      if (spi_sync(spi, &m) != 0 || m.status != 0)
++              return -1;
++
++      return m.actual_length;
++}
++
++      // spi write register
++static ssize_t spi_lcd_write_reg(struct pbmi_lcd *priv, char *buf, int len, int slot)
++{
++      int res = 0;
++
++      down(&priv->sem[slot]);
++
++      memset(priv->wbuf[slot], 0, BUF_MAX_SIZE);
++      priv->wbuf[slot][0] = buf[0];
++      priv->wbuf[slot][1] = buf[1];
++      priv->wbuf[slot][2] = buf[2];
++      priv->wbuf[slot][3] = buf[3];
++      res = spi_rw(priv->spi[slot], priv->wbuf[slot], len);
++      if (res != 1) {
++              up(&priv->sem[slot]);
++              return -EFAULT;
++      }
++
++      up(&priv->sem[slot]);
++
++      return res;
++}
++
++      // spi read register
++static ssize_t spi_lcd_read_reg(struct pbmi_lcd *priv, char *buf, int len, int slot)
++{
++      int res = 0;
++
++      down(&priv->sem[slot]);
++
++      memset(priv->wbuf[slot], 0, BUF_MAX_SIZE);
++      priv->wbuf[slot][0] = buf[0];
++      priv->wbuf[slot][1] = buf[1];
++      priv->wbuf[slot][2] = buf[2];
++      priv->wbuf[slot][3] = buf[3];
++      res = spi_rw(priv->spi[slot], priv->wbuf[slot], len);
++      if (res != 1) {
++              up(&priv->sem[slot]);
++              return -EFAULT;
++      }
++
++      memset(priv->rbuf[slot], 0, BUF_MAX_SIZE);
++      buf[0] = priv->wbuf[slot][2];
++      buf[1] = priv->wbuf[slot][1];
++
++      up(&priv->sem[slot]);
++
++      return res;
++}
++
++
++// control file operations
++static int lcd_ctl_open (struct inode *, struct file *);
++static int lcd_ctl_release (struct inode *, struct file *);
++static int lcd_ctl_ioctl (struct inode *, struct file *, unsigned int, unsigned long);
++
++struct file_operations lcd_ctl_fops = {
++      .owner = THIS_MODULE,
++      .ioctl = lcd_ctl_ioctl,
++      .open = lcd_ctl_open,
++      .release = lcd_ctl_release,
++};
++
++/*
++ * control device operations
++ */
++static int lcd_ctl_major;
++
++int lcd_ctl_init (void)
++{
++      dev_t   dev_id;
++      int     retval;
++
++      // alloc char driver with 4 minor numbers
++
++      retval = alloc_chrdev_region(&dev_id, 0, 4, "BMI LCD Control Driver");
++
++      if (retval) {
++              return -1;
++      }
++      lcd_ctl_major = MAJOR(dev_id);
++      return 0;
++}
++
++void lcd_ctl_clean (void)
++{
++      dev_t dev_id;
++
++      dev_id = MKDEV(lcd_ctl_major, 0);
++      unregister_chrdev_region(dev_id, 4);
++      return;
++}
++
++int lcd_ctl_probe (struct lcd_ctl *lcd_ctl, int slot)
++{
++      struct cdev *cdev;
++      dev_t dev_id;
++      int ret;
++      struct class *bmi_class;
++
++      cdev = &lcd_ctl->cdev;
++      cdev_init (cdev, &lcd_ctl_fops);
++
++      dev_id = MKDEV (lcd_ctl_major, slot);
++      ret = cdev_add (cdev, dev_id, 1);
++
++      //Create class device
++      bmi_class = bmi_get_bmi_class ();
++
++      lcd_ctl->class_dev = device_create (bmi_class, NULL, MKDEV(lcd_ctl_major, slot), lcd_ctl, "bmi_lcd_ctl_m%i", slot+1);
++
++      if (IS_ERR(lcd_ctl->class_dev)) {
++              printk(KERN_ERR "Unable to create "
++                     "class_device for bmi_lcd_ctl_m%i; errno = %ld\n",
++                     slot+1, PTR_ERR(lcd_ctl->class_dev));
++              lcd_ctl->class_dev = NULL;
++      }
++      lcd_ctl->slot = slot;
++
++      return ret;
++}
++
++void lcd_ctl_remove (struct lcd_ctl *lcd_ctl, int slot)
++{
++      struct class *bmi_class;
++
++      bmi_class = bmi_get_bmi_class ();
++      device_destroy (bmi_class, MKDEV(lcd_ctl_major, slot));
++
++      lcd_ctl->class_dev = 0;
++
++      cdev_del (&lcd_ctl->cdev);
++      return;
++}
++
++// open
++static int lcd_ctl_open (struct inode *inode, struct file *file)
++{
++      struct lcd_ctl *lcd_ctl;
++
++      lcd_ctl = container_of(inode->i_cdev, struct lcd_ctl, cdev);
++
++
++      // Save ctl pointer for later.
++
++      file->private_data = lcd_ctl;
++      return 0;
++}
++
++// release
++static int lcd_ctl_release (struct inode *inode, struct file *file)
++{
++      struct lcd_ctl *lcd_ctl;
++
++      lcd_ctl = container_of(inode->i_cdev, struct lcd_ctl, cdev);
++      return 0;
++}
++
++// ioctl
++int lcd_ctl_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
++                 unsigned long arg)
++{
++  struct lcd_ctl *lcd_ctl;
++  struct i2c_adapter *adap;
++  unsigned char iox_data[1];
++  int slot;
++  int bl = ((__user arg) & 0x70) >> 4;
++
++              // error if no lcd active.
++
++      if(cmd != BMI_LCD_GETSTAT) {
++                      // i2c adapter
++        lcd_ctl = container_of(inode->i_cdev, struct lcd_ctl, cdev);
++        slot = lcd_ctl->slot;
++        if (slot < 0) {
++          return -ENODEV;
++        }
++        adap = &pbmi_lcd.bdev[slot]->adap;
++      }
++
++              // ioctl's
++      switch (cmd) {
++              case BMI_LCD_RLEDOFF:
++                      bmi_set_module_gpio_data(slot, 3, 1);// Red LED=OFF
++                      break;
++              case BMI_LCD_RLEDON:
++                      bmi_set_module_gpio_data(slot, 3, 0);// Red LED=ON
++                      break;
++              case BMI_LCD_GLEDOFF:
++                      bmi_set_module_gpio_data(slot, 2, 1);// Green LED=OFF
++                      break;
++              case BMI_LCD_GLEDON:
++                      bmi_set_module_gpio_data(slot, 2, 0);// Green LED=ON
++                      break;
++              case BMI_LCD_VSYNC_DIS: // enable VSYNC buffer tristate output
++                      if(ReadByte_IOX(adap, IOX_OUTPUT_REG, iox_data))
++                              return -ENODEV;
++                      *iox_data |= 0x08;
++                      if(WriteByte_IOX(adap, IOX_OUTPUT_REG, *iox_data))
++                              return -ENODEV;
++                      break;
++              case BMI_LCD_VSYNC_EN:  // disable VSYNC buffer tristate output
++                      if(ReadByte_IOX(adap, IOX_OUTPUT_REG, iox_data))
++                              return -ENODEV;
++                      *iox_data &= ~0x08;
++                      if(WriteByte_IOX(adap, IOX_OUTPUT_REG, *iox_data))
++                              return -ENODEV;
++                      break;
++              case BMI_LCD_EN:        // enable LCD component
++                      if(ReadByte_IOX(adap, IOX_OUTPUT_REG, iox_data))
++                              return -ENODEV;
++                      *iox_data &= ~0x10;
++                      if(WriteByte_IOX(adap, IOX_OUTPUT_REG, *iox_data))
++                              return -ENODEV;
++                      break;
++              case BMI_LCD_DIS:       // disable LCD component only
++                      if(ReadByte_IOX(adap, IOX_OUTPUT_REG, iox_data))
++                              return -ENODEV;
++                      *iox_data |= 0x10;
++                      if(WriteByte_IOX(adap, IOX_OUTPUT_REG, *iox_data))
++                              return -ENODEV;
++                      break;
++              case BMI_LCD_SER_EN:    // enable Serializer component
++                      if(ReadByte_IOX(adap, IOX_OUTPUT_REG, iox_data))
++                              return -ENODEV;
++                      *iox_data &= ~0x20;
++                      if(WriteByte_IOX(adap, IOX_OUTPUT_REG, *iox_data))
++                              return -ENODEV;
++                      break;
++              case BMI_LCD_SER_DIS:   // disable Serializer component only
++                      if(ReadByte_IOX(adap, IOX_OUTPUT_REG, iox_data))
++                              return -ENODEV;
++                      *iox_data |= 0x20;
++                      if(WriteByte_IOX(adap, IOX_OUTPUT_REG, *iox_data))
++                              return -ENODEV;
++                      break;
++              case BMI_LCD_SETRST:    // overall module reset
++                      bmi_set_module_gpio_data (slot, 1, 0);          // RST=0
++                      break;
++              case BMI_LCD_CLRRST:    // overall module enable
++                      bmi_set_module_gpio_data (slot, 1, 1);          // RST=1
++                      break;
++              case BMI_LCD_SET_BL:    // set backlight brightness
++                      if(ReadByte_IOX(adap, IOX_OUTPUT_REG, iox_data))
++                              return -ENODEV;
++                      *iox_data = (*iox_data & 0xFC) | bl;
++                      if(WriteByte_IOX(adap, IOX_OUTPUT_REG, *iox_data))
++                              return -ENODEV;
++                      break;
++              case BMI_LCD_GETSTAT:
++                      {
++                              int *slot = ((int __user *) arg);
++                              int read_data;
++
++                              *slot &= 0xF;
++
++                                      // error if slot invalid
++                              if((*slot < CPLD_M1) || (*slot > CPLD_M4))
++                                      return -ENODEV;
++
++                                      // error if no lcd in chosen slot
++                              if(pbmi_lcd.bdev[*slot] == 0)
++                                      return -ENODEV;
++
++                                      // i2c adapter
++                              adap = &pbmi_lcd.bdev[*slot]->adap;
++
++                              if(ReadByte_IOX(adap, IOX_INPUT_REG, iox_data))
++                                      return -ENODEV;
++
++                              read_data = *iox_data | (bmi_read_gpio_data_reg(*slot) << 8);
++
++                              if(put_user(read_data, (int __user *) arg))
++                                              return -EFAULT;
++                      }
++                      break;
++              case BMI_LCD_ACTIVATE:  //pjg fix/test
++                              // check for opposite side already active
++                      switch(slot) {  // opposite side
++                              case 0:
++                                      if(pbmi_lcd.activated[2] == 1) {
++                                              printk(KERN_INFO "bmi_lcd.c: probe slot %d not allowed (slot 2 already active)\n", slot);
++                                              bmi_slot_power_off(0);
++                                              return -ENODEV;
++                                      }
++                                      break;
++                              case 1:
++                                      if(pbmi_lcd.activated[3] == 1) {
++                                              printk(KERN_INFO "bmi_lcd.c: probe slot %d not allowed (slot 3 already active)\n", slot);
++                                              bmi_slot_power_off(1);
++                                              return -ENODEV;
++                                      }
++                                      break;
++                              case 2:
++                                      if(pbmi_lcd.activated[0] == 1) {
++                                              printk(KERN_INFO "bmi_lcd.c: probe slot %d not allowed (slot 0 already active)\n", slot);
++                                              bmi_slot_power_off(2);
++                                              return -ENODEV;
++                                      }
++                                      break;
++                              case 3:
++                                      if(pbmi_lcd.activated[1] == 1) {
++                                              printk(KERN_INFO "bmi_lcd.c: probe slot %d not allowed (slot 1 already active)\n", slot);
++                                              bmi_slot_power_off(3);
++                                              return -ENODEV;
++                                      }
++                                      break;
++                      }
++                              // activate
++                      if((!pbmi_lcd.activated[slot]) && (pbmi_lcd.bdev[slot] != 0)) {
++                              bmi_lcd_probe(pbmi_lcd.bdev[slot]);
++                      }
++                      break;
++              case BMI_LCD_DEACTIVATE:
++                      if(pbmi_lcd.activated[slot]) {
++                              disable_irq_nosync(pbmi_lcd.interrupt[slot]);
++                              pbmi_lcd.activated[slot] = 0;
++                              if(ReadByte_IOX(adap, IOX_OUTPUT_REG, iox_data))
++                                      return -ENODEV;
++                              *iox_data = (*iox_data & 0xF8);
++                              if(WriteByte_IOX(adap, IOX_OUTPUT_REG, *iox_data))
++                                      return -ENODEV;
++                              bmi_slot_power_off(slot);
++                      }
++                      break;
++              case BMI_LCD_SUSPEND:
++                      printk(KERN_ERR "BMI_LCD_SUSPEND NOT IMPLEMENTED\n");   //pjg
++                      break;
++              case BMI_LCD_RESUME:
++                      printk(KERN_ERR "BMI_LCD_RESUME NOT IMPLEMENTED\n");    //pjg
++                      break;
++              default:
++                      return -ENOTTY;
++      }
++      return 0;
++}
++
++
++/*
++ *    BMI functions
++ */
++
++static irqreturn_t module_irq_handler(int irq, void *dummy);
++void bmi_lcd_config(struct bmi_lcd *lcd, int disp);
++
++      // probe
++int bmi_lcd_probe(struct bmi_device *bdev)
++{
++#if defined ACCELEROMETER
++      unsigned char acc_data[1];
++#endif        // ACCELEROMETER
++      unsigned char iox_data[1];
++      int slot = bdev->info->slot;
++      struct i2c_adapter *adap;
++      struct bmi_lcd *lcd;
++      char buf[4];
++      /*int first_time = 1;*/
++
++      printk(KERN_INFO "bmi_lcd.c: probe slot %d\n", slot);
++
++              // check for opposite side already active
++      switch(slot) {  // opposite side
++              case 0:
++                      if(pbmi_lcd.activated[2] == 1) {
++                              printk(KERN_INFO "bmi_lcd.c: probe slot %d not allowed (slot 2 already active)\n", slot);
++                              bmi_slot_power_off(0);
++                              /*bmi_slot_power_off(2);*/
++                              pbmi_lcd.bdev[0] = bdev;
++                              /*bdev = pbmi_lcd.bdev[2];
++                              slot = 2;
++                              first_time = 0;*/
++                              return 0;
++                      }
++                      break;
++              case 1:
++                      if(pbmi_lcd.activated[3] == 1) {
++                              printk(KERN_INFO "bmi_lcd.c: probe slot %d not allowed (slot 3 already active)\n", slot);
++                              bmi_slot_power_off(1);
++                              /*bmi_slot_power_off(3);*/
++                              pbmi_lcd.bdev[1] = bdev;
++                              /*bdev = pbmi_lcd.bdev[3];
++                              slot = 3;
++                              first_time = 0;*/
++                              return 0;
++                      }
++                      break;
++              case 2:
++                      if(pbmi_lcd.activated[0] == 1) {
++                              printk(KERN_INFO "bmi_lcd.c: probe slot %d not allowed (slot 0 already active)\n", slot);
++                              bmi_slot_power_off(2);
++                              /*bmi_slot_power_off(0);*/
++                              pbmi_lcd.bdev[2] = bdev;
++                              /*bdev = pbmi_lcd.bdev[0];
++                              slot = 0;
++                              first_time = 0;*/
++                              return 0;
++                      }
++                      break;
++              case 3:
++                      if(pbmi_lcd.activated[1] == 1) {
++                              printk(KERN_INFO "bmi_lcd.c: probe slot %d not allowed (slot 1 already active)\n", slot);
++                              bmi_slot_power_off(3);
++                              /*bmi_slot_power_off(1);*/
++                              pbmi_lcd.bdev[3] = bdev;
++                              /*bdev = pbmi_lcd.bdev[1];
++                              slot = 1;
++                              first_time = 0;*/
++                              return 0;
++                      }
++                      break;
++      }
++
++      adap = &bdev->adap;
++      bmi_slot_power_on(slot);
++
++      mdelay(500);
++
++      if (lcd_ctl_probe(&pbmi_lcd.ctl_dev[slot], slot)) {
++        printk(KERN_INFO "bmi_lcd.c: probe slot %d control device node error...\n", slot);
++        return -ENODEV;
++      }
++
++              // configure IOX
++              // [7:6]=interrupts, [5]=SER_PD*, [4]=LCD_RST*, [3]=VSYNC_OE*, [2]=ACC_RST*, [1:0]=backlight
++      if(WriteByte_IOX(adap, IOX_OUTPUT_REG, 0xFF))   // normal - no accelerometer interrupts
++              return -ENODEV;
++
++              // normal operation - no accelerometer interrupts
++      if(WriteByte_IOX(adap, IOX_CONTROL, 0x00))      // IOX[7:0]=OUT
++              return -ENODEV;
++
++              // clear interrupts
++      if(ReadByte_IOX(adap, IOX_INPUT_REG, iox_data))
++              return -ENODEV;
++
++      printk(KERN_INFO "bmi_lcd.c: probe slot %d iox data =  %x\n", slot, *iox_data);
++
++#if defined ACCELEROMETER
++              // accelerometer
++      printk(KERN_INFO "bmi_lcd.c: probe slot %d hardware version =  0x%x\n", slot, bdev->epraw.revision_msb);
++
++              // check for PCB revision >= 1.2
++      if(bdev->epraw.revision_msb >= 0x12) {
++
++                      // normal IOX operation - accelerometer interrupts
++              if(WriteByte_IOX(adap, IOX_CONTROL, 0xC0))      // IOX[7:6]=IN, IOX[5:0]=OUT
++                      return -ENODEV;
++
++              if(WriteByte_IOX(adap, IOX_OUTPUT_REG, 0xFB))   // reset OKI accelerometer
++                      return -ENODEV;
++
++              mdelay(2);
++
++              if(WriteByte_IOX(adap, IOX_OUTPUT_REG, 0xFF))   // enable OKI accelerometer
++                      return -ENODEV;
++
++              mdelay(2);
++
++                      // write PAGESEL
++              *acc_data = 0x0;
++              if(WriteByte_ACC(adap, ACC_PAGESEL, *acc_data))
++                      return -ENODEV;
++
++                      // read device to verify existance
++              if(ReadByte_ACC(adap, ACC_CPURDY, acc_data))
++                      return -ENODEV;
++
++                      // set TMD = 0x300 (~250 ms)
++              *acc_data = 0x5;
++              if(WriteByte_ACC(adap, ACC_TMDH, *acc_data))
++                      return -ENODEV;
++
++              *acc_data = 0x0;
++              if(WriteByte_ACC(adap, ACC_TMDL, *acc_data))
++                      return -ENODEV;
++
++                      // set INTOTM
++              *acc_data = 0x00;
++              if(WriteByte_ACC(adap, ACC_INTOTM, *acc_data))
++                      return -ENODEV;
++
++                      // set GxAVE
++              *acc_data = 0x0;
++              if(WriteByte_ACC(adap, ACC_GAAVE, *acc_data))
++                      return -ENODEV;
++
++                      // set GDTCT[01]
++              *acc_data = 0x00;
++              if(WriteByte_ACC(adap, ACC_GDTCT0L, *acc_data))
++                      return -ENODEV;
++
++              *acc_data = 0x00;
++              if(WriteByte_ACC(adap, ACC_GDTCT0H, *acc_data))
++                      return -ENODEV;
++
++              *acc_data = 0x00;
++              if(WriteByte_ACC(adap, ACC_GDTCT1L, *acc_data))
++                      return -ENODEV;
++
++              *acc_data = 0x00;
++              if(WriteByte_ACC(adap, ACC_GDTCT1H, *acc_data))
++                      return -ENODEV;
++
++                      // set MODE0
++              *acc_data = ACC_MODE0_PDOFF | ACC_MODE0_TMPOFF | ACC_MODE0_AGCON | ACC_MODE0_MAUTO | ACC_MODE0_GDET10;
++              if(WriteByte_ACC(adap, ACC_MODE0, *acc_data))
++                      return -ENODEV;
++
++                      // set CFG
++              *acc_data = ACC_CFG_REGMD | ACC_CFG_INTLVL;
++              if(WriteByte_ACC(adap, ACC_CFG, *acc_data))
++                      return -ENODEV;
++
++                      // set INTMSK
++              *acc_data = 0xFE;
++              if(WriteByte_ACC(adap, ACC_INTMSK, *acc_data))
++                      return -ENODEV;
++
++                      // set CTRL0
++              *acc_data = ACC_CTRL0_CGAUTO;
++              if(WriteByte_ACC(adap, ACC_CTRL0, *acc_data))
++                      return -ENODEV;
++
++                      // write PAGESEL
++              *acc_data = 0x1;
++              if(WriteByte_ACC(adap, ACC_PAGESEL, *acc_data))
++                      return -ENODEV;
++
++              acc_probe(&pbmi_lcd.acc[slot], slot);
++
++      } else {
++              printk(KERN_INFO "bmi_lcd.c: probe slot %d hardware version =  0x%x (accelerometer not supported)\n", slot, bdev->epraw.revision_msb);
++      }
++#endif        // ACCELEROMETER
++
++              // reset serial link (master)
++      if((slot == 0) || (slot == 2)) {
++        bmi_lcd_inactive(0);
++      } else {
++        bmi_lcd_inactive(1);
++      }
++
++              // configure GPIO
++              // turn LED's on
++      bmi_set_module_gpio_data(slot, 3, 0);   // Red LED=ON
++      bmi_set_module_gpio_data(slot, 2, 0);   // Green LED=ON
++
++              // assert reset
++      bmi_set_module_gpio_data(slot, 1, 0);   // RST=0
++
++              // set GPIO direction
++      bmi_set_module_gpio_dir(slot, 3, BMI_GPIO_OUT);
++      bmi_set_module_gpio_dir(slot, 2, BMI_GPIO_OUT);
++      bmi_set_module_gpio_dir(slot, 1, BMI_GPIO_OUT);
++      bmi_set_module_gpio_dir(slot, 0, BMI_GPIO_IN);  // real-time pen int state
++
++      mdelay(200);
++
++              // turn LED's off
++      bmi_set_module_gpio_data(slot, 3, 1);   // Red LED=OFF
++      bmi_set_module_gpio_data(slot, 2, 1);   // Green LED=OFF
++
++              // deassert reset (module)
++      bmi_set_module_gpio_data(slot, 1, 1);   // RST=1
++
++      mdelay(500);
++
++              // unreset serial link (master)
++      if((slot == 0) || (slot == 2)) {
++              mdelay(2);
++              bmi_lcd_active(0, 0x0, LCD_MODE_I80);
++      } else {
++              mdelay(2);
++              bmi_lcd_active(1, 0x0, LCD_MODE_I80);
++      }
++
++
++                      // set up bdev/pbmi_lcd pointers
++      bmi_device_set_drvdata(bdev, &pbmi_lcd);
++      pbmi_lcd.bdev[slot] = bdev;
++
++      // spi set-up
++      if (bmi_device_spi_setup(bdev, 2000000, SPI_MODE_2, 32)) {
++        printk(KERN_ERR "bmi_lcd.c: Unable to setup spi%d\n", slot);
++        bmi_device_set_drvdata(bdev, NULL);
++        pbmi_lcd.bdev[slot] = NULL;
++        bmi_slot_power_off(slot);
++        return -EFAULT;
++      }
++
++      bmi_slot_spi_enable(slot);
++      pbmi_lcd.spi[slot] = bmi_device_get_spi(bdev);
++
++
++              // check spi access and enable touch screen
++      memset(buf, 0, 4);
++      buf[3] = SPI_START | SPI_PD;
++      if(spi_lcd_write_reg(&pbmi_lcd, buf, 1, slot) != 1) {
++              printk(KERN_WARNING "bmi_lcd.c: Unable set-up spi for bmi_lcd %d\n", slot);
++              bmi_device_set_drvdata(bdev, NULL);
++              pbmi_lcd.bdev[slot] = NULL;
++              pbmi_lcd.spi[slot] = NULL;
++              bmi_device_spi_cleanup(bdev);
++              bmi_slot_spi_disable(slot);
++              bmi_slot_power_off(slot);
++              return -EFAULT;
++      }
++
++
++      // complete pbmi_lcd set-up
++      pbmi_lcd.lcd_cnt++;
++      pbmi_lcd.active = 1;
++      pbmi_lcd.activated[slot] = 1;
++
++
++      mdelay(100);
++
++      lcd = pbmi_lcd.blcd[slot];
++      if((slot == 0) || (slot == 2)) {
++              mdelay(2);
++              bmi_lcd_config(lcd, 0);
++              mdelay(2);
++      } else {
++              mdelay(2);
++              bmi_lcd_config(lcd, 1);
++              mdelay(2);
++      }
++
++
++                      // request input event interrupt handler
++      pbmi_lcd.interrupt[0] = M1_IRQ;
++      pbmi_lcd.interrupt[1] = M2_IRQ;
++      pbmi_lcd.interrupt[2] = M3_IRQ;
++      pbmi_lcd.interrupt[3] = M4_IRQ;
++      snprintf(pbmi_lcd.int_name, sizeof(pbmi_lcd.int_name), "bmi_lcd%d", slot);
++      if (request_irq(pbmi_lcd.interrupt[slot], &module_irq_handler, 0, pbmi_lcd.int_name, &pbmi_lcd)) {
++        printk( KERN_ERR "bmi_lcd.c: Can't allocate irq %d or find lcd in slot %d\n", pbmi_lcd.interrupt[slot], slot);
++        bmi_device_set_drvdata(bdev, NULL);
++        pbmi_lcd.bdev[slot] = NULL;
++        pbmi_lcd.spi[slot] = NULL;
++        bmi_device_spi_cleanup(bdev);
++        bmi_slot_power_off(slot);
++        return -EBUSY;
++      }
++
++              // check GPIO status
++      printk(KERN_INFO "bmi_lcd.c: slot %d gpio = %x\n", slot, bmi_read_gpio_data_reg(slot));
++      printk(KERN_INFO "bmi_lcd.c: LCD count = %d\n", pbmi_lcd.lcd_cnt);
++
++      return 0;
++}
++
++extern struct delayed_work bmilcd_work0;
++extern struct delayed_work bmilcd_work1;
++extern struct delayed_work bmilcd_work2;
++extern struct delayed_work bmilcd_work3;
++
++      // remove
++void bmi_lcd_remove(struct bmi_device *bdev)
++{
++      int slot = bdev->info->slot;
++
++      if(pbmi_lcd.activated[slot] == 0)
++          return;
++
++      switch(slot) {
++              case 0:
++                      cancel_delayed_work(&bmilcd_work0);
++                      break;
++              case 1:
++                      cancel_delayed_work(&bmilcd_work1);
++                      break;
++              case 2:
++                      cancel_delayed_work(&bmilcd_work2);
++                      break;
++              case 3:
++                      cancel_delayed_work(&bmilcd_work3);
++                      break;
++      }
++      lcd_ctl_remove(&pbmi_lcd.ctl_dev[slot], slot);
++
++      free_irq(pbmi_lcd.interrupt[slot], &pbmi_lcd);
++
++      bmi_set_module_gpio_dir (slot, 3, BMI_GPIO_IN);
++      bmi_set_module_gpio_dir (slot, 2, BMI_GPIO_IN);
++      bmi_set_module_gpio_dir (slot, 1, BMI_GPIO_IN);
++      bmi_set_module_gpio_dir (slot, 0, BMI_GPIO_IN);
++
++              // bmi/spi clean-up
++      bmi_device_spi_cleanup(bdev);
++      pbmi_lcd.spi[slot] = NULL;
++      bmi_slot_spi_disable(slot);
++
++              //de-attach driver-specific struct from bmi_device structure
++      bmi_device_set_drvdata (bdev, NULL);
++
++              // deactivate
++      pbmi_lcd.activated[slot] = 0;
++      pbmi_lcd.bdev[slot] = 0;
++      pbmi_lcd.lcd_cnt--;
++
++      if((pbmi_lcd.activated[0] == 0) && (pbmi_lcd.activated[2] == 0)) {
++              bmi_lcd_inactive(0); // disable serializer
++      }
++
++      if((pbmi_lcd.activated[1] == 0) && (pbmi_lcd.activated[3] == 0)) {
++              bmi_lcd_inactive(1); // disable serializer
++      }
++
++      if((pbmi_lcd.activated[0] == 0) && (pbmi_lcd.activated[1] == 0) &&
++              (pbmi_lcd.activated[2] == 0) && (pbmi_lcd.activated[3] == 0)) {
++              pbmi_lcd.active = -1;
++      }
++
++              // enable LCD on opposite side
++      switch(slot) {
++              case 0:
++                      if(pbmi_lcd.bdev[2] != 0)
++                              bmi_lcd_probe(pbmi_lcd.bdev[2]);
++                      break;
++              case 1:
++                      if(pbmi_lcd.bdev[3] != 0)
++                              bmi_lcd_probe(pbmi_lcd.bdev[3]);
++                      break;
++              case 2:
++                      if(pbmi_lcd.bdev[0] != 0)
++                              bmi_lcd_probe(pbmi_lcd.bdev[0]);
++                      break;
++              case 3:
++                      if(pbmi_lcd.bdev[1] != 0)
++                              bmi_lcd_probe(pbmi_lcd.bdev[1]);
++                      break;
++      }
++
++#ifdef ACCELEROMETER
++      acc_remove(&pbmi_lcd.acc[slot], slot);
++#endif
++      printk(KERN_INFO "bmi_lcd.c: LCD count = %d\n", pbmi_lcd.lcd_cnt);
++
++      return;
++}
++
++/*
++ * Input interrupt handler and support routines
++ */
++
++static void update_pen_state(void *arg, int slot, int x, int y, int pressure)
++{
++  struct pbmi_lcd *pbmi_lcd = (struct pbmi_lcd *)arg;
++  int sync = 0;
++
++  if (pressure)
++    {
++      if((slot == 0) || (slot == 2))
++      {
++        input_report_abs(pbmi_lcd->input_dev[BMI_TS_M13], ABS_Y, y);
++        input_report_abs(pbmi_lcd->input_dev[BMI_TS_M13], ABS_X, x);
++        input_report_abs(pbmi_lcd->input_dev[BMI_TS_M13], ABS_PRESSURE, pressure);
++      }
++      else
++      {
++        input_report_abs(pbmi_lcd->input_dev[BMI_TS_M24], ABS_Y, y);
++        input_report_abs(pbmi_lcd->input_dev[BMI_TS_M24], ABS_X, x);
++        input_report_abs(pbmi_lcd->input_dev[BMI_TS_M24], ABS_PRESSURE, pressure);
++      }
++
++      if (!pbmi_lcd->pen_down[slot])
++      {
++        if((slot == 0) || (slot == 2))
++          {
++            input_report_key(pbmi_lcd->input_dev[BMI_TS_M13], BTN_TOUCH, 1);
++          }
++        else
++          {
++            input_report_key(pbmi_lcd->input_dev[BMI_TS_M24], BTN_TOUCH, 1);
++          }
++
++      }
++      sync = 1;
++    }
++  else if (pbmi_lcd->pen_down[slot])
++    {
++      if((slot == 0) || (slot == 2))
++      {
++        input_report_key(pbmi_lcd->input_dev[BMI_TS_M13], BTN_TOUCH, 0);
++        input_report_abs(pbmi_lcd->input_dev[BMI_TS_M13], ABS_PRESSURE, 0);
++      }
++      else
++      {
++        input_report_key(pbmi_lcd->input_dev[BMI_TS_M24], BTN_TOUCH, 0);
++        input_report_abs(pbmi_lcd->input_dev[BMI_TS_M24], ABS_PRESSURE, 0);
++      }
++      sync = 1;
++    }
++
++  if (sync)
++    {
++      if((slot == 0) || (slot == 2))
++      {
++        input_sync(pbmi_lcd->input_dev[BMI_TS_M13]);
++      }
++      else
++      {
++        input_sync(pbmi_lcd->input_dev[BMI_TS_M24]);
++      }
++    }
++  pbmi_lcd->pen_down[slot] = pressure ? 1 : 0;
++
++}
++
++
++void bmilcd_input_work(void *arg, int slot);
++
++void bmilcd_input_work0(struct work_struct * work) {
++      bmilcd_input_work(&pbmi_lcd, 0);
++}
++
++void bmilcd_input_work1(struct work_struct * work) {
++      bmilcd_input_work(&pbmi_lcd, 1);
++}
++
++void bmilcd_input_work2(struct work_struct * work) {
++      bmilcd_input_work(&pbmi_lcd, 2);
++}
++
++void bmilcd_input_work3(struct work_struct * work) {
++  bmilcd_input_work(&pbmi_lcd, 3);
++}
++
++DECLARE_DELAYED_WORK(bmilcd_work0, bmilcd_input_work0);
++DECLARE_DELAYED_WORK(bmilcd_work1, bmilcd_input_work1);
++DECLARE_DELAYED_WORK(bmilcd_work2, bmilcd_input_work2);
++DECLARE_DELAYED_WORK(bmilcd_work3, bmilcd_input_work3);
++
++// work handler
++void bmilcd_input_work(void *arg, int slot) {
++      struct pbmi_lcd         *pbmi_lcd = (struct pbmi_lcd *)arg;
++#if defined ACCELEROMETER
++      struct i2c_adapter      *adap = &pbmi_lcd->bdev[slot]->adap;
++      unsigned char           acc_data[1];
++      static int              pitch = 0;
++      static int              roll = 0;
++      static int gx = 0;
++      static int gy = 0;
++
++#endif        // ACCELEROMETER
++      unsigned char           buf[4];
++      int                     x = 0;
++      int                     y = 0;
++      int                     z1 = 0;
++      int                     z2 = 0;
++      int                     pressure = 0;
++      int                     debounce;
++      int penirq;
++
++#if defined DEBUG
++      printk(KERN_INFO "bmi_lcd.c: bmi_lcd_input work (slot %d)\n", slot);
++#endif
++
++      if(pbmi_lcd->bdev[slot] == 0) {
++              printk(KERN_INFO "bmi_lcd.c: bmi_lcd_input work called with no bdev active (slot %d)\n", slot);
++              return;
++      }
++
++#if defined ACCELEROMETER
++      if(pbmi_lcd->bdev[slot]->epraw.revision_msb >= 0x12) {
++
++                      // orientation
++                      // read ROLL
++              if(ReadByte_ACC(adap, ACC_ROLLH, acc_data))
++                      goto touch;
++              roll = (0x0000 | *acc_data) << 8;
++
++              if(ReadByte_ACC(adap, ACC_ROLLL, acc_data))
++                      goto touch;
++              roll = roll | *acc_data;
++                      // read PITCH
++              if(ReadByte_ACC(adap, ACC_PITCHH, acc_data))
++                      goto touch;
++              pitch = (0x0000 | *acc_data) << 8;
++
++              if(ReadByte_ACC(adap, ACC_PITCHL, acc_data))
++                      goto touch;
++              pitch = pitch | *acc_data;
++
++
++
++
++              if(ReadByte_ACC(adap, ACC_GAZH, acc_data))
++                 goto touch;
++              pbmi_lcd->acc[slot].sample[0] = *acc_data;
++
++              if(ReadByte_ACC(adap, ACC_GAZL, acc_data))
++                 goto touch;
++              pbmi_lcd->acc[slot].sample[1] = *acc_data;
++
++              if(ReadByte_ACC(adap, ACC_GAYH, acc_data))
++                 goto touch;
++              pbmi_lcd->acc[slot].sample[2] = *acc_data;
++              gy = *acc_data << 8;
++
++              if(ReadByte_ACC(adap, ACC_GAYL, acc_data))
++                 goto touch;
++              pbmi_lcd->acc[slot].sample[3] = *acc_data;
++              gy = gy | *acc_data;
++
++              if(ReadByte_ACC(adap, ACC_GAXH, acc_data))
++                 goto touch;
++              pbmi_lcd->acc[slot].sample[4] = *acc_data;
++              gx = *acc_data << 8;
++
++              if(ReadByte_ACC(adap, ACC_GAXL, acc_data))
++                 goto touch;
++              pbmi_lcd->acc[slot].sample[5] = *acc_data;
++              gx = gx | *acc_data;
++
++              //wake up any read's
++              pbmi_lcd->acc[slot].flag = 1;
++              wake_up_interruptible(&pbmi_lcd->acc[slot].wq);
++
++              // read STATUS
++              if(ReadByte_ACC(adap, ACC_STATUS, acc_data))
++                      goto touch;
++
++              if((*acc_data & 0x1) == 0) {
++
++                              // write PAGESEL
++                      *acc_data = 0x0;
++                      if(WriteByte_ACC(adap, ACC_PAGESEL, *acc_data))
++                              goto touch;
++
++                              // read INTRQ
++                      if(ReadByte_ACC(adap, ACC_INTRQ, acc_data))
++                              goto touch;
++              }
++
++                      // write PAGESEL
++              *acc_data = 0x1;
++              if(WriteByte_ACC(adap, ACC_PAGESEL, *acc_data))
++                      goto touch;
++
++                      // report orientation
++              // printk(KERN_INFO "bmi_lcd.c: bmi_lcd_input work (slot %d) pitch=0x%x, roll=0x%x, ABS_MISC=0x%x\n",
++                      // slot, pitch, roll, pitch << 16 | roll);      //pjg - debug
++
++              input_report_abs(pbmi_lcd->input_dev[slot], ABS_MISC, (pitch << 16) | roll);
++              input_sync(pbmi_lcd->input_dev[slot]);
++      }
++#endif        // ACCELEROMETER
++
++
++      // read touch screen - X, Y, TOUCH, PRESSURE
++ touch:
++      penirq = bmi_slot_status_irq_state(slot);
++      /*printk(KERN_INFO "bmi_lcd.c: IRQ Status %d (slot %d) %d\n", penirq, slot,msecs_to_jiffies(10));*/
++
++      if (pbmi_lcd->activated[slot] && penirq)
++        {
++
++          for(debounce = 0; debounce < DEBOUNCE; debounce++)
++            {
++
++              memset(buf, 0, 4);
++              buf[3] = SPI_START | SPI_AY | SPI_MODE_12 | SPI_MODE_DFR | SPI_ADC;
++              spi_lcd_read_reg(pbmi_lcd, buf, 1, slot);
++              y = (((buf[0] << 5) | buf[1] >> 3)) & 0xFFF;
++
++              memset(buf, 0, 4);
++              buf[3] = SPI_START | SPI_AX | SPI_MODE_12 | SPI_MODE_DFR | SPI_ADC;
++              spi_lcd_read_reg(pbmi_lcd, buf, 1, slot);
++              x = (((buf[0] << 5) | buf[1]) >> 3) & 0xFFF;
++
++              memset(buf, 0, 4);
++              buf[3] = SPI_START | SPI_AZ1 | SPI_MODE_12 | SPI_MODE_DFR | SPI_ADC;
++              spi_lcd_read_reg(pbmi_lcd, buf, 1, slot);
++              z1 = (((buf[0] << 5) | buf[1]) >> 3) & 0xFFF;
++
++              memset(buf, 0, 4);
++              buf[3] = SPI_START | SPI_AZ2 | SPI_MODE_12 | SPI_MODE_DFR | SPI_ADC;
++              spi_lcd_read_reg(pbmi_lcd, buf, 1, slot);
++              z2 = (((buf[0] << 5) | buf[1]) >> 3) & 0xFFF;
++              mdelay(1);
++            }
++
++          if(x && y && z1 && z2)
++            pressure = (X_PLATE * x / 4096) * ((z2 / z1) - 1);
++
++          x = 4096 - x;
++          y = 4096 - y;
++
++          if (pressure < 70)
++            {
++              if (pbmi_lcd->scount)
++                update_pen_state(arg, slot, x, y, pressure);
++              else
++                {
++                  pbmi_lcd->scount[slot]++;
++                  /*update_pen_state(arg, slot, 0, 0, pressure);*/
++                }
++            }
++
++          switch(slot)
++            {
++            case BMI_TS_M1:
++              schedule_delayed_work(&bmilcd_work0, WORK_DELAY);
++              break;
++            case BMI_TS_M2:
++              schedule_delayed_work(&bmilcd_work1, WORK_DELAY);
++              break;
++            case BMI_TS_M3:
++              schedule_delayed_work(&bmilcd_work2, WORK_DELAY);
++              break;
++            case BMI_TS_M4:
++              schedule_delayed_work(&bmilcd_work3, WORK_DELAY);
++              break;
++            }
++          /* printk(KERN_INFO "bmi_lcd.c: work scheduled on (slot %d)\n", slot); */
++          /*buf[3] = SPI_START | SPI_PD;
++            spi_lcd_write_reg(pbmi_lcd, buf, 1, slot);*/
++        }
++
++      else
++        {
++          /*printk(KERN_INFO "bmi_lcd.c: Pen up on (slot %d)\n", slot);*/
++          memset(buf, 0, 4);
++          buf[3] = SPI_START | SPI_PD;
++          spi_lcd_write_reg(pbmi_lcd, buf, 1, slot);
++          update_pen_state(arg,slot, 0, 0, 0);
++          enable_irq(pbmi_lcd->interrupt[slot]);
++        }
++
++}
++
++
++// interrupt handler
++static irqreturn_t module_irq_handler(int irq, void *dummy)
++{
++  disable_irq_nosync(irq);
++  /*printk(KERN_INFO "bmi_lcd.c: Interupt on (slot %d)\n", irq);*/
++  switch(irq)
++    {
++    case M1_IRQ:
++      schedule_delayed_work(&bmilcd_work0, WORK_DELAY);
++      pbmi_lcd.scount[BMI_TS_M1] = 0;
++      break;
++    case M2_IRQ:
++      schedule_delayed_work(&bmilcd_work1, WORK_DELAY);
++      pbmi_lcd.scount[BMI_TS_M2] = 0;
++      break;
++    case M3_IRQ:
++      schedule_delayed_work(&bmilcd_work2, WORK_DELAY);
++      pbmi_lcd.scount[BMI_TS_M3] = 0;
++      break;
++    case M4_IRQ:
++      schedule_delayed_work(&bmilcd_work3, WORK_DELAY);
++      pbmi_lcd.scount[BMI_TS_M4] = 0;
++      break;
++    }
++  return IRQ_HANDLED;
++}
++
++
++      // BMI LCD fops
++void bmi_lcd_config(struct bmi_lcd *lcd, int disp)
++{
++      if(pbmi_lcd.active == -1) {
++              return;
++      }
++
++      if((lcd) && (lcd->lcd_ops.config)) {
++              lcd->lcd_ops.config(disp);
++      }
++}
++
++void bmi_lcd_reset(struct bmi_lcd *lcd, int slot)
++{
++      if(pbmi_lcd.active == -1) {
++              return;
++      }
++
++      if((lcd) && (lcd->lcd_ops.reset)) {
++              lcd->lcd_ops.reset(slot);
++      }
++}
++
++int register_bmi_lcd(struct bmi_lcd *lcd, int slot)   //pjg - placeholder for multiple LCD types
++{
++      if(!lcd) {
++              return -1;
++      }
++      if((slot < 0) || (slot > 3)) {
++              return -1;
++      }
++      if(pbmi_lcd.blcd[slot]) {
++              return -1;
++      }
++      else {
++              pbmi_lcd.blcd[slot] = lcd;
++      }
++
++      if(lcd->lcd_ops.activate) {
++              lcd->lcd_ops.activate(lcd, slot);
++      }
++
++      return 0;
++}
++
++int unregister_bmi_lcd(struct bmi_lcd *lcd, int slot) //pjg - placeholder for multiple LCD types
++{
++      if (!lcd) {
++              return -1;
++      }
++      if ((slot < 0) || (slot > 3)) {
++              return -1;
++      }
++      if (pbmi_lcd.blcd[slot] != lcd) {
++              return -1;
++      }
++      else {
++              pbmi_lcd.blcd [slot] = 0;
++              lcd->lcd_ops.deactivate(lcd, slot);
++      }
++      return 0;
++}
++
++/*
++ *    Module functions
++ */
++
++char const input_name0[MAX_STRG] = "bmi_lcd_ts0";
++char const input_name1[MAX_STRG] = "bmi_lcd_ts1";
++char const input_name2[MAX_STRG] = "bmi_lcd_ts2";
++char const input_name3[MAX_STRG] = "bmi_lcd_ts3";
++char const input_name4[MAX_STRG] = "bmi_lcd_ts4";
++char const input_name5[MAX_STRG] = "bmi_lcd_ts5";
++char const input_name6[MAX_STRG] = "bmi_lcd_ts6";
++
++static __init int bmi_lcd_init(void)
++{
++      int ts;
++      int rc = 0;
++
++              // No lcd is active.
++      pbmi_lcd.active = -1;
++      pbmi_lcd.activated[0] = 0;
++      pbmi_lcd.activated[1] = 0;
++      pbmi_lcd.activated[2] = 0;
++      pbmi_lcd.activated[3] = 0;
++
++              // set up control character device - bmi_lcd_control
++      rc = lcd_ctl_init();
++      if(rc) {
++              printk(KERN_ERR "bmi_lcd.c: Can't allocate bmi_lcd_control device\n");
++              return rc;
++      }
++
++              // Allocate and Register input device. - bmi_lcd_ts[BMI_TS_M1:BMI_TS_M1234]
++      for(ts = BMI_TS_M1; ts < BMI_TS_NUM; ts++) {
++              pbmi_lcd.input_dev[ts] = input_allocate_device();
++              if(!pbmi_lcd.input_dev[ts]) {
++                      printk(KERN_ERR "bmi_lcd_init: Can't allocate input_dev[ts]\n");
++                      return -ENOMEM;
++              }
++
++              // set up input device
++              switch(ts) {
++                  case BMI_TS_M1:
++                      pbmi_lcd.input_dev[BMI_TS_M1]->name = input_name0;
++                      pbmi_lcd.input_dev[BMI_TS_M1]->phys = input_name0;
++                      break;
++                  case BMI_TS_M2:
++                      pbmi_lcd.input_dev[BMI_TS_M2]->name = input_name1;
++                      pbmi_lcd.input_dev[BMI_TS_M2]->phys = input_name1;
++                      break;
++                  case BMI_TS_M3:
++                      pbmi_lcd.input_dev[BMI_TS_M3]->name = input_name2;
++                      pbmi_lcd.input_dev[BMI_TS_M3]->phys = input_name2;
++                      break;
++                  case BMI_TS_M4:
++                      pbmi_lcd.input_dev[BMI_TS_M4]->name = input_name3;
++                      pbmi_lcd.input_dev[BMI_TS_M4]->phys = input_name3;
++                      break;
++                  case BMI_TS_M13:
++                      pbmi_lcd.input_dev[BMI_TS_M13]->name = input_name4;
++                      pbmi_lcd.input_dev[BMI_TS_M13]->phys = input_name4;
++                      break;
++                  case BMI_TS_M24:
++                      pbmi_lcd.input_dev[BMI_TS_M24]->name = input_name5;
++                      pbmi_lcd.input_dev[BMI_TS_M24]->phys = input_name5;
++                      break;
++                  case BMI_TS_M1234:
++                      pbmi_lcd.input_dev[BMI_TS_M1234]->name = input_name6;
++                      pbmi_lcd.input_dev[BMI_TS_M1234]->phys = input_name6;
++                      break;
++              }
++              pbmi_lcd.input_dev[ts]->id.bustype = BUS_BMI;
++              //pbmi_lcd.input_dev[ts]->private = &pbmi_lcd;
++              pbmi_lcd.input_dev[ts]->evbit[BIT_WORD(EV_KEY)] |= BIT_MASK(EV_KEY);
++              pbmi_lcd.input_dev[ts]->evbit[BIT_WORD(EV_ABS)] |= BIT_MASK(EV_ABS);
++              pbmi_lcd.input_dev[ts]->keybit[BIT_WORD(BTN_TOUCH)] |= BIT_MASK(BTN_TOUCH);
++              pbmi_lcd.input_dev[ts]->absbit[BIT_WORD(ABS_X)] |= BIT_MASK(ABS_X);
++              pbmi_lcd.input_dev[ts]->absbit[BIT_WORD(ABS_Y)] |= BIT_MASK(ABS_Y);
++              pbmi_lcd.input_dev[ts]->absbit[BIT_WORD(ABS_PRESSURE)] |= BIT_MASK(ABS_PRESSURE);
++              pbmi_lcd.input_dev[ts]->absbit[BIT_WORD(ABS_MISC)] |= BIT_MASK(ABS_MISC);
++              input_set_abs_params(pbmi_lcd.input_dev[ts], ABS_X, BMI_LCD_MIN_XC, BMI_LCD_MAX_XC, 0, 0);
++              input_set_abs_params(pbmi_lcd.input_dev[ts], ABS_Y, BMI_LCD_MIN_YC, BMI_LCD_MAX_YC, 0, 0);
++              input_set_abs_params(pbmi_lcd.input_dev[ts], ABS_PRESSURE, 0, 1024, 0, 0);
++
++              // register input device
++              if(input_register_device(pbmi_lcd.input_dev[ts])) {
++                int tts;
++                      printk(KERN_ERR "bmi_lcd_init() - input_register_device failed.\n");
++
++                      for(tts = BMI_TS_M1; tts < ts; tts++)
++                              input_unregister_device(pbmi_lcd.input_dev[tts]);
++
++                      lcd_ctl_clean();
++
++                      return -ENODEV;
++              }
++      }
++
++      pbmi_lcd.lcd_cnt = 0;
++
++              // hardware specfic set-up
++      s320x240_bmi_lcd.interface = s320x240_lcd_interface,
++      s320x240_bmi_lcd_ops.config = (void(*)) &s320x240_config;
++      s320x240_bmi_lcd_ops.reset = NULL;      //pjg - placeholder for multiple LCD hardware types
++      s320x240_bmi_lcd_ops.suspend = NULL;    //pjg - placeholder for multiple LCD hardware types
++      s320x240_bmi_lcd_ops.resume = NULL;     //pjg - placeholder for multiple LCD hardware types
++      s320x240_bmi_lcd_ops.disp_on = NULL;    //pjg - placeholder for multiple LCD hardware types
++      s320x240_bmi_lcd_ops.disp_off = NULL;   //pjg - placeholder for multiple LCD hardware types
++      s320x240_bmi_lcd_ops.activate = NULL;   //pjg - placeholder for multiple LCD hardware types
++      s320x240_bmi_lcd_ops.deactivate = NULL; //pjg - placeholder for multiple LCD hardware types
++      s320x240_bmi_lcd.lcd_ops = s320x240_bmi_lcd_ops;
++      pbmi_lcd.blcd[0] = &s320x240_bmi_lcd;
++      pbmi_lcd.blcd[1] = &s320x240_bmi_lcd;
++      pbmi_lcd.blcd[2] = &s320x240_bmi_lcd;
++      pbmi_lcd.blcd[3] = &s320x240_bmi_lcd;
++
++      sema_init(&pbmi_lcd.sem[0], 1);
++      sema_init(&pbmi_lcd.sem[1], 1);
++      sema_init(&pbmi_lcd.sem[2], 1);
++      sema_init(&pbmi_lcd.sem[3], 1);
++
++
++#ifdef ACCELEROMETER
++      acc_init();
++#endif
++      /*s320x240_config(0);
++        s320x240_config(1);*/
++
++      // register with BMI
++      rc = bmi_register_driver(&bmi_lcd_driver);
++      if(rc) {
++              printk(KERN_ERR "bmi_lcd.c: Can't register bmi_lcd_driver\n");
++
++              for(ts = BMI_TS_M1; ts < BMI_TS_NUM; ts++)
++                      input_unregister_device(pbmi_lcd.input_dev[ts]);
++
++              lcd_ctl_clean();
++
++              return rc;
++      }
++
++      printk("bmi_lcd.c: BMI_LCD Driver v%s \n", BMILCD_VERSION);
++
++      return 0;
++}
++
++static void __exit bmi_lcd_clean(void)
++{
++      int ts;
++
++              // delete timers
++      del_timer(&pbmi_lcd.timer[0]);
++      del_timer(&pbmi_lcd.timer[1]);
++      del_timer(&pbmi_lcd.timer[2]);
++      del_timer(&pbmi_lcd.timer[3]);
++
++              // remove input devices
++      for(ts = BMI_TS_M1; ts < BMI_TS_NUM; ts++)
++              input_unregister_device(pbmi_lcd.input_dev[ts]);
++
++              // remove control device
++      lcd_ctl_clean();
++
++              // remove bmi driver
++      bmi_unregister_driver(&bmi_lcd_driver);
++
++#ifdef ACCELEROMETER
++      acc_clean();
++#endif
++        return;
++}
++
++module_init(bmi_lcd_init);
++module_exit(bmi_lcd_clean);
++
++// Exported symbols
++EXPORT_SYMBOL(register_bmi_lcd);
++EXPORT_SYMBOL(unregister_bmi_lcd);
++
++
++MODULE_AUTHOR("Peter Giacomini <p.giacomini@encadis.com>");
++MODULE_DESCRIPTION("BMI lcd device driver");
++MODULE_SUPPORTED_DEVICE("bmi_lcd_control");
++MODULE_SUPPORTED_DEVICE("bmi_lcd_ts");
++MODULE_SUPPORTED_DEVICE("bmi_lcd_acc");
++MODULE_LICENSE("GPL");
+--- /dev/null
++++ git/drivers/bmi/pims/lcd/bmi_lcd_inf.c
+@@ -0,0 +1,1775 @@
++/*
++ *    bmi_lcd.c
++ *
++ *    BMI LCD device driver
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*
++ * Include files
++ */
++
++#include <linux/input.h>
++#include <linux/kernel.h>
++#include <linux/major.h>
++#include <linux/module.h>
++#include <linux/fs.h>
++#include <linux/cdev.h>
++#include <linux/delay.h>
++#include <linux/jiffies.h>
++#include <linux/timer.h>
++#include <linux/i2c.h>
++#include <linux/spi/spi.h>
++#include <asm/uaccess.h>
++#include <linux/device.h>
++#include <linux/interrupt.h>
++#include <linux/miscdevice.h>
++
++#include <asm/irq.h>
++#include <asm/io.h>
++#include <asm/system.h>
++#include <mach/mxc_i2c.h>
++#include <mach/mx31bug_cpld.h>
++#include <linux/bmi.h>
++#include <linux/bmi/bmi-control.h>
++#include <linux/bmi/bmi-slot.h>
++#include <linux/bmi/bmi_lcd.h>
++#include <mach/ipu.h>
++
++#undef ACCELEROMETER
++#define ACCELEROMETER
++
++#ifdef ACCELEROMETER
++#include "acc.h"
++#endif //ACCELEROMETER
++
++#define DEBUG
++#undef DEBUG
++
++#define BMILCD_VERSION                "1.2"           // driver version
++#define BUF_MAX_SIZE          0x20            // spi buffer size
++#define WORK_DELAY            (1)             // interrupt work handler delay
++#define DEBOUNCE              10              // touch screen debounce
++#define X_PLATE                       400             // touch screen X plate resistance //pjg - This is not the correct value
++#define BMI_SLOT_NUM          (4)             // number of BMI slots
++#define MAX_STRG              (40)            // Max string buffer size
++
++#define       VSYNC_DISABLE           0x0
++#define       VSYNC_ENABLE            0x1
++
++      // lcd
++struct lcd_interface {
++      char                    lcd_type[MAX_STRG];     // text description of LCD type
++      u8                      suspended;              // power management state
++      u8                      rotation;               // screen rotation
++      u8                      disp;                   // display number (DISP0 or DISP1)
++      u8                      addr_mode;              // display addressing mode
++      u8                      vsync_mode;             // VSYNC signal enable (VSYNC_ENABLE | VSYNC_DISABLE)
++      u8                      bus_if_type;            // bus type (XY | FullWoBE | FullWithBE)
++      ipu_adc_sig_cfg_t       adc_sig;                // IPU ADC set-up parameters
++      ipu_di_signal_cfg_t     di_sig;                 // IPU DI set-up parameters
++};
++
++static struct lcd_interface s320x240_lcd_interface = {
++      .lcd_type = "MXCFB_SHARP_320X240",
++      .suspended = 0,
++      .rotation = IPU_ROTATE_NONE,
++      .disp = DISP0,
++      .vsync_mode = VSYNC_DISABLE,
++      .bus_if_type = XY,
++      .adc_sig = { 0, 0, 0, 0, 0, 0, 0, 0, IPU_ADC_BURST_WCS, IPU_ADC_IFC_MODE_SYS80_TYPE2,
++                      16, 0, 0, IPU_ADC_SER_NO_RW },
++      .di_sig = { 0,0,0,0,0,0,0,0 },          //pjg - reserved for multiple LCD driver
++};
++
++
++struct bmi_lcd;
++
++struct bmi_lcd_ops {
++      void *(*config) (int disp);                             // LCD configuration/initialization
++      void *(*reset) (int slot);                              // LCD reset
++      int *(*suspend) (struct bmi_lcd *blcd);                 // power management
++      int *(*resume) (struct bmi_lcd *blcd);                  // power management
++      int *(*disp_on) (int disp);                             // display on
++      int *(*disp_off) (int disp);                            // display off
++      int (*activate) (struct bmi_lcd *lcd, int slot);        // enable LCD backlight, touchscreen, accelerometer, ...
++      int (*deactivate) (struct bmi_lcd *lcd, int slot);      // disable LCD backlight, touchscreen, accelerometer, ...
++};
++
++
++struct bmi_lcd {
++      struct lcd_interface interface;         // pointer to this struct is returned by config()
++      struct bmi_lcd_ops lcd_ops;             // function pointers
++};
++
++
++int register_bmi_lcd(struct bmi_lcd *blcd, int slot);
++int unregister_bmi_lcd(struct bmi_lcd *blcd, int slot);
++
++      // private device structure
++struct pbmi_lcd
++{
++      int                     open_flag;                              // force single open
++      unsigned int            lcd_cnt;                                // number of LCD's present
++      unsigned int            active;                                 // indication of LCD presence
++      unsigned int            activated[BMI_SLOT_NUM];                // indication of LCD presence
++
++      struct bmi_lcd          *blcd[BMI_SLOT_NUM];                    // BMI LCD structure - placeholder for multiple display types
++      struct bmi_device       *bdev[BMI_SLOT_NUM];                    // BMI device per slot
++      unsigned int            interrupt[BMI_SLOT_NUM];                // input device interrupt handlers
++      char                    int_name[MAX_STRG];                     // interrupt name
++
++      struct input_dev        *input_dev[BMI_TS_NUM];                 // input device (touch screen and accelerometer)
++      struct timer_list       timer[BMI_SLOT_NUM];                    // touch timer
++
++  int pen_down[BMI_SLOT_NUM];
++  int scount[BMI_SLOT_NUM];
++
++      struct spi_device       *spi[BMI_SLOT_NUM];                     // touch screen device interface
++      struct semaphore        sem[BMI_SLOT_NUM];                      // spi semaphore
++      char                    rbuf[BMI_SLOT_NUM][BUF_MAX_SIZE];       // spi read buffer
++      char                    wbuf[BMI_SLOT_NUM][BUF_MAX_SIZE];       // spi write buffer
++
++#ifdef ACCELEROMETER
++  struct acc_dev             acc[BMI_SLOT_NUM];
++#endif
++};
++
++static struct pbmi_lcd pbmi_lcd;      // LCD device sructure
++
++/*
++ *    BMI set up
++ */
++
++      // BMI device ID table
++static struct bmi_device_id bmi_lcd_tbl[] =
++{
++      {
++              .match_flags = BMI_DEVICE_ID_MATCH_VENDOR | BMI_DEVICE_ID_MATCH_PRODUCT,
++              .vendor   = BMI_VENDOR_BUG_LABS,
++              .product  = BMI_PRODUCT_LCD_SHARP_320X240,
++              .revision = BMI_ANY,
++      },
++      { 0, },                                   /* terminate list */
++};
++
++MODULE_DEVICE_TABLE(bmi, bmi_lcd_tbl);
++
++/*printk(KERN_INFO "MDT: 0x%x\n", __mod_bmi_device_table);*/
++
++int   bmi_lcd_probe(struct bmi_device *bdev);
++void  bmi_lcd_remove(struct bmi_device *bdev);
++
++// BMI driver structure
++static struct bmi_driver bmi_lcd_driver =
++{
++      .name = "bmi_lcd",
++      .id_table = bmi_lcd_tbl,
++      .probe   = bmi_lcd_probe,
++      .remove  = bmi_lcd_remove,
++};
++
++//Accelerometer driver structure
++
++
++/*
++ *    I2C set up
++ */
++
++      // I2C Slave Address
++#define BMI_IOX_I2C_ADDRESS   0x71    // 7-bit address
++#define BMI_ACC_I2C_ADDRESS   0x17    // 7-bit address
++
++      // I2C IOX register addresses
++#define IOX_INPUT_REG         0x0     // IOX input data register
++#define IOX_OUTPUT_REG                0x1     // IOX output data register
++#define IOX_POLARITY_REG      0x2     // IOX polarity data register
++#define IOX_CONTROL           0x3     // IOX direction control register
++#define IOX_B1                        (0)     // bit 0 - backlight control
++#define IOX_A1_A2             (1)     // bit 1 - backlight control
++#define IOX_ACC_RST_N         (2)     // bit 2 - acceleromter reset
++#define IOX_VSYNC_EN_N                (3)     // bit 3 - VSYNC output buffer enable
++#define IOX_LCD_RST_N         (4)     // bit 4 - LCD reset
++#define IOX_SERDES_PD_N               (5)     // bit 5 - SERDES power down
++#define IOX_X_INT             (6)     // bit 6 - accelerometer interrupt
++#define IOX_Y_INT             (7)     // bit 7 - accelerometer interrupt
++
++      // I2C ACC register addresses - OKI
++#define ACC_PAGESEL                   0x1E    // device ready status
++      // page 0
++#define ACC_DVRST                     0x01    // device reset
++      #define ACC_DVRST_RST           0x3C    // device reset
++      #define ACC_DVRST_EN            0xC3    // device enable
++#define ACC_PDWN                      0x02    // osc power down
++      #define ACC_PWDN_RST            0x01    // device reset
++      #define ACC_PWDN_EN             0x00    // device enable
++#define ACC_CTRL0                     0x03    // control 0
++      #define ACC_CTRL0_CTSTR         0x40    // control 0 - temp sensor
++      #define ACC_CTRL0_CGSTRNC       0x08    // control 0 - 3-axis/no tilt
++      #define ACC_CTRL0_CGSTRC        0x04    // control 0 - 3-axis/tilt
++      #define ACC_CTRL0_CGAUTO        0x01    // control 0 - auto
++#define ACC_MODE0                     0x05    // control 0
++      #define ACC_MODE0_PDOFF         0x80    // mode 0 - disable auto power down
++      #define ACC_MODE0_RVOFF         0x40    // mode 0 - disable temp compensation
++      #define ACC_MODE0_TMPOFF        0x20    // mode 0 - disable temp measurement
++      #define ACC_MODE0_AGCON         0x10    // mode 0 - enable auto mode pitch and roll
++      #define ACC_MODE0_MAUTO         0x04    // mode 0 - enable auto termination
++      #define ACC_MODE0_GDET00        0x00    // mode 0 - g detection threshold - see ML8953 data sheet
++      #define ACC_MODE0_GDET01        0x01    // mode 0 - g detection threshold - see ML8953 data sheet
++      #define ACC_MODE0_GDET10        0x02    // mode 0 - g detection threshold - see ML8953 data sheet
++#define ACC_MODE1                     0x06    // mode 1
++      #define ACC_MODE1_MOFF          0x20    // mode 1 - disable 3-axis continuous mode
++      #define ACC_MODE1_ZAXIS         0x03    // mode 1 - Z axis
++      #define ACC_MODE1_YAXIS         0x02    // mode 1 - Y axis
++      #define ACC_MODE1_XAXIS         0x01    // mode 1 - X axis
++      #define ACC_MODE1_RAXIS         0x00    // mode 1 - Reference axis
++#define ACC_INTRQ                     0x07    // interrupt request (1 = request)
++#define ACC_INTMSK                    0x08    // interrupt mask (1 = masked)
++      #define ACC_INT_TREQ            0x20    // interrupt - temperature
++      #define ACC_INT_GREQ            0x08    // interrupt - acceleration/no tilt
++      #define ACC_INT_GCREQ           0x04    // interrupt - acceleration/tilt
++      #define ACC_INT_GAREQ           0x01    // interrupt - automatic
++#define ACC_TMDL                      0x09    // timer LSB = (1/6.2 MHz) x 2048 x TMD
++#define ACC_TMDH                      0x0A    // timer MSB
++#define ACC_CFG                               0x0C    // configuration
++      #define ACC_CFG_REGMD           0x80    // address auto-increment
++      #define ACC_CFG_SPI3M_3         0x40    // spi mode = 3-wire
++      #define ACC_CFG_SPI3M_4         0x00    // spi mode = 4-wire
++      #define ACC_CFG_SDOCFG_T        0x10    // sdo mode = totem-pole
++      #define ACC_CFG_SDOCFG_OC       0x00    // sdo mode = open-drain
++      #define ACC_CFG_INT1EN_G        0x08    // interrupt 1 mode = g only
++      #define ACC_CFG_INT1EN_ALL      0x00    // interrupt 1 mode = all
++      #define ACC_CFG_INTLVL          0x04    // interrupt level mode
++      #define ACC_CFG_INT1CFG_T       0x02    // interrupt 1 mode = totem-pole
++      #define ACC_CFG_INT1CFG_OC      0x00    // interrupt 1 mode = open-drain
++      #define ACC_CFG_INT0CFG_T       0x01    // interrupt 0 mode = totem-pole
++      #define ACC_CFG_INT0CFG_OC      0x00    // interrupt 0 mode = open-drain
++#define ACC_INTOTM                    0x0D    // interrupt output conditions
++#define ACC_GAAVE                     0x0E    // Data averaging - automatic mode
++#define ACC_GNAVE                     0x0F    // Data averaging - normal mode
++#define ACC_GDTCT0L                   0x11    // threshold 0 LSB
++#define ACC_GDTCT0H                   0x12    // threshold 0 MSB
++#define ACC_GDTCT1L                   0x13    // threshold 1 LSB
++#define ACC_GDTCT1H                   0x14    // threshold 1 MSB
++#define ACC_CPURDY                    0x15    // device ready status (ready = 0x01)
++      // page 1
++#define ACC_STATUS                    0x01    // measurment status
++      #define ACC_STATUS_ASTS         0x02    // acceleration measurement - automatic modes
++      #define ACC_STATUS_STS          0x01    // acceleration measurement - non-automatic modes
++#define ACC_GAXL                      0x02    // g vector
++#define ACC_GAXH                      0x03    // g vector
++#define ACC_GAYL                      0x04    // g vector
++#define ACC_GAYH                      0x05    // g vector
++#define ACC_GAZL                      0x06    // g vector
++#define ACC_GAZH                      0x07    // g vector
++#define ACC_GASVL                     0x08    // g vector
++#define ACC_GASVH                     0x09    // g vector
++#define ACC_GNXL                        0x0A    // g vector
++#define ACC_GNXH                        0x0B    // g vector
++#define ACC_GNYL                        0x0C    // g vector
++#define ACC_GNYH                        0x0D    // g vector
++#define ACC_GNZL                        0x0E    // g vector
++#define ACC_GNZH                        0x0F    // g vector
++#define ACC_GNSVL                     0x10    // g vector
++#define ACC_GNSVH                     0x11    // g vector
++#define ACC_PITCHL                    0x12    // pitch
++#define ACC_PITCHH                    0x13    // pitch
++#define ACC_ROLLL                     0x14    // roll
++#define ACC_ROLLH                     0x15    // roll
++#define ACC_TEMPL                     0x19    // temperature
++#define ACC_TEMPH                     0x1A    // temperature
++
++      // read byte from I2C IO expander
++static int ReadByte_IOX(struct i2c_adapter *adap, unsigned char offset, unsigned char *data)
++{
++              int     ret = 0;
++              struct i2c_msg rmsg[2];
++              int     num_msgs;
++              int retries = 0;
++
++              /* Read Byte with Pointer */
++
++              rmsg[0].addr = BMI_IOX_I2C_ADDRESS;
++              rmsg[0].flags = 0;        /* write */
++              rmsg[0].len = 1;
++              rmsg[0].buf = &offset;
++
++              rmsg[1].addr = BMI_IOX_I2C_ADDRESS;
++              rmsg[1].flags = I2C_M_RD;   /* read */
++              rmsg[1].len = 1;
++              rmsg[1].buf = data;
++
++              num_msgs = 2;
++
++              while (retries < 5)
++                {
++                  ret = i2c_transfer (adap, rmsg, num_msgs);
++                  if (ret == 2)
++                    break;
++                  else
++                    retries++;
++                }
++
++              if (ret == 2) {
++                      ret = 0;
++              }
++              else {
++                      printk (KERN_ERR "ReadByte_IOX() - i2c_transfer() failed.\n");
++                      ret = -1;
++              }
++              return ret;
++}
++
++      // write byte to I2C IO expander
++static int WriteByte_IOX(struct i2c_adapter *adap, unsigned char offset, unsigned char data)
++{
++              int     ret = 0;
++              struct i2c_msg wmsg[2];
++              int     num_msgs;
++
++              /* Write Byte with Pointer */
++
++              wmsg[0].addr = BMI_IOX_I2C_ADDRESS;
++              wmsg[0].flags = 0;      /* write */
++              wmsg[0].len = 1;
++              wmsg[0].buf = &offset;
++
++              wmsg[1].addr = BMI_IOX_I2C_ADDRESS;
++              wmsg[1].flags = 0;      /* write */
++              wmsg[1].len = 1;
++              wmsg[1].buf = &data;
++
++              num_msgs = 2;
++
++              ret = i2c_transfer (adap, wmsg, num_msgs);
++
++              if (ret == 2) {
++                      ret = 0;
++              }
++              else {
++                      printk (KERN_ERR "WriteByte_IOX() - i2c_transfer() failed.\n");
++                      ret = -1;
++              }
++              return ret;
++}
++
++
++#if defined ACCELEROMETER
++      // read byte from I2C acceleromter
++static int ReadByte_ACC(struct i2c_adapter *adap, unsigned char offset, unsigned char *data)
++{
++              int     ret = 0;
++              struct i2c_msg rmsg[2];
++              int     num_msgs;
++              int retries = 0;
++
++              /* Read Byte with Pointer */
++
++              rmsg[0].addr = BMI_ACC_I2C_ADDRESS;
++              rmsg[0].flags = 0;        /* write */
++              rmsg[0].len = 1;
++              rmsg[0].buf = &offset;
++
++              rmsg[1].addr = BMI_ACC_I2C_ADDRESS;
++              rmsg[1].flags = I2C_M_RD;   /* read */
++              rmsg[1].len = 1;
++              rmsg[1].buf = data;
++
++              num_msgs = 2;
++
++              while (retries < 5)
++                {
++                  ret = i2c_transfer (adap, rmsg, num_msgs);
++                  if (ret == 2)
++                    break;
++                  else
++                    retries++;
++                  mdelay(1);
++                }
++
++              if (ret == 2) {
++                      ret = 0;
++              }
++              else {
++                      printk (KERN_ERR "ReadByte_ACC() - i2c_transfer() failed.\n");
++                      ret = -1;
++              }
++              return ret;
++}
++
++static int ReadByteLock_ACC(struct pbmi_lcd *priv, unsigned char offset, unsigned char *data, int slot)
++{
++              int     ret = 0;
++              struct i2c_msg rmsg[2];
++              int     num_msgs;
++              int retries = 0;
++
++              /* Read Byte with Pointer */
++
++              rmsg[0].addr = BMI_ACC_I2C_ADDRESS;
++              rmsg[0].flags = 0;        /* write */
++              rmsg[0].len = 1;
++              rmsg[0].buf = &offset;
++
++              rmsg[1].addr = BMI_ACC_I2C_ADDRESS;
++              rmsg[1].flags = I2C_M_RD;   /* read */
++              rmsg[1].len = 1;
++              rmsg[1].buf = data;
++
++              num_msgs = 2;
++
++              while (retries < 5)
++                {
++                  ret = i2c_transfer (adap, rmsg, num_msgs);
++                  if (ret == 2)
++                    break;
++                  else
++                    retries++;
++                  mdelay(1);
++                }
++
++              if (ret == 2) {
++                      ret = 0;
++              }
++              else {
++                      printk (KERN_ERR "ReadByte_ACC() - i2c_transfer() failed.\n");
++                      ret = -1;
++              }
++              return ret;
++}
++
++      // write byte to I2C accelerometer
++static int WriteByte_ACC(struct i2c_adapter *adap, unsigned char offset, unsigned char data)
++{
++              int     ret = 0;
++              struct i2c_msg wmsg[2];
++              int     num_msgs;
++
++              /* Write Byte with Pointer */
++
++              wmsg[0].addr = BMI_ACC_I2C_ADDRESS;
++              wmsg[0].flags = 0;      /* write */
++              wmsg[0].len = 1;
++              wmsg[0].buf = &offset;
++
++              wmsg[1].addr = BMI_ACC_I2C_ADDRESS;
++              wmsg[1].flags = 0;      /* write */
++              wmsg[1].len = 1;
++              wmsg[1].buf = &data;
++
++              num_msgs = 2;
++
++              ret = i2c_transfer (adap, wmsg, num_msgs);
++
++              if (ret == 2) {
++                      ret = 0;
++              }
++              else {
++                      printk (KERN_ERR "WriteByte_ACC() - i2c_transfer() failed.\n");
++                      ret = -1;
++              }
++              return ret;
++}
++#endif        // ACCELEROMETER
++
++/*
++ *    SPI functions
++ */
++
++      // TSC2046 touch screen controller command register bit definitons
++#define SPI_START     0x80    // command start
++#define SPI_AT0               0x00    // read temperature - not supported
++#define SPI_AY                0x10    // read Y
++#define SPI_ABAT      0x20    // read battery - not supported
++#define SPI_AZ1               0x30    // read Z1
++#define SPI_AZ2               0x40    // read Z2
++#define SPI_AX                0x50    // read X
++#define SPI_AAUX      0x60    // read AUX - not supported
++#define SPI_AT1               0x70    // read temperature - not supported
++#define SPI_MODE_12   0x00    // 12-bit mode - Preferred
++#define SPI_MODE_8    0x08    // 8-bit mode
++#define SPI_MODE_DFR  0x00    // differential mode - Preferred
++#define SPI_MODE_SER  0x04    // single ended mode
++#define SPI_PD                0x00    // power down - PENIRQ enabled
++#define SPI_ADC               0x01    // ADC enabled
++#define SPI_REF               0x02    // Vref enabled - unused
++#define SPI_REF_ADC   0x03    // Vref & ADC enabled - unused
++
++      // spi access
++static int spi_rw(struct spi_device *spi, u8 * buf, size_t len)
++{
++      struct spi_transfer t = {
++              .tx_buf = (const void *)buf,
++              .rx_buf = buf,
++              .len = len,
++              .cs_change = 0,
++              .delay_usecs = 0,
++      };
++      struct spi_message m;
++
++      spi_message_init(&m);
++
++      spi_message_add_tail(&t, &m);
++      if (spi_sync(spi, &m) != 0 || m.status != 0)
++              return -1;
++
++      return m.actual_length;
++}
++
++      // spi write register
++static ssize_t spi_lcd_write_reg(struct pbmi_lcd *priv, char *buf, int len, int slot)
++{
++      int res = 0;
++
++      down(&priv->sem[slot]);
++
++      memset(priv->wbuf[slot], 0, BUF_MAX_SIZE);
++      priv->wbuf[slot][0] = buf[0];
++      priv->wbuf[slot][1] = buf[1];
++      priv->wbuf[slot][2] = buf[2];
++      priv->wbuf[slot][3] = buf[3];
++      res = spi_rw(priv->spi[slot], priv->wbuf[slot], len);
++      if (res != 1) {
++              up(&priv->sem[slot]);
++              return -EFAULT;
++      }
++
++      up(&priv->sem[slot]);
++
++      return res;
++}
++
++      // spi read register
++static ssize_t spi_lcd_read_reg(struct pbmi_lcd *priv, char *buf, int len, int slot)
++{
++      int res = 0;
++
++      down(&priv->sem[slot]);
++
++      memset(priv->wbuf[slot], 0, BUF_MAX_SIZE);
++      priv->wbuf[slot][0] = buf[0];
++      priv->wbuf[slot][1] = buf[1];
++      priv->wbuf[slot][2] = buf[2];
++      priv->wbuf[slot][3] = buf[3];
++      res = spi_rw(priv->spi[slot], priv->wbuf[slot], len);
++      if (res != 1) {
++              up(&priv->sem[slot]);
++              return -EFAULT;
++      }
++
++      memset(priv->rbuf[slot], 0, BUF_MAX_SIZE);
++      buf[0] = priv->wbuf[slot][2];
++      buf[1] = priv->wbuf[slot][1];
++
++      up(&priv->sem[slot]);
++
++      return res;
++}
++
++/*
++ *    BMI functions
++ */
++
++static irqreturn_t module_irq_handler(int irq, void *dummy);
++void bmi_lcd_config(struct bmi_lcd *lcd, int disp);
++
++      // probe
++int bmi_lcd_probe(struct bmi_device *bdev)
++{
++#if defined ACCELEROMETER
++      unsigned char acc_data[1];
++#endif        // ACCELEROMETER
++      unsigned char iox_data[1];
++      int slot = bdev->info->slot;
++      struct i2c_adapter *adap;
++      struct bmi_lcd *lcd;
++      char buf[4];
++      /*int first_time = 1;*/
++
++      printk(KERN_INFO "bmi_lcd.c: probe slot %d\n", slot);
++
++              // check for opposite side already active
++      switch(slot) {  // opposite side
++              case 0:
++                      if(pbmi_lcd.activated[2] == 1) {
++                              printk(KERN_INFO "bmi_lcd.c: probe slot %d not allowed (slot 2 already active)\n", slot);
++                              bmi_slot_power_off(0);
++                              /*bmi_slot_power_off(2);*/
++                              pbmi_lcd.bdev[0] = bdev;
++                              /*bdev = pbmi_lcd.bdev[2];
++                              slot = 2;
++                              first_time = 0;*/
++                              return 0;
++                      }
++                      break;
++              case 1:
++                      if(pbmi_lcd.activated[3] == 1) {
++                              printk(KERN_INFO "bmi_lcd.c: probe slot %d not allowed (slot 3 already active)\n", slot);
++                              bmi_slot_power_off(1);
++                              /*bmi_slot_power_off(3);*/
++                              pbmi_lcd.bdev[1] = bdev;
++                              /*bdev = pbmi_lcd.bdev[3];
++                              slot = 3;
++                              first_time = 0;*/
++                              return 0;
++                      }
++                      break;
++              case 2:
++                      if(pbmi_lcd.activated[0] == 1) {
++                              printk(KERN_INFO "bmi_lcd.c: probe slot %d not allowed (slot 0 already active)\n", slot);
++                              bmi_slot_power_off(2);
++                              /*bmi_slot_power_off(0);*/
++                              pbmi_lcd.bdev[2] = bdev;
++                              /*bdev = pbmi_lcd.bdev[0];
++                              slot = 0;
++                              first_time = 0;*/
++                              return 0;
++                      }
++                      break;
++              case 3:
++                      if(pbmi_lcd.activated[1] == 1) {
++                              printk(KERN_INFO "bmi_lcd.c: probe slot %d not allowed (slot 1 already active)\n", slot);
++                              bmi_slot_power_off(3);
++                              /*bmi_slot_power_off(1);*/
++                              pbmi_lcd.bdev[3] = bdev;
++                              /*bdev = pbmi_lcd.bdev[1];
++                              slot = 1;
++                              first_time = 0;*/
++                              return 0;
++                      }
++                      break;
++      }
++
++      adap = &bdev->adap;
++      bmi_slot_power_on(slot);
++
++      mdelay(500);
++
++              // configure IOX
++              // [7:6]=interrupts, [5]=SER_PD*, [4]=LCD_RST*, [3]=VSYNC_OE*, [2]=ACC_RST*, [1:0]=backlight
++      if(WriteByte_IOX(adap, IOX_OUTPUT_REG, 0xFF))   // normal - no accelerometer interrupts
++              return -ENODEV;
++
++              // normal operation - no accelerometer interrupts
++      if(WriteByte_IOX(adap, IOX_CONTROL, 0x00))      // IOX[7:0]=OUT
++              return -ENODEV;
++
++              // clear interrupts
++      if(ReadByte_IOX(adap, IOX_INPUT_REG, iox_data))
++              return -ENODEV;
++
++      printk(KERN_INFO "bmi_lcd.c: probe slot %d iox data =  %x\n", slot, *iox_data);
++
++#if defined ACCELEROMETER
++              // accelerometer
++      printk(KERN_INFO "bmi_lcd.c: probe slot %d hardware version =  0x%x\n", slot, bdev->epraw.revision_msb);
++
++              // check for PCB revision >= 1.2
++      if(bdev->epraw.revision_msb >= 0x12) {
++
++                      // normal IOX operation - accelerometer interrupts
++              if(WriteByte_IOX(adap, IOX_CONTROL, 0xC0))      // IOX[7:6]=IN, IOX[5:0]=OUT
++                      return -ENODEV;
++
++              if(WriteByte_IOX(adap, IOX_OUTPUT_REG, 0xFB))   // reset OKI accelerometer
++                      return -ENODEV;
++
++              mdelay(2);
++
++              if(WriteByte_IOX(adap, IOX_OUTPUT_REG, 0xFF))   // enable OKI accelerometer
++                      return -ENODEV;
++
++              mdelay(2);
++
++                      // write PAGESEL
++              *acc_data = 0x0;
++              if(WriteByte_ACC(adap, ACC_PAGESEL, *acc_data))
++                      return -ENODEV;
++
++                      // read device to verify existance
++              if(ReadByte_ACC(adap, ACC_CPURDY, acc_data))
++                      return -ENODEV;
++
++                      // set TMD = 0x300 (~250 ms)
++              *acc_data = 0x5;
++              if(WriteByte_ACC(adap, ACC_TMDH, *acc_data))
++                      return -ENODEV;
++
++              *acc_data = 0x0;
++              if(WriteByte_ACC(adap, ACC_TMDL, *acc_data))
++                      return -ENODEV;
++
++                      // set INTOTM
++              *acc_data = 0x00;
++              if(WriteByte_ACC(adap, ACC_INTOTM, *acc_data))
++                      return -ENODEV;
++
++                      // set GxAVE
++              *acc_data = 0x0;
++              if(WriteByte_ACC(adap, ACC_GAAVE, *acc_data))
++                      return -ENODEV;
++
++                      // set GDTCT[01]
++              *acc_data = 0x00;
++              if(WriteByte_ACC(adap, ACC_GDTCT0L, *acc_data))
++                      return -ENODEV;
++
++              *acc_data = 0x00;
++              if(WriteByte_ACC(adap, ACC_GDTCT0H, *acc_data))
++                      return -ENODEV;
++
++              *acc_data = 0x00;
++              if(WriteByte_ACC(adap, ACC_GDTCT1L, *acc_data))
++                      return -ENODEV;
++
++              *acc_data = 0x00;
++              if(WriteByte_ACC(adap, ACC_GDTCT1H, *acc_data))
++                      return -ENODEV;
++
++                      // set MODE0
++              *acc_data = ACC_MODE0_PDOFF | ACC_MODE0_TMPOFF | ACC_MODE0_AGCON | ACC_MODE0_MAUTO | ACC_MODE0_GDET10;
++              if(WriteByte_ACC(adap, ACC_MODE0, *acc_data))
++                      return -ENODEV;
++
++                      // set CFG
++              *acc_data = ACC_CFG_REGMD | ACC_CFG_INTLVL;
++              if(WriteByte_ACC(adap, ACC_CFG, *acc_data))
++                      return -ENODEV;
++
++                      // set INTMSK
++              *acc_data = 0xFE;
++              if(WriteByte_ACC(adap, ACC_INTMSK, *acc_data))
++                      return -ENODEV;
++
++                      // set CTRL0
++              *acc_data = ACC_CTRL0_CGAUTO;
++              if(WriteByte_ACC(adap, ACC_CTRL0, *acc_data))
++                      return -ENODEV;
++
++                      // write PAGESEL
++              *acc_data = 0x1;
++              if(WriteByte_ACC(adap, ACC_PAGESEL, *acc_data))
++                      return -ENODEV;
++
++              acc_probe(&pbmi_lcd.acc[slot], slot);
++
++      } else {
++              printk(KERN_INFO "bmi_lcd.c: probe slot %d hardware version =  0x%x (accelerometer not supported)\n", slot, bdev->epraw.revision_msb);
++      }
++#endif        // ACCELEROMETER
++
++              // reset serial link (master)
++      if((slot == 0) || (slot == 2)) {
++        bmi_lcd_inactive(0);
++      } else {
++        bmi_lcd_inactive(1);
++      }
++
++              // configure GPIO
++              // turn LED's on
++      bmi_set_module_gpio_data(slot, 3, 0);   // Red LED=ON
++      bmi_set_module_gpio_data(slot, 2, 0);   // Green LED=ON
++
++              // assert reset
++      bmi_set_module_gpio_data(slot, 1, 0);   // RST=0
++
++              // set GPIO direction
++      bmi_set_module_gpio_dir(slot, 3, BMI_GPIO_OUT);
++      bmi_set_module_gpio_dir(slot, 2, BMI_GPIO_OUT);
++      bmi_set_module_gpio_dir(slot, 1, BMI_GPIO_OUT);
++      bmi_set_module_gpio_dir(slot, 0, BMI_GPIO_IN);  // real-time pen int state
++
++      mdelay(200);
++
++              // turn LED's off
++      bmi_set_module_gpio_data(slot, 3, 1);   // Red LED=OFF
++      bmi_set_module_gpio_data(slot, 2, 1);   // Green LED=OFF
++
++              // deassert reset (module)
++      bmi_set_module_gpio_data(slot, 1, 1);   // RST=1
++
++      mdelay(500);
++
++              // unreset serial link (master)
++      if((slot == 0) || (slot == 2)) {
++              mdelay(2);
++              bmi_lcd_active(0, 0x0, LCD_MODE_I80);
++      } else {
++              mdelay(2);
++              bmi_lcd_active(1, 0x0, LCD_MODE_I80);
++      }
++
++
++                      // set up bdev/pbmi_lcd pointers
++      bmi_device_set_drvdata(bdev, &pbmi_lcd);
++      pbmi_lcd.bdev[slot] = bdev;
++
++      // spi set-up
++      if (bmi_device_spi_setup(bdev, 2000000, SPI_MODE_2, 32)) {
++        printk(KERN_ERR "bmi_lcd.c: Unable to setup spi%d\n", slot);
++        bmi_device_set_drvdata(bdev, NULL);
++        pbmi_lcd.bdev[slot] = NULL;
++        bmi_slot_power_off(slot);
++        return -EFAULT;
++      }
++
++      bmi_slot_spi_enable(slot);
++      pbmi_lcd.spi[slot] = bmi_device_get_spi(bdev);
++
++
++              // check spi access and enable touch screen
++      memset(buf, 0, 4);
++      buf[3] = SPI_START | SPI_PD;
++      if(spi_lcd_write_reg(&pbmi_lcd, buf, 1, slot) != 1) {
++              printk(KERN_WARNING "bmi_lcd.c: Unable set-up spi for bmi_lcd %d\n", slot);
++              bmi_device_set_drvdata(bdev, NULL);
++              pbmi_lcd.bdev[slot] = NULL;
++              pbmi_lcd.spi[slot] = NULL;
++              bmi_device_spi_cleanup(bdev);
++              bmi_slot_spi_disable(slot);
++              bmi_slot_power_off(slot);
++              return -EFAULT;
++      }
++
++
++      // complete pbmi_lcd set-up
++      pbmi_lcd.lcd_cnt++;
++      pbmi_lcd.active = 1;
++      pbmi_lcd.activated[slot] = 1;
++
++
++      mdelay(100);
++
++      lcd = pbmi_lcd.blcd[slot];
++      if((slot == 0) || (slot == 2)) {
++              mdelay(2);
++              bmi_lcd_config(lcd, 0);
++              mdelay(2);
++      } else {
++              mdelay(2);
++              bmi_lcd_config(lcd, 1);
++              mdelay(2);
++      }
++
++
++                      // request input event interrupt handler
++      pbmi_lcd.interrupt[0] = M1_IRQ;
++      pbmi_lcd.interrupt[1] = M2_IRQ;
++      pbmi_lcd.interrupt[2] = M3_IRQ;
++      pbmi_lcd.interrupt[3] = M4_IRQ;
++      snprintf(pbmi_lcd.int_name, sizeof(pbmi_lcd.int_name), "bmi_lcd%d", slot);
++      if (request_irq(pbmi_lcd.interrupt[slot], &module_irq_handler, 0, pbmi_lcd.int_name, &pbmi_lcd)) {
++        printk( KERN_ERR "bmi_lcd.c: Can't allocate irq %d or find lcd in slot %d\n", pbmi_lcd.interrupt[slot], slot);
++        bmi_device_set_drvdata(bdev, NULL);
++        pbmi_lcd.bdev[slot] = NULL;
++        pbmi_lcd.spi[slot] = NULL;
++        bmi_device_spi_cleanup(bdev);
++        bmi_slot_power_off(slot);
++        return -EBUSY;
++      }
++
++              // check GPIO status
++      printk(KERN_INFO "bmi_lcd.c: slot %d gpio = %x\n", slot, bmi_read_gpio_data_reg(slot));
++      printk(KERN_INFO "bmi_lcd.c: LCD count = %d\n", pbmi_lcd.lcd_cnt);
++
++      return 0;
++}
++
++extern struct delayed_work bmilcd_work0;
++extern struct delayed_work bmilcd_work1;
++extern struct delayed_work bmilcd_work2;
++extern struct delayed_work bmilcd_work3;
++
++      // remove
++void bmi_lcd_remove(struct bmi_device *bdev)
++{
++      int slot = bdev->info->slot;
++
++      if(pbmi_lcd.activated[slot] == 0)
++          return;
++
++      switch(slot) {
++              case 0:
++                      cancel_delayed_work(&bmilcd_work0);
++                      break;
++              case 1:
++                      cancel_delayed_work(&bmilcd_work1);
++                      break;
++              case 2:
++                      cancel_delayed_work(&bmilcd_work2);
++                      break;
++              case 3:
++                      cancel_delayed_work(&bmilcd_work3);
++                      break;
++      }
++
++      free_irq(pbmi_lcd.interrupt[slot], &pbmi_lcd);
++
++      bmi_set_module_gpio_dir (slot, 3, BMI_GPIO_IN);
++      bmi_set_module_gpio_dir (slot, 2, BMI_GPIO_IN);
++      bmi_set_module_gpio_dir (slot, 1, BMI_GPIO_IN);
++      bmi_set_module_gpio_dir (slot, 0, BMI_GPIO_IN);
++
++              // bmi/spi clean-up
++      bmi_device_spi_cleanup(bdev);
++      pbmi_lcd.spi[slot] = NULL;
++      bmi_slot_spi_disable(slot);
++
++              //de-attach driver-specific struct from bmi_device structure
++      bmi_device_set_drvdata (&bdev[slot], 0);
++
++              // deactivate
++      pbmi_lcd.activated[slot] = 0;
++      pbmi_lcd.bdev[slot] = 0;
++      pbmi_lcd.lcd_cnt--;
++
++      if((pbmi_lcd.activated[0] == 0) && (pbmi_lcd.activated[2] == 0)) {
++              bmi_lcd_inactive(0); // disable serializer
++      }
++
++      if((pbmi_lcd.activated[1] == 0) && (pbmi_lcd.activated[3] == 0)) {
++              bmi_lcd_inactive(1); // disable serializer
++      }
++
++      if((pbmi_lcd.activated[0] == 0) && (pbmi_lcd.activated[1] == 0) &&
++              (pbmi_lcd.activated[2] == 0) && (pbmi_lcd.activated[3] == 0)) {
++              pbmi_lcd.active = -1;
++      }
++
++              // enable LCD on opposite side
++      switch(slot) {
++              case 0:
++                      if(pbmi_lcd.bdev[2] != 0)
++                              bmi_lcd_probe(pbmi_lcd.bdev[2]);
++                      break;
++              case 1:
++                      if(pbmi_lcd.bdev[3] != 0)
++                              bmi_lcd_probe(pbmi_lcd.bdev[3]);
++                      break;
++              case 2:
++                      if(pbmi_lcd.bdev[0] != 0)
++                              bmi_lcd_probe(pbmi_lcd.bdev[0]);
++                      break;
++              case 3:
++                      if(pbmi_lcd.bdev[1] != 0)
++                              bmi_lcd_probe(pbmi_lcd.bdev[1]);
++                      break;
++      }
++
++#ifdef ACCELEROMETER
++      acc_remove(&pbmi_lcd.acc[slot], slot);
++#endif
++      printk(KERN_INFO "bmi_lcd.c: LCD count = %d\n", pbmi_lcd.lcd_cnt);
++
++      return;
++}
++
++/*
++ * Input interrupt handler and support routines
++ */
++
++static void update_pen_state(void *arg, int slot, int x, int y, int pressure)
++{
++  struct pbmi_lcd *pbmi_lcd = (struct pbmi_lcd *)arg;
++  int sync = 0;
++
++  if (pressure)
++    {
++      /*input_report_abs(pbmi_lcd->input_dev[slot], ABS_X, x);
++      input_report_abs(pbmi_lcd->input_dev[slot], ABS_Y, y);
++      input_report_abs(pbmi_lcd->input_dev[slot], ABS_PRESSURE, pressure);
++
++      input_report_abs(pbmi_lcd->input_dev[BMI_TS_M1234], ABS_X, x);
++      input_report_abs(pbmi_lcd->input_dev[BMI_TS_M1234], ABS_Y, y);
++      input_report_abs(pbmi_lcd->input_dev[BMI_TS_M1234], ABS_PRESSURE, pressure);*/
++
++      if((slot == 0) || (slot == 2))
++      {
++        input_report_abs(pbmi_lcd->input_dev[BMI_TS_M13], ABS_Y, y);
++        input_report_abs(pbmi_lcd->input_dev[BMI_TS_M13], ABS_X, x);
++        input_report_abs(pbmi_lcd->input_dev[BMI_TS_M13], ABS_PRESSURE, pressure);
++      }
++      else
++      {
++        input_report_abs(pbmi_lcd->input_dev[BMI_TS_M24], ABS_Y, y);
++        input_report_abs(pbmi_lcd->input_dev[BMI_TS_M24], ABS_X, x);
++        input_report_abs(pbmi_lcd->input_dev[BMI_TS_M24], ABS_PRESSURE, pressure);
++      }
++
++      if (!pbmi_lcd->pen_down[slot])
++      {
++        /*input_report_key(pbmi_lcd->input_dev[slot], BTN_TOUCH, 1);
++          input_report_key(pbmi_lcd->input_dev[BMI_TS_M1234], BTN_TOUCH, 1);*/
++        if((slot == 0) || (slot == 2))
++          {
++            input_report_key(pbmi_lcd->input_dev[BMI_TS_M13], BTN_TOUCH, 1);
++          }
++        else
++          {
++            input_report_key(pbmi_lcd->input_dev[BMI_TS_M24], BTN_TOUCH, 1);
++          }
++
++      }
++      sync = 1;
++    }
++  else if (pbmi_lcd->pen_down[slot])
++    {
++      /*input_report_key(pbmi_lcd->input_dev[slot], BTN_TOUCH, 0);
++      input_report_abs(pbmi_lcd->input_dev[slot], ABS_PRESSURE, 0);
++
++      input_report_key(pbmi_lcd->input_dev[BMI_TS_M1234], BTN_TOUCH, 0);
++      input_report_abs(pbmi_lcd->input_dev[BMI_TS_M1234], ABS_PRESSURE, 0); */
++
++      if((slot == 0) || (slot == 2))
++      {
++        input_report_key(pbmi_lcd->input_dev[BMI_TS_M13], BTN_TOUCH, 0);
++        input_report_abs(pbmi_lcd->input_dev[BMI_TS_M13], ABS_PRESSURE, 0);
++      }
++      else
++      {
++        input_report_key(pbmi_lcd->input_dev[BMI_TS_M24], BTN_TOUCH, 0);
++        input_report_abs(pbmi_lcd->input_dev[BMI_TS_M24], ABS_PRESSURE, 0);
++      }
++      sync = 1;
++    }
++
++  if (sync)
++    {
++      /*input_sync(pbmi_lcd->input_dev[slot]);
++      input_sync(pbmi_lcd->input_dev[BMI_TS_M1234]);*/
++      if((slot == 0) || (slot == 2))
++      {
++        input_sync(pbmi_lcd->input_dev[BMI_TS_M13]);
++      }
++      else
++      {
++        input_sync(pbmi_lcd->input_dev[BMI_TS_M24]);
++      }
++    }
++  pbmi_lcd->pen_down[slot] = pressure ? 1 : 0;
++
++}
++
++
++void bmilcd_input_work(void *arg, int slot);
++
++void bmilcd_input_work0(struct work_struct * work) {
++      bmilcd_input_work(&pbmi_lcd, 0);
++}
++
++void bmilcd_input_work1(struct work_struct * work) {
++      bmilcd_input_work(&pbmi_lcd, 1);
++}
++
++void bmilcd_input_work2(struct work_struct * work) {
++      bmilcd_input_work(&pbmi_lcd, 2);
++}
++
++void bmilcd_input_work3(struct work_struct * work) {
++  bmilcd_input_work(&pbmi_lcd, 3);
++}
++
++DECLARE_DELAYED_WORK(bmilcd_work0, bmilcd_input_work0);
++DECLARE_DELAYED_WORK(bmilcd_work1, bmilcd_input_work1);
++DECLARE_DELAYED_WORK(bmilcd_work2, bmilcd_input_work2);
++DECLARE_DELAYED_WORK(bmilcd_work3, bmilcd_input_work3);
++
++// work handler
++void bmilcd_input_work(void *arg, int slot) {
++      struct pbmi_lcd         *pbmi_lcd = (struct pbmi_lcd *)arg;
++#if defined ACCELEROMETER
++      struct i2c_adapter      *adap = &pbmi_lcd->bdev[slot]->adap;
++      unsigned char           acc_data[1];
++      static int              pitch = 0;
++      static int              roll = 0;
++      static int gx = 0;
++      static int gy = 0;
++
++#endif        // ACCELEROMETER
++      unsigned char           buf[4];
++      int                     x = 0;
++      int                     y = 0;
++      int                     z1 = 0;
++      int                     z2 = 0;
++      int                     pressure = 0;
++      int                     debounce;
++      int penirq;
++
++#if defined DEBUG
++      printk(KERN_INFO "bmi_lcd.c: bmi_lcd_input work (slot %d)\n", slot);
++#endif
++
++      if(pbmi_lcd->bdev[slot] == 0) {
++              printk(KERN_INFO "bmi_lcd.c: bmi_lcd_input work called with no bdev active (slot %d)\n", slot);
++              return;
++      }
++
++#if defined ACCELEROMETER
++      if(pbmi_lcd->bdev[slot]->epraw.revision_msb >= 0x12) {
++
++                      // orientation
++                      // read ROLL
++              if(ReadByte_ACC(adap, ACC_ROLLH, acc_data))
++                      return;
++              roll = (0x0000 | *acc_data) << 8;
++
++              if(ReadByte_ACC(adap, ACC_ROLLL, acc_data))
++                      return;
++              roll = roll | *acc_data;
++                      // read PITCH
++              if(ReadByte_ACC(adap, ACC_PITCHH, acc_data))
++                      return;
++              pitch = (0x0000 | *acc_data) << 8;
++
++              if(ReadByte_ACC(adap, ACC_PITCHL, acc_data))
++                      return;
++              pitch = pitch | *acc_data;
++
++
++
++
++              if(ReadByte_ACC(adap, ACC_GAZH, acc_data))
++                 return;
++              pbmi_lcd->acc[slot].sample[0] = *acc_data;
++
++              if(ReadByte_ACC(adap, ACC_GAZL, acc_data))
++                 return;
++              pbmi_lcd->acc[slot].sample[1] = *acc_data;
++
++              if(ReadByte_ACC(adap, ACC_GAYH, acc_data))
++                 return;
++              pbmi_lcd->acc[slot].sample[2] = *acc_data;
++              gy = *acc_data << 8;
++
++              if(ReadByte_ACC(adap, ACC_GAYL, acc_data))
++                 return;
++              pbmi_lcd->acc[slot].sample[3] = *acc_data;
++              gy = gy | *acc_data;
++
++              if(ReadByte_ACC(adap, ACC_GAXH, acc_data))
++                 return;
++              pbmi_lcd->acc[slot].sample[4] = *acc_data;
++              gx = *acc_data << 8;
++
++              if(ReadByte_ACC(adap, ACC_GAXL, acc_data))
++                 return;
++              pbmi_lcd->acc[slot].sample[5] = *acc_data;
++              gx = gx | *acc_data;
++
++              //wake up any read's
++              pbmi_lcd->acc[slot].flag = 1;
++              wake_up_interruptible(&pbmi_lcd->acc[slot].wq);
++
++              // read STATUS
++              if(ReadByte_ACC(adap, ACC_STATUS, acc_data))
++                      return;
++
++              if((*acc_data & 0x1) == 0) {
++
++                              // write PAGESEL
++                      *acc_data = 0x0;
++                      if(WriteByte_ACC(adap, ACC_PAGESEL, *acc_data))
++                              return;
++
++                              // read INTRQ
++                      if(ReadByte_ACC(adap, ACC_INTRQ, acc_data))
++                              return;
++              }
++
++                      // write PAGESEL
++              *acc_data = 0x1;
++              if(WriteByte_ACC(adap, ACC_PAGESEL, *acc_data))
++                      return;
++
++                      // report orientation
++              // printk(KERN_INFO "bmi_lcd.c: bmi_lcd_input work (slot %d) pitch=0x%x, roll=0x%x, ABS_MISC=0x%x\n",
++                      // slot, pitch, roll, pitch << 16 | roll);      //pjg - debug
++
++              input_report_abs(pbmi_lcd->input_dev[slot], ABS_MISC, (pitch << 16) | roll);
++              input_sync(pbmi_lcd->input_dev[slot]);
++      }
++#endif        // ACCELEROMETER
++
++
++      // read touch screen - X, Y, TOUCH, PRESSURE
++
++      penirq = bmi_slot_status_irq_state(slot);
++      /*printk(KERN_INFO "bmi_lcd.c: IRQ Status %d (slot %d) %d\n", penirq, slot,msecs_to_jiffies(10));*/
++
++      if (pbmi_lcd->activated[slot] && penirq)
++        {
++
++          for(debounce = 0; debounce < DEBOUNCE; debounce++)
++            {
++
++              memset(buf, 0, 4);
++              buf[3] = SPI_START | SPI_AY | SPI_MODE_12 | SPI_MODE_DFR | SPI_ADC;
++              spi_lcd_read_reg(pbmi_lcd, buf, 1, slot);
++              y = (((buf[0] << 5) | buf[1] >> 3)) & 0xFFF;
++
++              memset(buf, 0, 4);
++              buf[3] = SPI_START | SPI_AX | SPI_MODE_12 | SPI_MODE_DFR | SPI_ADC;
++              spi_lcd_read_reg(pbmi_lcd, buf, 1, slot);
++              x = (((buf[0] << 5) | buf[1]) >> 3) & 0xFFF;
++
++              memset(buf, 0, 4);
++              buf[3] = SPI_START | SPI_AZ1 | SPI_MODE_12 | SPI_MODE_DFR | SPI_ADC;
++              spi_lcd_read_reg(pbmi_lcd, buf, 1, slot);
++              z1 = (((buf[0] << 5) | buf[1]) >> 3) & 0xFFF;
++
++              memset(buf, 0, 4);
++              buf[3] = SPI_START | SPI_AZ2 | SPI_MODE_12 | SPI_MODE_DFR | SPI_ADC;
++              spi_lcd_read_reg(pbmi_lcd, buf, 1, slot);
++              z2 = (((buf[0] << 5) | buf[1]) >> 3) & 0xFFF;
++              mdelay(1);
++            }
++
++          if(x && y && z1 && z2)
++            pressure = (X_PLATE * x / 4096) * ((z2 / z1) - 1);
++
++          x = 4096 - x;
++          y = 4096 - y;
++
++          if (pressure < 70)
++            {
++              if (pbmi_lcd->scount)
++                update_pen_state(arg, slot, x, y, pressure);
++              else
++                {
++                  pbmi_lcd->scount[slot]++;
++                  /*update_pen_state(arg, slot, 0, 0, pressure);*/
++                }
++            }
++          /* else
++            {
++              update_pen_state(arg, slot, 0, 0, pressure);
++              }*/
++
++              switch(slot)
++                {
++                case BMI_TS_M1:
++                  schedule_delayed_work(&bmilcd_work0, WORK_DELAY);
++                  break;
++                case BMI_TS_M2:
++                  schedule_delayed_work(&bmilcd_work1, WORK_DELAY);
++                  break;
++                case BMI_TS_M3:
++                  schedule_delayed_work(&bmilcd_work2, WORK_DELAY);
++                  break;
++                case BMI_TS_M4:
++                  schedule_delayed_work(&bmilcd_work3, WORK_DELAY);
++                  break;
++                }
++              /* printk(KERN_INFO "bmi_lcd.c: work scheduled on (slot %d)\n", slot); */
++              /*buf[3] = SPI_START | SPI_PD;
++                spi_lcd_write_reg(pbmi_lcd, buf, 1, slot);*/
++        }
++
++      else
++        {
++          /*printk(KERN_INFO "bmi_lcd.c: Pen up on (slot %d)\n", slot);*/
++          memset(buf, 0, 4);
++          buf[3] = SPI_START | SPI_PD;
++          spi_lcd_write_reg(pbmi_lcd, buf, 1, slot);
++          update_pen_state(arg,slot, 0, 0, 0);
++          enable_irq(pbmi_lcd->interrupt[slot]);
++        }
++
++}
++
++
++// interrupt handler
++static irqreturn_t module_irq_handler(int irq, void *dummy)
++{
++  disable_irq(irq);
++  /*printk(KERN_INFO "bmi_lcd.c: Interupt on (slot %d)\n", irq);*/
++  switch(irq)
++    {
++    case M1_IRQ:
++      schedule_delayed_work(&bmilcd_work0, WORK_DELAY);
++      pbmi_lcd.scount[BMI_TS_M1] = 0;
++      break;
++    case M2_IRQ:
++      schedule_delayed_work(&bmilcd_work1, WORK_DELAY);
++      pbmi_lcd.scount[BMI_TS_M2] = 0;
++      break;
++    case M3_IRQ:
++      schedule_delayed_work(&bmilcd_work2, WORK_DELAY);
++      pbmi_lcd.scount[BMI_TS_M3] = 0;
++      break;
++    case M4_IRQ:
++      schedule_delayed_work(&bmilcd_work3, WORK_DELAY);
++      pbmi_lcd.scount[BMI_TS_M4] = 0;
++      break;
++    }
++  return IRQ_HANDLED;
++}
++
++/*
++ * control device operations
++ */
++
++/*
++ * control device operations
++ */
++
++// open
++int cntl_open(struct inode *inode, struct file *filp)
++{
++      if(pbmi_lcd.open_flag) {
++              return - EBUSY;
++      }
++      pbmi_lcd.open_flag = 1;
++      filp->private_data = &pbmi_lcd;
++      return 0;
++}
++
++// release
++int cntl_release(struct inode *inode, struct file *filp)
++{
++      pbmi_lcd.open_flag = 0;
++      return 0;
++}
++
++// ioctl
++int cntl_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
++                 unsigned long arg)
++{
++      struct i2c_adapter *adap;
++      unsigned char iox_data[1];
++      int slot = (__user arg) & 0xF;
++      int bl = ((__user arg) & 0x70) >> 4;
++
++              // error if no lcd active.
++      if(pbmi_lcd.active == -1)
++              return -ENODEV;
++
++      if(cmd != BMI_LCD_GETSTAT) {
++
++                      // error if slot invalid
++              if((slot < CPLD_M1) || (slot > CPLD_M4))
++                      return -ENODEV;
++
++                      // error if no lcd in chosen slot
++              if(pbmi_lcd.bdev[slot] == 0)
++                      return -ENODEV;
++
++                      // i2c adapter
++              adap = &pbmi_lcd.bdev[slot]->adap;
++      }
++
++              // ioctl's
++      switch (cmd) {
++              case BMI_LCD_RLEDOFF:
++                      bmi_set_module_gpio_data(slot, 3, 1);// Red LED=OFF
++                      break;
++              case BMI_LCD_RLEDON:
++                      bmi_set_module_gpio_data(slot, 3, 0);// Red LED=ON
++                      break;
++              case BMI_LCD_GLEDOFF:
++                      bmi_set_module_gpio_data(slot, 2, 1);// Green LED=OFF
++                      break;
++              case BMI_LCD_GLEDON:
++                      bmi_set_module_gpio_data(slot, 2, 0);// Green LED=ON
++                      break;
++              case BMI_LCD_VSYNC_DIS: // enable VSYNC buffer tristate output
++                      if(ReadByte_IOX(adap, IOX_OUTPUT_REG, iox_data))
++                              return -ENODEV;
++                      *iox_data |= 0x08;
++                      if(WriteByte_IOX(adap, IOX_OUTPUT_REG, *iox_data))
++                              return -ENODEV;
++                      break;
++              case BMI_LCD_VSYNC_EN:  // disable VSYNC buffer tristate output
++                      if(ReadByte_IOX(adap, IOX_OUTPUT_REG, iox_data))
++                              return -ENODEV;
++                      *iox_data &= ~0x08;
++                      if(WriteByte_IOX(adap, IOX_OUTPUT_REG, *iox_data))
++                              return -ENODEV;
++                      break;
++              case BMI_LCD_EN:        // enable LCD component
++                      if(ReadByte_IOX(adap, IOX_OUTPUT_REG, iox_data))
++                              return -ENODEV;
++                      *iox_data &= ~0x10;
++                      if(WriteByte_IOX(adap, IOX_OUTPUT_REG, *iox_data))
++                              return -ENODEV;
++                      break;
++              case BMI_LCD_DIS:       // disable LCD component only
++                      if(ReadByte_IOX(adap, IOX_OUTPUT_REG, iox_data))
++                              return -ENODEV;
++                      *iox_data |= 0x10;
++                      if(WriteByte_IOX(adap, IOX_OUTPUT_REG, *iox_data))
++                              return -ENODEV;
++                      break;
++              case BMI_LCD_SER_EN:    // enable Serializer component
++                      if(ReadByte_IOX(adap, IOX_OUTPUT_REG, iox_data))
++                              return -ENODEV;
++                      *iox_data &= ~0x20;
++                      if(WriteByte_IOX(adap, IOX_OUTPUT_REG, *iox_data))
++                              return -ENODEV;
++                      break;
++              case BMI_LCD_SER_DIS:   // disable Serializer component only
++                      if(ReadByte_IOX(adap, IOX_OUTPUT_REG, iox_data))
++                              return -ENODEV;
++                      *iox_data |= 0x20;
++                      if(WriteByte_IOX(adap, IOX_OUTPUT_REG, *iox_data))
++                              return -ENODEV;
++                      break;
++              case BMI_LCD_SETRST:    // overall module reset
++                      bmi_set_module_gpio_data (slot, 1, 0);          // RST=0
++                      break;
++              case BMI_LCD_CLRRST:    // overall module enable
++                      bmi_set_module_gpio_data (slot, 1, 1);          // RST=1
++                      break;
++              case BMI_LCD_SET_BL:    // set backlight brightness
++                      if(ReadByte_IOX(adap, IOX_OUTPUT_REG, iox_data))
++                              return -ENODEV;
++                      *iox_data = (*iox_data & 0xF8) | bl;
++                      if(WriteByte_IOX(adap, IOX_OUTPUT_REG, *iox_data))
++                              return -ENODEV;
++                      break;
++              case BMI_LCD_GETSTAT:
++                      {
++                              int *slot = ((int __user *) arg);
++                              int read_data;
++
++                              *slot &= 0xF;
++
++                                      // error if slot invalid
++                              if((*slot < CPLD_M1) || (*slot > CPLD_M4))
++                                      return -ENODEV;
++
++                                      // error if no lcd in chosen slot
++                              if(pbmi_lcd.bdev[*slot] == 0)
++                                      return -ENODEV;
++
++                                      // i2c adapter
++                              adap = &pbmi_lcd.bdev[*slot]->adap;
++
++                              if(ReadByte_IOX(adap, IOX_INPUT_REG, iox_data))
++                                      return -ENODEV;
++
++                              read_data = *iox_data | (bmi_read_gpio_data_reg(*slot) << 8);
++
++                              if(put_user(read_data, (int __user *) arg))
++                                              return -EFAULT;
++                      }
++                      break;
++              case BMI_LCD_ACTIVATE:  //pjg fix/test
++                              // check for opposite side already active
++                      switch(slot) {  // opposite side
++                              case 0:
++                                      if(pbmi_lcd.activated[2] == 1) {
++                                              printk(KERN_INFO "bmi_lcd.c: probe slot %d not allowed (slot 2 already active)\n", slot);
++                                              bmi_slot_power_off(0);
++                                              return -ENODEV;
++                                      }
++                                      break;
++                              case 1:
++                                      if(pbmi_lcd.activated[3] == 1) {
++                                              printk(KERN_INFO "bmi_lcd.c: probe slot %d not allowed (slot 3 already active)\n", slot);
++                                              bmi_slot_power_off(1);
++                                              return -ENODEV;
++                                      }
++                                      break;
++                              case 2:
++                                      if(pbmi_lcd.activated[0] == 1) {
++                                              printk(KERN_INFO "bmi_lcd.c: probe slot %d not allowed (slot 0 already active)\n", slot);
++                                              bmi_slot_power_off(2);
++                                              return -ENODEV;
++                                      }
++                                      break;
++                              case 3:
++                                      if(pbmi_lcd.activated[1] == 1) {
++                                              printk(KERN_INFO "bmi_lcd.c: probe slot %d not allowed (slot 1 already active)\n", slot);
++                                              bmi_slot_power_off(3);
++                                              return -ENODEV;
++                                      }
++                                      break;
++                      }
++                              // activate
++                      if((!pbmi_lcd.activated[slot]) && (pbmi_lcd.bdev[slot] != 0)) {
++                              bmi_lcd_probe(pbmi_lcd.bdev[slot]);
++                      }
++                      break;
++              case BMI_LCD_DEACTIVATE:
++                      if(pbmi_lcd.activated[slot]) {
++                              disable_irq_nosync(pbmi_lcd.interrupt[slot]);
++                              pbmi_lcd.activated[slot] = 0;
++                              if(ReadByte_IOX(adap, IOX_OUTPUT_REG, iox_data))
++                                      return -ENODEV;
++                              *iox_data = (*iox_data & 0xF8);
++                              if(WriteByte_IOX(adap, IOX_OUTPUT_REG, *iox_data))
++                                      return -ENODEV;
++                              bmi_slot_power_off(slot);
++                      }
++                      break;
++              case BMI_LCD_SUSPEND:
++                      printk(KERN_ERR "BMI_LCD_SUSPEND NOT IMPLEMENTED\n");   //pjg
++                      break;
++              case BMI_LCD_RESUME:
++                      printk(KERN_ERR "BMI_LCD_RESUME NOT IMPLEMENTED\n");    //pjg
++                      break;
++              default:
++                      return -ENOTTY;
++      }
++      return 0;
++}
++
++      // control file operations
++struct file_operations cntl_fops = {
++      .owner = THIS_MODULE,
++      .ioctl = cntl_ioctl,
++      .open = cntl_open,
++      .release = cntl_release,
++};
++
++      // BMI LCD fops
++void bmi_lcd_config(struct bmi_lcd *lcd, int disp)
++{
++      if(pbmi_lcd.active == -1) {
++              return;
++      }
++
++      if((lcd) && (lcd->lcd_ops.config)) {
++              lcd->lcd_ops.config(disp);
++      }
++}
++
++void bmi_lcd_reset(struct bmi_lcd *lcd, int slot)
++{
++      if(pbmi_lcd.active == -1) {
++              return;
++      }
++
++      if((lcd) && (lcd->lcd_ops.reset)) {
++              lcd->lcd_ops.reset(slot);
++      }
++}
++
++int register_bmi_lcd(struct bmi_lcd *lcd, int slot)   //pjg - placeholder for multiple LCD types
++{
++      if(!lcd) {
++              return -1;
++      }
++      if((slot < 0) || (slot > 3)) {
++              return -1;
++      }
++      if(pbmi_lcd.blcd[slot]) {
++              return -1;
++      }
++      else {
++              pbmi_lcd.blcd[slot] = lcd;
++      }
++
++      if(lcd->lcd_ops.activate) {
++              lcd->lcd_ops.activate(lcd, slot);
++      }
++
++      return 0;
++}
++
++int unregister_bmi_lcd(struct bmi_lcd *lcd, int slot) //pjg - placeholder for multiple LCD types
++{
++      if (!lcd) {
++              return -1;
++      }
++      if ((slot < 0) || (slot > 3)) {
++              return -1;
++      }
++      if (pbmi_lcd.blcd[slot] != lcd) {
++              return -1;
++      }
++      else {
++              pbmi_lcd.blcd [slot] = 0;
++              lcd->lcd_ops.deactivate(lcd, slot);
++      }
++      return 0;
++}
++
++static struct miscdevice cntl_dev = {
++      MISC_DYNAMIC_MINOR,
++      "bmi_lcd_control",
++      &cntl_fops
++};
++
++/*
++ *    Module functions
++ */
++
++char const input_name0[MAX_STRG] = "bmi_lcd_ts0";
++char const input_name1[MAX_STRG] = "bmi_lcd_ts1";
++char const input_name2[MAX_STRG] = "bmi_lcd_ts2";
++char const input_name3[MAX_STRG] = "bmi_lcd_ts3";
++char const input_name4[MAX_STRG] = "bmi_lcd_ts4";
++char const input_name5[MAX_STRG] = "bmi_lcd_ts5";
++char const input_name6[MAX_STRG] = "bmi_lcd_ts6";
++
++static __init int bmi_lcd_init(void)
++{
++  int ts;
++  int rc = 0;
++
++  // No lcd is active.
++  pbmi_lcd.active = -1;
++  pbmi_lcd.activated[0] = 0;
++  pbmi_lcd.activated[1] = 0;
++  pbmi_lcd.activated[2] = 0;
++  pbmi_lcd.activated[3] = 0;
++
++  // set up control character device - bmi_lcd_control
++  rc = misc_register(&cntl_dev);
++  if(rc) {
++    printk(KERN_ERR "bmi_lcd.c: Can't allocate bmi_lcd_control device\n");
++    return rc;
++  }
++
++  // Allocate and Register input device. - bmi_lcd_ts[BMI_TS_M1:BMI_TS_M1234]
++  for(ts = BMI_TS_M1; ts < BMI_TS_NUM; ts++) {
++    pbmi_lcd.input_dev[ts] = input_allocate_device();
++    if(!pbmi_lcd.input_dev[ts]) {
++      printk(KERN_ERR "bmi_lcd_init: Can't allocate input_dev[ts]\n");
++      return -ENOMEM;
++    }
++
++    // set up input device
++    switch(ts) {
++    case BMI_TS_M1:
++      pbmi_lcd.input_dev[BMI_TS_M1]->name = input_name0;
++      pbmi_lcd.input_dev[BMI_TS_M1]->phys = input_name0;
++      break;
++    case BMI_TS_M2:
++      pbmi_lcd.input_dev[BMI_TS_M2]->name = input_name1;
++      pbmi_lcd.input_dev[BMI_TS_M2]->phys = input_name1;
++      break;
++    case BMI_TS_M3:
++      pbmi_lcd.input_dev[BMI_TS_M3]->name = input_name2;
++      pbmi_lcd.input_dev[BMI_TS_M3]->phys = input_name2;
++      break;
++    case BMI_TS_M4:
++      pbmi_lcd.input_dev[BMI_TS_M4]->name = input_name3;
++      pbmi_lcd.input_dev[BMI_TS_M4]->phys = input_name3;
++      break;
++    case BMI_TS_M13:
++      pbmi_lcd.input_dev[BMI_TS_M13]->name = input_name4;
++      pbmi_lcd.input_dev[BMI_TS_M13]->phys = input_name4;
++      break;
++    case BMI_TS_M24:
++      pbmi_lcd.input_dev[BMI_TS_M24]->name = input_name5;
++      pbmi_lcd.input_dev[BMI_TS_M24]->phys = input_name5;
++      break;
++    case BMI_TS_M1234:
++      pbmi_lcd.input_dev[BMI_TS_M1234]->name = input_name6;
++      pbmi_lcd.input_dev[BMI_TS_M1234]->phys = input_name6;
++      break;
++    }
++    pbmi_lcd.input_dev[ts]->id.bustype = BUS_BMI;
++    pbmi_lcd.input_dev[ts]->private = &pbmi_lcd;
++    pbmi_lcd.input_dev[ts]->evbit[BIT_WORD(EV_KEY)] |= BIT_MASK(EV_KEY);
++    pbmi_lcd.input_dev[ts]->evbit[BIT_WORD(EV_ABS)] |= BIT_MASK(EV_ABS);
++    pbmi_lcd.input_dev[ts]->keybit[BIT_WORD(BTN_TOUCH)] |= BIT_MASK(BTN_TOUCH);
++    pbmi_lcd.input_dev[ts]->absbit[BIT_WORD(ABS_X)] |= BIT_MASK(ABS_X);
++    pbmi_lcd.input_dev[ts]->absbit[BIT_WORD(ABS_Y)] |= BIT_MASK(ABS_Y);
++    pbmi_lcd.input_dev[ts]->absbit[BIT_WORD(ABS_PRESSURE)] |= BIT_MASK(ABS_PRESSURE);
++    pbmi_lcd.input_dev[ts]->absbit[BIT_WORD(ABS_MISC)] |= BIT_MASK(ABS_MISC);
++    input_set_abs_params(pbmi_lcd.input_dev[ts], ABS_X, BMI_LCD_MIN_XC, BMI_LCD_MAX_XC, 0, 0);
++    input_set_abs_params(pbmi_lcd.input_dev[ts], ABS_Y, BMI_LCD_MIN_YC, BMI_LCD_MAX_YC, 0, 0);
++    input_set_abs_params(pbmi_lcd.input_dev[ts], ABS_PRESSURE, 0, 1024, 0, 0);
++
++    // register input device
++    if(input_register_device(pbmi_lcd.input_dev[ts])) {
++      int tts;
++      printk(KERN_ERR "bmi_lcd_init() - input_register_device failed.\n");
++
++      for(tts = BMI_TS_M1; tts < ts; tts++)
++      input_unregister_device(pbmi_lcd.input_dev[tts]);
++
++      misc_deregister(&cntl_dev);
++
++      return -ENODEV;
++    }
++  }
++
++  pbmi_lcd.lcd_cnt = 0;
++
++  // hardware specfic set-up
++  s320x240_bmi_lcd.interface = s320x240_lcd_interface;
++  s320x240_bmi_lcd_ops.config = (void(*)) &s320x240_config;
++  s320x240_bmi_lcd_ops.reset = NULL;  //pjg - placeholder for multiple LCD hardware types
++  s320x240_bmi_lcd_ops.suspend = NULL;        //pjg - placeholder for multiple LCD hardware types
++  s320x240_bmi_lcd_ops.resume = NULL; //pjg - placeholder for multiple LCD hardware types
++  s320x240_bmi_lcd_ops.disp_on = NULL;        //pjg - placeholder for multiple LCD hardware types
++  s320x240_bmi_lcd_ops.disp_off = NULL;       //pjg - placeholder for multiple LCD hardware types
++  s320x240_bmi_lcd_ops.activate = NULL;       //pjg - placeholder for multiple LCD hardware types
++  s320x240_bmi_lcd_ops.deactivate = NULL;     //pjg - placeholder for multiple LCD hardware types
++  s320x240_bmi_lcd.lcd_ops = s320x240_bmi_lcd_ops;
++  pbmi_lcd.blcd[0] = &s320x240_bmi_lcd;
++  pbmi_lcd.blcd[1] = &s320x240_bmi_lcd;
++  pbmi_lcd.blcd[2] = &s320x240_bmi_lcd;
++  pbmi_lcd.blcd[3] = &s320x240_bmi_lcd;
++
++  sema_init(&pbmi_lcd.sem[0], 1);
++  sema_init(&pbmi_lcd.sem[1], 1);
++  sema_init(&pbmi_lcd.sem[2], 1);
++  sema_init(&pbmi_lcd.sem[3], 1);
++
++
++  acc_init();
++
++  // register with BMI
++  rc = bmi_register_driver(&bmi_lcd_driver);
++  if(rc) {
++    printk(KERN_ERR "bmi_lcd.c: Can't register bmi_lcd_driver\n");
++
++    for(ts = BMI_TS_M1; ts < BMI_TS_NUM; ts++)
++      input_unregister_device(pbmi_lcd.input_dev[ts]);
++
++    misc_deregister(&cntl_dev);
++
++    return rc;
++  }
++
++  printk("bmi_lcd.c: BMI_LCD Driver v%s \n", BMILCD_VERSION);
++
++  return 0;
++}
++
++
++static void __exit bmi_lcd_clean(void)
++{
++  int ts;
++
++  // remove input devices
++  for(ts = BMI_TS_M1; ts < BMI_TS_NUM; ts++)
++    input_unregister_device(pbmi_lcd.input_dev[ts]);
++
++  // remove control device
++  misc_deregister(&cntl_dev);
++
++  // remove bmi driver
++  bmi_unregister_driver(&bmi_lcd_driver);
++  acc_clean();
++  return;
++}
++
++module_init(bmi_lcd_init);
++module_exit(bmi_lcd_clean);
++
++// Exported symbols
++EXPORT_SYMBOL(register_bmi_lcd);
++EXPORT_SYMBOL(unregister_bmi_lcd);
++
++
++MODULE_AUTHOR("Peter Giacomini <p.giacomini@encadis.com>");
++MODULE_DESCRIPTION("BMI lcd device driver");
++MODULE_SUPPORTED_DEVICE("bmi_lcd_control");
++MODULE_SUPPORTED_DEVICE("bmi_lcd_ts");
++MODULE_SUPPORTED_DEVICE("bmi_lcd_acc");
++MODULE_LICENSE("GPL");
+--- /dev/null
++++ git/drivers/bmi/pims/lcd/bmi_lcd_mi.c
+@@ -0,0 +1,1855 @@
++/*
++ *    bmi_lcd.c
++ *
++ *    BMI LCD device driver
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*
++ * Include files
++ */
++
++#include <linux/input.h>
++#include <linux/kernel.h>
++#include <linux/major.h>
++#include <linux/module.h>
++#include <linux/fs.h>
++#include <linux/cdev.h>
++#include <linux/delay.h>
++#include <linux/jiffies.h>
++#include <linux/timer.h>
++#include <linux/i2c.h>
++#include <linux/spi/spi.h>
++#include <asm/uaccess.h>
++#include <linux/device.h>
++#include <linux/interrupt.h>
++#include <linux/miscdevice.h>
++
++#include <asm/irq.h>
++#include <asm/io.h>
++#include <asm/system.h>
++#include <mach/mxc_i2c.h>
++#include <mach/mx31bug_cpld.h>
++#include <linux/bmi.h>
++#include <linux/bmi/bmi-control.h>
++#include <linux/bmi/bmi-slot.h>
++#include <linux/bmi/bmi_lcd.h>
++#include <mach/ipu.h>
++
++#include "acc.h"
++
++
++#define DEBUG
++#undef DEBUG
++
++#define BMILCD_VERSION                "1.2"           // driver version
++#define BUF_MAX_SIZE          0x20            // spi buffer size
++#define WORK_DELAY            (1)             // interrupt work handler delay
++#define DEBOUNCE              10              // touch screen debounce
++#define X_PLATE                       400             // touch screen X plate resistance //pjg - This is not the correct value
++#define BMI_SLOT_NUM          (4)             // number of BMI slots
++#define MAX_STRG              (40)            // Max string buffer size
++
++#define       VSYNC_DISABLE           0x0
++#define       VSYNC_ENABLE            0x1
++
++      // lcd
++struct lcd_interface {
++      char                    lcd_type[MAX_STRG];     // text description of LCD type
++      u8                      suspended;              // power management state
++      u8                      rotation;               // screen rotation
++      u8                      disp;                   // display number (DISP0 or DISP1)
++      u8                      addr_mode;              // display addressing mode
++      u8                      vsync_mode;             // VSYNC signal enable (VSYNC_ENABLE | VSYNC_DISABLE)
++      u8                      bus_if_type;            // bus type (XY | FullWoBE | FullWithBE)
++      ipu_adc_sig_cfg_t       adc_sig;                // IPU ADC set-up parameters
++      ipu_di_signal_cfg_t     di_sig;                 // IPU DI set-up parameters
++};
++
++static struct lcd_interface s320x240_lcd_interface = {
++      .lcd_type = "MXCFB_SHARP_320X240",
++      .suspended = 0,
++      .rotation = IPU_ROTATE_NONE,
++      .disp = DISP0,
++      .vsync_mode = VSYNC_DISABLE,
++      .bus_if_type = XY,
++      .adc_sig = { 0, 0, 0, 0, 0, 0, 0, 0, IPU_ADC_BURST_WCS, IPU_ADC_IFC_MODE_SYS80_TYPE2,
++                      16, 0, 0, IPU_ADC_SER_NO_RW },
++      .di_sig = { 0,0,0,0,0,0,0,0 },          //pjg - reserved for multiple LCD driver
++};
++
++extern void s320x240_config(int disp);
++extern void s320x240_disp_off(int disp);
++extern void s320x240_disp_on(int disp);
++
++
++struct bmi_lcd;
++
++struct bmi_lcd_ops {
++      void *(*config) (int disp);                             // LCD configuration/initialization
++      void *(*reset) (int slot);                              // LCD reset
++      int *(*suspend) (struct bmi_lcd *blcd);                 // power management
++      int *(*resume) (struct bmi_lcd *blcd);                  // power management
++      int *(*disp_on) (int disp);                             // display on
++      int *(*disp_off) (int disp);                            // display off
++      int (*activate) (struct bmi_lcd *lcd, int slot);        // enable LCD backlight, touchscreen, accelerometer, ...
++      int (*deactivate) (struct bmi_lcd *lcd, int slot);      // disable LCD backlight, touchscreen, accelerometer, ...
++};
++
++struct bmi_lcd_ops s320x240_bmi_lcd_ops;
++
++struct bmi_lcd {
++      struct lcd_interface interface;         // pointer to this struct is returned by config()
++      struct bmi_lcd_ops lcd_ops;             // function pointers
++};
++
++static struct bmi_lcd s320x240_bmi_lcd;
++
++int register_bmi_lcd(struct bmi_lcd *blcd, int slot);
++int unregister_bmi_lcd(struct bmi_lcd *blcd, int slot);
++
++      // private device structure
++struct pbmi_lcd
++{
++      int                     open_flag;                              // force single open
++      unsigned int            lcd_cnt;                                // number of LCD's present
++      unsigned int            active;                                 // indication of LCD presence
++      unsigned int            activated[BMI_SLOT_NUM];                // indication of LCD presence
++
++      struct bmi_lcd          *blcd[BMI_SLOT_NUM];                    // BMI LCD structure - placeholder for multiple display types
++      struct bmi_device       *bdev[BMI_SLOT_NUM];                    // BMI device per slot
++      unsigned int            interrupt[BMI_SLOT_NUM];                // input device interrupt handlers
++      char                    int_name[MAX_STRG];                     // interrupt name
++
++      struct input_dev        *input_dev[BMI_TS_NUM];                 // input device (touch screen and accelerometer)
++      struct timer_list       timer[BMI_SLOT_NUM];                    // touch timer
++
++  int pen_down[BMI_SLOT_NUM];
++  int scount[BMI_SLOT_NUM];
++
++  struct semaphore    i2c_sem[BMI_SLOT_NUM];
++
++      struct spi_device       *spi[BMI_SLOT_NUM];                     // touch screen device interface
++      struct semaphore        sem[BMI_SLOT_NUM];                      // spi semaphore
++      char                    rbuf[BMI_SLOT_NUM][BUF_MAX_SIZE];       // spi read buffer
++      char                    wbuf[BMI_SLOT_NUM][BUF_MAX_SIZE];       // spi write buffer
++
++  struct acc_dev             acc[BMI_SLOT_NUM];
++
++};
++
++static struct pbmi_lcd pbmi_lcd;      // LCD device sructure
++
++/*
++ *    BMI set up
++ */
++
++      // BMI device ID table
++static struct bmi_device_id bmi_lcd_tbl[] =
++{
++      {
++              .match_flags = BMI_DEVICE_ID_MATCH_VENDOR | BMI_DEVICE_ID_MATCH_PRODUCT,
++              .vendor   = BMI_VENDOR_BUG_LABS,
++              .product  = BMI_PRODUCT_LCD_SHARP_320X240,
++              .revision = BMI_ANY,
++      },
++      { 0, },                                   /* terminate list */
++};
++
++MODULE_DEVICE_TABLE(bmi, bmi_lcd_tbl);
++
++/*printk(KERN_INFO "MDT: 0x%x\n", __mod_bmi_device_table);*/
++
++int   bmi_lcd_probe(struct bmi_device *bdev);
++void  bmi_lcd_remove(struct bmi_device *bdev);
++
++// BMI driver structure
++static struct bmi_driver bmi_lcd_driver =
++{
++      .name = "bmi_lcd",
++      .id_table = bmi_lcd_tbl,
++      .probe   = bmi_lcd_probe,
++      .remove  = bmi_lcd_remove,
++};
++
++//Accelerometer driver structure
++
++
++/*
++ *    I2C set up
++ */
++
++      // I2C Slave Address
++#define BMI_IOX_I2C_ADDRESS   0x71    // 7-bit address
++#define BMI_ACC_I2C_ADDRESS   0x17    // 7-bit address
++
++      // I2C IOX register addresses
++#define IOX_INPUT_REG         0x0     // IOX input data register
++#define IOX_OUTPUT_REG                0x1     // IOX output data register
++#define IOX_POLARITY_REG      0x2     // IOX polarity data register
++#define IOX_CONTROL           0x3     // IOX direction control register
++#define IOX_B1                        (0)     // bit 0 - backlight control
++#define IOX_A1_A2             (1)     // bit 1 - backlight control
++#define IOX_ACC_RST_N         (2)     // bit 2 - acceleromter reset
++#define IOX_VSYNC_EN_N                (3)     // bit 3 - VSYNC output buffer enable
++#define IOX_LCD_RST_N         (4)     // bit 4 - LCD reset
++#define IOX_SERDES_PD_N               (5)     // bit 5 - SERDES power down
++#define IOX_X_INT             (6)     // bit 6 - accelerometer interrupt
++#define IOX_Y_INT             (7)     // bit 7 - accelerometer interrupt
++
++      // I2C ACC register addresses - OKI
++#define ACC_PAGESEL                   0x1E    // device ready status
++      // page 0
++#define ACC_DVRST                     0x01    // device reset
++      #define ACC_DVRST_RST           0x3C    // device reset
++      #define ACC_DVRST_EN            0xC3    // device enable
++#define ACC_PDWN                      0x02    // osc power down
++      #define ACC_PWDN_RST            0x01    // device reset
++      #define ACC_PWDN_EN             0x00    // device enable
++#define ACC_CTRL0                     0x03    // control 0
++      #define ACC_CTRL0_CTSTR         0x40    // control 0 - temp sensor
++      #define ACC_CTRL0_CGSTRNC       0x08    // control 0 - 3-axis/no tilt
++      #define ACC_CTRL0_CGSTRC        0x04    // control 0 - 3-axis/tilt
++      #define ACC_CTRL0_CGAUTO        0x01    // control 0 - auto
++#define ACC_MODE0                     0x05    // control 0
++      #define ACC_MODE0_PDOFF         0x80    // mode 0 - disable auto power down
++      #define ACC_MODE0_RVOFF         0x40    // mode 0 - disable temp compensation
++      #define ACC_MODE0_TMPOFF        0x20    // mode 0 - disable temp measurement
++      #define ACC_MODE0_AGCON         0x10    // mode 0 - enable auto mode pitch and roll
++      #define ACC_MODE0_MAUTO         0x04    // mode 0 - enable auto termination
++      #define ACC_MODE0_GDET00        0x00    // mode 0 - g detection threshold - see ML8953 data sheet
++      #define ACC_MODE0_GDET01        0x01    // mode 0 - g detection threshold - see ML8953 data sheet
++      #define ACC_MODE0_GDET10        0x02    // mode 0 - g detection threshold - see ML8953 data sheet
++#define ACC_MODE1                     0x06    // mode 1
++      #define ACC_MODE1_MOFF          0x20    // mode 1 - disable 3-axis continuous mode
++      #define ACC_MODE1_ZAXIS         0x03    // mode 1 - Z axis
++      #define ACC_MODE1_YAXIS         0x02    // mode 1 - Y axis
++      #define ACC_MODE1_XAXIS         0x01    // mode 1 - X axis
++      #define ACC_MODE1_RAXIS         0x00    // mode 1 - Reference axis
++#define ACC_INTRQ                     0x07    // interrupt request (1 = request)
++#define ACC_INTMSK                    0x08    // interrupt mask (1 = masked)
++      #define ACC_INT_TREQ            0x20    // interrupt - temperature
++      #define ACC_INT_GREQ            0x08    // interrupt - acceleration/no tilt
++      #define ACC_INT_GCREQ           0x04    // interrupt - acceleration/tilt
++      #define ACC_INT_GAREQ           0x01    // interrupt - automatic
++#define ACC_TMDL                      0x09    // timer LSB = (1/6.2 MHz) x 2048 x TMD
++#define ACC_TMDH                      0x0A    // timer MSB
++#define ACC_CFG                               0x0C    // configuration
++      #define ACC_CFG_REGMD           0x80    // address auto-increment
++      #define ACC_CFG_SPI3M_3         0x40    // spi mode = 3-wire
++      #define ACC_CFG_SPI3M_4         0x00    // spi mode = 4-wire
++      #define ACC_CFG_SDOCFG_T        0x10    // sdo mode = totem-pole
++      #define ACC_CFG_SDOCFG_OC       0x00    // sdo mode = open-drain
++      #define ACC_CFG_INT1EN_G        0x08    // interrupt 1 mode = g only
++      #define ACC_CFG_INT1EN_ALL      0x00    // interrupt 1 mode = all
++      #define ACC_CFG_INTLVL          0x04    // interrupt level mode
++      #define ACC_CFG_INT1CFG_T       0x02    // interrupt 1 mode = totem-pole
++      #define ACC_CFG_INT1CFG_OC      0x00    // interrupt 1 mode = open-drain
++      #define ACC_CFG_INT0CFG_T       0x01    // interrupt 0 mode = totem-pole
++      #define ACC_CFG_INT0CFG_OC      0x00    // interrupt 0 mode = open-drain
++#define ACC_INTOTM                    0x0D    // interrupt output conditions
++#define ACC_GAAVE                     0x0E    // Data averaging - automatic mode
++#define ACC_GNAVE                     0x0F    // Data averaging - normal mode
++#define ACC_GDTCT0L                   0x11    // threshold 0 LSB
++#define ACC_GDTCT0H                   0x12    // threshold 0 MSB
++#define ACC_GDTCT1L                   0x13    // threshold 1 LSB
++#define ACC_GDTCT1H                   0x14    // threshold 1 MSB
++#define ACC_CPURDY                    0x15    // device ready status (ready = 0x01)
++      // page 1
++#define ACC_STATUS                    0x01    // measurment status
++      #define ACC_STATUS_ASTS         0x02    // acceleration measurement - automatic modes
++      #define ACC_STATUS_STS          0x01    // acceleration measurement - non-automatic modes
++#define ACC_GAXL                      0x02    // g vector
++#define ACC_GAXH                      0x03    // g vector
++#define ACC_GAYL                      0x04    // g vector
++#define ACC_GAYH                      0x05    // g vector
++#define ACC_GAZL                      0x06    // g vector
++#define ACC_GAZH                      0x07    // g vector
++#define ACC_GASVL                     0x08    // g vector
++#define ACC_GASVH                     0x09    // g vector
++#define ACC_GNXL                        0x0A    // g vector
++#define ACC_GNXH                        0x0B    // g vector
++#define ACC_GNYL                        0x0C    // g vector
++#define ACC_GNYH                        0x0D    // g vector
++#define ACC_GNZL                        0x0E    // g vector
++#define ACC_GNZH                        0x0F    // g vector
++#define ACC_GNSVL                     0x10    // g vector
++#define ACC_GNSVH                     0x11    // g vector
++#define ACC_PITCHL                    0x12    // pitch
++#define ACC_PITCHH                    0x13    // pitch
++#define ACC_ROLLL                     0x14    // roll
++#define ACC_ROLLH                     0x15    // roll
++#define ACC_TEMPL                     0x19    // temperature
++#define ACC_TEMPH                     0x1A    // temperature
++
++      // read byte from I2C IO expander
++static int ReadByte_IOX(struct i2c_adapter *adap, unsigned char offset, unsigned char *data)
++{
++              int     ret = 0;
++              struct i2c_msg rmsg[2];
++              int     num_msgs;
++
++              /* Read Byte with Pointer */
++
++              rmsg[0].addr = BMI_IOX_I2C_ADDRESS;
++              rmsg[0].flags = 0;        /* write */
++              rmsg[0].len = 1;
++              rmsg[0].buf = &offset;
++
++              rmsg[1].addr = BMI_IOX_I2C_ADDRESS;
++              rmsg[1].flags = I2C_M_RD;   /* read */
++              rmsg[1].len = 1;
++              rmsg[1].buf = data;
++
++              num_msgs = 2;
++
++              ret = i2c_transfer (adap, rmsg, num_msgs);
++
++              if (ret == 2) {
++                      ret = 0;
++              }
++              else {
++                      printk (KERN_ERR "ReadByte_IOX() - i2c_transfer() failed.\n");
++                      ret = -1;
++              }
++              return ret;
++}
++
++
++static int ReadByteLock_IOX(struct pbmi_lcd *priv, unsigned char offset, unsigned char *data, int slot)
++{
++              int     ret = 0;
++              struct i2c_msg rmsg[2];
++              int     num_msgs;
++              struct i2c_adapter *adap;
++
++              /* Read Byte with Pointer */
++
++              adap = &priv->bdev[slot]->adap;
++
++              rmsg[0].addr = BMI_IOX_I2C_ADDRESS;
++              rmsg[0].flags = 0;        /* write */
++              rmsg[0].len = 1;
++              rmsg[0].buf = &offset;
++
++              rmsg[1].addr = BMI_IOX_I2C_ADDRESS;
++              rmsg[1].flags = I2C_M_RD;   /* read */
++              rmsg[1].len = 1;
++              rmsg[1].buf = data;
++
++              num_msgs = 2;
++
++              down(&priv->i2c_sem[slot]);
++              ret = i2c_transfer (adap, rmsg, num_msgs);
++              up(&priv->i2c_sem[slot]);
++
++              if (ret == 2) {
++                      ret = 0;
++              }
++              else {
++                      printk (KERN_ERR "ReadByte_IOX() - i2c_transfer() failed.\n");
++                      ret = -1;
++              }
++              return ret;
++}
++
++
++      // write byte to I2C IO expander
++static int WriteByte_IOX(struct i2c_adapter *adap, unsigned char offset, unsigned char data)
++{
++              int     ret = 0;
++              struct i2c_msg wmsg[2];
++              int     num_msgs;
++
++              /* Write Byte with Pointer */
++
++              wmsg[0].addr = BMI_IOX_I2C_ADDRESS;
++              wmsg[0].flags = 0;      /* write */
++              wmsg[0].len = 1;
++              wmsg[0].buf = &offset;
++
++              wmsg[1].addr = BMI_IOX_I2C_ADDRESS;
++              wmsg[1].flags = 0;      /* write */
++              wmsg[1].len = 1;
++              wmsg[1].buf = &data;
++
++              num_msgs = 2;
++              ret = i2c_transfer (adap, wmsg, num_msgs);
++
++              if (ret == 2) {
++                      ret = 0;
++              }
++              else {
++                      printk (KERN_ERR "WriteByte_IOX() - i2c_transfer() failed.\n");
++                      ret = -1;
++              }
++              return ret;
++}
++
++
++static int WriteByteLock_IOX(struct pbmi_lcd *priv, unsigned char offset, unsigned char data, int slot)
++{
++              int     ret = 0;
++              struct i2c_msg wmsg[2];
++              int     num_msgs;
++              struct i2c_adapter *adap;
++              /* Write Byte with Pointer */
++
++              adap = &priv->bdev[slot]->adap;
++              if (adap == NULL)
++                {
++                  printk(KERN_INFO "WriteByteLock_IOX adap NULL\n");
++                  return -1;
++                }
++              wmsg[0].addr = BMI_IOX_I2C_ADDRESS;
++              wmsg[0].flags = 0;      /* write */
++              wmsg[0].len = 1;
++              wmsg[0].buf = &offset;
++
++              wmsg[1].addr = BMI_IOX_I2C_ADDRESS;
++              wmsg[1].flags = 0;      /* write */
++              wmsg[1].len = 1;
++              wmsg[1].buf = &data;
++
++              num_msgs = 2;
++
++              down(&priv->i2c_sem[slot]);
++              printk(KERN_INFO "WriteByteLock_IOX attempting I2C xfer\n");
++              ret = i2c_transfer (adap, wmsg, num_msgs);
++              up(&priv->i2c_sem[slot]);
++
++              if (ret == 2) {
++                      ret = 0;
++              }
++              else {
++                      printk (KERN_ERR "WriteByteLock_IOX() - i2c_transfer() failed.\n");
++                      ret = -1;
++              }
++              return ret;
++}
++
++
++      // read byte from I2C acceleromter
++static int ReadByte_ACC(struct i2c_adapter *adap, unsigned char offset, unsigned char *data)
++{
++              int     ret = 0;
++              struct i2c_msg rmsg[2];
++              int     num_msgs;
++              int retries = 0;
++
++              /* Read Byte with Pointer */
++
++              rmsg[0].addr = BMI_ACC_I2C_ADDRESS;
++              rmsg[0].flags = 0;        /* write */
++              rmsg[0].len = 1;
++              rmsg[0].buf = &offset;
++
++              rmsg[1].addr = BMI_ACC_I2C_ADDRESS;
++              rmsg[1].flags = I2C_M_RD;   /* read */
++              rmsg[1].len = 1;
++              rmsg[1].buf = data;
++
++              num_msgs = 2;
++
++              while (retries < 5)
++                {
++                  ret = i2c_transfer (adap, rmsg, num_msgs);
++                  if (ret == 2)
++                    break;
++                  else
++                    retries++;
++                  mdelay(1);
++                }
++
++              if (ret == 2) {
++                      ret = 0;
++              }
++              else {
++                      printk (KERN_ERR "ReadByte_ACC() - i2c_transfer() failed.\n");
++                      ret = -1;
++              }
++              return ret;
++}
++
++static int ReadByteLock_ACC(struct pbmi_lcd *priv, unsigned char offset, unsigned char *data, int slot)
++{
++              int     ret = 0;
++              struct i2c_msg rmsg[2];
++              int     num_msgs;
++              struct i2c_adapter *adap;
++
++              /* Read Byte with Pointer */
++
++              adap = &priv->bdev[slot]->adap;
++
++              rmsg[0].addr = BMI_ACC_I2C_ADDRESS;
++              rmsg[0].flags = 0;        /* write */
++              rmsg[0].len = 1;
++              rmsg[0].buf = &offset;
++
++              rmsg[1].addr = BMI_ACC_I2C_ADDRESS;
++              rmsg[1].flags = I2C_M_RD;   /* read */
++              rmsg[1].len = 1;
++              rmsg[1].buf = data;
++
++              num_msgs = 2;
++
++              down(&priv->i2c_sem[slot]);
++              ret = i2c_transfer (adap, rmsg, num_msgs);
++              up(&priv->i2c_sem[slot]);
++
++              if (ret == 2) {
++                      ret = 0;
++              }
++              else {
++                printk (KERN_ERR "ReadByteLock_ACC() - i2c_transfer() failed.0x%x\n",-ret);
++                      ret = -1;
++              }
++              return ret;
++}
++
++      // write byte to I2C accelerometer
++static int WriteByte_ACC(struct i2c_adapter *adap, unsigned char offset, unsigned char data)
++{
++              int     ret = 0;
++              struct i2c_msg wmsg[2];
++              int     num_msgs;
++
++              /* Write Byte with Pointer */
++
++              wmsg[0].addr = BMI_ACC_I2C_ADDRESS;
++              wmsg[0].flags = 0;      /* write */
++              wmsg[0].len = 1;
++              wmsg[0].buf = &offset;
++
++              wmsg[1].addr = BMI_ACC_I2C_ADDRESS;
++              wmsg[1].flags = 0;      /* write */
++              wmsg[1].len = 1;
++              wmsg[1].buf = &data;
++
++              num_msgs = 2;
++
++              ret = i2c_transfer (adap, wmsg, num_msgs);
++
++              if (ret == 2) {
++                      ret = 0;
++              }
++              else {
++                      printk (KERN_ERR "WriteByte_ACC() - i2c_transfer() failed.\n");
++                      ret = -1;
++              }
++              return ret;
++}
++
++static int WriteByteLock_ACC(struct pbmi_lcd *priv, unsigned char offset, unsigned char data, int slot)
++{
++              int     ret = 0;
++              struct i2c_msg wmsg[2];
++              int     num_msgs;
++              struct i2c_adapter *adap;
++              /* Write Byte with Pointer */
++
++              adap = &priv->bdev[slot]->adap;
++
++              wmsg[0].addr = BMI_ACC_I2C_ADDRESS;
++              wmsg[0].flags = 0;      /* write */
++              wmsg[0].len = 1;
++              wmsg[0].buf = &offset;
++
++              wmsg[1].addr = BMI_ACC_I2C_ADDRESS;
++              wmsg[1].flags = 0;      /* write */
++              wmsg[1].len = 1;
++              wmsg[1].buf = &data;
++
++              num_msgs = 2;
++
++              down(&priv->i2c_sem[slot]);
++              ret = i2c_transfer (adap, wmsg, num_msgs);
++              up(&priv->i2c_sem[slot]);
++
++              if (ret == 2) {
++                      ret = 0;
++              }
++              else {
++                      printk (KERN_ERR "WriteByteLock_ACC() - i2c_transfer() failed.\n");
++                      ret = -1;
++              }
++              return ret;
++}
++
++/*
++ *    SPI functions
++ */
++
++      // TSC2046 touch screen controller command register bit definitons
++#define SPI_START     0x80    // command start
++#define SPI_AT0               0x00    // read temperature - not supported
++#define SPI_AY                0x10    // read Y
++#define SPI_ABAT      0x20    // read battery - not supported
++#define SPI_AZ1               0x30    // read Z1
++#define SPI_AZ2               0x40    // read Z2
++#define SPI_AX                0x50    // read X
++#define SPI_AAUX      0x60    // read AUX - not supported
++#define SPI_AT1               0x70    // read temperature - not supported
++#define SPI_MODE_12   0x00    // 12-bit mode - Preferred
++#define SPI_MODE_8    0x08    // 8-bit mode
++#define SPI_MODE_DFR  0x00    // differential mode - Preferred
++#define SPI_MODE_SER  0x04    // single ended mode
++#define SPI_PD                0x00    // power down - PENIRQ enabled
++#define SPI_ADC               0x01    // ADC enabled
++#define SPI_REF               0x02    // Vref enabled - unused
++#define SPI_REF_ADC   0x03    // Vref & ADC enabled - unused
++
++      // spi access
++static int spi_rw(struct spi_device *spi, u8 * buf, size_t len)
++{
++      struct spi_transfer t = {
++              .tx_buf = (const void *)buf,
++              .rx_buf = buf,
++              .len = len,
++              .cs_change = 0,
++              .delay_usecs = 0,
++      };
++      struct spi_message m;
++
++      spi_message_init(&m);
++
++      spi_message_add_tail(&t, &m);
++      if (spi_sync(spi, &m) != 0 || m.status != 0)
++              return -1;
++
++      return m.actual_length;
++}
++
++      // spi write register
++static ssize_t spi_lcd_write_reg(struct pbmi_lcd *priv, char *buf, int len, int slot)
++{
++      int res = 0;
++
++      down(&priv->sem[slot]);
++
++      memset(priv->wbuf[slot], 0, BUF_MAX_SIZE);
++      priv->wbuf[slot][0] = buf[0];
++      priv->wbuf[slot][1] = buf[1];
++      priv->wbuf[slot][2] = buf[2];
++      priv->wbuf[slot][3] = buf[3];
++      res = spi_rw(priv->spi[slot], priv->wbuf[slot], len);
++      if (res != 1) {
++              up(&priv->sem[slot]);
++              return -EFAULT;
++      }
++
++      up(&priv->sem[slot]);
++
++      return res;
++}
++
++      // spi read register
++static ssize_t spi_lcd_read_reg(struct pbmi_lcd *priv, char *buf, int len, int slot)
++{
++      int res = 0;
++
++      down(&priv->sem[slot]);
++
++      memset(priv->wbuf[slot], 0, BUF_MAX_SIZE);
++      priv->wbuf[slot][0] = buf[0];
++      priv->wbuf[slot][1] = buf[1];
++      priv->wbuf[slot][2] = buf[2];
++      priv->wbuf[slot][3] = buf[3];
++      res = spi_rw(priv->spi[slot], priv->wbuf[slot], len);
++      if (res != 1) {
++              up(&priv->sem[slot]);
++              return -EFAULT;
++      }
++
++      memset(priv->rbuf[slot], 0, BUF_MAX_SIZE);
++      buf[0] = priv->wbuf[slot][2];
++      buf[1] = priv->wbuf[slot][1];
++
++      up(&priv->sem[slot]);
++
++      return res;
++}
++
++/*
++ *    BMI functions
++ */
++
++static irqreturn_t module_irq_handler(int irq, void *dummy);
++void bmi_lcd_config(struct bmi_lcd *lcd, int disp);
++
++      // probe
++int bmi_lcd_probe(struct bmi_device *bdev)
++{
++
++  unsigned char acc_data[1];
++  unsigned char iox_data[1];
++  int slot = bdev->info->slot;
++  struct i2c_adapter *adap;
++  struct bmi_lcd *lcd;
++  char buf[4];
++
++  printk(KERN_INFO "bmi_lcd.c: probe slot %d\n", slot);
++
++  // check for opposite side already active
++  switch(slot) {      // opposite side
++  case 0:
++    if(pbmi_lcd.activated[2] == 1) {
++      printk(KERN_INFO "bmi_lcd.c: probe slot %d not allowed (slot 2 already active)\n", slot);
++      bmi_slot_power_off(0);
++      pbmi_lcd.bdev[0] = bdev;
++      return 0;
++    }
++    break;
++  case 1:
++    if(pbmi_lcd.activated[3] == 1) {
++      printk(KERN_INFO "bmi_lcd.c: probe slot %d not allowed (slot 3 already active)\n", slot);
++      bmi_slot_power_off(1);
++      pbmi_lcd.bdev[1] = bdev;
++      return 0;
++    }
++    break;
++  case 2:
++    if(pbmi_lcd.activated[0] == 1) {
++      printk(KERN_INFO "bmi_lcd.c: probe slot %d not allowed (slot 0 already active)\n", slot);
++      bmi_slot_power_off(2);
++      pbmi_lcd.bdev[2] = bdev;
++      return 0;
++    }
++    break;
++  case 3:
++    if(pbmi_lcd.activated[1] == 1) {
++      printk(KERN_INFO "bmi_lcd.c: probe slot %d not allowed (slot 1 already active)\n", slot);
++      bmi_slot_power_off(3);
++      pbmi_lcd.bdev[3] = bdev;
++      return 0;
++    }
++    break;
++  }
++
++  adap = &bdev->adap;
++  bmi_slot_power_on(slot);
++
++  // set up bdev/pbmi_lcd pointers
++  bmi_device_set_drvdata(bdev, &pbmi_lcd);
++  pbmi_lcd.bdev[slot] = bdev;
++
++  printk(KERN_INFO "Adap = 0x%x",adap);
++
++  printk(KERN_INFO "Lock stuff = 0x%x", &(pbmi_lcd.bdev[slot]->adap));
++
++  mdelay(500);
++
++  // configure IOX
++  // [7:6]=interrupts, [5]=SER_PD*, [4]=LCD_RST*, [3]=VSYNC_OE*, [2]=ACC_RST*, [1:0]=backlight
++  if(WriteByte_IOX(adap, IOX_OUTPUT_REG, 0xFF))       // normal - no accelerometer interrupts
++    return -ENODEV;
++  if(WriteByteLock_IOX(&pbmi_lcd, IOX_OUTPUT_REG, 0xFF, slot))        // normal - no accelerometer interrupts
++    return -ENODEV;
++
++  // normal operation - no accelerometer interrupts
++  if(WriteByteLock_IOX(&pbmi_lcd, IOX_CONTROL, 0x00, slot))   // IOX[7:0]=OUT
++    return -ENODEV;
++
++  // clear interrupts
++  if(ReadByteLock_IOX(&pbmi_lcd, IOX_INPUT_REG, iox_data, slot))
++    return -ENODEV;
++
++  printk(KERN_INFO "bmi_lcd.c: probe slot %d iox data =  %x\n", slot, *iox_data);
++
++
++  // accelerometer
++  printk(KERN_INFO "bmi_lcd.c: probe slot %d hardware version =  0x%x\n", slot, bdev->epraw.revision_msb);
++
++  // check for PCB revision >= 1.2
++  if(bdev->epraw.revision_msb >= 0x12)
++    {
++
++      // normal IOX operation - accelerometer interrupts
++      if(WriteByteLock_IOX(&pbmi_lcd, IOX_CONTROL, 0xC0, slot))       // IOX[7:6]=IN, IOX[5:0]=OUT
++      return -ENODEV;
++
++      if(WriteByteLock_IOX(&pbmi_lcd, IOX_OUTPUT_REG, 0xFB, slot))    // reset OKI accelerometer
++      return -ENODEV;
++
++      mdelay(2);
++
++      if(WriteByteLock_IOX(&pbmi_lcd, IOX_OUTPUT_REG, 0xFF, slot))    // enable OKI accelerometer
++      return -ENODEV;
++
++      mdelay(2);
++
++      // write PAGESEL
++      *acc_data = 0x0;
++      if(WriteByteLock_ACC(&pbmi_lcd, ACC_PAGESEL, *acc_data, slot))
++      return -ENODEV;
++
++      // read device to verify existance
++      if(ReadByteLock_ACC(&pbmi_lcd, ACC_CPURDY, acc_data, slot))
++      return -ENODEV;
++
++      // set TMD = 0x300 (~250 ms)
++      *acc_data = 0x5;
++      if(WriteByteLock_ACC(&pbmi_lcd, ACC_TMDH, *acc_data, slot))
++      return -ENODEV;
++
++      *acc_data = 0x0;
++      if(WriteByteLock_ACC(&pbmi_lcd, ACC_TMDL, *acc_data, slot))
++      return -ENODEV;
++
++      // set INTOTM
++      *acc_data = 0x00;
++      if(WriteByteLock_ACC(&pbmi_lcd, ACC_INTOTM, *acc_data, slot))
++      return -ENODEV;
++
++      // set GxAVE
++      *acc_data = 0x0;
++      if(WriteByteLock_ACC(&pbmi_lcd, ACC_GAAVE, *acc_data, slot))
++      return -ENODEV;
++
++      // set GDTCT[01]
++      *acc_data = 0x00;
++      if(WriteByteLock_ACC(&pbmi_lcd, ACC_GDTCT0L, *acc_data, slot))
++      return -ENODEV;
++
++      *acc_data = 0x00;
++      if(WriteByteLock_ACC(&pbmi_lcd, ACC_GDTCT0H, *acc_data, slot))
++      return -ENODEV;
++
++      *acc_data = 0x00;
++      if(WriteByteLock_ACC(&pbmi_lcd, ACC_GDTCT1L, *acc_data, slot))
++      return -ENODEV;
++
++      *acc_data = 0x00;
++      if(WriteByteLock_ACC(&pbmi_lcd, ACC_GDTCT1H, *acc_data, slot))
++      return -ENODEV;
++
++      // set MODE0
++      *acc_data = ACC_MODE0_PDOFF | ACC_MODE0_TMPOFF | ACC_MODE0_AGCON | ACC_MODE0_MAUTO | ACC_MODE0_GDET10;
++      if(WriteByteLock_ACC(&pbmi_lcd, ACC_MODE0, *acc_data, slot))
++      return -ENODEV;
++
++      // set CFG
++      *acc_data = ACC_CFG_REGMD | ACC_CFG_INTLVL;
++      if(WriteByteLock_ACC(&pbmi_lcd, ACC_CFG, *acc_data, slot))
++      return -ENODEV;
++
++      // set INTMSK
++      *acc_data = 0xFE;
++      if(WriteByteLock_ACC(&pbmi_lcd, ACC_INTMSK, *acc_data, slot))
++      return -ENODEV;
++
++      // set CTRL0
++      *acc_data = ACC_CTRL0_CGAUTO;
++      if(WriteByteLock_ACC(&pbmi_lcd, ACC_CTRL0, *acc_data, slot))
++      return -ENODEV;
++
++      // write PAGESEL
++      *acc_data = 0x1;
++      if(WriteByteLock_ACC(&pbmi_lcd, ACC_PAGESEL, *acc_data, slot))
++      return -ENODEV;
++
++      acc_probe(&pbmi_lcd.acc[slot], slot);
++    }
++  else
++    {
++      printk(KERN_INFO "bmi_lcd.c: probe slot %d hardware version =  0x%x (accelerometer not supported)\n", slot, bdev->epraw.revision_msb);
++    }
++
++  // reset serial link (master)
++  if((slot == 0) || (slot == 2))
++    {
++      bmi_lcd_inactive(0);
++    }
++  else
++    {
++      bmi_lcd_inactive(1);
++    }
++
++  // configure GPIO
++  // turn LED's on
++  bmi_set_module_gpio_data(slot, 3, 0);       // Red LED=ON
++  bmi_set_module_gpio_data(slot, 2, 0);       // Green LED=ON
++
++  // assert reset
++  bmi_set_module_gpio_data(slot, 1, 0);       // RST=0
++
++  // set GPIO direction
++  bmi_set_module_gpio_dir(slot, 3, BMI_GPIO_OUT);
++  bmi_set_module_gpio_dir(slot, 2, BMI_GPIO_OUT);
++  bmi_set_module_gpio_dir(slot, 1, BMI_GPIO_OUT);
++  bmi_set_module_gpio_dir(slot, 0, BMI_GPIO_IN);      // real-time pen int state
++
++  mdelay(200);
++
++  // turn LED's off
++  bmi_set_module_gpio_data(slot, 3, 1);       // Red LED=OFF
++  bmi_set_module_gpio_data(slot, 2, 1);       // Green LED=OFF
++
++  // deassert reset (module)
++  bmi_set_module_gpio_data(slot, 1, 1);       // RST=1
++
++  mdelay(500);
++
++  // unreset serial link (master)
++  if((slot == 0) || (slot == 2)) {
++    mdelay(2);
++    bmi_lcd_active(0, 0x0, LCD_MODE_I80);
++  } else {
++    mdelay(2);
++    bmi_lcd_active(1, 0x0, LCD_MODE_I80);
++  }
++
++
++
++
++  // spi set-up
++  if (bmi_device_spi_setup(bdev, 2000000, SPI_MODE_2, 32)) {
++    printk(KERN_ERR "bmi_lcd.c: Unable to setup spi%d\n", slot);
++    bmi_device_set_drvdata(bdev, NULL);
++    pbmi_lcd.bdev[slot] = NULL;
++    bmi_slot_power_off(slot);
++    return -EFAULT;
++  }
++
++  bmi_slot_spi_enable(slot);
++  pbmi_lcd.spi[slot] = bmi_device_get_spi(bdev);
++
++
++  // check spi access and enable touch screen
++  memset(buf, 0, 4);
++  buf[3] = SPI_START | SPI_PD;
++  if(spi_lcd_write_reg(&pbmi_lcd, buf, 1, slot) != 1) {
++    printk(KERN_WARNING "bmi_lcd.c: Unable set-up spi for bmi_lcd %d\n", slot);
++    bmi_device_set_drvdata(bdev, NULL);
++    pbmi_lcd.bdev[slot] = NULL;
++    pbmi_lcd.spi[slot] = NULL;
++    bmi_device_spi_cleanup(bdev);
++    bmi_slot_spi_disable(slot);
++    bmi_slot_power_off(slot);
++    return -EFAULT;
++  }
++
++
++  // complete pbmi_lcd set-up
++  pbmi_lcd.lcd_cnt++;
++  pbmi_lcd.active = 1;
++  pbmi_lcd.activated[slot] = 1;
++
++
++  mdelay(100);
++
++  lcd = pbmi_lcd.blcd[slot];
++  if((slot == 0) || (slot == 2)) {
++    mdelay(2);
++    bmi_lcd_config(lcd, 0);
++    mdelay(2);
++  } else {
++    mdelay(2);
++    bmi_lcd_config(lcd, 1);
++    mdelay(2);
++  }
++
++
++  // request input event interrupt handler
++  pbmi_lcd.interrupt[0] = M1_IRQ;
++  pbmi_lcd.interrupt[1] = M2_IRQ;
++  pbmi_lcd.interrupt[2] = M3_IRQ;
++  pbmi_lcd.interrupt[3] = M4_IRQ;
++  snprintf(pbmi_lcd.int_name, sizeof(pbmi_lcd.int_name), "bmi_lcd%d", slot);
++  if (request_irq(pbmi_lcd.interrupt[slot], &module_irq_handler, 0, pbmi_lcd.int_name, &pbmi_lcd))
++    {
++      printk( KERN_ERR "bmi_lcd.c: Can't allocate irq %d or find lcd in slot %d\n", pbmi_lcd.interrupt[slot], slot);
++      bmi_device_set_drvdata(bdev, NULL);
++      pbmi_lcd.bdev[slot] = NULL;
++      pbmi_lcd.spi[slot] = NULL;
++      bmi_device_spi_cleanup(bdev);
++      bmi_slot_power_off(slot);
++      return -EBUSY;
++    }
++
++  // check GPIO status
++  printk(KERN_INFO "bmi_lcd.c: slot %d gpio = %x\n", slot, bmi_read_gpio_data_reg(slot));
++  printk(KERN_INFO "bmi_lcd.c: LCD count = %d\n", pbmi_lcd.lcd_cnt);
++
++  return 0;
++}
++
++extern struct delayed_work bmilcd_work0;
++extern struct delayed_work bmilcd_work1;
++extern struct delayed_work bmilcd_work2;
++extern struct delayed_work bmilcd_work3;
++
++      // remove
++void bmi_lcd_remove(struct bmi_device *bdev)
++{
++      int slot = bdev->info->slot;
++
++      if(pbmi_lcd.activated[slot] == 0)
++          return;
++
++      switch(slot) {
++              case 0:
++                      cancel_delayed_work(&bmilcd_work0);
++                      break;
++              case 1:
++                      cancel_delayed_work(&bmilcd_work1);
++                      break;
++              case 2:
++                      cancel_delayed_work(&bmilcd_work2);
++                      break;
++              case 3:
++                      cancel_delayed_work(&bmilcd_work3);
++                      break;
++      }
++
++      free_irq(pbmi_lcd.interrupt[slot], &pbmi_lcd);
++
++      bmi_set_module_gpio_dir (slot, 3, BMI_GPIO_IN);
++      bmi_set_module_gpio_dir (slot, 2, BMI_GPIO_IN);
++      bmi_set_module_gpio_dir (slot, 1, BMI_GPIO_IN);
++      bmi_set_module_gpio_dir (slot, 0, BMI_GPIO_IN);
++
++              // bmi/spi clean-up
++      bmi_device_spi_cleanup(bdev);
++      pbmi_lcd.spi[slot] = NULL;
++      bmi_slot_spi_disable(slot);
++
++              //de-attach driver-specific struct from bmi_device structure
++      bmi_device_set_drvdata (&bdev[slot], 0);
++
++              // deactivate
++      pbmi_lcd.activated[slot] = 0;
++      pbmi_lcd.bdev[slot] = 0;
++      pbmi_lcd.lcd_cnt--;
++
++      if((pbmi_lcd.activated[0] == 0) && (pbmi_lcd.activated[2] == 0)) {
++              bmi_lcd_inactive(0); // disable serializer
++      }
++
++      if((pbmi_lcd.activated[1] == 0) && (pbmi_lcd.activated[3] == 0)) {
++              bmi_lcd_inactive(1); // disable serializer
++      }
++
++      if((pbmi_lcd.activated[0] == 0) && (pbmi_lcd.activated[1] == 0) &&
++              (pbmi_lcd.activated[2] == 0) && (pbmi_lcd.activated[3] == 0)) {
++              pbmi_lcd.active = -1;
++      }
++
++              // enable LCD on opposite side
++      switch(slot) {
++              case 0:
++                      if(pbmi_lcd.bdev[2] != 0)
++                              bmi_lcd_probe(pbmi_lcd.bdev[2]);
++                      break;
++              case 1:
++                      if(pbmi_lcd.bdev[3] != 0)
++                              bmi_lcd_probe(pbmi_lcd.bdev[3]);
++                      break;
++              case 2:
++                      if(pbmi_lcd.bdev[0] != 0)
++                              bmi_lcd_probe(pbmi_lcd.bdev[0]);
++                      break;
++              case 3:
++                      if(pbmi_lcd.bdev[1] != 0)
++                              bmi_lcd_probe(pbmi_lcd.bdev[1]);
++                      break;
++      }
++
++      acc_remove(&pbmi_lcd.acc[slot], slot);
++      printk(KERN_INFO "bmi_lcd.c: LCD count = %d\n", pbmi_lcd.lcd_cnt);
++
++      return;
++}
++
++/*
++ * Input interrupt handler and support routines
++ */
++
++static void update_pen_state(void *arg, int slot, int x, int y, int pressure)
++{
++  struct pbmi_lcd *pbmi_lcd = (struct pbmi_lcd *)arg;
++  int sync = 0;
++
++  if (pressure)
++    {
++      /*input_report_abs(pbmi_lcd->input_dev[slot], ABS_X, x);
++      input_report_abs(pbmi_lcd->input_dev[slot], ABS_Y, y);
++      input_report_abs(pbmi_lcd->input_dev[slot], ABS_PRESSURE, pressure);
++
++      input_report_abs(pbmi_lcd->input_dev[BMI_TS_M1234], ABS_X, x);
++      input_report_abs(pbmi_lcd->input_dev[BMI_TS_M1234], ABS_Y, y);
++      input_report_abs(pbmi_lcd->input_dev[BMI_TS_M1234], ABS_PRESSURE, pressure);*/
++
++      if((slot == 0) || (slot == 2))
++      {
++        input_report_abs(pbmi_lcd->input_dev[BMI_TS_M13], ABS_Y, y);
++        input_report_abs(pbmi_lcd->input_dev[BMI_TS_M13], ABS_X, x);
++        input_report_abs(pbmi_lcd->input_dev[BMI_TS_M13], ABS_PRESSURE, pressure);
++      }
++      else
++      {
++        input_report_abs(pbmi_lcd->input_dev[BMI_TS_M24], ABS_Y, y);
++        input_report_abs(pbmi_lcd->input_dev[BMI_TS_M24], ABS_X, x);
++        input_report_abs(pbmi_lcd->input_dev[BMI_TS_M24], ABS_PRESSURE, pressure);
++      }
++
++      if (!pbmi_lcd->pen_down[slot])
++      {
++        /*input_report_key(pbmi_lcd->input_dev[slot], BTN_TOUCH, 1);
++          input_report_key(pbmi_lcd->input_dev[BMI_TS_M1234], BTN_TOUCH, 1);*/
++        if((slot == 0) || (slot == 2))
++          {
++            input_report_key(pbmi_lcd->input_dev[BMI_TS_M13], BTN_TOUCH, 1);
++          }
++        else
++          {
++            input_report_key(pbmi_lcd->input_dev[BMI_TS_M24], BTN_TOUCH, 1);
++          }
++
++      }
++      sync = 1;
++    }
++  else if (pbmi_lcd->pen_down[slot])
++    {
++      /*input_report_key(pbmi_lcd->input_dev[slot], BTN_TOUCH, 0);
++      input_report_abs(pbmi_lcd->input_dev[slot], ABS_PRESSURE, 0);
++
++      input_report_key(pbmi_lcd->input_dev[BMI_TS_M1234], BTN_TOUCH, 0);
++      input_report_abs(pbmi_lcd->input_dev[BMI_TS_M1234], ABS_PRESSURE, 0); */
++
++      if((slot == 0) || (slot == 2))
++      {
++        input_report_key(pbmi_lcd->input_dev[BMI_TS_M13], BTN_TOUCH, 0);
++        input_report_abs(pbmi_lcd->input_dev[BMI_TS_M13], ABS_PRESSURE, 0);
++      }
++      else
++      {
++        input_report_key(pbmi_lcd->input_dev[BMI_TS_M24], BTN_TOUCH, 0);
++        input_report_abs(pbmi_lcd->input_dev[BMI_TS_M24], ABS_PRESSURE, 0);
++      }
++      sync = 1;
++    }
++
++  if (sync)
++    {
++      /*input_sync(pbmi_lcd->input_dev[slot]);
++      input_sync(pbmi_lcd->input_dev[BMI_TS_M1234]);*/
++      if((slot == 0) || (slot == 2))
++      {
++        input_sync(pbmi_lcd->input_dev[BMI_TS_M13]);
++      }
++      else
++      {
++        input_sync(pbmi_lcd->input_dev[BMI_TS_M24]);
++      }
++    }
++  pbmi_lcd->pen_down[slot] = pressure ? 1 : 0;
++
++}
++
++
++void bmilcd_input_work(void *arg, int slot);
++
++void bmilcd_input_work0(struct work_struct * work) {
++      bmilcd_input_work(&pbmi_lcd, 0);
++}
++
++void bmilcd_input_work1(struct work_struct * work) {
++      bmilcd_input_work(&pbmi_lcd, 1);
++}
++
++void bmilcd_input_work2(struct work_struct * work) {
++      bmilcd_input_work(&pbmi_lcd, 2);
++}
++
++void bmilcd_input_work3(struct work_struct * work) {
++  bmilcd_input_work(&pbmi_lcd, 3);
++}
++
++DECLARE_DELAYED_WORK(bmilcd_work0, bmilcd_input_work0);
++DECLARE_DELAYED_WORK(bmilcd_work1, bmilcd_input_work1);
++DECLARE_DELAYED_WORK(bmilcd_work2, bmilcd_input_work2);
++DECLARE_DELAYED_WORK(bmilcd_work3, bmilcd_input_work3);
++
++// work handler
++void bmilcd_input_work(void *arg, int slot) {
++      struct pbmi_lcd         *pbmi_lcd = (struct pbmi_lcd *)arg;
++      struct i2c_adapter      *adap = &pbmi_lcd->bdev[slot]->adap;
++      unsigned char           acc_data[1];
++      static int              pitch = 0;
++      static int              roll = 0;
++      static int gx = 0;
++      static int gy = 0;
++
++      unsigned char iox_data[1];
++
++      unsigned char           buf[4];
++      int                     x = 0;
++      int                     y = 0;
++      int                     z1 = 0;
++      int                     z2 = 0;
++      int                     pressure = 0;
++      int                     debounce;
++      int penirq;
++
++#if defined DEBUG
++      printk(KERN_INFO "bmi_lcd.c: bmi_lcd_input work (slot %d)\n", slot);
++#endif
++
++      if(pbmi_lcd->bdev[slot] == 0) {
++              printk(KERN_INFO "bmi_lcd.c: bmi_lcd_input work called with no bdev active (slot %d)\n", slot);
++              return;
++      }
++
++      if(pbmi_lcd->bdev[slot]->epraw.revision_msb >= 0x12) {
++
++                      // orientation
++                      // read ROLL
++        printk(KERN_INFO "ACC Work: ROLLH\n");
++        if(ReadByteLock_ACC(pbmi_lcd, ACC_ROLLH, acc_data, slot))
++                      return;
++        roll = (0x0000 | *acc_data) << 8;
++        printk(KERN_INFO "ACC Work: ROLLL\n");
++        if(ReadByteLock_ACC(pbmi_lcd, ACC_ROLLL, acc_data, slot))
++          return;
++        roll = roll | *acc_data;
++        // read PITCH
++        printk(KERN_INFO "ACC Work: PITCHH\n");
++        if(ReadByteLock_ACC(pbmi_lcd, ACC_PITCHH, acc_data, slot))
++          return;
++        pitch = (0x0000 | *acc_data) << 8;
++        printk(KERN_INFO "ACC Work: PITCHL\n");
++        if(ReadByteLock_ACC(pbmi_lcd, ACC_PITCHL, acc_data, slot))
++          return;
++        pitch = pitch | *acc_data;
++
++
++
++        printk(KERN_INFO "ACC Work: GAZH\n");
++        if(ReadByteLock_ACC(pbmi_lcd, ACC_GAZH, acc_data, slot))
++          return;
++        pbmi_lcd->acc[slot].sample[0] = *acc_data;
++        printk(KERN_INFO "ACC Work: GAZL\n");
++        if(ReadByteLock_ACC(pbmi_lcd, ACC_GAZL, acc_data, slot))
++          return;
++        pbmi_lcd->acc[slot].sample[1] = *acc_data;
++        printk(KERN_INFO "ACC Work: GAYH\n");
++        if(ReadByteLock_ACC(pbmi_lcd, ACC_GAYH, acc_data, slot))
++          return;
++        pbmi_lcd->acc[slot].sample[2] = *acc_data;
++        gy = *acc_data << 8;
++        printk(KERN_INFO "ACC Work: GAYL\n");
++        if(ReadByteLock_ACC(pbmi_lcd, ACC_GAYL, acc_data, slot))
++          return;
++        pbmi_lcd->acc[slot].sample[3] = *acc_data;
++        gy = gy | *acc_data;
++        printk(KERN_INFO "ACC Work: GAXH\n");
++        if(ReadByteLock_ACC(pbmi_lcd, ACC_GAXH, acc_data, slot))
++          return;
++        pbmi_lcd->acc[slot].sample[4] = *acc_data;
++        gx = *acc_data << 8;
++        printk(KERN_INFO "ACC Work: GAXL\n");
++        if(ReadByteLock_ACC(pbmi_lcd, ACC_GAXL, acc_data, slot))
++          return;
++        pbmi_lcd->acc[slot].sample[5] = *acc_data;
++        gx = gx | *acc_data;
++
++        //wake up any read's
++        pbmi_lcd->acc[slot].flag = 1;
++        wake_up_interruptible(&pbmi_lcd->acc[slot].wq);
++
++        if(ReadByteLock_IOX(pbmi_lcd, IOX_OUTPUT_REG, iox_data, slot))
++          return;
++        *iox_data = (*iox_data & 0xF8) | 0x4;
++        if(WriteByteLock_IOX(pbmi_lcd, IOX_OUTPUT_REG, *iox_data, slot))
++          return;
++        printk(KERN_INFO "ACC Work: IOX\n");
++
++        // read STATUS
++        printk(KERN_INFO "ACC Work: STATUS\n");
++        if(ReadByteLock_ACC(pbmi_lcd, ACC_STATUS, acc_data, slot))
++          return;
++
++        if((*acc_data & 0x1) == 0) {
++
++          // write PAGESEL
++          *acc_data = 0x0;
++          if(WriteByteLock_ACC(pbmi_lcd, ACC_PAGESEL, *acc_data, slot))
++            return;
++
++          // read INTRQ
++          printk(KERN_INFO "ACC Work: INTRQ\n");
++          if(ReadByteLock_ACC(pbmi_lcd, ACC_INTRQ, acc_data, slot))
++            return;
++        }
++
++        // write PAGESEL
++        *acc_data = 0x1;
++        if(WriteByteLock_ACC(pbmi_lcd, ACC_PAGESEL, *acc_data, slot))
++          return;
++
++
++
++        // report orientation
++        // printk(KERN_INFO "bmi_lcd.c: bmi_lcd_input work (slot %d) pitch=0x%x, roll=0x%x, ABS_MISC=0x%x\n",
++        // slot, pitch, roll, pitch << 16 | roll);    //pjg - debug
++
++        input_report_abs(pbmi_lcd->input_dev[slot], ABS_MISC, (pitch << 16) | roll);
++        input_sync(pbmi_lcd->input_dev[slot]);
++      }
++
++      // read touch screen - X, Y, TOUCH, PRESSURE
++
++
++      penirq = bmi_slot_status_irq_state(slot);
++      /*printk(KERN_INFO "bmi_lcd.c: IRQ Status %d (slot %d) %d\n", penirq, slot,msecs_to_jiffies(10));*/
++
++      if (pbmi_lcd->activated[slot] && penirq)
++        {
++
++          for(debounce = 0; debounce < DEBOUNCE; debounce++)
++            {
++
++              memset(buf, 0, 4);
++              buf[3] = SPI_START | SPI_AY | SPI_MODE_12 | SPI_MODE_DFR | SPI_ADC;
++              spi_lcd_read_reg(pbmi_lcd, buf, 1, slot);
++              y = (((buf[0] << 5) | buf[1] >> 3)) & 0xFFF;
++
++              memset(buf, 0, 4);
++              buf[3] = SPI_START | SPI_AX | SPI_MODE_12 | SPI_MODE_DFR | SPI_ADC;
++              spi_lcd_read_reg(pbmi_lcd, buf, 1, slot);
++              x = (((buf[0] << 5) | buf[1]) >> 3) & 0xFFF;
++
++              memset(buf, 0, 4);
++              buf[3] = SPI_START | SPI_AZ1 | SPI_MODE_12 | SPI_MODE_DFR | SPI_ADC;
++              spi_lcd_read_reg(pbmi_lcd, buf, 1, slot);
++              z1 = (((buf[0] << 5) | buf[1]) >> 3) & 0xFFF;
++
++              memset(buf, 0, 4);
++              buf[3] = SPI_START | SPI_AZ2 | SPI_MODE_12 | SPI_MODE_DFR | SPI_ADC;
++              spi_lcd_read_reg(pbmi_lcd, buf, 1, slot);
++              z2 = (((buf[0] << 5) | buf[1]) >> 3) & 0xFFF;
++              mdelay(1);
++            }
++
++          if(x && y && z1 && z2)
++            pressure = (X_PLATE * x / 4096) * ((z2 / z1) - 1);
++
++          x = 4096 - x;
++          y = 4096 - y;
++
++          if (pressure < 70)
++            {
++              if (pbmi_lcd->scount)
++                update_pen_state(arg, slot, x, y, pressure);
++              else
++                {
++                  pbmi_lcd->scount[slot]++;
++                  /*update_pen_state(arg, slot, 0, 0, pressure);*/
++                }
++            }
++          /* else
++            {
++              update_pen_state(arg, slot, 0, 0, pressure);
++              }*/
++
++              switch(slot)
++                {
++                case BMI_TS_M1:
++                  schedule_delayed_work(&bmilcd_work0, WORK_DELAY);
++                  break;
++                case BMI_TS_M2:
++                  schedule_delayed_work(&bmilcd_work1, WORK_DELAY);
++                  break;
++                case BMI_TS_M3:
++                  schedule_delayed_work(&bmilcd_work2, WORK_DELAY);
++                  break;
++                case BMI_TS_M4:
++                  schedule_delayed_work(&bmilcd_work3, WORK_DELAY);
++                  break;
++                }
++              /* printk(KERN_INFO "bmi_lcd.c: work scheduled on (slot %d)\n", slot); */
++              /*buf[3] = SPI_START | SPI_PD;
++                spi_lcd_write_reg(pbmi_lcd, buf, 1, slot);*/
++        }
++
++      else
++        {
++          /*printk(KERN_INFO "bmi_lcd.c: Pen up on (slot %d)\n", slot);*/
++          memset(buf, 0, 4);
++          buf[3] = SPI_START | SPI_PD;
++          spi_lcd_write_reg(pbmi_lcd, buf, 1, slot);
++          update_pen_state(arg,slot, 0, 0, 0);
++          enable_irq(pbmi_lcd->interrupt[slot]);
++        }
++
++}
++
++
++// interrupt handler
++static irqreturn_t module_irq_handler(int irq, void *dummy)
++{
++  disable_irq(irq);
++  /*printk(KERN_INFO "bmi_lcd.c: Interupt on (slot %d)\n", irq);*/
++  switch(irq)
++    {
++    case M1_IRQ:
++      schedule_delayed_work(&bmilcd_work0, WORK_DELAY);
++      pbmi_lcd.scount[BMI_TS_M1] = 0;
++      break;
++    case M2_IRQ:
++      schedule_delayed_work(&bmilcd_work1, WORK_DELAY);
++      pbmi_lcd.scount[BMI_TS_M2] = 0;
++      break;
++    case M3_IRQ:
++      schedule_delayed_work(&bmilcd_work2, WORK_DELAY);
++      pbmi_lcd.scount[BMI_TS_M3] = 0;
++      break;
++    case M4_IRQ:
++      schedule_delayed_work(&bmilcd_work3, WORK_DELAY);
++      pbmi_lcd.scount[BMI_TS_M4] = 0;
++      break;
++    }
++  return IRQ_HANDLED;
++}
++
++/*
++ * control device operations
++ */
++
++/*
++ * control device operations
++ */
++
++// open
++int cntl_open(struct inode *inode, struct file *filp)
++{
++      if(pbmi_lcd.open_flag) {
++              return - EBUSY;
++      }
++      pbmi_lcd.open_flag = 1;
++      filp->private_data = &pbmi_lcd;
++      return 0;
++}
++
++// release
++int cntl_release(struct inode *inode, struct file *filp)
++{
++      pbmi_lcd.open_flag = 0;
++      return 0;
++}
++
++// ioctl
++int cntl_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
++                 unsigned long arg)
++{
++      struct i2c_adapter *adap;
++      unsigned char iox_data[1];
++      int slot = (__user arg) & 0xF;
++      int bl = ((__user arg) & 0x70) >> 4;
++
++              // error if no lcd active.
++      if(pbmi_lcd.active == -1)
++              return -ENODEV;
++
++      if(cmd != BMI_LCD_GETSTAT) {
++
++                      // error if slot invalid
++              if((slot < CPLD_M1) || (slot > CPLD_M4))
++                      return -ENODEV;
++
++                      // error if no lcd in chosen slot
++              if(pbmi_lcd.bdev[slot] == 0)
++                      return -ENODEV;
++
++                      // i2c adapter
++              adap = &pbmi_lcd.bdev[slot]->adap;
++      }
++
++              // ioctl's
++      switch (cmd) {
++              case BMI_LCD_RLEDOFF:
++                      bmi_set_module_gpio_data(slot, 3, 1);// Red LED=OFF
++                      break;
++              case BMI_LCD_RLEDON:
++                      bmi_set_module_gpio_data(slot, 3, 0);// Red LED=ON
++                      break;
++              case BMI_LCD_GLEDOFF:
++                      bmi_set_module_gpio_data(slot, 2, 1);// Green LED=OFF
++                      break;
++              case BMI_LCD_GLEDON:
++                      bmi_set_module_gpio_data(slot, 2, 0);// Green LED=ON
++                      break;
++              case BMI_LCD_VSYNC_DIS: // enable VSYNC buffer tristate output
++                if(ReadByteLock_IOX(&pbmi_lcd, IOX_OUTPUT_REG, iox_data, slot))
++                  return -ENODEV;
++                *iox_data |= 0x08;
++                if(WriteByteLock_IOX(&pbmi_lcd, IOX_OUTPUT_REG, *iox_data, slot))
++                  return -ENODEV;
++                break;
++              case BMI_LCD_VSYNC_EN:  // disable VSYNC buffer tristate output
++                if(ReadByteLock_IOX(&pbmi_lcd, IOX_OUTPUT_REG, iox_data, slot))
++                  return -ENODEV;
++                *iox_data &= ~0x08;
++                if(WriteByteLock_IOX(&pbmi_lcd, IOX_OUTPUT_REG, *iox_data, slot))
++                  return -ENODEV;
++                break;
++              case BMI_LCD_EN:        // enable LCD component
++                if(ReadByteLock_IOX(&pbmi_lcd, IOX_OUTPUT_REG, iox_data, slot))
++                  return -ENODEV;
++                *iox_data &= ~0x10;
++                if(WriteByteLock_IOX(&pbmi_lcd, IOX_OUTPUT_REG, *iox_data, slot))
++                  return -ENODEV;
++                break;
++              case BMI_LCD_DIS:       // disable LCD component only
++                if(ReadByteLock_IOX(&pbmi_lcd, IOX_OUTPUT_REG, iox_data, slot))
++                  return -ENODEV;
++                *iox_data |= 0x10;
++                if(WriteByteLock_IOX(&pbmi_lcd, IOX_OUTPUT_REG, *iox_data, slot))
++                  return -ENODEV;
++                break;
++              case BMI_LCD_SER_EN:    // enable Serializer component
++                if(ReadByteLock_IOX(&pbmi_lcd, IOX_OUTPUT_REG, iox_data, slot))
++                  return -ENODEV;
++                *iox_data &= ~0x20;
++                if(WriteByteLock_IOX(&pbmi_lcd, IOX_OUTPUT_REG, *iox_data, slot))
++                  return -ENODEV;
++                break;
++              case BMI_LCD_SER_DIS:   // disable Serializer component only
++                if(ReadByteLock_IOX(&pbmi_lcd, IOX_OUTPUT_REG, iox_data, slot))
++                  return -ENODEV;
++                *iox_data |= 0x20;
++                if(WriteByteLock_IOX(&pbmi_lcd, IOX_OUTPUT_REG, *iox_data, slot))
++                  return -ENODEV;
++                break;
++              case BMI_LCD_SETRST:    // overall module reset
++                bmi_set_module_gpio_data (slot, 1, 0);                // RST=0
++                break;
++              case BMI_LCD_CLRRST:    // overall module enable
++                bmi_set_module_gpio_data (slot, 1, 1);                // RST=1
++                break;
++              case BMI_LCD_SET_BL:    // set backlight brightness
++                if(ReadByteLock_IOX(&pbmi_lcd, IOX_OUTPUT_REG, iox_data, slot))
++                  return -ENODEV;
++                *iox_data = (*iox_data & 0xF8) | bl;
++                if(WriteByteLock_IOX(&pbmi_lcd, IOX_OUTPUT_REG, *iox_data, slot))
++                  return -ENODEV;
++                break;
++              case BMI_LCD_GETSTAT:
++                {
++                  int *slot = ((int __user *) arg);
++                  int read_data;
++
++                  *slot &= 0xF;
++
++                  // error if slot invalid
++                  if((*slot < CPLD_M1) || (*slot > CPLD_M4))
++                    return -ENODEV;
++
++                  // error if no lcd in chosen slot
++                  if(pbmi_lcd.bdev[*slot] == 0)
++                    return -ENODEV;
++
++                  // i2c adapter
++                  adap = &pbmi_lcd.bdev[*slot]->adap;
++
++                  if(ReadByteLock_IOX(&pbmi_lcd, IOX_INPUT_REG, iox_data, *slot))
++                    return -ENODEV;
++
++                  read_data = *iox_data | (bmi_read_gpio_data_reg(*slot) << 8);
++
++                  if(put_user(read_data, (int __user *) arg))
++                    return -EFAULT;
++                }
++                break;
++              case BMI_LCD_ACTIVATE:  //pjg fix/test
++                // check for opposite side already active
++                switch(slot) {        // opposite side
++                case 0:
++                  if(pbmi_lcd.activated[2] == 1) {
++                    printk(KERN_INFO "bmi_lcd.c: probe slot %d not allowed (slot 2 already active)\n", slot);
++                    bmi_slot_power_off(0);
++                    return -ENODEV;
++                  }
++                  break;
++                case 1:
++                  if(pbmi_lcd.activated[3] == 1) {
++                    printk(KERN_INFO "bmi_lcd.c: probe slot %d not allowed (slot 3 already active)\n", slot);
++                    bmi_slot_power_off(1);
++                    return -ENODEV;
++                  }
++                  break;
++                case 2:
++                  if(pbmi_lcd.activated[0] == 1) {
++                    printk(KERN_INFO "bmi_lcd.c: probe slot %d not allowed (slot 0 already active)\n", slot);
++                    bmi_slot_power_off(2);
++                    return -ENODEV;
++                  }
++                  break;
++                case 3:
++                  if(pbmi_lcd.activated[1] == 1) {
++                    printk(KERN_INFO "bmi_lcd.c: probe slot %d not allowed (slot 1 already active)\n", slot);
++                    bmi_slot_power_off(3);
++                    return -ENODEV;
++                  }
++                  break;
++                }
++                // activate
++                if((!pbmi_lcd.activated[slot]) && (pbmi_lcd.bdev[slot] != 0)) {
++                  bmi_lcd_probe(pbmi_lcd.bdev[slot]);
++                }
++                break;
++              case BMI_LCD_DEACTIVATE:
++                if(pbmi_lcd.activated[slot]) {
++                  disable_irq_nosync(pbmi_lcd.interrupt[slot]);
++                  pbmi_lcd.activated[slot] = 0;
++                  if(ReadByteLock_IOX(&pbmi_lcd, IOX_OUTPUT_REG, iox_data, slot))
++                    return -ENODEV;
++                  *iox_data = (*iox_data & 0xF8);
++                  if(WriteByteLock_IOX(&pbmi_lcd, IOX_OUTPUT_REG, *iox_data, slot))
++                    return -ENODEV;
++                  bmi_slot_power_off(slot);
++                }
++                break;
++              case BMI_LCD_SUSPEND:
++                printk(KERN_ERR "BMI_LCD_SUSPEND NOT IMPLEMENTED\n"); //pjg
++                break;
++              case BMI_LCD_RESUME:
++                printk(KERN_ERR "BMI_LCD_RESUME NOT IMPLEMENTED\n");  //pjg
++                break;
++              default:
++                return -ENOTTY;
++      }
++      return 0;
++}
++
++      // control file operations
++struct file_operations cntl_fops = {
++      .owner = THIS_MODULE,
++      .ioctl = cntl_ioctl,
++      .open = cntl_open,
++      .release = cntl_release,
++};
++
++      // BMI LCD fops
++void bmi_lcd_config(struct bmi_lcd *lcd, int disp)
++{
++      if(pbmi_lcd.active == -1) {
++              return;
++      }
++
++      if((lcd) && (lcd->lcd_ops.config)) {
++              lcd->lcd_ops.config(disp);
++      }
++}
++
++void bmi_lcd_reset(struct bmi_lcd *lcd, int slot)
++{
++      if(pbmi_lcd.active == -1) {
++              return;
++      }
++
++      if((lcd) && (lcd->lcd_ops.reset)) {
++              lcd->lcd_ops.reset(slot);
++      }
++}
++
++
++static struct miscdevice cntl_dev = {
++      MISC_DYNAMIC_MINOR,
++      "bmi_lcd_control",
++      &cntl_fops
++};
++
++/*
++ *    Module functions
++ */
++
++char const input_name0[MAX_STRG] = "bmi_lcd_ts0";
++char const input_name1[MAX_STRG] = "bmi_lcd_ts1";
++char const input_name2[MAX_STRG] = "bmi_lcd_ts2";
++char const input_name3[MAX_STRG] = "bmi_lcd_ts3";
++char const input_name4[MAX_STRG] = "bmi_lcd_ts4";
++char const input_name5[MAX_STRG] = "bmi_lcd_ts5";
++char const input_name6[MAX_STRG] = "bmi_lcd_ts6";
++
++static __init int bmi_lcd_init(void)
++{
++      int ts;
++      int rc = 0;
++
++              // No lcd is active.
++      pbmi_lcd.active = -1;
++      pbmi_lcd.activated[0] = 0;
++      pbmi_lcd.activated[1] = 0;
++      pbmi_lcd.activated[2] = 0;
++      pbmi_lcd.activated[3] = 0;
++
++              // set up control character device - bmi_lcd_control
++      rc = misc_register(&cntl_dev);
++      if(rc) {
++              printk(KERN_ERR "bmi_lcd.c: Can't allocate bmi_lcd_control device\n");
++              return rc;
++      }
++
++              // Allocate and Register input device. - bmi_lcd_ts[BMI_TS_M1:BMI_TS_M1234]
++      for(ts = BMI_TS_M1; ts < BMI_TS_NUM; ts++) {
++              pbmi_lcd.input_dev[ts] = input_allocate_device();
++              if(!pbmi_lcd.input_dev[ts]) {
++                      printk(KERN_ERR "bmi_lcd_init: Can't allocate input_dev[ts]\n");
++                      return -ENOMEM;
++              }
++
++              // set up input device
++              switch(ts) {
++                  case BMI_TS_M1:
++                      pbmi_lcd.input_dev[BMI_TS_M1]->name = input_name0;
++                      pbmi_lcd.input_dev[BMI_TS_M1]->phys = input_name0;
++                      break;
++                  case BMI_TS_M2:
++                      pbmi_lcd.input_dev[BMI_TS_M2]->name = input_name1;
++                      pbmi_lcd.input_dev[BMI_TS_M2]->phys = input_name1;
++                      break;
++                  case BMI_TS_M3:
++                      pbmi_lcd.input_dev[BMI_TS_M3]->name = input_name2;
++                      pbmi_lcd.input_dev[BMI_TS_M3]->phys = input_name2;
++                      break;
++                  case BMI_TS_M4:
++                      pbmi_lcd.input_dev[BMI_TS_M4]->name = input_name3;
++                      pbmi_lcd.input_dev[BMI_TS_M4]->phys = input_name3;
++                      break;
++                  case BMI_TS_M13:
++                      pbmi_lcd.input_dev[BMI_TS_M13]->name = input_name4;
++                      pbmi_lcd.input_dev[BMI_TS_M13]->phys = input_name4;
++                      break;
++                  case BMI_TS_M24:
++                      pbmi_lcd.input_dev[BMI_TS_M24]->name = input_name5;
++                      pbmi_lcd.input_dev[BMI_TS_M24]->phys = input_name5;
++                      break;
++                  case BMI_TS_M1234:
++                      pbmi_lcd.input_dev[BMI_TS_M1234]->name = input_name6;
++                      pbmi_lcd.input_dev[BMI_TS_M1234]->phys = input_name6;
++                      break;
++              }
++              pbmi_lcd.input_dev[ts]->id.bustype = BUS_BMI;
++              pbmi_lcd.input_dev[ts]->private = &pbmi_lcd;
++              pbmi_lcd.input_dev[ts]->evbit[BIT_WORD(EV_KEY)] |= BIT_MASK(EV_KEY);
++              pbmi_lcd.input_dev[ts]->evbit[BIT_WORD(EV_ABS)] |= BIT_MASK(EV_ABS);
++              pbmi_lcd.input_dev[ts]->keybit[BIT_WORD(BTN_TOUCH)] |= BIT_MASK(BTN_TOUCH);
++              pbmi_lcd.input_dev[ts]->absbit[BIT_WORD(ABS_X)] |= BIT_MASK(ABS_X);
++              pbmi_lcd.input_dev[ts]->absbit[BIT_WORD(ABS_Y)] |= BIT_MASK(ABS_Y);
++              pbmi_lcd.input_dev[ts]->absbit[BIT_WORD(ABS_PRESSURE)] |= BIT_MASK(ABS_PRESSURE);
++              pbmi_lcd.input_dev[ts]->absbit[BIT_WORD(ABS_MISC)] |= BIT_MASK(ABS_MISC);
++              input_set_abs_params(pbmi_lcd.input_dev[ts], ABS_X, BMI_LCD_MIN_XC, BMI_LCD_MAX_XC, 0, 0);
++              input_set_abs_params(pbmi_lcd.input_dev[ts], ABS_Y, BMI_LCD_MIN_YC, BMI_LCD_MAX_YC, 0, 0);
++              input_set_abs_params(pbmi_lcd.input_dev[ts], ABS_PRESSURE, 0, 1024, 0, 0);
++
++              // register input device
++              if(input_register_device(pbmi_lcd.input_dev[ts])) {
++                int tts;
++                      printk(KERN_ERR "bmi_lcd_init() - input_register_device failed.\n");
++
++                      for(tts = BMI_TS_M1; tts < ts; tts++)
++                              input_unregister_device(pbmi_lcd.input_dev[tts]);
++
++                      misc_deregister(&cntl_dev);
++
++                      return -ENODEV;
++              }
++      }
++
++      pbmi_lcd.lcd_cnt = 0;
++
++              // hardware specfic set-up
++      s320x240_bmi_lcd.interface = s320x240_lcd_interface,
++      s320x240_bmi_lcd_ops.config = (void(*)) &s320x240_config;
++      s320x240_bmi_lcd_ops.reset = NULL;      //pjg - placeholder for multiple LCD hardware types
++      s320x240_bmi_lcd_ops.suspend = NULL;    //pjg - placeholder for multiple LCD hardware types
++      s320x240_bmi_lcd_ops.resume = NULL;     //pjg - placeholder for multiple LCD hardware types
++      s320x240_bmi_lcd_ops.disp_on = NULL;    //pjg - placeholder for multiple LCD hardware types
++      s320x240_bmi_lcd_ops.disp_off = NULL;   //pjg - placeholder for multiple LCD hardware types
++      s320x240_bmi_lcd_ops.activate = NULL;   //pjg - placeholder for multiple LCD hardware types
++      s320x240_bmi_lcd_ops.deactivate = NULL; //pjg - placeholder for multiple LCD hardware types
++      s320x240_bmi_lcd.lcd_ops = s320x240_bmi_lcd_ops;
++      pbmi_lcd.blcd[0] = &s320x240_bmi_lcd;
++      pbmi_lcd.blcd[1] = &s320x240_bmi_lcd;
++      pbmi_lcd.blcd[2] = &s320x240_bmi_lcd;
++      pbmi_lcd.blcd[3] = &s320x240_bmi_lcd;
++
++      sema_init(&pbmi_lcd.sem[0], 1);
++      sema_init(&pbmi_lcd.sem[1], 1);
++      sema_init(&pbmi_lcd.sem[2], 1);
++      sema_init(&pbmi_lcd.sem[3], 1);
++
++      sema_init(&pbmi_lcd.i2c_sem[0], 1);
++      sema_init(&pbmi_lcd.i2c_sem[1], 1);
++      sema_init(&pbmi_lcd.i2c_sem[2], 1);
++      sema_init(&pbmi_lcd.i2c_sem[3], 1);
++
++      acc_init();
++
++      /*s320x240_config(0);
++        s320x240_config(1);*/
++
++      // register with BMI
++      rc = bmi_register_driver(&bmi_lcd_driver);
++      if(rc) {
++              printk(KERN_ERR "bmi_lcd.c: Can't register bmi_lcd_driver\n");
++
++              for(ts = BMI_TS_M1; ts < BMI_TS_NUM; ts++)
++                      input_unregister_device(pbmi_lcd.input_dev[ts]);
++
++              misc_deregister(&cntl_dev);
++
++              return rc;
++      }
++
++      printk("bmi_lcd.c: BMI_LCD Driver v%s \n", BMILCD_VERSION);
++
++      return 0;
++}
++
++static void __exit bmi_lcd_clean(void)
++{
++      int ts;
++
++              // delete timers
++      del_timer(&pbmi_lcd.timer[0]);
++      del_timer(&pbmi_lcd.timer[1]);
++      del_timer(&pbmi_lcd.timer[2]);
++      del_timer(&pbmi_lcd.timer[3]);
++
++              // remove input devices
++      for(ts = BMI_TS_M1; ts < BMI_TS_NUM; ts++)
++              input_unregister_device(pbmi_lcd.input_dev[ts]);
++
++              // remove control device
++      misc_deregister(&cntl_dev);
++
++              // remove bmi driver
++      bmi_unregister_driver(&bmi_lcd_driver);
++
++      acc_clean();
++
++        return;
++}
++
++module_init(bmi_lcd_init);
++module_exit(bmi_lcd_clean);
++
++
++MODULE_AUTHOR("Peter Giacomini <p.giacomini@encadis.com>");
++MODULE_DESCRIPTION("BMI lcd device driver");
++MODULE_SUPPORTED_DEVICE("bmi_lcd_control");
++MODULE_SUPPORTED_DEVICE("bmi_lcd_ts");
++MODULE_SUPPORTED_DEVICE("bmi_lcd_acc");
++MODULE_LICENSE("GPL");
+--- /dev/null
++++ git/drivers/bmi/pims/lcd/bmi_s320x240.c
+@@ -0,0 +1,632 @@
++#include <linux/bmi.h>
++#include <linux/bmi/bmi-control.h>
++#include <linux/bmi/bmi_camera.h>     //pjg
++#include <linux/delay.h>
++#include <linux/input.h>
++#include <linux/workqueue.h>
++#include "bug_lcd.h"
++
++// BMI device ID table
++static struct bmi_device_id bmi_vs6624_tbl[] =
++{
++      { //pjg .match_flags = BMI_DEVICE_ID_MATCH_VENDOR | BMI_DEVICE_ID_MATCH_PRODUCT,
++              .match_flags = BMI_ANY,
++              .vendor   = BMI_VENDOR_BUG_LABS,
++              .product  = BMI_PRODUCT_CAMERA_VS6624,
++              .revision = BMI_ANY,
++      },
++      { 0, },                               /* terminate list */
++};
++MODULE_DEVICE_TABLE(bmi, bmi_vs6624_tbl);
++
++int   bmi_vs6624_probe(struct bmi_device *bdev);
++void  bmi_vs6624_remove(struct bmi_device *bdev);
++int   bmi_vs6624_suspend(struct bmi_device *bdev);
++int   bmi_vs6624_resume(struct bmi_device *bdev);
++
++// BMI driver structure
++static struct bmi_driver bmi_vs6624_driver =
++{
++      .name = "bmi_vs6624",
++      .id_table = bmi_vs6624_tbl,
++      .probe   = bmi_vs6624_probe,
++      .remove  = bmi_vs6624_remove,
++      };
++
++
++struct bmi_vs6624 {
++      struct bmi_device *bdev;
++      struct bmi_cam    bcam;
++      unsigned int    shutter;     // shutter button save state
++      unsigned int    zoomin;      // zoomin button save state
++      unsigned int    zoomout;     // zoom out button save state
++      unsigned int    flash;       // state of camera FLASH
++      int irq;
++      struct input_dev *idev;
++      struct work_struct work;
++
++};
++
++      // I2C Slave Address
++#define BMI_IOX_I2C_ADDRESS   0x71    // 7-bit address
++
++      // I2C IOX register addresses
++#define IOX_INPUT_REG         0x0
++#define IOX_OUTPUT_REG                0x1
++#define IOX_POLARITY_REG      0x2
++#define IOX_CONTROL                   0x3
++
++
++// read byte from I2C IO expander
++
++static int ReadByte_IOX(struct i2c_adapter *adap, unsigned char offset, unsigned char *data)
++{
++        int    ret = 0;
++        struct i2c_msg rmsg[2];
++        int    num_msgs;
++
++        /* Read Byte with Pointer */
++
++        rmsg[0].addr = BMI_IOX_I2C_ADDRESS;
++        rmsg[0].flags = 0;          /* write */
++        rmsg[0].len = 1;
++        rmsg[0].buf = &offset;
++
++        rmsg[1].addr = BMI_IOX_I2C_ADDRESS;
++        rmsg[1].flags = I2C_M_RD;   /* read */
++        rmsg[1].len = 1;
++        rmsg[1].buf = data;
++
++        num_msgs = 2;
++        ret = i2c_transfer (adap, rmsg, num_msgs);
++
++        if (ret == 2) {
++                ret = 0;
++        }
++        else {
++                //Rework: add conditional debug messages here
++                ret = -1;
++        }
++        return ret;
++}
++
++
++// write byte to I2C IO expander
++static int WriteByte_IOX(struct i2c_adapter *adap, unsigned char offset, unsigned char data)
++{
++        int    ret = 0;
++        struct i2c_msg wmsg[2];
++        int    num_msgs;
++
++        /* Write Byte with Pointer */
++
++
++        wmsg[0].addr = BMI_IOX_I2C_ADDRESS;
++        wmsg[0].flags = 0;          /* write */
++        wmsg[0].len = 1;
++        wmsg[0].buf = &offset;
++
++        wmsg[1].addr = BMI_IOX_I2C_ADDRESS;
++        wmsg[1].flags = 0;       /* write */
++        wmsg[1].len = 1;
++        wmsg[1].buf = &data;
++
++        num_msgs = 2;
++
++
++        ret = i2c_transfer (adap, wmsg, num_msgs);
++
++        if (ret == 2) {
++                ret = 0;
++        }
++        else {
++                //Rework: add conditional debug messages here
++
++                printk (KERN_ERR "WriteByte_IOX() - i2c_transfer() failed.\n");
++                ret = -1;
++        }
++        return ret;
++}
++
++
++/*
++ * Input interrupt handler and support routines
++ */
++
++
++// work handler
++void bmi_vs6624_buttons_work(void *arg)
++{
++      struct bmi_vs6624 *bmicam = (struct bmi_vs6624*)arg;
++      struct i2c_adapter *adap = &bmicam->bdev->adap;
++
++      unsigned char   iox_data;
++      unsigned int    test_value;
++      int sync_flag = 0;
++
++
++      // read IOX data input
++      ReadByte_IOX (adap, IOX_INPUT_REG, &iox_data);
++
++      // zoom in button
++      test_value = !((iox_data & 0x2) >> 1);
++      if (test_value != bmicam->zoomin) {
++              printk (KERN_ERR "bmi_vs6624buttons_work() - report ZOOMIN\n");
++              bmicam->zoomin = test_value;
++              input_report_key(bmicam->idev, BN_ZOOMIN, test_value);
++              sync_flag = 1;
++      }
++
++
++      // zoom out button
++      test_value = !((iox_data & 0x4) >> 2);
++      if (test_value != bmicam->zoomout) {
++              printk (KERN_ERR "bmi_vs6624_buttons_work() - report ZOOMOUT\n");
++              bmicam->zoomout = test_value;
++              input_report_key(bmicam->idev, BN_ZOOMOUT, test_value);
++              sync_flag = 1;
++      }
++
++      // flash button
++      test_value = (iox_data & 0x8) >> 3;
++      if (test_value != bmicam->flash) {
++              printk (KERN_ERR "bmi_vs6624_buttons_work() - report FLASH\n");
++              bmicam->flash = test_value;
++              input_report_key(bmicam->idev, BN_FLASH, test_value);
++              sync_flag = 1;
++      }
++
++
++      if ( sync_flag ) {
++              printk (KERN_ERR "bmi_vs6624_buttons_work() - input_sync()ing..\n");
++              input_sync(bmicam->idev);
++      }
++
++      enable_irq(bmicam->irq);
++
++}
++
++
++// interrupt handler
++static irqreturn_t module_irq_handler(int irq, void *dummy)
++{
++      struct bmi_vs6624 *bmicam = dummy;
++      unsigned int test_value;
++
++      int slot;
++
++
++      disable_irq_nosync(irq);
++
++      slot = bmicam->bdev->info->slot;
++
++
++      // shutter button on GPIO
++
++      test_value = !(bmi_read_gpio_data_reg (slot) & 0x1);
++
++      if (!test_value == bmicam->shutter) {
++              bmicam->shutter = test_value;
++              printk (KERN_ERR "module_irq_handler() - report SHUTTER\n");
++              input_report_key(bmicam->idev, BN_SHUTTER, test_value);
++              input_sync(bmicam->idev);
++      }
++
++
++
++      // other buttons on I2C IOX
++      schedule_work (&bmicam->work);
++      return IRQ_HANDLED;
++}
++
++/*
++ * control functions
++ */
++
++
++// configure IOX IO and states
++void configure_IOX(struct bmi_vs6624 *cam)
++{
++      struct i2c_adapter *adap = &cam->bdev->adap;
++
++      printk (KERN_ERR "configure_IOX() - enter\n");
++      printk (KERN_ERR "configure_IOX() - cam             = %p\n", cam);
++      printk (KERN_ERR "configure_IOX() - cam->bdev       = %p\n", cam->bdev);
++      printk (KERN_ERR "configure_IOX() - cam->bdev->adap = %p\n", &cam->bdev->adap);
++
++
++      WriteByte_IOX (adap, IOX_OUTPUT_REG, 0x40);           // CE=0, F_CHG=1,SYNC=0, TORCH=0
++      WriteByte_IOX (adap, IOX_CONTROL, 0x0F);              // IOX[7:4]=OUT, IOX[3:0]=IN
++}
++
++// configure GPIO IO and states
++void configure_GPIO(struct bmi_vs6624 *cam)
++{
++      // set states before turning on outputs
++
++      int slot = cam->bdev->info->slot;
++
++      bmi_set_module_gpio_data (slot, 3, 1); // Red LED=OFF
++      bmi_set_module_gpio_data (slot, 2, 1); // Green LED=OFF
++      bmi_set_module_gpio_data (slot, 1, 0); // SER_RST=0
++
++      // configure direction
++      bmi_set_module_gpio_data (slot, 3, BMI_GPIO_OUT);
++      bmi_set_module_gpio_data (slot, 2, BMI_GPIO_OUT);
++      bmi_set_module_gpio_data (slot, 1, BMI_GPIO_OUT);
++      bmi_set_module_gpio_data (slot, 0, BMI_GPIO_IN); // SHUTTER
++}
++
++// deconfigure IOX and GPIO
++void deconfigure_module(struct bmi_vs6624 *cam)
++{
++      int slot = cam->bdev->info->slot;
++      struct i2c_adapter *adap = &cam->bdev->adap;
++
++      WriteByte_IOX (adap, IOX_CONTROL, 0xFF);
++      bmi_set_module_gpio_data (slot, 3, BMI_GPIO_IN);
++      bmi_set_module_gpio_data (slot, 2, BMI_GPIO_IN);
++      bmi_set_module_gpio_data (slot, 1, BMI_GPIO_IN);
++}
++
++
++// configure serializer on plug-in module
++void configure_serializer(struct bmi_vs6624 *cam)
++{
++      int slot = cam->bdev->info->slot;
++
++      bmi_set_module_gpio_data(slot, 1, 1);            // SER_RST=1
++}
++
++void deconfigure_serializer(struct bmi_vs6624 *cam)
++{
++      int slot = cam->bdev->info->slot;
++      bmi_set_module_gpio_data(slot, 1, 0);           // SER_RST=0
++}
++
++void enable_camera(struct bmi_vs6624 *cam)
++{
++      struct i2c_adapter *adap = &cam->bdev->adap;
++        unsigned char iox_data;
++
++        printk (KERN_ERR "enable_camera() enter\n");
++
++        // The first i2c read seems to mess everything up.
++
++        ReadByte_IOX(adap, IOX_OUTPUT_REG, &iox_data);
++        printk (KERN_ERR "enable_camera() iox_data = %02X\n", iox_data);
++
++        WriteByte_IOX(adap, IOX_OUTPUT_REG, iox_data | 0x80);
++        printk (KERN_ERR "enable_camera() exit\n");
++}
++
++// disable camera on plug-in module
++void disable_camera(struct bmi_vs6624 *cam)
++{
++      struct i2c_adapter *adap = &cam->bdev->adap;
++        unsigned char iox_data;
++
++        printk (KERN_ERR "disable_camera() enter\n");
++
++        ReadByte_IOX (adap, IOX_OUTPUT_REG, &iox_data);
++        WriteByte_IOX (adap, IOX_OUTPUT_REG, iox_data & 0x70);
++
++        printk (KERN_ERR "disable_camera() exit\n");
++}
++
++// generate sync
++void generate_camera_sync(struct i2c_adapter *adap)
++{
++      unsigned char iox_data[0];
++
++      printk(KERN_INFO "generate_camera_sync() - enter\n");
++      ReadByte_IOX (adap, IOX_OUTPUT_REG, iox_data);
++
++      printk(KERN_INFO "generate_camera_sync() - read  = %02X\n", iox_data[0]);
++      printk(KERN_INFO "generate_camera_sync() - write = %02X\n", *iox_data | 0x20);
++
++      WriteByte_IOX (adap, IOX_OUTPUT_REG, *iox_data | 0x20);// SYNC = 1
++
++      printk(KERN_INFO "generate_camera_sync() - write = %02X\n", *iox_data & 0xD0);
++
++      WriteByte_IOX (adap, IOX_OUTPUT_REG, *iox_data & 0xD0);// SYNC = 0
++      udelay(20);                                   // 60 MHz * 1024 = ~17 us sync time
++
++      printk(KERN_INFO "generate_camera_sync() - exit\n");
++}
++
++void set_sync(struct i2c_adapter *adap)
++{
++      unsigned char iox_data[0];
++
++      printk(KERN_INFO "set_sync() - enter\n");
++
++      ReadByte_IOX (adap, IOX_OUTPUT_REG, iox_data);
++      WriteByte_IOX (adap, IOX_OUTPUT_REG, *iox_data | 0x20);// SYNC = 1
++
++      printk(KERN_INFO "set_sync() - exit\n");
++}
++
++void clear_sync(struct i2c_adapter *adap)
++{
++      unsigned char iox_data[0];
++
++      printk(KERN_INFO "clear_sync() - enter\n");
++
++      ReadByte_IOX (adap, IOX_OUTPUT_REG, iox_data);
++      WriteByte_IOX (adap, IOX_OUTPUT_REG, *iox_data & 0xD0);// SYNC = 0
++
++      printk(KERN_INFO "clear_sync() - exit\n");
++}
++
++
++// check serializer lock
++int check_camera_lock(void)
++{
++      return bmi_sensor_lock_status();
++}
++
++void bmi_vs6624_set_color(struct bmi_cam *cam, int bright, int saturation, int red, int green, int blue)
++{
++
++      struct i2c_adapter *adap;
++      struct bmi_vs6624 *bmi_vs6624;
++
++      bmi_vs6624 = container_of(cam, struct bmi_vs6624, bcam);
++      adap = &bmi_vs6624->bdev->adap;
++
++      vs6624_set_color (adap, bright, saturation, red, green, blue);
++      return;
++
++}
++
++void bmi_vs6624_get_color(struct bmi_cam *cam, int *bright, int *saturation, int *red, int *green, int *blue)
++{
++      struct i2c_adapter *adap;
++      struct bmi_vs6624 *bmi_vs6624;
++
++      bmi_vs6624 = container_of(cam, struct bmi_vs6624, bcam);
++      adap = &bmi_vs6624->bdev->adap;
++
++      vs6624_get_color (adap, bright, saturation, red, green, blue);
++      return;
++}
++
++
++
++
++void bmi_vs6624_set_ae_mode (struct bmi_cam *cam, int ae_mode)
++{
++      printk (KERN_ERR "bmi_vs6624_set_ae_mode() - NOT IMPLEMENTED.\n");
++}
++
++
++void bmi_vs6624_get_ae_mode (struct bmi_cam *cam, int *ae_mode)
++{
++      printk (KERN_ERR "bmi_vs6624_set_ae_mode() - NOT IMPLEMENTED.\n");
++}
++
++
++sensor_interface * bmi_vs6624_config (struct bmi_cam *cam, int *frame_rate, int high_quality)
++{
++      //REWORK: Add code here
++      return 0;
++
++}
++
++
++sensor_interface * bmi_vs6624_reset (struct bmi_cam *cam)
++{
++      //REWORK: Add code here
++      //REWORK: What is a valid soft reset sequence ?
++      return 0;
++}
++
++int bmi_vs6624_activate (struct bmi_cam *cam, struct input_dev *idev)
++{
++      //REWORK: Add code here
++      int rc = 0;
++      int i;
++      struct i2c_adapter *adap;
++      struct bmi_vs6624 *bmi_vs6624;
++
++      bmi_vs6624 = container_of(cam, struct bmi_vs6624, bcam);
++
++
++      //bmi_vs6624 struct fields
++      bmi_vs6624->shutter  = 0;
++      bmi_vs6624->zoomin   = 0;
++      bmi_vs6624->zoomout  = 0;
++      bmi_vs6624->flash    = 0;
++
++      // install button irq_handler
++      if (request_irq(bmi_vs6624->irq, &module_irq_handler, 0, "bmi_cam_button", bmi_vs6624)) {
++              printk( KERN_ERR
++                      "bmi_vs6624_activate() Can't allocate irq %d\n",
++                      bmi_vs6624->irq
++                      );
++
++                      rc = -EBUSY;
++                      goto exit;
++              }
++
++      //Activate serial link
++      bmi_sensor_active(0);                 // rising edge clock
++      bmi_sensor_active(1);                 // rising edge clock
++      configure_serializer (bmi_vs6624);
++
++      adap = &bmi_vs6624->bdev->adap;
++        set_sync (adap);
++
++        for (i = 0; i < 10; i++) {
++
++                msleep(10);
++
++                if(check_camera_lock()) {
++                        printk(KERN_INFO "vs6624.c: camera serializer locked, i = %d\n", i);
++                        break;
++                }
++                else {
++                        printk(KERN_ERR "vs6624.c: camera serializer did not lock,i = %d\n", i);
++                }
++
++        }
++        clear_sync (adap);
++
++
++exit:
++      return rc;
++}
++int bmi_vs6624_deactivate (struct bmi_cam *cam)
++{
++      //REWORK: Add code here
++      struct bmi_vs6624 *bmi_vs6624;
++      bmi_vs6624 = container_of(cam, struct bmi_vs6624, bcam);
++
++
++      //De-activate serial link
++      deconfigure_serializer (bmi_vs6624);
++
++
++      //uninstall button irq_handler
++
++      free_irq(bmi_vs6624->irq, bmi_vs6624);
++
++
++      return 0;
++}
++
++int bmi_vs6624_probe(struct bmi_device *bdev)
++{
++
++      //REWORK: Add code here
++
++      int slot = bdev->info->slot;
++
++
++      // allocate a driver-specific <this> structure
++
++      struct bmi_vs6624 *bmi_vs6624 = kzalloc(sizeof(struct bmi_vs6624), GFP_KERNEL);
++      if (!bmi_vs6624) {
++           return -1;
++      }
++
++      // attach <this> bmi_device structure (so we can find it later).
++
++      bmi_device_set_drvdata(bdev, bmi_vs6624);
++
++
++
++      // initialize bmi_vs6624 struct
++
++      bmi_vs6624->bdev = bdev;
++
++      // sensor interface struct fields
++
++      bmi_vs6624->bcam.interface.clk_mode   = 0;                // gated
++      bmi_vs6624->bcam.interface.ext_vsync  = 1;                // external vsync
++      bmi_vs6624->bcam.interface.Vsync_pol  = 0;                // non-inverted
++      bmi_vs6624->bcam.interface.Hsync_pol  = 0;                // non-inverted
++      bmi_vs6624->bcam.interface.pixclk_pol = 0;                // non-inverted
++      bmi_vs6624->bcam.interface.data_pol   = 0;                // non-inverted
++      bmi_vs6624->bcam.interface.data_width = 1;                // 8-bits
++      bmi_vs6624->bcam.interface.width      = 1280-1;           // 1280 - SXGA
++      bmi_vs6624->bcam.interface.height     = 1024-1;           // 1024 - SXGA
++      bmi_vs6624->bcam.interface.pixel_fmt  = IPU_PIX_FMT_UYVY; // YUV422
++      bmi_vs6624->bcam.interface.mclk       = 12000000;         // frequency/src
++
++      //bmi_camera_sensor struct fields
++
++      bmi_vs6624->bcam.sensor.set_color   = bmi_vs6624_set_color;
++      bmi_vs6624->bcam.sensor.get_color   = bmi_vs6624_get_color;
++      bmi_vs6624->bcam.sensor.set_ae_mode = bmi_vs6624_set_ae_mode;
++      bmi_vs6624->bcam.sensor.get_ae_mode = bmi_vs6624_get_ae_mode;
++      bmi_vs6624->bcam.sensor.config      = bmi_vs6624_config;
++      bmi_vs6624->bcam.sensor.reset       = bmi_vs6624_reset;
++
++      //bmi_cam struct fields
++
++      bmi_vs6624->bcam.activate   = bmi_vs6624_activate  ;
++      bmi_vs6624->bcam.deactivate = bmi_vs6624_deactivate;
++
++      //bmi_vs6624 struct fields
++      bmi_vs6624->shutter  = 0;
++      bmi_vs6624->zoomin   = 0;
++      bmi_vs6624->zoomout  = 0;
++      bmi_vs6624->flash    = 0;
++
++      //initialize struct work_struct
++      PREPARE_WORK (&bmi_vs6624->work, bmi_vs6624_buttons_work, bmi_vs6624);
++
++
++      //Do one-time hw initialization (e.g. patch)
++
++      // configure IOX
++      configure_IOX (bmi_vs6624);
++
++      // configure GPIO
++      configure_GPIO (bmi_vs6624);
++
++      // chip enable camera
++      enable_camera (bmi_vs6624);
++
++      vs6624_patch (&bmi_vs6624->bdev->adap);
++
++      //register with bug_camera
++
++      //REWORK: check return code
++      register_bug_camera (&bmi_vs6624->bcam, slot);
++
++      return 0;
++}
++
++void bmi_vs6624_remove(struct bmi_device *bdev)
++{
++      //REWORK: Add code here
++
++
++      //get our <this> pointer
++      struct bmi_vs6624 *bmi_vs6624 = (struct bmi_vs6624*)(bmi_device_get_drvdata (bdev));
++      int slot = bdev->info->slot;
++
++
++
++      unregister_bug_camera ( &bmi_vs6624->bcam, slot);
++
++      //REWORK: Avoid I2c access if camera module is not present.
++
++      disable_camera (bmi_vs6624);
++      deconfigure_module (bmi_vs6624);
++
++
++      //de-attach driver-specific struct from bmi_device structure
++      bmi_device_set_drvdata (bdev, 0);
++
++      //free driver-specific structure
++      kfree (bmi_vs6624);
++      return;
++}
++
++
++static __init int bmi_vs6624_init(void)
++{
++
++//    REWORK: Add code here.
++
++//    Register with BMI bus.
++      return  bmi_register_driver (&bmi_vs6624_driver);
++
++}
++
++static void __exit bmi_vs6624_cleanup(void)
++{
++//    REWORK: Add code here.
++      bmi_unregister_driver (&bmi_vs6624_driver);
++      return;
++}
++
++
++module_init(bmi_vs6624_init);
++module_exit(bmi_vs6624_cleanup);
++
++
+--- /dev/null
++++ git/drivers/bmi/pims/lcd/lcd_ctl.c
+@@ -0,0 +1,421 @@
++/*
++ * Copyright 2008 EnCADIS Designs, Inc. All Rights Reserved.
++ * Copyright 2008 Bug-Labs, Inc. All Rights Reserved.
++ *
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*-----------------------------------------------------------------------------
++ *
++ *      Part of BMI Motion Detector Accelerometer (MDACC) Kernel Module
++ *
++ *-----------------------------------------------------------------------------
++ */
++
++#include <linux/ioctl.h>
++#include <linux/bmi.h>
++#include <linux/bmi/bmi-slot.h>
++#include <linux/i2c.h>
++#include <linux/module.h>
++#include "lcd_ctl.h"
++
++static int lcd_ctl_open (struct inode *, struct file *);
++static int lcd_ctl_release (struct inode *, struct file *);
++static int lcd_ctl_ioctl (struct inode *, struct file *, unsigned int, unsigned long);
++static int ReadByte_IOX(struct i2c_adapter *, unsigned char, unsigned char *)
++
++
++struct file_operations lcd_ctl_fops = {
++      .owner = THIS_MODULE,
++      .ioctl = lcd_ctl_ioctl,
++      .open = lcd_ctl_open,
++      .release = lcd_ctl_release,
++};
++
++
++      // read byte from I2C IO expander
++static int ReadByte_IOX(struct i2c_adapter *adap, unsigned char offset, unsigned char *data)
++{
++              int     ret = 0;
++              struct i2c_msg rmsg[2];
++              int     num_msgs;
++
++              /* Read Byte with Pointer */
++
++              rmsg[0].addr = BMI_IOX_I2C_ADDRESS;
++              rmsg[0].flags = 0;        /* write */
++              rmsg[0].len = 1;
++              rmsg[0].buf = &offset;
++
++              rmsg[1].addr = BMI_IOX_I2C_ADDRESS;
++              rmsg[1].flags = I2C_M_RD;   /* read */
++              rmsg[1].len = 1;
++              rmsg[1].buf = data;
++
++              num_msgs = 2;
++              ret = i2c_transfer (adap, rmsg, num_msgs);
++
++              if (ret == 2) {
++                      ret = 0;
++              }
++              else {
++                      printk (KERN_ERR "ReadByte_IOX() - i2c_transfer() failed.\n");
++                      ret = -1;
++              }
++              return ret;
++}
++
++      // write byte to I2C IO expander
++static int WriteByte_IOX(struct i2c_adapter *adap, unsigned char offset, unsigned char data)
++{
++              int     ret = 0;
++              struct i2c_msg wmsg[2];
++              int     num_msgs;
++
++              /* Write Byte with Pointer */
++
++              wmsg[0].addr = BMI_IOX_I2C_ADDRESS;
++              wmsg[0].flags = 0;      /* write */
++              wmsg[0].len = 1;
++              wmsg[0].buf = &offset;
++
++              wmsg[1].addr = BMI_IOX_I2C_ADDRESS;
++              wmsg[1].flags = 0;      /* write */
++              wmsg[1].len = 1;
++              wmsg[1].buf = &data;
++
++              num_msgs = 2;
++
++              ret = i2c_transfer (adap, wmsg, num_msgs);
++
++              if (ret == 2) {
++                      ret = 0;
++              }
++              else {
++                      printk (KERN_ERR "WriteByte_IOX() - i2c_transfer() failed.\n");
++                      ret = -1;
++              }
++              return ret;
++}
++
++
++static int lcd_ctl_major;
++
++int lcd_ctl_init (void)
++{
++      dev_t   dev_id;
++      int     retval;
++
++      // alloc char driver with 4 minor numbers
++
++      retval = alloc_chrdev_region(&dev_id, 0, 4, "BMI LCD Control Driver");
++
++      if (retval) {
++              return -1;
++      }
++      lcd_ctl_major = MAJOR(dev_id);
++      return 0;
++}
++
++void lcd_ctl_clean (void)
++{
++      dev_t dev_id;
++
++      dev_id = MKDEV(lcd_ctl_major, 0);
++      unregister_chrdev_region(dev_id, 4);
++      return;
++}
++
++int lcd_ctl_probe (struct lcd_ctl *lcd_ctl, int slot)
++{
++      struct cdev *cdev;
++      dev_t dev_id;
++      int ret;
++      struct class *bmi_class;
++
++      cdev = &lcd_ctl->cdev;
++      cdev_init (cdev, &lcd_ctl_fops);
++
++      dev_id = MKDEV (lcd_ctl_major, slot);
++      ret = cdev_add (cdev, dev_id, 1);
++
++      //Create class device
++      bmi_class = bmi_get_bmi_class ();
++
++      lcd_ctl->class_dev = device_create (bmi_class, NULL, MKDEV(lcd_ctl_major, slot), lcd_ctl, "bmi_lcd_ctl_m%i", slot+1);
++
++      if (IS_ERR(lcd_ctl->class_dev)) {
++              printk(KERN_ERR "Unable to create "
++                     "class_device for bmi_lcd_ctl_m%i; errno = %ld\n",
++                     slot+1, PTR_ERR(lcd_ctl->class_dev));
++              lcd_ctl->class_dev = NULL;
++      }
++      lcd_ctl->slot = slot;
++
++      return ret;
++}
++
++void lcd_ctl_remove (struct lcd_ctl *lcd_ctl, int slot)
++{
++      struct class *bmi_class;
++
++      bmi_class = bmi_get_bmi_class ();
++      device_destroy (bmi_class, MKDEV(lcd_ctl_major, slot));
++
++      lcd_ctl->class_dev = 0;
++
++      cdev_del (&lcd_ctl->cdev);
++      return;
++}
++
++
++static int lcd_ctl_open (struct inode *inode, struct file *file)
++{
++      struct lcd_ctl *lcd_ctl;
++
++      lcd_ctl = container_of(inode->i_cdev, struct lcd_ctl, cdev);
++
++
++      // Save ctl pointer for later.
++
++      file->private_data = lcd_ctl;
++      return 0;
++}
++
++static int lcd_ctl_release (struct inode *inode, struct file *file)
++{
++      struct lcd_ctl *lcd_ctl;
++
++      lcd_ctl = container_of(inode->i_cdev, struct lcd_ctl, cdev);
++      return 0;
++}
++
++
++/*// ioctl
++int cntl_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
++                 unsigned long arg)
++{
++      struct i2c_adapter *adap;
++      unsigned char iox_data[1];
++      int slot = (__user arg) & 0xF;
++      int bl = ((__user arg) & 0x70) >> 4;
++
++              // error if no lcd active.
++      if(pbmi_lcd.active == -1)
++              return -ENODEV;
++
++      if(cmd != BMI_LCD_GETSTAT) {
++
++                      // error if slot invalid
++              if((slot < CPLD_M1) || (slot > CPLD_M4))
++                      return -ENODEV;
++
++                      // error if no lcd in chosen slot
++              if(pbmi_lcd.bdev[slot] == 0)
++                      return -ENODEV;
++
++                      // i2c adapter
++              adap = &pbmi_lcd.bdev[slot]->adap;
++      }
++
++              // ioctl's
++      switch (cmd) {
++              case BMI_LCD_RLEDOFF:
++                      bmi_set_module_gpio_data(slot, 3, 1);// Red LED=OFF
++                      break;
++              case BMI_LCD_RLEDON:
++                      bmi_set_module_gpio_data(slot, 3, 0);// Red LED=ON
++                      break;
++              case BMI_LCD_GLEDOFF:
++                      bmi_set_module_gpio_data(slot, 2, 1);// Green LED=OFF
++                      break;
++              case BMI_LCD_GLEDON:
++                      bmi_set_module_gpio_data(slot, 2, 0);// Green LED=ON
++                      break;
++              case BMI_LCD_VSYNC_DIS: // enable VSYNC buffer tristate output
++                      if(ReadByte_IOX(adap, IOX_OUTPUT_REG, iox_data))
++                              return -ENODEV;
++                      *iox_data |= 0x08;
++                      if(WriteByte_IOX(adap, IOX_OUTPUT_REG, *iox_data))
++                              return -ENODEV;
++                      break;
++              case BMI_LCD_VSYNC_EN:  // disable VSYNC buffer tristate output
++                      if(ReadByte_IOX(adap, IOX_OUTPUT_REG, iox_data))
++                              return -ENODEV;
++                      *iox_data &= ~0x08;
++                      if(WriteByte_IOX(adap, IOX_OUTPUT_REG, *iox_data))
++                              return -ENODEV;
++                      break;
++              case BMI_LCD_EN:        // enable LCD component
++                      if(ReadByte_IOX(adap, IOX_OUTPUT_REG, iox_data))
++                              return -ENODEV;
++                      *iox_data &= ~0x10;
++                      if(WriteByte_IOX(adap, IOX_OUTPUT_REG, *iox_data))
++                              return -ENODEV;
++                      break;
++              case BMI_LCD_DIS:       // disable LCD component only
++                      if(ReadByte_IOX(adap, IOX_OUTPUT_REG, iox_data))
++                              return -ENODEV;
++                      *iox_data |= 0x10;
++                      if(WriteByte_IOX(adap, IOX_OUTPUT_REG, *iox_data))
++                              return -ENODEV;
++                      break;
++              case BMI_LCD_SER_EN:    // enable Serializer component
++                      if(ReadByte_IOX(adap, IOX_OUTPUT_REG, iox_data))
++                              return -ENODEV;
++                      *iox_data &= ~0x20;
++                      if(WriteByte_IOX(adap, IOX_OUTPUT_REG, *iox_data))
++                              return -ENODEV;
++                      break;
++              case BMI_LCD_SER_DIS:   // disable Serializer component only
++                      if(ReadByte_IOX(adap, IOX_OUTPUT_REG, iox_data))
++                              return -ENODEV;
++                      *iox_data |= 0x20;
++                      if(WriteByte_IOX(adap, IOX_OUTPUT_REG, *iox_data))
++                              return -ENODEV;
++                      break;
++              case BMI_LCD_SETRST:    // overall module reset
++                      bmi_set_module_gpio_data (slot, 1, 0);          // RST=0
++                      break;
++              case BMI_LCD_CLRRST:    // overall module enable
++                      bmi_set_module_gpio_data (slot, 1, 1);          // RST=1
++                      break;
++              case BMI_LCD_SET_BL:    // set backlight brightness
++                      if(ReadByte_IOX(adap, IOX_OUTPUT_REG, iox_data))
++                              return -ENODEV;
++                      *iox_data = (*iox_data & 0xFC) | bl;
++                      if(WriteByte_IOX(adap, IOX_OUTPUT_REG, *iox_data))
++                              return -ENODEV;
++                      break;
++              case BMI_LCD_GETSTAT:
++                      {
++                              int *slot = ((int __user *) arg);
++                              int read_data;
++
++                              *slot &= 0xF;
++
++                                      // error if slot invalid
++                              if((*slot < CPLD_M1) || (*slot > CPLD_M4))
++                                      return -ENODEV;
++
++                                      // error if no lcd in chosen slot
++                              if(pbmi_lcd.bdev[*slot] == 0)
++                                      return -ENODEV;
++
++                                      // i2c adapter
++                              adap = &pbmi_lcd.bdev[*slot]->adap;
++
++                              if(ReadByte_IOX(adap, IOX_INPUT_REG, iox_data))
++                                      return -ENODEV;
++
++                              read_data = *iox_data | (bmi_read_gpio_data_reg(*slot) << 8);
++
++                              if(put_user(read_data, (int __user *) arg))
++                                              return -EFAULT;
++                      }
++                      break;
++              case BMI_LCD_ACTIVATE:  //pjg fix/test
++                              // check for opposite side already active
++                      switch(slot) {  // opposite side
++                              case 0:
++                                      if(pbmi_lcd.activated[2] == 1) {
++                                              printk(KERN_INFO "bmi_lcd.c: probe slot %d not allowed (slot 2 already active)\n", slot);
++                                              bmi_slot_power_off(0);
++                                              return -ENODEV;
++                                      }
++                                      break;
++                              case 1:
++                                      if(pbmi_lcd.activated[3] == 1) {
++                                              printk(KERN_INFO "bmi_lcd.c: probe slot %d not allowed (slot 3 already active)\n", slot);
++                                              bmi_slot_power_off(1);
++                                              return -ENODEV;
++                                      }
++                                      break;
++                              case 2:
++                                      if(pbmi_lcd.activated[0] == 1) {
++                                              printk(KERN_INFO "bmi_lcd.c: probe slot %d not allowed (slot 0 already active)\n", slot);
++                                              bmi_slot_power_off(2);
++                                              return -ENODEV;
++                                      }
++                                      break;
++                              case 3:
++                                      if(pbmi_lcd.activated[1] == 1) {
++                                              printk(KERN_INFO "bmi_lcd.c: probe slot %d not allowed (slot 1 already active)\n", slot);
++                                              bmi_slot_power_off(3);
++                                              return -ENODEV;
++                                      }
++                                      break;
++                      }
++                              // activate
++                      if((!pbmi_lcd.activated[slot]) && (pbmi_lcd.bdev[slot] != 0)) {
++                              bmi_lcd_probe(pbmi_lcd.bdev[slot]);
++                      }
++                      break;
++              case BMI_LCD_DEACTIVATE:
++                      if(pbmi_lcd.activated[slot]) {
++                              disable_irq_nosync(pbmi_lcd.interrupt[slot]);
++                              pbmi_lcd.activated[slot] = 0;
++                              if(ReadByte_IOX(adap, IOX_OUTPUT_REG, iox_data))
++                                      return -ENODEV;
++                              *iox_data = (*iox_data & 0xF8);
++                              if(WriteByte_IOX(adap, IOX_OUTPUT_REG, *iox_data))
++                                      return -ENODEV;
++                              bmi_slot_power_off(slot);
++                      }
++                      break;
++              case BMI_LCD_SUSPEND:
++                      printk(KERN_ERR "BMI_LCD_SUSPEND NOT IMPLEMENTED\n");   //pjg
++                      break;
++              case BMI_LCD_RESUME:
++                      printk(KERN_ERR "BMI_LCD_RESUME NOT IMPLEMENTED\n");    //pjg
++                      break;
++              default:
++                      return -ENOTTY;
++      }
++      return 0;
++}
++*/
++
++static int lcd_ctl_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
++{
++      struct lcd_ctl *lcd_ctl;
++      int slot;
++
++      lcd_ctl = container_of(inode->i_cdev, struct lcd_ctl, cdev);
++      slot = lcd_ctl->slot;
++      if (slot < 0) {
++              return -ENODEV;
++      }
++
++
++      switch (cmd) {
++
++      case BMI_LCD_RLEDOFF:
++              bmi_slot_gpio_write_bit (slot, 3, 1); //Red LED Off
++              break;
++
++      case BMI_LCD_RLEDON:
++              bmi_slot_gpio_write_bit (slot, 3, 0); //Red LED On
++              break;
++
++      case BMI_LCD_GLEDOFF:
++              bmi_slot_gpio_write_bit (slot, 2, 1); //Green LED Off
++              break;
++
++      case BMI_LCD_GLEDON:
++              bmi_slot_gpio_write_bit (slot, 2, 0); //Green LED On
++              break;
++
++      default:
++              printk (KERN_ERR "lcd_ctl_ioctl() - error exit\n");
++              return -ENOTTY;
++      }
++
++      return 0;
++}
++
+--- /dev/null
++++ git/drivers/bmi/pims/lcd/lcd_ctl.h
+@@ -0,0 +1,87 @@
++/*
++ * Copyright 2008 EnCADIS Designs, Inc. All Rights Reserved.
++ * Copyright 2008 Bug-Labs, Inc. All Rights Reserved.
++ *
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*-----------------------------------------------------------------------------
++ *
++ *      Part of BMI LCD Kernel Module
++ *
++ *-----------------------------------------------------------------------------
++ */
++
++#ifndef LCD_CTL_H
++#define LCD_CTL_H
++
++#include <linux/kernel.h>
++
++#include <linux/fs.h>
++#include <linux/cdev.h>
++
++#include <linux/bmi/bmi_ioctl.h>
++
++      // IOCTL commands for BMI LCD driver
++#define BMI_LCD_RLEDOFF               _IOW(BMI_LCD_IOCTL, 0x1, __u32)         // turn off Red LED
++#define BMI_LCD_RLEDON                _IOW(BMI_LCD_IOCTL, 0x2, __u32)         // turn on Red LED
++#define BMI_LCD_GLEDOFF               _IOW(BMI_LCD_IOCTL, 0x3, __u32)         // turn off Green LED
++#define BMI_LCD_GLEDON                _IOW(BMI_LCD_IOCTL, 0x4, __u32)         // turn on Green LED
++#define BMI_LCD_VSYNC_DIS     _IOW(BMI_LCD_IOCTL, 0x5, __u32)         // Enable VSYNC output buffer
++#define BMI_LCD_VSYNC_EN      _IOW(BMI_LCD_IOCTL, 0x6, __u32)         // Disable VSYNC output buffer
++#define BMI_LCD_EN            _IOW(BMI_LCD_IOCTL, 0x7, __u32)         // Enable LCD component
++#define BMI_LCD_DIS           _IOW(BMI_LCD_IOCTL, 0x8, __u32)         // Disable LCD component
++#define BMI_LCD_SER_EN                _IOW(BMI_LCD_IOCTL, 0x9, __u32)         // Enable Seriallizer component
++#define BMI_LCD_SER_DIS               _IOW(BMI_LCD_IOCTL, 0xa, __u32)         // Disable Seriallizer component
++#define BMI_LCD_SETRST                _IOW(BMI_LCD_IOCTL, 0xb, __u32)         // Disable entire module
++#define BMI_LCD_CLRRST                _IOW(BMI_LCD_IOCTL, 0xc, __u32)         // Enable entire module
++#define BMI_LCD_SET_BL                _IOW(BMI_LCD_IOCTL, 0xd, __u32)         // Set IOX backlight bits [2:0]
++#define BMI_LCD_GETSTAT               _IOR(BMI_LCD_IOCTL, 0xe, __u32)         // Get IOX state
++#define BMI_LCD_ACTIVATE      _IOW(BMI_LCD_IOCTL, 0xf, __u32)         // Activate SER, TS, ACCEL
++#define BMI_LCD_DEACTIVATE    _IOW(BMI_LCD_IOCTL, 0x10, __u32)        // Deactivate SER, TS, ACCEL
++#define BMI_LCD_SUSPEND               _IOW(BMI_LCD_IOCTL, 0x11, __u32)        // Power down module
++#define BMI_LCD_RESUME                _IOW(BMI_LCD_IOCTL, 0x12, __u32)        // Power up module
++
++/*
++ *    I2C set up
++ */
++
++      // I2C Slave Address
++#define BMI_IOX_I2C_ADDRESS   0x71    // 7-bit address
++#define BMI_ACC_I2C_ADDRESS   0x17    // 7-bit address
++
++      // I2C IOX register addresses
++#define IOX_INPUT_REG         0x0     // IOX input data register
++#define IOX_OUTPUT_REG                0x1     // IOX output data register
++#define IOX_POLARITY_REG      0x2     // IOX polarity data register
++#define IOX_CONTROL           0x3     // IOX direction control register
++#define IOX_B1                        (0)     // bit 0 - backlight control
++#define IOX_A1_A2             (1)     // bit 1 - backlight control
++#define IOX_ACC_RST_N         (2)     // bit 2 - acceleromter reset
++#define IOX_VSYNC_EN_N                (3)     // bit 3 - VSYNC output buffer enable
++#define IOX_LCD_RST_N         (4)     // bit 4 - LCD reset
++#define IOX_SERDES_PD_N               (5)     // bit 5 - SERDES power down
++#define IOX_X_INT             (6)     // bit 6 - accelerometer interrupt
++#define IOX_Y_INT             (7)     // bit 7 - accelerometer interrupt
++
++struct lcd_ctl
++{
++  int slot;
++  struct cdev cdev;
++  struct device *class_dev;
++};
++
++extern int  lcd_ctl_init (void);
++extern void lcd_ctl_clean(void);
++extern int  lcd_ctl_probe (struct lcd_ctl *lcd_ctl, int slot);
++extern void lcd_ctl_remove(struct lcd_ctl *lcd_ctl, int slot);
++
++
++#endif
++
++
+--- /dev/null
++++ git/drivers/bmi/pims/mdacc/Kconfig
+@@ -0,0 +1,6 @@
++config BMI_MDACC
++      tristate "BMI Motion Detector/Accelerometer"
++      depends on BMI_PIMS
++      default n
++      ---help---
++        This is the BMI Motion Detector/Acceleromter driver.
+--- /dev/null
++++ git/drivers/bmi/pims/mdacc/Makefile
+@@ -0,0 +1,9 @@
++#
++# BMI PIM: Motion Detector Accelerometer
++#
++
++bmi_mdacc-objs := mdacc.o avr.o md.o acc.o ctl.o mon.o cque.o
++obj-$(CONFIG_BMI_MDACC) += bmi_mdacc.o
++
++
++
+--- /dev/null
++++ git/drivers/bmi/pims/mdacc/acc.c
+@@ -0,0 +1,381 @@
++/*
++ * Copyright 2008 EnCADIS Designs, Inc. All Rights Reserved.
++ * Copyright 2008 Bug-Labs, Inc. All Rights Reserved.
++ *
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*-----------------------------------------------------------------------------
++ *
++ *      Part of BMI Motion Detector Accelerometer (MDACC) Kernel Module
++ *
++ *-----------------------------------------------------------------------------
++ */
++
++#include "acc.h"
++#include "mdacc.h"
++#include "mon.h"
++#include <linux/bmi/bmi_mdacc.h>
++#include <linux/ioctl.h>
++#include <linux/poll.h>
++
++static int acc_open (struct inode *, struct file *);
++static int acc_release (struct inode *, struct file *);
++static int acc_ioctl (struct inode *, struct file *, unsigned int, unsigned long);
++static ssize_t acc_read (struct file *, char __user *, size_t, loff_t *);
++static unsigned int acc_poll (struct file *, struct poll_table_struct *);
++
++struct file_operations acc_fops = {
++      .owner = THIS_MODULE,
++      .ioctl = acc_ioctl,
++      .open = acc_open,
++      .release = acc_release,
++      .read = acc_read,
++      .poll = acc_poll,
++};
++
++static int acc_major;
++
++int acc_init (void)
++{
++      dev_t   dev_id;
++      int     retval;
++
++      // alloc char driver with 4 minor numbers
++
++      retval = alloc_chrdev_region(&dev_id, 0, 4, "BMI MDACC Accelerometer Driver");
++
++      if (retval) {
++              return -1;
++      }
++      acc_major = MAJOR(dev_id);
++      return 0;
++}
++
++void acc_clean(void)
++{
++      dev_t dev_id;
++
++      dev_id = MKDEV(acc_major, 0);
++      unregister_chrdev_region(dev_id, 4);
++      return;
++}
++
++int  acc_probe (struct acc *acc, int slot, struct mon *mon)
++{
++      struct cdev *cdev;
++      dev_t dev_id;
++      int ret;
++      struct class *bmi_class;
++
++      // initialize cdev
++
++      cdev = &acc->cdev;
++      cdev_init (cdev, &acc_fops);
++
++      dev_id = MKDEV (acc_major, slot);
++      ret = cdev_add (cdev, dev_id, 1);
++
++      //Create class device
++
++      bmi_class = bmi_get_class ();
++
++      acc->class_dev = device_create (bmi_class, NULL, MKDEV(acc_major, slot), acc, "bmi_mdacc_acc_m%i", slot+1);
++
++      if (IS_ERR(acc->class_dev)) {
++              printk(KERN_ERR "Unable to create "
++                     "class_device for bmi_mdacc_acc_m%i; errno = %ld\n",
++                     slot+1, PTR_ERR(acc->class_dev));
++              acc->class_dev = NULL;
++      }
++
++      acc->open_flag = 0;
++      acc->mon = mon;
++
++
++      // initialize mdacc_accel_config
++
++      acc->cfg.read_queue_size = 1;
++      acc->cfg.read_queue_threshold = 1;
++      acc->cfg.delay_mode = 0;
++      acc->cfg.delay = 4000;
++      acc->cfg.delay_resolution = 1;
++      acc->cfg.sensitivity = 0;
++      acc->cfg.run = 0;
++
++
++      // initialize cque
++
++      acc->cque = cque_create  (acc->cfg.read_queue_size, acc->cfg.read_queue_threshold);
++
++      // initialize read_wait_queue
++
++      init_waitqueue_head (&acc->read_wait_queue);
++      return ret;
++}
++
++void acc_remove (struct acc *acc, int slot)
++{
++      struct class *bmi_class;
++
++      cque_destroy (acc->cque);
++
++      bmi_class = bmi_get_class ();
++      device_destroy (bmi_class, MKDEV(acc_major, slot));
++
++      acc->class_dev = 0;
++
++      cdev_del (&acc->cdev);
++
++
++      return;
++}
++
++
++static int acc_open (struct inode *inode, struct file *file)
++{
++      struct acc *acc;
++
++      acc = container_of(inode->i_cdev, struct acc, cdev);
++
++      //Enforce single open behavior
++      if (acc->open_flag) {
++              return -EBUSY;
++      }
++      acc->open_flag = 1;
++
++      // Save acc_drv pointer for later.
++      file->private_data = acc;
++      return 0;
++}
++
++static int acc_release (struct inode *inode, struct file *file)
++{
++      struct acc *acc;
++
++      acc = container_of(inode->i_cdev, struct acc, cdev);
++      acc->open_flag = 0;
++
++      //Enforce stop-on-close behavior.
++      if (acc->cfg.run) {
++              acc->cfg.run = 0;
++              mon_stop_accel (acc->mon);
++      }
++      return 0;
++
++}
++
++static int check_config (struct mdacc_accel_config *config)
++{
++      int err = 0;
++
++      if (!config) {
++              err = 1;
++              goto exit;
++      }
++
++      if (config->read_queue_size < 1) {
++              err = 1;
++      }
++      if (config->read_queue_threshold > config->read_queue_size) {
++              err = 1;
++      }
++      if (config->delay_mode) {
++              switch (config->delay_resolution)
++              {
++                      case 0:
++                              err = 1;
++                              break;
++                      case 1:                              // 1 => 1 usec
++                              if (config->delay < 5000) {
++                                      err = 1;
++                              }
++                              break;
++                      case 2:
++                              if (config->delay < 625) {  // 2 => 8 usec
++                                      err = 1;
++                              }
++                              break;
++                      case 3:
++                              if (config->delay < 79) {  // 3 => 64 usec
++                                      err = 1;
++                              }
++                              break;
++                      case 4:
++                              if (config->delay < 20) { // 4 => 256 usec
++                                      err = 1;
++                              }
++                              break;
++                      case 5:
++                              if (config->delay < 5) { // 5 => 1024 usec
++                                      err = 1;
++                              }
++                              break;
++                      default:
++                              err = 1;
++                              break;
++              }
++      }
++
++      if (config->sensitivity > 3) {
++              err = 1;
++      }
++
++exit:
++      return err;
++}
++
++static int acc_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
++{
++      int err = 0;
++      struct acc *acc;
++      acc = container_of(inode->i_cdev, struct acc, cdev);
++
++      switch (cmd) {
++
++      case BMI_MDACC_ACCELEROMETER_SET_CONFIG:
++      {
++              struct mdacc_accel_config new_cfg;
++
++              err = copy_from_user ( (void*)&new_cfg, (void*)arg, sizeof (struct mdacc_accel_config) );
++              if (err) {
++                      return -EFAULT;
++              }
++
++              err = check_config (&new_cfg);
++              if (err) {
++                      return -EINVAL;
++              }
++
++              if (acc->cfg.run) {
++                      mon_stop_accel (acc->mon);
++              }
++
++              // take the mon semaphore
++              down_interruptible (&acc->mon->sem);
++
++              memcpy ( &acc->cfg, &new_cfg, sizeof (struct mdacc_accel_config) );
++              cque_destroy (acc->cque);
++              acc->cque = cque_create  (acc->cfg.read_queue_size, acc->cfg.read_queue_threshold);
++
++              // release the mon semaphore
++              up (&acc->mon->sem);
++
++              mon_set_config_accel( acc->mon, &acc->cfg);
++
++      }
++              break;
++
++      case BMI_MDACC_ACCELEROMETER_GET_CONFIG:
++
++              mon_get_config_accel( acc->mon, &acc->cfg);
++
++
++              err = copy_to_user ( (void*)arg, &acc->cfg, sizeof (struct mdacc_accel_config) );
++              if (err) {
++                      return -EFAULT;
++              }
++              break;
++
++      case BMI_MDACC_ACCELEROMETER_RUN:
++
++              acc->cfg.run = 1;
++              err = mon_start_accel (acc->mon);
++              if (err){
++                      return -ENODEV;
++              }
++              break;
++
++
++      case BMI_MDACC_ACCELEROMETER_STOP:
++
++              acc->cfg.run = 0;
++              err = mon_stop_accel (acc->mon);
++              if (err){
++                      return -ENODEV;
++              }
++              break;
++
++      default:
++              printk (KERN_ERR "acc_ioctl() - error exit\n");
++              return -ENOTTY;
++      }
++
++      return 0;
++}
++
++static ssize_t acc_read (struct file *file, char __user *buf, size_t count, loff_t *ppos)
++{
++// if fd is non-blocking and acc is not enabled, return EAGAIN
++// if fd is non-blocking and acc is enabled, and cque is not ready, return EAGAIN
++// if fd is non-blocking and acc is enabled, and cque is ready, read cque, copy to user,
++
++// if fd is blocking and acc is not enabled, , return EAGAIN
++//
++
++// if fs is blocking and acc is enabled, and cque is not ready, sleep until ready.
++//                                                           when ready, read cque, copy to user,
++
++
++
++      struct acc *acc = file->private_data;
++      unsigned char temp[6];
++      int bytes_read;
++
++      if (count < 6) {
++              return -EINVAL;
++      }
++
++      if (!acc->cfg.run) {
++              return -EAGAIN;
++      }
++
++      while (!cque_is_ready_for_read(acc->cque)) {
++              if (file->f_flags & O_NONBLOCK)
++                      return -EAGAIN;
++              if (wait_event_interruptible (acc->read_wait_queue, (cque_is_ready_for_read(acc->cque))))
++                      return -ERESTARTSYS;
++      }
++
++      //loop through 1 sample at a time.
++
++      bytes_read = 0;
++
++      while (count >= 6) {
++
++              if (cque_read (acc->cque, &temp))
++                      break;
++              if (copy_to_user (buf, &temp, 6))
++                      break;
++              bytes_read += 6;
++              buf += 6;
++              count -= 6;
++      }
++      return bytes_read;
++}
++
++
++static unsigned int acc_poll (struct file *file, struct poll_table_struct *table)
++{
++      unsigned int mask = 0;
++      struct acc *acc = file->private_data;
++
++      poll_wait(file, &acc->read_wait_queue, table);
++
++      if (cque_is_ready_for_read( acc->cque) ) {
++              mask |= POLLIN | POLLRDNORM;    /* readable */
++      }
++      if (mdacc_check_bdev_acc (acc) ) {
++              mask |= POLLHUP;        /* hang-up */
++      }
++      if (!acc->cfg.run) {
++              mask |= POLLHUP;        /* hang-up */
++      }
++      return mask;
++}
++
+--- /dev/null
++++ git/drivers/bmi/pims/mdacc/acc.h
+@@ -0,0 +1,54 @@
++/*
++ * Copyright 2008 EnCADIS Designs, Inc. All Rights Reserved.
++ * Copyright 2008 Bug-Labs, Inc. All Rights Reserved.
++ *
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*-----------------------------------------------------------------------------
++ *
++ *      Part of BMI Motion Detector Accelerometer (MDACC) Kernel Module
++ *
++ *-----------------------------------------------------------------------------
++ */
++
++#ifndef MDACC_ACC_H
++#define MDACC_ACC_H
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/fs.h>
++#include <linux/cdev.h>
++#include <linux/bmi.h>
++#include <linux/delay.h>
++#include <linux/bmi/bmi_mdacc.h>
++#include "cque.h"
++
++struct mon;
++
++struct acc
++{
++      struct cdev cdev;
++      struct device *class_dev;
++      int open_flag;
++      struct mon *mon;
++      struct mdacc_accel_config cfg;
++      struct cque *cque;
++      wait_queue_head_t read_wait_queue;
++};
++
++
++extern int  acc_init (void);
++extern void acc_clean(void);
++extern int  acc_probe (struct acc *acc, int slot, struct mon *mon);
++extern void acc_remove(struct acc *acc, int slot);
++
++
++
++
++#endif
+--- /dev/null
++++ git/drivers/bmi/pims/mdacc/avr.c
+@@ -0,0 +1,511 @@
++/*
++ * Copyright 2008 EnCADIS Designs, Inc. All Rights Reserved.
++ * Copyright 2008 Bug-Labs, Inc. All Rights Reserved.
++ *
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*-----------------------------------------------------------------------------
++ *
++ *      Part of BMI Motion Detector Accelerometer (MDACC) Kernel Module
++ *
++ *-----------------------------------------------------------------------------
++ */
++
++#include <linux/device.h>
++#include <linux/spi/spi.h>
++
++
++struct avr_regs
++{
++      unsigned char timer_res;        // SPI Register 0
++      unsigned char timer_msb;        // SPI Register 1
++      unsigned char timer_lsb;        // SPI Register 2
++      unsigned char mode;             // SPI Register 3
++
++      unsigned char status;           // SPI Register 4
++
++      unsigned char adc0h;            // SPI Register 5
++      unsigned char adc0l;            // SPI Register 6
++      unsigned char adc1h;            // SPI Register 7
++      unsigned char adc1l;            // SPI Register 8
++      unsigned char adc2h;            // SPI Register 9
++      unsigned char adc2l;            // SPI Register 10
++};
++
++
++
++/*
++
++Cmd Bit Definitions
++
++Cmd bit 7  - R0/W1
++Cmd bit 6  - Cnt 2
++Cmd bit 5  - Cnt 1
++Cmd bit 4  - Cnt 0
++Cmd bit 3  - Address 3
++Cmd bit 2  - Address 2
++Cmd bit 1  - Address 1
++Cmd bit 0  - Address 0
++*/
++
++
++
++#define AVR_CMD_READ_ADC              (0x65)
++#define AVR_CMD_READ_STATUS         (0x14)
++#define AVR_CMD_READ_STATUS_AND_ADC   (0x74)
++#define AVR_CMD_READ_MODE             (0x13)
++#define AVR_CMD_READ_TIMER            (0x30)
++#define AVR_CMD_READ_TIMER_AND_MODE   (0x40)
++#define AVR_CMD_WRITE_MODE            (0x93)
++#define AVR_CMD_WRITE_TIMER           (0xB0)
++#define AVR_CMD_WRITE_TIMER_AND_MODE  (0xC0)
++
++int avr_read_adc (struct spi_device *spi, struct avr_regs *regs);
++int avr_read_status (struct spi_device *spi, struct avr_regs *regs);
++int avr_read_status_and_adc (struct spi_device *spi, struct avr_regs *regs);
++int avr_read_mode  (struct spi_device *spi, struct avr_regs *regs);
++int avr_read_timer  (struct spi_device *spi, struct avr_regs *regs);
++int avr_read_timer_and_mode  (struct spi_device *spi, struct avr_regs *regs);
++int avr_write_mode (struct spi_device *spi, struct avr_regs *regs);
++int avr_write_timer (struct spi_device *spi, struct avr_regs *regs);
++int avr_write_timer_and_mode (struct spi_device *spi, struct avr_regs *regs);
++
++
++int avr_read_adc (struct spi_device *spi, struct avr_regs *regs)
++{
++      int                     err;
++      unsigned char           cmd;
++      unsigned char           sync;
++      unsigned char           dont_care;
++
++      struct spi_transfer     x[7];
++      struct spi_message      message;
++
++      cmd = AVR_CMD_READ_ADC;
++      sync = 0;
++
++      dont_care = 0;
++
++      spi_message_init(&message);
++      memset(x, 0, sizeof x);
++
++      x[0].len = 1;
++      x[0].tx_buf = &cmd;
++      x[0].rx_buf = &sync;
++      x[0].delay_usecs = 400;
++      x[0].bits_per_word = 8;
++      spi_message_add_tail(&x[0], &message);
++
++      x[1].len = 1;
++      x[1].tx_buf = &dont_care;
++      x[1].rx_buf = &regs->adc0h;
++      x[1].delay_usecs = 400;
++      x[1].bits_per_word = 8;
++      spi_message_add_tail(&x[1], &message);
++
++      x[2].len = 1;
++      x[2].tx_buf = &dont_care;
++      x[2].rx_buf = &regs->adc0l;
++      x[2].delay_usecs = 400;
++      x[2].bits_per_word = 8;
++      spi_message_add_tail(&x[2], &message);
++
++      x[3].len = 1;
++      x[3].tx_buf = &dont_care;
++      x[3].rx_buf = &regs->adc1h;
++      x[3].delay_usecs = 400;
++      x[3].bits_per_word = 8;
++      spi_message_add_tail(&x[3], &message);
++
++      x[4].len = 1;
++      x[4].tx_buf = &dont_care;
++      x[4].rx_buf = &regs->adc1l;
++      x[4].delay_usecs = 400;
++      x[4].bits_per_word = 8;
++      spi_message_add_tail(&x[4], &message);
++
++      x[5].len = 1;
++      x[5].tx_buf = &dont_care;
++      x[5].rx_buf = &regs->adc2h;
++      x[5].delay_usecs = 400;
++      x[5].bits_per_word = 8;
++      spi_message_add_tail(&x[5], &message);
++
++      x[6].len = 1;
++      x[6].tx_buf = &dont_care;
++      x[6].rx_buf = &regs->adc2l;
++      x[6].delay_usecs = 400;
++      x[6].bits_per_word = 8;
++      spi_message_add_tail(&x[6], &message);
++
++      err = spi_sync(spi, &message);
++
++      return err;
++}
++
++
++int avr_read_status (struct spi_device *spi, struct avr_regs *regs)
++{
++      int                     err;
++      unsigned char           cmd;
++      unsigned char           sync;
++      unsigned char           dont_care;
++      struct spi_transfer     x[2];
++      struct spi_message      message;
++
++      cmd = AVR_CMD_READ_STATUS;
++      sync = 0;
++
++      dont_care = 0;;
++
++      memset(x, 0, sizeof x);
++      spi_message_init(&message);
++
++      x[0].len = 1;
++      x[0].tx_buf = &cmd;
++      x[0].rx_buf = &sync;
++      x[0].delay_usecs = 400;
++      spi_message_add_tail(&x[0], &message);
++
++      x[1].len = 1;
++      x[1].tx_buf = &dont_care;
++      x[1].rx_buf = &regs->status;
++      x[1].delay_usecs = 400;
++      spi_message_add_tail(&x[1], &message);
++
++      err = spi_sync(spi, &message);
++
++      return err;
++}
++
++int avr_read_status_and_adc (struct spi_device *spi, struct avr_regs *regs)
++{
++      int                     err;
++      unsigned char           cmd;
++      unsigned char           sync;
++      unsigned char           dont_care;
++      struct spi_transfer     x[8];
++      struct spi_message      message;
++
++      cmd = AVR_CMD_READ_STATUS_AND_ADC;
++      sync = 0;
++      dont_care = 0;
++
++      memset(x, 0, sizeof x);
++      spi_message_init(&message);
++
++      x[0].len = 1;
++      x[0].tx_buf = &cmd;
++      x[0].rx_buf = &sync;
++      x[0].delay_usecs = 400;
++      spi_message_add_tail(&x[0], &message);
++
++      x[1].len = 1;
++      x[1].tx_buf = &dont_care;
++      x[1].rx_buf = &regs->status;
++      x[1].delay_usecs = 400;
++      spi_message_add_tail(&x[1], &message);
++
++      x[2].len = 1;
++      x[2].tx_buf = &dont_care;
++      x[2].rx_buf = &regs->adc0h;
++      x[2].delay_usecs = 400;
++      spi_message_add_tail(&x[2], &message);
++
++      x[3].len = 1;
++      x[3].tx_buf = &dont_care;
++      x[3].rx_buf = &regs->adc0l;
++      x[3].delay_usecs = 400;
++      spi_message_add_tail(&x[3], &message);
++
++      x[4].len = 1;
++      x[4].tx_buf = &dont_care;
++      x[4].rx_buf = &regs->adc1h;
++      x[4].delay_usecs = 400;
++      spi_message_add_tail(&x[4], &message);
++
++      x[5].len = 1;
++      x[5].tx_buf = &dont_care;
++      x[5].rx_buf = &regs->adc1l;
++      x[5].delay_usecs = 400;
++      spi_message_add_tail(&x[5], &message);
++
++      x[6].len = 1;
++      x[6].tx_buf = &dont_care;
++      x[6].rx_buf = &regs->adc2h;
++      x[6].delay_usecs = 400;
++      spi_message_add_tail(&x[6], &message);
++
++      x[7].len = 1;
++      x[7].tx_buf = &dont_care;
++      x[7].rx_buf = &regs->adc2l;
++      x[7].delay_usecs = 400;
++      spi_message_add_tail(&x[7], &message);
++
++      err = spi_sync(spi, &message);
++
++      return err;
++}
++
++int avr_read_mode  (struct spi_device *spi, struct avr_regs *regs)
++{
++      int                     err;
++      unsigned char           cmd;
++      unsigned char           sync;
++      unsigned char           dont_care;
++
++      struct spi_transfer     x[2];
++      struct spi_message      message;
++
++
++      cmd = AVR_CMD_READ_MODE;
++      sync = 0;
++
++      dont_care = 0;
++      memset(x, 0, sizeof x);
++      spi_message_init(&message);
++
++      x[0].len = 1;
++      x[0].tx_buf = &cmd;
++      x[0].rx_buf = &sync;
++      x[0].delay_usecs = 400;
++      spi_message_add_tail(&x[0], &message);
++
++      x[1].len = 1;
++      x[1].tx_buf = &dont_care;
++      x[1].rx_buf = &regs->mode;
++      x[1].delay_usecs = 400;
++      spi_message_add_tail(&x[1], &message);
++
++      err = spi_sync(spi, &message);
++
++      return err;
++}
++
++int avr_read_timer  (struct spi_device *spi, struct avr_regs *regs)
++{
++      int                     err;
++      unsigned char           cmd;
++      unsigned char           sync;
++      unsigned char           dont_care;
++      struct spi_transfer     x[4];
++      struct spi_message      message;
++
++
++      cmd = AVR_CMD_READ_TIMER;
++      sync = 0;
++      dont_care = 0;
++
++      memset(x, 0, sizeof x);
++      spi_message_init(&message);
++
++      x[0].len = 1;
++      x[0].tx_buf = &cmd;
++      x[0].rx_buf = &sync;
++      x[0].delay_usecs = 400;
++      spi_message_add_tail(&x[0], &message);
++
++      x[1].len = 1;
++      x[1].tx_buf = &dont_care;
++      x[1].rx_buf = &regs->timer_res;
++      x[1].delay_usecs = 400;
++      spi_message_add_tail(&x[1], &message);
++
++      x[2].len = 1;
++      x[2].tx_buf = &dont_care;
++      x[2].rx_buf = &regs->timer_msb;
++      x[2].delay_usecs = 400;
++      spi_message_add_tail(&x[2], &message);
++
++      x[3].len = 1;
++      x[3].tx_buf = &dont_care;
++      x[3].rx_buf = &regs->timer_lsb;
++      x[3].delay_usecs = 400;
++      spi_message_add_tail(&x[3], &message);
++
++      err = spi_sync(spi, &message);
++
++      return err;
++}
++int avr_read_timer_and_mode  (struct spi_device *spi, struct avr_regs *regs)
++{
++      int                     err;
++      unsigned char           cmd;
++      unsigned char           sync;
++      unsigned char           dont_care;
++      struct spi_transfer     x[5];
++      struct spi_message      message;
++
++
++      cmd = AVR_CMD_READ_TIMER_AND_MODE;
++      sync = 0;
++      dont_care = 0;
++
++      memset(x, 0, sizeof x);
++      spi_message_init(&message);
++
++      x[0].len = 1;
++      x[0].tx_buf = &cmd;
++      x[0].rx_buf = &sync;
++      x[0].delay_usecs = 400;
++      spi_message_add_tail(&x[0], &message);
++
++      x[1].len = 1;
++      x[1].tx_buf = &dont_care;
++      x[1].rx_buf = &regs->timer_res;
++      x[1].delay_usecs = 400;
++      spi_message_add_tail(&x[1], &message);
++
++      x[2].len = 1;
++      x[2].tx_buf = &dont_care;
++      x[2].rx_buf = &regs->timer_msb;
++      x[2].delay_usecs = 400;
++      spi_message_add_tail(&x[2], &message);
++
++      x[3].len = 1;
++      x[3].tx_buf = &dont_care;
++      x[3].rx_buf = &regs->timer_lsb;
++      x[3].delay_usecs = 400;
++      spi_message_add_tail(&x[3], &message);
++
++      x[4].len = 1;
++      x[4].tx_buf = &dont_care;
++      x[4].rx_buf = &regs->mode;
++      x[4].delay_usecs = 400;
++      spi_message_add_tail(&x[4], &message);
++
++      err = spi_sync(spi, &message);
++
++      return err;
++}
++
++int avr_write_mode (struct spi_device *spi, struct avr_regs *regs)
++{
++      int                     err;
++      unsigned char           cmd;
++      unsigned char           sync;
++      struct spi_transfer     x[2];
++      struct spi_message      message;
++
++      cmd = AVR_CMD_WRITE_MODE;
++      sync = 0;
++
++      memset(x, 0, sizeof x);
++      spi_message_init(&message);
++
++      x[0].len = 1;
++      x[0].tx_buf = &cmd;
++      x[0].rx_buf = &sync;
++      x[0].delay_usecs = 400;
++      spi_message_add_tail(&x[0], &message);
++
++      x[1].len = 1;
++      x[1].tx_buf = &regs->mode;
++      x[1].rx_buf = 0;
++      x[1].delay_usecs = 400;
++      spi_message_add_tail(&x[1], &message);
++
++      err = spi_sync(spi, &message);
++
++      return err;
++}
++
++int avr_write_timer (struct spi_device *spi, struct avr_regs *regs)
++{
++      int                     err;
++      unsigned char           cmd;
++      unsigned char           sync;
++      struct spi_transfer     x[4];
++      struct spi_message      message;
++
++      cmd = AVR_CMD_WRITE_TIMER;
++      sync = 0;
++
++      memset(x, 0, sizeof x);
++      spi_message_init(&message);
++
++      x[0].len = 1;
++      x[0].tx_buf = &cmd;
++      x[0].rx_buf = &sync;
++      x[0].delay_usecs = 400;
++      spi_message_add_tail(&x[0], &message);
++
++      x[1].len = 1;
++      x[1].tx_buf = &regs->timer_res;
++      x[1].rx_buf = 0;
++      x[1].delay_usecs = 400;
++      spi_message_add_tail(&x[1], &message);
++
++      x[2].len = 1;
++      x[2].tx_buf = &regs->timer_msb;
++      x[2].rx_buf = 0;
++      x[2].delay_usecs = 400;
++      spi_message_add_tail(&x[2], &message);
++
++      x[3].len = 1;
++      x[3].tx_buf = &regs->timer_lsb;
++      x[3].rx_buf = 0;
++      x[3].delay_usecs = 400;
++      spi_message_add_tail(&x[3], &message);
++
++      err = spi_sync(spi, &message);
++
++      return err;
++}
++
++int avr_write_timer_and_mode (struct spi_device *spi, struct avr_regs *regs)
++{
++      int                     err;
++      unsigned char           cmd;
++      unsigned char           sync;
++      struct spi_transfer     x[5];
++      struct spi_message      message;
++
++
++      cmd = AVR_CMD_WRITE_TIMER_AND_MODE;
++      sync = 0;
++
++      memset(x, 0, sizeof x);
++      spi_message_init(&message);
++
++      x[0].len = 1;
++      x[0].tx_buf = &cmd;
++      x[0].rx_buf = &sync;
++      x[0].delay_usecs = 400;
++      spi_message_add_tail(&x[0], &message);
++
++      x[1].len = 1;
++      x[1].tx_buf = &regs->timer_res;
++      x[1].rx_buf = 0;
++      x[1].delay_usecs = 400;
++      spi_message_add_tail(&x[1], &message);
++
++      x[2].len = 1;
++      x[2].tx_buf = &regs->timer_msb;
++      x[2].rx_buf = 0;
++      x[2].delay_usecs = 400;
++      spi_message_add_tail(&x[2], &message);
++
++      x[3].len = 1;
++      x[3].tx_buf = &regs->timer_lsb;
++      x[3].rx_buf = 0;
++      x[3].delay_usecs = 400;
++      spi_message_add_tail(&x[3], &message);
++
++      x[4].len = 1;
++      x[4].tx_buf = &regs->mode;
++      x[4].rx_buf = 0;
++      x[4].delay_usecs = 400;
++      spi_message_add_tail(&x[4], &message);
++
++      err = spi_sync(spi, &message);
++
++      return err;
++}
++
+--- /dev/null
++++ git/drivers/bmi/pims/mdacc/avr.h
+@@ -0,0 +1,54 @@
++/*
++ * Copyright 2008 EnCADIS Designs, Inc. All Rights Reserved.
++ * Copyright 2008 Bug-Labs, Inc. All Rights Reserved.
++ *
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*-----------------------------------------------------------------------------
++ *
++ *      Part of BMI Motion Detector Accelerometer (MDACC) Kernel Module
++ *
++ *-----------------------------------------------------------------------------
++ */
++#ifndef MDACC_AVR_H
++#define MDACC_AVR_H
++
++#include <linux/device.h>
++#include <linux/spi/spi.h>
++
++struct avr_regs
++{
++      unsigned char timer_res;        // SPI Register 0
++      unsigned char timer_msb;        // SPI Register 1
++      unsigned char timer_lsb;        // SPI Register 2
++      unsigned char mode;             // SPI Register 3
++
++      unsigned char status;           // SPI Register 4
++
++      unsigned char adc0h;            // SPI Register 5
++      unsigned char adc0l;            // SPI Register 6
++      unsigned char adc1h;            // SPI Register 7
++      unsigned char adc1l;            // SPI Register 8
++      unsigned char adc2h;            // SPI Register 9
++      unsigned char adc2l;            // SPI Register 10
++};
++
++int avr_read_adc (struct spi_device *spi, struct avr_regs *regs);
++int avr_read_status (struct spi_device *spi, struct avr_regs *regs);
++int avr_read_status_and_adc (struct spi_device *spi, struct avr_regs *regs);
++int avr_read_mode  (struct spi_device *spi, struct avr_regs *regs);
++int avr_read_timer  (struct spi_device *spi, struct avr_regs *regs);
++int avr_read_timer_and_mode  (struct spi_device *spi, struct avr_regs *regs);
++int avr_write_mode (struct spi_device *spi, struct avr_regs *regs);
++int avr_write_timer (struct spi_device *spi, struct avr_regs *regs);
++int avr_write_timer_and_mode (struct spi_device *spi, struct avr_regs *regs);
++
++#endif
++
++
+--- /dev/null
++++ git/drivers/bmi/pims/mdacc/cque.c
+@@ -0,0 +1,150 @@
++/*
++ * Copyright 2008 EnCADIS Designs, Inc. All Rights Reserved.
++ * Copyright 2008 Bug-Labs, Inc. All Rights Reserved.
++ *
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*-----------------------------------------------------------------------------
++ *
++ *      Part of BMI Motion Detector Accelerometer (MDACC) Kernel Module
++ *
++ *-----------------------------------------------------------------------------
++ */
++
++#include "cque.h"
++#include <linux/slab.h>
++#include <linux/byteorder/generic.h>
++
++struct cque *cque_create  (int num_entries, int threshold)
++{
++
++      int entry_size;
++      struct cque     *cque;
++      void            *buf_base;
++      int             buf_size;
++
++      entry_size = 6;
++      cque = 0;
++      buf_size = entry_size * num_entries;
++      if (!buf_size) {
++              return 0;
++      }
++
++      if (( threshold > num_entries) ||
++          ( threshold < 1)) {
++              return 0;
++      }
++
++      cque = kmalloc (sizeof(cque), GFP_KERNEL);
++      if (!cque) {
++              return 0;
++      }
++
++      buf_base = kmalloc (buf_size, GFP_KERNEL);
++      if (!buf_base) {
++              kfree (cque);
++              return 0;
++      }
++
++      cque->entry_size  = entry_size;
++      cque->num_entries = num_entries;
++      cque->entry_cnt   = 0;
++      cque->threshold   = threshold;
++      cque->start       = buf_base;
++      cque->end         = buf_base + buf_size - entry_size;
++      cque->top         = buf_base;
++      cque->bot         = buf_base;
++
++      return cque;
++}
++
++void cque_destroy (struct cque *cque)
++{
++
++      if (cque) {
++              kfree (cque->start);
++              kfree (cque);
++      }
++      return;
++
++}
++
++int cque_write (struct cque *cque, void *data)
++{
++      int size;
++      int err;
++
++      size = 6;
++      err = 1;
++      if (cque) {
++              //insert
++
++              memcpy (cque->top, data, size);
++              cque->top += size;
++              if (cque->top > cque->end) {
++                      cque->top = cque->start;
++              }
++
++
++              if (cque->entry_cnt < cque->num_entries) {
++                      cque->entry_cnt++;
++              }
++              else {
++                      cque->bot += size;
++                      if (cque->bot > cque->end) {
++                              cque->bot = cque->start;
++                      }
++              }
++              err = 0;
++      }
++      return err;
++
++}
++
++int cque_read (struct cque *cque, void *data )
++{
++      int size;
++      int err;
++
++      size = 6;
++      err = 1;
++      if (cque) {
++
++              if (cque->entry_cnt) {
++
++                      //remove
++
++                      //memcpy (data, cque->bot, size) with swab ;
++
++                      *((short*)(data))   = ntohs (*((short*)(cque->bot)));
++                      *((short*)(data+2)) = ntohs (*((short*)(cque->bot+2)));
++                      *((short*)(data+4)) = ntohs (*((short*)(cque->bot+4)));
++                      cque->bot += size;
++                      if (cque->bot > cque->end) {
++                              cque->bot = cque->start;
++                      }
++                      cque->entry_cnt--;
++                      err = 0;
++              }
++      }
++      return err;
++}
++
++int cque_is_ready_for_read (struct cque *cque)
++{
++      int ready;
++
++      ready = 0;
++      if ((cque) && (cque->entry_cnt >= cque->threshold)) {
++              ready = 1;
++      }
++      return ready;
++}
++
++
+--- /dev/null
++++ git/drivers/bmi/pims/mdacc/cque.h
+@@ -0,0 +1,42 @@
++/*
++ * Copyright 2008 EnCADIS Designs, Inc. All Rights Reserved.
++ * Copyright 2008 Bug-Labs, Inc. All Rights Reserved.
++ *
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*-----------------------------------------------------------------------------
++ *
++ *      Part of BMI Motion Detector Accelerometer (MDACC) Kernel Module
++ *
++ *-----------------------------------------------------------------------------
++ */
++#ifndef MDACC_CQUE_H
++#define MDACC_CQUE_H
++
++struct cque
++{
++      int     entry_size;
++      int     num_entries;
++      int     entry_cnt;
++      int     threshold;
++
++      void    *start;
++      void    *end;
++      void    *top;
++      void    *bot;
++};
++
++struct cque *cque_create  (int num_entries, int threshold);
++void cque_destroy (struct cque *cque);
++
++int cque_write (struct cque *cque, void *data);
++int cque_read (struct cque *cque, void *data);
++int cque_is_ready_for_read (struct cque *cque);
++
++#endif
+--- /dev/null
++++ git/drivers/bmi/pims/mdacc/ctl.c
+@@ -0,0 +1,176 @@
++/*
++ * Copyright 2008 EnCADIS Designs, Inc. All Rights Reserved.
++ * Copyright 2008 Bug-Labs, Inc. All Rights Reserved.
++ *
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*-----------------------------------------------------------------------------
++ *
++ *      Part of BMI Motion Detector Accelerometer (MDACC) Kernel Module
++ *
++ *-----------------------------------------------------------------------------
++ */
++
++#include "ctl.h"
++#include "mdacc.h"
++#include <linux/bmi/bmi_mdacc.h>
++#include <linux/ioctl.h>
++#include <linux/bmi.h>
++#include <linux/bmi/bmi-slot.h>
++
++
++#include <linux/module.h>
++
++static int ctl_open (struct inode *, struct file *);
++static int ctl_release (struct inode *, struct file *);
++static int ctl_ioctl (struct inode *, struct file *, unsigned int, unsigned long);
++
++struct file_operations ctl_fops = {
++      .owner = THIS_MODULE,
++      .ioctl = ctl_ioctl,
++      .open = ctl_open,
++      .release = ctl_release,
++};
++
++static int ctl_major;
++
++int ctl_init (void)
++{
++      dev_t   dev_id;
++      int     retval;
++
++      // alloc char driver with 4 minor numbers
++
++      retval = alloc_chrdev_region(&dev_id, 0, 4, "BMI MDACC Control Driver");
++
++      if (retval) {
++              return -1;
++      }
++      ctl_major = MAJOR(dev_id);
++      return 0;
++}
++
++void ctl_clean (void)
++{
++      dev_t dev_id;
++
++      dev_id = MKDEV(ctl_major, 0);
++      unregister_chrdev_region(dev_id, 4);
++      return;
++}
++
++int ctl_probe (struct ctl *ctl, int slot)
++{
++      struct cdev *cdev;
++      dev_t dev_id;
++      int ret;
++      struct class *bmi_class;
++
++      cdev = &ctl->cdev;
++      cdev_init (cdev, &ctl_fops);
++
++      dev_id = MKDEV (ctl_major, slot);
++      ret = cdev_add (cdev, dev_id, 1);
++
++      //Create class device
++      bmi_class = bmi_get_class ();
++
++      ctl->class_dev = device_create (bmi_class, NULL, MKDEV(ctl_major, slot), ctl, "bmi_mdacc_ctl_m%i", slot+1);
++
++      if (IS_ERR(ctl->class_dev)) {
++              printk(KERN_ERR "Unable to create "
++                     "class_device for bmi_mdacc_ctl_m%i; errno = %ld\n",
++                     slot+1, PTR_ERR(ctl->class_dev));
++              ctl->class_dev = NULL;
++      }
++
++      return ret;
++}
++
++void ctl_remove (struct ctl *ctl, int slot)
++{
++      struct class *bmi_class;
++
++      bmi_class = bmi_get_class ();
++      device_destroy (bmi_class, MKDEV(ctl_major, slot));
++
++      ctl->class_dev = 0;
++
++      cdev_del (&ctl->cdev);
++      return;
++}
++
++
++static int ctl_open (struct inode *inode, struct file *file)
++{
++      struct ctl *ctl;
++
++      ctl = container_of(inode->i_cdev, struct ctl, cdev);
++
++
++      // Save ctl pointer for later.
++
++      file->private_data = ctl;
++      return 0;
++}
++
++static int ctl_release (struct inode *inode, struct file *file)
++{
++      struct ctl *ctl;
++
++      ctl = container_of(inode->i_cdev, struct ctl, cdev);
++      return 0;
++}
++
++static int ctl_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
++{
++      struct ctl *ctl;
++      int slot;
++      unsigned char tmp = 0;
++
++      ctl = container_of(inode->i_cdev, struct ctl, cdev);
++      slot = mdacc_get_slot_ctl (ctl);
++      if (slot < 0) {
++              return -ENODEV;
++      }
++
++      switch (cmd) {
++
++      case BMI_MDACC_CTL_RED_LED_OFF:
++       tmp = bmi_slot_gpio_get(slot);
++       bmi_slot_gpio_set (slot, tmp | RED_LED);
++       //bmi_slot_gpio_write_bit (slot, 3, 1); //Red LED Off
++       break;
++
++      case BMI_MDACC_CTL_RED_LED_ON:
++        tmp = bmi_slot_gpio_get(slot);
++        bmi_slot_gpio_set (slot, tmp & ~RED_LED);
++        //bmi_slot_gpio_write_bit (slot, 3, 0); //Red LED On
++        break;
++
++      case BMI_MDACC_CTL_GREEN_LED_OFF:
++        tmp = bmi_slot_gpio_get(slot);
++        bmi_slot_gpio_set (slot, tmp | GREEN_LED);
++        //bmi_slot_gpio_write_bit (slot, 2, 1); //Green LED Off
++        break;
++
++      case BMI_MDACC_CTL_GREEN_LED_ON:
++        tmp = bmi_slot_gpio_get(slot);
++        bmi_slot_gpio_set (slot, tmp & ~GREEN_LED);
++        //bmi_slot_gpio_write_bit (slot, 2, 0); //Green LED On
++        break;
++
++      default:
++        printk (KERN_ERR "ctl_ioctl() - error exit\n");
++        return -ENOTTY;
++      }
++
++      return 0;
++}
++
+--- /dev/null
++++ git/drivers/bmi/pims/mdacc/ctl.h
+@@ -0,0 +1,43 @@
++/*
++ * Copyright 2008 EnCADIS Designs, Inc. All Rights Reserved.
++ * Copyright 2008 Bug-Labs, Inc. All Rights Reserved.
++ *
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*-----------------------------------------------------------------------------
++ *
++ *      Part of BMI Motion Detector Accelerometer (MDACC) Kernel Module
++ *
++ *-----------------------------------------------------------------------------
++ */
++
++#ifndef MDACC_CTL_H
++#define MDACC_CTL_H
++
++#include <linux/kernel.h>
++
++#include <linux/fs.h>
++#include <linux/cdev.h>
++
++
++struct ctl
++{
++      struct cdev cdev;
++      struct device *class_dev;
++};
++
++extern int  ctl_init (void);
++extern void ctl_clean(void);
++extern int  ctl_probe (struct ctl *ctl, int slot);
++extern void ctl_remove(struct ctl *ctl, int slot);
++
++
++#endif
++
++
+--- /dev/null
++++ git/drivers/bmi/pims/mdacc/md.c
+@@ -0,0 +1,333 @@
++/*
++ * Copyright 2008 EnCADIS Designs, Inc. All Rights Reserved.
++ * Copyright 2008 Bug-Labs, Inc. All Rights Reserved.
++ *
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*-----------------------------------------------------------------------------
++ *
++ *      Part of BMI Motion Detector Accelerometer (MDACC) Kernel Module
++ *
++ *-----------------------------------------------------------------------------
++ */
++
++#include "md.h"
++#include "mdacc.h"
++#include "mon.h"
++#include <linux/bmi/bmi_mdacc.h>
++#include <linux/ioctl.h>
++#include <linux/poll.h>
++
++static int md_open (struct inode *, struct file *);
++static int md_release (struct inode *, struct file *);
++static int md_ioctl (struct inode *, struct file *, unsigned int, unsigned long);
++static ssize_t md_read (struct file *, char __user *, size_t, loff_t *);
++static unsigned int md_poll (struct file *, struct poll_table_struct *);
++
++struct file_operations md_fops = {
++      .owner = THIS_MODULE,
++      .ioctl = md_ioctl,
++      .open = md_open,
++      .release = md_release,
++      .read = md_read,
++      .poll = md_poll,
++};
++
++static int md_major;
++
++#define BMI_MOTION_DETECT_MASK   (BMI_MOTION_DETECT_STATUS         | \
++                                BMI_MOTION_DETECT_LATCHED_STATUS | \
++                                BMI_MOTION_DETECT_DELTA          | \
++                                BMI_MOTION_DETECT_ENABLED)
++
++
++
++void md_update (struct md *md, char data)
++{
++
++      unsigned char old_delta;
++      unsigned char new_delta;
++      unsigned char merge_bits;
++      unsigned char new_bits;
++
++
++      // Delta and Latched Status Bit Handling.
++
++      //  MOTION_STATUS        Bit 3
++      //  LATCHED_STATUS       Bit 2
++      //  DELTA                Bit 1
++      //  ENABLED              Bit 0
++
++
++      // Handle bits individually
++
++      old_delta = md->status & 0x02;
++      new_delta = data & 0x02;
++
++      if (!new_delta) {
++              //preserve old latch bit, update delta bit
++              merge_bits = (md->status & 0x06) | (data & 0x02);
++      }
++      else {
++              //update latch bit and delta bit
++              merge_bits = (md->status & 0x06) | (data & 0x06);
++      }
++      new_bits = data & 0x09;
++      md->status = merge_bits | new_bits;
++
++      if (!old_delta && new_delta) {
++              md->ready = 1;
++              //wake up anyone sleeping on our read wait queue
++              wake_up_interruptible (&md->read_wait_queue);
++
++      }
++      return;
++}
++
++
++void md_clear_status (struct md *md)
++{
++
++      md->status &= ~(BMI_MOTION_DETECT_LATCHED_STATUS |
++                      BMI_MOTION_DETECT_DELTA);
++
++      md->ready = 0;
++      return;
++
++}
++
++
++int  md_init (void)
++{
++      dev_t   dev_id;
++      int     retval;
++
++      // alloc char driver with 4 minor numbers
++
++      retval = alloc_chrdev_region(&dev_id, 0, 4, "BMI MDACC Motion Detector Driver");
++
++      if (retval) {
++              return -1;
++      }
++      md_major = MAJOR(dev_id);
++      return 0;
++}
++
++void md_clean (void)
++{
++      dev_t dev_id;
++
++      dev_id = MKDEV(md_major, 0);
++      unregister_chrdev_region(dev_id, 4);
++      return;
++}
++
++int  md_probe (struct md *md, int slot, struct mon *mon)
++{
++      struct cdev *cdev;
++      dev_t dev_id;
++      int ret;
++      struct class *bmi_class;
++
++      md->removed = 0;
++
++      cdev = &md->cdev;
++      cdev_init (cdev, &md_fops);
++
++      dev_id = MKDEV (md_major, slot);
++      ret = cdev_add (cdev, dev_id, 1);
++
++      //Create class device
++      bmi_class = bmi_get_class ();
++
++      md->class_dev = device_create (bmi_class, NULL, MKDEV(md_major, slot), md, "bmi_mdacc_mot_m%i", slot+1);
++
++      if (IS_ERR(md->class_dev)) {
++              printk(KERN_ERR "Unable to create "
++                     "class_device for bmi_mdacc_mot_m%i; errno = %ld\n",
++                     slot+1, PTR_ERR(md->class_dev));
++              md->class_dev = NULL;
++      }
++
++      md->open_flag = 0;
++      md->enabled = 0;
++      md->status = 0;
++      init_waitqueue_head (&md->read_wait_queue);
++      md->mon = mon;
++      return ret;
++}
++
++void md_remove (struct md *md, int slot )
++{
++      struct class *bmi_class;
++
++      md->removed = 1;
++      md->ready = -1;
++      wake_up_interruptible (&md->read_wait_queue);
++
++      cdev_del (&md->cdev);
++      bmi_class = bmi_get_class ();
++      device_destroy (bmi_class, MKDEV(md_major, slot));
++      md->class_dev = 0;
++      return;
++}
++
++
++static int md_open (struct inode *inode, struct file *file)
++{
++      struct md *md;
++
++      md = container_of(inode->i_cdev, struct md, cdev);
++
++      //Enforce single open behavior
++      if (md->open_flag) {
++              return -EBUSY;
++      }
++      md->open_flag = 1;
++
++      // Save md_drv pointer for later.
++      file->private_data = md;
++      return 0;
++}
++
++static int md_release (struct inode *inode, struct file *file)
++{
++      struct md *md;
++
++      md = container_of(inode->i_cdev, struct md, cdev);
++      md->open_flag = 0;
++
++      //Enforce stop-on-close behavior.
++      if (md->enabled) {
++              mon_stop_motion (md->mon);
++      }
++      return 0;
++}
++
++static int md_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
++{
++      int err = 0;
++      struct md *md;
++      md = container_of(inode->i_cdev, struct md, cdev);
++
++      switch (cmd) {
++
++      case BMI_MDACC_MOTION_DETECTOR_GET_STATUS:
++
++              err = mon_status_request (md->mon);
++              if (err){
++                      return -ENODEV;
++              }
++
++              //copy to user
++              err = copy_to_user((void*)(arg), &md->status, sizeof(md->status));
++              md_clear_status (md);
++              if (err) {
++                      return -EFAULT;
++              }
++              break;
++
++
++      case BMI_MDACC_MOTION_DETECTOR_RUN:
++
++              err = mon_start_motion (md->mon);
++
++              if (err){
++                      return -ENODEV;
++              }
++              mon_status_request (md->mon);
++              md->enabled = 1;
++              break;
++
++
++      case BMI_MDACC_MOTION_DETECTOR_STOP:
++
++              err = mon_stop_motion (md->mon);
++              if (err){
++                      return -ENODEV;
++              }
++
++              break;
++
++      default:
++              printk (KERN_ERR "md_ioctl() - error exit\n");
++              return -ENOTTY;
++      }
++      return 0;
++}
++
++static ssize_t md_read (struct file *file, char __user *buf, size_t count, loff_t *ppos)
++{
++
++//
++// if fd is non-blocking and md is not enabled, return EWOULDBLOCK
++// if fd is non-blocking and md is enabled, and md is not ready, return EWOULDBLOCK
++// if fd is non-blocking and md is enabled, and md is ready, copy md->status to user, md_clear_status(),
++
++// if fd is blocking and md is not enabled, avr_read_status,
++//                                        md_update,  copy md->status to user, md_clear_status()
++
++// if fs is blocking and md is enabled, and md is not ready, sleep until ready.
++//                                                           when ready, copy md->status to user, md_clear_status()
++
++
++      int err;
++      struct md *md = file->private_data;
++
++
++      if (!md->enabled) {
++              return -EAGAIN;
++      }
++
++      if (file->f_flags & O_NONBLOCK) {
++              return -EAGAIN;
++      }
++
++      while (!md->ready) {
++
++              if (file->f_flags & O_NONBLOCK)
++                      return -EAGAIN;
++              if (wait_event_interruptible (md->read_wait_queue, (md->ready)))
++                      return -ERESTARTSYS;
++
++              if(md->removed) {
++                return -1;
++              }
++      }
++
++      err = copy_to_user (buf, &md->status, 1);
++      md_clear_status (md);
++      if (err) {
++              return -EFAULT;
++      }
++      return 1;
++}
++
++static unsigned int md_poll (struct file *file, struct poll_table_struct *table)
++{
++      unsigned int mask = 0;
++      struct md *md = file->private_data;
++
++      poll_wait(file, &md->read_wait_queue, table);
++
++      if (md->ready) {
++              mask |= POLLIN | POLLRDNORM;    /* readable */
++      }
++
++      if (mdacc_check_bdev_md (md) ) {
++              mask |= POLLHUP;        /* hang-up */
++      }
++
++      if (!md->enabled) {
++              mask |= POLLHUP;        /* hang-up */
++      }
++      return mask;
++}
++
++
+--- /dev/null
++++ git/drivers/bmi/pims/mdacc/md.h
+@@ -0,0 +1,60 @@
++/*
++ * Copyright 2008 EnCADIS Designs, Inc. All Rights Reserved.
++ * Copyright 2008 Bug-Labs, Inc. All Rights Reserved.
++ *
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*-----------------------------------------------------------------------------
++ *
++ *      Part of BMI Motion Detector Accelerometer (MDACC) Kernel Module
++ *
++ *-----------------------------------------------------------------------------
++ */
++
++#ifndef MDACC_MD_H
++#define MDACC_MD_H
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++
++#include <linux/fs.h>
++#include <linux/cdev.h>
++
++#include <linux/bmi.h>
++#include <linux/delay.h>
++
++#include <linux/workqueue.h>
++
++struct mon;
++
++struct md
++{
++      struct cdev cdev;
++      struct device *class_dev;
++      int open_flag;
++      int enabled;
++      unsigned char status;
++      int ready;
++      wait_queue_head_t read_wait_queue;
++      struct mon *mon;
++        u8 removed;
++};
++
++
++extern int  md_init (void);
++extern void md_clean(void);
++extern int  md_probe (struct md *md, int slot, struct mon *mon);
++extern void md_remove(struct md *md, int slot);
++
++
++void md_update ( struct md *md, char data);
++void md_clear_status (struct md *md );
++
++
++#endif
+--- /dev/null
++++ git/drivers/bmi/pims/mdacc/mdacc.c
+@@ -0,0 +1,333 @@
++/*
++ * Copyright 2008 EnCADIS Designs, Inc. All Rights Reserved.
++ * Copyright 2008 Bug-Labs, Inc. All Rights Reserved.
++ *
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*-----------------------------------------------------------------------------
++ *
++ *         BMI Motion Detector Accelerometer (MDACC) Kernel Module
++ *
++ * This kernel module contains the device drivers for the Bug MDACC Plug-In
++ * Module. Refer to include/linux/bmi/bmi_mdacc.h for user-level device driver
++ * programming information.
++ *------------------------------------------------------------------------------
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++
++#include <linux/fs.h>
++#include <linux/cdev.h>
++
++#include <linux/bmi.h>
++#include <linux/delay.h>
++
++#include <linux/workqueue.h>
++
++#define BMI_MDACC_VERSION  "1.0" // driver version
++
++
++#include "md.h"
++#include "acc.h"
++#include "ctl.h"
++#include "mon.h"
++#include "avr.h"
++#include "cque.h"
++#include "mdacc.h"
++
++
++// private device structure
++struct pim
++{
++  struct bmi_device *bdev;
++  struct ctl ctl;
++  struct md  md;
++  struct acc acc;
++  struct mon mon;
++  char *name;
++};
++
++static struct pim bug_mdacc_pim[4];
++
++// BMI device ID table
++static struct bmi_device_id bmi_mdacc_tbl[] =
++{
++      {
++              .match_flags = BMI_DEVICE_ID_MATCH_VENDOR | BMI_DEVICE_ID_MATCH_PRODUCT,
++              .vendor   = BMI_VENDOR_BUG_LABS,
++              .product  = BMI_PRODUCT_MOT_ACCEL,
++              .revision = BMI_ANY,
++      },
++      { 0, },                                   /* terminate list */
++};
++MODULE_DEVICE_TABLE(bmi, bmi_mdacc_tbl);
++
++int   bmi_mdacc_probe(struct bmi_device *bdev);
++void  bmi_mdacc_remove(struct bmi_device *bdev);
++
++// BMI driver structure
++static struct bmi_driver bmi_mdacc_driver =
++{
++      .name     = "bmi_mdacc",
++      .id_table =  bmi_mdacc_tbl,
++      .probe    =  bmi_mdacc_probe,
++      .remove   =  bmi_mdacc_remove,
++};
++
++
++// Support functions
++
++int mdacc_get_slot_mon (struct mon *mon)
++{
++      struct pim *pim;
++      int slot;
++
++      pim = container_of(mon, struct pim, mon);
++
++      if (pim->bdev == 0) {
++              slot = -1;
++      }
++      else {
++              slot = pim->bdev->slot->slotnum;
++      }
++      return slot;
++}
++
++int mdacc_get_slot_ctl (struct ctl *ctl)
++{
++      struct pim *pim;
++      int slot;
++
++      pim = container_of(ctl, struct pim, ctl);
++
++      if (pim->bdev == 0) {
++              slot = -1;
++      }
++      else {
++              slot = pim->bdev->slot->slotnum;
++      }
++      return slot;
++}
++
++
++struct spi_device* mdacc_get_spi_mon (struct mon *mon)
++{
++      struct pim *pim;
++      struct spi_device *spi = 0;
++
++      /*
++      pim = container_of(mon, struct pim, mon);
++
++      if (pim->bdev) {
++              spi = pim->bdev->slot->slotnum;
++      }
++      */
++      return spi;
++}
++
++struct bmi_device* mdacc_get_bdev_mon (struct mon *mon)
++{
++      struct pim *pim;
++
++      pim = container_of(mon, struct pim, mon);
++      return pim->bdev;
++}
++
++int mdacc_check_bdev_md (struct md *md)
++{
++      int err;
++      struct pim *pim;
++
++      err = 0;
++      pim = container_of(md, struct pim, md);
++      if (!pim->bdev) {
++              err = 1;
++      }
++      return err;
++}
++
++int mdacc_check_bdev_acc (struct acc *acc)
++{
++      int err;
++      struct pim *pim;
++
++      err = 0;
++      pim = container_of(acc, struct pim, acc);
++      if (!pim->bdev) {
++              err = 1;;
++      }
++      return err;
++}
++
++// BMI Functions
++
++int bmi_mdacc_probe(struct bmi_device *bdev)
++{
++      int slot;
++      struct pim *pim;
++      int irq;
++      unsigned char tmp = 0;
++
++      // Module GPIO use:
++      //                                      0       1
++      // GPIO 3       Red LED                 On      Off
++      // GPIO 2       Green LED               On      Off
++      // GPIO 1       AVR Reset               Reset   Normal Operation
++      // GPIO 0       Accel. Sleep Mode       Sleep   Normal Operation
++
++      slot = bdev->slot->slotnum;
++      pim = &bug_mdacc_pim[slot];
++
++      bmi_device_set_drvdata(bdev, pim);
++      pim->bdev = bdev;
++
++
++      // Setup GPIOs for this slot
++
++      bmi_slot_gpio_configure(slot, RED_LED | GREEN_LED | GPIO_1 | GPIO_0);    //Red   LED: On
++      bmi_slot_gpio_set(slot, GPIO_0);
++
++      bmi_slot_spi_enable(slot);
++
++      //AVR Reset Active time
++      mdelay(1);
++
++
++      //Take AVR out of reset
++      bmi_slot_gpio_set(slot, GPIO_1 | GPIO_0);
++
++      //AVR Reset Recovery time
++
++      mdelay (100);
++
++
++      switch (slot) {
++      case 0:
++              pim->name = "mdacc_m1";
++              break;
++      case 1:
++              pim->name = "mdacc_m2";
++              break;
++      case 2:
++              pim->name = "mdacc_m3";
++              break;
++      case 3:
++              pim->name = "mdacc_m4";
++              break;
++      }
++
++      irq = bdev->slot->status_irq;
++
++      if (mon_probe (&pim->mon, pim->name, irq, &pim->md, &pim->acc) ) {
++              printk (KERN_ERR "bmi_mdacc_probe() - mon_probe() failed.\n");
++              goto exit1;
++              }
++      if (md_probe (&pim->md, slot, &pim->mon) ) {
++              printk (KERN_ERR "bmi_mdacc_probe() - md_probe() failed.\n");
++              goto exit2;
++              }
++      if (acc_probe (&pim->acc, slot, &pim->mon) ) {
++              printk (KERN_ERR "bmi_mdacc_probe() - acc_probe() failed.\n");
++              goto exit3;
++              }
++      if (ctl_probe (&pim->ctl, slot) ) {
++              printk (KERN_ERR "bmi_mdacc_probe() - ctl_probe() failed.\n");
++              goto exit4;
++              }
++
++      tmp = bmi_slot_gpio_get(slot);
++      bmi_slot_gpio_set (slot, tmp | RED_LED); //Red + Green LEDs Off
++      return 0;
++
++exit4:
++      acc_remove (&pim->acc, slot);
++exit3:
++      md_remove (&pim->md, slot);
++exit2:
++      mon_remove (&pim->mon);
++
++exit1:
++      bmi_slot_spi_disable(slot);
++      bmi_device_set_drvdata (bdev, 0);
++      pim->bdev = 0;
++      //      bmi_slot_gpio_write_bit (slot, 2, 1); //Green LED Off
++      tmp = bmi_slot_gpio_get(slot);
++      bmi_slot_gpio_set (slot, tmp | GREEN_LED);
++      return -1;
++}
++
++void bmi_mdacc_remove(struct bmi_device *bdev)
++{
++      int slot;
++      struct pim *pim;
++
++      slot = bdev->slot->slotnum;
++      pim = &bug_mdacc_pim[slot];
++
++      ctl_remove (&pim->ctl, slot);
++      acc_remove (&pim->acc, slot);
++      md_remove (&pim->md, slot);
++      mon_remove (&pim->mon);
++
++      bmi_slot_spi_disable(slot);
++
++      bmi_device_set_drvdata (bdev, 0);
++#if 0
++      pim->bdev = 0;
++#endif
++
++      return;
++}
++
++
++
++static __init int bmi_mdacc_init(void)
++{
++      int rc = 0;
++
++      acc_init();
++      md_init();
++      ctl_init();
++
++//    Register with BMI bus.
++      rc = bmi_register_driver(&bmi_mdacc_driver);
++      if(rc) {
++              printk(KERN_ERR "bmi_mdacc_init() - bmi_register_driver failed\n");
++              return rc;
++      }
++
++      printk("BMI MDACC Driver v%s \n", BMI_MDACC_VERSION);
++      return 0;
++}
++
++static void __exit bmi_mdacc_clean(void)
++{
++//    Unregister with BMI bus.
++      bmi_unregister_driver(&bmi_mdacc_driver);
++
++      ctl_clean();
++      md_clean();
++      acc_clean();
++      return;
++}
++
++module_init(bmi_mdacc_init);
++module_exit(bmi_mdacc_clean);
++
++MODULE_AUTHOR("EnCADIS Design, Inc.");
++MODULE_DESCRIPTION("BMI Motion Detector/Accelerometer Driver");
++MODULE_LICENSE("GPL");
++
++
++
++
++
++
++
+--- /dev/null
++++ git/drivers/bmi/pims/mdacc/mdacc.h
+@@ -0,0 +1,43 @@
++/*
++ * Copyright 2008 EnCADIS Designs, Inc. All Rights Reserved.
++ * Copyright 2008 Bug-Labs, Inc. All Rights Reserved.
++ *
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*-----------------------------------------------------------------------------
++ *
++ *      Part of BMI Motion Detector Accelerometer (MDACC) Kernel Module
++ *
++ *-----------------------------------------------------------------------------
++ */
++
++#ifndef MDACC_H
++#define MDACC_H
++
++struct acc;
++struct ctl;
++struct md;
++struct mon;
++struct spi_device;
++struct bmi_device;
++
++extern int mdacc_get_slot_mon (struct mon *mon);
++extern int mdacc_get_slot_ctl (struct ctl *ctl);
++
++extern struct bmi_device* mdacc_get_bdev_mon (struct mon *mon);
++extern struct spi_device* mdacc_get_spi_mon (struct mon *mon);
++
++int mdacc_check_bdev_md (struct md *md);
++int mdacc_check_bdev_acc (struct acc *acc);
++
++struct mon *mdacc_get_mon_md(struct md *md);
++struct mon *mdacc_get_mon_acc(struct acc *acc);
++
++#endif
++
+--- /dev/null
++++ git/drivers/bmi/pims/mdacc/mon.c
+@@ -0,0 +1,474 @@
++/*
++ * Copyright 2008 EnCADIS Designs, Inc. All Rights Reserved.
++ * Copyright 2008 Bug-Labs, Inc. All Rights Reserved.
++ *
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*-----------------------------------------------------------------------------
++ *
++ *      Part of BMI Motion Detector Accelerometer (MDACC) Kernel Module
++ *
++ *-----------------------------------------------------------------------------
++ */
++
++#include "mon.h"
++#include "mdacc.h"
++#include <linux/interrupt.h>
++
++#include <linux/spi/spi.h>
++
++#define work_to_mon(w)  container_of(w, struct mon, work_item)
++
++enum
++{
++      MON_STATE_IDLE,
++      MON_STATE_MOTION_ONLY,
++      MON_STATE_ACC_ONLY,
++      MON_STATE_MOTION_AND_ACC
++};
++
++enum
++{
++      MON_ACTION_START_ACC,
++      MON_ACTION_START_MOTION,
++      MON_ACTION_STOP_ACC,
++      MON_ACTION_STOP_MOTION
++};
++
++
++
++
++/*
++   Spi Mode Register
++   --------------------------------
++   Timer Enable           Bit  4
++   ADC Poll Enable        Bit  3
++   Motion Detect Enable   Bit  2
++   GSEL1:0                Bits 1:0
++
++
++   SPI Status Register
++   ------------------------------------
++   Not used                     Bit 7
++   Timer Enabled                Bit 6
++   Adc Complete                 Bit 5
++   Adc Enabled                  Bit 4
++   Motion Detect Status         Bit 3
++   Motion Detect Latched Status Bit 2
++   Motion Detect Delta          Bit 1
++   Motion Detect Enabled        Bit 0
++
++
++
++*/
++
++static void mon_change_state (struct mon* mon, int action)
++{
++      switch (mon->state) {
++
++      case MON_STATE_IDLE:
++
++              switch (action) {
++
++              case MON_ACTION_START_MOTION:
++                      mon->state = MON_STATE_MOTION_ONLY;
++                      break;
++
++              case MON_ACTION_START_ACC:
++                      mon->state = MON_STATE_ACC_ONLY;
++                      break;
++              }
++              break;
++
++      case MON_STATE_MOTION_ONLY:
++
++              switch (action) {
++
++              case MON_ACTION_STOP_MOTION:
++                      mon->state = MON_STATE_IDLE;
++                      break;
++
++              case MON_ACTION_START_ACC:
++                      mon->state = MON_STATE_MOTION_AND_ACC;
++                      break;
++              }
++              break;
++
++      case MON_STATE_ACC_ONLY:
++
++              switch (action) {
++
++              case MON_ACTION_STOP_ACC:
++                      mon->state = MON_STATE_IDLE;
++                      break;
++
++              case MON_ACTION_START_MOTION:
++                      mon->state = MON_STATE_MOTION_AND_ACC;
++                      break;
++              }
++              break;
++
++      case MON_STATE_MOTION_AND_ACC:
++
++              switch (action) {
++
++              case MON_ACTION_STOP_ACC:
++                      mon->state = MON_STATE_MOTION_ONLY;
++                      break;
++
++              case MON_ACTION_STOP_MOTION:
++                      mon->state = MON_STATE_ACC_ONLY;
++                      break;
++              }
++              break;
++      }
++      return;
++}
++
++int mon_start_motion (struct mon *mon)
++{
++      int err = 0;
++      struct spi_device *spi;
++
++      spi = mon->spi;
++      if (spi) {
++        if (down_interruptible (&mon->sem))
++          return -ERESTARTSYS;
++        mon->regs.mode |= 0x04;
++        avr_write_mode (spi, &mon->regs);
++        mon_change_state (mon, MON_ACTION_START_MOTION);
++        up (&mon->sem);
++      }
++      else {
++        printk (KERN_ERR "mon_start_motion() - FAIL - spi is 0.\n");
++        err = 1;
++      }
++      return err ;
++}
++
++int mon_stop_motion (struct mon *mon)
++{
++      int err = 0;
++      struct spi_device *spi;
++
++      spi = mon->spi;
++      if (spi) {
++        if (down_interruptible (&mon->sem))
++          return -ERESTARTSYS;
++        mon->regs.mode &= ~(0x04);
++        avr_write_mode (spi, &mon->regs);
++        mon_change_state (mon, MON_ACTION_STOP_MOTION);
++        up (&mon->sem);
++      }
++      else {
++        printk (KERN_ERR "mon_stop_motion() - FAIL - spi is 0.\n");
++        err = 1;
++      }
++      return err ;
++}
++
++
++int mon_set_config_accel (struct mon *mon, struct mdacc_accel_config *cfg)
++{
++      int err = 0;
++      unsigned char tmp;
++      struct spi_device *spi;
++
++      spi = mon->spi;
++      if (cfg && spi) {
++        if (down_interruptible (&mon->sem))
++          return -ERESTARTSYS;
++        if  (cfg->delay_mode) {
++
++          mon->regs.timer_res = cfg->delay_resolution;
++          mon->regs.timer_msb = cfg->delay >> 8;
++          mon->regs.timer_lsb = cfg->delay;
++          mon->regs.mode |= 0x10;
++        }
++        else {
++          mon->regs.mode &= ~0x10;
++        }
++
++        if  (cfg->run) {
++          mon->regs.mode |= 0x08;
++          mon_change_state (mon, MON_ACTION_START_ACC);
++        }
++        else {
++          mon->regs.mode &= ~0x08;
++          mon_change_state (mon, MON_ACTION_STOP_ACC);
++
++        }
++
++        tmp = mon->regs.mode & 0xFC;
++        tmp |= cfg->sensitivity & 0x03;
++        mon->regs.mode = tmp;
++
++        if  (cfg->delay_mode) {
++          avr_write_timer_and_mode (spi, &mon->regs);
++        }
++        else {
++          avr_write_mode (spi, &mon->regs);
++        }
++        up (&mon->sem);
++      }
++      else {
++        printk (KERN_ERR "mon_set_config_accel() - FAIL - null pointer.\n");
++        err = 1;
++      }
++      return err ;
++}
++
++int mon_get_config_accel (struct mon *mon, struct mdacc_accel_config *cfg)
++{
++      int err = 0;
++      struct spi_device *spi;
++
++      spi = mon->spi;
++      if (cfg && spi) {
++        if (down_interruptible (&mon->sem))
++          return -ERESTARTSYS;
++
++        avr_read_timer_and_mode (spi, &mon->regs);
++
++
++        if (mon->regs.mode & 0x10) {
++          cfg->delay_mode = 1;
++          cfg->delay_resolution = mon->regs.timer_res;
++          cfg->delay = mon->regs.timer_msb << 8 |  mon->regs.timer_lsb;
++        }
++        else {
++          cfg->delay_mode = 0;
++          cfg->delay_resolution = 1;
++          cfg->delay = 5000;
++        }
++
++        if (mon->regs.mode & 0x08) {
++          cfg->run = 1;
++        }
++        else {
++          cfg->run = 0;
++        }
++        cfg->sensitivity = mon->regs.mode & 0x03;
++        up (&mon->sem);
++      }
++      else {
++        printk (KERN_ERR "mon_get_config_accel() - FAIL - null pointer.\n");
++        err = 1;
++      }
++      return err ;
++}
++
++int mon_start_accel (struct mon *mon)
++{
++      int err = 0;
++      struct spi_device *spi;
++
++      spi = mon->spi;
++      if (spi) {
++        if (down_interruptible (&mon->sem))
++          return -ERESTARTSYS;
++        mon->regs.mode |= 0x08;
++        avr_write_mode (spi, &mon->regs);
++        mon_change_state (mon, MON_ACTION_START_ACC);
++        up (&mon->sem);
++      }
++      else {
++        printk (KERN_ERR "mon_start_accel() - FAIL - spi is 0.\n");
++        err = 1;
++      }
++      return err ;
++}
++
++
++int mon_stop_accel (struct mon *mon)
++{
++      int err = 0;
++
++      struct spi_device *spi;
++
++      spi = mon->spi;
++      if (spi) {
++        if (down_interruptible (&mon->sem))
++          return -ERESTARTSYS;
++
++        mon->regs.mode &= ~0x08;
++        avr_write_mode (spi, &mon->regs);
++        mon_change_state (mon, MON_ACTION_STOP_ACC);
++        up (&mon->sem);
++      }
++      else {
++        printk (KERN_ERR "mon_stop_accel() - FAIL - spi is 0.\n");
++        err = 1;
++      }
++      return err ;
++}
++
++
++int mon_status_request (struct mon* mon)
++{
++      struct spi_device *spi;
++      int err = 0;
++
++
++      spi = mon->spi;
++
++      if (!spi) {
++              printk (KERN_ERR "mon_status_request() - FAIL - spi is 0.\n");
++              err = 1;
++      }
++      else {
++
++        if (down_interruptible (&mon->sem))
++          return -ERESTARTSYS;
++              //Read the avr status register
++
++        switch (mon->state) {
++
++
++        case MON_STATE_IDLE:
++
++          avr_read_status (spi, &mon->regs);
++
++                      //update md status
++          md_update (mon->md, mon->regs.status);
++          break;
++
++        case MON_STATE_MOTION_ONLY:
++
++          avr_read_status (spi, &mon->regs);
++
++          //update md status
++          md_update (mon->md, mon->regs.status);
++          break;
++
++
++        case MON_STATE_ACC_ONLY:
++
++          avr_read_status_and_adc (spi, &mon->regs);
++
++          cque_write (mon->acc->cque, &mon->regs.adc0h);
++          if (cque_is_ready_for_read (mon->acc->cque) ) {
++            wake_up_interruptible (&mon->acc->read_wait_queue);
++          }
++          break;
++
++        case MON_STATE_MOTION_AND_ACC:
++
++          avr_read_status (spi, &mon->regs);
++
++          //update md status
++          md_update (mon->md, mon->regs.status);
++
++          // adc complete status ?
++          if (mon->regs.status & 0x20) {
++            avr_read_adc (spi, &mon->regs);
++            cque_write (mon->acc->cque, &mon->regs.adc0h);
++            if (cque_is_ready_for_read (mon->acc->cque) ) {
++              wake_up_interruptible (&mon->acc->read_wait_queue);
++            }
++          }
++
++          break;
++
++        default:
++          printk (KERN_ERR "mon_work_handler() - invalid state.\n");
++
++        }
++        up (&mon->sem);
++      }
++      return err;
++}
++
++// work handler
++static void mon_work_handler (struct work_struct * work)
++{
++
++      struct mon *mon = work_to_mon(work);
++
++      if ( !mon_status_request(mon) ) {
++              enable_irq (mon->irq);
++      }
++      return;
++}
++
++// interrupt handler
++static irqreturn_t mon_irq_handler(int irq, void *dummy)
++{
++      struct mon *mon = dummy;
++
++      disable_irq_nosync(irq);
++      schedule_work (&mon->work_item);
++      return IRQ_HANDLED;
++}
++
++int mon_probe (struct mon *mon, const char *name, int irq, struct md *md, struct acc *acc)
++{
++      int err;
++      struct bmi_device *bdev;
++      unsigned long speed;
++
++      unsigned char mode;
++      unsigned char bits_per_word;
++
++      err = 1;
++      if (mon) {
++              bdev = mdacc_get_bdev_mon (mon);
++              speed = 250000;
++//            speed = 125000;
++              mode = 1;
++              bits_per_word = 8;
++
++              strcpy(mon->mon_spi_info.modalias, "bug_mdacc_spi");
++              mon->mon_spi_info.max_speed_hz = speed;
++              mon->mon_spi_info.bus_num = bdev->slot->spi_bus_num;
++              mon->mon_spi_info.chip_select = bdev->slot->spi_cs;
++              mon->mon_spi_info.mode = mode;
++              mon->spi = spi_new_device(spi_busnum_to_master(mon->mon_spi_info.bus_num), &mon->mon_spi_info) ;
++              if (!mon->spi) {
++                      printk (KERN_ERR "mon_probe() - bmi_device_spi_setup() failed.\n");
++                      goto exit;
++              }
++
++              mon->irq = irq;
++              mon->md = md;
++              mon->acc = acc;
++              init_MUTEX (&mon->sem);
++              mon->state = MON_STATE_IDLE;
++              memset (&mon->regs, 0, sizeof (struct avr_regs) );
++
++              mon->workqueue = create_singlethread_workqueue (name);
++              if (!mon->workqueue) {
++                      printk (KERN_ERR "mon_probe() - create_singlethread_workqueue() failed.\n");
++                      goto exit;
++              }
++              INIT_WORK(&mon->work_item, mon_work_handler);
++
++              if (request_irq(irq, &mon_irq_handler, 0, name, mon)) {
++                      printk (KERN_ERR "mon_probe() - request_irq (irq = %d) failed.\n", irq);
++                      destroy_workqueue( mon->workqueue );
++                      goto exit;
++              }
++              err = 0;
++      }
++exit:
++      return err;
++}
++
++
++void mon_remove (struct mon *mon)
++{
++      if (mon) {
++              free_irq(mon->irq, mon);
++              destroy_workqueue( mon->workqueue );
++              spi_unregister_device(mon->spi);
++      }
++              return;
++}
++
++
+--- /dev/null
++++ git/drivers/bmi/pims/mdacc/mon.h
+@@ -0,0 +1,61 @@
++/*
++ * Copyright 2008 EnCADIS Designs, Inc. All Rights Reserved.
++ * Copyright 2008 Bug-Labs, Inc. All Rights Reserved.
++ *
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*-----------------------------------------------------------------------------
++ *
++ *      Part of BMI Motion Detector Accelerometer (MDACC) Kernel Module
++ *
++ *-----------------------------------------------------------------------------
++ */
++
++#ifndef MDACC_MON_H
++#define MDACC_MON_H
++
++#include "avr.h"
++#include "md.h"
++#include "acc.h"
++
++#include <linux/workqueue.h>
++
++struct mon
++{
++      int irq;
++      struct md *md;
++      struct acc *acc;
++  struct spi_device *spi;
++  struct spi_board_info mon_spi_info;
++      struct semaphore sem;
++      int state;
++      struct avr_regs regs;
++      struct workqueue_struct *workqueue;
++      struct work_struct work_item;
++};
++
++struct md;
++struct acc;
++
++int  mon_probe (struct mon *mon, const char *name, int irq, struct md *md, struct acc *acc);
++void mon_remove (struct mon *mon);
++
++int mon_start_motion (struct mon *mon);
++int mon_stop_motion (struct mon *mon);
++
++int mon_set_config_accel (struct mon *mon, struct mdacc_accel_config *cfg);
++int mon_get_config_accel (struct mon *mon, struct mdacc_accel_config *cfg);
++int mon_start_accel (struct mon *mon);
++int mon_stop_accel (struct mon *mon);
++
++int mon_status_request (struct mon *mon);
++
++
++#endif
++
+--- /dev/null
++++ git/drivers/bmi/pims/projector/Makefile
+@@ -0,0 +1,7 @@
++#\r
++# BMI PIMS\r
++#\r
++\r
++obj-$(CONFIG_VIDEO_BMI_PROJECTOR)     += bmi_projector_core.o\r
++bmi_projector_core-objs := bmi_projector.o ch7024.o\r
++\r
+--- /dev/null
++++ git/drivers/bmi/pims/projector/bmi_projector.c
+@@ -0,0 +1,674 @@
++/*\r
++ *    bmi_projector.c\r
++ *\r
++ *    BMI PROJECTOR device driver\r
++ *\r
++ *              Derived from: bmi_lcd.c\r
++ */\r
++\r
++/*\r
++ * The code contained herein is licensed under the GNU General Public\r
++ * License. You may obtain a copy of the GNU General Public License\r
++ * Version 2 or later at the following locations:\r
++ *\r
++ * http://www.opensource.org/licenses/gpl-license.html\r
++ * http://www.gnu.org/copyleft/gpl.html\r
++ */\r
++\r
++/*\r
++ * Include files\r
++ */\r
++\r
++#include <linux/input.h>\r
++#include <linux/kernel.h>\r
++#include <linux/major.h>\r
++#include <linux/module.h>\r
++#include <linux/fs.h>\r
++#include <linux/cdev.h>\r
++#include <linux/delay.h>\r
++#include <linux/jiffies.h>\r
++#include <linux/timer.h>\r
++#include <linux/i2c.h>\r
++#include <asm/uaccess.h>\r
++#include <linux/device.h>\r
++#include <linux/interrupt.h>\r
++#include <linux/miscdevice.h>\r
++\r
++#include <asm/irq.h>\r
++#include <asm/io.h>\r
++#include <asm/system.h>\r
++#include <mach/mxc_i2c.h>\r
++#include <mach/mx31bug_cpld.h>\r
++#include <linux/bmi.h>\r
++#include <linux/bmi/bmi-control.h>\r
++#include <linux/bmi/bmi-slot.h>\r
++#include <linux/bmi/bmi_projector.h>\r
++#include <mach/ipu.h>\r
++\r
++#include "ch7024.h"\r
++\r
++#define DEBUG_PROJECTOR\r
++#undef DEBUG_PROJECTOR\r
++\r
++#define BMIPROJECTOR_VERSION  "1.0"           // driver version\r
++#define BMI_SLOT_NUM          (4)             // number of BMI slots\r
++#define MAX_STRG              (40)            // Max string buffer size\r
++#define       VSYNC_DISABLE           0x0\r
++#define       VSYNC_ENABLE            0x1\r
++#define PROJ_DEF_MODE         0x09            // Projector default mode of operation\r
++\r
++      // projector\r
++struct projector_interface {\r
++      char                    projector_type[MAX_STRG];       // text description of PROJECTOR type\r
++      u8                      suspended;              // power management state\r
++      u8                      rotation;               // screen rotation\r
++      u8                      disp;                   // display number (DISP0 or DISP1)\r
++      u8                      addr_mode;              // display addressing mode\r
++      u8                      vsync_mode;             // VSYNC signal enable (VSYNC_ENABLE | VSYNC_DISABLE)\r
++      u8                      bus_if_type;            // bus type (XY | FullWoBE | FullWithBE)\r
++      ipu_adc_sig_cfg_t       adc_sig;                // IPU ADC set-up parameters\r
++      ipu_di_signal_cfg_t     di_sig;                 // IPU DI set-up parameters\r
++};\r
++\r
++static struct projector_interface projector_interface = {\r
++      .projector_type = "MXCFB_PROJECTOR",\r
++      .suspended = 0,\r
++      .rotation = IPU_ROTATE_NONE,\r
++      .disp = DISP0,\r
++      .vsync_mode = VSYNC_DISABLE,\r
++      .bus_if_type = XY,\r
++      .adc_sig = { 0, 0, 0, 0, 0, 0, 0, 0, IPU_ADC_BURST_WCS, IPU_ADC_IFC_MODE_SYS80_TYPE2,\r
++                      16, 0, 0, IPU_ADC_SER_NO_RW },\r
++      .di_sig = { 0,0,0,0,0,0,0,0 },          //pjg - reserved for multiple Projector driver\r
++};\r
++\r
++extern void projector_config(int disp);\r
++extern int projector_disp_on(int disp);\r
++extern int projector_disp_regset(int disp, unsigned short reg, unsigned short val);\r
++\r
++struct bmi_projector;\r
++static int disp_mode_reg = 0x09;  // Bit 3 of GPIO control register should always be maintained high\r
++//static int proj_mode = 0x1;  // Bit 3 of GPIO control register should always be maintained high\r
++\r
++struct bmi_projector_ops {\r
++      void *(*config) (int disp);                             // Projector configuration/initialization\r
++      void *(*reset) (int slot);                              // Projector reset\r
++      int *(*suspend) (struct bmi_projector *bprojector);     // power management\r
++      int *(*resume) (struct bmi_projector *bprojector);      // power management\r
++      int *(*disp_on) (int disp);                             // display on\r
++      int *(*disp_off) (int disp);                            // display off\r
++      int (*activate) (struct bmi_projector *projector, int slot);    // enable Projector\r
++      int (*deactivate) (struct bmi_projector *projector, int slot);  // disable Projector\r
++};\r
++\r
++struct bmi_projector_ops bmi_projector_ops;\r
++\r
++struct bmi_projector {\r
++      struct projector_interface interface;           // pointer to this struct is returned by config()\r
++      struct bmi_projector_ops projector_ops;         // function pointers\r
++};\r
++\r
++static struct bmi_projector bmi_projector;\r
++\r
++int register_bmi_projector(struct bmi_projector *bprojector, int slot);\r
++int unregister_bmi_projector(struct bmi_projector *bprojector, int slot);\r
++\r
++      // private device structure\r
++struct pbmi_projector\r
++{\r
++      int                     open_flag;                              // force single open\r
++      unsigned int            projector_cnt;                          // number of Projector's present\r
++      unsigned int            active;                                 // indication of Projector's presence\r
++      unsigned int            activated[BMI_SLOT_NUM];                // indication of Projector's presence\r
++      int                     proj_mode[BMI_SLOT_NUM];                // Indicate the state of projector on the slot\r
++      //int                   disp_mode_reg[BMI_SLOT_NUM];\r
++\r
++      struct bmi_projector            *bprojector[BMI_SLOT_NUM];      // BMI Projector structure - placeholder for multiple display types\r
++      struct bmi_device       *bdev[BMI_SLOT_NUM];                    // BMI device per slot\r
++      unsigned int            interrupt[BMI_SLOT_NUM];                // input device interrupt handlers\r
++      char                    int_name[MAX_STRG];                     // interrupt name\r
++};\r
++\r
++static struct pbmi_projector pbmi_projector;  // Projector device sructure\r
++\r
++/*\r
++ *    BMI set up\r
++ */\r
++\r
++      // BMI device ID table\r
++static struct bmi_device_id bmi_projector_tbl[] =\r
++{\r
++      {\r
++              .match_flags = BMI_DEVICE_ID_MATCH_VENDOR | BMI_DEVICE_ID_MATCH_PRODUCT,\r
++              .vendor   = BMI_VENDOR_BUG_LABS,\r
++              .product  = BMI_PRODUCT_PROJECTOR,\r
++              .revision = BMI_ANY,\r
++      },\r
++      { 0, },                                   /* terminate list */\r
++};\r
++\r
++MODULE_DEVICE_TABLE(bmi, bmi_projector_tbl);\r
++\r
++int   bmi_projector_probe(struct bmi_device *bdev);\r
++void  bmi_projector_remove(struct bmi_device *bdev);\r
++\r
++// BMI driver structure\r
++static struct bmi_driver bmi_projector_driver =\r
++{\r
++      .name = "bmi_projector",\r
++      .id_table = bmi_projector_tbl,\r
++      .probe   = bmi_projector_probe,\r
++      .remove  = bmi_projector_remove,\r
++};\r
++\r
++void bmi_projector_config(struct bmi_projector *projector, int disp);\r
++\r
++      // probe\r
++int bmi_projector_probe(struct bmi_device *bdev)\r
++{\r
++      int slot = bdev->info->slot;\r
++      struct i2c_adapter *adap;\r
++      struct bmi_projector *projector;\r
++      /*int first_time = 1;*/\r
++\r
++      printk(KERN_INFO "bmi_projector.c: probe slot %d\n", slot);\r
++\r
++      // check for opposite side already active\r
++      switch(slot) {  // opposite side\r
++              case 0:\r
++                      if(pbmi_projector.activated[2] == 1) {\r
++                              printk(KERN_INFO "bmi_projector.c: probe slot %d not allowed (slot 2 already active)\n", slot);\r
++                              bmi_slot_power_off(0);\r
++                              pbmi_projector.bdev[0] = bdev;\r
++                              return 0;\r
++                      }\r
++                      break;\r
++              case 1:\r
++                      if(pbmi_projector.activated[3] == 1) {\r
++                              printk(KERN_INFO "bmi_projector.c: probe slot %d not allowed (slot 3 already active)\n", slot);\r
++                              bmi_slot_power_off(1);\r
++                              pbmi_projector.bdev[1] = bdev;\r
++                              return 0;\r
++                      }\r
++                      break;\r
++              case 2:\r
++                      if(pbmi_projector.activated[0] == 1) {\r
++                              printk(KERN_INFO "bmi_projector.c: probe slot %d not allowed (slot 0 already active)\n", slot);\r
++                              bmi_slot_power_off(2);\r
++                              pbmi_projector.bdev[2] = bdev;\r
++                              return 0;\r
++                      }\r
++                      break;\r
++              case 3:\r
++                      if(pbmi_projector.activated[1] == 1) {\r
++                              printk(KERN_INFO "bmi_projector.c: probe slot %d not allowed (slot 1 already active)\n", slot);\r
++                              bmi_slot_power_off(3);\r
++                              pbmi_projector.bdev[3] = bdev;\r
++                              return 0;\r
++                      }\r
++                      break;\r
++      }\r
++\r
++      adap = &bdev->adap;\r
++\r
++//    bmi_slot_power_on(slot);\r
++\r
++      mdelay(500);\r
++\r
++      if (!ch7024_detect (adap))\r
++      {\r
++              /* setup for NTSC */\r
++              ch7024_setup (adap, PROJOUT_FMT_NTSC);\r
++#ifdef DEBUG_PROJECTOR\r
++              printk ("\nFound encoder on slot %d \n", slot);\r
++#endif\r
++              ch7024_enable (adap);\r
++      }\r
++      else\r
++      {\r
++              printk ("\nError! Failed to detect encoder chip\n");\r
++              return 0;\r
++      }\r
++\r
++      // reset serial link (master)\r
++      if((slot == 0) || (slot == 2)) {\r
++        bmi_lcd_inactive(0);                  // We are using Same CPLD pins for projector\r
++      } else {\r
++        bmi_lcd_inactive(1);\r
++      }\r
++\r
++      // FPGA PROG_0 - Active low signal\r
++      bmi_set_module_gpio_data(slot, 0, 0);\r
++      bmi_set_module_gpio_dir(slot, 0, BMI_GPIO_OUT);\r
++\r
++      /* Reset the FPGA */\r
++      bmi_set_module_gpio_data(slot, 1, 1);\r
++      bmi_set_module_gpio_dir(slot, 0, BMI_GPIO_OUT);\r
++      mdelay(100);\r
++      bmi_set_module_gpio_data(slot, 1, 0);\r
++\r
++      // unreset serial link (master)\r
++      if((slot == 0) || (slot == 2)) {\r
++              mdelay(2);\r
++              bmi_lcd_active(0, 0x0, LCD_MODE_I80);\r
++      } else {\r
++              mdelay(2);\r
++              bmi_lcd_active(1, 0x0, LCD_MODE_I80);\r
++      }\r
++\r
++\r
++      // set up bdev/pbmi_projector pointers\r
++      bmi_device_set_drvdata(bdev, &pbmi_projector);\r
++      pbmi_projector.bdev[slot] = bdev;\r
++\r
++      // complete pbmi_projector set-up\r
++      pbmi_projector.projector_cnt++;\r
++      pbmi_projector.active = 1;\r
++      pbmi_projector.activated[slot] = 1;\r
++      pbmi_projector.proj_mode[slot] = 1;\r
++\r
++      mdelay(100);\r
++\r
++      projector = pbmi_projector.bprojector[slot];\r
++      if((slot == 0) || (slot == 2)) {\r
++              mdelay(2);\r
++              bmi_projector_config(projector, 0);\r
++              mdelay(2);\r
++      } else {\r
++              mdelay(2);\r
++              bmi_projector_config(projector, 1);\r
++              mdelay(2);\r
++      }\r
++\r
++      // Turn on Projctor\r
++      disp_mode_reg = PROJ_DEF_MODE;\r
++        projector_disp_regset((slot & 0x1), 0x1, disp_mode_reg);\r
++              // check GPIO status\r
++      printk(KERN_INFO "bmi_projector.c: slot %d gpio = %x\n", slot, bmi_read_gpio_data_reg(slot));\r
++      printk(KERN_INFO "bmi_projector.c: Projector count = %d\n", pbmi_projector.projector_cnt);\r
++\r
++      return 0;\r
++}\r
++\r
++      // remove\r
++void bmi_projector_remove(struct bmi_device *bdev)\r
++{\r
++      int slot = bdev->info->slot;\r
++\r
++      if(pbmi_projector.activated[slot] == 0)\r
++          return;\r
++\r
++      bmi_set_module_gpio_dir (slot, 3, BMI_GPIO_IN);\r
++      bmi_set_module_gpio_dir (slot, 2, BMI_GPIO_IN);\r
++      bmi_set_module_gpio_dir (slot, 1, BMI_GPIO_IN);\r
++      bmi_set_module_gpio_dir (slot, 0, BMI_GPIO_IN);\r
++\r
++              //de-attach driver-specific struct from bmi_device structure\r
++      bmi_device_set_drvdata (bdev, NULL);\r
++\r
++              // deactivate\r
++      pbmi_projector.activated[slot] = 0;\r
++      pbmi_projector.bdev[slot] = 0;\r
++      pbmi_projector.projector_cnt--;\r
++\r
++      if((pbmi_projector.activated[0] == 0) && (pbmi_projector.activated[2] == 0)) {\r
++              bmi_lcd_inactive(0); // disable serializer\r
++      }\r
++\r
++      if((pbmi_projector.activated[1] == 0) && (pbmi_projector.activated[3] == 0)) {\r
++              bmi_lcd_inactive(1); // disable serializer\r
++      }\r
++\r
++      if((pbmi_projector.activated[0] == 0) && (pbmi_projector.activated[1] == 0) &&\r
++              (pbmi_projector.activated[2] == 0) && (pbmi_projector.activated[3] == 0)) {\r
++              pbmi_projector.active = -1;\r
++      }\r
++\r
++              // enable Projector on opposite side\r
++      switch(slot) {\r
++              case 0:\r
++                      if(pbmi_projector.bdev[2] != 0)\r
++                              bmi_projector_probe(pbmi_projector.bdev[2]);\r
++                      break;\r
++              case 1:\r
++                      if(pbmi_projector.bdev[3] != 0)\r
++                              bmi_projector_probe(pbmi_projector.bdev[3]);\r
++                      break;\r
++              case 2:\r
++                      if(pbmi_projector.bdev[0] != 0)\r
++                              bmi_projector_probe(pbmi_projector.bdev[0]);\r
++                      break;\r
++              case 3:\r
++                      if(pbmi_projector.bdev[1] != 0)\r
++                              bmi_projector_probe(pbmi_projector.bdev[1]);\r
++                      break;\r
++      }\r
++\r
++      printk(KERN_INFO "bmi_projector.c: projector count = %d\n", pbmi_projector.projector_cnt);\r
++\r
++      return;\r
++}\r
++\r
++/*\r
++ * control device operations\r
++ */\r
++\r
++/*\r
++ * control device operations\r
++ */\r
++\r
++// open\r
++int cntl_open(struct inode *inode, struct file *filp)\r
++{\r
++      if(pbmi_projector.open_flag) {\r
++              return - EBUSY;\r
++      }\r
++      pbmi_projector.open_flag = 1;\r
++      filp->private_data = &pbmi_projector;\r
++      return 0;\r
++}\r
++\r
++// release\r
++int cntl_release(struct inode *inode, struct file *filp)\r
++{\r
++      pbmi_projector.open_flag = 0;\r
++      return 0;\r
++}\r
++\r
++// ioctl\r
++int cntl_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,\r
++                 unsigned long arg)\r
++{\r
++      struct i2c_adapter *adap;\r
++      int slot = (__user arg) & 0xF;\r
++      int disp = 0;\r
++      int ret = 0;\r
++\r
++              // error if no projector active.\r
++      if(pbmi_projector.active == -1)\r
++              return -ENODEV;\r
++\r
++              // error if slot invalid\r
++      if((slot < CPLD_M1) || (slot > CPLD_M4))\r
++              return -ENODEV;\r
++\r
++      disp = slot & 0x1;  // disp=0 for Slot 0 and 2, disp=1 for 1 and 3\r
++#ifdef DEBUG_PROJECTOR\r
++      printk (KERN_INFO "Slot No is:%d\n", slot);\r
++      printk (KERN_INFO "Disp No is:%d\n", disp);\r
++#endif\r
++\r
++              // error if no projector in chosen slot\r
++      if(pbmi_projector.bdev[slot] == 0)\r
++              return -ENODEV;\r
++\r
++              // i2c adapter\r
++      adap = &pbmi_projector.bdev[slot]->adap;\r
++\r
++      if( (cmd != BMI_PROJECTOR_ON) && (pbmi_projector.proj_mode[slot]/*proj_mode*/ == 0) )\r
++      {\r
++              printk(KERN_ERR "Project is in OFF state !!!\n");\r
++              return -EINVAL;\r
++      }\r
++\r
++              // ioctl's\r
++      switch (cmd) {\r
++              case BMI_PROJECTOR_ON:\r
++                      {\r
++                              printk(KERN_INFO "BMI_PROJECTOR turning on\n");\r
++                              disp_mode_reg &= ~(0x3);\r
++                              disp_mode_reg |= 0x1;\r
++                              ch7024_enable(adap);\r
++                              projector_disp_regset(disp, 0x1, disp_mode_reg);\r
++                              mdelay(100);\r
++                              projector_disp_regset(disp, 0x0, 0x1);\r
++                              //proj_mode = 0x1;\r
++                              pbmi_projector.proj_mode[slot] = 0x1;\r
++                      }\r
++                      break;\r
++\r
++              case BMI_PROJECTOR_MODE:\r
++                      {\r
++                              int mode = ((__user arg) & 0xF0) >> 4;\r
++                              printk(KERN_INFO "BMI_PROJECTOR setting mode to 0x%x \n",mode);\r
++\r
++                              disp_mode_reg &= ~(0x3);\r
++                              switch(mode)\r
++                              {\r
++                                      case PROJECTOR_ECONOMY_MODE:\r
++                                              disp_mode_reg |= 0x2;  //Economy mode\r
++                                              break;\r
++                                      case PROJECTOR_BRIGHT_MODE:\r
++                                              disp_mode_reg |= 0x1;\r
++                                              break;\r
++                                      default:\r
++                                              printk(KERN_ERR "Invalid Mode\n");\r
++                                              return -EINVAL;\r
++                              }\r
++\r
++                              projector_disp_regset(disp, 0x1, disp_mode_reg);\r
++                      }\r
++                      break;\r
++\r
++              case BMI_PROJECTOR_OFF:\r
++                      {\r
++                              disp_mode_reg &= ~(0x3);\r
++                              disp_mode_reg |= 0x3;\r
++                              ch7024_disable(adap);\r
++#ifdef DEBUG_PROJECTOR\r
++                              printk (KERN_INFO "Mode reg value is:0x%X\n", disp_mode_reg);\r
++#endif\r
++                              projector_disp_regset(disp, 0x1, disp_mode_reg);\r
++                              //proj_mode = 0x0;\r
++                              pbmi_projector.proj_mode[slot] = 0x0;\r
++                      }\r
++                      break;\r
++\r
++              case BMI_PROJECTOR_BATTERY:\r
++                      {\r
++                              printk(KERN_INFO "BMI_PROJECTOR Staring Battery Charger for BUG\n");\r
++                              ch7024_disable(adap);\r
++                              projector_disp_regset(disp, 0x1, 0xF);\r
++                              //proj_mode = 0x0;\r
++                              pbmi_projector.proj_mode[slot] = 0x0;\r
++                      }\r
++\r
++                      break;\r
++              case BMI_PROJECTOR_HUE:\r
++                      {\r
++                              int val = ((__user arg) >> 8) & 0xff;\r
++                              printk(KERN_INFO "BMI_PROJECTOR setting Hue to 0x%x\n",val);\r
++                              ret = ch7024_set_hue(adap, val);\r
++                      }\r
++                      break;\r
++              case BMI_PROJECTOR_SATURATION:\r
++                      {\r
++                              int val = ((__user arg) >> 8) & 0xff;\r
++                              printk(KERN_INFO "BMI_PROJECTOR setting Saturation to 0x%x\n",val);\r
++                              ret = ch7024_set_sat(adap, val);\r
++                      }\r
++                      break;\r
++              case BMI_PROJECTOR_CONTRAST:\r
++                      {\r
++                              int val = ((__user arg) >> 8) & 0xff;\r
++                              printk(KERN_INFO "BMI_PROJECTOR setting Contrast to 0x%x\n",val);\r
++                              ret = ch7024_set_cont(adap, val);\r
++                      }\r
++                      break;\r
++              case BMI_PROJECTOR_BRIGHTNESS:\r
++                      {\r
++                              int val = ((__user arg) >> 8) & 0xff;\r
++                              printk(KERN_INFO "BMI_PROJECTOR setting Brightness to 0x%x\n",val);\r
++                              ret = ch7024_set_bright(adap, val);\r
++                      }\r
++                      break;\r
++              case BMI_PROJECTOR_SHARPNESS:\r
++                      {\r
++                              int val = ((__user arg) >> 8) & 0xff;\r
++                              printk(KERN_INFO "BMI_PROJECTOR setting Sharpness to 0x%x\n",val);\r
++                              ret = ch7024_set_sharp(adap, val);\r
++                      }\r
++                      break;\r
++              default:\r
++                      return -ENOTTY;\r
++      }\r
++      return ret;\r
++}\r
++\r
++      // control file operations\r
++struct file_operations cntl_fops = {\r
++      .owner = THIS_MODULE,\r
++      .ioctl = cntl_ioctl,\r
++      .open = cntl_open,\r
++      .release = cntl_release,\r
++};\r
++\r
++      // BMI Projector fops\r
++void bmi_projector_config(struct bmi_projector *projector, int disp)\r
++{\r
++      if(pbmi_projector.active == -1) {\r
++              return;\r
++      }\r
++\r
++      if((projector) && (projector->projector_ops.config)) {\r
++              projector->projector_ops.config(disp);\r
++      }\r
++}\r
++\r
++void bmi_projector_reset(struct bmi_projector *projector, int slot)\r
++{\r
++      if(pbmi_projector.active == -1) {\r
++              return;\r
++      }\r
++\r
++      if((projector) && (projector->projector_ops.reset)) {\r
++              projector->projector_ops.reset(slot);\r
++      }\r
++}\r
++\r
++int register_bmi_projector(struct bmi_projector *projector, int slot) //pjg - placeholder for multiple Projector types\r
++{\r
++      if(!projector) {\r
++              return -1;\r
++      }\r
++      if((slot < 0) || (slot > 3)) {\r
++              return -1;\r
++      }\r
++      if(pbmi_projector.bprojector[slot]) {\r
++              return -1;\r
++      }\r
++      else {\r
++              pbmi_projector.bprojector[slot] = projector;\r
++      }\r
++\r
++      if(projector->projector_ops.activate) {\r
++              projector->projector_ops.activate(projector, slot);\r
++      }\r
++\r
++      return 0;\r
++}\r
++\r
++int unregister_bmi_projector(struct bmi_projector *projector, int slot)       //pjg - placeholder for multiple projector types\r
++{\r
++      if (!projector) {\r
++              return -1;\r
++      }\r
++      if ((slot < 0) || (slot > 3)) {\r
++              return -1;\r
++      }\r
++      if (pbmi_projector.bprojector[slot] != projector) {\r
++              return -1;\r
++      }\r
++      else {\r
++              pbmi_projector.bprojector [slot] = 0;\r
++              projector->projector_ops.deactivate(projector, slot);\r
++      }\r
++      return 0;\r
++}\r
++\r
++static struct miscdevice cntl_dev = {\r
++      MISC_DYNAMIC_MINOR,\r
++      "bmi_projector",\r
++      &cntl_fops\r
++};\r
++\r
++static __init int bmi_projector_init(void)\r
++{\r
++      int rc = 0;\r
++\r
++              // No projector is active.\r
++      pbmi_projector.active = -1;\r
++      pbmi_projector.activated[0] = 0;\r
++      pbmi_projector.activated[1] = 0;\r
++      pbmi_projector.activated[2] = 0;\r
++      pbmi_projector.activated[3] = 0;\r
++      pbmi_projector.proj_mode[0] = 0;\r
++      pbmi_projector.proj_mode[1] = 0;\r
++      pbmi_projector.proj_mode[2] = 0;\r
++      pbmi_projector.proj_mode[3] = 0;\r
++\r
++              // set up control character device - bmi_projector_control\r
++      rc = misc_register(&cntl_dev);\r
++      if(rc) {\r
++              printk(KERN_ERR "bmi_projector.c: Can't allocate bmi_projector_control device\n");\r
++              return rc;\r
++      }\r
++\r
++      pbmi_projector.projector_cnt = 0;\r
++\r
++              // hardware specfic set-up\r
++      bmi_projector.interface = projector_interface,\r
++      bmi_projector_ops.config = (void(*)) &projector_config;\r
++      bmi_projector_ops.reset = NULL; //pjg - placeholder for multiple projector hardware types\r
++      bmi_projector_ops.suspend = NULL;       //pjg - placeholder for multiple projector hardware types\r
++      bmi_projector_ops.resume = NULL;        //pjg - placeholder for multiple projector hardware types\r
++      bmi_projector_ops.disp_on = NULL;       //pjg - placeholder for multiple projector hardware types\r
++      bmi_projector_ops.disp_off = NULL;      //pjg - placeholder for multiple projector hardware types\r
++      bmi_projector_ops.activate = NULL;      //pjg - placeholder for multiple Projector hardware types\r
++      bmi_projector_ops.deactivate = NULL;    //pjg - placeholder for multiple Projector hardware types\r
++      bmi_projector.projector_ops = bmi_projector_ops;\r
++      pbmi_projector.bprojector[0] = &bmi_projector;\r
++      pbmi_projector.bprojector[1] = &bmi_projector;\r
++      pbmi_projector.bprojector[2] = &bmi_projector;\r
++      pbmi_projector.bprojector[3] = &bmi_projector;\r
++\r
++      // register with BMI\r
++      rc = bmi_register_driver(&bmi_projector_driver);\r
++      if(rc) {\r
++              printk(KERN_ERR "bmi_projector.c: Can't register bmi_projector_driver\n");\r
++\r
++              misc_deregister(&cntl_dev);\r
++\r
++              return rc;\r
++      }\r
++\r
++      printk("bmi_projector.c: BMI_Projector Driver v%s \n", BMIPROJECTOR_VERSION);\r
++\r
++      return 0;\r
++}\r
++\r
++static void __exit bmi_projector_clean(void)\r
++{\r
++\r
++              // remove control device\r
++      misc_deregister(&cntl_dev);\r
++\r
++              // remove bmi driver\r
++      bmi_unregister_driver(&bmi_projector_driver);\r
++\r
++        return;\r
++}\r
++\r
++module_init(bmi_projector_init);\r
++module_exit(bmi_projector_clean);\r
++\r
++// Exported symbols\r
++EXPORT_SYMBOL(register_bmi_projector);\r
++EXPORT_SYMBOL(unregister_bmi_projector);\r
++\r
++\r
++MODULE_AUTHOR("Suresh Rao");\r
++MODULE_DESCRIPTION("BMI projector device driver");\r
++MODULE_SUPPORTED_DEVICE("bmi_projector_control");\r
++MODULE_LICENSE("GPL");\r
++\r
+--- /dev/null
++++ git/drivers/bmi/pims/projector/ch7024.c
+@@ -0,0 +1,476 @@
++/*\r
++ * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved.\r
++ */\r
++\r
++/*\r
++ * The code contained herein is licensed under the GNU General Public\r
++ * License. You may obtain a copy of the GNU General Public License\r
++ * Version 2 or later at the following locations:\r
++ *\r
++ * http://www.opensource.org/licenses/gpl-license.html\r
++ * http://www.gnu.org/copyleft/gpl.html\r
++ */\r
++\r
++ /*!\r
++  * @file ch7024.c\r
++  * @brief Driver for CH7024 TV encoder\r
++  *\r
++  * @ingroup Framebuffer\r
++  */\r
++//#define DEBUG\r
++#include <linux/kernel.h>\r
++#include <linux/module.h>\r
++#include <linux/init.h>\r
++#include <linux/delay.h>\r
++#include <linux/i2c.h>\r
++#include <asm/uaccess.h>\r
++\r
++#include "ch7024.h"\r
++\r
++#define DEBUG_CH7024\r
++\r
++static int ch7024_found = 0;\r
++static struct i2c_adapter *ch7024_adap = NULL;\r
++\r
++static int i2c_ch7024_client_xfer( char *reg, int reg_len, char *buf, int num,\r
++                                int tran_flag)\r
++{\r
++      struct i2c_msg msg[2];\r
++      int ret;\r
++      if ((ch7024_adap == NULL))\r
++              {\r
++              printk (KERN_ERR "ch7024_adap is NULL\n");\r
++              return -1;\r
++              }\r
++      msg[0].addr = CH7024_I2C_ADDR;\r
++      msg[0].len = reg_len;\r
++      msg[0].buf = reg;\r
++      msg[0].flags = tran_flag;\r
++      msg[0].flags &= ~I2C_M_RD;\r
++\r
++      msg[1].addr = CH7024_I2C_ADDR;\r
++      msg[1].len = num;\r
++      msg[1].buf = buf;\r
++\r
++      msg[1].flags = tran_flag;\r
++      if (tran_flag & I2C_M_RD) {\r
++              msg[1].flags |= I2C_M_RD;\r
++      } else {\r
++              msg[1].flags &= ~I2C_M_RD;\r
++      }\r
++\r
++      ret = i2c_transfer(ch7024_adap, msg, 2);\r
++      return ret;\r
++}\r
++\r
++static int bug_i2c_ch7024_polling_read(char *reg, int reg_len, char *buf, int num)\r
++{\r
++      return i2c_ch7024_client_xfer(reg, reg_len, buf, num,I2C_M_RD);\r
++}\r
++\r
++static int bug_i2c_ch7024_polling_write(char *reg, int reg_len, char *buf,\r
++                                      int num)\r
++{\r
++      return i2c_ch7024_client_xfer(reg, reg_len, buf, num, 0);\r
++\r
++}\r
++\r
++static int ch7024_read_reg(u32 reg, u32 * word, u32 len)\r
++{\r
++      int i;\r
++      u8 *wp = (u8 *) word;\r
++\r
++      *word = 0;\r
++\r
++      for (i = 0; i < len; i++) {\r
++              int ret = bug_i2c_ch7024_polling_read((char *)&reg, 1, wp, 1);\r
++              if (ret < 0)\r
++                      return ret;\r
++              wp++;\r
++              reg++;\r
++      }\r
++      return 0;\r
++}\r
++\r
++static int ch7024_write_reg(u32 reg, u32 word, u32 len)\r
++{\r
++      return bug_i2c_ch7024_polling_write((char *)&reg, 1, (u8 *) & word, len);\r
++}\r
++\r
++/**\r
++ * PAL B/D/G/H/K/I clock and timting structures\r
++ */\r
++static struct ch7024_clock ch7024_clk_pal = {\r
++      .A = 0x0,\r
++      .P = 0x36b00,\r
++      .N = 0x41eb00,\r
++      .T = 0x3f,\r
++      .PLLN1 = 0x0,\r
++      .PLLN2 = 0x1b,\r
++      .PLLN3 = 0x12,\r
++};\r
++\r
++static struct ch7024_input_timing ch7024_timing_pal = {\r
++      .HTI = 950,\r
++      .VTI = 560,\r
++      .HAI = 640,\r
++      .VAI = 480,\r
++      .HW = 60,\r
++      .HO = 250,\r
++      .VW = 40,\r
++      .VO = 40,\r
++      .VOS = CH7024_VOS_PAL_BDGHKI,\r
++};\r
++\r
++/**\r
++ * NTSC_M clock and timting structures\r
++ * TODO: change values to work well.\r
++ */\r
++static struct ch7024_clock ch7024_clk_ntsc = {\r
++      .A = 0x0,\r
++      .P = 0x2ac90,\r
++      .N = 0x36fc90,\r
++      .T = 0x3f,\r
++      .PLLN1 = 0x0,\r
++      .PLLN2 = 0x1b,\r
++      .PLLN3 = 0x12,\r
++};\r
++\r
++static struct ch7024_input_timing ch7024_timing_ntsc = {\r
++      .HTI = 801,\r
++      .VTI = 554,\r
++      .HAI = 640,\r
++      .VAI = 480,\r
++      .HW = 60,\r
++      .HO = 101,\r
++      .VW = 20,\r
++      .VO = 54,\r
++      .VOS = CH7024_VOS_NTSC_M,\r
++};\r
++\r
++/**\r
++ * ch7024_setup\r
++ * initial the CH7024 chipset by setting register\r
++ * @param:\r
++ *    vos: output video format\r
++ * @return:\r
++ *    0 successful\r
++ *    otherwise failed\r
++ */\r
++int ch7024_setup(struct i2c_adapter *adap,int vos)\r
++{\r
++      struct ch7024_input_timing *ch_timing;\r
++      struct ch7024_clock *ch_clk;\r
++#ifdef DEBUG_CH7024\r
++      int i, val;\r
++#endif\r
++      ch7024_adap = adap;\r
++#if 0\r
++      if (!ch7024_found) {\r
++              printk(KERN_ERR "CH7024: no such device to setup!\n");\r
++              return -ENODEV;\r
++      }\r
++#endif\r
++      /* select output video format */\r
++      if (vos == PROJOUT_FMT_PAL) {\r
++              ch_timing = &ch7024_timing_pal;\r
++              ch_clk = &ch7024_clk_pal;\r
++              pr_debug("CH7024: change to PAL video\n");\r
++      } else if (vos == PROJOUT_FMT_NTSC) {\r
++              ch_timing = &ch7024_timing_ntsc;\r
++              ch_clk = &ch7024_clk_ntsc;\r
++              pr_debug("CH7024: change to NTSC video\n");\r
++      } else if (vos == PROJOUT_FMT_QVGA) {\r
++                ch_timing = &ch7024_timing_ntsc;\r
++                ch_clk = &ch7024_clk_ntsc;\r
++                pr_debug("CH7024: change to NTSC video\n");\r
++        }\r
++        else {\r
++\r
++              pr_debug("CH7024: no such video format.\n");\r
++              return -EINVAL;\r
++      }\r
++      printk("Resetting Chrontel Card\n");\r
++      ch7024_write_reg(CH7024_POWER, 0x0C, 1);        /* power on, disable DAC */\r
++      ch7024_write_reg(CH7024_RESET, 0x00, 1);        /* Reset */\r
++      ch7024_write_reg(CH7024_RESET, 0x03, 1);        /* Reset */\r
++      mdelay(10);\r
++\r
++      ch7024_write_reg(CH7024_POWER, 0x0C, 1);        /* power on, disable DAC */\r
++      ch7024_write_reg(CH7024_XTAL, CH7024_XTAL_13MHZ, 1);    /* 13MHz cystal */\r
++      ch7024_write_reg(CH7024_SYNC, 0x0D, 1); /* Master mode, and TTL */\r
++      ch7024_write_reg(CH7024_IDF1, 0x00, 1);\r
++      ch7024_write_reg(CH7024_TVFILTER1, 0x00, 1);    /* set XCH=0 */\r
++\r
++      /* set input clock and divider */\r
++      /* set PLL */\r
++      ch7024_write_reg(CH7024_PLL1, ch_clk->PLLN1, 1);\r
++      ch7024_write_reg(CH7024_PLL2, ch_clk->PLLN2, 1);\r
++      ch7024_write_reg(CH7024_PLL3, ch_clk->PLLN3, 1);\r
++\r
++      /* set A register */\r
++      ch7024_write_reg(CH7024_PCLK_A1, 0x00, 1);\r
++      ch7024_write_reg(CH7024_PCLK_A2, 0x00, 1);\r
++      ch7024_write_reg(CH7024_PCLK_A3, 0x00, 1);\r
++      ch7024_write_reg(CH7024_PCLK_A4, 0x00, 1);\r
++      /* set P register */\r
++      ch7024_write_reg(CH7024_CLK_P1, (ch_clk->P >> 16) & 0xFF, 1);\r
++      ch7024_write_reg(CH7024_CLK_P2, (ch_clk->P >> 8) & 0xFF, 1);\r
++      ch7024_write_reg(CH7024_CLK_P3, ch_clk->P & 0xFF, 1);\r
++      /* set N register */\r
++      ch7024_write_reg(CH7024_CLK_N1, (ch_clk->N >> 16) & 0xFF, 1);\r
++      ch7024_write_reg(CH7024_CLK_N2, (ch_clk->N >> 8) & 0xFF, 1);\r
++      ch7024_write_reg(CH7024_CLK_N3, ch_clk->N & 0xFF, 1);\r
++      /* set T register */\r
++      ch7024_write_reg(CH7024_CLK_T, ch_clk->T & 0xFF, 1);\r
++\r
++      /* set sub-carrier frequency generation method */\r
++      ch7024_write_reg(CH7024_ACIV, 0x10, 1); /* ACIV = 1, automatical SCF */\r
++      /* TV out pattern and DAC switch */\r
++      ch7024_write_reg(CH7024_OUT_FMT, (0x10 | ch_timing->VOS) & 0xFF, 1);\r
++\r
++if (vos != PROJOUT_FMT_QVGA)\r
++{\r
++\r
++      /* input settings */\r
++      ch7024_write_reg(CH7024_IDF2, 0x033, 1);\r
++      /* HAI/HTI VAI */\r
++      ch7024_write_reg(CH7024_IN_TIMING1, ((ch_timing->HTI >> 5) & 0x38) |\r
++                       ((ch_timing->HAI >> 8) & 0x07), 1);\r
++      ch7024_write_reg(CH7024_IN_TIMING2, ch_timing->HAI & 0xFF, 1);\r
++      ch7024_write_reg(CH7024_IN_TIMING8, ch_timing->VAI & 0xFF, 1);\r
++      /* HTI VTI */\r
++      ch7024_write_reg(CH7024_IN_TIMING3, ch_timing->HTI & 0xFF, 1);\r
++      ch7024_write_reg(CH7024_IN_TIMING9, ch_timing->VTI & 0xFF, 1);\r
++      /* HW/HO(h) VW */\r
++      ch7024_write_reg(CH7024_IN_TIMING4, ((ch_timing->HW >> 5) & 0x18) |\r
++                       ((ch_timing->HO >> 8) & 0x7), 1);\r
++      ch7024_write_reg(CH7024_IN_TIMING6, ch_timing->HW & 0xFF, 1);\r
++      ch7024_write_reg(CH7024_IN_TIMING11, ch_timing->VW & 0x3F, 1);\r
++      /* HO(l) VO/VAI/VTI */\r
++      ch7024_write_reg(CH7024_IN_TIMING5, ch_timing->HO & 0xFF, 1);\r
++      ch7024_write_reg(CH7024_IN_TIMING7, ((ch_timing->VO >> 4) & 0x30) |\r
++                       ((ch_timing->VTI >> 6) & 0x0C) |\r
++                       ((ch_timing->VAI >> 8) & 0x03), 1);\r
++      ch7024_write_reg(CH7024_IN_TIMING10, ch_timing->VO & 0xFF, 1);\r
++\r
++}\r
++      /* adjust the brightness */\r
++      ch7024_write_reg(CH7024_TVBRI, 0x90, 1);\r
++\r
++      ch7024_write_reg(CH7024_OUT_TIMING1, 0x4, 1);\r
++      ch7024_write_reg(CH7024_OUT_TIMING2, 0xe0, 1);\r
++\r
++      if (vos == PROJOUT_FMT_PAL) {\r
++              ch7024_write_reg(CH7024_V_POS1, 0x03, 1);\r
++              ch7024_write_reg(CH7024_V_POS2, 0x7d, 1);\r
++      } else {\r
++              ch7024_write_reg(CH7024_V_POS1, 0x02, 1);\r
++              ch7024_write_reg(CH7024_V_POS2, 0x7b, 1);\r
++      }\r
++\r
++        /* Set up the sub carrier frequency */\r
++      if (vos == PROJOUT_FMT_PAL) {\r
++      }\r
++      else {\r
++      /* We have crystal of 13MHz */\r
++      ch7024_write_reg(CH7024_SC_FREQ4, 0x7E, 1);\r
++      ch7024_write_reg(CH7024_SC_FREQ3, 0xEA, 1);\r
++      ch7024_write_reg(CH7024_SC_FREQ2, 0x33, 1);\r
++      ch7024_write_reg(CH7024_SC_FREQ1, 0x02, 1);\r
++\r
++      }\r
++\r
++#ifdef DEBUG_CH7024\r
++      for (i = 0; i < CH7024_SC_FREQ4; i++) {\r
++\r
++              ch7024_read_reg(i, &val, 1);\r
++              pr_debug("CH7024, reg[0x%x] = %x\n", i, val);\r
++      }\r
++#endif\r
++      return 0;\r
++}\r
++\r
++/**\r
++ * ch7024_enable\r
++ * Enable the ch7024 Power to begin TV encoder\r
++ */\r
++void ch7024_enable(struct i2c_adapter *adap)\r
++{\r
++      ch7024_adap = adap;\r
++      if (ch7024_found) {\r
++              ch7024_write_reg(CH7024_POWER, 0x00, 1);\r
++              printk("CH7024 power on.\n");\r
++      }\r
++}\r
++\r
++/**\r
++ * ch7024_disable\r
++ * Disable the ch7024 Power to stop TV encoder\r
++ */\r
++void ch7024_disable(struct i2c_adapter *adap)\r
++{\r
++      ch7024_adap = adap;\r
++      if (ch7024_found) {\r
++              ch7024_write_reg(CH7024_POWER, 0x0D, 1);\r
++              printk("CH7024 power off.\n");\r
++      }\r
++}\r
++\r
++int ch7024_dump (struct i2c_adapter *adap)\r
++    {\r
++    int i;\r
++    u32 data;\r
++    ch7024_adap = adap;\r
++    for (i =0; i <= CH7024_SC_FREQ4; i++)\r
++        {\r
++        ch7024_read_reg(i, &data, 1);\r
++        printk ("Offset :0%X Value :0%X\n", i, data);\r
++        }\r
++    ch7024_read_reg(0x62, &data, 1);\r
++    printk ("Offset :0x62 Value :0%X\n", data);\r
++    ch7024_read_reg(0x63, &data, 1);\r
++    printk ("Offset :0x63 Value :0%X\n", data);\r
++    ch7024_read_reg(0x7E, &data, 1);\r
++    printk ("Offset :0x7E Value :0%X\n", data);\r
++    return 0;\r
++    }\r
++EXPORT_SYMBOL(ch7024_dump);\r
++\r
++int encoder_read_reg (struct i2c_adapter *adap, u32 offset, u32 *data)\r
++    {\r
++    int ret;\r
++    ch7024_adap = adap;\r
++    ret = ch7024_read_reg(offset, data, 1);\r
++    if (ret < 0)\r
++        {\r
++        printk ("Encoder read register failed at offset 0x%X\n", offset);\r
++        return ret;\r
++        }\r
++    return 0;\r
++\r
++    }\r
++EXPORT_SYMBOL(encoder_read_reg);\r
++\r
++int encoder_write_reg (struct i2c_adapter *adap, u32 offset, u32 data)\r
++    {\r
++    int ret;\r
++    ch7024_adap = adap;\r
++    ret = ch7024_write_reg(offset, data, 1);\r
++    if (ret < 0)\r
++        {\r
++        printk ("Encoder write2 register failed at offset 0x%X\n", offset);\r
++        return ret;\r
++        }\r
++    return 0;\r
++\r
++    }\r
++EXPORT_SYMBOL(encoder_write_reg);\r
++\r
++int ch7024_detect (struct i2c_adapter *adap)\r
++{\r
++      int ret;\r
++      u32 id;\r
++      ch7024_adap = adap;\r
++      /*TODO client detection */\r
++      ret = ch7024_read_reg(CH7024_DEVID, &id, 1);\r
++      if (ret < 0 || id != CH7024_DEVICE_ID) {\r
++              printk(KERN_ERR\r
++                     "ch7024: TV encoder not present: %d, read ret %d\n", id,\r
++                     ret);\r
++              return -1;\r
++      }\r
++      printk(KERN_ERR "ch7024: TV encoder present: %x, read ret %x\n", id,\r
++             ret);\r
++      ch7024_found = 1;\r
++      return 0;\r
++\r
++}\r
++EXPORT_SYMBOL(ch7024_detect);\r
++\r
++int ch7024_set_bright (struct i2c_adapter *adap,u32 val)\r
++{\r
++      ch7024_adap = adap;\r
++      if (val & ~0xFF) {\r
++              printk ("Brighness value is out of range[0-255] %d\n", val);\r
++              return -1;\r
++      } else {\r
++              ch7024_write_reg(CH7024_TVBRI, val, 1);\r
++      }\r
++      return 0;\r
++}\r
++EXPORT_SYMBOL(ch7024_set_bright);\r
++\r
++int ch7024_set_cont (struct i2c_adapter *adap,u32 val)\r
++{\r
++      ch7024_adap = adap;\r
++      if (val & ~0x7F) {\r
++              printk ("Contrast value is out of range[0-127] %d\n", val);\r
++              return -1;\r
++      } else {\r
++              ch7024_write_reg(CH7024_TVCTA, val, 1);\r
++      }\r
++      return 0;\r
++}\r
++EXPORT_SYMBOL(ch7024_set_cont);\r
++\r
++int ch7024_set_hue (struct i2c_adapter *adap,u32 val)\r
++{\r
++      ch7024_adap = adap;\r
++      if (val & ~0x7F) {\r
++              printk ("Hue value is out of range[0-127] %d\n", val);\r
++              return -1;\r
++      } else {\r
++              ch7024_write_reg(CH7024_TVHUE, val, 1);\r
++      }\r
++      return 0;\r
++}\r
++EXPORT_SYMBOL(ch7024_set_hue);\r
++\r
++int ch7024_set_sharp (struct i2c_adapter *adap,u32 val)\r
++{\r
++      ch7024_adap = adap;\r
++      if (val & ~0x07) {\r
++              printk ("Sharpness value is out of range[0-8] %d\n", val);\r
++              return -1;\r
++      } else {\r
++              ch7024_write_reg(CH7024_TVSHARP, val, 1);\r
++      }\r
++      return 0;\r
++}\r
++EXPORT_SYMBOL(ch7024_set_sharp);\r
++\r
++int ch7024_set_sat (struct i2c_adapter *adap,u32 val)\r
++{\r
++      ch7024_adap = adap;\r
++      if (val & ~0x7F) {\r
++              printk ("Saturation value is out of range[0-127] %d\n", val);\r
++              return -1;\r
++      } else {\r
++              ch7024_write_reg(CH7024_TVSAT, val, 1);\r
++      }\r
++      return 0;\r
++}\r
++EXPORT_SYMBOL(ch7024_set_sat);\r
++\r
++void ch7024_set_attr (struct i2c_adapter *adap,struct ch7024_attr *attributes)\r
++{\r
++      if (!attributes)\r
++              return;\r
++      ch7024_set_bright (adap, attributes->brghtness & 0xFF);\r
++      ch7024_set_cont (adap, attributes->contrast & 0xFF);\r
++      ch7024_set_hue (adap, attributes->hue & 0xFF);\r
++      ch7024_set_sharp (adap, attributes->sharpness & 0xFF);\r
++      ch7024_set_sat (adap,attributes->saturation & 0xFF);\r
++      return;\r
++}\r
++\r
++EXPORT_SYMBOL(ch7024_set_attr);\r
++\r
++\r
++EXPORT_SYMBOL(ch7024_setup);\r
++EXPORT_SYMBOL(ch7024_enable);\r
++EXPORT_SYMBOL(ch7024_disable);\r
++\r
++\r
++\r
+--- /dev/null
++++ git/drivers/bmi/pims/projector/ch7024.h
+@@ -0,0 +1,166 @@
++/*\r
++ * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved.\r
++ */\r
++\r
++/*\r
++ * The code contained herein is licensed under the GNU General Public\r
++ * License. You may obtain a copy of the GNU General Public License\r
++ * Version 2 or later at the following locations:\r
++ *\r
++ * http://www.opensource.org/licenses/gpl-license.html\r
++ * http://www.gnu.org/copyleft/gpl.html\r
++ */\r
++\r
++/*!\r
++ * @file ch7024.h\r
++ * @brief Driver for CH7024 TV encoder\r
++ *\r
++ * @ingroup Framebuffer\r
++ */\r
++#ifndef _CH7024_H_\r
++#define _CH7024_H_\r
++\r
++#ifdef __KERNEL__\r
++\r
++\r
++/* I2C bus id and device address of CH7024 chip */\r
++\r
++#define CH7024_I2C_ADDR       0x76    /* 7bits I2C address */\r
++\r
++/*!\r
++ * CH7024 registers\r
++ */\r
++#define CH7024_DEVID          0x00\r
++#define CH7024_REVID          0x01\r
++#define CH7024_PG                 0x02\r
++\r
++#define CH7024_RESET          0x03\r
++#define CH7024_POWER          0x04\r
++#define CH7024_TVHUE          0x05\r
++#define CH7024_TVSAT          0x06\r
++#define CH7024_TVCTA          0x07\r
++#define CH7024_TVBRI          0x08\r
++#define CH7024_TVSHARP                0x09\r
++#define CH7024_OUT_FMT                0x0A\r
++#define CH7024_XTAL               0x0B\r
++#define CH7024_IDF1               0x0C\r
++#define CH7024_IDF2               0x0D\r
++#define CH7024_SYNC               0x0E\r
++#define CH7024_TVFILTER1      0x0F\r
++#define CH7024_TVFILTER2      0x10\r
++#define CH7024_IN_TIMING1     0x11\r
++#define CH7024_IN_TIMING2     0x12\r
++#define CH7024_IN_TIMING3     0x13\r
++#define CH7024_IN_TIMING4     0x14\r
++#define CH7024_IN_TIMING5     0x15\r
++#define CH7024_IN_TIMING6     0x16\r
++#define CH7024_IN_TIMING7     0x17\r
++#define CH7024_IN_TIMING8     0x18\r
++#define CH7024_IN_TIMING9     0x19\r
++#define CH7024_IN_TIMING10    0x1A\r
++#define CH7024_IN_TIMING11    0x1B\r
++#define CH7024_ACIV               0x1C\r
++#define CH7024_OUT_TIMING1    0x1E\r
++#define CH7024_OUT_TIMING2    0x1F\r
++#define CH7024_V_POS1         0x20\r
++#define CH7024_V_POS2         0x21\r
++#define CH7024_H_POS1         0x22\r
++#define CH7024_H_POS2         0x23\r
++#define CH7024_PCLK_A1                0x24\r
++#define CH7024_PCLK_A2                0x25\r
++#define CH7024_PCLK_A3                0x26\r
++#define CH7024_PCLK_A4                0x27\r
++#define CH7024_CLK_P1         0x28\r
++#define CH7024_CLK_P2         0x29\r
++#define CH7024_CLK_P3         0x2A\r
++#define CH7024_CLK_N1         0x2B\r
++#define CH7024_CLK_N2         0x2C\r
++#define CH7024_CLK_N3         0x2D\r
++#define CH7024_CLK_T          0x2E\r
++#define CH7024_PLL1               0x2F\r
++#define CH7024_PLL2               0x30\r
++#define CH7024_PLL3           0x31\r
++#define CH7024_SC_FREQ1               0x34\r
++#define CH7024_SC_FREQ2               0x35\r
++#define CH7024_SC_FREQ3               0x36\r
++#define CH7024_SC_FREQ4               0x37\r
++#define CH7024_DATA_IO                0x63\r
++\r
++/*!\r
++ * CH7024 register values\r
++ */\r
++/* video output formats */\r
++#define CH7024_VOS_NTSC_M     0x0\r
++#define CH7024_VOS_NTSC_J     0x1\r
++#define CH7024_VOS_NTSC_443   0x2\r
++#define CH7024_VOS_PAL_BDGHKI 0x3\r
++#define CH7024_VOS_PAL_M      0x4\r
++#define CH7024_VOS_PAL_N      0x5\r
++#define CH7024_VOS_PAL_NC     0x6\r
++#define CH7024_VOS_PAL_60     0x7\r
++/* crystal predefined */\r
++#define CH7024_XTAL_13MHZ     0x4\r
++#define CH7024_XTAL_26MHZ     0xB\r
++#define CH7024_XTAL_27MHZ     0xC\r
++\r
++/* chip ID */\r
++#define CH7024_DEVICE_ID      0x45\r
++\r
++/* clock source define */\r
++#define CLK_HIGH      0\r
++#define CLK_LOW               1\r
++\r
++/* CH7024 presets structs */\r
++struct ch7024_clock {\r
++      u32 A;\r
++      u32 P;\r
++      u32 N;\r
++      u32 T;\r
++      u8 PLLN1;\r
++      u8 PLLN2;\r
++      u8 PLLN3;\r
++};\r
++\r
++struct ch7024_input_timing {\r
++      u32 HTI;\r
++      u32 VTI;\r
++      u32 HAI;\r
++      u32 VAI;\r
++      u32 HW;\r
++      u32 HO;\r
++      u32 VW;\r
++      u32 VO;\r
++      u32 VOS;\r
++};\r
++\r
++struct ch7024_attr{\r
++      u32 brghtness;\r
++      u32 sharpness;\r
++      u32 hue;\r
++      u32 contrast;\r
++      u32 saturation;\r
++};\r
++\r
++/* function declare, used by bmi projector module */\r
++int           ch7024_setup                    (struct i2c_adapter *adap,int vos);\r
++void  ch7024_enable           (struct i2c_adapter *adap);\r
++void  ch7024_disable          (struct i2c_adapter *adap);\r
++int   ch7024_detect           (struct i2c_adapter *adap);\r
++void  ch7024_set_attr         (struct i2c_adapter *adap, struct ch7024_attr *attributes);\r
++int   ch7024_set_sat          (struct i2c_adapter *adap, u32 val);\r
++int   ch7024_set_sharp        (struct i2c_adapter *adap, u32 val);\r
++int   ch7024_set_hue          (struct i2c_adapter *adap, u32 val);\r
++int   ch7024_set_cont         (struct i2c_adapter *adap, u32 val);\r
++int   ch7024_set_bright       (struct i2c_adapter *adap, u32 val);\r
++int     ch7024_dump         (struct i2c_adapter *adap);\r
++int     encoder_read_reg    (struct i2c_adapter *adap, u32 offset, u32 *data);\r
++int     encoder_write_reg   (struct i2c_adapter *adap, u32 offset, u32 data);\r
++\r
++#endif                                /* __KERNEL__ */\r
++\r
++/* output video format */\r
++#define PROJOUT_FMT_PAL               0x01\r
++#define PROJOUT_FMT_NTSC      0x02\r
++#define PROJOUT_FMT_QVGA        0x03\r
++\r
++#endif                                /* _CH7024_H_ */\r
+--- /dev/null
++++ git/drivers/bmi/pims/sensor/Makefile
+@@ -0,0 +1,6 @@
++#
++# BMI PIMS
++#
++
++obj-$(CONFIG_BMI_SENSOR)              += bmi_sensor.o
++
+--- /dev/null
++++ git/drivers/bmi/pims/sensor/bmi_sensor.c
+@@ -0,0 +1,4321 @@
++/*
++ *    bmi_sensor.c
++ *
++ *    BMI sensor device driver
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*
++ *    Include files
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/fs.h>
++#include <linux/cdev.h>
++#include <linux/interrupt.h>
++#include <linux/i2c.h>
++#include <linux/delay.h>
++#include <linux/jiffies.h>
++#include <linux/timer.h>
++#include <linux/wait.h>
++#include <linux/workqueue.h>
++
++#include <asm/uaccess.h>
++#include <asm/arch-mxc/mxc_i2c.h>
++
++#include <linux/bmi.h>
++#include <linux/bmi/bmi-control.h>
++#include <linux/bmi/bmi_sensor.h>
++
++#define BMISENSOR_VERSION     "1.0"
++
++#define work_to_sensor(w)  container_of(w, struct bmi_sensor, work_item)
++#define dev_to_bmi_device(d)  container_of(d, struct bmi_device, dev)
++
++/*
++ *    Global variables
++ */
++
++static ushort factory_test = 0;
++static int eeprom_init = 0;
++static ushort xdac_init = 0;
++static ushort ydac_init = 0;
++static ushort zdac_init = 0;
++static ushort fcc_test = 0;
++
++// private device structure
++struct bmi_sensor
++{
++      struct semaphore                sem;                    // bmi_sensor mutex
++      struct bmi_device               *bdev;                  // BMI device
++      struct cdev                     cdev;                   // control device
++      struct device                   *class_dev;             // control class device
++      struct sensor_eeprom_raw        eeprom;                 // eeprom contents
++      char                            int_name[20];           // interrupt name
++      struct workqueue_struct         *workqueue;             // interrupt work queue
++      struct work_struct              work_item;              // interrupt work structure
++      char                            work_name[20];          // workqueue name
++      wait_queue_head_t               pl_wait_queue;          // Proximity/Light interrupt wait queue
++      unsigned char                   pl_int_en;              // Proximity/Light interrupts are enabled
++      unsigned char                   pl_int_fl;              // Proximity/Light interrupt occurred
++      wait_queue_head_t               temp_wait_queue;        // Temperature interrupt wait queue
++      unsigned char                   temp_int_en;            // Temperature interrupts are enabled
++      unsigned char                   temp_int_fl;            // Temperature interrupt occurred
++      wait_queue_head_t               mot_wait_queue;         // Motion interrupt wait queue
++      unsigned char                   mot_int_en;             // Motion interrupts are enabled
++      unsigned char                   mot_int_fl;             // Motion interrupt occurred
++      unsigned int                    mot_state;              // previous motion detector state
++      wait_queue_head_t               acc_wait1_queue;        // Accelerometer interrupt wait queue
++      unsigned char                   acc_int1_en;            // Accelerometer interrupts are enabled
++      unsigned char                   acc_int1_fl;            // Accelerometer interrupt occurred
++      wait_queue_head_t               acc_wait2_queue;        // Accelerometer interrupt wait queue
++      unsigned char                   acc_int2_en;            // Accelerometer interrupts are enabled
++      unsigned char                   acc_int2_fl;            // Accelerometer interrupt occurred
++      wait_queue_head_t               usb_wait_queue;         // USB interrupt wait queue
++      unsigned char                   usb_int_en;             // USB interrupts are enabled
++      unsigned char                   usb_int_fl;             // USB interrupt occurred
++      wait_queue_head_t               dcomp_wait_queue;       // Digital compass interrupt wait queue
++      unsigned char                   dcomp_int_en;           // Digital compass interrupts are enabled
++      unsigned char                   dcomp_int_fl;           // Digital compass interrupt occurred
++      unsigned int                    aprox_duration;         // Analog Proximity LED burst duration (ms)
++      struct timer_list               aprox_timer;            // Analog Proximity LED burst timer
++      wait_queue_head_t               aprox_wait_queue;       // Analog Proximity timer wait queue
++      unsigned char                   aprox_int_en;           // Analog Proximity timer are enabled
++      unsigned char                   aprox_int_fl;           // Analog Proximity timer occurred
++      wait_queue_head_t               dlight_wait_queue;      // Digital Light interrupt wait queue
++      unsigned char                   dlight_int_en;          // Digital Light interrupts are enabled
++      unsigned char                   dlight_int_fl;          // Digital Light interrupt occurred
++      unsigned int                    comp_xsf;               // Compass calibration
++      unsigned int                    comp_ysf;               // Compass calibration
++      unsigned int                    comp_zsf;               // Compass calibration
++      unsigned int                    comp_xoff;              // Compass calibration
++      unsigned int                    comp_yoff;              // Compass calibration
++      unsigned int                    comp_zoff;              // Compass calibration
++};
++
++static struct bmi_sensor bmi_sensor[4];       // per slot device structure
++static int major;                     // control device major
++
++/*
++ *    BMI set up
++ */
++
++// BMI device ID table
++static struct bmi_device_id bmi_sensor_tbl[] =
++{
++      {
++              .match_flags = BMI_DEVICE_ID_MATCH_VENDOR | BMI_DEVICE_ID_MATCH_PRODUCT,
++              .vendor   = BMI_VENDOR_BUG_LABS,
++              .product  = BMI_PRODUCT_SENSOR,
++              .revision = BMI_ANY,
++      },
++      { 0, },   /* terminate list */
++};
++MODULE_DEVICE_TABLE(bmi, bmi_sensor_tbl);
++
++int   bmi_sensor_probe(struct bmi_device *bdev);
++void  bmi_sensor_remove(struct bmi_device *bdev);
++
++// BMI driver structure
++static struct bmi_driver bmi_sensor_driver =
++{
++      .name = "bmi_sensor",
++      .id_table = bmi_sensor_tbl,
++      .probe   = bmi_sensor_probe,
++      .remove  = bmi_sensor_remove,
++};
++
++/*
++ *    I2C set up
++ */
++
++// IOX
++// write byte to I2C IO expander
++static int WriteByte_IOX(struct i2c_adapter *adap, unsigned char offset, unsigned char data)
++{
++      int     ret = 0;
++      struct i2c_msg wmsg[2];
++      int     num_msgs;
++
++      // Write Byte with Pointer
++      wmsg[0].addr = BMI_IOX_I2C_ADDRESS;
++      wmsg[0].flags = 0;  // write
++      wmsg[0].len = 1;
++      wmsg[0].buf = &offset;
++
++      wmsg[1].addr = BMI_IOX_I2C_ADDRESS;
++      wmsg[1].flags = 0;   // write
++      wmsg[1].len = 1;
++      wmsg[1].buf = &data;
++
++      num_msgs = 2;
++
++      ret = i2c_transfer(adap, wmsg, num_msgs);
++
++      if(ret == 2) {
++              ret = 0;
++      }
++      else {
++              printk(KERN_ERR "WriteByte_IOX() - i2c_transfer() failed.\n");
++              ret = -1;
++      }
++      return ret;
++}
++
++// read byte from I2C IO expander
++static int ReadByte_IOX(struct i2c_adapter *adap, unsigned char offset, unsigned char *data)
++{
++      int     ret = 0;
++      struct i2c_msg rmsg[2];
++      int     num_msgs;
++
++      // Read Byte with Pointer
++      rmsg[0].addr = BMI_IOX_I2C_ADDRESS;
++      rmsg[0].flags = 0;              // write
++      rmsg[0].len = 1;
++      rmsg[0].buf = &offset;
++
++      rmsg[1].addr = BMI_IOX_I2C_ADDRESS;
++      rmsg[1].flags = I2C_M_RD;       // read
++      rmsg[1].len = 1;
++      rmsg[1].buf = data;
++
++      num_msgs = 2;
++      ret = i2c_transfer(adap, rmsg, num_msgs);
++
++      if(ret == 2) {
++              ret = 0;
++      }
++      else {
++              printk(KERN_ERR "ReadByte_IOX() - i2c_transfer() failed.\n");
++              ret = -1;
++      }
++      return ret;
++}
++
++// ADC
++// write byte to ADC
++static int WriteByte_ADC(struct i2c_adapter *adap, unsigned char data)
++{
++      int     ret = 0;
++      struct i2c_msg wmsg[1];
++      int     num_msgs;
++
++      wmsg[0].addr = BMI_ADC_I2C_ADDRESS;
++      wmsg[0].flags = 0;   // write
++      wmsg[0].len = 1;
++      wmsg[0].buf = &data;
++
++      num_msgs = 1;
++
++      ret = i2c_transfer(adap, wmsg, num_msgs);
++
++      if(ret == 1) {
++              ret = 0;
++      }
++      else {
++              printk(KERN_ERR "WriteByte_ADC() - i2c_transfer() failed.\n");
++              ret = -1;
++      }
++      return ret;
++}
++
++// read data from ADC
++static int ReadByte_ADC(struct i2c_adapter *adap, unsigned char *data)
++{
++      int     ret = 0;
++      struct i2c_msg rmsg[1];
++      int     num_msgs;
++
++      rmsg[0].addr = BMI_ADC_I2C_ADDRESS;
++      rmsg[0].flags = I2C_M_RD;       // read
++      rmsg[0].len = 2;
++      rmsg[0].buf = data;
++
++      num_msgs = 1;
++      ret = i2c_transfer(adap, rmsg, num_msgs);
++
++      if(ret == 1) {
++              ret = 0;
++      }
++      else {
++              printk(KERN_ERR "ReadByte_ADC() - i2c_transfer() failed.\n");
++              ret = -1;
++      }
++      return ret;
++}
++
++// Proximity/Light and Digital Light (same I2c address and format)
++// write byte to I2C PL
++static int WriteByte_PL(struct i2c_adapter *adap, unsigned char offset, unsigned char data)
++{
++      int     ret = 0;
++      struct i2c_msg wmsg[2];
++      int     num_msgs;
++
++      // Write Byte with Pointer
++      wmsg[0].addr = BMI_PL_I2C_ADDRESS;
++      wmsg[0].flags = 0;  // write
++      wmsg[0].len = 1;
++      wmsg[0].buf = &offset;
++
++      wmsg[1].addr = BMI_PL_I2C_ADDRESS;
++      wmsg[1].flags = 0;   // write
++      wmsg[1].len = 1;
++      wmsg[1].buf = &data;
++
++      num_msgs = 2;
++
++      ret = i2c_transfer(adap, wmsg, num_msgs);
++
++      if(ret == 2) {
++              ret = 0;
++      }
++      else {
++              printk(KERN_ERR "WriteByte_PL() - i2c_transfer() failed.\n");
++              ret = -1;
++      }
++      return ret;
++}
++
++// read byte from I2C PL
++static int ReadByte_PL(struct i2c_adapter *adap, unsigned char offset, unsigned char *data)
++{
++      int     ret = 0;
++      struct i2c_msg rmsg[2];
++      int     num_msgs;
++
++      // Read Byte with Pointer
++      rmsg[0].addr = BMI_PL_I2C_ADDRESS;
++      rmsg[0].flags = 0;              // write
++      rmsg[0].len = 1;
++      rmsg[0].buf = &offset;
++
++      rmsg[1].addr = BMI_PL_I2C_ADDRESS;
++      rmsg[1].flags = I2C_M_RD;       // read
++      rmsg[1].len = 1;
++      rmsg[1].buf = data;
++
++      num_msgs = 2;
++      ret = i2c_transfer(adap, rmsg, num_msgs);
++
++      if(ret == 2) {
++              ret = 0;
++      }
++      else {
++              printk(KERN_ERR "ReadByte_PL() - i2c_transfer() failed.\n");
++              ret = -1;
++      }
++      return ret;
++}
++
++// write byte to I2C PL SYNC
++static int WriteByte_PL_SYNC(struct i2c_adapter *adap)
++{
++      int     ret = 0;
++      struct i2c_msg wmsg[1];
++      int     num_msgs;
++      unsigned char offset = SENSOR_PL_EXT_SYNC;
++
++      // Write Byte with Pointer
++      wmsg[0].addr = BMI_PL_I2C_ADDRESS;
++      wmsg[0].flags = 0;  // write
++      wmsg[0].len = 1;
++      wmsg[0].buf = &offset;
++
++      num_msgs = 1;
++
++      ret = i2c_transfer(adap, wmsg, num_msgs);
++
++      if(ret == 1) {
++              ret = 0;
++      }
++      else {
++              printk(KERN_ERR "WriteByte_PL_SYNC() - i2c_transfer() failed.\n");
++              ret = -1;
++      }
++      return ret;
++}
++
++// write byte to I2C DL Interrupt Clear
++static int WriteByte_DL_IC(struct i2c_adapter *adap)
++{
++      int     ret = 0;
++      struct i2c_msg wmsg[1];
++      int     num_msgs;
++      unsigned char offset = SENSOR_DL_INT_CLR;
++
++      // Write Byte with Pointer
++      wmsg[0].addr = BMI_DLIGHT_I2C_ADDRESS;
++      wmsg[0].flags = 0;  // write
++      wmsg[0].len = 1;
++      wmsg[0].buf = &offset;
++
++      num_msgs = 1;
++
++      ret = i2c_transfer(adap, wmsg, num_msgs);
++
++      if(ret == 1) {
++              ret = 0;
++      }
++      else {
++              printk(KERN_ERR "WriteByte_DL_IC() - i2c_transfer() failed.\n");
++              ret = -1;
++      }
++      return ret;
++}
++
++// Temperature
++// write byte to Temperature sensor
++static int WriteByte_TEMP(struct i2c_adapter *adap, unsigned char offset, unsigned char data)
++{
++      int     ret = 0;
++      struct i2c_msg wmsg[2];
++      int     num_msgs;
++
++      // Write Byte with Pointer
++      wmsg[0].addr = BMI_TEMP_I2C_ADDRESS;
++      wmsg[0].flags = 0;  // write
++      wmsg[0].len = 1;
++      wmsg[0].buf = &offset;
++
++      wmsg[1].addr = BMI_TEMP_I2C_ADDRESS;
++      wmsg[1].flags = 0;   // write
++      wmsg[1].len = 1;
++      wmsg[1].buf = &data;
++
++      num_msgs = 2;
++
++      ret = i2c_transfer(adap, wmsg, num_msgs);
++
++      if(ret == 2) {
++              ret = 0;
++      }
++      else {
++              printk(KERN_ERR "WriteByte_TEMP() - i2c_transfer() failed.\n");
++              ret = -1;
++      }
++      return ret;
++}
++
++// read byte from Temperature sensor
++static int ReadByte_TEMP(struct i2c_adapter *adap, unsigned char offset, unsigned char *data)
++{
++      int     ret = 0;
++      struct i2c_msg rmsg[2];
++      int     num_msgs;
++
++      // Read Byte with Pointer
++      rmsg[0].addr = BMI_TEMP_I2C_ADDRESS;
++      rmsg[0].flags = 0;              // write
++      rmsg[0].len = 1;
++      rmsg[0].buf = &offset;
++
++      rmsg[1].addr = BMI_TEMP_I2C_ADDRESS;
++      rmsg[1].flags = I2C_M_RD;       // read
++      rmsg[1].len = 1;
++      rmsg[1].buf = data;
++
++      num_msgs = 2;
++      ret = i2c_transfer(adap, rmsg, num_msgs);
++
++      if(ret == 2) {
++              ret = 0;
++      }
++      else {
++              printk(KERN_ERR "ReadByte_TEMP() - i2c_transfer() failed.\n");
++              ret = -1;
++      }
++      return ret;
++}
++
++// Accelerometer
++// write byte to I2C Accelerometer
++static int WriteByte_ACC(struct i2c_adapter *adap, struct sensor_acc_rw *acc_rw)
++{
++      int     ret = 0;
++      struct i2c_msg wmsg[2];
++      int     num_msgs;
++
++      // Write Byte with Pointer
++      wmsg[0].addr = BMI_ACCEL_I2C_ADDRESS;
++      wmsg[0].flags = 0;  // write
++      wmsg[0].len = 1;
++      wmsg[0].buf = &acc_rw->address;
++
++      wmsg[1].addr = BMI_ACCEL_I2C_ADDRESS;
++      wmsg[1].flags = 0;   // write
++      wmsg[1].len = 1;
++      wmsg[1].buf = acc_rw->data;
++
++      num_msgs = 2;
++
++      ret = i2c_transfer(adap, wmsg, num_msgs);
++
++      if(ret == 2) {
++              ret = 0;
++      }
++      else {
++              printk(KERN_ERR "WriteByte_ACC() - i2c_transfer() failed.\n");
++              ret = -1;
++      }
++      return ret;
++}
++
++// read byte(s) from Acceleromter
++static int ReadByte_ACC(struct i2c_adapter *adap, struct sensor_acc_rw *acc_rw)
++{
++      int     ret = 0;
++      struct i2c_msg rmsg[2];
++      int     num_msgs;
++
++      // Read Byte with Pointer
++      rmsg[0].addr = BMI_ACCEL_I2C_ADDRESS;
++      rmsg[0].flags = 0;              // write
++      rmsg[0].len = 1;
++      rmsg[0].buf = &acc_rw->address;
++
++      rmsg[1].addr = BMI_ACCEL_I2C_ADDRESS;
++      rmsg[1].flags = I2C_M_RD;       // read
++      rmsg[1].len = acc_rw->count;
++      rmsg[1].buf = acc_rw->data;
++
++      num_msgs = 2;
++      ret = i2c_transfer(adap, rmsg, num_msgs);
++
++      if(ret == 2) {
++              ret = 0;
++      }
++      else {
++              printk(KERN_ERR "ReadByte_ACC() - i2c_transfer() failed.\n");
++              ret = -1;
++      }
++      return ret;
++}
++
++// digital compass
++// write byte to digital compass
++static int WriteByte_DCOMP(struct i2c_adapter *adap, unsigned char offset, unsigned char data)
++{
++      int     ret = 0;
++      struct i2c_msg wmsg[2];
++      int     num_msgs;
++
++      // Write Byte with Pointer
++      wmsg[0].addr = BMI_DCOMP_I2C_ADDRESS;
++      wmsg[0].flags = 0;  // write
++      wmsg[0].len = 1;
++      wmsg[0].buf = &offset;
++
++      wmsg[1].addr = BMI_DCOMP_I2C_ADDRESS;
++      wmsg[1].flags = 0;   // write
++      wmsg[1].len = 1;
++      wmsg[1].buf = &data;
++
++      num_msgs = 2;
++
++      ret = i2c_transfer(adap, wmsg, num_msgs);
++
++      if(ret == 2) {
++              ret = 0;
++      }
++      else {
++              printk(KERN_ERR "WriteByte_DCOMP() - i2c_transfer() failed.\n");
++              ret = -1;
++      }
++      return ret;
++}
++
++// read byte from digital compass
++static int ReadByte_DCOMP(struct i2c_adapter *adap, unsigned char offset, unsigned char *data)
++{
++      int     ret = 0;
++      struct i2c_msg rmsg[2];
++      int     num_msgs;
++
++      // Read Byte with Pointer
++      rmsg[0].addr = BMI_DCOMP_I2C_ADDRESS;
++      rmsg[0].flags = 0;              // write
++      rmsg[0].len = 1;
++      rmsg[0].buf = &offset;
++
++      rmsg[1].addr = BMI_DCOMP_I2C_ADDRESS;
++      rmsg[1].flags = I2C_M_RD;       // read
++      rmsg[1].len = 1;
++      rmsg[1].buf = data;
++
++      num_msgs = 2;
++      ret = i2c_transfer(adap, rmsg, num_msgs);
++
++      if(ret == 2) {
++              ret = 0;
++      }
++      else {
++              printk(KERN_ERR "ReadByte_DCOMP() - i2c_transfer() failed.\n");
++              ret = -1;
++      }
++      return ret;
++}
++
++// EEPROM
++// write byte to I2C EEPROM
++static int WriteByte_EE(struct i2c_adapter *adap, unsigned char offset, unsigned char data)
++{
++      int     ret = 0;
++      struct i2c_msg wmsg[2];
++      int     num_msgs;
++
++      // Write Byte with Pointer
++      wmsg[0].addr = BMI_MEE_I2C_ADDRESS;
++      wmsg[0].flags = 0;  // write
++      wmsg[0].len = 1;
++      wmsg[0].buf = &offset;
++
++      wmsg[1].addr = BMI_MEE_I2C_ADDRESS;
++      wmsg[1].flags = 0;   // write
++      wmsg[1].len = 1;
++      wmsg[1].buf = &data;
++
++      num_msgs = 2;
++
++      ret = i2c_transfer(adap, wmsg, num_msgs);
++
++      if(ret == 2) {
++              ret = 0;
++      }
++      else {
++              printk(KERN_ERR "WriteByte_EE() - i2c_transfer() failed.\n");
++              ret = -1;
++      }
++      return ret;
++}
++
++// read byte from I2C EEPROM
++static int ReadByte_EE(struct i2c_adapter *adap, unsigned char offset, unsigned char *data)
++{
++      int     ret = 0;
++      struct i2c_msg rmsg[2];
++      int     num_msgs;
++
++      // Read Byte with Pointer
++      rmsg[0].addr = BMI_MEE_I2C_ADDRESS;
++      rmsg[0].flags = 0;              // write
++      rmsg[0].len = 1;
++      rmsg[0].buf = &offset;
++
++      rmsg[1].addr = BMI_MEE_I2C_ADDRESS;
++      rmsg[1].flags = I2C_M_RD;       // read
++      rmsg[1].len = 1;
++      rmsg[1].buf = data;
++
++      num_msgs = 2;
++      ret = i2c_transfer(adap, rmsg, num_msgs);
++
++      if(ret == 2) {
++              ret = 0;
++      }
++      else {
++              printk(KERN_ERR "ReadByte_EE() - i2c_transfer() failed.\n");
++              ret = -1;
++      }
++      return ret;
++}
++
++/*
++ *    control device operations
++ */
++
++// open
++int cntl_open(struct inode *inode, struct file *file)
++{
++      struct bmi_sensor *sensor;
++
++      sensor = container_of(inode->i_cdev, struct bmi_sensor, cdev);
++      file->private_data = sensor;
++      return 0;
++
++}
++
++// release
++int cntl_release(struct inode *inode, struct file *file)
++{
++      return 0;
++}
++
++// analog proximity timer function
++void aptimer(unsigned long arg)
++{
++      struct bmi_sensor *sensor = (struct bmi_sensor *) arg;
++      int ret;
++
++      del_timer (&sensor->aprox_timer);
++
++      // wake sleepers
++      ret = down_interruptible(&sensor->sem);
++      sensor->aprox_int_en = 0;
++      sensor->aprox_int_fl = 1;
++      up(&sensor->sem);
++      wake_up_all(&sensor->aprox_wait_queue);
++}
++
++// ioctl
++int cntl_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
++                 unsigned long arg)
++{
++      struct i2c_adapter *adap;
++      unsigned char iox_data;
++      struct bmi_sensor *sensor = (struct bmi_sensor *)(file->private_data);
++      int slot;
++      int ret = 0;
++
++      // error if sensor not present
++      if(sensor->bdev == 0)
++              return -ENODEV;
++
++      slot = bmi_device_get_slot(sensor->bdev);
++      adap = bmi_device_get_i2c_adapter(sensor->bdev);
++
++      // ioctl's
++      switch(cmd) {
++
++      case BMI_SENSOR_RLEDOFF:
++              bmi_slot_gpio_write_bit(slot, SENSOR_GPIO_RED_LED, SENSOR_GPIO_LED_OFF); // Red LED=OFF
++              break;
++
++      case BMI_SENSOR_RLEDON:
++              bmi_slot_gpio_write_bit(slot, SENSOR_GPIO_RED_LED, SENSOR_GPIO_LED_ON); // Red LED=ON
++              break;
++
++      case BMI_SENSOR_GLEDOFF:
++              bmi_slot_gpio_write_bit(slot, SENSOR_GPIO_GREEN_LED, SENSOR_GPIO_LED_OFF); // Green LED=OFF
++              break;
++
++      case BMI_SENSOR_GLEDON:
++              bmi_slot_gpio_write_bit(slot, SENSOR_GPIO_GREEN_LED, SENSOR_GPIO_LED_ON); // Green LED=ON
++              break;
++
++      case BMI_SENSOR_GETSTAT:
++              {
++                      int read_data;
++
++                      if(ReadByte_IOX(adap, IOX_INPUT0_REG, &iox_data))
++                              return -ENODEV;
++                      read_data = iox_data;
++
++                      if(ReadByte_IOX(adap, IOX_INPUT1_REG, &iox_data))
++                              return -ENODEV;
++                      read_data |= (iox_data << 8) | (bmi_read_gpio_data_reg(slot) << 16);
++
++                      if(put_user(read_data, (int __user *) arg))
++                              return -EFAULT;
++              }
++              break;
++
++      case BMI_SENSOR_ADCWR:
++              {
++                      unsigned char adc_data;
++
++                      if(sensor->eeprom.adc_present != SENSOR_DEVICE_PRESENT)
++                              return -ENODEV;
++
++                      adc_data = (unsigned char) (arg & 0xFF);
++                      if(WriteByte_ADC(adap, adc_data))
++                              return -ENODEV;
++              }
++              break;
++
++      case BMI_SENSOR_ADCRD:
++              {
++                      unsigned char adc_data[2];
++                      int read_data;
++
++                      if(sensor->eeprom.adc_present != SENSOR_DEVICE_PRESENT)
++                              return -ENODEV;
++
++                      if(ReadByte_ADC(adap, adc_data))
++                              return -ENODEV;
++                      read_data = ((adc_data[0] & SENSOR_ADC_DATA_MSB) << 8) | adc_data[1];
++
++                      if(put_user(read_data, (int __user *) arg))
++                              return -EFAULT;
++              }
++              break;
++
++      case BMI_SENSOR_HUMRD:
++              {
++                      unsigned char adc_data[2];
++                      int read_data;
++
++                      if(sensor->eeprom.humidity_present != SENSOR_DEVICE_PRESENT)
++                              return -ENODEV;
++
++                      if(WriteByte_ADC(adap, SENSOR_ADC_HUMIDITY | SENSOR_ADC_PD_OFF))
++                              return -ENODEV;
++
++                      mdelay(1);
++
++                      if(ReadByte_ADC(adap, adc_data))
++                              return -ENODEV;
++                      read_data = ((adc_data[0] & SENSOR_ADC_DATA_MSB) << 8) | adc_data[1];
++
++                      if(put_user(read_data, (int __user *) arg))
++                              return -EFAULT;
++              }
++              break;
++
++      case BMI_SENSOR_ACOMPRST:
++              {
++                      if(sensor->eeprom.acompass_present != SENSOR_DEVICE_PRESENT)
++                              return -ENODEV;
++
++                      if(ReadByte_IOX(adap, IOX_INPUT0_REG, &iox_data))
++                              return -ENODEV;
++
++                      iox_data &= ~(0x1 << SENSOR_IOX_COMP_RS_N);
++                      if(WriteByte_IOX(adap, IOX_OUTPUT0_REG, iox_data))
++                              return -ENODEV;
++
++                      mdelay(5);
++
++                      iox_data |= (0x1 << SENSOR_IOX_COMP_RS_N);
++                      if(WriteByte_IOX(adap, IOX_OUTPUT0_REG, iox_data))
++                              return -ENODEV;
++              }
++              break;
++
++      case BMI_SENSOR_ACOMPXRD:
++              {
++                      unsigned char adc_data[2];
++                      int read_data;
++
++                      if(sensor->eeprom.acompass_present != SENSOR_DEVICE_PRESENT)
++                              return -ENODEV;
++
++                      if(WriteByte_ADC(adap, SENSOR_ADC_ACOMPASS_X | SENSOR_ADC_PD_OFF))
++                              return -ENODEV;
++
++                      mdelay(1);
++
++                      if(ReadByte_ADC(adap, adc_data))
++                              return -ENODEV;
++                      read_data = ((adc_data[0] & SENSOR_ADC_DATA_MSB) << 8) | adc_data[1];
++
++                      if(put_user(read_data, (int __user *) arg))
++                              return -EFAULT;
++              }
++              break;
++
++      case BMI_SENSOR_ACOMPYRD:
++              {
++                      unsigned char adc_data[2];
++                      int read_data;
++
++                      if(sensor->eeprom.acompass_present != SENSOR_DEVICE_PRESENT)
++                              return -ENODEV;
++
++                      if(WriteByte_ADC(adap, SENSOR_ADC_ACOMPASS_Y | SENSOR_ADC_PD_OFF))
++                              return -ENODEV;
++
++                      mdelay(1);
++
++                      if(ReadByte_ADC(adap, adc_data))
++                              return -ENODEV;
++                      read_data = ((adc_data[0] & SENSOR_ADC_DATA_MSB) << 8) | adc_data[1];
++
++                      if(put_user(read_data, (int __user *) arg))
++                              return -EFAULT;
++              }
++              break;
++
++      case BMI_SENSOR_ACOMPZRD:
++              {
++                      unsigned char adc_data[2];
++                      int read_data;
++
++                      if(sensor->eeprom.acompass_present != SENSOR_DEVICE_PRESENT)
++                              return -ENODEV;
++
++                      if(WriteByte_ADC(adap, SENSOR_ADC_ACOMPASS_Z | SENSOR_ADC_PD_OFF))
++                              return -ENODEV;
++
++                      mdelay(1);
++
++                      if(ReadByte_ADC(adap, adc_data))
++                              return -ENODEV;
++                      read_data = ((adc_data[0] & SENSOR_ADC_DATA_MSB) << 8) | adc_data[1];
++
++                      if(put_user(read_data, (int __user *) arg))
++                              return -EFAULT;
++              }
++              break;
++
++      case BMI_SENSOR_PLWR:
++              {
++                      struct sensor_pl_rw *pl = NULL;
++                      unsigned char pl_data;
++
++                      if(sensor->eeprom.light_proximity_present != SENSOR_DEVICE_PRESENT)
++                              return -ENODEV;
++
++                      if ((pl = kmalloc(sizeof(struct sensor_pl_rw), GFP_KERNEL)) == NULL)
++                              return -ENOMEM;
++                      if (copy_from_user(pl, (struct sensor_pl_rw *) arg, sizeof(struct sensor_pl_rw))) {
++                              kfree(pl);
++                              return -EFAULT;
++                      }
++
++                      pl_data = pl->cmd1;
++                      if(WriteByte_PL(adap, SENSOR_PL_CMD1, pl_data)) {
++                              kfree(pl);
++                              return -ENODEV;
++                      }
++
++                      pl_data = pl->cmd2;
++                      if(WriteByte_PL(adap, SENSOR_PL_CMD2, pl_data)) {
++                              kfree(pl);
++                              return -ENODEV;
++                      }
++
++                      pl_data = pl->int_lt_lsb;
++                      if(WriteByte_PL(adap, SENSOR_PL_INT_LT_LSB, pl_data)) {
++                              kfree(pl);
++                              return -ENODEV;
++                      }
++
++                      pl_data = pl->int_lt_msb;
++                      if(WriteByte_PL(adap, SENSOR_PL_INT_LT_MSB, pl_data)) {
++                              kfree(pl);
++                              return -ENODEV;
++                      }
++
++                      pl_data = pl->int_ht_lsb;
++                      if(WriteByte_PL(adap, SENSOR_PL_INT_HT_LSB, pl_data)) {
++                              kfree(pl);
++                              return -ENODEV;
++                      }
++
++                      pl_data = pl->int_ht_msb;
++                      if(WriteByte_PL(adap, SENSOR_PL_INT_HT_MSB, pl_data)) {
++                              kfree(pl);
++                              return -ENODEV;
++                      }
++
++                      kfree(pl);
++              }
++              break;
++
++      case BMI_SENSOR_PLRD:
++              {
++                      struct sensor_pl_rw *pl = NULL;
++                      unsigned char pl_data;
++
++                      if(sensor->eeprom.light_proximity_present != SENSOR_DEVICE_PRESENT)
++                              return -ENODEV;
++
++                      if ((pl = kmalloc(sizeof(struct sensor_pl_rw), GFP_KERNEL)) == NULL)
++                              return -ENOMEM;
++
++                      if(ReadByte_PL(adap, SENSOR_PL_CMD1, &pl_data)) {
++                              kfree(pl);
++                              return -ENODEV;
++                      }
++                      pl->cmd1 = pl_data;
++
++                      if(ReadByte_PL(adap, SENSOR_PL_DATA_MSB, &pl_data)) {
++                              kfree(pl);
++                              return -ENODEV;
++                      }
++                      pl->dm = pl_data;
++
++                      if(ReadByte_PL(adap, SENSOR_PL_DATA_LSB, &pl_data)) {
++                              kfree(pl);
++                              return -ENODEV;
++                      }
++                      pl->dl = pl_data;
++
++                      if(copy_to_user((struct sensor_pl_rw *) arg, pl, sizeof(struct sensor_pl_rw))) {
++                              kfree(pl);
++                              return -EFAULT;
++                      }
++
++                      kfree(pl);
++              }
++              break;
++
++      case BMI_SENSOR_PL_SYNC:
++              {
++                      if(sensor->eeprom.light_proximity_present != SENSOR_DEVICE_PRESENT)
++                              return -ENODEV;
++
++                      if(WriteByte_PL_SYNC(adap))
++                              return -ENODEV;
++              }
++              break;
++
++      case BMI_SENSOR_PL_IWAIT:
++              {
++                      struct sensor_pl_rw *pl = NULL;
++                      unsigned char pl_data;
++
++                      if(sensor->eeprom.light_proximity_present != SENSOR_DEVICE_PRESENT)
++                              return -ENODEV;
++
++                      if ((pl = kmalloc(sizeof(struct sensor_pl_rw), GFP_KERNEL)) == NULL)
++                              return -ENOMEM;
++                      if (copy_from_user(pl, (struct sensor_pl_rw *) arg, sizeof(struct sensor_pl_rw))) {
++                              kfree(pl);
++                              return -EFAULT;
++                      }
++
++                      pl_data = pl->cmd1;
++                      if(WriteByte_PL(adap, SENSOR_PL_CMD1, pl_data)) {
++                              kfree(pl);
++                              return -ENODEV;
++                      }
++
++                      pl_data = pl->cmd2;
++                      if(WriteByte_PL(adap, SENSOR_PL_CMD2, pl_data)) {
++                              kfree(pl);
++                              return -ENODEV;
++                      }
++
++                      pl_data = pl->int_lt_lsb;
++                      if(WriteByte_PL(adap, SENSOR_PL_INT_LT_LSB, pl_data)) {
++                              kfree(pl);
++                              return -ENODEV;
++                      }
++
++                      pl_data = pl->int_lt_msb;
++                      if(WriteByte_PL(adap, SENSOR_PL_INT_LT_MSB, pl_data)) {
++                              kfree(pl);
++                              return -ENODEV;
++                      }
++
++                      pl_data = pl->int_ht_lsb;
++                      if(WriteByte_PL(adap, SENSOR_PL_INT_HT_LSB, pl_data)) {
++                              kfree(pl);
++                              return -ENODEV;
++                      }
++
++                      pl_data = pl->int_ht_msb;
++                      if(WriteByte_PL(adap, SENSOR_PL_INT_HT_MSB, pl_data)) {
++                              kfree(pl);
++                              return -ENODEV;
++                      }
++
++                      ret = down_interruptible(&sensor->sem);
++                      sensor->pl_int_en = 1;
++                      sensor->pl_int_fl = 0;
++                      up(&sensor->sem);
++                      ret = wait_event_interruptible(sensor->pl_wait_queue, (sensor->pl_int_fl == 1));
++                      if(ret)
++                              return ret;
++
++                      if(ReadByte_PL(adap, SENSOR_PL_CMD1, &pl_data)) {
++                              kfree(pl);
++                              return -ENODEV;
++                      }
++                      pl->cmd1 = pl_data;
++
++                      if(ReadByte_PL(adap, SENSOR_PL_DATA_MSB, &pl_data)) {
++                              kfree(pl);
++                              return -ENODEV;
++                      }
++                      pl->dm = pl_data;
++
++                      if(ReadByte_PL(adap, SENSOR_PL_DATA_LSB, &pl_data)) {
++                              kfree(pl);
++                              return -ENODEV;
++                      }
++                      pl->dl = pl_data;
++
++                      if(copy_to_user((struct sensor_pl_rw *) arg, pl, sizeof(struct sensor_pl_rw))) {
++                              kfree(pl);
++                              return -EFAULT;
++                      }
++
++                      kfree(pl);
++              }
++              break;
++
++      case BMI_SENSOR_SNDARD:
++              {
++                      unsigned char adc_data[2];
++                      int read_data;
++
++                      if(sensor->eeprom.sound_present != SENSOR_DEVICE_PRESENT)
++                              return -ENODEV;
++
++                      if(WriteByte_ADC(adap, SENSOR_ADC_SOUND_AVG | SENSOR_ADC_PD_OFF))
++                              return -ENODEV;
++
++                      mdelay(1);
++
++                      if(ReadByte_ADC(adap, adc_data))
++                              return -ENODEV;
++                      read_data = ((adc_data[0] & SENSOR_ADC_DATA_MSB) << 8) | adc_data[1];
++
++                      if(put_user(read_data, (int __user *) arg))
++                              return -EFAULT;
++              }
++              break;
++
++      case BMI_SENSOR_SNDPRD:
++      case BMI_SENSOR_SNDIRD:
++              {
++                      unsigned char adc_data[2];
++                      int read_data;
++
++                      if(sensor->eeprom.sound_present != SENSOR_DEVICE_PRESENT)
++                              return -ENODEV;
++
++                      // read peak
++                      if(WriteByte_ADC(adap, SENSOR_ADC_SOUND_PEAK | SENSOR_ADC_PD_OFF))
++                              return -ENODEV;
++
++                      mdelay(1);
++
++                      if(ReadByte_ADC(adap, adc_data))
++                              return -ENODEV;
++                      read_data = ((adc_data[0] & SENSOR_ADC_DATA_MSB) << 8) | adc_data[1];
++
++                      // clear peak
++                      if(ReadByte_IOX(adap, IOX_INPUT1_REG, &iox_data))
++                              return -ENODEV;
++
++                      iox_data &= ~(0x1 << SENSOR_IOX_S_PK_CLR_N);
++                      if(WriteByte_IOX(adap, IOX_OUTPUT1_REG, iox_data))
++                              return -ENODEV;
++
++                      mdelay(1);
++
++                      iox_data |= (0x1 << SENSOR_IOX_S_PK_CLR_N);
++                      if(WriteByte_IOX(adap, IOX_OUTPUT1_REG, iox_data))
++                              return -ENODEV;
++
++                      if(cmd == BMI_SENSOR_SNDPRD) {
++                              // return data
++                              if(put_user(read_data, (int __user *) arg))
++                                      return -EFAULT;
++                      } else {
++
++                              // read peak
++                              if(WriteByte_ADC(adap, SENSOR_ADC_SOUND_PEAK | SENSOR_ADC_PD_OFF))
++                                      return -ENODEV;
++
++                              mdelay(1);
++
++                              if(ReadByte_ADC(adap, adc_data))
++                                      return -ENODEV;
++                              read_data = ((adc_data[0] & SENSOR_ADC_DATA_MSB) << 8) | adc_data[1];
++
++                              // return data
++                              if(put_user(read_data, (int __user *) arg))
++                                      return -EFAULT;
++                      }
++
++              }
++              break;
++
++      case BMI_SENSOR_TEMPWR:
++              {
++                      struct sensor_temp_rw *temp = NULL;
++                      unsigned char temp_addr;
++                      unsigned char temp_data;
++
++                      if(sensor->eeprom.temperature_present != SENSOR_DEVICE_PRESENT)
++                              return -ENODEV;
++
++                      if ((temp = kmalloc(sizeof(struct sensor_temp_rw), GFP_KERNEL)) == NULL)
++                              return -ENOMEM;
++                      if (copy_from_user(temp, (struct sensor_temp_rw *) arg, sizeof(struct sensor_temp_rw))) {
++                              kfree(temp);
++                              return -EFAULT;
++                      }
++
++                      temp_addr = temp->address;
++                      temp_data = temp->d1;
++                      if(WriteByte_TEMP(adap, temp_addr, temp_data)) {
++                              kfree(temp);
++                              return -ENODEV;
++                      }
++
++                      kfree(temp);
++              }
++              break;
++
++      case BMI_SENSOR_TEMPRD:
++              {
++                      struct sensor_temp_rw *temp = NULL;
++                      unsigned char temp_addr;
++                      unsigned char temp_data;
++
++                      if(sensor->eeprom.temperature_present != SENSOR_DEVICE_PRESENT)
++                              return -ENODEV;
++
++                      if ((temp = kmalloc(sizeof(struct sensor_temp_rw), GFP_KERNEL)) == NULL)
++                              return -ENOMEM;
++                      if (copy_from_user(temp, (struct sensor_temp_rw *) arg, sizeof(struct sensor_temp_rw))) {
++                              kfree(temp);
++                              return -EFAULT;
++                      }
++
++                      temp_addr = temp->address;
++                      if(ReadByte_TEMP(adap, temp_addr, &temp_data)) {
++                              kfree(temp);
++                              return -ENODEV;
++                      }
++
++                      temp->d1 = temp_data;
++                      if(copy_to_user((struct sensor_temp_rw *) arg, temp, sizeof(struct sensor_temp_rw))) {
++                              kfree(temp);
++                              return -EFAULT;
++                      }
++
++                      kfree(temp);
++              }
++              break;
++
++      case BMI_SENSOR_TEMPRD_SL:
++              {
++                      unsigned int read_data;
++                      unsigned char temp_datam;
++                      unsigned char temp_datal;
++
++                      if(sensor->eeprom.temperature_present != SENSOR_DEVICE_PRESENT)
++                              return -ENODEV;
++
++                      if(ReadByte_TEMP(adap, SENSOR_TEMP_LOC_MSB, &temp_datam)) {
++                              return -ENODEV;
++                      }
++
++                      if(ReadByte_TEMP(adap, SENSOR_TEMP_LOC_LSB, &temp_datal)) {
++                              return -ENODEV;
++                      }
++
++                      read_data = (temp_datam << 8) | temp_datal;
++                      if(put_user(read_data, (int __user *) arg))
++                              return -EFAULT;
++
++              }
++              break;
++
++      case BMI_SENSOR_TEMPRD_SR:
++              {
++                      unsigned int read_data;
++                      unsigned char temp_datam;
++                      unsigned char temp_datal;
++
++                      if(sensor->eeprom.temperature_present != SENSOR_DEVICE_PRESENT)
++                              return -ENODEV;
++
++                      if(ReadByte_TEMP(adap, SENSOR_TEMP_REM_MSB, &temp_datam)) {
++                              return -ENODEV;
++                      }
++
++                      if(ReadByte_TEMP(adap, SENSOR_TEMP_REM_LSB, &temp_datal)) {
++                              return -ENODEV;
++                      }
++
++                      read_data = (temp_datam << 8) | temp_datal;
++                      if(put_user(read_data, (int __user *) arg))
++                              return -EFAULT;
++
++              }
++              break;
++
++      case BMI_SENSOR_TEMPRD_UR:
++              {
++                      unsigned int read_data;
++                      unsigned char temp_datam;
++                      unsigned char temp_datal;
++
++                      if(sensor->eeprom.temperature_present != SENSOR_DEVICE_PRESENT)
++                              return -ENODEV;
++
++                      if(ReadByte_TEMP(adap, SENSOR_TEMP_UREM_MSB, &temp_datam)) {
++                              return -ENODEV;
++                      }
++
++                      if(ReadByte_TEMP(adap, SENSOR_TEMP_UREM_LSB, &temp_datal)) {
++                              return -ENODEV;
++                      }
++
++                      read_data = (temp_datam << 8) | temp_datal;
++                      if(put_user(read_data, (int __user *) arg))
++                              return -EFAULT;
++
++              }
++              break;
++
++      case BMI_SENSOR_TEMP_IWAIT:
++              {
++                      if(sensor->eeprom.temperature_present != SENSOR_DEVICE_PRESENT)
++                              return -ENODEV;
++
++                      ret = down_interruptible(&sensor->sem);
++                      sensor->temp_int_en = 1;
++                      sensor->temp_int_fl = 0;
++                      up(&sensor->sem);
++                      ret = wait_event_interruptible(sensor->temp_wait_queue, (sensor->temp_int_fl == 1));
++                      if(ret)
++                              return ret;
++              }
++              break;
++
++      case BMI_SENSOR_MOTRD:
++              {
++                      unsigned int read_data;
++
++                      if(sensor->eeprom.motion_present != SENSOR_DEVICE_PRESENT)
++                              return -ENODEV;
++
++                      read_data = bmi_slot_gpio_read_bit(slot, SENSOR_GPIO_MOT_DET);
++                      if(put_user(read_data, (int __user *) arg))
++                              return -EFAULT;
++
++              }
++              break;
++
++      case BMI_SENSOR_MOT_IWAIT:
++              {
++                      unsigned int read_data;
++
++                      if(sensor->eeprom.motion_present != SENSOR_DEVICE_PRESENT)
++                              return -ENODEV;
++
++                      ret = down_interruptible(&sensor->sem);
++                      sensor->mot_int_en = 1;
++                      sensor->mot_int_fl = 0;
++                      up(&sensor->sem);
++                      ret = wait_event_interruptible(sensor->mot_wait_queue, (sensor->mot_int_fl == 1));
++                      if(ret)
++                              return ret;
++
++                      read_data = bmi_slot_gpio_read_bit(slot, SENSOR_GPIO_MOT_DET);
++                      if(put_user(read_data, (int __user *) arg))
++                              return -EFAULT;
++
++              }
++              break;
++
++      case BMI_SENSOR_ACCWR:
++              {
++                      struct sensor_acc_rw *acc = NULL;
++
++                      if((sensor->eeprom.accel_present != SENSOR_DEVICE_PRESENT)
++                              && (sensor->eeprom.acc302_present != SENSOR_DEVICE_PRESENT))
++                              return -ENODEV;
++
++                      if ((acc = kmalloc(sizeof(struct sensor_acc_rw), GFP_KERNEL)) == NULL)
++                              return -ENOMEM;
++                      if (copy_from_user(acc, (struct sensor_acc_rw *) arg, sizeof(struct sensor_acc_rw))) {
++                              kfree(acc);
++                              return -EFAULT;
++                      }
++
++                      if(WriteByte_ACC(adap, acc)) {
++                              kfree(acc);
++                              return -ENODEV;
++                      }
++
++                      kfree(acc);
++              }
++              break;
++
++      case BMI_SENSOR_ACCRD:
++              {
++                      struct sensor_acc_rw *acc = NULL;
++
++                      if((sensor->eeprom.accel_present != SENSOR_DEVICE_PRESENT)
++                              && (sensor->eeprom.acc302_present != SENSOR_DEVICE_PRESENT))
++                              return -ENODEV;
++
++                      if ((acc = kmalloc(sizeof(struct sensor_acc_rw), GFP_KERNEL)) == NULL)
++                              return -ENOMEM;
++                      if (copy_from_user(acc, (struct sensor_acc_rw *) arg, sizeof(struct sensor_acc_rw))) {
++                              kfree(acc);
++                              return -EFAULT;
++                      }
++
++                      if(ReadByte_ACC(adap, acc)) {
++                              kfree(acc);
++                              return -ENODEV;
++                      }
++
++                      if(copy_to_user((struct sensor_acc_rw *) arg, acc, sizeof(struct sensor_acc_rw))) {
++                              kfree(acc);
++                              return -EFAULT;
++                      }
++
++                      kfree(acc);
++              }
++              break;
++
++      case BMI_SENSOR_ACCXRD:
++              {
++                      struct sensor_acc_rw *acc = NULL;
++                      unsigned int read_data;
++
++                      if(sensor->eeprom.accel_present == SENSOR_DEVICE_PRESENT) {
++
++                              if ((acc = kmalloc(sizeof(struct sensor_acc_rw), GFP_KERNEL)) == NULL)
++                                      return -ENOMEM;
++
++                              acc->address = SENSOR_ACC_DX0;
++                              acc->count = 2;
++
++                              if(ReadByte_ACC(adap, acc)) {
++                                      kfree(acc);
++                                      return -ENODEV;
++                              }
++
++                              read_data = (acc->data[1] << 8) | acc->data[0];
++                              if(put_user(read_data, (int __user *) arg)) {
++                                      kfree(acc);
++                                      return -EFAULT;
++                              }
++                      } else if(sensor->eeprom.acc302_present == SENSOR_DEVICE_PRESENT) {
++                              if ((acc = kmalloc(sizeof(struct sensor_acc_rw), GFP_KERNEL)) == NULL)
++                                      return -ENOMEM;
++
++                              acc->address = SENSOR_A3_OUTX;
++                              acc->count = 1;
++
++                              if(ReadByte_ACC(adap, acc)) {
++                                      kfree(acc);
++                                      return -ENODEV;
++                              }
++
++                              read_data = acc->data[0];
++                              if(put_user(read_data, (int __user *) arg)) {
++                                      kfree(acc);
++                                      return -EFAULT;
++                              }
++                      } else {
++                              return -ENODEV;
++                      }
++
++                      kfree(acc);
++              }
++              break;
++
++      case BMI_SENSOR_ACCYRD:
++              {
++                      struct sensor_acc_rw *acc = NULL;
++                      unsigned int read_data;
++
++                      if(sensor->eeprom.accel_present != SENSOR_DEVICE_PRESENT) {
++                              if ((acc = kmalloc(sizeof(struct sensor_acc_rw), GFP_KERNEL)) == NULL)
++                                      return -ENOMEM;
++
++                              acc->address = SENSOR_ACC_DY0;
++                              acc->count = 2;
++
++                              if(ReadByte_ACC(adap, acc)) {
++                                      kfree(acc);
++                                      return -ENODEV;
++                              }
++
++                              read_data = (acc->data[1] << 8) | acc->data[0];
++                              if(put_user(read_data, (int __user *) arg)) {
++                                      kfree(acc);
++                                      return -EFAULT;
++                              }
++                      } else if(sensor->eeprom.acc302_present == SENSOR_DEVICE_PRESENT) {
++                              if ((acc = kmalloc(sizeof(struct sensor_acc_rw), GFP_KERNEL)) == NULL)
++                                      return -ENOMEM;
++
++                              acc->address = SENSOR_A3_OUTY;
++                              acc->count = 1;
++
++                              if(ReadByte_ACC(adap, acc)) {
++                                      kfree(acc);
++                                      return -ENODEV;
++                              }
++
++                              read_data = acc->data[0];
++                              if(put_user(read_data, (int __user *) arg)) {
++                                      kfree(acc);
++                                      return -EFAULT;
++                              }
++                      } else {
++                              return -ENODEV;
++                      }
++
++                      kfree(acc);
++              }
++              break;
++
++      case BMI_SENSOR_ACCZRD:
++              {
++                      struct sensor_acc_rw *acc = NULL;
++                      unsigned int read_data;
++
++                      if(sensor->eeprom.accel_present != SENSOR_DEVICE_PRESENT) {
++                              if ((acc = kmalloc(sizeof(struct sensor_acc_rw), GFP_KERNEL)) == NULL)
++                                      return -ENOMEM;
++
++                              acc->address = SENSOR_ACC_DZ0;
++                              acc->count = 2;
++
++                              if(ReadByte_ACC(adap, acc)) {
++                                      kfree(acc);
++                                      return -ENODEV;
++                              }
++
++                              read_data = (acc->data[1] << 8) | acc->data[0];
++                              if(put_user(read_data, (int __user *) arg)) {
++                                      kfree(acc);
++                                      return -EFAULT;
++                              }
++                      } else if(sensor->eeprom.acc302_present == SENSOR_DEVICE_PRESENT) {
++                              if ((acc = kmalloc(sizeof(struct sensor_acc_rw), GFP_KERNEL)) == NULL)
++                                      return -ENOMEM;
++
++                              acc->address = SENSOR_A3_OUTZ;
++                              acc->count = 1;
++
++                              if(ReadByte_ACC(adap, acc)) {
++                                      kfree(acc);
++                                      return -ENODEV;
++                              }
++
++                              read_data = acc->data[0];
++                              if(put_user(read_data, (int __user *) arg)) {
++                                      kfree(acc);
++                                      return -EFAULT;
++                              }
++                      } else {
++                              return -ENODEV;
++                      }
++
++                      kfree(acc);
++              }
++              break;
++
++      case BMI_SENSOR_ACC_I1WAIT:
++              {
++                      if((sensor->eeprom.accel_present != SENSOR_DEVICE_PRESENT)
++                              && (sensor->eeprom.acc302_present != SENSOR_DEVICE_PRESENT))
++                              return -ENODEV;
++
++                      ret = down_interruptible(&sensor->sem);
++                      sensor->acc_int1_en = 1;
++                      sensor->acc_int1_fl = 0;
++                      up(&sensor->sem);
++                      ret = wait_event_interruptible(sensor->acc_wait1_queue, (sensor->acc_int1_fl == 1));
++                      if(ret)
++                              return ret;
++              }
++              break;
++
++      case BMI_SENSOR_ACC_I2WAIT:
++              {
++                      if((sensor->eeprom.accel_present != SENSOR_DEVICE_PRESENT)
++                              && (sensor->eeprom.acc302_present != SENSOR_DEVICE_PRESENT))
++                              return -ENODEV;
++
++                      ret = down_interruptible(&sensor->sem);
++                      sensor->acc_int2_en = 1;
++                      sensor->acc_int2_fl = 0;
++                      up(&sensor->sem);
++                      ret = wait_event_interruptible(sensor->acc_wait2_queue, (sensor->acc_int2_fl == 1));
++                      if(ret)
++                              return ret;
++              }
++              break;
++
++      case BMI_SENSOR_EEWR:
++              {
++                      struct sensor_rw *ee = NULL;
++                      unsigned char ee_addr;
++                      unsigned char ee_data;
++
++                      if ((ee = kmalloc(sizeof(struct sensor_rw), GFP_KERNEL)) == NULL)
++                              return -ENOMEM;
++                      if (copy_from_user(ee, (struct sensor_rw *) arg, sizeof(struct sensor_rw))) {
++                              kfree(ee);
++                              return -EFAULT;
++                      }
++
++                      ee_addr = ee->address;
++                      ee_data = ee->data;
++                      if(WriteByte_EE(adap, ee_addr, ee_data)) {
++                              kfree(ee);
++                              return -ENODEV;
++                      }
++
++                      kfree(ee);
++              }
++              break;
++
++      case BMI_SENSOR_EERD:
++              {
++                      struct sensor_rw *ee = NULL;
++                      unsigned char ee_addr;
++                      unsigned char ee_data;
++
++                      if ((ee = kmalloc(sizeof(struct sensor_rw), GFP_KERNEL)) == NULL)
++                              return -ENOMEM;
++                      if (copy_from_user(ee, (struct sensor_rw *) arg, sizeof(struct sensor_rw))) {
++                              kfree(ee);
++                              return -EFAULT;
++                      }
++
++                      ee_addr = ee->address;
++                      if(ReadByte_EE(adap, ee_addr, &ee_data)) {
++                              kfree(ee);
++                              return -ENODEV;
++                      }
++
++                      ee->data = ee_data;
++                      if(copy_to_user((struct sensor_rw *) arg, ee, sizeof(struct sensor_rw))) {
++                              kfree(ee);
++                              return -EFAULT;
++                      }
++
++                      kfree(ee);
++              }
++              break;
++
++      case BMI_SENSOR_MOT_IE:
++              {
++                      if(sensor->eeprom.motion_present != SENSOR_DEVICE_PRESENT)
++                              return -ENODEV;
++
++                      if(ReadByte_IOX(adap, IOX_OUTPUT0_REG, &iox_data))
++                              return -ENODEV;
++
++                      if(arg == BMI_SENSOR_ON)
++                              iox_data |= (0x1 << SENSOR_IOX_MOT_EN);
++                      else
++                              iox_data &= ~(0x1 << SENSOR_IOX_MOT_EN);
++
++                      if(WriteByte_IOX(adap, IOX_OUTPUT0_REG, iox_data))
++                              return -ENODEV;
++              }
++              break;
++
++      case BMI_SENSOR_USB_IWAIT:
++              {
++                      ret = down_interruptible(&sensor->sem);
++                      sensor->usb_int_en = 1;
++                      sensor->usb_int_fl = 0;
++                      up(&sensor->sem);
++                      ret = wait_event_interruptible(sensor->usb_wait_queue, (sensor->usb_int_fl == 1));
++                      if(ret)
++                              return ret;
++              }
++              break;
++
++      case BMI_SENSOR_USB_PWR_EN:
++              {
++                      if(ReadByte_IOX(adap, IOX_OUTPUT0_REG, &iox_data))
++                              return -ENODEV;
++
++                      if(arg == BMI_SENSOR_ON)
++                              iox_data |= (0x1 << SENSOR_IOX_USB_EN);
++                      else
++                              iox_data &= ~(0x1 << SENSOR_IOX_USB_EN);
++
++                      if(WriteByte_IOX(adap, IOX_OUTPUT0_REG, iox_data))
++                              return -ENODEV;
++              }
++              break;
++
++      case BMI_SENSOR_HUM_PWR_EN:
++              {
++                      if(ReadByte_IOX(adap, IOX_OUTPUT0_REG, &iox_data))
++                              return -ENODEV;
++
++                      if(arg == BMI_SENSOR_ON)
++                              iox_data |= (0x1 << SENSOR_IOX_HUM_EN);
++                      else
++                              iox_data &= ~(0x1 << SENSOR_IOX_HUM_EN);
++
++                      if(WriteByte_IOX(adap, IOX_OUTPUT0_REG, iox_data))
++                              return -ENODEV;
++              }
++              break;
++
++      case BMI_SENSOR_DCOM_RST:
++              {
++                      if(ReadByte_IOX(adap, IOX_OUTPUT0_REG, &iox_data))
++                              return -ENODEV;
++
++                      if(arg == BMI_SENSOR_ON)
++                              iox_data |= (0x1 << SENSOR_IOX_COMP_RS_N);
++                      else
++                              iox_data &= ~(0x1 << SENSOR_IOX_COMP_RS_N);
++
++                      if(WriteByte_IOX(adap, IOX_OUTPUT0_REG, iox_data))
++                              return -ENODEV;
++
++              }
++              break;
++
++      case BMI_SENSOR_COM_GCAL:
++              {
++                      struct sensor_comp_cal *cal = NULL;
++                      unsigned char ee_datam;
++                      unsigned char ee_datal;
++
++                      if ((cal = kmalloc(sizeof(struct sensor_comp_cal), GFP_KERNEL)) == NULL)
++                              return -ENOMEM;
++
++                      if(ReadByte_EE(adap, 0x0, &ee_datam)) {
++                              kfree(cal);
++                              return -ENODEV;
++                      }
++
++                      if(ReadByte_EE(adap, 0x1, &ee_datal)) {
++                              kfree(cal);
++                              return -ENODEV;
++                      }
++
++                      cal->xsf = (ee_datam << 8) | ee_datal;
++
++                      if(ReadByte_EE(adap, 0x2, &ee_datam)) {
++                              kfree(cal);
++                              return -ENODEV;
++                      }
++
++                      if(ReadByte_EE(adap, 0x3, &ee_datal)) {
++                              kfree(cal);
++                              return -ENODEV;
++                      }
++
++                      cal->ysf = (ee_datam << 8) | ee_datal;
++
++                      if(ReadByte_EE(adap, 0x4, &ee_datam)) {
++                              kfree(cal);
++                              return -ENODEV;
++                      }
++
++                      if(ReadByte_EE(adap, 0x5, &ee_datal)) {
++                              kfree(cal);
++                              return -ENODEV;
++                      }
++
++                      cal->zsf = (ee_datam << 8) | ee_datal;
++
++                      if(ReadByte_EE(adap, 0x6, &ee_datam)) {
++                              kfree(cal);
++                              return -ENODEV;
++                      }
++
++                      if(ReadByte_EE(adap, 0x7, &ee_datal)) {
++                              kfree(cal);
++                              return -ENODEV;
++                      }
++
++                      cal->xoff = (ee_datam << 8) | ee_datal;
++
++                      if(ReadByte_EE(adap, 0x8, &ee_datam)) {
++                              kfree(cal);
++                              return -ENODEV;
++                      }
++
++                      if(ReadByte_EE(adap, 0x9, &ee_datal)) {
++                              kfree(cal);
++                              return -ENODEV;
++                      }
++
++                      cal->yoff = (ee_datam << 8) | ee_datal;
++
++                      if(ReadByte_EE(adap, 0xA, &ee_datam)) {
++                              kfree(cal);
++                              return -ENODEV;
++                      }
++
++                      if(ReadByte_EE(adap, 0xB, &ee_datal)) {
++                              kfree(cal);
++                              return -ENODEV;
++                      }
++
++                      cal->zoff = (ee_datam << 8) | ee_datal;
++
++                      if(copy_to_user((struct sensor_comp_cal *) arg, cal, sizeof(struct sensor_comp_cal))) {
++                              kfree(cal);
++                              return -EFAULT;
++                      }
++
++                      kfree(cal);
++              }
++              break;
++
++      case BMI_SENSOR_COM_SCAL:
++              {
++                      struct sensor_comp_cal *cal = NULL;
++                      unsigned char ee_datam;
++                      unsigned char ee_datal;
++
++                      if ((cal = kmalloc(sizeof(struct sensor_comp_cal), GFP_KERNEL)) == NULL)
++                              return -ENOMEM;
++                      if (copy_from_user(cal, (struct sensor_comp_cal *) arg, sizeof(struct sensor_comp_cal))) {
++                              kfree(cal);
++                              return -EFAULT;
++                      }
++
++                      sensor->comp_xsf = cal->xsf;
++                      sensor->comp_ysf = cal->ysf;
++                      sensor->comp_zsf = cal->zsf;
++                      sensor->comp_xoff = cal->xoff;
++                      sensor->comp_xoff = cal->xoff;
++                      sensor->comp_zoff = cal->zoff;
++
++                      ee_datam = (unsigned char) ((cal->xsf >> 8) & 0xff);
++                      ee_datal = (unsigned char) (cal->xsf & 0xff);
++
++                      if(WriteByte_EE(adap, 0x0, ee_datam)) {
++                              kfree(cal);
++                              return -ENODEV;
++                      }
++
++                      if(WriteByte_EE(adap, 0x1, ee_datal)) {
++                              kfree(cal);
++                              return -ENODEV;
++                      }
++
++                      ee_datam = (unsigned char) ((cal->ysf >> 8) & 0xff);
++                      ee_datal = (unsigned char) (cal->ysf & 0xff);
++
++                      if(WriteByte_EE(adap, 0x2, ee_datam)) {
++                              kfree(cal);
++                              return -ENODEV;
++                      }
++
++                      if(WriteByte_EE(adap, 0x3, ee_datal)) {
++                              kfree(cal);
++                              return -ENODEV;
++                      }
++
++                      ee_datam = (unsigned char) ((cal->zsf >> 8) & 0xff);
++                      ee_datal = (unsigned char) (cal->zsf & 0xff);
++
++                      if(WriteByte_EE(adap, 0x4, ee_datam)) {
++                              kfree(cal);
++                              return -ENODEV;
++                      }
++
++                      if(WriteByte_EE(adap, 0x5, ee_datal)) {
++                              kfree(cal);
++                              return -ENODEV;
++                      }
++
++                      ee_datam = (unsigned char) ((cal->xoff >> 8) & 0xff);
++                      ee_datal = (unsigned char) (cal->xoff & 0xff);
++
++                      if(WriteByte_EE(adap, 0x6, ee_datam)) {
++                              kfree(cal);
++                              return -ENODEV;
++                      }
++
++                      if(WriteByte_EE(adap, 0x7, ee_datal)) {
++                              kfree(cal);
++                              return -ENODEV;
++                      }
++
++                      ee_datam = (unsigned char) ((cal->yoff >> 8) & 0xff);
++                      ee_datal = (unsigned char) (cal->yoff & 0xff);
++
++                      if(WriteByte_EE(adap, 0x8, ee_datam)) {
++                              kfree(cal);
++                              return -ENODEV;
++                      }
++
++                      if(WriteByte_EE(adap, 0x9, ee_datal)) {
++                              kfree(cal);
++                              return -ENODEV;
++                      }
++
++                      ee_datam = (unsigned char) ((cal->zoff >> 8) & 0xff);
++                      ee_datal = (unsigned char) (cal->zoff & 0xff);
++
++                      if(WriteByte_EE(adap, 0xA, ee_datam)) {
++                              kfree(cal);
++                              return -ENODEV;
++                      }
++
++                      if(WriteByte_EE(adap, 0xB, ee_datal)) {
++                              kfree(cal);
++                              return -ENODEV;
++                      }
++
++                      kfree(cal);
++              }
++              break;
++
++      case BMI_SENSOR_DCWR:
++              {
++                      struct sensor_rw *dc = NULL;
++                      unsigned char dc_addr;
++                      unsigned char dc_data;
++
++                      if(sensor->eeprom.dcompass_present != SENSOR_DEVICE_PRESENT)
++                              return -ENODEV;
++
++                      if ((dc = kmalloc(sizeof(struct sensor_rw), GFP_KERNEL)) == NULL)
++                              return -ENOMEM;
++                      if (copy_from_user(dc, (struct sensor_rw *) arg, sizeof(struct sensor_rw))) {
++                              kfree(dc);
++                              return -EFAULT;
++                      }
++
++                      dc_addr = dc->address;
++                      dc_data = dc->data;
++                      if(WriteByte_DCOMP(adap, dc_addr, dc_data)) {
++                              kfree(dc);
++                              return -ENODEV;
++                      }
++
++                      kfree(dc);
++              }
++              break;
++
++      case BMI_SENSOR_DCRD:
++              {
++                      struct sensor_rw *dc = NULL;
++                      unsigned char dc_addr;
++                      unsigned char dc_data;
++
++                      if(sensor->eeprom.dcompass_present != SENSOR_DEVICE_PRESENT)
++                              return -ENODEV;
++
++                      if ((dc = kmalloc(sizeof(struct sensor_rw), GFP_KERNEL)) == NULL)
++                              return -ENOMEM;
++                      if (copy_from_user(dc, (struct sensor_rw *) arg, sizeof(struct sensor_rw))) {
++                              kfree(dc);
++                              return -EFAULT;
++                      }
++
++                      dc_addr = dc->address;
++                      if(ReadByte_DCOMP(adap, dc_addr, &dc_data)) {
++                              kfree(dc);
++                              return -ENODEV;
++                      }
++
++                      dc->data = dc_data;
++                      if(copy_to_user((struct sensor_rw *) arg, dc, sizeof(struct sensor_rw))) {
++                              kfree(dc);
++                              return -EFAULT;
++                      }
++
++                      kfree(dc);
++              }
++              break;
++
++      case BMI_SENSOR_DC_GDAC:
++              {
++                      struct sensor_comp_dac *dac = NULL;
++
++                      if(sensor->eeprom.dcompass_present != SENSOR_DEVICE_PRESENT)
++                              return -ENODEV;
++
++                      if ((dac = kmalloc(sizeof(struct sensor_comp_dac), GFP_KERNEL)) == NULL)
++                              return -ENOMEM;
++
++                      dac->xdac = sensor->eeprom.xdac;
++                      dac->ydac = sensor->eeprom.ydac;
++                      dac->zdac = sensor->eeprom.zdac;
++
++                      if(copy_to_user((struct sensor_comp_dac *) arg, dac, sizeof(struct sensor_comp_dac))) {
++                              kfree(dac);
++                              return -EFAULT;
++                      }
++
++                      kfree(dac);
++              }
++              break;
++
++      case BMI_SENSOR_DC_SDAC:
++              {
++                      struct sensor_comp_dac *dac = NULL;
++
++                      if(sensor->eeprom.dcompass_present != SENSOR_DEVICE_PRESENT)
++                              return -ENODEV;
++
++                      if ((dac = kmalloc(sizeof(struct sensor_comp_dac), GFP_KERNEL)) == NULL)
++                              return -ENOMEM;
++                      if (copy_from_user(dac, (struct sensor_comp_dac *) arg, sizeof(struct sensor_comp_dac))) {
++                              kfree(dac);
++                              return -EFAULT;
++                      }
++
++                      sensor->eeprom.xdac = dac->xdac;
++                      sensor->eeprom.ydac = dac->ydac;
++                      sensor->eeprom.zdac = dac->zdac;
++
++                      if(WriteByte_EE(adap, SENSOR_EE_XDAC, dac->xdac & 0xFF)) {
++                              kfree(dac);
++                              return -ENODEV;
++                      }
++                      mdelay(5);
++
++                      if(WriteByte_EE(adap, SENSOR_EE_YDAC, dac->ydac & 0xFF)) {
++                              kfree(dac);
++                              return -ENODEV;
++                      }
++                      mdelay(5);
++
++                      if(WriteByte_EE(adap, SENSOR_EE_ZDAC, dac->zdac & 0xFF)) {
++                              kfree(dac);
++                              return -ENODEV;
++                      }
++                      mdelay(5);
++
++                      kfree(dac);
++              }
++              break;
++
++      case BMI_SENSOR_DC_IWAIT:
++              {
++                      if(sensor->eeprom.dcompass_present != SENSOR_DEVICE_PRESENT)
++                              return -ENODEV;
++
++                      ret = down_interruptible(&sensor->sem);
++                      sensor->dcomp_int_en = 1;
++                      sensor->dcomp_int_fl = 0;
++                      up(&sensor->sem);
++                      ret = wait_event_interruptible(sensor->dcomp_wait_queue, (sensor->dcomp_int_fl == 1));
++                      if(ret)
++                              return ret;
++              }
++              break;
++
++      case BMI_SENSOR_APROX_DUR:
++              {
++                      if(sensor->eeprom.aproximity_present != SENSOR_DEVICE_PRESENT)
++                              return -ENODEV;
++
++                      if(arg < 2)
++                              sensor->aprox_duration = HZ/50;
++                      else if(arg > 100)
++                              sensor->aprox_duration = HZ/10;
++                      else
++                              sensor->aprox_duration = (HZ/100) * arg;
++              }
++              break;
++
++      case BMI_SENSOR_APROXRD:
++              {
++                      unsigned char aprox_data[2];
++                      int read_data;
++
++                      if(sensor->eeprom.aproximity_present != SENSOR_DEVICE_PRESENT)
++                              return -ENODEV;
++
++                      // start burst to LED
++                      if(ReadByte_IOX(adap, IOX_INPUT1_REG, &iox_data))
++                              return -ENODEV;
++                      iox_data |= (0x1 << SENSOR_IOX_PROX_RST_N);
++                      if(WriteByte_IOX(adap, IOX_OUTPUT1_REG, iox_data))
++                              return -ENODEV;
++
++                      // set up timer
++                      sensor->aprox_timer.expires = jiffies + sensor->aprox_duration;
++                      add_timer (&sensor->aprox_timer);
++
++                      // wait for timer
++                      ret = down_interruptible(&sensor->sem);
++                      sensor->aprox_int_en = 1;
++                      sensor->aprox_int_fl = 0;
++                      up(&sensor->sem);
++                      ret = wait_event_interruptible(sensor->aprox_wait_queue, (sensor->aprox_int_fl == 1));
++                      if(ret)
++                              return ret;
++
++                      if(ReadByte_IOX(adap, IOX_INPUT1_REG, &iox_data))
++                              return -ENODEV;
++
++                      // digital output
++                      read_data = (iox_data & (0x1 << SENSOR_IOX_PROX_OUT)) << 14;
++
++                      // read ADC - analog output
++                      if(WriteByte_ADC(adap, SENSOR_ADC_APROXIMITY | SENSOR_ADC_PD_OFF))
++                              return -ENODEV;
++
++                      mdelay(1);
++
++                      if(ReadByte_ADC(adap, aprox_data))
++                              return -ENODEV;
++                      read_data |= (aprox_data[0] << 8) | aprox_data[1];
++
++                      // stop burst to LED
++                      iox_data &= ~(0x1 << SENSOR_IOX_PROX_RST_N);
++                      if(WriteByte_IOX(adap, IOX_OUTPUT1_REG, iox_data))
++                              return -ENODEV;
++
++                      if(put_user(read_data, (int __user *) arg))
++                              return -EFAULT;
++              }
++              break;
++
++      case BMI_SENSOR_ALIGHTRD:
++              {
++                      unsigned char adc_data[2];
++                      int read_data;
++
++                      if(sensor->eeprom.alight_present != SENSOR_DEVICE_PRESENT)
++                              return -ENODEV;
++
++                      if(WriteByte_ADC(adap, SENSOR_ADC_LIGHT | SENSOR_ADC_PD_OFF))
++                              return -ENODEV;
++
++                      mdelay(1);
++
++                      if(ReadByte_ADC(adap, adc_data))
++                              return -ENODEV;
++                      read_data = ((adc_data[0] & SENSOR_ADC_DATA_MSB) << 8) | adc_data[1];
++
++                      if(put_user(read_data, (int __user *) arg))
++                              return -EFAULT;
++              }
++              break;
++
++      case BMI_SENSOR_DLIGHTWR:
++              {
++                      struct sensor_dl_rw *dl = NULL;
++                      unsigned char dl_data;
++
++                      if(sensor->eeprom.dlight_present != SENSOR_DEVICE_PRESENT)
++                              return -ENODEV;
++
++                      if ((dl = kmalloc(sizeof(struct sensor_dl_rw), GFP_KERNEL)) == NULL)
++                              return -ENOMEM;
++                      if (copy_from_user(dl, (struct sensor_dl_rw *) arg, sizeof(struct sensor_dl_rw))) {
++                              kfree(dl);
++                              return -EFAULT;
++                      }
++
++                      dl_data = dl->cmd;
++                      if(WriteByte_PL(adap, SENSOR_DL_CMD, dl_data)) {
++                              kfree(dl);
++                              return -ENODEV;
++                      }
++
++                      dl_data = dl->control;
++                      if(WriteByte_PL(adap, SENSOR_DL_CONT, dl_data)) {
++                              kfree(dl);
++                              return -ENODEV;
++                      }
++
++                      dl_data = dl->int_thi;
++                      if(WriteByte_PL(adap, SENSOR_DL_INT_THI, dl_data)) {
++                              kfree(dl);
++                              return -ENODEV;
++                      }
++
++                      dl_data = dl->int_tlo;
++                      if(WriteByte_PL(adap, SENSOR_DL_INT_TLO, dl_data)) {
++                              kfree(dl);
++                              return -ENODEV;
++                      }
++
++                      kfree(dl);
++              }
++              break;
++
++      case BMI_SENSOR_DLIGHTRD:
++              {
++                      unsigned char dl_data;
++                      unsigned int read_data;
++
++                      if(sensor->eeprom.dlight_present != SENSOR_DEVICE_PRESENT)
++                              return -ENODEV;
++
++                      // read sensor data
++                      if(ReadByte_PL(adap, SENSOR_DL_SENSOR_MSB, &dl_data)) {
++                              return -ENODEV;
++                      }
++                      read_data = ((unsigned int) (dl_data)) << 8;
++
++                      if(ReadByte_PL(adap, SENSOR_DL_SENSOR_LSB, &dl_data)) {
++                              return -ENODEV;
++                      }
++                      read_data |= dl_data;
++
++                      if(put_user(read_data, (int __user *) arg))
++                              return -EFAULT;
++              }
++              break;
++
++      case BMI_SENSOR_DLIGHT_IC:
++              {
++                      if(sensor->eeprom.dlight_present != SENSOR_DEVICE_PRESENT)
++                              return -ENODEV;
++
++                      if(WriteByte_DL_IC(adap))
++                              return -ENODEV;
++              }
++              break;
++
++      case BMI_SENSOR_DLIGHT_IWAIT:
++              {
++                      struct sensor_dl_rw *dl = NULL;
++                      unsigned char dl_data;
++                      unsigned int read_data;
++
++                      if(sensor->eeprom.dlight_present != SENSOR_DEVICE_PRESENT)
++                              return -ENODEV;
++
++                      // write all register
++                      if ((dl = kmalloc(sizeof(struct sensor_dl_rw), GFP_KERNEL)) == NULL)
++                              return -ENOMEM;
++                      if (copy_from_user(dl, (struct sensor_dl_rw *) arg, sizeof(struct sensor_dl_rw))) {
++                              kfree(dl);
++                              return -EFAULT;
++                      }
++
++                      dl_data = dl->cmd;
++                      if(WriteByte_PL(adap, SENSOR_DL_CMD, dl_data)) {
++                              kfree(dl);
++                              return -ENODEV;
++                      }
++
++                      dl_data = dl->control;
++                      if(WriteByte_PL(adap, SENSOR_DL_CONT, dl_data)) {
++                              kfree(dl);
++                              return -ENODEV;
++                      }
++
++                      dl_data = dl->int_thi;
++                      if(WriteByte_PL(adap, SENSOR_DL_INT_THI, dl_data)) {
++                              kfree(dl);
++                              return -ENODEV;
++                      }
++
++                      dl_data = dl->int_tlo;
++                      if(WriteByte_PL(adap, SENSOR_DL_INT_TLO, dl_data)) {
++                              kfree(dl);
++                              return -ENODEV;
++                      }
++
++                      // enable interrupt
++                      ret = down_interruptible(&sensor->sem);
++                      sensor->dlight_int_en = 1;
++                      sensor->dlight_int_fl = 0;
++                      up(&sensor->sem);
++                      // wait on interrupt
++                      ret = wait_event_interruptible(sensor->dlight_wait_queue, (sensor->dlight_int_fl == 1));
++                      if(ret)
++                              return ret;
++
++                      // read sensor data
++                      if(ReadByte_PL(adap, SENSOR_DL_SENSOR_MSB, &dl_data)) {
++                              return -ENODEV;
++                      }
++                      read_data = ((unsigned int) (dl_data)) << 8;
++
++                      if(ReadByte_PL(adap, SENSOR_DL_SENSOR_LSB, &dl_data)) {
++                              return -ENODEV;
++                      }
++                      read_data |= dl_data;
++                      dl->sensor_data = read_data;
++
++                      if(copy_to_user((struct sensor_dl_rw *) arg, dl, sizeof(struct sensor_dl_rw))) {
++                              kfree(dl);
++                              return -EFAULT;
++                      }
++
++                      kfree(dl);
++              }
++              break;
++
++      case BMI_SENSOR_MIC_EN:
++              {
++                      if(sensor->eeprom.sound_present != SENSOR_DEVICE_PRESENT)
++                              return -ENODEV;
++
++                      if(ReadByte_IOX(adap, IOX_OUTPUT1_REG, &iox_data))
++                              return -ENODEV;
++
++                      if(arg == BMI_SENSOR_ON)
++                              iox_data |= (0x1 << SENSOR_IOX_MIC_EN);
++                      else
++                              iox_data &= ~(0x1 << SENSOR_IOX_MIC_EN);
++
++                      if(WriteByte_IOX(adap, IOX_OUTPUT1_REG, iox_data))
++                              return -ENODEV;
++              }
++              break;
++
++      default:
++              return -ENOTTY;
++      }
++
++      return 0;
++}
++
++// control file operations
++struct file_operations cntl_fops = {
++      .owner = THIS_MODULE,
++      .ioctl = cntl_ioctl,
++      .open = cntl_open,
++      .release = cntl_release,
++};
++
++/*
++ *    PIM functions
++ */
++
++// interrupt handler
++static void sensor_work_handler(struct work_struct * work)
++{
++      struct bmi_sensor *sensor = work_to_sensor(work);
++      struct i2c_adapter *adap = bmi_device_get_i2c_adapter(sensor->bdev);
++      int slot = bmi_device_get_slot(sensor->bdev);
++      unsigned char iox0;
++      unsigned char iox1;
++      unsigned char i2c_dummy;
++      struct sensor_acc_rw acc_rw;
++
++      if(ReadByte_IOX(adap, IOX_INPUT0_REG, &iox0)) {
++              printk(KERN_ERR "bmi_sensor.c: sensor_work_handler - IOX0 error\n");
++              return;
++      }
++
++      if(ReadByte_IOX(adap, IOX_INPUT1_REG, &iox1)) {
++              printk(KERN_ERR "bmi_sensor.c: sensor_work_handler - IOX1 error\n");
++              return;
++      }
++
++      if(sensor->eeprom.light_proximity_present == SENSOR_DEVICE_PRESENT) {
++              if(sensor->pl_int_en) {
++                      if((iox1 & (0x1 << SENSOR_IOX_PL_INT)) == 0) {
++                              sensor->pl_int_en = 0;
++                              sensor->pl_int_fl = 1;
++                              // clear interrupts
++                              if(ReadByte_PL(adap, SENSOR_PL_CMD1, &i2c_dummy)) {
++                                      printk(KERN_ERR "bmi_sensor.c: PL read error\n");
++                              }
++                              wake_up_all(&sensor->pl_wait_queue);
++                      }
++              }
++      }
++
++      if(sensor->eeprom.temperature_present == SENSOR_DEVICE_PRESENT) {
++              if(sensor->temp_int_en) {
++                      if((iox1 & (0x1 << SENSOR_IOX_TEMP_INT)) == 0) {
++                              sensor->temp_int_en = 0;
++                              sensor->temp_int_fl = 1;
++                              // disable interrupts
++                              if(WriteByte_TEMP(adap, SENSOR_TEMP_CONF1_WR, SENSOR_TEMP_CONF1_STOP)) {
++                                      printk(KERN_ERR "bmi_sensor.c: TEMP write error\n");
++                              }
++                              wake_up_all(&sensor->temp_wait_queue);
++                      }
++              }
++      }
++
++      if(sensor->eeprom.motion_present == SENSOR_DEVICE_PRESENT) {
++              if(sensor->mot_int_en) {
++                      if(sensor->mot_state != bmi_slot_gpio_read_bit(slot, SENSOR_GPIO_MOT_DET)) {
++                              sensor->mot_state = bmi_slot_gpio_read_bit(slot, SENSOR_GPIO_MOT_DET);
++                              sensor->mot_int_en = 0;
++                              sensor->mot_int_fl = 1;
++                              wake_up_all(&sensor->mot_wait_queue);
++                      }
++              }
++      }
++
++      if((sensor->eeprom.accel_present == SENSOR_DEVICE_PRESENT)
++              || (sensor->eeprom.acc302_present == SENSOR_DEVICE_PRESENT)) {
++              if(sensor->acc_int1_en) {
++                      if((iox0 & (0x1 << SENSOR_IOX_ACC_INT1)) == 0) {
++                              sensor->acc_int1_en = 0;
++                              sensor->acc_int1_fl = 1;
++                              wake_up_all(&sensor->acc_wait1_queue);
++                      }
++              }
++
++              if(sensor->acc_int2_en) {
++                      if((iox0 & (0x1 << SENSOR_IOX_ACC_INT2)) == 0) {
++                              sensor->acc_int2_en = 0;
++                              sensor->acc_int2_fl = 1;
++                              wake_up_all(&sensor->acc_wait2_queue);
++                      }
++              }
++
++              if(sensor->eeprom.accel_present == SENSOR_DEVICE_PRESENT)  {
++                      // clear interrupts
++                      acc_rw.address = SENSOR_ACC_IS;
++                      acc_rw.count = 1;
++                      if(ReadByte_ACC(adap, &acc_rw)) {
++                              printk(KERN_ERR "bmi_sensor.c: ACC_IS read error\n");
++                      }
++
++                      acc_rw.address = SENSOR_ACC_DX0;
++                      acc_rw.count = 2;
++                      if(ReadByte_ACC(adap, &acc_rw)) {
++                              printk(KERN_ERR "bmi_sensor.c: ACC read (DX0) error\n");
++                      }
++
++                      acc_rw.address = SENSOR_ACC_DY0;
++                      acc_rw.count = 2;
++                      if(ReadByte_ACC(adap, &acc_rw)) {
++                              printk(KERN_ERR "bmi_sensor.c: ACC read (DY0) error\n");
++                      }
++
++                      acc_rw.address = SENSOR_ACC_DZ0;
++                      acc_rw.count = 2;
++                      if(ReadByte_ACC(adap, &acc_rw)) {
++                              printk(KERN_ERR "bmi_sensor.c: ACC read (DZ0) error\n");
++                      }
++              } else { // LIS302DL
++                      // clear interrupts
++                      if(sensor->acc_int1_en) {
++                              if((iox0 & (0x1 << SENSOR_IOX_ACC_INT1)) == 0) {
++                                      acc_rw.address = SENSOR_A3_SRC1;
++                                      acc_rw.count = 1;
++                                      if(ReadByte_ACC(adap, &acc_rw)) {
++                                              printk(KERN_ERR "bmi_sensor.c: A3_SRC1 read error\n");
++                                      }
++                              }
++                      }
++
++                      if(sensor->acc_int2_en) {
++                              if((iox0 & (0x1 << SENSOR_IOX_ACC_INT2)) == 0) {
++                                      acc_rw.address = SENSOR_A3_SRC2;
++                                      acc_rw.count = 1;
++                                      if(ReadByte_ACC(adap, &acc_rw)) {
++                                              printk(KERN_ERR "bmi_sensor.c: A3_SRC2 read error\n");
++                                      }
++                              }
++                      }
++
++                      acc_rw.address = SENSOR_A3_STAT;
++                      acc_rw.count = 1;
++                      if(ReadByte_ACC(adap, &acc_rw)) {
++                              printk(KERN_ERR "bmi_sensor.c: A3_STAT read error\n");
++                      }
++
++                      acc_rw.address = SENSOR_A3_OUTX;
++                      acc_rw.count = 1;
++                      if(ReadByte_ACC(adap, &acc_rw)) {
++                              printk(KERN_ERR "bmi_sensor.c: A3 read (OUTX) error\n");
++                      }
++
++                      acc_rw.address = SENSOR_A3_OUTY;
++                      acc_rw.count = 1;
++                      if(ReadByte_ACC(adap, &acc_rw)) {
++                              printk(KERN_ERR "bmi_sensor.c: A3 read (OUTY) error\n");
++                      }
++
++                      acc_rw.address = SENSOR_A3_OUTZ;
++                      acc_rw.count = 1;
++                      if(ReadByte_ACC(adap, &acc_rw)) {
++                              printk(KERN_ERR "bmi_sensor.c: A3 read (OUTZ) error\n");
++                      }
++              }
++      }
++
++      if(sensor->eeprom.dcompass_present == SENSOR_DEVICE_PRESENT) {
++              if(sensor->dcomp_int_en) {
++                      if((iox1 & (0x1 << SENSOR_IOX_DCOMP_INT)) != 0) {
++                              sensor->dcomp_int_en = 0;
++                              sensor->dcomp_int_fl = 1;
++                              // clear interrupts
++                              if(ReadByte_DCOMP(adap, SENSOR_DCOMP_TMPS, &i2c_dummy)) {
++                                      printk(KERN_ERR "bmi_sensor.c: TMPS error\n");
++                              }
++
++                              wake_up_all(&sensor->dcomp_wait_queue);
++                      }
++              }
++      }
++
++      if(sensor->eeprom.dlight_present == SENSOR_DEVICE_PRESENT) {
++              if(sensor->dlight_int_en) {
++                      if((iox1 & (0x1 << SENSOR_IOX_PL_INT)) == 0) {
++                              sensor->dlight_int_en = 0;
++                              sensor->dlight_int_fl = 1;
++                              // clear interrupts
++                              if(ReadByte_PL(adap, SENSOR_DL_CONT, &i2c_dummy)) {
++                                      printk(KERN_ERR "bmi_sensor.c: DL read error\n");
++                              }
++                              i2c_dummy &= ~(SENSOR_DL_CONT_INT);
++                              if(WriteByte_PL(adap, SENSOR_DL_CONT, i2c_dummy)) {
++                                      printk(KERN_ERR "bmi_sensor.c: DL write error\n");
++                              }
++                              if(WriteByte_DL_IC(adap)) {
++                                      printk(KERN_ERR "bmi_sensor.c: DL interrupt clear error\n");
++                              }
++                              wake_up_all(&sensor->pl_wait_queue);
++                      }
++              }
++      }
++
++
++      if((iox0 & (0x1 << SENSOR_IOX_USB_FL_N)) == 0) {
++              sensor->usb_int_en = 0;
++              sensor->usb_int_fl = 1;
++              // disable USB power
++              if(ReadByte_IOX(adap, IOX_INPUT0_REG, &i2c_dummy)) // clear IOX interrupts
++                      printk(KERN_ERR "bmi_sensor.c: USB IOX read error\n");
++              wake_up_all(&sensor->usb_wait_queue);
++      }
++
++      return;
++}
++
++static irqreturn_t module_irq_handler(int irq, void *dummy)
++{
++      struct bmi_sensor *sensor = (struct bmi_sensor *) dummy;
++
++      schedule_work (&sensor->work_item);
++      return IRQ_HANDLED;
++}
++
++/*
++ *    BMI functions
++ */
++
++/*-------------------------------------
++ *
++ *    bmi device sysfs attributes
++ *
++ *-------------------------------------
++ */
++
++static ssize_t show_humidity(struct device *dev, struct device_attribute *attr, char *buf)
++{
++      struct bmi_device *bdev = dev_to_bmi_device(dev);
++      struct i2c_adapter *adap = bmi_device_get_i2c_adapter(bdev);
++      unsigned char adc_data[2];
++
++      if(WriteByte_ADC(adap, SENSOR_ADC_HUMIDITY)) {
++              printk(KERN_ERR "bmi_sensor.c: ADC write error\n");
++      }
++
++      mdelay(1);
++
++      if(ReadByte_ADC(adap, adc_data)) {
++              printk(KERN_ERR "bmi_sensor.c: ADC read error\n");
++      }
++
++      return sprintf(buf, "0x%x\n", (adc_data[0] << 8) | adc_data[1]);
++}
++static DEVICE_ATTR(humidity, S_IRUGO, show_humidity, NULL);
++
++static ssize_t show_acompass(struct device *dev, struct device_attribute *attr, char *buf)
++{
++      struct bmi_device *bdev = dev_to_bmi_device(dev);
++      struct i2c_adapter *adap = bmi_device_get_i2c_adapter(bdev);
++      unsigned char adc_data[2];
++      unsigned int compass_x;
++      unsigned int compass_y;
++      unsigned int compass_z;
++
++      if(WriteByte_ADC(adap, SENSOR_ADC_ACOMPASS_X)) {
++              printk(KERN_ERR "bmi_sensor.c: ADC write error\n");
++      }
++
++      mdelay(1);
++
++      if(ReadByte_ADC(adap, adc_data)) {
++              printk(KERN_ERR "bmi_sensor.c: ADC read error\n");
++      }
++      compass_x = (adc_data[0] << 8) | adc_data[1];
++
++      if(WriteByte_ADC(adap, SENSOR_ADC_ACOMPASS_Y)) {
++              printk(KERN_ERR "bmi_sensor.c: ADC write error\n");
++      }
++
++      mdelay(1);
++
++      if(ReadByte_ADC(adap, adc_data)) {
++              printk(KERN_ERR "bmi_sensor.c: ADC read error\n");
++      }
++      compass_y = (adc_data[0] << 8) | adc_data[1];
++
++      if(WriteByte_ADC(adap, SENSOR_ADC_ACOMPASS_Z)) {
++              printk(KERN_ERR "bmi_sensor.c: ADC write error\n");
++      }
++
++      mdelay(1);
++
++      if(ReadByte_ADC(adap, adc_data)) {
++              printk(KERN_ERR "bmi_sensor.c: ADC read error\n");
++      }
++      compass_z = (adc_data[0] << 8) | adc_data[1];
++
++      return sprintf(buf, "X=0x%x\nY=0x%x\nZ=0x%x\n",
++              compass_x, compass_y, compass_z);
++}
++static DEVICE_ATTR(acompass, S_IRUGO, show_acompass, NULL);
++
++static ssize_t show_dcompass(struct device *dev, struct device_attribute *attr, char *buf)
++{
++      struct bmi_device *bdev = dev_to_bmi_device(dev);
++      struct i2c_adapter *adap = bmi_device_get_i2c_adapter(bdev);
++      unsigned char compass_i;
++      unsigned char compass_t;
++      unsigned char compass_x;
++      unsigned char compass_y;
++      unsigned char compass_z;
++
++      if(WriteByte_DCOMP(adap, SENSOR_DCOMP_MS1, SENSOR_DCOMP_MS1_SENSOR)) {
++              printk(KERN_ERR "bmi_sensor.c: DCOMP MS1 write error\n");
++      }
++
++      mdelay(20);
++
++      if(ReadByte_DCOMP(adap, SENSOR_DCOMP_ST, &compass_i)) {
++              printk(KERN_ERR "bmi_sensor.c: ADC read error\n");
++      }
++      if((compass_i & SENSOR_DCOMP_ST_INT) == 0) {
++              printk(KERN_ERR "bmi_sensor.c: DCOMP interrupt error\n");
++      }
++
++      if(ReadByte_DCOMP(adap, SENSOR_DCOMP_TMPS, &compass_t)) {
++              printk(KERN_ERR "bmi_sensor.c: TMPS error\n");
++      }
++
++      if(ReadByte_DCOMP(adap, SENSOR_DCOMP_H1X, &compass_x)) {
++              printk(KERN_ERR "bmi_sensor.c: H1X error\n");
++      }
++
++      if(ReadByte_DCOMP(adap, SENSOR_DCOMP_H1Y, &compass_y)) {
++              printk(KERN_ERR "bmi_sensor.c: H1Y error\n");
++      }
++
++      if(ReadByte_DCOMP(adap, SENSOR_DCOMP_H1Z, &compass_z)) {
++              printk(KERN_ERR "bmi_sensor.c: H1Z error\n");
++      }
++
++      return sprintf(buf, "T=0x%x\nX=0x%x\nY=0x%x\nZ=0x%x\n",
++              compass_t, compass_x, compass_y, compass_z);
++}
++static DEVICE_ATTR(dcompass, S_IRUGO, show_dcompass, NULL);
++
++static ssize_t show_als(struct device *dev, struct device_attribute *attr, char *buf)
++{
++      struct bmi_device *bdev = dev_to_bmi_device(dev);
++      struct i2c_adapter *adap = bmi_device_get_i2c_adapter(bdev);
++      unsigned char pl_data[2];
++
++      if(WriteByte_PL(adap, SENSOR_PL_CMD1, SENSOR_PL_CMD1_ALS_1X)) {
++              printk(KERN_ERR "bmi_sensor.c: PL write error\n");
++      }
++
++      mdelay(20);
++
++      if(ReadByte_PL(adap, SENSOR_PL_DATA_MSB, &pl_data[0])) {
++              printk(KERN_ERR "bmi_sensor.c: PL read error\n");
++      }
++
++      if(ReadByte_PL(adap, SENSOR_PL_DATA_LSB, &pl_data[1])) {
++              printk(KERN_ERR "bmi_sensor.c: PL read error\n");
++      }
++
++      return sprintf(buf, "0x%x\n", (pl_data[0] << 8) | pl_data[1]);
++}
++static DEVICE_ATTR(als, S_IRUGO, show_als, NULL);
++
++static ssize_t show_ir(struct device *dev, struct device_attribute *attr, char *buf)
++{
++      struct bmi_device *bdev = dev_to_bmi_device(dev);
++      struct i2c_adapter *adap = bmi_device_get_i2c_adapter(bdev);
++      unsigned char pl_data[2];
++
++      if(WriteByte_PL(adap, SENSOR_PL_CMD1, SENSOR_PL_CMD1_IR_1X)) {
++              printk(KERN_ERR "bmi_sensor.c: PL write error\n");
++      }
++
++      mdelay(20);
++
++      if(ReadByte_PL(adap, SENSOR_PL_DATA_MSB, &pl_data[0])) {
++              printk(KERN_ERR "bmi_sensor.c: PL read error\n");
++      }
++
++      if(ReadByte_PL(adap, SENSOR_PL_DATA_LSB, &pl_data[1])) {
++              printk(KERN_ERR "bmi_sensor.c: PL read error\n");
++      }
++
++      return sprintf(buf, "0x%x\n", (pl_data[0] << 8) | pl_data[1]);
++}
++static DEVICE_ATTR(ir, S_IRUGO, show_ir, NULL);
++
++static ssize_t show_proximity(struct device *dev, struct device_attribute *attr, char *buf)
++{
++      struct bmi_device *bdev = dev_to_bmi_device(dev);
++      struct i2c_adapter *adap = bmi_device_get_i2c_adapter(bdev);
++      unsigned char pl_data[2];
++
++      if(WriteByte_PL(adap, SENSOR_PL_CMD1, SENSOR_PL_CMD1_PROX_1X)) {
++              printk(KERN_ERR "bmi_sensor.c: PL write error\n");
++      }
++
++      mdelay(20);
++
++      if(ReadByte_PL(adap, SENSOR_PL_DATA_MSB, &pl_data[0])) {
++              printk(KERN_ERR "bmi_sensor.c: PL read error\n");
++      }
++
++      if(ReadByte_PL(adap, SENSOR_PL_DATA_LSB, &pl_data[1])) {
++              printk(KERN_ERR "bmi_sensor.c: PL read error\n");
++      }
++
++      return sprintf(buf, "0x%x\n", (pl_data[0] << 8) | pl_data[1]);
++}
++static DEVICE_ATTR(proximity, S_IRUGO, show_proximity, NULL);
++
++static ssize_t show_snda(struct device *dev, struct device_attribute *attr, char *buf)
++{
++      struct bmi_device *bdev = dev_to_bmi_device(dev);
++      struct i2c_adapter *adap = bmi_device_get_i2c_adapter(bdev);
++      unsigned char adc_data[2];
++
++      if(WriteByte_ADC(adap, SENSOR_ADC_SOUND_AVG)) {
++              printk(KERN_ERR "bmi_sensor.c: ADC write error\n");
++      }
++
++      mdelay(1);
++
++      if(ReadByte_ADC(adap, adc_data)) {
++              printk(KERN_ERR "bmi_sensor.c: ADC read error\n");
++      }
++
++      return sprintf(buf, "0x%x\n", (adc_data[0] << 8) | adc_data[1]);
++}
++static DEVICE_ATTR(sound_avg, S_IRUGO, show_snda, NULL);
++
++static ssize_t show_sndp(struct device *dev, struct device_attribute *attr, char *buf)
++{
++      struct bmi_device *bdev = dev_to_bmi_device(dev);
++      struct i2c_adapter *adap = bmi_device_get_i2c_adapter(bdev);
++      unsigned char adc_data[2];
++
++      if(WriteByte_ADC(adap, SENSOR_ADC_SOUND_PEAK)) {
++              printk(KERN_ERR "bmi_sensor.c: ADC write error\n");
++      }
++
++      mdelay(1);
++
++      if(ReadByte_ADC(adap, adc_data)) {
++              printk(KERN_ERR "bmi_sensor.c: ADC read error\n");
++      }
++
++      return sprintf(buf, "0x%x\n", (adc_data[0] << 8) | adc_data[1]);
++}
++static DEVICE_ATTR(sound_peak, S_IRUGO, show_sndp, NULL);
++
++static ssize_t show_temp_l(struct device *dev, struct device_attribute *attr, char *buf)
++{
++      struct bmi_device *bdev = dev_to_bmi_device(dev);
++      struct i2c_adapter *adap = bmi_device_get_i2c_adapter(bdev);
++      unsigned char temp_datam;
++      unsigned char temp_datal;
++
++      if(WriteByte_TEMP(adap, SENSOR_TEMP_CONF1_WR, SENSOR_TEMP_CONF1_STOP)) {
++              printk(KERN_ERR "bmi_sensor.c: TEMP write (CONF1) error\n");
++      }
++
++      if(WriteByte_TEMP(adap, SENSOR_TEMP_ONE_SHOT, 0x0)) {
++              printk(KERN_ERR "bmi_sensor.c: TEMP write (CONF1) error\n");
++      }
++
++      mdelay(400);
++
++      if(ReadByte_TEMP(adap, SENSOR_TEMP_LOC_MSB, &temp_datam)) {
++              printk(KERN_ERR "bmi_sensor.c: TEMP read (LOCAL MSB) error\n");
++      }
++
++      if(ReadByte_TEMP(adap, SENSOR_TEMP_LOC_LSB, &temp_datal)) {
++              printk(KERN_ERR "bmi_sensor.c: TEMP read (LOCAL LSB) error\n");
++      }
++
++      return sprintf(buf, "0x%x\n", (temp_datam << 8) | temp_datal);
++}
++static DEVICE_ATTR(temp_local, S_IRUGO, show_temp_l, NULL);
++
++static ssize_t show_temp_sr(struct device *dev, struct device_attribute *attr, char *buf)
++{
++      struct bmi_device *bdev = dev_to_bmi_device(dev);
++      struct i2c_adapter *adap = bmi_device_get_i2c_adapter(bdev);
++      unsigned char temp_datam;
++      unsigned char temp_datal;
++
++      if(WriteByte_TEMP(adap, SENSOR_TEMP_CONF1_WR, SENSOR_TEMP_CONF1_STOP)) {
++              printk(KERN_ERR "bmi_sensor.c: TEMP write (CONF1) error\n");
++      }
++
++      if(WriteByte_TEMP(adap, SENSOR_TEMP_ONE_SHOT, 0x0)) {
++              printk(KERN_ERR "bmi_sensor.c: TEMP write (CONF1) error\n");
++      }
++
++      mdelay(400);
++
++      if(ReadByte_TEMP(adap, SENSOR_TEMP_REM_MSB, &temp_datam)) {
++              printk(KERN_ERR "bmi_sensor.c: TEMP read (REM MSB) error\n");
++      }
++
++      if(ReadByte_TEMP(adap, SENSOR_TEMP_REM_LSB, &temp_datal)) {
++              printk(KERN_ERR "bmi_sensor.c: TEMP read (REM LSB) error\n");
++      }
++
++      return sprintf(buf, "0x%x\n", (temp_datam << 8) | temp_datal);
++}
++static DEVICE_ATTR(temp_sremote, S_IRUGO, show_temp_sr, NULL);
++
++static ssize_t show_temp_ur(struct device *dev, struct device_attribute *attr, char *buf)
++{
++      struct bmi_device *bdev = dev_to_bmi_device(dev);
++      struct i2c_adapter *adap = bmi_device_get_i2c_adapter(bdev);
++      unsigned char temp_datam;
++      unsigned char temp_datal;
++
++      if(WriteByte_TEMP(adap, SENSOR_TEMP_CONF1_WR, SENSOR_TEMP_CONF1_STOP)) {
++              printk(KERN_ERR "bmi_sensor.c: TEMP write (CONF1) error\n");
++      }
++
++      if(WriteByte_TEMP(adap, SENSOR_TEMP_ONE_SHOT, 0x0)) {
++              printk(KERN_ERR "bmi_sensor.c: TEMP write (CONF1) error\n");
++      }
++
++      mdelay(400);
++
++      if(ReadByte_TEMP(adap, SENSOR_TEMP_UREM_MSB, &temp_datam)) {
++              printk(KERN_ERR "bmi_sensor.c: TEMP read (UREM MSB) error\n");
++      }
++
++      if(ReadByte_TEMP(adap, SENSOR_TEMP_UREM_LSB, &temp_datal)) {
++              printk(KERN_ERR "bmi_sensor.c: TEMP read (UREM LSB) error\n");
++      }
++
++      return sprintf(buf, "0x%x\n", (temp_datam << 8) | temp_datal);
++}
++static DEVICE_ATTR(temp_uremote, S_IRUGO, show_temp_ur, NULL);
++
++static ssize_t show_motion(struct device *dev, struct device_attribute *attr, char *buf)
++{
++      struct bmi_device *bdev = dev_to_bmi_device(dev);
++      int slot = bmi_device_get_slot(bdev);
++
++      return sprintf(buf, "0x%x\n", bmi_slot_gpio_read_bit(slot, SENSOR_GPIO_MOT_DET));
++}
++static DEVICE_ATTR(motion, S_IRUGO, show_motion, NULL);
++
++static ssize_t show_accel(struct device *dev, struct device_attribute *attr, char *buf)
++{
++      struct bmi_device *bdev = dev_to_bmi_device(dev);
++      int slot = bmi_device_get_slot(bdev);
++      struct i2c_adapter *adap = bmi_device_get_i2c_adapter(bdev);
++      struct sensor_acc_rw acc_rw;
++      int x;
++      int y;
++      int z;
++
++      if(bmi_sensor[slot].eeprom.accel_present != SENSOR_DEVICE_PRESENT) {
++              acc_rw.address = SENSOR_ACC_DX0;
++              acc_rw.count = 2;
++              if(ReadByte_ACC(adap, &acc_rw)) {
++                      printk(KERN_ERR "bmi_sensor.c: ACC read (DX0) error\n");
++              }
++              x = (acc_rw.data[0] << 8) | acc_rw.data[1];
++
++              acc_rw.address = SENSOR_ACC_DY0;
++              acc_rw.count = 2;
++              if(ReadByte_ACC(adap, &acc_rw)) {
++                      printk(KERN_ERR "bmi_sensor.c: ACC read (DY0) error\n");
++              }
++              y = (acc_rw.data[0] << 8) | acc_rw.data[1];
++
++              acc_rw.address = SENSOR_ACC_DZ0;
++              acc_rw.count = 2;
++              if(ReadByte_ACC(adap, &acc_rw)) {
++                      printk(KERN_ERR "bmi_sensor.c: ACC read (DZ0) error\n");
++              }
++              z = (acc_rw.data[0] << 8) | acc_rw.data[1];
++      } else {
++              acc_rw.address = SENSOR_A3_OUTX;
++              acc_rw.count = 1;
++              if(ReadByte_ACC(adap, &acc_rw)) {
++                      printk(KERN_ERR "bmi_sensor.c: ACC read (OUTX) error\n");
++              }
++              x = acc_rw.data[0];
++
++              acc_rw.address = SENSOR_A3_OUTY;
++              acc_rw.count = 1;
++              if(ReadByte_ACC(adap, &acc_rw)) {
++                      printk(KERN_ERR "bmi_sensor.c: ACC read (OUTY) error\n");
++              }
++              y = acc_rw.data[0];
++
++              acc_rw.address = SENSOR_A3_OUTZ;
++              acc_rw.count = 1;
++              if(ReadByte_ACC(adap, &acc_rw)) {
++                      printk(KERN_ERR "bmi_sensor.c: ACC read (OUTZ) error\n");
++              }
++              z = acc_rw.data[0];
++      }
++      return sprintf(buf, "X=0x%x\nY=0x%x\nZ=0x%x\n", x, y, z);
++}
++static DEVICE_ATTR(accel, S_IRUGO, show_accel, NULL);
++
++static ssize_t show_aprox(struct device *dev, struct device_attribute *attr, char *buf)
++{
++      struct bmi_device *bdev = dev_to_bmi_device(dev);
++      int slot = bmi_device_get_slot(bdev);
++      struct bmi_sensor *sensor = &bmi_sensor[slot];
++      struct i2c_adapter *adap = bmi_device_get_i2c_adapter(bdev);
++      unsigned int read_data;
++      unsigned char iox_data;
++      unsigned char aprox_data;
++      int ret;
++
++      // start burst to LED
++      if(ReadByte_IOX(adap, IOX_INPUT1_REG, &iox_data))
++              printk(KERN_ERR "bmi_sensor.c: IOX read error\n");
++      iox_data |= (0x1 << SENSOR_IOX_PROX_RST_N);
++      if(WriteByte_IOX(adap, IOX_OUTPUT1_REG, iox_data))
++              printk(KERN_ERR "bmi_sensor.c: IOX write error\n");
++
++      // set up timer
++      sensor->aprox_timer.expires = jiffies + sensor->aprox_duration;
++      add_timer (&sensor->aprox_timer);
++
++      // wait for timer
++      ret = down_interruptible(&sensor->sem);
++      sensor->aprox_int_en = 1;
++      sensor->aprox_int_fl = 0;
++      up(&sensor->sem);
++      wait_event_interruptible(sensor->aprox_wait_queue, (sensor->aprox_int_fl == 1));
++
++      // stop burst to LED
++      if(ReadByte_IOX(adap, IOX_INPUT1_REG, &iox_data))
++              printk(KERN_ERR "bmi_sensor.c: IOX read error\n");
++      iox_data &= ~(0x1 << SENSOR_IOX_PROX_RST_N);
++      if(WriteByte_IOX(adap, IOX_OUTPUT1_REG, iox_data))
++              printk(KERN_ERR "bmi_sensor.c: IOX write error\n");
++
++      // digital output
++      read_data = (iox_data & (0x1 << SENSOR_IOX_PROX_OUT)) << 14;
++
++      // read ADC - analog output
++      if(WriteByte_ADC(adap, SENSOR_ADC_APROXIMITY | SENSOR_ADC_PD_OFF))
++              printk(KERN_ERR "bmi_sensor.c: IOX write error\n");
++
++      mdelay(1);
++
++      if(ReadByte_ADC(adap, &aprox_data))
++              printk(KERN_ERR "bmi_sensor.c: IOX read error\n");
++      read_data |= aprox_data;
++
++      return sprintf(buf, "Analog Proxiimity = 0x%x\n", read_data);
++}
++static DEVICE_ATTR(aprox, S_IRUGO, show_aprox, NULL);
++
++static ssize_t show_alight(struct device *dev, struct device_attribute *attr, char *buf)
++{
++      struct bmi_device *bdev = dev_to_bmi_device(dev);
++      struct i2c_adapter *adap = bmi_device_get_i2c_adapter(bdev);
++      unsigned char adc_data[2];
++
++      if(WriteByte_ADC(adap, SENSOR_ADC_LIGHT)) {
++              printk(KERN_ERR "bmi_sensor.c: ADC write error\n");
++      }
++
++      mdelay(1);
++
++      if(ReadByte_ADC(adap, adc_data)) {
++              printk(KERN_ERR "bmi_sensor.c: ADC read error\n");
++      }
++
++      return sprintf(buf, "0x%x\n", (adc_data[0] << 8) | adc_data[1]);
++}
++static DEVICE_ATTR(alight, S_IRUGO, show_alight, NULL);
++
++static ssize_t show_dlight(struct device *dev, struct device_attribute *attr, char *buf)
++{
++      struct bmi_device *bdev = dev_to_bmi_device(dev);
++      struct i2c_adapter *adap = bmi_device_get_i2c_adapter(bdev);
++      unsigned char dl_data[2];
++
++      if(ReadByte_PL(adap, SENSOR_DL_SENSOR_MSB, &dl_data[0])) {
++              printk(KERN_ERR "bmi_sensor.c: DL read error\n");
++      }
++
++      if(ReadByte_PL(adap, SENSOR_DL_SENSOR_LSB, &dl_data[1])) {
++              printk(KERN_ERR "bmi_sensor.c: DL read error\n");
++      }
++
++      return sprintf(buf, "0x%x\n", (dl_data[0] << 8) | dl_data[1]);
++}
++static DEVICE_ATTR(dlight, S_IRUGO, show_dlight, NULL);
++
++
++// read calibration/equipage EEPROM
++int read_eeprom(struct i2c_adapter *adap, struct sensor_eeprom_raw *eeprom)
++{
++      unsigned char ee_data;
++
++      if(ReadByte_EE(adap, 0x0, &ee_data))
++              return -ENODEV;
++      eeprom->xsf_msb = (__u8) ee_data;
++
++      if(ReadByte_EE(adap, 0x1, &ee_data))
++              return -ENODEV;
++      eeprom->xsf_lsb = (__u8) ee_data;
++
++      if(ReadByte_EE(adap, 0x2, &ee_data))
++              return -ENODEV;
++      eeprom->ysf_msb = (__u8) ee_data;
++
++      if(ReadByte_EE(adap, 0x3, &ee_data))
++              return -ENODEV;
++      eeprom->ysf_lsb = (__u8) ee_data;
++
++      if(ReadByte_EE(adap, 0x4, &ee_data))
++              return -ENODEV;
++      eeprom->zsf_msb = (__u8) ee_data;
++
++      if(ReadByte_EE(adap, 0x5, &ee_data))
++              return -ENODEV;
++      eeprom->zsf_lsb = (__u8) ee_data;
++
++      if(ReadByte_EE(adap, 0x6, &ee_data))
++              return -ENODEV;
++      eeprom->xoff_msb = (__u8) ee_data;
++
++      if(ReadByte_EE(adap, 0x7, &ee_data))
++              return -ENODEV;
++      eeprom->xoff_lsb = (__u8) ee_data;
++
++      if(ReadByte_EE(adap, 0x8, &ee_data))
++              return -ENODEV;
++      eeprom->yoff_msb = (__u8) ee_data;
++
++      if(ReadByte_EE(adap, 0x9, &ee_data))
++              return -ENODEV;
++      eeprom->zoff_lsb = (__u8) ee_data;
++
++      if(ReadByte_EE(adap, 0xA, &ee_data))
++              return -ENODEV;
++      eeprom->zoff_msb = (__u8) ee_data;
++
++      if(ReadByte_EE(adap, 0xB, &ee_data))
++              return -ENODEV;
++      eeprom->yoff_lsb = (__u8) ee_data;
++
++      if(ReadByte_EE(adap, 0xC, &ee_data))
++              return -ENODEV;
++      eeprom->xdac = (__u8) ee_data;
++
++      if(ReadByte_EE(adap, 0xD, &ee_data))
++              return -ENODEV;
++      eeprom->ydac = (__u8) ee_data;
++
++      if(ReadByte_EE(adap, 0xE, &ee_data))
++              return -ENODEV;
++      eeprom->zdac = (__u8) ee_data;
++
++      if(ReadByte_EE(adap, 0xF, &ee_data))
++              return -ENODEV;
++      eeprom->adc_present = (__u8) ee_data;
++
++      if(ReadByte_EE(adap, 0x10, &ee_data))
++              return -ENODEV;
++      eeprom->humidity_present = (__u8) ee_data;
++
++      if(ReadByte_EE(adap, 0x11, &ee_data))
++              return -ENODEV;
++      eeprom->acompass_present = (__u8) ee_data;
++
++      if(ReadByte_EE(adap, 0x12, &ee_data))
++              return -ENODEV;
++      eeprom->light_proximity_present = (__u8) ee_data;
++
++      if(ReadByte_EE(adap, 0x13, &ee_data))
++              return -ENODEV;
++      eeprom->sound_present = (__u8) ee_data;
++
++      if(ReadByte_EE(adap, 0x14, &ee_data))
++              return -ENODEV;
++      eeprom->temperature_present = (__u8) ee_data;
++
++      if(ReadByte_EE(adap, 0x15, &ee_data))
++              return -ENODEV;
++      eeprom->motion_present = (__u8) ee_data;
++
++      if(ReadByte_EE(adap, 0x16, &ee_data))
++              return -ENODEV;
++      eeprom->accel_present = (__u8) ee_data;
++
++      if(ReadByte_EE(adap, 0x17, &ee_data))
++              return -ENODEV;
++      eeprom->dcompass_present = (__u8) ee_data;
++
++      if(ReadByte_EE(adap, 0x18, &ee_data))
++              return -ENODEV;
++      eeprom->aproximity_present = (__u8) ee_data;
++
++      if(ReadByte_EE(adap, 0x19, &ee_data))
++              return -ENODEV;
++      eeprom->alight_present = (__u8) ee_data;
++
++      if(ReadByte_EE(adap, 0x1A, &ee_data))
++              return -ENODEV;
++      eeprom->dlight_present = (__u8) ee_data;
++
++      if(ReadByte_EE(adap, 0x1B, &ee_data))
++              return -ENODEV;
++      eeprom->acc302_present = (__u8) ee_data;
++
++      return 0;
++}
++
++// probe - insert PIM
++int bmi_sensor_probe(struct bmi_device *bdev)
++{
++      int err = 0;
++      int slot = bmi_device_get_slot(bdev);
++      struct bmi_sensor *sensor = &bmi_sensor[slot];
++      struct i2c_adapter *adap = bmi_device_get_i2c_adapter(bdev);
++      struct cdev *cdev;
++      struct class *bmi_class;
++      dev_t dev_id;
++      int irq;
++      unsigned char iox_data;
++
++      sensor->bdev = 0;
++
++      // Create 1 minor device
++      cdev = &sensor->cdev;
++      cdev_init(cdev, &cntl_fops);
++
++      dev_id = MKDEV(major, slot);
++      err = cdev_add(cdev, dev_id, 1);
++      if(err) {
++              return err;
++      }
++
++      // Create class device
++      bmi_class = bmi_get_bmi_class();
++      sensor->class_dev = device_create(bmi_class, NULL,
++                                  MKDEV(major, slot), NULL,
++                                  "bmi_sensor_cntl_m%i", slot+1);
++
++      if(IS_ERR(sensor->class_dev)) {
++              printk(KERN_ERR "Unable to create "
++                     "class_device for bmi_sensor_cntl_m%i; errno = %ld\n",
++                     slot+1, PTR_ERR(sensor->class_dev));
++              goto error;
++      }
++
++      // bind driver and bmi_device
++      sensor->bdev = bdev;
++      bmi_device_set_drvdata(bdev, sensor);
++
++      printk(KERN_INFO "bmi_sensor.c: probe slot %d\n", slot);
++
++      // configure IOX
++      if(factory_test || fcc_test) {
++              if(WriteByte_IOX(adap, IOX_OUTPUT0_REG, 0x98)) {  // USB/HUM on, MOT_INT off, COMPASS RST High
++                      printk(KERN_ERR "bmi_sensor.c: IOX error in slot %d\n", slot);
++                      goto error;
++              }
++
++              if(WriteByte_IOX(adap, IOX_OUTPUT1_REG, 0x08)) {  // Speaker Peak Clear, all other outputs low
++                      printk(KERN_ERR "bmi_sensor.c: IOX error in slot %d\n", slot);
++                      goto error;
++              }
++      } else {
++              if(WriteByte_IOX(adap, IOX_OUTPUT0_REG, 0x80)) {  // USB/HUM/MOT_INT off, COMPASS RST High
++                      printk(KERN_ERR "bmi_sensor.c: IOX error in slot %d\n", slot);
++                      goto error;
++              }
++
++              if(WriteByte_IOX(adap, IOX_OUTPUT1_REG, 0x0A)) {  // Speaker Peak Clear/analog proximity enable high, all other outputs low
++                      printk(KERN_ERR "bmi_sensor.c: IOX error in slot %d\n", slot);
++                      goto error;
++              }
++      }
++
++      if(WriteByte_IOX(adap, IOX_CONTROL0_REG, 0x27)) {     // IOX[5,2:0]=IN, IOX[7:6,4:3]=OUT
++              printk(KERN_ERR "bmi_sensor.c: IOX error in slot %d\n", slot);
++              goto error;
++      }
++
++      if(WriteByte_IOX(adap, IOX_CONTROL1_REG, 0xb4)) {     // IOX[7,5:4,2]=IN, IOX[6,3,1:0]=OUT
++              printk(KERN_ERR "bmi_sensor.c: IOX error in slot %d\n", slot);
++              goto error;
++      }
++
++      // Initialize GPIOs (turn LED's on)
++      bmi_slot_gpio_configure_as_output(slot, SENSOR_GPIO_RED_LED, SENSOR_GPIO_LED_ON);       // Red LED=ON
++      bmi_slot_gpio_configure_as_output(slot, SENSOR_GPIO_GREEN_LED, SENSOR_GPIO_LED_ON);     // Green LED=ON
++      bmi_slot_gpio_configure_as_input(slot, SENSOR_GPIO_PDOUT);                              // proximity real-time state
++      bmi_slot_gpio_configure_as_input(slot, SENSOR_GPIO_MOT_DET);                            // motion real-time state
++
++      mdelay(200);
++
++      // turn LED's off
++      bmi_slot_gpio_write_bit(slot, SENSOR_GPIO_RED_LED, SENSOR_GPIO_LED_OFF);                // Red LED=OFF
++      bmi_slot_gpio_write_bit(slot, SENSOR_GPIO_GREEN_LED, SENSOR_GPIO_LED_OFF);              // Green LED=OFF
++
++      // bmi_sensor initialization
++      init_MUTEX(&sensor->sem);
++      sprintf(sensor->work_name, "sensor_m%d", slot + 1);
++      init_waitqueue_head(&sensor->pl_wait_queue);
++      sensor->pl_int_en = 0;
++      sensor->pl_int_fl = 0;
++      init_waitqueue_head(&sensor->temp_wait_queue);
++      sensor->temp_int_en = 0;
++      sensor->temp_int_fl = 0;
++      init_waitqueue_head(&sensor->mot_wait_queue);
++      sensor->mot_int_en = 0;
++      sensor->mot_int_fl = 0;
++      sensor->mot_state = bmi_slot_gpio_read_bit(slot, SENSOR_GPIO_MOT_DET);                  // initial motion detector state
++      init_waitqueue_head(&sensor->acc_wait1_queue);
++      sensor->acc_int1_en = 0;
++      sensor->acc_int1_fl = 0;
++      init_waitqueue_head(&sensor->acc_wait2_queue);
++      sensor->acc_int2_en = 0;
++      sensor->acc_int2_fl = 0;
++      init_waitqueue_head(&sensor->usb_wait_queue);
++      sensor->usb_int_en = 0;
++      sensor->usb_int_fl = 0;
++      init_waitqueue_head(&sensor->dcomp_wait_queue);
++      sensor->dcomp_int_en = 0;
++      sensor->dcomp_int_fl = 0;
++      sensor->aprox_duration = 200;
++      init_timer(&sensor->aprox_timer);
++      sensor->aprox_timer.data = (unsigned long) &bmi_sensor[slot];
++      sensor->aprox_timer.function = aptimer;
++      init_waitqueue_head(&sensor->aprox_wait_queue);
++      sensor->aprox_int_en = 0;
++      sensor->aprox_int_fl = 0;
++
++      sensor->workqueue = create_singlethread_workqueue(sensor->work_name);
++      if (!sensor->workqueue) {
++              printk(KERN_ERR "bmi_sensor.c: Can't create_singlethread_workqueue() in slot %d\n",
++                      slot);
++              goto error;
++      }
++      INIT_WORK(&sensor->work_item, sensor_work_handler);
++
++      // initialize EEPROM for presence
++      if(factory_test && eeprom_init) {
++              unsigned char addr = SENSOR_PRESENT_START;
++
++              // presence
++              while(addr <= SENSOR_PRESENT_END) {
++                      if(eeprom_init & 0x1) {
++                              WriteByte_EE(adap, addr++, SENSOR_DEVICE_PRESENT);
++                      } else {
++                              WriteByte_EE(adap, addr++, SENSOR_DEVICE_NOT_PRESENT);
++                      }
++                      eeprom_init = eeprom_init >> 1;
++                      mdelay(5);
++              }
++      }
++
++      if(factory_test && xdac_init) {
++              WriteByte_EE(adap, SENSOR_EE_XDAC, xdac_init & 0xFF);
++              mdelay(5);
++      }
++
++      if(factory_test && ydac_init) {
++              WriteByte_EE(adap, SENSOR_EE_YDAC, ydac_init & 0xFF);
++              mdelay(5);
++      }
++
++      if(factory_test && zdac_init) {
++              WriteByte_EE(adap, SENSOR_EE_ZDAC, zdac_init & 0xFF);
++              mdelay(5);
++      }
++
++      // read EEPROM for calibration/presence
++      if(read_eeprom(adap, &sensor->eeprom)) {
++              printk(KERN_ERR "bmi_sensor.c: Can't read calibration EEPROM in slot %d\n",
++                      slot);
++              goto error;
++      }
++
++      sensor->comp_xsf = (sensor->eeprom.xsf_msb << 8) | sensor->eeprom.xsf_lsb;
++      sensor->comp_ysf = (sensor->eeprom.ysf_msb << 8) | sensor->eeprom.ysf_lsb;
++      sensor->comp_zsf = (sensor->eeprom.zsf_msb << 8) | sensor->eeprom.zsf_lsb;
++      sensor->comp_xoff = (sensor->eeprom.xoff_msb << 8) | sensor->eeprom.xoff_lsb;
++      sensor->comp_yoff = (sensor->eeprom.yoff_msb << 8) | sensor->eeprom.yoff_lsb;
++      sensor->comp_zoff = (sensor->eeprom.zoff_msb << 8) | sensor->eeprom.zoff_lsb;
++
++      if(sensor->eeprom.adc_present == SENSOR_DEVICE_PRESENT) {
++              unsigned char adc_data[2];
++
++              if(WriteByte_ADC(adap, SENSOR_ADC_CH0)) {
++                      printk(KERN_ERR "bmi_sensor.c: ADC write error\n");
++                      goto error;
++              }
++
++              mdelay(1);
++
++              if(ReadByte_ADC(adap, adc_data)) {
++                      printk(KERN_ERR "bmi_sensor.c: ADC read error\n");
++                      goto error;
++              }
++
++              if((adc_data[0] & 0xF0) != 0x0) {
++                      printk(KERN_ERR "bmi_sensor.c: ADC compare error\n");
++                      goto error;
++              }
++
++              if(factory_test == 1) {
++                      printk(KERN_INFO "bmi_sensor.c: ADC present in slot %d\n", slot);
++              }
++      }
++
++      if(sensor->eeprom.humidity_present == SENSOR_DEVICE_PRESENT) {
++              unsigned char adc_data[2];
++
++              if(WriteByte_ADC(adap, SENSOR_ADC_HUMIDITY)) {
++                      printk(KERN_ERR "bmi_sensor.c: ADC write (Humidity) error\n");
++                      goto error;
++              }
++
++              mdelay(1);
++
++              if(ReadByte_ADC(adap, adc_data)) {
++                      printk(KERN_ERR "bmi_sensor.c: ADC read (Humidity) error\n");
++                      goto error;
++              }
++
++              printk(KERN_INFO "bmi_sensor.c: initial Humidity = %d\n",
++                      (adc_data[0] << 8) | adc_data[1]);
++
++              if(device_create_file(&sensor->bdev->dev, &dev_attr_humidity)) {
++                      printk (KERN_ERR
++                      "bmi_sensor.c (%d): attr (humidity) failed.\n",
++                      slot);
++                      goto sysfs_err1;
++              }
++
++              if(factory_test == 1) {
++                      printk(KERN_INFO "bmi_sensor.c: HUMIDITY Sensor present in slot %d\n", slot);
++              }
++      }
++
++      if(sensor->eeprom.acompass_present == SENSOR_DEVICE_PRESENT) {
++              unsigned char adc_data[2];
++              unsigned int compass_x;
++              unsigned int compass_y;
++              unsigned int compass_z;
++
++              if(WriteByte_ADC(adap, SENSOR_ADC_ACOMPASS_X)) {
++                      printk(KERN_ERR "bmi_sensor.c: ADC write error\n");
++                      goto sysfs_err1;
++
++              }
++
++              mdelay(1);
++
++              if(ReadByte_ADC(adap, adc_data)) {
++                      printk(KERN_ERR "bmi_sensor.c: ADC read error\n");
++                      device_remove_file(&sensor->bdev->dev, &dev_attr_humidity);
++                      goto sysfs_err1;
++              }
++              compass_x = (adc_data[0] << 8) | adc_data[1];
++
++              if(WriteByte_ADC(adap, SENSOR_ADC_ACOMPASS_Y)) {
++                      printk(KERN_ERR "bmi_sensor.c: ADC write error\n");
++                      goto sysfs_err1;
++              }
++
++              mdelay(1);
++
++              if(ReadByte_ADC(adap, adc_data)) {
++                      printk(KERN_ERR "bmi_sensor.c: ADC read error\n");
++                      goto sysfs_err1;
++              }
++              compass_y = (adc_data[0] << 8) | adc_data[1];
++
++              if(WriteByte_ADC(adap, SENSOR_ADC_ACOMPASS_Z)) {
++                      printk(KERN_ERR "bmi_sensor.c: ADC write error\n");
++                      goto sysfs_err1;
++              }
++
++              mdelay(1);
++
++              if(ReadByte_ADC(adap, adc_data)) {
++                      printk(KERN_ERR "bmi_sensor.c: ADC read error\n");
++                      goto sysfs_err1;
++              }
++              compass_z = (adc_data[0] << 8) | adc_data[1];
++
++              printk(KERN_INFO "bmi_sensor.c: initial COMPASS (X,Y,Z) = %d,%d,%d\n",
++                      compass_x, compass_y, compass_z);
++
++              if(device_create_file(&sensor->bdev->dev, &dev_attr_acompass)) {
++                      printk (KERN_ERR
++                      "bmi_sensor.c (%d): attr (acompass) failed.\n",
++                      slot);
++                      goto sysfs_err1;
++              }
++
++              if(factory_test == 1) {
++                      printk(KERN_INFO "bmi_sensor.c: ACOMPASS Sensor present in slot %d\n", slot);
++              }
++      }
++
++      if(sensor->eeprom.dcompass_present == SENSOR_DEVICE_PRESENT) {
++              unsigned char hxga;
++              unsigned char hyga;
++              unsigned char hzga;
++              unsigned char compass_i;
++              unsigned char compass_t;
++              unsigned char compass_x;
++              unsigned char compass_y;
++              unsigned char compass_z;
++
++              if(WriteByte_DCOMP(adap, SENSOR_DCOMP_MS1, SENSOR_DCOMP_MS1_EEPROM)) {
++                      printk(KERN_ERR "bmi_sensor.c: DCOMP_MS1 write error\n");
++                      goto sysfs_err2;
++              }
++
++              if(ReadByte_DCOMP(adap, SENSOR_DCOMP_EE_EHXGA, &hxga)) {
++                      printk(KERN_ERR "bmi_sensor.c: EE_EHXGA read error\n");
++                      goto sysfs_err2;
++              }
++
++              if(ReadByte_DCOMP(adap, SENSOR_DCOMP_EE_EHYGA, &hyga)) {
++                      printk(KERN_ERR "bmi_sensor.c: EE_EHYGA read error\n");
++                      goto sysfs_err2;
++              }
++
++              if(ReadByte_DCOMP(adap, SENSOR_DCOMP_EE_EHZGA, &hzga)) {
++                      printk(KERN_ERR "bmi_sensor.c: EE_EHZGA read error\n");
++                      goto sysfs_err2;
++              }
++
++              if(WriteByte_DCOMP(adap, SENSOR_DCOMP_MS1, SENSOR_DCOMP_MS1_PD)) {
++                      printk(KERN_ERR "bmi_sensor.c: DCOMP_MS1 write error\n");
++                      goto sysfs_err2;
++              }
++
++              if(WriteByte_DCOMP(adap, SENSOR_DCOMP_HXGA, hxga)) {
++                      printk(KERN_ERR "bmi_sensor.c: DCOMP_HXGA write error\n");
++                      goto sysfs_err2;
++              }
++
++              if(WriteByte_DCOMP(adap, SENSOR_DCOMP_HYGA, hyga)) {
++                      printk(KERN_ERR "bmi_sensor.c: DCOMP_HYGA write error\n");
++                      goto sysfs_err2;
++              }
++
++              if(WriteByte_DCOMP(adap, SENSOR_DCOMP_HZGA, hzga)) {
++                      printk(KERN_ERR "bmi_sensor.c: DCOMP_HZGA write error\n");
++                      goto sysfs_err2;
++              }
++
++              if(WriteByte_DCOMP(adap, SENSOR_DCOMP_HXDA, sensor->eeprom.xdac)) {
++                      printk(KERN_ERR "bmi_sensor.c: DCOMP_HXDA write error\n");
++                      goto sysfs_err2;
++
++              }
++
++              if(WriteByte_DCOMP(adap, SENSOR_DCOMP_HYDA, sensor->eeprom.ydac)) {
++                      printk(KERN_ERR "bmi_sensor.c: DCOMP_HYDA write error\n");
++                      goto sysfs_err2;
++
++              }
++
++              if(WriteByte_DCOMP(adap, SENSOR_DCOMP_HZDA, sensor->eeprom.zdac)) {
++                      printk(KERN_ERR "bmi_sensor.c: DCOMP_HZDA write error\n");
++                      goto sysfs_err2;
++
++              }
++
++              if(WriteByte_DCOMP(adap, SENSOR_DCOMP_MS1, SENSOR_DCOMP_MS1_SENSOR)) {
++                      printk(KERN_ERR "bmi_sensor.c: DCOMP_MS1 write error\n");
++                      goto sysfs_err2;
++
++              }
++
++              mdelay(20);
++
++              if(ReadByte_DCOMP(adap, SENSOR_DCOMP_ST, &compass_i)) {
++                      printk(KERN_ERR "bmi_sensor.c: DCOMP_ST read error\n");
++                      goto sysfs_err2;
++              }
++
++              if((compass_i & SENSOR_DCOMP_ST_INT) == 0) {
++                      printk(KERN_ERR "bmi_sensor.c: DCOMP interrupt error\n");
++                      goto sysfs_err2;
++              }
++
++              if(ReadByte_DCOMP(adap, SENSOR_DCOMP_TMPS, &compass_t)) {
++                      printk(KERN_ERR "bmi_sensor.c: DCOMP_TMPS error\n");
++                      goto sysfs_err2;
++              }
++
++              if(ReadByte_DCOMP(adap, SENSOR_DCOMP_H1X, &compass_x)) {
++                      printk(KERN_ERR "bmi_sensor.c: DCOMP_H1X error\n");
++                      goto sysfs_err2;
++              }
++
++              if(ReadByte_DCOMP(adap, SENSOR_DCOMP_H1Y, &compass_y)) {
++                      printk(KERN_ERR "bmi_sensor.c: DCOMP_H1Y error\n");
++                      goto sysfs_err2;
++              }
++
++              if(ReadByte_DCOMP(adap, SENSOR_DCOMP_H1Z, &compass_z)) {
++                      printk(KERN_ERR "bmi_sensor.c: DCOMP_H1Z error\n");
++                      goto sysfs_err2;
++              }
++
++              printk(KERN_INFO "bmi_sensor.c: initial COMPASS (T,X,Y,Z) = 0x%x,0x%x,0x%x,0x%x\n",
++                      compass_t, compass_x, compass_y, compass_z);
++
++              if(device_create_file(&sensor->bdev->dev, &dev_attr_dcompass)) {
++                      printk (KERN_ERR
++                      "bmi_sensor.c (%d): attr (dcompass) failed.\n",
++                      slot);
++                      goto sysfs_err2;
++              }
++
++              if(factory_test == 1) {
++                      printk(KERN_INFO "bmi_sensor.c: DCOMPASS Sensor present in slot %d\n", slot);
++              }
++      }
++
++      if(sensor->eeprom.light_proximity_present == SENSOR_DEVICE_PRESENT) {
++              unsigned char pl_data[2];
++
++              if(WriteByte_PL(adap, SENSOR_PL_CMD1, SENSOR_PL_CMD1_ALS_1X)) {
++                      printk(KERN_ERR "bmi_sensor.c: PL write (ALS) error\n");
++                      goto sysfs_err3;
++              }
++
++              if(ReadByte_PL(adap, SENSOR_PL_DATA_MSB, &pl_data[0])) {
++                      printk(KERN_ERR "bmi_sensor.c: PL read (ALS) error\n");
++                      goto sysfs_err3;
++              }
++
++              if(ReadByte_PL(adap, SENSOR_PL_DATA_MSB, &pl_data[1])) {
++                      printk(KERN_ERR "bmi_sensor.c: PL read (ALS) error\n");
++                      goto sysfs_err3;
++              }
++              printk(KERN_INFO "bmi_sensor.c: initial PL ALS = %d\n",
++                      (pl_data[0] << 8) | pl_data[1]);
++
++              if(device_create_file(&sensor->bdev->dev, &dev_attr_als)) {
++                      printk (KERN_ERR
++                      "bmi_sensor.c (%d): attr (ALS) failed.\n",
++                      slot);
++                      goto sysfs_err3;
++              }
++
++              if(WriteByte_PL(adap, SENSOR_PL_CMD1, SENSOR_PL_CMD1_IR_1X)) {
++                      printk(KERN_ERR "bmi_sensor.c: PL write (IR) error\n");
++                      goto sysfs_err4;
++              }
++
++              mdelay(20);
++
++              if(ReadByte_PL(adap, SENSOR_PL_DATA_MSB, &pl_data[0])) {
++                      printk(KERN_ERR "bmi_sensor.c: ADC read (IR) error\n");
++                      goto sysfs_err4;
++              }
++
++              if(ReadByte_PL(adap, SENSOR_PL_DATA_MSB, &pl_data[1])) {
++                      printk(KERN_ERR "bmi_sensor.c: ADC read (IR) error\n");
++                      goto sysfs_err4;
++              }
++              printk(KERN_INFO "bmi_sensor.c: initial IR = %d\n",
++                      (pl_data[0] << 8) | pl_data[1]);
++
++              if(device_create_file(&sensor->bdev->dev, &dev_attr_ir)) {
++                      printk (KERN_ERR
++                      "bmi_sensor.c (%d): attr (IR) failed.\n",
++                      slot);
++                      goto sysfs_err4;
++              }
++
++              if(WriteByte_PL(adap, SENSOR_PL_CMD1, SENSOR_PL_CMD1_PROX_1X)) {
++                      printk(KERN_ERR "bmi_sensor.c: PL write (Proximity) error\n");
++                      goto sysfs_err5;
++              }
++
++              mdelay(20);
++
++              if(ReadByte_PL(adap, SENSOR_PL_DATA_MSB, &pl_data[0])) {
++                      printk(KERN_ERR "bmi_sensor.c: ADC read (Proximity) error\n");
++                      goto sysfs_err5;
++              }
++
++              if(ReadByte_PL(adap, SENSOR_PL_DATA_MSB, &pl_data[1])) {
++                      printk(KERN_ERR "bmi_sensor.c: ADC read (Proximity) error\n");
++                      goto sysfs_err5;
++              }
++              printk(KERN_INFO "bmi_sensor.c: initial Proximity = %d\n",
++                      (pl_data[0] << 8) | pl_data[1]);
++
++              if(device_create_file(&sensor->bdev->dev, &dev_attr_proximity)) {
++                      printk (KERN_ERR
++                      "bmi_sensor.c (%d): attr (Proximity) failed.\n",
++                      slot);
++                      goto sysfs_err5;
++              }
++
++              if(factory_test == 1) {
++                      printk(KERN_INFO "bmi_sensor.c: Combined LIGHT/PROXIMITY Sensor present in slot %d\n", slot);
++              }
++      }
++
++      if(sensor->eeprom.sound_present == SENSOR_DEVICE_PRESENT) {
++              unsigned char adc_data[2];
++
++              if(WriteByte_ADC(adap, SENSOR_ADC_SOUND_AVG)) {
++                      printk(KERN_ERR "bmi_sensor.c: ADC write (Sound Average) error\n");
++                      goto sysfs_err6;
++              }
++
++              mdelay(1);
++
++              if(ReadByte_ADC(adap, adc_data)) {
++                      printk(KERN_ERR "bmi_sensor.c: ADC read (Sound Average) error\n");
++                      goto sysfs_err6;
++              }
++
++              printk(KERN_INFO "bmi_sensor.c: initial Sound Average = %d\n",
++                      (adc_data[0] << 8) | adc_data[1]);
++
++              if(device_create_file(&sensor->bdev->dev, &dev_attr_sound_avg)) {
++                      printk (KERN_ERR
++                      "bmi_sensor.c (%d): attr (Sound Average) failed.\n",
++                      slot);
++                      goto sysfs_err6;
++              }
++
++              if(WriteByte_ADC(adap, SENSOR_ADC_SOUND_PEAK)) {
++                      printk(KERN_ERR "bmi_sensor.c: ADC write (Sound Peak) error\n");
++                      goto sysfs_err7;
++              }
++
++              mdelay(1);
++
++              if(ReadByte_ADC(adap, adc_data)) {
++                      printk(KERN_ERR "bmi_sensor.c: ADC read (Sound Peak) error\n");
++                      goto sysfs_err7;
++              }
++
++              printk(KERN_INFO "bmi_sensor.c: initial Sound Peak = %d\n",
++                      (adc_data[0] << 8) | adc_data[1]);
++
++              if(device_create_file(&sensor->bdev->dev, &dev_attr_sound_peak)) {
++                      printk (KERN_ERR
++                      "bmi_sensor.c (%d): attr (Sound Peak) failed.\n",
++                      slot);
++                      goto sysfs_err7;
++              }
++
++              if(factory_test == 1) {
++                      printk(KERN_INFO "bmi_sensor.c: SOUND PRESSURE Sensor present in slot %d\n", slot);
++              }
++      }
++
++      if(sensor->eeprom.temperature_present == SENSOR_DEVICE_PRESENT) {
++              unsigned char temp_datam;
++              unsigned char temp_datal;
++
++              if(ReadByte_TEMP(adap, SENSOR_TEMP_MAN_ID, &temp_datam)) {
++                      printk(KERN_ERR "bmi_sensor.c: TEMP read (Manufacturer ID) error\n");
++                      goto sysfs_err8;
++              }
++
++              if(temp_datam != SENSOR_TEMP_MAN_ID_DATA) {
++                      printk(KERN_ERR "bmi_sensor.c: TEMP MAN ID error (read=0x%x, expected=0x%x\n",
++                              temp_datam, SENSOR_TEMP_MAN_ID_DATA);
++                      goto sysfs_err8;
++              }
++
++              printk(KERN_INFO "bmi_sensor.c: TEMP Manufacturer ID = 0x%x\n", temp_datam);
++
++              if(ReadByte_TEMP(adap, SENSOR_TEMP_REV_ID, &temp_datam)) {
++                      printk(KERN_ERR "bmi_sensor.c: TEMP read (Revision ID) error\n");
++                      goto sysfs_err8;
++              }
++
++              if(temp_datam != SENSOR_TEMP_REV_ID_DATA) {
++                      printk(KERN_ERR "bmi_sensor.c: TEMP REV ID error (read=0x%x, expected=0x%x\n",
++                              temp_datam, SENSOR_TEMP_REV_ID_DATA);
++                      goto sysfs_err8;
++              }
++
++              printk(KERN_INFO "bmi_sensor.c: TEMP Revision ID = 0x%x\n", temp_datam);
++
++              if(WriteByte_TEMP(adap, SENSOR_TEMP_CONF2, 0x0)) {
++                      printk(KERN_ERR "bmi_sensor.c: TEMP write (CONF2) error\n");
++                      goto sysfs_err8;
++              }
++
++              if(WriteByte_TEMP(adap, SENSOR_TEMP_CONF1_WR, SENSOR_TEMP_CONF1_STOP)) {
++                      printk(KERN_ERR "bmi_sensor.c: TEMP write (CONF1) error\n");
++                      goto sysfs_err8;
++              }
++
++              if(WriteByte_TEMP(adap, SENSOR_TEMP_CONV_WR, SENSOR_TEMP_CONV_P364)) {
++                      printk(KERN_ERR "bmi_sensor.c: TEMP write (CONF1) error\n");
++                      goto sysfs_err8;
++              }
++
++              if(WriteByte_TEMP(adap, SENSOR_TEMP_ONE_SHOT, 0x0)) {
++                      printk(KERN_ERR "bmi_sensor.c: TEMP write (CONF1) error\n");
++                      goto sysfs_err8;
++              }
++
++              mdelay(400);
++
++              if(ReadByte_TEMP(adap, SENSOR_TEMP_LOC_MSB, &temp_datam)) {
++                      printk(KERN_ERR "bmi_sensor.c: TEMP read (LOCAL MSB) error\n");
++                      goto sysfs_err8;
++              }
++
++              if(ReadByte_TEMP(adap, SENSOR_TEMP_LOC_LSB, &temp_datal)) {
++                      printk(KERN_ERR "bmi_sensor.c: TEMP read (LOCAL LSB) error\n");
++                      goto sysfs_err8;
++              }
++
++              printk(KERN_INFO "bmi_sensor.c: initial Local temperature = 0x%x\n",
++                      (temp_datam << 8) | temp_datal);
++
++              if(device_create_file(&sensor->bdev->dev, &dev_attr_temp_local)) {
++                      printk (KERN_ERR
++                      "bmi_sensor.c (%d): attr (TEMP local) failed.\n",
++                      slot);
++                      goto sysfs_err8;
++              }
++
++              if(ReadByte_TEMP(adap, SENSOR_TEMP_REM_MSB, &temp_datam)) {
++                      printk(KERN_ERR "bmi_sensor.c: TEMP read (REM MSB) error\n");
++                      goto sysfs_err9;
++              }
++
++              if(ReadByte_TEMP(adap, SENSOR_TEMP_REM_LSB, &temp_datal)) {
++                      printk(KERN_ERR "bmi_sensor.c: TEMP read (REM LSB) error\n");
++                      goto sysfs_err9;
++              }
++
++              printk(KERN_INFO "bmi_sensor.c: initial Remote temperature = 0x%x\n",
++                      (temp_datam << 8) | temp_datal);
++
++              if(device_create_file(&sensor->bdev->dev, &dev_attr_temp_sremote)) {
++                      printk (KERN_ERR
++                      "bmi_sensor.c (%d): attr (TEMP sremote) failed.\n",
++                      slot);
++                      goto sysfs_err9;
++              }
++
++              if(ReadByte_TEMP(adap, SENSOR_TEMP_UREM_MSB, &temp_datam)) {
++                      printk(KERN_ERR "bmi_sensor.c: TEMP read (UREM MSB) error\n");
++                      goto sysfs_err10;
++              }
++
++              if(ReadByte_TEMP(adap, SENSOR_TEMP_UREM_LSB, &temp_datal)) {
++                      printk(KERN_ERR "bmi_sensor.c: TEMP read (UREM LSB) error\n");
++                      goto sysfs_err10;
++              }
++
++              if(device_create_file(&sensor->bdev->dev, &dev_attr_temp_uremote)) {
++                      printk (KERN_ERR
++                      "bmi_sensor.c (%d): attr (TEMP uremote) failed.\n",
++                      slot);
++                      goto sysfs_err10;
++              }
++
++              printk(KERN_INFO "bmi_sensor.c: initial Remote temperature (unsigned) = 0x%x\n",
++                      (temp_datam << 8) | temp_datal);
++
++              if(factory_test == 1) {
++                      printk(KERN_INFO "bmi_sensor.c: TEMPERATURE Sensor present in slot %d\n", slot);
++              }
++      }
++
++      if(sensor->eeprom.motion_present == SENSOR_DEVICE_PRESENT) {
++              if(device_create_file(&sensor->bdev->dev, &dev_attr_motion)) {
++                      printk (KERN_ERR
++                      "bmi_sensor.c (%d): attr (motion) failed.\n",
++                      slot);
++                      goto sysfs_err11;
++              }
++
++              printk(KERN_INFO "bmi_sensor.c: initial Motion state = 0x%x\n",
++                      bmi_slot_gpio_read_bit(slot, SENSOR_GPIO_MOT_DET));
++
++              if(factory_test == 1) {
++                      printk(KERN_INFO "bmi_sensor.c: MOTION Sensor present in slot %d\n", slot);
++              }
++      }
++
++      if(sensor->eeprom.accel_present == SENSOR_DEVICE_PRESENT) {
++              struct sensor_acc_rw acc_rw;
++
++              acc_rw.address = SENSOR_ACC_ID;
++              acc_rw.count = 1;
++              if(ReadByte_ACC(adap, &acc_rw)) {
++                      printk(KERN_ERR "bmi_sensor.c: ACC read (ID) error\n");
++                      goto sysfs_err12;
++              }
++
++              if(acc_rw.data[0] != SENSOR_ACC_ID_DATA) {
++                      printk(KERN_ERR "bmi_sensor.c: ACC ID error (read=0x%x, expected=0x%x)\n",
++                              acc_rw.data[0], SENSOR_ACC_ID_DATA);
++                      goto sysfs_err12;
++              }
++
++              acc_rw.address = SENSOR_ACC_RATE;
++              acc_rw.count = 1;
++              acc_rw.data[0] = SENSOR_ACC_RC_3200_1600;
++              if(WriteByte_ACC(adap, &acc_rw)) {
++                      printk(KERN_ERR "bmi_sensor.c: ACC write (RATE) error\n");
++                      goto sysfs_err12;
++              }
++
++              acc_rw.address = SENSOR_ACC_POWER;
++              acc_rw.count = 1;
++              acc_rw.data[0] = SENSOR_ACC_P_NORM;
++              if(WriteByte_ACC(adap, &acc_rw)) {
++                      printk(KERN_ERR "bmi_sensor.c: ACC write (RATE) error\n");
++                      goto sysfs_err12;
++              }
++
++              acc_rw.address = SENSOR_ACC_DF;
++              acc_rw.count = 1;
++              acc_rw.data[0] = SENSOR_ACC_DF_LENGTH;
++              if(WriteByte_ACC(adap, &acc_rw)) {
++                      printk(KERN_ERR "bmi_sensor.c: ACC write (DF) error\n");
++                      goto sysfs_err12;
++              }
++
++              mdelay(20);
++
++              acc_rw.address = SENSOR_ACC_DX0;
++              acc_rw.count = 2;
++              if(ReadByte_ACC(adap, &acc_rw)) {
++                      printk(KERN_ERR "bmi_sensor.c: ACC read (DX0) error\n");
++                      goto sysfs_err12;
++              }
++
++              printk(KERN_INFO "bmi_sensor.c: initial ACC X state = 0x%x\n",
++                      (acc_rw.data[0] << 8) | acc_rw.data[1]);
++
++              acc_rw.address = SENSOR_ACC_DY0;
++              acc_rw.count = 2;
++              if(ReadByte_ACC(adap, &acc_rw)) {
++                      printk(KERN_ERR "bmi_sensor.c: ACC read (DY0) error\n");
++                      goto sysfs_err12;
++              }
++
++              printk(KERN_INFO "bmi_sensor.c: initial ACC Y state = 0x%x\n",
++                      (acc_rw.data[0] << 8) | acc_rw.data[1]);
++
++              acc_rw.address = SENSOR_ACC_DZ0;
++              acc_rw.count = 2;
++              if(ReadByte_ACC(adap, &acc_rw)) {
++                      printk(KERN_ERR "bmi_sensor.c: ACC read (DZ0) error\n");
++                      goto sysfs_err12;
++              }
++
++              printk(KERN_INFO "bmi_sensor.c: initial ACC Z state = 0x%x\n",
++                      (acc_rw.data[0] << 8) | acc_rw.data[1]);
++
++              if(device_create_file(&sensor->bdev->dev, &dev_attr_accel)) {
++                      printk (KERN_ERR
++                      "bmi_sensor.c (%d): attr (accel) failed.\n",
++                      slot);
++                      goto sysfs_err12;
++              }
++
++              if(factory_test == 1) {
++                      printk(KERN_INFO "bmi_sensor.c: ACCELEROMETER Sensor present in slot %d\n", slot);
++              }
++      }
++
++      if(sensor->eeprom.acc302_present == SENSOR_DEVICE_PRESENT) {
++              struct sensor_acc_rw acc_rw;
++
++              acc_rw.address = SENSOR_A3_WAI;
++              acc_rw.count = 1;
++              if(ReadByte_ACC(adap, &acc_rw)) {
++                      printk(KERN_ERR "bmi_sensor.c: ACC302 read (WAI) error\n");
++                      goto sysfs_err12;
++              }
++
++              if(acc_rw.data[0] != SENSOR_A3_WAI_ID) {
++                      printk(KERN_ERR "bmi_sensor.c: ACC302 ID error (read=0x%x, expected=0x%x)\n",
++                              acc_rw.data[0], SENSOR_A3_WAI_ID);
++                      goto sysfs_err12;
++              }
++
++              acc_rw.address = SENSOR_A3_CTRL1;
++              acc_rw.count = 1;
++              if(factory_test)
++                      acc_rw.data[0] = SENSOR_A3_CTRL1_DR400 | SENSOR_A3_CTRL1_PU |
++                          SENSOR_A3_CTRL1_STP | SENSOR_A3_CTRL1_STM | SENSOR_A3_CTRL1_XYZEN;
++              else
++                      acc_rw.data[0] = SENSOR_A3_CTRL1_DR400 | SENSOR_A3_CTRL1_PU
++                          | SENSOR_A3_CTRL1_XYZEN;
++              if(WriteByte_ACC(adap, &acc_rw)) {
++                      printk(KERN_ERR "bmi_sensor.c: ACC302 write (RATE) error\n");
++                      goto sysfs_err12;
++              }
++
++              acc_rw.address = SENSOR_A3_CTRL3;
++              acc_rw.count = 1;
++              acc_rw.data[0] = SENSOR_A3_CTRL3_IL;
++              if(WriteByte_ACC(adap, &acc_rw)) {
++                      printk(KERN_ERR "bmi_sensor.c: ACC302 write (RATE) error\n");
++                      goto sysfs_err12;
++              }
++
++              mdelay(20);
++
++              acc_rw.address = SENSOR_A3_OUTX;
++              acc_rw.count = 1;
++              if(ReadByte_ACC(adap, &acc_rw)) {
++                      printk(KERN_ERR "bmi_sensor.c: ACC302 read (OUTX) error\n");
++                      goto sysfs_err12;
++              }
++
++              printk(KERN_INFO "bmi_sensor.c: initial ACC302 X state = 0x%x\n",
++                      acc_rw.data[0]);
++
++              acc_rw.address = SENSOR_A3_OUTY;
++              acc_rw.count = 1;
++              if(ReadByte_ACC(adap, &acc_rw)) {
++                      printk(KERN_ERR "bmi_sensor.c: ACC302 read (OUTY) error\n");
++                      goto sysfs_err12;
++              }
++
++              printk(KERN_INFO "bmi_sensor.c: initial ACC302 Y state = 0x%x\n",
++                      acc_rw.data[0]);
++
++              acc_rw.address = SENSOR_A3_OUTZ;
++              acc_rw.count = 1;
++              if(ReadByte_ACC(adap, &acc_rw)) {
++                      printk(KERN_ERR "bmi_sensor.c: ACC302 read (OUTZ) error\n");
++                      goto sysfs_err12;
++              }
++
++              printk(KERN_INFO "bmi_sensor.c: initial ACC302 Z state = 0x%x\n",
++                      acc_rw.data[0]);
++
++              if(device_create_file(&sensor->bdev->dev, &dev_attr_accel)) {
++                      printk (KERN_ERR
++                      "bmi_sensor.c (%d): attr (accel) failed.\n",
++                      slot);
++                      goto sysfs_err12;
++              }
++
++              if(factory_test == 1) {
++                      printk(KERN_INFO "bmi_sensor.c: ISL302 ACCELEROMETER Sensor present in slot %d\n", slot);
++              }
++      }
++
++      if(sensor->eeprom.aproximity_present == SENSOR_DEVICE_PRESENT) {
++              unsigned char aprox_data;
++              unsigned int read_data;
++              int ret;
++
++              // enable sensor
++              if(ReadByte_IOX(adap, IOX_INPUT1_REG, &iox_data)) {
++                      printk(KERN_ERR "bmi_sensor.c: IOX error in slot %d\n", slot);
++                      goto sysfs_err13;
++              }
++              iox_data &= ~(0x1 << SENSOR_IOX_PROX_EN_N);
++              if(WriteByte_IOX(adap, IOX_OUTPUT1_REG, iox_data)) {
++                      printk(KERN_ERR "bmi_sensor.c: IOX error in slot %d\n", slot);
++                      goto sysfs_err13;
++              }
++
++              // start burst to LED
++              iox_data |= (0x1 << SENSOR_IOX_PROX_RST_N);
++              if(WriteByte_IOX(adap, IOX_OUTPUT1_REG, iox_data))
++                      goto sysfs_err13;
++
++              // set up timer
++              sensor->aprox_timer.expires = jiffies + sensor->aprox_duration;
++              add_timer (&sensor->aprox_timer);
++
++              // wait for timer
++              ret = down_interruptible(&sensor->sem);
++              sensor->aprox_int_en = 1;
++              sensor->aprox_int_fl = 0;
++              up(&sensor->sem);
++              wait_event_interruptible(sensor->aprox_wait_queue, (sensor->aprox_int_fl == 1));
++
++              // stop burst to LED
++              if(ReadByte_IOX(adap, IOX_INPUT1_REG, &iox_data))
++                      goto sysfs_err13;
++              iox_data &= ~(0x1 << SENSOR_IOX_PROX_RST_N);
++              if(WriteByte_IOX(adap, IOX_OUTPUT1_REG, iox_data))
++                      goto sysfs_err13;
++
++              // digital output
++              read_data = (iox_data & (0x1 << SENSOR_IOX_PROX_OUT)) << 14;
++
++              // read ADC - analog output
++              if(WriteByte_ADC(adap, SENSOR_ADC_APROXIMITY | SENSOR_ADC_PD_OFF))
++                      goto sysfs_err13;
++
++              mdelay(1);
++
++              if(ReadByte_ADC(adap, &aprox_data))
++                      goto sysfs_err13;
++              read_data |= aprox_data;
++
++              printk(KERN_INFO "bmi_sensor.c: initial analog proximity = 0x%x\n", read_data);
++
++              if(device_create_file(&sensor->bdev->dev, &dev_attr_aprox)) {
++                      printk (KERN_ERR
++                      "bmi_sensor.c (%d): attr (aprox) failed.\n",
++                      slot);
++                      goto sysfs_err13;
++              }
++
++              if(factory_test == 1) {
++                      printk(KERN_INFO "bmi_sensor.c: Analog PROXIMITY Sensor present in slot %d\n", slot);
++              }
++      }
++
++      if(sensor->eeprom.alight_present == SENSOR_DEVICE_PRESENT) {
++              unsigned char adc_data[2];
++
++              if(WriteByte_ADC(adap, SENSOR_ADC_LIGHT)) {
++                      printk(KERN_ERR "bmi_sensor.c: ADC write (Analog Light) error\n");
++                      goto sysfs_err14;
++              }
++
++              mdelay(1);
++
++              if(ReadByte_ADC(adap, adc_data)) {
++                      printk(KERN_ERR "bmi_sensor.c: ADC read (Humidity) error\n");
++                      goto sysfs_err14;
++              }
++
++              printk(KERN_INFO "bmi_sensor.c: initial Analog Light = 0x%x\n",
++                      (adc_data[0] << 8) | adc_data[1]);
++
++              if(device_create_file(&sensor->bdev->dev, &dev_attr_alight)) {
++                      printk (KERN_ERR
++                      "bmi_sensor.c (%d): attr (alight) failed.\n",
++                      slot);
++                      goto sysfs_err14;
++              }
++
++              if(factory_test == 1) {
++                      printk(KERN_INFO "bmi_sensor.c: Analog LIGHT Sensor present in slot %d\n", slot);
++              }
++      }
++
++      if(sensor->eeprom.dlight_present == SENSOR_DEVICE_PRESENT) {
++              unsigned char dl_data[2];
++
++              if(WriteByte_PL(adap, SENSOR_DL_CMD, SENSOR_DL_CMD_ADC_EN)) {
++                      printk(KERN_ERR "bmi_sensor.c: PL write (Digital Light) error\n");
++                      goto sysfs_err15;
++              }
++
++              mdelay(20);
++
++              if(ReadByte_PL(adap, SENSOR_DL_SENSOR_MSB, &dl_data[0])) {
++                      printk(KERN_ERR "bmi_sensor.c: ADC read (Digital Light) error\n");
++                      goto sysfs_err15;
++              }
++
++              if(ReadByte_PL(adap, SENSOR_DL_SENSOR_MSB, &dl_data[1])) {
++                      printk(KERN_ERR "bmi_sensor.c: ADC read (Digital Light) error\n");
++                      goto sysfs_err15;
++              }
++              printk(KERN_INFO "bmi_sensor.c: initial Digital Light = %d\n",
++                      (dl_data[0] << 8) | dl_data[1]);
++
++              // clear interrupts
++              if(ReadByte_PL(adap, SENSOR_DL_CONT, &dl_data[0])) {
++                      printk(KERN_ERR "bmi_sensor.c: DL read error\n");
++              }
++              dl_data[0] &= ~(SENSOR_DL_CONT_INT);
++              if(WriteByte_PL(adap, SENSOR_DL_CONT, dl_data[0])) {
++                      printk(KERN_ERR "bmi_sensor.c: DL write error\n");
++              }
++              if(WriteByte_DL_IC(adap)) {
++                      printk(KERN_ERR "bmi_sensor.c: DL interrupt clear error\n");
++              }
++
++              if(device_create_file(&sensor->bdev->dev, &dev_attr_dlight)) {
++                      printk (KERN_ERR
++                      "bmi_sensor.c (%d): attr (Digital Light) failed.\n",
++                      slot);
++                      goto sysfs_err15;
++              }
++
++              if(factory_test == 1) {
++                      printk(KERN_INFO "bmi_sensor.c: Digital LIGHT Sensor present in slot %d\n", slot);
++              }
++      }
++
++      if(ReadByte_IOX(adap, IOX_INPUT0_REG, &iox_data)) { // clear IOX interrupts
++              printk (KERN_ERR
++              "bmi_sensor.c(%d): IOX0 interrupt clear fail.\n",
++              slot);
++              goto sysfs_err16;
++      }
++
++      if(ReadByte_IOX(adap, IOX_INPUT1_REG, &iox_data)) { // clear IOX interrupts
++              printk (KERN_ERR
++              "bmi_sensor.c(%d): IOX1 interrupt clear fail.\n",
++              slot);
++              goto sysfs_err16;
++      }
++
++      // request PIM interrupt
++      irq = bmi_device_get_status_irq(bdev);
++      sprintf(sensor->int_name, "bmi_sensor%d", slot);
++      //pjg if(request_irq(irq, &module_irq_handler, 0, sensor->int_name, sensor)) {
++              //pjg printk(KERN_ERR "bmi_sensor.c: Can't allocate irq %d or find Sensor in slot %d\n",
++                      //pjg irq, slot);
++              //pjg goto sysfs_err16;
++      //pjg }
++
++      return 0;
++
++sysfs_err16:
++      if(sensor->eeprom.dlight_present == SENSOR_DEVICE_PRESENT) {
++              device_remove_file(&sensor->bdev->dev, &dev_attr_dlight);
++      }
++sysfs_err15:
++      if(sensor->eeprom.alight_present == SENSOR_DEVICE_PRESENT) {
++              device_remove_file(&sensor->bdev->dev, &dev_attr_alight);
++      }
++sysfs_err14:
++      if(sensor->eeprom.aproximity_present == SENSOR_DEVICE_PRESENT) {
++              device_remove_file(&sensor->bdev->dev, &dev_attr_aprox);
++      }
++sysfs_err13:
++      if(sensor->eeprom.accel_present == SENSOR_DEVICE_PRESENT) {
++              device_remove_file(&sensor->bdev->dev, &dev_attr_accel);
++      }
++sysfs_err12:
++      if(sensor->eeprom.motion_present == SENSOR_DEVICE_PRESENT) {
++              device_remove_file(&sensor->bdev->dev, &dev_attr_motion);
++      }
++sysfs_err11:
++      if(sensor->eeprom.temperature_present == SENSOR_DEVICE_PRESENT) {
++              device_remove_file(&sensor->bdev->dev, &dev_attr_temp_uremote);
++      }
++sysfs_err10:
++      if(sensor->eeprom.temperature_present == SENSOR_DEVICE_PRESENT) {
++              device_remove_file(&sensor->bdev->dev, &dev_attr_temp_sremote);
++      }
++sysfs_err9:
++      if(sensor->eeprom.temperature_present == SENSOR_DEVICE_PRESENT) {
++              device_remove_file(&sensor->bdev->dev, &dev_attr_temp_local);
++      }
++sysfs_err8:
++      if(sensor->eeprom.sound_present == SENSOR_DEVICE_PRESENT) {
++              device_remove_file(&sensor->bdev->dev, &dev_attr_sound_peak);
++      }
++sysfs_err7:
++      if(sensor->eeprom.sound_present == SENSOR_DEVICE_PRESENT) {
++              device_remove_file(&sensor->bdev->dev, &dev_attr_sound_avg);
++      }
++sysfs_err6:
++      if(sensor->eeprom.light_proximity_present == SENSOR_DEVICE_PRESENT) {
++              device_remove_file(&sensor->bdev->dev, &dev_attr_proximity);
++      }
++sysfs_err5:
++      if(sensor->eeprom.light_proximity_present == SENSOR_DEVICE_PRESENT) {
++              device_remove_file(&sensor->bdev->dev, &dev_attr_ir);
++      }
++sysfs_err4:
++      if(sensor->eeprom.light_proximity_present == SENSOR_DEVICE_PRESENT) {
++              device_remove_file(&sensor->bdev->dev, &dev_attr_als);
++      }
++sysfs_err3:
++      if(sensor->eeprom.dcompass_present == SENSOR_DEVICE_PRESENT) {
++              device_remove_file(&sensor->bdev->dev, &dev_attr_dcompass);
++      }
++sysfs_err2:
++      if(sensor->eeprom.acompass_present == SENSOR_DEVICE_PRESENT) {
++              device_remove_file(&sensor->bdev->dev, &dev_attr_acompass);
++      }
++sysfs_err1:
++      if(sensor->eeprom.humidity_present == SENSOR_DEVICE_PRESENT) {
++              device_remove_file(&sensor->bdev->dev, &dev_attr_humidity);
++      }
++error:
++      sensor->class_dev = NULL;
++      cdev_del(&sensor->cdev);
++      device_destroy(bmi_class, MKDEV(major, slot));
++      bmi_device_set_drvdata(bdev, 0);
++      sensor->bdev = 0;
++      printk(KERN_ERR "bmi_sensor.c: probe slot %d FAILED\n", slot);
++      return -ENODEV;
++
++}
++
++// remove PIM
++void bmi_sensor_remove(struct bmi_device *bdev)
++{
++      int slot;
++      struct bmi_sensor *sensor;
++      struct class *bmi_class;
++      int irq;
++
++      slot = bmi_device_get_slot(bdev);
++      sensor = &bmi_sensor[slot];
++
++      irq = bmi_device_get_status_irq(bdev);
++      free_irq(irq, sensor);
++
++      destroy_workqueue(sensor->workqueue);
++
++      if(sensor->eeprom.humidity_present == SENSOR_DEVICE_PRESENT) {
++              device_remove_file(&sensor->bdev->dev, &dev_attr_humidity);
++      }
++      if(sensor->eeprom.acompass_present == SENSOR_DEVICE_PRESENT) {
++              device_remove_file(&sensor->bdev->dev, &dev_attr_acompass);
++      }
++      if(sensor->eeprom.dcompass_present == SENSOR_DEVICE_PRESENT) {
++              device_remove_file(&sensor->bdev->dev, &dev_attr_dcompass);
++      }
++      if(sensor->eeprom.light_proximity_present == SENSOR_DEVICE_PRESENT) {
++              device_remove_file(&sensor->bdev->dev, &dev_attr_als);
++              device_remove_file(&sensor->bdev->dev, &dev_attr_ir);
++              device_remove_file(&sensor->bdev->dev, &dev_attr_proximity);
++      }
++      if(sensor->eeprom.sound_present == SENSOR_DEVICE_PRESENT) {
++              device_remove_file(&sensor->bdev->dev, &dev_attr_sound_avg);
++              device_remove_file(&sensor->bdev->dev, &dev_attr_sound_peak);
++      }
++      if(sensor->eeprom.temperature_present == SENSOR_DEVICE_PRESENT) {
++              device_remove_file(&sensor->bdev->dev, &dev_attr_temp_local);
++              device_remove_file(&sensor->bdev->dev, &dev_attr_temp_sremote);
++              device_remove_file(&sensor->bdev->dev, &dev_attr_temp_uremote);
++      }
++      if(sensor->eeprom.motion_present == SENSOR_DEVICE_PRESENT) {
++              device_remove_file(&sensor->bdev->dev, &dev_attr_motion);
++      }
++      if(sensor->eeprom.acc302_present == SENSOR_DEVICE_PRESENT) {
++              device_remove_file(&sensor->bdev->dev, &dev_attr_accel);
++      }
++      if(sensor->eeprom.accel_present == SENSOR_DEVICE_PRESENT) {
++              device_remove_file(&sensor->bdev->dev, &dev_attr_accel);
++      }
++      if(sensor->eeprom.aproximity_present == SENSOR_DEVICE_PRESENT) {
++              device_remove_file(&sensor->bdev->dev, &dev_attr_aprox);
++              del_timer(&sensor->aprox_timer);
++      }
++      if(sensor->eeprom.alight_present == SENSOR_DEVICE_PRESENT) {
++              device_remove_file(&sensor->bdev->dev, &dev_attr_alight);
++      }
++      if(sensor->eeprom.dlight_present == SENSOR_DEVICE_PRESENT) {
++              device_remove_file(&sensor->bdev->dev, &dev_attr_dlight);
++      }
++
++      bmi_slot_gpio_configure_all_as_inputs(slot);
++
++      bmi_class = bmi_get_bmi_class();
++      device_destroy(bmi_class, MKDEV(major, slot));
++
++      sensor->class_dev = 0;
++
++      cdev_del(&sensor->cdev);
++
++      // de-attach driver-specific struct from bmi_device structure
++      bmi_device_set_drvdata(bdev, 0);
++      sensor->bdev = 0;
++
++      return;
++}
++
++/*
++ *    module routines
++ */
++
++static int __init bmi_sensor_init(void)
++{
++      dev_t   dev_id;
++      int     retval;
++
++      // alloc char driver with 4 minor numbers
++      retval = alloc_chrdev_region(&dev_id, 0, 4, "BMI SENSOR Driver");
++      if(retval) {
++              return -ENODEV;
++      }
++
++      major = MAJOR(dev_id);
++      retval = bmi_register_driver(&bmi_sensor_driver);
++      if(retval) {
++              unregister_chrdev_region(dev_id, 4);
++              return -ENODEV;
++      }
++
++      if(factory_test) {
++              printk(KERN_INFO "bmi_sensor.c: Factory Test mode enabled\n");
++              if(eeprom_init)
++                      printk(KERN_INFO "bmi_sensor.c: eeprom init = 0x%x\n", eeprom_init);
++              if(xdac_init)
++                      printk(KERN_INFO "bmi_sensor.c: XDAC init = 0x%x\n", xdac_init);
++              if(ydac_init)
++                      printk(KERN_INFO "bmi_sensor.c: YDAC init = 0x%x\n", ydac_init);
++              if(zdac_init)
++                      printk(KERN_INFO "bmi_sensor.c: ZDAC init = 0x%x\n", zdac_init);
++      }
++
++      if(fcc_test)
++              printk(KERN_INFO "bmi_sensor.c: FCC Test mode enabled\n");
++
++      printk(KERN_INFO "bmi_sensor.c: BMI_SENSOR Driver v%s \n", BMISENSOR_VERSION);
++
++      return 0;
++}
++
++static void __exit bmi_sensor_cleanup(void)
++{
++      dev_t dev_id;
++
++      bmi_unregister_driver(&bmi_sensor_driver);
++
++      dev_id = MKDEV(major, 0);
++      unregister_chrdev_region(dev_id, 4);
++      return;
++}
++
++module_init(bmi_sensor_init);
++module_exit(bmi_sensor_cleanup);
++
++module_param(factory_test, ushort, S_IRUGO);
++MODULE_PARM_DESC(factory_test, "Factory Test code enable");
++
++module_param(eeprom_init, int, S_IRUGO);
++MODULE_PARM_DESC(eeprom_init, "Factory presence EEPROM programming");
++
++module_param(xdac_init, ushort, S_IRUGO);
++MODULE_PARM_DESC(xdac_init, "Factory EEPROM XDAC programming");
++
++module_param(ydac_init, ushort, S_IRUGO);
++MODULE_PARM_DESC(ydac_init, "Factory EEPROM YDAC programming");
++
++module_param(zdac_init, ushort, S_IRUGO);
++MODULE_PARM_DESC(zdac_init, "Factory EEPROM ZDAC programming");
++
++module_param(fcc_test, ushort, S_IRUGO);
++MODULE_PARM_DESC(fcc_test, "FCC Test code enable");
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Peter Giacomini <p.giacomini@encadis.com>");
++MODULE_DESCRIPTION("BMI Sensor device driver");
++MODULE_SUPPORTED_DEVICE("bmi_sensor_cntl_mX");
++
+--- /dev/null
++++ git/drivers/bmi/pims/sound/Makefile
+@@ -0,0 +1,6 @@
++#
++# BMI PIMS
++#
++
++obj-$(CONFIG_BMI_AUDIO)               += bmi_audio.o
++
+--- /dev/null
++++ git/drivers/bmi/pims/sound/bmi_audio.c
+@@ -0,0 +1,4434 @@
++/*
++ *    bmi_audio.c
++ *
++ *    BMI audio device driver for audio PIMs
++ *
++ * The BMI Audio driver and this API were developed to support
++ * audio playback and record on the BUG audio PIMs.
++ *
++ * The following operating modes are supported:
++ *
++ *      Operating Mode                PIM
++ *      ---------------------------- -------
++ *      Stereo DAC Playback           Yes
++ *      Stereo ADC Record             Yes
++ *      Output Amplifier Control      Yes
++ *      Input Mixer Control           Yes
++ *
++ * This file also implements the sound driver mixer interface for ALSA.
++ *
++ * Playback and Recording supports 11025, 22050, and 44100 kHz for stereo.
++ *
++ * Future Enhanement Options:
++ *    48000-based rates
++ *    efx control
++ *    I2S -> TDM mode
++ *    power management
++ */
++
++/*
++ *    This code was derived from the following sources:
++ *
++ * @file      pmic_audio.c
++ * @file      mxc-alsa-mixer.c
++ * @file      mxc-alsa-pmic.c
++ *
++ * Copyright 2004-2006 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++#undef CODEC  // disable CODEC access for code testing
++#define CODEC // enable CODEC access for code testing
++
++#define DEBUG // enable debug printk
++#undef DEBUG  // disable debug printk
++
++#ifdef DEBUG
++
++#  define DDPRINTK(fmt, args...) printk(KERN_ERR"%s :: %d :: %s - " \
++                fmt, __FILE__,__LINE__,__FUNCTION__ , ## args)
++#  define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args)
++#  define PRINTK(fmt) printk(KERN_INFO fmt)
++
++#  define FUNC_START DPRINTK(" func start\n")
++#  define FUNC_END DPRINTK(" func end\n")
++
++#  define FUNC_ERR printk(KERN_ERR"%s :: %d :: %s  err= %d \n", \
++                __FILE__,__LINE__,__FUNCTION__ ,err)
++
++#else // DEBUG
++
++#define DDPRINTK(fmt, args...)  do {} while(0)
++#define DPRINTK(fmt, args...)   do {} while(0)
++#define PRINTK(fmt)   do {} while(0)
++
++#endif        // DEBUG
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/spinlock.h>
++#include <linux/clk.h>
++
++// BMI/BUG interfaces
++#include <linux/bmi.h>
++#include <linux/bmi/bmi-control.h>
++#include <linux/bmi-ids.h>
++#include <linux/bmi/bmi_ioctl.h>
++#include <linux/bmi/bmi_audio.h>
++
++// control interface - LED/RESET/MODULE ACTIVATION
++#include <asm/ioctl.h>
++#include <linux/fs.h>
++#include <linux/cdev.h>
++#include <linux/major.h>
++
++// I2C interface - IOX/CODEC
++#include <linux/i2c.h>
++#include <mach/mxc_i2c.h>
++
++// Input interface - BUTTONS/JACKS
++#include <linux/input.h>
++#include <linux/interrupt.h>
++
++// includes from mxc-alsa-mixer.c:
++#include <sound/driver.h>
++#include <sound/core.h>
++#include <sound/control.h>
++#include <sound/pcm.h>
++#include <sound/initval.h>
++#include <linux/soundcard.h>
++#include "../../../mxc/bug_audio/bug-alsa-common.h"
++
++// includes from mxc-alsa-pmic.c:
++#include <linux/moduleparam.h>
++#include <linux/errno.h>
++#include <linux/ioctl.h>
++#include <linux/delay.h>
++#include <linux/slab.h>
++#include <linux/dma-mapping.h>
++
++#ifdef CONFIG_PM
++#include <linux/pm.h>
++#endif        // CONFIG_PM
++
++#include <mach/dma.h>
++#include <mach/spba.h>
++#include <mach/clock.h>
++#include <asm/mach-types.h>
++
++#include "../../../../arch/arm/mach-mx3/crm_regs.h"
++#include "../../../mxc/ssi/ssi.h"
++#include "../../../mxc/ssi/registers.h"
++#include "../../../mxc/dam/dam.h"
++
++// Global variables
++static ushort fcc_test = 0;
++static ushort output_ints = 0;
++
++// BMI defines
++#define BMIAUDIO_VERSION      "1.0"
++#define MAX_STRG              (20)
++#define WORK_DELAY            (1)     // input debounce
++
++// BMI private device structure
++struct bmi_audio
++{
++      struct bmi_device   *bdev;                      // BMI device
++      struct cdev          cdev;                      // control character device
++      struct device *class_dev;                       // control device class
++      unsigned int         active;                    // PIM active
++      unsigned int         irq;                       // interrupt number
++      char                 int_name[MAX_STRG];        // interrupt name for /proc
++      struct input_dev     *input_dev;                // button/insertion input device
++};
++
++static struct bmi_audio bmi_audio[BMI_AUDIO_PIM_NUM]; // PIM structures
++static int major;                                     // control device major
++
++//
++// I2C
++//
++
++// I2C Slave Addresses
++#define BMI_IOX_I2C_ADDRESS   0x71    // 7-bit address
++#define BMI_CODEC_I2C_ADDRESS 0x18    // 7-bit address
++
++// I2C IOX register definitions
++#define IOX_INPUT_REG         0x0     // IOX input data register
++#define IOX_OUTPUT_REG                0x1     // IOX output data register
++#define IOX_POLARITY_REG      0x2     // IOX polarity data register
++#define IOX_CONTROL           0x3     // IOX direction control register
++#define IOX_AMP                       (0)     // bit 0 - amplifier off (O - low active)
++#define IOX_SPARE             (1)     // bit 1 - spare
++#define IOX_VOLP              (2)     // bit 2 - VOLP (I - interrupt)
++#define IOX_VOLD              (3)     // bit 3 - VOLD (I - interrupt)
++#define IOX_HP_INS            (4)     // bit 4 - HP_INS (I - interrupt)
++#define IOX_MIC_INS           (5)     // bit 5 - MIC_INS (I - interrupt)
++#define IOX_LI_INS            (6)     // bit 6 - LI_INS (I - interrupt)
++#define IOX_LO_INS            (7)     // bit 7 - LO_INS (I - interrupt)
++
++//
++// I2C routines
++//
++
++// read byte from I2C IO expander
++static int ReadByte_IOX (struct i2c_adapter *adap, unsigned char offset, unsigned char *data)
++{
++              int     ret = 0;
++              struct i2c_msg rmsg[2];
++              int     num_msgs;
++
++              // Read Byte with Pointer
++              rmsg[0].addr = BMI_IOX_I2C_ADDRESS;
++              rmsg[0].flags = 0;        // write
++              rmsg[0].len = 1;
++              rmsg[0].buf = &offset;
++
++              rmsg[1].addr = BMI_IOX_I2C_ADDRESS;
++              rmsg[1].flags = I2C_M_RD;   // read
++              rmsg[1].len = 1;
++              rmsg[1].buf = data;
++
++              num_msgs = 2;
++              ret = i2c_transfer (adap, rmsg, num_msgs);
++
++              if (ret == 2) {
++                      ret = 0;
++              }
++              else {
++                      printk (KERN_ERR "ReadByte_IOX() - i2c_transfer() failed.\n");
++                      ret = -1;
++              }
++              return ret;
++}
++
++// write byte to I2C IO expander
++static int WriteByte_IOX (struct i2c_adapter *adap, unsigned char offset, unsigned char data)
++{
++              int     ret = 0;
++              struct i2c_msg wmsg[2];
++              int     num_msgs;
++
++              // Write Byte with Pointer
++              wmsg[0].addr = BMI_IOX_I2C_ADDRESS;
++              wmsg[0].flags = 0;      // write
++              wmsg[0].len = 1;
++              wmsg[0].buf = &offset;
++
++              wmsg[1].addr = BMI_IOX_I2C_ADDRESS;
++              wmsg[1].flags = 0;      // write
++              wmsg[1].len = 1;
++              wmsg[1].buf = &data;
++
++              num_msgs = 2;
++
++              ret = i2c_transfer (adap, wmsg, num_msgs);
++
++              if (ret == 2) {
++                      ret = 0;
++              }
++              else {
++                      printk (KERN_ERR "WriteByte_IOX() - i2c_transfer() failed.\n");
++                      ret = -1;
++              }
++              return ret;
++}
++
++#ifdef CODEC
++// read byte from I2C CODEC
++static int ReadByte_CODEC (struct i2c_adapter *adap, unsigned char offset, unsigned char *data)
++{
++              int     ret = 0;
++              struct i2c_msg rmsg[2];
++              int     num_msgs;
++
++              // Read Byte with Pointer
++              rmsg[0].addr = BMI_CODEC_I2C_ADDRESS;
++              rmsg[0].flags = 0;        // write
++              rmsg[0].len = 1;
++              rmsg[0].buf = &offset;
++
++              rmsg[1].addr = BMI_CODEC_I2C_ADDRESS;
++              rmsg[1].flags = I2C_M_RD;   // read
++              rmsg[1].len = 1;
++              rmsg[1].buf = data;
++
++              num_msgs = 2;
++              ret = i2c_transfer (adap, rmsg, num_msgs);
++
++              if (ret == 2) {
++                      ret = 0;
++              }
++              else {
++                      printk (KERN_ERR "ReadByte_CODEC() - i2c_transfer() failed.\n");
++                      ret = -1;
++              }
++              return ret;
++}
++
++// write byte to I2C CODEC
++static int WriteByte_CODEC (struct i2c_adapter *adap, unsigned char offset, unsigned char data)
++{
++              int     ret = 0;
++              struct i2c_msg wmsg[2];
++              int     num_msgs;
++
++              // Write Byte with Pointer
++              wmsg[0].addr = BMI_CODEC_I2C_ADDRESS;
++              wmsg[0].flags = 0;      // write
++              wmsg[0].len = 1;
++              wmsg[0].buf = &offset;
++
++              wmsg[1].addr = BMI_CODEC_I2C_ADDRESS;
++              wmsg[1].flags = 0;      // write
++              wmsg[1].len = 1;
++              wmsg[1].buf = &data;
++
++              num_msgs = 2;
++
++              ret = i2c_transfer (adap, wmsg, num_msgs);
++
++              if (ret == 2) {
++                      ret = 0;
++              }
++              else {
++                      printk (KERN_ERR "WriteByte_CODEC() - i2c_transfer() failed.\n");
++                      ret = -1;
++              }
++              return ret;
++}
++#endif        // CODEC
++
++//
++// control cdev routines
++//
++
++// open
++int cntl_open (struct inode *inode, struct file *file)
++{
++      struct bmi_audio *audio;
++
++      audio = container_of (inode->i_cdev, struct bmi_audio, cdev);
++      file->private_data = audio;
++      return 0;
++
++}
++
++// release
++int cntl_release (struct inode *inode, struct file *file)
++{
++      file->private_data = 0;
++      return 0;
++}
++
++static int configure_CODEC(struct i2c_adapter *adap, struct bmi_audio *audio);
++
++// ioctl
++int cntl_ioctl (struct inode *inode, struct file *file, unsigned int cmd,
++                 unsigned long arg)
++{
++      struct bmi_audio *audio = (struct bmi_audio *) (file->private_data);
++      struct codec_xfer codec_xfer;
++      struct i2c_adapter *adap;
++      unsigned char iox_data;
++      int slot;
++
++      // error if audio/bdev not present
++      if (audio == 0)
++              return -ENODEV;
++
++      if (audio->bdev == 0)
++              return -ENODEV;
++
++      adap = bmi_device_get_i2c_adapter (audio->bdev);
++      slot = bmi_device_get_slot (audio->bdev);
++
++      // get codec transfer structure
++      if ((cmd == BMI_AUDIO_WCODEC) || (cmd == BMI_AUDIO_RCODEC)) {
++              if (copy_from_user (&codec_xfer, (struct codec_xfer *) arg, sizeof(struct codec_xfer))) {
++                      printk (KERN_INFO "bmi_audio.c: ioctl(%d): copy_from_user error\n", slot);
++                      return -EFAULT;
++              }
++      }
++
++      // ioctl's
++      switch (cmd) {
++
++              case BMI_AUDIO_RLEDOFF:
++                      bmi_slot_gpio_write_bit (slot, GPIO_RED, BMI_GPIO_ON); // Red LED=OFF
++                      break;
++
++              case BMI_AUDIO_RLEDON:
++                      bmi_slot_gpio_write_bit (slot, GPIO_RED, BMI_GPIO_OFF); // Red LED=ON
++                      break;
++
++              case BMI_AUDIO_GLEDOFF:
++                      bmi_slot_gpio_write_bit (slot, GPIO_GREEN, BMI_GPIO_ON); // Greem LED=OFF
++                      break;
++
++              case BMI_AUDIO_GLEDON:
++                      bmi_slot_gpio_write_bit (slot, GPIO_GREEN, BMI_GPIO_OFF); // Greem LED=ON
++                      break;
++
++      case BMI_AUDIO_SPKON:
++        {
++          printk(KERN_INFO "BMI_AUDIO: SPKOFF Called...\n");
++          if (ReadByte_IOX (adap, IOX_OUTPUT_REG, &iox_data))
++            return -ENODEV;
++          printk(KERN_INFO "BMI_AUDIO: IOX Output Read: 0x%x\n", iox_data);
++          if (WriteByte_IOX (adap, IOX_OUTPUT_REG, (iox_data | (1 << IOX_AMP))))
++            return -ENODEV;
++        }
++        break;
++      case BMI_AUDIO_SPKOFF:
++        {
++          printk(KERN_INFO "BMI_AUDIO: SPKON Called...\n");
++          if (ReadByte_IOX (adap, IOX_OUTPUT_REG, &iox_data))
++            return -ENODEV;
++          printk(KERN_INFO "BMI_AUDIO: IOX Output Read: 0x%x\n", iox_data);
++          if (WriteByte_IOX (adap, IOX_OUTPUT_REG, (iox_data & ~(1 << IOX_AMP))))
++            return -ENODEV;
++        }
++        break;
++              case BMI_AUDIO_SETRST:
++                      bmi_slot_gpio_configure_as_output (slot, GPIO_RESET, BMI_GPIO_OFF); // RST = 0;
++                      break;
++
++              case BMI_AUDIO_CLRRST:
++                      bmi_slot_gpio_configure_as_output (slot, GPIO_RESET, BMI_GPIO_ON); // RST = 1;
++                      break;
++
++              case BMI_AUDIO_GETSTAT:
++                      {
++                      int read_data;
++
++                      if(ReadByte_IOX (adap, IOX_INPUT_REG, &iox_data))
++                              return -ENODEV;
++
++                      read_data = iox_data | (bmi_read_gpio_data_reg(slot) << 8);
++
++                      if(put_user(read_data, (int __user *) arg))
++                              return -EFAULT;
++                      }
++                      break;
++
++              case BMI_AUDIO_ACTIVATE:
++                      audio->active = 0;
++                      switch (slot) {
++                              case 0:
++                                      if (bmi_audio[2].active == 0) {
++                                              audio->active = 1;
++                                      }
++                                      break;
++                              case 1:
++                                      if (bmi_audio[3].active == 0) {
++                                              audio->active = 1;
++                                      }
++                                      break;
++                              case 2:
++                                      if (bmi_audio[0].active == 0) {
++                                              audio->active = 1;
++                                      }
++                                      break;
++                              case 3:
++                                      if (bmi_audio[1].active == 0) {
++                                              audio->active = 1;
++                                      }
++                                      break;
++                      }
++#ifdef CODEC
++                      // write page register
++                      if (WriteByte_CODEC (adap, 0x0, 0x0))
++                              return -ENODEV;
++                      if (audio->active) {    // power-up ADC
++                              if (WriteByte_CODEC (adap, CODEC_L1L_LPGA, CODEC_L_PGA(0x00) | CODEC_LX_PGA_PU))
++                                      return -ENODEV;
++                              if (WriteByte_CODEC (adap, CODEC_L1R_RPGA, CODEC_L_PGA(0x00) | CODEC_LX_PGA_PU))
++                                      return -ENODEV;
++                              configure_CODEC(adap, audio);
++                      } else {        // power-down ADC
++                              if (WriteByte_CODEC (adap, CODEC_L1L_LPGA, 0x38))
++                                      return -ENODEV;
++                              if (WriteByte_CODEC (adap, CODEC_L1R_RPGA, 0x38))
++                                      return -ENODEV;
++                      }
++#endif        // CODEC
++
++              case BMI_AUDIO_DEACTIVATE:
++#ifdef CODEC
++                      // write page register
++                      if (WriteByte_CODEC (adap, 0x0, 0x0))
++                              return -ENODEV;
++                      // power-down ADC
++                      if (WriteByte_CODEC (adap, CODEC_L1L_LPGA, 0x38))
++                              return -ENODEV;
++                      if (WriteByte_CODEC (adap, CODEC_L1R_RPGA, 0x38))
++                              return -ENODEV;
++#endif        // CODEC
++                      audio->active = 0;
++                      break;
++
++              case BMI_AUDIO_WCODEC:
++#ifdef CODEC
++                      // write page register
++                      if (WriteByte_CODEC (adap, 0x0, codec_xfer.page))
++                              return -ENODEV;
++                      // write codec register
++                      if (WriteByte_CODEC (adap, codec_xfer.reg, codec_xfer.data))
++                              return -ENODEV;
++#endif        // CODEC
++                      break;
++
++              case BMI_AUDIO_RCODEC:
++#ifdef CODEC
++                      // write page register
++                      if (WriteByte_CODEC (adap, 0x0, codec_xfer.page))
++                              return -ENODEV;
++                      // read codec register
++                      if (ReadByte_CODEC (adap, codec_xfer.reg, &codec_xfer.data))
++                              return -ENODEV;
++                      if (copy_to_user ((struct codec_xfer *) arg, &codec_xfer,
++                                  sizeof(struct codec_xfer)))
++                              return -EFAULT;
++#endif        // CODEC
++                      break;
++
++              default:
++                      return -ENOTTY;
++      }
++
++      return 0;
++}
++
++// control file operations
++struct file_operations cntl_fops = {
++      .owner = THIS_MODULE,
++      .ioctl = cntl_ioctl,
++      .open = cntl_open,
++      .release = cntl_release,
++};
++
++// functionality from mxc-alsa-pmic.h:
++#define DAM_PORT_4    port_4
++#define DAM_PORT_5    port_5
++#define TX_WATERMARK  0x4
++#define RX_WATERMARK  0x6
++
++// functionality from mxc-alsa-pmic.c:
++
++/*
++ * driver buffer policy.
++ * Customize here if the sound is not correct
++ */
++#define MAX_BUFFER_SIZE       (32*1024)
++#define DMA_BUF_SIZE          (8*1024)
++#define MIN_PERIOD_SIZE               64
++#define MIN_PERIOD            2
++#define MAX_PERIOD            255
++
++#define AUD_MUX_CONF          0x0031010
++#define MASK_2_TS             0xfffffffc
++#define SOUND_CARD13_NAME     "PIM_AUDIO13"
++#define SOUND_CARD24_NAME     "PIM_AUDIO24"
++
++// These defines enable DMA chaining for playback and capture respectively.
++#define MXC_SOUND_PLAYBACK_CHAIN_DMA_EN       1
++#define MXC_SOUND_CAPTURE_CHAIN_DMA_EN        1
++
++// ID for the PIM cards
++static char id13[] = "PIM_AUDIO13";   // slots 1 & 3
++static char id24[] = "PIM_AUDIO24";   // slots 2 & 4
++
++#define MXC_ALSA_MAX_PCM_DEV  1
++#define MXC_ALSA_MAX_PLAYBACK 1
++#define MXC_ALSA_MAX_CAPTURE  1
++
++#define PLAYBACK_STREAM       (0)
++#define CAPTURE_STREAM        (1)
++
++#define NUM_CARDS     (2)
++
++/*
++ * This structure is the global configuration of the soundcard
++ * that are accessed by the mixer as well as by the playback/recording
++ * stream. This contains various settings.
++ */
++typedef struct audio_mixer_control {
++
++      /*
++       * This variable holds the current volume for ouput devices
++       */
++      int vol_for_output[OP_MAXDEV];
++
++      /*
++       * This variable holds the current volume for input devices
++       */
++      int vol_for_input[IP_MAXDEV];
++
++      /*
++       * This variable holds the current volume for playback devices.
++       */
++      int master_volume_out;
++
++      /*
++       * These variables holds the current state of the jack indicators
++       */
++      int hp_indicator;
++      int mic_indicator;
++      int li_indicator;
++      int lo_indicator;
++
++      /*
++       * Semaphore used to control the access to this structure.
++       */
++      struct semaphore sem;
++
++      /*
++       * These variables are set by PCM stream
++       */
++      int codec_playback_active;
++      int codec_capture_active;
++
++} audio_mixer_control_t;
++
++/*
++ * This structure represents an audio stream in term of
++ * channel DMA, HW configuration on CODEC and AudioMux/SSI
++ */
++typedef struct audio_stream {
++      /*
++       * identification string
++       */
++      char *id;
++
++      /*
++       * numeric identification
++       */
++      int stream_id;
++
++      /*
++       * SSI ID on the ARM side
++       */
++      int ssi;
++
++      /*
++       * DAM port on the ARM side
++       */
++      int dam_port;
++
++      /*
++       * device identifier for DMA
++       */
++      int dma_wchannel;
++
++      /*
++       * we are using this stream for transfer now
++       */
++      int active:1;
++
++      /*
++       * current transfer period
++       */
++      int period;
++
++      /*
++       * current count of transfered periods
++       */
++      int periods;
++
++      /*
++       * are we recording - flag used to do DMA trans. for sync
++       */
++      int tx_spin;
++
++      /*
++       * Previous offset value for resume
++       */
++      unsigned int old_offset;
++
++      /*
++       * for locking in DMA operations
++       */
++      spinlock_t dma_lock;
++
++      /*
++       * Alsa substream pointer
++       */
++      struct snd_pcm_substream *stream;
++
++} audio_stream_t;
++
++/*
++ * This structure represents the CODEC sound card with its
++ * streams and its shared parameters
++ */
++typedef struct snd_card_mxc_bmi_audio {
++      /*
++       * ALSA sound card handle
++       */
++      struct snd_card *card;
++
++      /*
++       * ALSA pcm driver type handle
++       */
++      struct snd_pcm *pcm[MXC_ALSA_MAX_PCM_DEV];
++
++      /*
++       * playback & capture streams handle
++       * We can support a maximum of 1 playback streams
++       * We can support a maximum of 1 capture streams
++       */
++      audio_stream_t s[MXC_ALSA_MAX_CAPTURE + MXC_ALSA_MAX_PLAYBACK];
++
++} mxc_bmi_audio_t;
++
++/*
++ * bmi audio chip parameters for IP/OP and volume controls
++ */
++audio_mixer_control_t audio_mixer_control[NUM_CARDS];
++
++/*
++ * Global variable that represents the CODEC soundcard.
++ */
++mxc_bmi_audio_t *mxc_audio[NUM_CARDS] = { NULL, NULL };
++
++/*
++ * Supported playback rates array
++ */
++static unsigned int playback_rates_stereo[] = {
++      8000,
++      11025,
++      12000,
++      16000,
++      22050,
++      24000,
++      32000,
++      44100,
++      48000,
++      88200,
++      96000
++};
++
++/*
++ * Supported capture rates array
++ */
++static unsigned int capture_rates_stereo[] = {
++      8000,
++      11025,
++      12000,
++      16000,
++      22050,
++      24000,
++      32000,
++      44100,
++      48000,
++      88200,
++      96000
++};
++
++/*
++ * this structure represents the sample rates supported
++ * by CODEC for playback operations on DAC.
++ */
++static struct snd_pcm_hw_constraint_list hw_playback_rates_stereo = {
++      .count = ARRAY_SIZE(playback_rates_stereo),
++      .list = playback_rates_stereo,
++      .mask = 0,
++};
++
++/*
++ * this structure represents the sample rates supported
++ * by capture operations on ADC.
++ */
++static struct snd_pcm_hw_constraint_list hw_capture_rates_stereo = {
++      .count = ARRAY_SIZE(capture_rates_stereo),
++      .list = capture_rates_stereo,
++      .mask = 0,
++};
++
++/*
++ * This function configures audio multiplexer to support
++ * audio data routing in CODEC slave mode.
++ *
++ * @param       ssi   SSI of the ARM to connect to the DAM.
++ */
++void configure_dam_bmi_master(int ssi)
++{
++      int source_port;
++      int target_port;
++
++      if (ssi == SSI1) {
++              PRINTK("DAM: port 1 -> port 4\n");
++              source_port = port_1;
++              target_port = port_4;
++      } else {
++              PRINTK("DAM: port 2 -> port 5\n");
++              source_port = port_2;
++              target_port = port_5;
++      }
++
++      dam_reset_register (source_port);
++      dam_reset_register (target_port);
++
++      dam_select_mode (source_port, normal_mode);
++      dam_select_mode (target_port, normal_mode);
++
++      dam_set_synchronous (source_port, true);
++      dam_set_synchronous (target_port, true);
++
++      dam_select_RxD_source (source_port, target_port);
++      dam_select_RxD_source (target_port, source_port);
++
++      dam_select_TxFS_direction (source_port, signal_in);
++      dam_select_TxFS_direction (target_port, signal_out);
++      dam_select_TxFS_source (target_port, false, source_port);
++
++      dam_select_TxClk_direction (source_port, signal_in);
++      dam_select_TxClk_direction (target_port, signal_out);
++      dam_select_TxClk_source (target_port, false, source_port);
++
++      dam_select_RxFS_direction (source_port, signal_in);
++      dam_select_RxFS_direction (target_port, signal_out);
++      dam_select_RxFS_source (source_port, false, target_port);
++      dam_select_RxFS_source (target_port, false, source_port);
++
++      dam_select_RxClk_direction (source_port, signal_in);
++      dam_select_RxClk_direction (target_port, signal_out);
++      dam_select_RxClk_source (source_port, false, target_port);
++      dam_select_RxClk_source (target_port, false, source_port);
++}
++
++void ssi_rx_sampleRate (int ssi, int samplerate) {
++      struct clk *ssi_clk;
++
++      ssi_rx_clock_divide_by_two (ssi, false);
++      ssi_rx_clock_prescaler (ssi, false);
++      ssi_rx_frame_rate (ssi, 2);
++
++      ssi_clk = clk_get (NULL, "usb_pll.0");
++
++      if (ssi == SSI1) {
++              ssi_clk = clk_get (NULL, "ssi_clk.0");
++      } else {
++              ssi_clk = clk_get (NULL, "ssi_clk.1");
++      }
++
++      clk_set_rate (ssi_clk, clk_round_rate (ssi_clk, 11289600));
++      switch (samplerate) {
++              case 8000:
++                      ssi_rx_prescaler_modulus (ssi, 17);
++                      break;
++              case 11025:
++                      ssi_rx_prescaler_modulus (ssi, 12);
++                      break;
++              case 16000:
++                      ssi_rx_prescaler_modulus (ssi, 8);
++                      break;
++              case 22050:
++                      ssi_rx_prescaler_modulus (ssi, 6);
++                      break;
++              default:
++                      if (samplerate != 44100)
++                              printk (KERN_ERR
++                                      "ssi_rx_sampleRate(): samplerate=%d not supported (default to 44100).\n",
++                                      samplerate);
++
++                      ssi_rx_prescaler_modulus (ssi, 3);
++                      break;
++      }
++}
++
++void ssi_tx_sampleRate (int ssi, int samplerate) {
++      struct clk *ssi_clk;
++
++      ssi_tx_clock_divide_by_two (ssi, false);
++      ssi_tx_clock_prescaler (ssi, false);
++      ssi_tx_frame_rate (ssi, 2);
++
++      ssi_clk = clk_get (NULL, "usb_pll.0");
++
++      if (ssi == SSI1) {
++              ssi_clk = clk_get (NULL, "ssi_clk.0");
++      } else {
++              ssi_clk = clk_get (NULL, "ssi_clk.1");
++      }
++
++      clk_set_rate (ssi_clk, clk_round_rate (ssi_clk, 11289600));
++      switch (samplerate) {
++              case 8000:
++                      ssi_tx_prescaler_modulus (ssi, 17);
++                      break;
++              case 11025:
++                      ssi_tx_prescaler_modulus (ssi, 12);
++                      break;
++              case 16000:
++                      ssi_tx_prescaler_modulus (ssi, 8);
++                      break;
++              case 22050:
++                      ssi_tx_prescaler_modulus (ssi, 6);
++                      break;
++              default:
++                      if (samplerate != 44100)
++                              printk (KERN_ERR
++                                      "ssi_tx_sampleRate(): samplerate=%d not supported (default to 44100).\n",
++                                      samplerate);
++
++                      ssi_tx_prescaler_modulus (ssi, 3);
++                      break;
++      }
++}
++
++/*
++ * This function configures the SSI in order to receive audio
++ * from CODEC (recording). Configuration of SSI consists mainly in
++ * setting the following:
++ *
++ * 1) SSI to use (SSI1 or SSI2)
++ * 2) SSI mode (normal or network. We use always network mode)
++ * 3) SSI STCCR register settings, which control the sample rate (BCL and
++ *    FS clocks)
++ * 4) Watermarks for SSI FIFOs as well as timeslots to be used.
++ * 5) Enable SSI.
++ *
++ * @param     substream       pointer to the structure of the current stream.
++ */
++void configure_ssi_rx (int ssi)
++{
++      DPRINTK("configure_ssi_rx: SSI%d\n", ssi + 1);
++
++      // receive set up
++      ssi_rx_shift_direction (ssi, ssi_msb_first);
++      ssi_rx_clock_polarity (ssi, ssi_clock_on_falling_edge);
++      ssi_rx_frame_sync_active (ssi, ssi_frame_sync_active_low);
++      ssi_rx_frame_sync_length (ssi, ssi_frame_sync_one_word);
++      ssi_rx_early_frame_sync (ssi, ssi_frame_sync_one_bit_before);
++      ssi_rx_word_length (ssi, ssi_16_bits);
++      ssi_rx_bit0 (ssi, false);
++
++      // FIFO set up
++      ssi_rx_fifo_full_watermark (ssi, ssi_fifo_0, RX_WATERMARK);
++      ssi_rx_fifo_enable (ssi, ssi_fifo_0, true);
++}
++
++/*
++ * This function configures the SSI in order to
++ * send data to CODEC. Configuration of SSI consists
++ * mainly in setting the following:
++ *
++ * 1) SSI to use (SSI1 or SSI2)
++ * 2) SSI mode (normal for normal use e.g. playback, network for mixing)
++ * 3) SSI STCCR register settings, which control the sample rate (BCL and
++ *    FS clocks)
++ * 4) Watermarks for SSI FIFOs as well as timeslots to be used.
++ * 5) Enable SSI.
++ *
++ * @param     substream       pointer to the structure of the current stream.
++ */
++void configure_ssi_tx (int ssi)
++{
++      DPRINTK("configure_ssi_tx: SSI%d\n", ssi + 1);
++
++      // disable SSI
++      ssi_clock_off (ssi, false);
++
++      // I2S master, 16 bits, 44.1 KHz
++      // basic I2S settings
++      ssi_network_mode (ssi, true);
++      ssi_synchronous_mode (ssi, true);
++      ssi_tx_shift_direction (ssi, ssi_msb_first);
++      ssi_tx_clock_polarity (ssi, ssi_clock_on_falling_edge);
++      ssi_tx_frame_sync_active (ssi, ssi_frame_sync_active_low);
++      ssi_tx_frame_sync_length (ssi, ssi_frame_sync_one_word);
++      ssi_tx_early_frame_sync (ssi, ssi_frame_sync_one_bit_before);
++      ssi_tx_word_length (ssi, ssi_16_bits);
++      ssi_tx_bit0 (ssi, false);
++
++      // clocks are being provided by SSI
++      ssi_tx_frame_direction (ssi, ssi_tx_rx_internally);
++      ssi_tx_clock_direction (ssi, ssi_tx_rx_internally);
++
++      // FIFO set up
++      ssi_tx_fifo_enable (ssi, ssi_fifo_0, true);
++      ssi_tx_fifo_empty_watermark (ssi, ssi_fifo_0, TX_WATERMARK);
++
++      // Clocking
++      ssi_tx_sampleRate (ssi, 44100);
++      ssi_system_clock (ssi, true);
++
++      // enable ssi
++      ssi_i2s_mode (ssi, i2s_master);
++      ssi_enable (ssi, true);
++}
++
++/*
++ * This function configures number of channels for next audio operation
++ * (recording/playback) Number of channels define if sound is stereo
++ * or mono.
++ *
++ * @param     substream       pointer to the structure of the current stream.
++ *
++ */
++void set_bmi_channels (struct snd_pcm_substream *substream)
++{
++      mxc_bmi_audio_t *chip;
++      audio_stream_t *s;
++
++      chip = snd_pcm_substream_chip (substream);
++      s = &chip->s[substream->pstr->stream];
++
++      ssi_tx_mask_time_slot (s->ssi, MASK_2_TS);
++      ssi_rx_mask_time_slot (s->ssi, MASK_2_TS);
++}
++
++/*
++ * This function configures the DMA channel used to transfer
++ * audio from MCU to CODEC
++ *
++ * @param     substream       pointer to the structure of the current stream.
++ * @param       callback        pointer to function that will be
++ *                              called when a SDMA TX transfer finishes.
++ *
++ * @return              0 on success, -1 otherwise.
++ */
++static int
++configure_write_channel (audio_stream_t *s, mxc_dma_callback_t callback, int stream_id)
++{
++      int ret = -1;
++      int channel = -1;
++
++      if (s->ssi == SSI1)
++              channel = mxc_dma_request (MXC_DMA_SSI1_16BIT_TX0, "ALSA TX DMA1");
++      else
++              channel = mxc_dma_request (MXC_DMA_SSI2_16BIT_TX0, "ALSA TX DMA2");
++
++      if (channel < 0) {
++              PRINTK("error requesting a write dma channel\n");
++              return -1;
++      }
++
++      ret = mxc_dma_callback_set (channel, (mxc_dma_callback_t) callback, (void *) s);
++      if (ret != 0) {
++              mxc_dma_free (channel);
++              return -1;
++      }
++      s->dma_wchannel = channel;
++
++      return 0;
++}
++
++/*
++ * This function configures the DMA channel used to transfer
++ * audio from CODEC to MCU
++ *
++ * @param     substream       pointer to the structure of the current stream.
++ * @param       callback        pointer to function that will be
++ *                              called when a SDMA RX transfer finishes.
++ *
++ * @return              0 on success, -1 otherwise.
++ */
++static int configure_read_channel (audio_stream_t *s,
++                              mxc_dma_callback_t callback)
++{
++      int ret = -1;
++      int channel = -1;
++
++      if (s->ssi == SSI1)
++              channel = mxc_dma_request (MXC_DMA_SSI1_16BIT_RX0, "ALSA RX DMA1");
++      else
++              channel = mxc_dma_request (MXC_DMA_SSI2_16BIT_RX0, "ALSA RX DMA2");
++
++      if (channel < 0) {
++              PRINTK("error requesting a read dma channel\n");
++              return -1;
++      }
++
++      ret =
++          mxc_dma_callback_set (channel, (mxc_dma_callback_t) callback,
++                               (void *) s);
++      if (ret != 0) {
++              mxc_dma_free (channel);
++              return -1;
++      }
++      s->dma_wchannel = channel;
++
++      return 0;
++}
++
++/*
++ * This function frees the stream structure
++ *
++ * @param     s       pointer to the structure of the current stream.
++ */
++static void audio_dma_free (audio_stream_t *s)
++{
++      /*
++       * There is nothing to be done here since the dma channel has been
++       * freed either in the callback or in the stop method
++       */
++}
++
++/*
++ * This function gets the dma pointer position during record.
++ * Our DMA implementation does not allow to retrieve this position
++ * when a transfer is active, so, it answers the middle of
++ * the current period beeing transfered
++ *
++ * @param     s       pointer to the structure of the current stream.
++ *
++ */
++static u_int audio_get_capture_dma_pos (audio_stream_t *s)
++{
++      struct snd_pcm_substream *substream;
++      struct snd_pcm_runtime *runtime;
++      unsigned int offset;
++
++      substream = s->stream;
++      runtime = substream->runtime;
++      offset = 0;
++
++      // tx_spin value is used here to check if a transfer is active
++      if (s->tx_spin) {
++              offset = (runtime->period_size * (s->periods)) + 0;
++              if (offset >= runtime->buffer_size)
++                      offset = 0;
++              DPRINTK("MXC: audio_get_dma_pos offset  %d\n", offset);
++      } else {
++              offset = (runtime->period_size * (s->periods));
++              if (offset >= runtime->buffer_size)
++                      offset = 0;
++              DPRINTK("MXC: audio_get_dma_pos BIS offset  %d\n", offset);
++      }
++
++      return offset;
++}
++
++/*
++ * This function gets the dma pointer position during playback.
++ * Our DMA implementation does not allow to retrieve this position
++ * when a transfer is active, so, it answers the middle of
++ * the current period beeing transfered
++ *
++ * @param     s       pointer to the structure of the current stream.
++ *
++ */
++static u_int audio_get_playback_dma_pos (audio_stream_t *s)
++{
++      struct snd_pcm_substream *substream;
++      struct snd_pcm_runtime *runtime;
++      unsigned int offset;
++
++      substream = s->stream;
++      runtime = substream->runtime;
++      offset = 0;
++
++      // tx_spin value is used here to check if a transfer is active
++      if (s->tx_spin) {
++              offset = (runtime->period_size * (s->periods)) + 0;
++              if (offset >= runtime->buffer_size)
++                      offset = 0;
++              DPRINTK("MXC: audio_get_dma_pos offset  %d\n", offset);
++      } else {
++              offset = (runtime->period_size * (s->periods));
++              if (offset >= runtime->buffer_size)
++                      offset = 0;
++              DPRINTK("MXC: audio_get_dma_pos BIS offset  %d\n", offset);
++      }
++
++      return offset;
++}
++
++/*
++ * This function stops the current dma transfer for playback
++ * and clears the dma pointers.
++ *
++ * @param     substream       pointer to the structure of the current stream.
++ *
++ */
++static void audio_playback_stop_dma (audio_stream_t *s)
++{
++      unsigned long flags;
++      struct snd_pcm_substream *substream;
++      struct snd_pcm_runtime *runtime;
++      unsigned int dma_size;
++      unsigned int offset;
++
++      substream = s->stream;
++      runtime = substream->runtime;
++      dma_size = frames_to_bytes (runtime, runtime->period_size);
++      offset = dma_size * s->periods;
++
++      spin_lock_irqsave (&s->dma_lock, flags);
++
++      PRINTK("MXC : audio_stop_dma active = 0\n");
++      s->active = 0;
++      s->period = 0;
++      s->periods = 0;
++
++      // this stops the dma channel and clears the buffer ptrs
++      mxc_dma_disable (s->dma_wchannel);
++      dma_unmap_single (NULL, runtime->dma_addr + offset, dma_size,
++                       DMA_TO_DEVICE);
++
++      spin_unlock_irqrestore (&s->dma_lock, flags);
++}
++
++/*
++ * This function stops the current dma transfer for capture
++ * and clears the dma pointers.
++ *
++ * @param     substream       pointer to the structure of the current stream.
++ *
++ */
++static void audio_capture_stop_dma (audio_stream_t *s)
++{
++      unsigned long flags;
++      struct snd_pcm_substream *substream;
++      struct snd_pcm_runtime *runtime;
++      unsigned int dma_size;
++      unsigned int offset;
++
++      substream = s->stream;
++      runtime = substream->runtime;
++      dma_size = frames_to_bytes (runtime, runtime->period_size);
++      offset = dma_size * s->periods;
++
++      spin_lock_irqsave (&s->dma_lock, flags);
++
++      PRINTK("MXC : audio_stop_dma active = 0\n");
++      s->active = 0;
++      s->period = 0;
++      s->periods = 0;
++
++      // this stops the dma channel and clears the buffer ptrs
++      mxc_dma_disable (s->dma_wchannel);
++      dma_unmap_single (NULL, runtime->dma_addr + offset, dma_size,
++                       DMA_FROM_DEVICE);
++
++      spin_unlock_irqrestore (&s->dma_lock, flags);
++}
++
++/*
++ * This function is called whenever a new audio block needs to be
++ * transferred to CODEC. The function receives the address and the size
++ * of the new block and start a new DMA transfer.
++ *
++ * @param     substream       pointer to the structure of the current stream.
++ *
++ */
++static void audio_playback_dma (audio_stream_t *s)
++{
++      struct snd_pcm_substream *substream;
++      struct snd_pcm_runtime *runtime;
++      unsigned int dma_size = 0;
++      unsigned int offset;
++      int ret = 0;
++      mxc_dma_requestbuf_t dma_request;
++      int device;
++
++      substream = s->stream;
++      runtime = substream->runtime;
++      device = substream->pcm->device;
++
++      DPRINTK("\nDMA direction %d\(0 is playback 1 is capture)\n",
++               s->stream_id);
++
++      memset (&dma_request, 0, sizeof (mxc_dma_requestbuf_t));
++
++      if (s->active) {
++              if (ssi_get_status(s->ssi) & ssi_transmitter_underrun_0) {
++                      ssi_enable (s->ssi, false);
++                      ssi_transmit_enable (s->ssi, false);
++                      ssi_enable (s->ssi, true);
++              }
++              dma_size = frames_to_bytes (runtime, runtime->period_size);
++              DPRINTK("s->period (%x) runtime->periods (%d)\n",
++                       s->period, runtime->periods);
++              DPRINTK("runtime->period_size (%d) dma_size (%d)\n",
++                       (unsigned int) runtime->period_size,
++                       runtime->dma_bytes);
++
++              offset = dma_size * s->period;
++              snd_assert (dma_size <= DMA_BUF_SIZE,);
++
++              dma_request.src_addr = (dma_addr_t) (dma_map_single (NULL,
++                                                                  runtime->
++                                                                  dma_area +
++                                                                  offset,
++                                                                  dma_size,
++                                                                  DMA_TO_DEVICE));
++
++              if (s->ssi == SSI1)
++                      dma_request.dst_addr = (dma_addr_t) (SSI1_BASE_ADDR + MXC_SSI1STX0);
++              else
++                      dma_request.dst_addr = (dma_addr_t) (SSI2_BASE_ADDR + MXC_SSI2STX0);
++              dma_request.num_of_bytes = dma_size;
++
++              DPRINTK("MXC: Start DMA offset (%d) size (%d)\n", offset,
++                       runtime->dma_bytes);
++
++              mxc_dma_config (s->dma_wchannel, &dma_request, 1,
++                             MXC_DMA_MODE_WRITE);
++              ret = mxc_dma_enable (s->dma_wchannel);
++              ssi_transmit_enable (s->ssi, true);
++              ssi_enable (s->ssi, true);
++              s->tx_spin = 1; /* FGA little trick to retrieve DMA pos */
++
++              if (ret) {
++                      DPRINTK("audio_process_dma: cannot queue DMA buffer\
++                                                              (%i)\n", ret);
++                      return;
++              }
++              s->period++;
++              s->period %= runtime->periods;
++
++#ifdef MXC_SOUND_PLAYBACK_CHAIN_DMA_EN
++              if ((s->period > s->periods) && ((s->period - s->periods) > 1)) {
++                      PRINTK("audio playback chain dma: already double buffered\n");
++                      return;
++              }
++
++              if ((s->period < s->periods)
++                  && ((s->period + runtime->periods - s->periods) > 1)) {
++                      PRINTK("audio playback chain dma: already double buffered\n");
++                      return;
++              }
++
++              if (s->period == s->periods) {
++                      PRINTK("audio playback chain dma: s->period == s->periods\n");
++                      return;
++              }
++
++              if (snd_pcm_playback_hw_avail(runtime) <
++                  2 * runtime->period_size) {
++                      PRINTK("audio playback chain dma: available data is not enough\n");
++                      return;
++              }
++
++              PRINTK("audio playback chain dma:to set up the 2nd dma buffer\n");
++              offset = dma_size * s->period;
++              dma_request.src_addr = (dma_addr_t) (dma_map_single (NULL,
++                                                                  runtime->
++                                                                  dma_area +
++                                                                  offset,
++                                                                  dma_size,
++                                                                  DMA_TO_DEVICE));
++              mxc_dma_config (s->dma_wchannel, &dma_request, 1,
++                             MXC_DMA_MODE_WRITE);
++              ret = mxc_dma_enable (s->dma_wchannel);
++
++              s->period++;
++              s->period %= runtime->periods;
++#endif        // MXC_SOUND_PLAYBACK_CHAIN_DMA_EN
++      }
++}
++
++/*
++ * This function is called whenever a new audio block needs to be
++ * transferred from CODEC. The function receives the address and the size
++ * of the block that will store the audio samples and start a new DMA transfer.
++ *
++ * @param     substream       pointer to the structure of the current stream.
++ *
++ */
++static void audio_capture_dma (audio_stream_t *s)
++{
++      struct snd_pcm_substream *substream;
++      struct snd_pcm_runtime *runtime;
++      unsigned int dma_size;
++      unsigned int offset;
++      int ret = 0;
++      mxc_dma_requestbuf_t dma_request;
++
++      substream = s->stream;
++      runtime = substream->runtime;
++
++      DPRINTK("\nDMA direction %d\
++              (0 is playback 1 is capture)\n", s->stream_id);
++
++      memset (&dma_request, 0, sizeof (mxc_dma_requestbuf_t));
++
++      if (s->active) {
++              dma_size = frames_to_bytes (runtime, runtime->period_size);
++              DPRINTK("s->period (%x) runtime->periods (%d)\n",
++                       s->period, runtime->periods);
++              DPRINTK("runtime->period_size (%d) dma_size (%d)\n",
++                       (unsigned int) runtime->period_size,
++                       runtime->dma_bytes);
++
++              offset = dma_size * s->period;
++              snd_assert (dma_size <= DMA_BUF_SIZE,);
++
++              dma_request.dst_addr = (dma_addr_t) (dma_map_single(NULL,
++                                                                  runtime->
++                                                                  dma_area +
++                                                                  offset,
++                                                                  dma_size,
++                                                                  DMA_FROM_DEVICE));
++              if (s->ssi == SSI1)
++                      dma_request.src_addr = (dma_addr_t) (SSI1_BASE_ADDR + MXC_SSI1SRX0);
++              else
++                      dma_request.src_addr = (dma_addr_t) (SSI2_BASE_ADDR + MXC_SSI2SRX0);
++              dma_request.num_of_bytes = dma_size;
++
++              DPRINTK("MXC: Start DMA offset (%d) size (%d)\n", offset,
++                       runtime->dma_bytes);
++
++              mxc_dma_config (s->dma_wchannel, &dma_request, 1,
++                             MXC_DMA_MODE_READ);
++              ret = mxc_dma_enable (s->dma_wchannel);
++
++              s->tx_spin = 1; /* FGA little trick to retrieve DMA pos */
++
++              if (ret) {
++                      DPRINTK("audio_process_dma: cannot queue DMA buffer\
++                                                              (%i)\n", ret);
++                      return;
++              }
++              s->period++;
++              s->period %= runtime->periods;
++
++#ifdef MXC_SOUND_CAPTURE_CHAIN_DMA_EN
++              if ((s->period > s->periods) && ((s->period - s->periods) > 1)) {
++                      PRINTK("audio capture chain dma: already double buffered\n");
++                      return;
++              }
++
++              if ((s->period < s->periods)
++                  && ((s->period + runtime->periods - s->periods) > 1)) {
++                      PRINTK("audio capture chain dma: already double buffered\n");
++                      return;
++              }
++
++              if (s->period == s->periods) {
++                      PRINTK("audio capture chain dma: s->period == s->periods\n");
++                      return;
++              }
++
++              if (snd_pcm_capture_hw_avail (runtime) <
++                  2 * runtime->period_size) {
++                      PRINTK("audio capture chain dma: available data is not enough\n");
++                      return;
++              }
++
++              PRINTK("audio capture chain dma:to set up the 2nd dma buffer\n");
++              offset = dma_size * s->period;
++              dma_request.dst_addr = (dma_addr_t) (dma_map_single(NULL,
++                                                                  runtime->
++                                                                  dma_area +
++                                                                  offset,
++                                                                  dma_size,
++                                                                  DMA_FROM_DEVICE));
++              mxc_dma_config (s->dma_wchannel, &dma_request, 1,
++                             MXC_DMA_MODE_READ);
++              ret = mxc_dma_enable (s->dma_wchannel);
++
++              s->period++;
++              s->period %= runtime->periods;
++#endif        // MXC_SOUND_CAPTURE_CHAIN_DMA_EN
++      }
++}
++
++/*
++ * This is a callback which will be called
++ * when a TX transfer finishes. The call occurs
++ * in interrupt context.
++ *
++ * @param     dat     pointer to the structure of the current stream.
++ *
++ */
++static void audio_playback_dma_callback (void *data, int error,
++                                      unsigned int count)
++{
++      audio_stream_t *s;
++      struct snd_pcm_substream *substream;
++      struct snd_pcm_runtime *runtime;
++      unsigned int dma_size;
++      unsigned int previous_period;
++      unsigned int offset;
++
++      s = data;
++      substream = s->stream;
++      runtime = substream->runtime;
++      previous_period = s->periods;
++      dma_size = frames_to_bytes (runtime, runtime->period_size);
++      offset = dma_size * previous_period;
++
++      s->tx_spin = 0;
++      s->periods++;
++      s->periods %= runtime->periods;
++
++       // Give back to the CPU the access to the non cached memory
++      dma_unmap_single (NULL, runtime->dma_addr + offset, dma_size,
++                       DMA_TO_DEVICE);
++
++      /*
++       * If we are getting a callback for an active stream then we inform
++       * the PCM middle layer we've finished a period
++       */
++      if (s->active)
++              snd_pcm_period_elapsed (s->stream);
++
++      spin_lock (&s->dma_lock);
++
++      // Trig next DMA transfer
++      audio_playback_dma (s);
++
++      spin_unlock (&s->dma_lock);
++}
++
++/*
++ * This is a callback which will be called when a RX transfer finishes. The
++ * call occurs in interrupt context.
++ *
++ * @param     substream       pointer to the structure of the current stream.
++ */
++static void audio_capture_dma_callback (void *data, int error,
++                                     unsigned int count)
++{
++      audio_stream_t *s;
++      struct snd_pcm_substream *substream;
++      struct snd_pcm_runtime *runtime;
++      unsigned int dma_size;
++      unsigned int previous_period;
++      unsigned int offset;
++
++      s = data;
++      substream = s->stream;
++      runtime = substream->runtime;
++      previous_period = s->periods;
++      dma_size = frames_to_bytes (runtime, runtime->period_size);
++      offset = dma_size * previous_period;
++
++      s->tx_spin = 0;
++      s->periods++;
++      s->periods %= runtime->periods;
++
++      // Give back to the CPU the access to the non cached memory
++      dma_unmap_single (NULL, runtime->dma_addr + offset, dma_size,
++                       DMA_FROM_DEVICE);
++
++      /*
++       * If we are getting a callback for an active stream then we inform
++       * the PCM middle layer we've finished a period
++       */
++      if (s->active)
++              snd_pcm_period_elapsed (s->stream);
++
++      spin_lock (&s->dma_lock);
++
++      // Trig next DMA transfer
++      audio_capture_dma (s);
++
++      spin_unlock (&s->dma_lock);
++}
++
++/*
++ * This function is a dispatcher of command to be executed
++ * by the driver for playback.
++ *
++ * @param     substream       pointer to the structure of the current stream.
++ * @param     cmd             command to be executed
++ *
++ * @return              0 on success, -1 otherwise.
++ */
++static int
++snd_mxc_audio_playback_trigger (struct snd_pcm_substream *substream, int cmd)
++{
++      mxc_bmi_audio_t *chip;
++      int stream_id = PLAYBACK_STREAM;
++      audio_stream_t *s;
++      int err;
++      int device;
++
++      device = substream->pcm->device;
++      chip = snd_pcm_substream_chip (substream);
++      stream_id = substream->pstr->stream;
++      s = &chip->s[stream_id];
++      err = 0;
++
++      // note local interrupts are already disabled in the midlevel code
++      spin_lock (&s->dma_lock);
++      switch (cmd) {
++      case SNDRV_PCM_TRIGGER_START:
++              PRINTK("MXC: SNDRV_PCM_TRIGGER_START\n");
++              s->tx_spin = 0;
++              // requested stream startup
++              s->active = 1;
++              audio_playback_dma (s);
++              break;
++      case SNDRV_PCM_TRIGGER_STOP:
++              PRINTK("MXC: SNDRV_PCM_TRIGGER_STOP\n");
++              // requested stream shutdown
++              audio_playback_stop_dma (s);
++              break;
++      case SNDRV_PCM_TRIGGER_SUSPEND:
++              PRINTK("MXC : SNDRV_PCM_TRIGGER_SUSPEND active = 0\n");
++              s->active = 0;
++              s->periods = 0;
++              break;
++      case SNDRV_PCM_TRIGGER_RESUME:
++              PRINTK("MXC: SNDRV_PCM_TRIGGER_RESUME\n");
++              s->active = 1;
++              s->tx_spin = 0;
++              audio_playback_dma (s);
++              break;
++      case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
++              PRINTK("MXC: SNDRV_PCM_TRIGGER_PAUSE_PUSH\n");
++              s->active = 0;
++              break;
++      case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
++              PRINTK("MXC: SNDRV_PCM_TRIGGER_PAUSE_RELEASE\n");
++              s->active = 1;
++              if (s->old_offset) {
++                      s->tx_spin = 0;
++                      audio_playback_dma (s);
++                      break;
++              }
++              break;
++      default:
++              err = -EINVAL;
++              break;
++      }
++      spin_unlock (&s->dma_lock);
++      return err;
++}
++
++/*
++ * This function is a dispatcher of command to be executed
++ * by the driver for capture.
++ *
++ * @param     substream       pointer to the structure of the current stream.
++ * @param     cmd             command to be executed
++ *
++ * @return              0 on success, -1 otherwise.
++ */
++static int
++snd_mxc_audio_capture_trigger (struct snd_pcm_substream *substream, int cmd)
++{
++      mxc_bmi_audio_t *chip;
++      int stream_id;
++      audio_stream_t *s;
++      int err;
++
++      chip = snd_pcm_substream_chip (substream);
++      stream_id = substream->pstr->stream;
++      s = &chip->s[stream_id];
++      err = 0;
++
++      // note local interrupts are already disabled in the midlevel code
++      spin_lock (&s->dma_lock);
++      switch (cmd) {
++      case SNDRV_PCM_TRIGGER_START:
++              PRINTK("MXC: SNDRV_PCM_TRIGGER_START\n");
++              s->tx_spin = 0;
++              // requested stream startup
++              s->active = 1;
++              audio_capture_dma (s);
++              break;
++      case SNDRV_PCM_TRIGGER_STOP:
++              PRINTK("MXC: SNDRV_PCM_TRIGGER_STOP\n");
++              // requested stream shutdown
++              audio_capture_stop_dma (s);
++              break;
++      case SNDRV_PCM_TRIGGER_SUSPEND:
++              PRINTK("MXC : SNDRV_PCM_TRIGGER_SUSPEND active = 0\n");
++              s->active = 0;
++              s->periods = 0;
++              break;
++      case SNDRV_PCM_TRIGGER_RESUME:
++              PRINTK("MXC: SNDRV_PCM_TRIGGER_RESUME\n");
++              s->active = 1;
++              s->tx_spin = 0;
++              audio_capture_dma (s);
++              break;
++      case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
++              PRINTK("MXC: SNDRV_PCM_TRIGGER_PAUSE_PUSH\n");
++              s->active = 0;
++              break;
++      case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
++              PRINTK("MXC: SNDRV_PCM_TRIGGER_PAUSE_RELEASE\n");
++              s->active = 1;
++              if (s->old_offset) {
++                      s->tx_spin = 0;
++                      audio_capture_dma (s);
++                      break;
++              }
++              break;
++      default:
++              err = -EINVAL;
++              break;
++      }
++      spin_unlock (&s->dma_lock);
++      return err;
++}
++
++/*
++ * This function configures the hardware to allow audio
++ * playback operations. It is called by ALSA framework.
++ *
++ * @param     substream       pointer to the structure of the current stream.
++ *
++ * @return              0 on success, -1 otherwise.
++ */
++static int snd_mxc_audio_playback_prepare (struct snd_pcm_substream *substream)
++{
++      mxc_bmi_audio_t *chip;
++      audio_stream_t *s;
++      int ssi;
++      int device = -1;
++      int stream_id = PLAYBACK_STREAM;
++      struct snd_pcm_runtime *runtime;
++
++      device = substream->pcm->device;
++
++      chip = snd_pcm_substream_chip (substream);
++      runtime = substream->runtime;
++      s = &chip->s[stream_id];
++      ssi = s->ssi;
++
++      configure_dam_bmi_master (ssi);
++      configure_ssi_rx (ssi);
++      ssi_rx_sampleRate (ssi, runtime->rate);
++      configure_ssi_tx (ssi);
++      ssi_tx_sampleRate (ssi, runtime->rate);
++      set_bmi_channels (substream);
++      ssi_interrupt_enable (ssi, ssi_tx_dma_interrupt_enable);
++      ssi_interrupt_enable(ssi, ssi_tx_interrupt_enable);
++      ssi_interrupt_enable (ssi, ssi_tx_fifo_0_empty);
++      ssi_enable(ssi, true);
++
++      s->period = 0;
++      s->periods = 0;
++
++      msleep (100);
++
++      return 0;
++}
++
++/*
++ * This function gets the current capture pointer position.
++ * It is called by ALSA framework.
++ *
++ * @param     substream       pointer to the structure of the current stream.
++ *
++ */
++static snd_pcm_uframes_t
++snd_mxc_audio_capture_pointer (struct snd_pcm_substream *substream)
++{
++      mxc_bmi_audio_t *chip;
++
++      chip = snd_pcm_substream_chip (substream);
++      return audio_get_capture_dma_pos (&chip->s[substream->pstr->stream]);
++}
++
++/*
++ * This function gets the current playback pointer position.
++ * It is called by ALSA framework.
++ *
++ * @param     substream       pointer to the structure of the current stream.
++ *
++ */
++static snd_pcm_uframes_t
++snd_mxc_audio_playback_pointer (struct snd_pcm_substream *substream)
++{
++      mxc_bmi_audio_t *chip;
++      int device;
++      int stream_id;
++      device = substream->pcm->device;
++      stream_id = PLAYBACK_STREAM;
++      chip = snd_pcm_substream_chip (substream);
++      return audio_get_playback_dma_pos (&chip->s[stream_id]);
++}
++
++/*
++ * This structure reprensents the capabilities of the driver
++ * in capture mode.
++ * It is used by ALSA framework.
++ */
++static struct snd_pcm_hardware snd_mxc_bmi_capture = {
++      .info = (SNDRV_PCM_INFO_INTERLEAVED |
++               SNDRV_PCM_INFO_BLOCK_TRANSFER |
++               SNDRV_PCM_INFO_MMAP |
++               SNDRV_PCM_INFO_MMAP_VALID |
++               SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
++      .formats = SNDRV_PCM_FMTBIT_S16_LE,
++      .rates = (SNDRV_PCM_RATE_8000_96000 | SNDRV_PCM_RATE_CONTINUOUS),
++      .rate_min = 8000,
++      .rate_max = 96000,
++      .channels_min = 1,
++      .channels_max = 2,
++      .buffer_bytes_max = MAX_BUFFER_SIZE,
++      .period_bytes_min = MIN_PERIOD_SIZE,
++      .period_bytes_max = DMA_BUF_SIZE,
++      .periods_min = MIN_PERIOD,
++      .periods_max = MAX_PERIOD,
++      .fifo_size = 0,
++};
++
++/*
++ * This structure reprensents the capabilities of the driver
++ * in playback mode for ST-Dac.
++ * It is used by ALSA framework.
++ */
++static struct snd_pcm_hardware snd_mxc_bmi_playback_stereo = {
++      .info = (SNDRV_PCM_INFO_INTERLEAVED |
++               SNDRV_PCM_INFO_BLOCK_TRANSFER |
++               SNDRV_PCM_INFO_MMAP |
++               SNDRV_PCM_INFO_MMAP_VALID |
++               SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
++      .formats = SNDRV_PCM_FMTBIT_S16_LE,
++      .rates = (SNDRV_PCM_RATE_8000_96000 | SNDRV_PCM_RATE_CONTINUOUS),
++      .rate_min = 8000,
++      .rate_max = 96000,
++      .channels_min = 1,
++      .channels_max = 2,
++      .buffer_bytes_max = MAX_BUFFER_SIZE,
++      .period_bytes_min = MIN_PERIOD_SIZE,
++      .period_bytes_max = DMA_BUF_SIZE,
++      .periods_min = MIN_PERIOD,
++      .periods_max = MAX_PERIOD,
++      .fifo_size = 0,
++};
++
++/*
++ * This function opens a CODEC audio device in playback mode
++ * It is called by ALSA framework.
++ *
++ * @param     substream       pointer to the structure of the current stream.
++ *
++ * @return              0 on success, -1 otherwise.
++ */
++static int snd_card_mxc_audio_playback_open (struct snd_pcm_substream *substream)
++{
++      mxc_bmi_audio_t *chip;
++      struct snd_pcm_runtime *runtime;
++      int stream_id = -1;
++      int err;
++      int device = -1;
++
++      device = substream->pcm->device;
++
++      chip = snd_pcm_substream_chip (substream);
++      runtime = substream->runtime;
++      stream_id = PLAYBACK_STREAM;
++
++      err = -1;
++
++      audio_mixer_control[chip->s->ssi].codec_playback_active = 1;
++
++      chip->s[stream_id].stream = substream;
++
++      runtime->hw = snd_mxc_bmi_playback_stereo;
++
++      if ((err = snd_pcm_hw_constraint_integer (runtime,
++                                               SNDRV_PCM_HW_PARAM_PERIODS)) <
++          0)
++              return err;
++      if ((err = snd_pcm_hw_constraint_list (runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
++              &hw_playback_rates_stereo)) < 0)
++              return err;
++
++      msleep (10);
++
++      // setup DMA controller for playback
++      if ((err =
++           configure_write_channel (&mxc_audio[chip->s->ssi]->s[stream_id],
++                                   audio_playback_dma_callback,
++                                   stream_id)) < 0)
++              return err;
++
++      return 0;
++}
++
++/*
++ * This function closes an CODEC audio device for playback.
++ * It is called by ALSA framework.
++ *
++ * @param     substream       pointer to the structure of the current stream.
++ *
++ * @return              0 on success, -1 otherwise.
++ */
++static int snd_card_mxc_audio_playback_close (struct snd_pcm_substream *substream)
++{
++      mxc_bmi_audio_t *chip;
++      audio_stream_t *s;
++      int ssi;
++      int device, stream_id = -1;
++
++      device = substream->pcm->device;
++      stream_id = PLAYBACK_STREAM;
++
++      chip = snd_pcm_substream_chip (substream);
++      s = &chip->s[stream_id];
++      ssi = s->ssi;
++
++      audio_mixer_control[chip->s->ssi].codec_playback_active = 0;
++
++      ssi_tx_fifo_enable (ssi, ssi_fifo_0, false);
++      ssi_interrupt_disable (ssi, ssi_tx_interrupt_enable);
++      ssi_interrupt_disable (ssi, ssi_tx_dma_interrupt_enable);
++      ssi_interrupt_disable (ssi, ssi_tx_fifo_0_empty);
++      mxc_dma_free ((mxc_audio[ssi]->s[stream_id]).dma_wchannel);
++
++      chip->s[stream_id].stream = NULL;
++
++      return 0;
++}
++
++/*
++ * This function closes a audio device for capture.
++ * It is called by ALSA framework.
++ *
++ * @param     substream       pointer to the structure of the current stream.
++ *
++ * @return              0 on success, -1 otherwise.
++ */
++static int snd_card_mxc_audio_capture_close (struct snd_pcm_substream *substream)
++{
++      mxc_bmi_audio_t *chip;
++      audio_stream_t *s;
++      int ssi;
++
++      chip = snd_pcm_substream_chip (substream);
++      s = &chip->s[substream->pstr->stream];
++      ssi = s->ssi;
++
++      audio_mixer_control[ssi].codec_capture_active = 0;
++
++      ssi_rx_fifo_enable (ssi, ssi_fifo_0, false);
++      ssi_interrupt_disable(ssi, ssi_rx_interrupt_enable);
++      ssi_interrupt_disable (ssi, ssi_rx_dma_interrupt_enable);
++      ssi_interrupt_disable (ssi, ssi_rx_fifo_0_full);
++      mxc_dma_free ((mxc_audio[ssi]->s[1]).dma_wchannel);
++
++      chip->s[substream->pstr->stream].stream = NULL;
++
++      return 0;
++}
++
++/*
++ * This function configure the Audio HW in terms of memory allocation.
++ * It is called by ALSA framework.
++ *
++ * @param     substream       pointer to the structure of the current stream.
++ *
++ * @return              0 on success, -1 otherwise.
++ */
++static int snd_mxc_audio_hw_params (struct snd_pcm_substream *substream,
++                                 struct snd_pcm_hw_params *hw_params)
++{
++      struct snd_pcm_runtime *runtime;
++      int ret;
++
++      runtime = substream->runtime;
++      ret =
++          snd_pcm_lib_malloc_pages (substream, params_buffer_bytes (hw_params));
++      if (ret < 0)
++              return ret;
++
++      runtime->dma_addr = virt_to_phys (runtime->dma_area);
++
++      DPRINTK("MXC: snd_mxc_audio_hw_params runtime->dma_addr 0x(%x)\n",
++               (unsigned int) runtime->dma_addr);
++      DPRINTK("MXC: snd_mxc_audio_hw_params runtime->dma_area 0x(%x)\n",
++               (unsigned int) runtime->dma_area);
++      DPRINTK("MXC: snd_mxc_audio_hw_params runtime->dma_bytes 0x(%x)\n",
++               (unsigned int) runtime->dma_bytes);
++
++      return ret;
++}
++
++/*
++ * This function frees the audio hardware at the end of playback/capture.
++ *
++ * @param     substream       pointer to the structure of the current stream.
++ *
++ * @return              0 on success, -1 otherwise.
++ */
++static int snd_mxc_audio_hw_free (struct snd_pcm_substream *substream)
++{
++      return snd_pcm_lib_free_pages (substream);
++}
++
++/*
++ * This function configures the hardware to allow audio
++ * capture operations. It is called by ALSA framework.
++ *
++ * @param     substream       pointer to the structure of the current stream.
++ *
++ * @return              0 on success, -1 otherwise.
++ */
++static int snd_mxc_audio_capture_prepare (struct snd_pcm_substream *substream)
++{
++      mxc_bmi_audio_t *chip;
++      audio_stream_t *s;
++      struct snd_pcm_runtime *runtime;
++      int ssi;
++
++      chip = snd_pcm_substream_chip (substream);
++      runtime = substream->runtime;
++      s = &chip->s[substream->pstr->stream];
++      ssi = s->ssi;
++
++      DPRINTK("substream->pstr->stream %d\n", substream->pstr->stream);
++      DPRINTK("SSI%d\n", ssi + 1);
++
++      configure_dam_bmi_master (ssi);
++      configure_ssi_tx (ssi);
++      ssi_tx_sampleRate (ssi, runtime->rate);
++      configure_ssi_rx (ssi);
++      ssi_rx_sampleRate (ssi, runtime->rate);
++
++      ssi_interrupt_enable (ssi, ssi_rx_fifo_0_full);
++      ssi_interrupt_enable (ssi, ssi_rx_dma_interrupt_enable);
++      ssi_interrupt_enable (ssi, ssi_rx_interrupt_enable);
++      set_bmi_channels (substream);
++      ssi_receive_enable (ssi, true);
++
++      msleep(20);
++
++      s->period = 0;
++      s->periods = 0;
++
++      return 0;
++}
++
++/*
++ * This function opens an audio device in capture mode on Codec.
++ * It is called by ALSA framework.
++ *
++ * @param     substream       pointer to the structure of the current stream.
++ *
++ * @return              0 on success, -1 otherwise.
++ */
++static int snd_card_mxc_audio_capture_open (struct snd_pcm_substream *substream)
++{
++      mxc_bmi_audio_t *chip;
++      struct snd_pcm_runtime *runtime;
++      int stream_id;
++      int err;
++
++      chip = snd_pcm_substream_chip (substream);
++      runtime = substream->runtime;
++      stream_id = substream->pstr->stream;
++      err = -1;
++
++      audio_mixer_control[chip->s->ssi].codec_capture_active = 1;
++
++      chip->s[stream_id].stream = substream;
++
++      if (stream_id == SNDRV_PCM_STREAM_CAPTURE) {
++              runtime->hw = snd_mxc_bmi_capture;
++      } else {
++              return err;
++      }
++
++      if ((err = snd_pcm_hw_constraint_integer (runtime,
++                                               SNDRV_PCM_HW_PARAM_PERIODS)) <
++          0) {
++              return err;
++      }
++
++      if ((err = snd_pcm_hw_constraint_list (runtime, 0,
++                                            SNDRV_PCM_HW_PARAM_RATE,
++                                            &hw_capture_rates_stereo)) < 0) {
++              return err;
++      }
++
++      // setup DMA controller for Record
++      err = configure_read_channel (&mxc_audio[chip->s->ssi]->s[SNDRV_PCM_STREAM_CAPTURE],
++                                   audio_capture_dma_callback);
++      if (err < 0) {
++              return err;
++      }
++
++      msleep (50);
++
++      return 0;
++}
++
++/*
++ * This structure is the list of operation that the driver
++ * must provide for the capture interface
++ */
++static struct snd_pcm_ops snd_card_mxc_audio_capture_ops = {
++      .open = snd_card_mxc_audio_capture_open,
++      .close = snd_card_mxc_audio_capture_close,
++      .ioctl = snd_pcm_lib_ioctl,
++      .hw_params = snd_mxc_audio_hw_params,
++      .hw_free = snd_mxc_audio_hw_free,
++      .prepare = snd_mxc_audio_capture_prepare,
++      .trigger = snd_mxc_audio_capture_trigger,
++      .pointer = snd_mxc_audio_capture_pointer,
++};
++
++/*
++ * This structure is the list of operation that the driver
++ * must provide for the playback interface
++ */
++static struct snd_pcm_ops snd_card_mxc_audio_playback_ops = {
++      .open = snd_card_mxc_audio_playback_open,
++      .close = snd_card_mxc_audio_playback_close,
++      .ioctl = snd_pcm_lib_ioctl,
++      .hw_params = snd_mxc_audio_hw_params,
++      .hw_free = snd_mxc_audio_hw_free,
++      .prepare = snd_mxc_audio_playback_prepare,
++      .trigger = snd_mxc_audio_playback_trigger,
++      .pointer = snd_mxc_audio_playback_pointer,
++};
++
++/*
++ * This functions initializes the capture audio device supported by
++ * CODEC IC.
++ *
++ * @param     mxc_audio       pointer to the sound card structure
++ * @param     device          SSI interface
++ */
++void init_device_capture (mxc_bmi_audio_t *mxc_audio, int device)
++{
++      audio_stream_t *audio_stream;
++
++      audio_stream = &mxc_audio->s[SNDRV_PCM_STREAM_CAPTURE];
++
++      /*
++       * These parameters defines the identity of
++       * the device (stereoadc or stereodac)
++       */
++      if (device == 0) {
++              audio_stream->ssi = SSI1;
++              audio_stream->dam_port = DAM_PORT_4;
++      } else {
++              audio_stream->ssi = SSI2;
++              audio_stream->dam_port = DAM_PORT_5;
++      }
++}
++
++/*
++ * This functions initializes the playback audio device supported by
++ * CODEC IC.
++ *
++ * @param     mxc_audio       pointer to the sound card structure.
++ * @param     device          SSI interface
++ */
++void init_device_playback (mxc_bmi_audio_t *mxc_audio, int device)
++{
++      audio_stream_t *audio_stream;
++      audio_stream = &mxc_audio->s[0];
++
++      /* These parameters defines the identity of
++       * the device (codec or stereodac)
++       */
++      if (device == 0) {
++              audio_stream->ssi = SSI1;
++              audio_stream->dam_port = DAM_PORT_4;
++      } else {
++              audio_stream->ssi = SSI2;
++              audio_stream->dam_port = DAM_PORT_5;
++      }
++}
++
++void mxc_bmi_mixer_controls_init (mxc_bmi_audio_t *mxc_audio, int device)
++{
++      audio_mixer_control_t *audio_control;
++      struct i2c_adapter *adap = 0;
++      char iox_data[1];
++      int i = 0;
++
++      audio_control = &audio_mixer_control[device];
++
++      memset (audio_control, 0, sizeof (audio_mixer_control_t));
++      sema_init (&audio_control->sem, 1);
++
++      for (i = 0; i < OP_MAXDEV; i++) {
++              audio_control->vol_for_output[i] = 9;   // maximum gain
++      }
++      for (i = 0; i < IP_MAXDEV; i++) {
++              audio_control->vol_for_input[i] = 4;    // gain = -6 dB
++      }
++
++      audio_control->master_volume_out = 127;
++
++      if(device == 0) {
++              if (bmi_audio[0].active == 1) {
++                      adap = bmi_device_get_i2c_adapter (bmi_audio[0].bdev);
++              } else if (bmi_audio[2].active == 1) {
++                      adap = bmi_device_get_i2c_adapter (bmi_audio[2].bdev);
++              }
++      } else {
++              if (bmi_audio[1].active == 1) {
++                      adap = bmi_device_get_i2c_adapter (bmi_audio[1].bdev);
++              } else if (bmi_audio[3].active == 1) {
++                      adap = bmi_device_get_i2c_adapter (bmi_audio[3].bdev);
++              }
++      }
++
++      if (adap) {
++              // IOX status
++              if (ReadByte_IOX (adap, IOX_INPUT_REG, iox_data) == 0) {
++                      audio_control->lo_indicator = (*iox_data >> IOX_LO_INS) & 0x1;
++                      audio_control->li_indicator = (*iox_data >> IOX_LI_INS) & 0x1;
++                      audio_control->mic_indicator = (*iox_data >> IOX_MIC_INS) & 0x1;
++                      audio_control->hp_indicator = (*iox_data >> IOX_HP_INS) & 0x1;
++              }
++      }
++}
++
++/*
++ * This functions initializes the audio devices supported by
++ * CODEC IC.
++ *
++ * @param     mxc_audio       pointer to the sound card structure.
++ * @param     device          SSi interface
++ */
++void mxc_bmi_audio_init (mxc_bmi_audio_t *mxc_audio, int device)
++{
++      mxc_audio->s[SNDRV_PCM_STREAM_PLAYBACK].id = "Audio out";
++      mxc_audio->s[SNDRV_PCM_STREAM_PLAYBACK].stream_id = SNDRV_PCM_STREAM_PLAYBACK;
++      mxc_audio->s[SNDRV_PCM_STREAM_CAPTURE].id = "Audio in";
++      mxc_audio->s[SNDRV_PCM_STREAM_CAPTURE].stream_id = SNDRV_PCM_STREAM_CAPTURE;
++
++      init_device_playback (mxc_audio, device);
++      init_device_capture (mxc_audio, device);
++}
++
++/*
++ * This function initializes the soundcard structure.
++ *
++ * @param     mxc_audio       pointer to the sound card structure.
++ * @param     device          the device index (zero based)
++ *
++ * @return              0 on success, -1 otherwise.
++ */
++static int __init snd_card_mxc_audio_pcm (mxc_bmi_audio_t *mxc_audio, int device)
++{
++      struct snd_pcm *pcm;
++      int err;
++
++      // Create a new PCM instance with 1 capture stream and 1 playback substream
++      if (device == 0) {
++              if ((err = snd_pcm_new (mxc_audio->card, "PIM_AUDIO13", 0, 1, 1, &pcm)) < 0) {
++                      return err;
++              }
++      } else {
++              if ((err = snd_pcm_new (mxc_audio->card, "PIM_AUDIO24", 0, 1, 1, &pcm)) < 0) {
++                      return err;
++              }
++      }
++
++      /*
++       * this sets up our initial buffers and sets the dma_type to isa.
++       * isa works but I'm not sure why (or if) it's the right choice
++       * this may be too large, trying it for now
++       */
++      snd_pcm_lib_preallocate_pages_for_all (pcm, SNDRV_DMA_TYPE_CONTINUOUS,
++                                            snd_dma_continuous_data
++                                            (GFP_KERNEL), MAX_BUFFER_SIZE * 2,
++                                            MAX_BUFFER_SIZE * 2);
++
++      snd_pcm_set_ops (pcm, SNDRV_PCM_STREAM_PLAYBACK,
++                      &snd_card_mxc_audio_playback_ops);
++      snd_pcm_set_ops (pcm, SNDRV_PCM_STREAM_CAPTURE,
++                      &snd_card_mxc_audio_capture_ops);
++
++      pcm->private_data = mxc_audio;
++      pcm->info_flags = 0;
++      if (device == 0)
++              strncpy (pcm->name, SOUND_CARD13_NAME, sizeof (pcm->name));
++      else
++              strncpy (pcm->name, SOUND_CARD24_NAME, sizeof (pcm->name));
++      mxc_audio->pcm[0] = pcm;
++      mxc_bmi_audio_init (mxc_audio, device);
++      mxc_bmi_mixer_controls_init (mxc_audio, device);
++
++      return 0;
++}
++
++#if 0 //pjg - POWER_MANAGEMENT
++#ifdef CONFIG_PM
++/*
++  * This function suspends all active streams.
++  *
++  * TBD
++  *
++  * @param    card    pointer to the sound card structure.
++  * @param    state   requested state
++  *
++  * @return              0 on success, -1 otherwise.
++  */
++static int snd_mxc_audio_suspend (struct bmi_device *bdev,
++                               pm_message_t state)
++{
++      struct snd_card *card = bmi_device_get_drvdata (bdev);
++      mxc_bmi_audio_t *chip = card->private_data;
++
++      snd_power_change_state (card, SNDRV_CTL_POWER_D3hot);
++      snd_pcm_suspend_all (chip->pcm[0]);
++      //mxc_alsa_audio_shutdown (chip);
++
++      return 0;
++}
++
++/*
++  * This function resumes all suspended streams.
++  *
++  * TBD
++  *
++  * @param    card    pointer to the sound card structure.
++  * @param    state   requested state
++  *
++  * @return              0 on success, -1 otherwise.
++  */
++static int snd_mxc_audio_resume (struct bmi_device *bdev)
++{
++      struct snd_card *card = bmi_device_get_drvdata (bdev);
++
++      snd_power_change_state (card, SNDRV_CTL_POWER_D0);
++
++      return 0;
++}
++#endif        // CONFIG_PM
++#endif //pjg - POWER_MANAGEMENT
++
++/*
++ * This function frees the sound card structure
++ *
++ * @param     card    pointer to the sound card structure.
++ *
++ * @return              0 on success, -1 otherwise.
++ */
++void snd_mxc_audio_free (struct snd_card *card)
++{
++      mxc_bmi_audio_t *chip;
++
++      chip = card->private_data;
++      audio_dma_free (&chip->s[SNDRV_PCM_STREAM_PLAYBACK]);
++      audio_dma_free (&chip->s[SNDRV_PCM_STREAM_CAPTURE]);
++      mxc_audio[chip->s->ssi] = NULL;
++      card->private_data = NULL;
++      kfree (chip);
++
++}
++
++/*
++ * Input interrupt handler and support routines
++ */
++
++      // work handler
++void bmiaudio_input_work (void *arg, int slot) {
++      struct bmi_audio        *audio = (struct bmi_audio *) arg;
++      audio_mixer_control_t   *audio_control;
++      struct i2c_adapter      *adap;
++      unsigned char           iox_data[1];
++      int                     input_data;
++
++      if (audio->bdev == 0) {
++              printk (KERN_INFO
++                      "bmi_audio.c: bmi_audio_input work called with no bdev (slot %d)\n",
++                      slot);
++              return;
++      }
++
++      if (bmi_device_present (audio->bdev) == 0) {
++              printk (KERN_INFO
++                      "bmi_audio.c: bmi_audio_input work called with no bdev active (slot %d)\n",
++                      slot);
++              return;
++      }
++
++      adap = bmi_device_get_i2c_adapter (audio->bdev);
++
++      // IOX status
++      if (ReadByte_IOX (adap, IOX_INPUT_REG, iox_data) != 0) {
++              return;
++      }
++      input_data = 0;
++      if ((*iox_data & GETSTAT_VOLP) == 0)
++              input_data |= VOLUME_UP;
++      if ((*iox_data & GETSTAT_VOLD) == 0)
++              input_data |= VOLUME_DOWN;
++      if ((*iox_data & GETSTAT_LI_INS) == GETSTAT_LI_INS)
++              input_data |= LINEIN_INSERTED;
++      if ((*iox_data & GETSTAT_MIC_INS) != GETSTAT_MIC_INS)
++              input_data |= MICROPHONE_INSERTED;
++      if (output_ints) {
++              if ((*iox_data & GETSTAT_LO_INS) == GETSTAT_LO_INS)
++                      input_data |= LINEOUT_INSERTED;
++              if ((*iox_data & GETSTAT_HP_INS) == GETSTAT_HP_INS)
++                      input_data |= HEADPHONE_INSERTED;
++      }
++      input_report_abs (audio->input_dev, ABS_MISC, input_data);
++      input_sync (audio->input_dev);
++
++      if ((slot == 0) || (slot == 2)) {
++              audio_control = &audio_mixer_control[0];
++      } else {
++              audio_control = &audio_mixer_control[1];
++      }
++
++      if (down_interruptible (&audio_control->sem) == 0) {
++              audio_control->lo_indicator = (*iox_data >> IOX_LO_INS) & 0x1;
++              audio_control->li_indicator = (*iox_data >> IOX_LI_INS) & 0x1;
++              audio_control->mic_indicator = (*iox_data >> IOX_MIC_INS) & 0x1;
++              audio_control->hp_indicator = (*iox_data >> IOX_HP_INS) & 0x1;
++              up (&audio_control->sem);
++      }
++
++      enable_irq (audio->irq);
++      return;
++}
++
++void bmiaudio_input_work0 (struct work_struct *work) {
++      bmiaudio_input_work (&bmi_audio[0], 0);
++}
++
++void bmiaudio_input_work1 (struct work_struct *work) {
++      bmiaudio_input_work (&bmi_audio[1], 1);
++}
++
++void bmiaudio_input_work2 (struct work_struct *work) {
++      bmiaudio_input_work (&bmi_audio[2], 2);
++}
++
++void bmiaudio_input_work3 (struct work_struct *work) {
++      bmiaudio_input_work (&bmi_audio[3], 3);
++}
++
++DECLARE_DELAYED_WORK(bmiaudio_work0, bmiaudio_input_work0);
++DECLARE_DELAYED_WORK(bmiaudio_work1, bmiaudio_input_work1);
++DECLARE_DELAYED_WORK(bmiaudio_work2, bmiaudio_input_work2);
++DECLARE_DELAYED_WORK(bmiaudio_work3, bmiaudio_input_work3);
++
++static irqreturn_t module_irq_handler (int irq, void *dummy)
++{
++      disable_irq_nosync (irq);
++
++      switch (irq) {
++              case M1_IRQ:
++                      schedule_delayed_work (&bmiaudio_work0, WORK_DELAY);
++                      break;
++              case M2_IRQ:
++                      schedule_delayed_work (&bmiaudio_work1, WORK_DELAY);
++                      break;
++              case M3_IRQ:
++                      schedule_delayed_work (&bmiaudio_work2, WORK_DELAY);
++                      break;
++              case M4_IRQ:
++                      schedule_delayed_work (&bmiaudio_work3, WORK_DELAY);
++                      break;
++      }
++      return IRQ_HANDLED;
++}
++
++/*
++ * Configure the CODEC registers to the initial values
++ */
++
++static int configure_CODEC(struct i2c_adapter *adap, struct bmi_audio *audio)
++{
++      unsigned char codec_data[1];
++
++      // page select = 0
++      if (WriteByte_CODEC (adap, CODEC_PAGE_SEL, 0x00))
++              goto nodev;
++      if (ReadByte_CODEC (adap, CODEC_PAGE_SEL, codec_data))
++              goto nodev;
++      if (*codec_data != 0x00)
++              goto nodev;
++
++      // ADC,DAC SR = SR/1
++      if (WriteByte_CODEC (adap, CODEC_SAMPLE_RATE, (CODEC_SR1 << CODEC_SR_SHIFT) | CODEC_SR1))
++              goto nodev;
++
++      // PLL disabled, Q = 2 => Fsref = 46875 Hz
++      if (WriteByte_CODEC (adap, CODEC_PLLA, CODEC_PLLA_DIS | CODEC_PLLA_Q(2)))
++              goto nodev;
++
++      // CODEC datapath normal
++      if (WriteByte_CODEC (adap, CODEC_DATAPATH,
++                  CODEC_DP_44 | CODEC_DP_L(CODEC_DP_REVERSE) | CODEC_DP_R(CODEC_DP_NORMAL)))
++              goto nodev;
++
++      // CODEC is slave
++      if (WriteByte_CODEC (adap, CODEC_AIFA, CODEC_AIFA_BCLK_S | CODEC_AIFA_WCLK_S |
++                  CODEC_AIFA_DOUT_TS | CODEC_AIFA_CLK_F | CODEC_AIFA_FX_OFF))
++              goto nodev;
++
++      // CODEC is in I2S mode, WL = 32
++      if (WriteByte_CODEC (adap, CODEC_AIFB, CODEC_AIFB_I2S | CODEC_AIFB_32))
++              goto nodev;
++
++      // HP outputs AC coupled
++      if (WriteByte_CODEC (adap, CODEC_HS, CODEC_HS_COUPLED | CODEC_HS_ADIFF))
++              goto nodev;
++
++      // ADC PGA not muted, maximum gain
++      if (WriteByte_CODEC (adap, CODEC_LADC_PGA, CODEC_ADC_PGA_G(0x3C)))      // 59 dB
++              goto nodev;
++      if (WriteByte_CODEC (adap, CODEC_RADC_PGA, CODEC_ADC_PGA_G(0x3C)))      // 59 dB
++              goto nodev;
++
++      // M3R -> [LR]PGA -6 dB gain, M3L muted
++      if (WriteByte_CODEC (adap, CODEC_M3_LPGA, CODEC_M3_PGA_R(0x04) | CODEC_M3_PGA_LOFF))
++              goto nodev;
++      if (WriteByte_CODEC (adap, CODEC_M3_RPGA, CODEC_M3_PGA_R(0x04) | CODEC_M3_PGA_LOFF))
++              goto nodev;
++
++      // L1 -> [LR]PGA gain = -6 dB
++      // selectively activate ADC
++      if (audio->active) {
++              if (WriteByte_CODEC (adap, CODEC_L1L_LPGA, CODEC_L_PGA(0x04) | CODEC_LX_PGA_PU))
++                      goto nodev;
++              if (WriteByte_CODEC (adap, CODEC_L1R_RPGA, CODEC_L_PGA(0x04) | CODEC_LX_PGA_PU))
++                      goto nodev;
++      } else {
++              if (WriteByte_CODEC (adap, CODEC_L1L_LPGA, CODEC_L_PGA(0x0F)))
++                      goto nodev;
++              if (WriteByte_CODEC (adap, CODEC_L1R_RPGA, CODEC_L_PGA(0x0F)))
++                      goto nodev;
++      }
++
++      // L2 -> [LR]PGA gain = -6 dB
++      if (WriteByte_CODEC (adap, CODEC_L2L_LPGA, CODEC_L_PGA(0x04)))
++              goto nodev;
++      if (WriteByte_CODEC (adap, CODEC_L2R_RPGA, CODEC_L_PGA(0x04)))
++              goto nodev;
++
++      // MIC Bias = 2V
++      if (WriteByte_CODEC (adap, CODEC_MIC_BIAS, CODEC_MIC_BIAS_2V))
++              goto nodev;
++
++      // {LR]AGC A
++      if (WriteByte_CODEC (adap, CODEC_MIC_LAGC_A, CODEC_MIC_AGC_EN))
++              goto nodev;
++      if (WriteByte_CODEC (adap, CODEC_MIC_LAGC_A, CODEC_MIC_AGC_EN))
++              goto nodev;
++
++      // {LR]AGC B
++      if (WriteByte_CODEC (adap, CODEC_MIC_LAGC_B, CODEC_MIC_AGC_MG(0x40)))   // 30 dB, 0xEC=59 dB
++              goto nodev;
++      if (WriteByte_CODEC (adap, CODEC_MIC_RAGC_B, CODEC_MIC_AGC_MG(0x40)))   // 30 dB, 0xEC=59 dB
++              goto nodev;
++
++      // DAC powered up
++      if (WriteByte_CODEC (adap, CODEC_DAC_PWR,
++                  CODEC_DAC_PWR_L_EN | CODEC_DAC_PWR_R_EN | CODEC_DAC_PWR_HP_ISE))
++              goto nodev;
++      if (WriteByte_CODEC (adap, CODEC_DAC_HPWR, CODEC_DAC_HPWR_HPL_DIFF))
++              goto nodev;
++      if (WriteByte_CODEC (adap, CODEC_DAC_HPOS, CODEC_DAC_HPOS_SS_DIS))
++              goto nodev;
++
++      // DAC volume = max
++      if (WriteByte_CODEC (adap, CODEC_DAC_LVOL, CODEC_DAC_VOL(0x0)))
++              goto nodev;
++      if (WriteByte_CODEC (adap, CODEC_DAC_RVOL, CODEC_DAC_VOL(0x0)))
++              goto nodev;
++
++      // MIC3->speaker
++      if(fcc_test)
++              if (WriteByte_CODEC (adap, CODEC_PGAR_HPLCOM, 0x80))
++                      goto nodev;
++
++      // output switching volume = max
++      if (WriteByte_CODEC (adap, CODEC_DACL1_HPL, CODEC_HP_EN | CODEC_HP_VOL(0x0)))
++              goto nodev;
++      if (WriteByte_CODEC (adap, CODEC_DACL1_HPLCOM, CODEC_HP_EN | CODEC_HP_VOL(0x0)))
++              goto nodev;
++
++      if (WriteByte_CODEC (adap, CODEC_DACR1_HPR, CODEC_HP_EN | CODEC_HP_VOL(0x0)))
++              goto nodev;
++      if (WriteByte_CODEC (adap, CODEC_DACR1_HPRCOM, CODEC_HP_EN | CODEC_HP_VOL(0x0)))
++              goto nodev;
++
++      if (WriteByte_CODEC (adap, CODEC_DACL1_LLOPM, CODEC_HP_EN | CODEC_HP_VOL(0x0)))
++              goto nodev;
++      if (WriteByte_CODEC (adap, CODEC_DACR1_RLOPM, CODEC_HP_EN | CODEC_HP_VOL(0x0)))
++              goto nodev;
++
++      // output levels = max
++      if (WriteByte_CODEC (adap, CODEC_HPLOUT,
++                  CODEC_HPX_LC(0x09) | CODEC_HPX_EN | CODEC_HPX_PD | CODEC_HPX_PC))
++              goto nodev;
++      if (WriteByte_CODEC (adap, CODEC_HPLCOM,
++                  CODEC_HPX_LC(0x09) | CODEC_HPX_EN | CODEC_HPX_PD | CODEC_HPX_PC))
++              goto nodev;
++      if (WriteByte_CODEC (adap, CODEC_HPROUT,
++                  CODEC_HPX_LC(0x09) | CODEC_HPX_EN | CODEC_HPX_PD | CODEC_HPX_PC))
++              goto nodev;
++      if (WriteByte_CODEC (adap, CODEC_HPRCOM,
++                  CODEC_HPX_LC(0x09) | CODEC_HPX_EN | CODEC_HPX_PD | CODEC_HPX_PC))
++              goto nodev;
++      if (WriteByte_CODEC (adap, CODEC_LLOPM,
++                  CODEC_HPX_LC(0x09) | CODEC_HPX_EN | CODEC_HPX_PD | CODEC_HPX_PC))
++              goto nodev;
++      if (WriteByte_CODEC (adap, CODEC_RLOPM,
++                  CODEC_HPX_LC(0x09) | CODEC_HPX_EN | CODEC_HPX_PD | CODEC_HPX_PC))
++              goto nodev;
++
++      // clocking
++      if (WriteByte_CODEC (adap, CODEC_CLK, CODEC_CLK_CLKDIV))
++              goto nodev;
++      if (WriteByte_CODEC (adap, CODEC_CLKGEN, CODEC_CLKGEN_C_M))
++              goto nodev;
++      return (0);
++
++nodev:
++      WriteByte_CODEC (adap, CODEC_L1L_LPGA, 0x38);
++      WriteByte_CODEC (adap, CODEC_L1R_RPGA, 0x38);
++      return -ENODEV;
++}
++
++/*
++ * This function initializes the driver in terms of BMI and
++ * CODEC functionality.
++ *
++ * @return              0 on success, >0 otherwise.
++ */
++static int mxc_alsa_audio_probe (struct bmi_device *bdev)
++{
++      int rc = 0;
++      struct bmi_audio *audio;
++      struct i2c_adapter *adap;
++      struct cdev *cdev;
++      struct class *bmi_class;
++      int slot;
++      dev_t dev_id;
++      int ssi;
++      unsigned char iox_data[1];
++
++      // bmi set-up
++      slot = bmi_device_get_slot (bdev);
++      adap = bmi_device_get_i2c_adapter (bdev);
++      audio = &bmi_audio[slot];
++
++      audio->bdev = 0;
++
++      // Create 1 minor device
++      cdev = &audio->cdev;
++      cdev_init (cdev, &cntl_fops);
++
++      dev_id = MKDEV(major, slot);
++      rc = cdev_add (cdev, dev_id, 1);
++      if (rc)
++              return rc;
++
++      // Create class device
++      bmi_class = bmi_get_bmi_class ();
++      audio->class_dev = device_create (bmi_class, NULL, MKDEV(major, slot), audio, "bmi_audio_ctrl_m%i", slot+1);
++
++      if (IS_ERR(audio->class_dev)) {
++              printk (KERN_ERR "Unable to create class_device for bmi_audio_m%i; errno = %ld\n",
++                     slot+1, PTR_ERR(audio->class_dev));
++              cdev_del (&audio->cdev);
++              audio->class_dev = NULL;
++              return -ENODEV;
++      }
++
++      // bind driver and bmi_device
++      audio->bdev = bdev;
++
++      // check for opposite side already active
++      switch (slot) {
++              case 0:
++                      ssi = 0;
++                      if (bmi_audio[2].active == 0) {
++                              mxc_audio[0]->card->dev = &bdev->dev;
++                              audio->active = 1;
++                      }
++                      break;
++              case 1:
++                      ssi = 1;
++                      if (bmi_audio[3].active == 0) {
++                              mxc_audio[1]->card->dev = &bdev->dev;
++                              audio->active = 1;
++                      }
++                      break;
++              case 2:
++                      ssi = 0;
++                      if (bmi_audio[0].active == 0) {
++                              mxc_audio[0]->card->dev = &bdev->dev;
++                              audio->active = 1;
++                      }
++                      break;
++              case 3:
++                      ssi = 1;
++                      if (bmi_audio[1].active == 0) {
++                              mxc_audio[1]->card->dev = &bdev->dev;
++                              audio->active = 1;
++                      }
++                      break;
++      }
++
++      bmi_device_set_drvdata (bdev, &bmi_audio[slot]);
++
++      // Initialize GPIOs (turn LED's on )
++      // bmi_slot_gpio_configure_as_output (int slot, int gpio, int data)
++      bmi_slot_gpio_configure_as_output (slot, GPIO_RED, BMI_GPIO_OFF);       // Red LED=ON
++      bmi_slot_gpio_configure_as_output (slot, GPIO_GREEN, BMI_GPIO_OFF);     // Green LED=ON
++      bmi_slot_gpio_configure_as_output (slot, GPIO_RESET, BMI_GPIO_OFF);     // Assert RST = 0;
++      bmi_slot_gpio_configure_as_input (slot, GPIO_SPARE);                    // unused
++
++      mdelay (200);
++
++      // turn LED's off
++      bmi_slot_gpio_write_bit (slot, GPIO_RED, BMI_GPIO_ON);          // Red LED=OFF
++      bmi_slot_gpio_write_bit (slot, GPIO_GREEN, BMI_GPIO_ON);        // Green LED=OFF
++
++      // release reset
++      bmi_slot_gpio_write_bit (slot, GPIO_RESET, BMI_GPIO_ON);        // Reset = 1
++
++      // configure IOX
++      if (WriteByte_IOX (adap, IOX_OUTPUT_REG, 0x01))
++              goto nodev;
++
++      if (output_ints) {
++              if (WriteByte_IOX (adap, IOX_CONTROL, 0xFC))             // IOX[1:0]=OUT, IOX[7:2]=IN
++                      goto nodev;
++      } else {
++              if (WriteByte_IOX (adap, IOX_CONTROL, 0x6C))             // IOX[7,4,1:0]=OUT, IOX[6:5,3:2]=IN
++                      goto nodev;
++      }
++
++      if (ReadByte_IOX (adap, IOX_INPUT_REG, iox_data))       // clear interrupts
++              goto nodev;
++
++      printk (KERN_INFO "bmi_audio.c: probe(%d) IOX = 0x%x\n", slot, *iox_data & 0xFF);
++
++#ifdef CODEC  // CODEC
++      // configure codec
++      if (configure_CODEC(adap, audio))
++              goto nodev;
++#endif        // CODEC
++
++      // set up input interrupt
++      audio->irq = bmi_device_get_status_irq (bdev);
++      snprintf (audio->int_name, sizeof (audio->int_name), "bmi_audio_stat_m%d", slot + 1);
++      if  (request_irq (audio->irq, &module_irq_handler, 0, audio->int_name, &bmi_audio[slot])) {
++              printk (KERN_ERR "bmi_audio.c: Can't allocate irq %d or find audio in slot %d\n",
++                      audio->irq, slot + 1);
++              device_destroy (bmi_class, MKDEV(major, slot));
++              cdev_del (&audio->cdev);
++              audio->class_dev = NULL;
++              return -EBUSY;
++      }
++
++              // power stablization delay
++        mdelay (500);
++      return 0;
++
++nodev:
++      device_destroy (bmi_class, MKDEV(major, slot));
++      cdev_del (&audio->cdev);
++      audio->class_dev = NULL;
++      return -ENODEV;
++}
++
++void mxc_alsa_audio_remove (struct bmi_device *bdev)
++{
++      struct bmi_audio *audio = (struct bmi_audio *) (bmi_device_get_drvdata (bdev));
++      int slot = bmi_device_get_slot (bdev);
++      struct class *bmi_class;
++
++      // release sound card srtucture
++      if (bmi_audio[slot].active && ((slot == 0) || (slot == 2)))
++              mxc_audio[0]->card->dev = NULL;
++      else if (bmi_audio[slot]. active && ((slot == 1) || (slot == 3)))
++              mxc_audio[1]->card->dev = NULL;
++
++      // remove input interrupt scheduled work
++      free_irq (bmi_device_get_status_irq (bdev), &bmi_audio[slot]);
++      switch(slot) {
++              case 0:
++                      cancel_delayed_work(&bmiaudio_work0);
++                      break;
++              case 1:
++                      cancel_delayed_work(&bmiaudio_work1);
++                      break;
++              case 2:
++                      cancel_delayed_work(&bmiaudio_work2);
++                      break;
++              case 3:
++                      cancel_delayed_work(&bmiaudio_work3);
++                      break;
++      }
++
++
++      // deconfigure GPIO
++      bmi_slot_gpio_configure_all_as_inputs (slot);
++
++      // remove class device
++      bmi_class = bmi_get_bmi_class ();
++      device_destroy (bmi_class, MKDEV(major, slot));
++
++      // clean slot structure
++      cdev_del (&audio->cdev);
++      audio->class_dev = NULL;
++      audio->bdev = NULL;
++      audio->active = 0;
++
++      // de-attach driver-specific struct from bmi_device structure
++      bmi_device_set_drvdata (bdev, 0);
++
++      return;
++}
++
++// BMI device ID table
++static struct bmi_device_id bmi_audio_tbl[] =
++{
++      {
++              .match_flags = BMI_DEVICE_ID_MATCH_VENDOR | BMI_DEVICE_ID_MATCH_PRODUCT,
++              .vendor   = BMI_VENDOR_BUG_LABS,
++              .product  = BMI_PRODUCT_AUDIO,
++              .revision = BMI_ANY,
++      },
++      { 0, }, // terminate list
++};
++MODULE_DEVICE_TABLE(bmi, bmi_audio_tbl);
++
++static struct bmi_driver bmi_audio_driver = {
++      .name = "bmi_audio",
++      .id_table = bmi_audio_tbl,
++      .probe = mxc_alsa_audio_probe,
++      .remove = mxc_alsa_audio_remove,
++#if 0 //pjg - POWER_MANAGEMENT
++#ifdef CONFIG_PM
++      .suspend = snd_mxc_audio_suspend,
++      .resume = snd_mxc_audio_resume,
++#endif
++#endif        //pjg - POWER_MANAGEMENT
++      .driver = {
++                 .name = "pim_ALSA",
++                 },
++};
++
++// mxc-alsa-mixer.c
++
++/*
++  * These are the functions implemented in the ALSA PCM driver that
++  * are used for mixer operations
++  *
++  */
++
++      //
++      // DAC Volume control
++      //
++      // PIM_AUDIO13
++static int bmi_pb_volume_put0 (struct snd_kcontrol *kcontrol,
++                            struct snd_ctl_elem_value *uvalue)
++{
++      struct i2c_adapter *adap = 0;
++      int volume;
++
++      // calculate register value
++      volume = uvalue->value.integer.value[0];
++      volume = 127 - volume;
++
++      // get I2C dapter
++      if (bmi_audio[0].active) {
++              adap = bmi_device_get_i2c_adapter (bmi_audio[0].bdev);
++      } else if (bmi_audio[2].active) {
++              adap = bmi_device_get_i2c_adapter (bmi_audio[2].bdev);
++      }
++
++#ifdef CODEC
++      // set volume
++      if (adap) {
++              // write page register
++              if (WriteByte_CODEC (adap, 0x0, 0x0))
++                      return -ENODEV;
++              if (WriteByte_CODEC (adap, CODEC_DAC_LVOL, CODEC_DAC_VOL(volume)))
++                      return -ENODEV;
++              if (WriteByte_CODEC (adap, CODEC_DAC_RVOL, CODEC_DAC_VOL(volume)))
++                      return -ENODEV;
++      } else {
++              return -1;
++      }
++#endif        // CODEC
++
++      if (down_interruptible (&audio_mixer_control[0].sem))
++              return -EINTR;
++
++      audio_mixer_control[0].master_volume_out = uvalue->value.integer.value[0];
++
++      up (&audio_mixer_control[0].sem);
++
++      return 0;
++}
++static int bmi_pb_volume_info0 (struct snd_kcontrol *kcontrol,
++                             struct snd_ctl_elem_info *uinfo)
++{
++
++      uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
++      uinfo->count = 1;
++      uinfo->value.integer.min = 0;
++      uinfo->value.integer.max = 127;
++      uinfo->value.integer.step = 1;
++      return 0;
++}
++
++static int bmi_pb_volume_get0 (struct snd_kcontrol *kcontrol,
++                            struct snd_ctl_elem_value *uvalue)
++{
++      struct i2c_adapter *adap = 0;
++      char val[1];
++
++      *val = 0x0;
++
++      // get I2C dapter
++      if (bmi_audio[0].active) {
++              adap = bmi_device_get_i2c_adapter (bmi_audio[0].bdev);
++      } else if (bmi_audio[2].active) {
++              adap = bmi_device_get_i2c_adapter (bmi_audio[2].bdev);
++      }
++
++#ifdef CODEC
++      if (adap) {
++              // write page register
++              if (WriteByte_CODEC (adap, 0x0, 0x0))
++                      return -ENODEV;
++              if (ReadByte_CODEC (adap, CODEC_DAC_LVOL, val))
++                      return -ENODEV;
++      } else {
++              *val = 0;
++      }
++#endif        // CODEC
++
++      uvalue->value.integer.value[0] = 127 - ((int) *val);
++
++#ifdef CODEC
++      if (adap)
++              return 0;
++      else
++              return -1;
++#endif        // CODEC
++      return 0;
++}
++
++struct snd_kcontrol_new bmi_control_pb_vol0 __devinitdata = {
++      .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++      .name = "Master Playback Volume",
++      .index = 0x00,
++      .info = bmi_pb_volume_info0,
++      .get = bmi_pb_volume_get0,
++      .put = bmi_pb_volume_put0,
++      .private_value = 0xffab1,
++};
++
++// PIM_AUDIO24
++static int bmi_pb_volume_put1 (struct snd_kcontrol *kcontrol,
++                            struct snd_ctl_elem_value *uvalue)
++{
++      struct i2c_adapter *adap = 0;
++      int volume;
++
++      // calculate register value
++      volume = uvalue->value.integer.value[0];
++      volume = 127 - volume;
++
++      // get I2C dapter
++      if  (bmi_audio[1].active) {
++              adap = bmi_device_get_i2c_adapter (bmi_audio[1].bdev);
++      } else if (bmi_audio[3].active) {
++              adap = bmi_device_get_i2c_adapter (bmi_audio[3].bdev);
++      }
++
++#ifdef CODEC
++      // set volume
++      if (adap) {
++              // write page register
++              if (WriteByte_CODEC (adap, 0x0, 0x0))
++                      return -ENODEV;
++              if (WriteByte_CODEC (adap, CODEC_DAC_LVOL, CODEC_DAC_VOL(volume)))
++                      return -ENODEV;
++              if (WriteByte_CODEC (adap, CODEC_DAC_RVOL, CODEC_DAC_VOL(volume)))
++                      return -ENODEV;
++      } else {
++              return -1;
++      }
++#endif        // CODEC
++
++      if (down_interruptible (&audio_mixer_control[1].sem))
++              return -EINTR;
++
++      audio_mixer_control[1].master_volume_out = uvalue->value.integer.value[0];
++
++      up (&audio_mixer_control[1].sem);
++
++      return 0;
++}
++static int bmi_pb_volume_info1 (struct snd_kcontrol *kcontrol,
++                             struct snd_ctl_elem_info *uinfo)
++{
++
++      uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
++      uinfo->count = 1;
++      uinfo->value.integer.min = 0;
++      uinfo->value.integer.max = 127;
++      uinfo->value.integer.step = 1;
++      return 0;
++}
++
++static int bmi_pb_volume_get1 (struct snd_kcontrol *kcontrol,
++                            struct snd_ctl_elem_value *uvalue)
++{
++      struct i2c_adapter *adap = 0;
++      char val[1];
++
++      *val = 0x0;
++
++      // get I2C dapter
++      if (bmi_audio[1].active) {
++              adap = bmi_device_get_i2c_adapter (bmi_audio[1].bdev);
++      } else if (bmi_audio[3].active) {
++              adap = bmi_device_get_i2c_adapter (bmi_audio[3].bdev);
++      }
++
++#ifdef CODEC
++      if (adap) {
++              // write page register
++              if (WriteByte_CODEC (adap, 0x0, 0x0))
++                      return -ENODEV;
++              if (ReadByte_CODEC (adap, CODEC_DAC_LVOL, val))
++                      return -ENODEV;
++      } else {
++              *val = 0;
++      }
++#endif        // CODEC
++
++      uvalue->value.integer.value[0] = 127 - ((int) *val);
++
++#ifdef CODEC
++      if (adap)
++              return 0;
++      else
++              return -1;
++#endif        // CODEC
++      return 0;
++}
++
++struct snd_kcontrol_new bmi_control_pb_vol1 __devinitdata = {
++      .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++      .name = "Master Playback Volume",
++      .index = 0x00,
++      .info = bmi_pb_volume_info1,
++      .get = bmi_pb_volume_get1,
++      .put = bmi_pb_volume_put1,
++      .private_value = 0xffab1,
++};
++
++//
++// LI (L1) Volume control
++//
++// PIM_AUDIO13
++static int bmi_li_volume_put0 (struct snd_kcontrol *kcontrol,
++                            struct snd_ctl_elem_value *uvalue)
++{
++      struct i2c_adapter *adap = 0;
++      int volume;
++
++      // calculate register value
++      volume = uvalue->value.integer.value[0];
++      volume = 8 - volume;
++      if (volume == 0)
++              volume = 0xF;   // mute
++
++      // get I2C dapter
++      if (bmi_audio[0].active) {
++              adap = bmi_device_get_i2c_adapter (bmi_audio[0].bdev);
++      } else if (bmi_audio[2].active) {
++              adap = bmi_device_get_i2c_adapter (bmi_audio[2].bdev);
++      }
++
++#ifdef CODEC
++      // set volume
++      if (adap) {
++              // write page register
++              if (WriteByte_CODEC (adap, 0x0, 0x0))
++                      return -ENODEV;
++              if (WriteByte_CODEC (adap, CODEC_L1L_LPGA, CODEC_L_PGA(volume) | CODEC_LX_PGA_PU))
++                      return -ENODEV;
++              if (WriteByte_CODEC (adap, CODEC_L1R_RPGA, CODEC_L_PGA(volume) | CODEC_LX_PGA_PU))
++                      return -ENODEV;
++      } else {
++              return -1;
++      }
++#endif        // CODEC
++
++      if (down_interruptible (&audio_mixer_control[0].sem))
++              return -EINTR;
++
++      audio_mixer_control[0].vol_for_input[IP_LINEIN] = uvalue->value.integer.value[0];
++
++      up (&audio_mixer_control[0].sem);
++
++      return 0;
++}
++static int bmi_li_volume_info0 (struct snd_kcontrol *kcontrol,
++                             struct snd_ctl_elem_info *uinfo)
++{
++
++      uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
++      uinfo->count = 1;
++      uinfo->value.integer.min = 0;
++      uinfo->value.integer.max = 8;
++      uinfo->value.integer.step = 1;
++      return 0;
++}
++
++static int bmi_li_volume_get0 (struct snd_kcontrol *kcontrol,
++                            struct snd_ctl_elem_value *uvalue)
++{
++      if (down_interruptible (&audio_mixer_control[0].sem))
++              return -EINTR;
++
++      uvalue->value.integer.value[0] = audio_mixer_control[0].vol_for_input[IP_LINEIN];
++
++      up (&audio_mixer_control[0].sem);
++
++      return 0;
++}
++
++struct snd_kcontrol_new bmi_control_li_vol0 __devinitdata = {
++      .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++      .name = "Linein Capture Volume/Mute",
++      .index = 0x00,
++      .info = bmi_li_volume_info0,
++      .get = bmi_li_volume_get0,
++      .put = bmi_li_volume_put0,
++      .private_value = 0xffab3,
++};
++
++// PIM_AUDIO24
++static int bmi_li_volume_put1 (struct snd_kcontrol *kcontrol,
++                            struct snd_ctl_elem_value *uvalue)
++{
++      struct i2c_adapter *adap = 0;
++      int volume;
++
++      // calculate register value
++      volume = uvalue->value.integer.value[0];
++      volume = 8 - volume;
++      if (volume == 0)
++              volume = 0xF;   // mute
++
++      // get I2C dapter
++      if (bmi_audio[1].active) {
++              adap = bmi_device_get_i2c_adapter (bmi_audio[1].bdev);
++      } else if (bmi_audio[3].active) {
++              adap = bmi_device_get_i2c_adapter (bmi_audio[3].bdev);
++      }
++
++#ifdef CODEC
++      // set volume
++      if (adap) {
++              // write page register
++              if (WriteByte_CODEC (adap, 0x0, 0x0))
++                      return -ENODEV;
++              if (WriteByte_CODEC (adap, CODEC_L1L_LPGA, CODEC_L_PGA(volume) | CODEC_LX_PGA_PU))
++                      return -ENODEV;
++              if (WriteByte_CODEC (adap, CODEC_L1R_RPGA, CODEC_L_PGA(volume) | CODEC_LX_PGA_PU))
++                      return -ENODEV;
++      } else {
++              return -1;
++      }
++#endif        // CODEC
++
++      if (down_interruptible (&audio_mixer_control[1].sem))
++              return -EINTR;
++
++      audio_mixer_control[1].vol_for_input[IP_LINEIN] = uvalue->value.integer.value[0];
++
++      up (&audio_mixer_control[1].sem);
++
++      return 0;
++}
++static int bmi_li_volume_info1 (struct snd_kcontrol *kcontrol,
++                             struct snd_ctl_elem_info *uinfo)
++{
++
++      uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
++      uinfo->count = 1;
++      uinfo->value.integer.min = 0;
++      uinfo->value.integer.max = 8;
++      uinfo->value.integer.step = 1;
++      return 0;
++}
++
++static int bmi_li_volume_get1 (struct snd_kcontrol *kcontrol,
++                            struct snd_ctl_elem_value *uvalue)
++{
++      if  (down_interruptible (&audio_mixer_control[1].sem))
++              return -EINTR;
++
++      uvalue->value.integer.value[0] = audio_mixer_control[1].vol_for_input[IP_LINEIN];
++
++      up (&audio_mixer_control[1].sem);
++
++      return 0;
++}
++
++struct snd_kcontrol_new bmi_control_li_vol1 __devinitdata = {
++      .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++      .name = "Linein Capture Volume/Mute",
++      .index = 0x00,
++      .info = bmi_li_volume_info1,
++      .get = bmi_li_volume_get1,
++      .put = bmi_li_volume_put1,
++      .private_value = 0xffab3,
++};
++
++//
++// MIC (L2) Volume control
++//
++// PIM_AUDIO13
++static int bmi_mic_volume_put0 (struct snd_kcontrol *kcontrol,
++                            struct snd_ctl_elem_value *uvalue)
++{
++      struct i2c_adapter *adap = 0;
++      int volume;
++
++      // calculate register value
++      volume = uvalue->value.integer.value[0];
++      volume = 8 - volume;
++      if (volume == 0)
++              volume = 0xF;   // mute
++
++      // get I2C dapter
++      if (bmi_audio[0].active) {
++              adap = bmi_device_get_i2c_adapter (bmi_audio[0].bdev);
++      } else if (bmi_audio[2].active) {
++              adap = bmi_device_get_i2c_adapter (bmi_audio[2].bdev);
++      }
++
++#ifdef CODEC
++      // set volume
++      if (adap) {
++              // write page register
++              if (WriteByte_CODEC (adap, 0x0, 0x0))
++                      return -ENODEV;
++              if (WriteByte_CODEC (adap, CODEC_L2L_LPGA, CODEC_L_PGA(volume)))
++                      return -ENODEV;
++              if (WriteByte_CODEC (adap, CODEC_L2R_RPGA, CODEC_L_PGA(volume)))
++                      return -ENODEV;
++      } else {
++              return -1;
++      }
++#endif        // CODEC
++
++      if (down_interruptible (&audio_mixer_control[0].sem))
++              return -EINTR;
++
++      audio_mixer_control[0].vol_for_input[IP_MIC] = uvalue->value.integer.value[0];
++
++      up (&audio_mixer_control[0].sem);
++
++      return 0;
++}
++static int bmi_mic_volume_info0 (struct snd_kcontrol *kcontrol,
++                             struct snd_ctl_elem_info *uinfo)
++{
++
++      uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
++      uinfo->count = 1;
++      uinfo->value.integer.min = 0;
++      uinfo->value.integer.max = 8;
++      uinfo->value.integer.step = 1;
++      return 0;
++}
++
++static int bmi_mic_volume_get0 (struct snd_kcontrol *kcontrol,
++                            struct snd_ctl_elem_value *uvalue)
++{
++      if (down_interruptible (&audio_mixer_control[0].sem))
++              return -EINTR;
++
++      uvalue->value.integer.value[0] = audio_mixer_control[0].vol_for_input[IP_MIC];
++
++      up (&audio_mixer_control[0].sem);
++
++      return 0;
++}
++
++struct snd_kcontrol_new bmi_control_mic_vol0 __devinitdata = {
++      .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++      .name = "Mic Capture Volume/Mute",
++      .index = 0x00,
++      .info = bmi_mic_volume_info0,
++      .get = bmi_mic_volume_get0,
++      .put = bmi_mic_volume_put0,
++      .private_value = 0xffab4,
++};
++
++// PIM_AUDIO24
++static int bmi_mic_volume_put1 (struct snd_kcontrol *kcontrol,
++                            struct snd_ctl_elem_value *uvalue)
++{
++      struct i2c_adapter *adap = 0;
++      int volume;
++
++      // calculate register value
++      volume = uvalue->value.integer.value[0];
++      volume = 8 - volume;
++      if (volume == 0)
++              volume = 0xF;   // mute
++
++      // get I2C dapter
++      if (bmi_audio[1].active) {
++              adap = bmi_device_get_i2c_adapter (bmi_audio[1].bdev);
++      } else if (bmi_audio[3].active) {
++              adap = bmi_device_get_i2c_adapter (bmi_audio[3].bdev);
++      }
++
++#ifdef CODEC
++      // set volume
++      if (adap) {
++              // write page register
++              if (WriteByte_CODEC (adap, 0x0, 0x0))
++                      return -ENODEV;
++              if (WriteByte_CODEC (adap, CODEC_L2L_LPGA, CODEC_L_PGA(volume)))
++                      return -ENODEV;
++              if (WriteByte_CODEC (adap, CODEC_L2R_RPGA, CODEC_L_PGA(volume)))
++                      return -ENODEV;
++      } else {
++              return -1;
++      }
++#endif        // CODEC
++
++      if (down_interruptible (&audio_mixer_control[1].sem))
++              return -EINTR;
++
++      audio_mixer_control[1].vol_for_input[IP_MIC] = uvalue->value.integer.value[0];
++
++      up (&audio_mixer_control[1].sem);
++
++      return 0;
++}
++static int bmi_mic_volume_info1 (struct snd_kcontrol *kcontrol,
++                             struct snd_ctl_elem_info *uinfo)
++{
++
++      uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
++      uinfo->count = 1;
++      uinfo->value.integer.min = 0;
++      uinfo->value.integer.max = 8;
++      uinfo->value.integer.step = 1;
++      return 0;
++}
++
++static int bmi_mic_volume_get1 (struct snd_kcontrol *kcontrol,
++                            struct snd_ctl_elem_value *uvalue)
++{
++      if (down_interruptible (&audio_mixer_control[1].sem))
++              return -EINTR;
++
++      uvalue->value.integer.value[0] = audio_mixer_control[1].vol_for_input[IP_MIC];
++
++      up (&audio_mixer_control[1].sem);
++
++      return 0;
++}
++
++struct snd_kcontrol_new bmi_control_mic_vol1 __devinitdata = {
++      .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++      .name = "Mic Capture Volume/Mute",
++      .index = 0x00,
++      .info = bmi_mic_volume_info1,
++      .get = bmi_mic_volume_get1,
++      .put = bmi_mic_volume_put1,
++      .private_value = 0xffab4,
++};
++
++//
++// EMIC (L3) Volume control
++//
++// PIM_AUDIO13
++static int bmi_emic_volume_put0 (struct snd_kcontrol *kcontrol,
++                            struct snd_ctl_elem_value *uvalue)
++{
++      struct i2c_adapter *adap = 0;
++      int volume;
++
++      // calculate register value
++      volume = uvalue->value.integer.value[0];
++      volume = 8 - volume;
++      if (volume == 0)
++              volume = 0xF;   // mute
++
++      // get I2C dapter
++      if (bmi_audio[0].active) {
++              adap = bmi_device_get_i2c_adapter (bmi_audio[0].bdev);
++      } else if (bmi_audio[2].active) {
++              adap = bmi_device_get_i2c_adapter (bmi_audio[2].bdev);
++      }
++
++#ifdef CODEC
++      // set volume
++      if (adap) {
++              // write page register
++              if (WriteByte_CODEC (adap, 0x0, 0x0))
++                      return -ENODEV;
++              if (WriteByte_CODEC (adap, CODEC_M3_LPGA, CODEC_M3_PGA_R(volume)))
++                      return -ENODEV;
++              if (WriteByte_CODEC (adap, CODEC_M3_RPGA, CODEC_M3_PGA_R(volume)))
++                      return -ENODEV;
++      } else {
++              return -1;
++      }
++#endif        // CODEC
++
++      if  (down_interruptible (&audio_mixer_control[0].sem))
++              return -EINTR;
++
++      audio_mixer_control[0].vol_for_input[IP_EMIC] = uvalue->value.integer.value[0];
++
++      up (&audio_mixer_control[0].sem);
++
++      return 0;
++}
++static int bmi_emic_volume_info0 (struct snd_kcontrol *kcontrol,
++                             struct snd_ctl_elem_info *uinfo)
++{
++
++      uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
++      uinfo->count = 1;
++      uinfo->value.integer.min = 0;
++      uinfo->value.integer.max = 8;
++      uinfo->value.integer.step = 1;
++      return 0;
++}
++
++static int bmi_emic_volume_get0 (struct snd_kcontrol *kcontrol,
++                            struct snd_ctl_elem_value *uvalue)
++{
++      if (down_interruptible (&audio_mixer_control[0].sem))
++              return -EINTR;
++
++      uvalue->value.integer.value[0] = audio_mixer_control[0].vol_for_input[IP_EMIC];
++
++      up (&audio_mixer_control[0].sem);
++
++      return 0;
++}
++
++struct snd_kcontrol_new bmi_control_emic_vol0 __devinitdata = {
++      .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++      .name = "Emic Capture Volume/Mute",
++      .index = 0x00,
++      .info = bmi_emic_volume_info0,
++      .get = bmi_emic_volume_get0,
++      .put = bmi_emic_volume_put0,
++      .private_value = 0xffab5,
++};
++
++// PIM_AUDIO24
++static int bmi_emic_volume_put1 (struct snd_kcontrol *kcontrol,
++                            struct snd_ctl_elem_value *uvalue)
++{
++      struct i2c_adapter *adap = 0;
++      int volume;
++
++      // calculate register value
++      volume = uvalue->value.integer.value[0];
++      volume = 8 - volume;
++      if (volume == 0)
++              volume = 0xF;   // mute
++
++      // get I2C dapter
++      if (bmi_audio[1].active) {
++              adap = bmi_device_get_i2c_adapter (bmi_audio[1].bdev);
++      } else if (bmi_audio[3].active) {
++              adap = bmi_device_get_i2c_adapter (bmi_audio[3].bdev);
++      }
++
++#ifdef CODEC
++      // set volume
++      if (adap) {
++              // write page register
++              if (WriteByte_CODEC (adap, 0x0, 0x0))
++                      return -ENODEV;
++              if (WriteByte_CODEC (adap, CODEC_M3_LPGA, CODEC_M3_PGA_R(volume)))
++                      return -ENODEV;
++              if (WriteByte_CODEC (adap, CODEC_M3_RPGA, CODEC_M3_PGA_R(volume)))
++                      return -ENODEV;
++      } else {
++              return -1;
++      }
++#endif        // CODEC
++
++      if  (down_interruptible (&audio_mixer_control[1].sem))
++              return -EINTR;
++
++      audio_mixer_control[1].vol_for_input[IP_EMIC] = uvalue->value.integer.value[0];
++
++      up (&audio_mixer_control[1].sem);
++
++      return 0;
++}
++static int bmi_emic_volume_info1 (struct snd_kcontrol *kcontrol,
++                             struct snd_ctl_elem_info *uinfo)
++{
++
++      uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
++      uinfo->count = 1;
++      uinfo->value.integer.min = 0;
++      uinfo->value.integer.max = 8;
++      uinfo->value.integer.step = 1;
++      return 0;
++}
++
++static int bmi_emic_volume_get1 (struct snd_kcontrol *kcontrol,
++                            struct snd_ctl_elem_value *uvalue)
++{
++      if  (down_interruptible (&audio_mixer_control[1].sem))
++              return -EINTR;
++
++      uvalue->value.integer.value[0] = audio_mixer_control[1].vol_for_input[IP_EMIC];
++
++      up (&audio_mixer_control[1].sem);
++
++      return 0;
++}
++
++struct snd_kcontrol_new bmi_control_emic_vol1 __devinitdata = {
++      .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++      .name = "Emic Capture Volume/Mute",
++      .index = 0x00,
++      .info = bmi_emic_volume_info1,
++      .get = bmi_emic_volume_get1,
++      .put = bmi_emic_volume_put1,
++      .private_value = 0xffab5,
++};
++
++//
++// HEADPHONE (HP[LR]OUT) Volume control
++//
++// PIM_AUDIO13
++static int bmi_hp_volume_put0 (struct snd_kcontrol *kcontrol,
++                            struct snd_ctl_elem_value *uvalue)
++{
++      struct i2c_adapter *adap = 0;
++      int volume;
++
++      // calculate register value
++      volume = uvalue->value.integer.value[0];
++
++      // get I2C dapter
++      if (bmi_audio[0].active) {
++              adap = bmi_device_get_i2c_adapter (bmi_audio[0].bdev);
++      } else if (bmi_audio[2].active) {
++              adap = bmi_device_get_i2c_adapter (bmi_audio[2].bdev);
++      }
++
++#ifdef CODEC
++      // set volume
++      if (adap) {
++              // write page register
++              if (WriteByte_CODEC (adap, 0x0, 0x0))
++                      return -ENODEV;
++              if (volume == 0) {
++                      if (WriteByte_CODEC (adap, CODEC_HPLOUT, 0x0))  // mute
++                              return -ENODEV;
++                      if (WriteByte_CODEC (adap, CODEC_HPROUT, 0x0))  // mute
++                              return -ENODEV;
++              } else {
++                      if (WriteByte_CODEC (adap, CODEC_HPLOUT, CODEC_HPX_LC(volume)
++                              | CODEC_HPX_EN | CODEC_HPX_PD | CODEC_HPX_PC))
++                              return -ENODEV;
++                      if (WriteByte_CODEC (adap, CODEC_HPROUT, CODEC_HPX_LC(volume)
++                              | CODEC_HPX_EN | CODEC_HPX_PD | CODEC_HPX_PC))
++                              return -ENODEV;
++              }
++      } else {
++              return -1;
++      }
++#endif        // CODEC
++
++      if (down_interruptible (&audio_mixer_control[0].sem))
++              return -EINTR;
++
++      audio_mixer_control[0].vol_for_output[OP_HEADPHONE] = uvalue->value.integer.value[0];
++
++      up (&audio_mixer_control[0].sem);
++
++      return 0;
++}
++static int bmi_hp_volume_info0 (struct snd_kcontrol *kcontrol,
++                             struct snd_ctl_elem_info *uinfo)
++{
++
++      uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
++      uinfo->count = 1;
++      uinfo->value.integer.min = 0;
++      uinfo->value.integer.max = 9;
++      uinfo->value.integer.step = 1;
++      return 0;
++}
++
++static int bmi_hp_volume_get0 (struct snd_kcontrol *kcontrol,
++                            struct snd_ctl_elem_value *uvalue)
++{
++      if  (down_interruptible (&audio_mixer_control[0].sem))
++              return -EINTR;
++
++      uvalue->value.integer.value[0] = audio_mixer_control[0].vol_for_output[OP_HEADPHONE];
++
++      up (&audio_mixer_control[0].sem);
++
++      return 0;
++}
++
++struct snd_kcontrol_new bmi_control_hp_vol0 __devinitdata = {
++      .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++      .name = "Headphone Playback Volume/Mute",
++      .index = 0x00,
++      .info = bmi_hp_volume_info0,
++      .get = bmi_hp_volume_get0,
++      .put = bmi_hp_volume_put0,
++      .private_value = 0xffab4,
++};
++
++      // PIM_AUDIO24
++static int bmi_hp_volume_put1 (struct snd_kcontrol *kcontrol,
++                            struct snd_ctl_elem_value *uvalue)
++{
++      struct i2c_adapter *adap = 0;
++      int volume;
++
++      // calculate register value
++      volume = uvalue->value.integer.value[0];
++
++      // get I2C dapter
++      if (bmi_audio[1].active) {
++              adap = bmi_device_get_i2c_adapter (bmi_audio[1].bdev);
++      } else if (bmi_audio[3].active) {
++              adap = bmi_device_get_i2c_adapter (bmi_audio[3].bdev);
++      }
++
++#ifdef CODEC
++      // set volume
++      if (adap) {
++              // write page register
++              if (WriteByte_CODEC (adap, 0x0, 0x0))
++                      return -ENODEV;
++              if (volume == 0) {
++                      if (WriteByte_CODEC (adap, CODEC_HPLOUT, 0x0))  // mute
++                              return -ENODEV;
++                      if (WriteByte_CODEC (adap, CODEC_HPROUT, 0x0))  // mute
++                              return -ENODEV;
++              } else {
++                      if (WriteByte_CODEC (adap, CODEC_HPLOUT, CODEC_HPX_LC(volume)
++                              | CODEC_HPX_EN | CODEC_HPX_PD | CODEC_HPX_PC))
++                              return -ENODEV;
++                      if (WriteByte_CODEC (adap, CODEC_HPROUT, CODEC_HPX_LC(volume)
++                              | CODEC_HPX_EN | CODEC_HPX_PD | CODEC_HPX_PC))
++                              return -ENODEV;
++              }
++      } else {
++              return -1;
++      }
++#endif        // CODEC
++
++      if  (down_interruptible (&audio_mixer_control[1].sem))
++              return -EINTR;
++
++      audio_mixer_control[1].vol_for_output[OP_HEADPHONE] = uvalue->value.integer.value[0];
++
++      up (&audio_mixer_control[1].sem);
++
++      return 0;
++}
++static int bmi_hp_volume_info1 (struct snd_kcontrol *kcontrol,
++                             struct snd_ctl_elem_info *uinfo)
++{
++
++      uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
++      uinfo->count = 1;
++      uinfo->value.integer.min = 0;
++      uinfo->value.integer.max = 9;
++      uinfo->value.integer.step = 1;
++      return 0;
++}
++
++static int bmi_hp_volume_get1 (struct snd_kcontrol *kcontrol,
++                            struct snd_ctl_elem_value *uvalue)
++{
++      if  (down_interruptible (&audio_mixer_control[1].sem))
++              return -EINTR;
++
++      uvalue->value.integer.value[0] = audio_mixer_control[1].vol_for_output[OP_HEADPHONE];
++
++      up (&audio_mixer_control[1].sem);
++
++      return 0;
++}
++
++struct snd_kcontrol_new bmi_control_hp_vol1 __devinitdata = {
++      .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++      .name = "Headphone Playback Volume/Mute",
++      .index = 0x00,
++      .info = bmi_hp_volume_info1,
++      .get = bmi_hp_volume_get1,
++      .put = bmi_hp_volume_put1,
++      .private_value = 0xffab4,
++};
++
++//
++// Speaker (HP[LR]COM) Volume control
++//
++// PIM_AUDIO13
++static int bmi_spkr_volume_put0 (struct snd_kcontrol *kcontrol,
++                            struct snd_ctl_elem_value *uvalue)
++{
++      struct i2c_adapter *adap = 0;
++      int volume;
++
++      // calculate register value
++      volume = uvalue->value.integer.value[0];
++
++      // get I2C dapter
++      if (bmi_audio[0].active) {
++              adap = bmi_device_get_i2c_adapter (bmi_audio[0].bdev);
++      } else if (bmi_audio[2].active) {
++              adap = bmi_device_get_i2c_adapter (bmi_audio[2].bdev);
++      }
++
++#ifdef CODEC
++      // set volume
++      if (adap) {
++              // write page register
++              if (WriteByte_CODEC (adap, 0x0, 0x0))
++                      return -ENODEV;
++              if (volume == 0) {
++                      if (WriteByte_CODEC (adap, CODEC_HPLCOM, 0x0))
++                              return -ENODEV;
++                      if (WriteByte_CODEC (adap, CODEC_HPRCOM, 0x0))
++                              return -ENODEV;
++              } else {
++                      if (WriteByte_CODEC (adap, CODEC_HPLCOM, CODEC_HPX_LC(volume)
++                              | CODEC_HPX_EN | CODEC_HPX_PD | CODEC_HPX_PC))
++                              return -ENODEV;
++                      if (WriteByte_CODEC (adap, CODEC_HPRCOM, CODEC_HPX_LC(volume)
++                              | CODEC_HPX_EN | CODEC_HPX_PD | CODEC_HPX_PC))
++                              return -ENODEV;
++              }
++      } else {
++              return -1;
++      }
++#endif        // CODEC
++
++      if (down_interruptible (&audio_mixer_control[0].sem))
++              return -EINTR;
++
++      audio_mixer_control[0].vol_for_output[OP_SPEAKER] = uvalue->value.integer.value[0];
++
++      up (&audio_mixer_control[0].sem);
++
++      return 0;
++}
++static int bmi_spkr_volume_info0 (struct snd_kcontrol *kcontrol,
++                             struct snd_ctl_elem_info *uinfo)
++{
++
++      uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
++      uinfo->count = 1;
++      uinfo->value.integer.min = 0;
++      uinfo->value.integer.max = 9;
++      uinfo->value.integer.step = 1;
++      return 0;
++}
++
++static int bmi_spkr_volume_get0 (struct snd_kcontrol *kcontrol,
++                            struct snd_ctl_elem_value *uvalue)
++{
++      if (down_interruptible (&audio_mixer_control[0].sem))
++              return -EINTR;
++
++      uvalue->value.integer.value[0] = audio_mixer_control[0].vol_for_output[OP_SPEAKER];
++
++      up (&audio_mixer_control[0].sem);
++
++      return 0;
++}
++
++struct snd_kcontrol_new bmi_control_spkr_vol0 __devinitdata = {
++      .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++      .name = "Speaker Playback Volume/Mute",
++      .index = 0x00,
++      .info = bmi_spkr_volume_info0,
++      .get = bmi_spkr_volume_get0,
++      .put = bmi_spkr_volume_put0,
++      .private_value = 0xffab5,
++};
++
++// PIM_AUDIO24
++static int bmi_spkr_volume_put1 (struct snd_kcontrol *kcontrol,
++                            struct snd_ctl_elem_value *uvalue)
++{
++      struct i2c_adapter *adap = 0;
++      int volume;
++
++      // calculate register value
++      volume = uvalue->value.integer.value[0];
++
++      // get I2C dapter
++      if (bmi_audio[1].active) {
++              adap = bmi_device_get_i2c_adapter (bmi_audio[1].bdev);
++      } else if (bmi_audio[3].active) {
++              adap = bmi_device_get_i2c_adapter (bmi_audio[3].bdev);
++      }
++
++#ifdef CODEC
++      // set volume
++      if (adap) {
++              // write page register
++              if (WriteByte_CODEC (adap, 0x0, 0x0))
++                      return -ENODEV;
++              if (volume == 0) {
++                      if (WriteByte_CODEC (adap, CODEC_HPLCOM, 0x0))
++                              return -ENODEV;
++                      if (WriteByte_CODEC (adap, CODEC_HPRCOM, 0x0))
++                              return -ENODEV;
++              } else {
++                      if (WriteByte_CODEC (adap, CODEC_HPLCOM, CODEC_HPX_LC(volume)
++                                      | CODEC_HPX_EN | CODEC_HPX_PD | CODEC_HPX_PC))
++                              return -ENODEV;
++                      if (WriteByte_CODEC (adap, CODEC_HPRCOM, CODEC_HPX_LC(volume)
++                                      | CODEC_HPX_EN | CODEC_HPX_PD | CODEC_HPX_PC))
++                              return -ENODEV;
++              }
++      } else {
++              return -1;
++      }
++#endif        // CODEC
++
++      if (down_interruptible (&audio_mixer_control[1].sem))
++              return -EINTR;
++
++      audio_mixer_control[1].vol_for_output[OP_SPEAKER] = uvalue->value.integer.value[0];
++
++      up (&audio_mixer_control[1].sem);
++
++      return 0;
++}
++static int bmi_spkr_volume_info1 (struct snd_kcontrol *kcontrol,
++                             struct snd_ctl_elem_info *uinfo)
++{
++
++      uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
++      uinfo->count = 1;
++      uinfo->value.integer.min = 0;
++      uinfo->value.integer.max = 9;
++      uinfo->value.integer.step = 1;
++      return 0;
++}
++
++static int bmi_spkr_volume_get1 (struct snd_kcontrol *kcontrol,
++                            struct snd_ctl_elem_value *uvalue)
++{
++      if  (down_interruptible (&audio_mixer_control[1].sem))
++              return -EINTR;
++
++      uvalue->value.integer.value[0] = audio_mixer_control[1].vol_for_output[OP_SPEAKER];
++
++      up (&audio_mixer_control[1].sem);
++
++      return 0;
++}
++
++struct snd_kcontrol_new bmi_control_spkr_vol1 __devinitdata = {
++      .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++      .name = "Speaker Playback Volume/Mute",
++      .index = 0x00,
++      .info = bmi_spkr_volume_info1,
++      .get = bmi_spkr_volume_get1,
++      .put = bmi_spkr_volume_put1,
++      .private_value = 0xffab5,
++};
++
++//
++// Line out ([LR]LOP) Volume control
++//
++// PIM_AUDIO13
++static int bmi_lo_volume_put0 (struct snd_kcontrol *kcontrol,
++                            struct snd_ctl_elem_value *uvalue)
++{
++      struct i2c_adapter *adap = 0;
++      int volume;
++
++      // calculate register value
++      volume = uvalue->value.integer.value[0];
++
++      // get I2C dapter
++      if (bmi_audio[0].active) {
++              adap = bmi_device_get_i2c_adapter (bmi_audio[0].bdev);
++      } else if (bmi_audio[2].active) {
++              adap = bmi_device_get_i2c_adapter (bmi_audio[2].bdev);
++      }
++
++#ifdef CODEC
++      // set volume
++      if (adap) {
++              // write page register
++              if (WriteByte_CODEC (adap, 0x0, 0x0))
++                      return -ENODEV;
++              if (volume == 0) {
++                      if (WriteByte_CODEC (adap, CODEC_LLOPM, 0x0))
++                              return -ENODEV;
++                      if (WriteByte_CODEC (adap, CODEC_RLOPM, 0x0))
++                              return -ENODEV;
++              } else {
++                      if (WriteByte_CODEC (adap, CODEC_LLOPM, CODEC_HPX_LC(volume)
++                                      | CODEC_HPX_EN | CODEC_HPX_PD | CODEC_HPX_PC))
++                              return -ENODEV;
++                      if (WriteByte_CODEC (adap, CODEC_RLOPM, CODEC_HPX_LC(volume)
++                                      | CODEC_HPX_EN | CODEC_HPX_PD | CODEC_HPX_PC))
++                              return -ENODEV;
++              }
++      } else {
++              return -1;
++      }
++#endif        // CODEC
++
++      if (down_interruptible (&audio_mixer_control[0].sem))
++              return -EINTR;
++
++      audio_mixer_control[0].vol_for_output[OP_LINEOUT] = uvalue->value.integer.value[0];
++
++      up (&audio_mixer_control[0].sem);
++
++      return 0;
++}
++static int bmi_lo_volume_info0 (struct snd_kcontrol *kcontrol,
++                             struct snd_ctl_elem_info *uinfo)
++{
++
++      uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
++      uinfo->count = 1;
++      uinfo->value.integer.min = 0;
++      uinfo->value.integer.max = 9;
++      uinfo->value.integer.step = 1;
++      return 0;
++}
++
++static int bmi_lo_volume_get0 (struct snd_kcontrol *kcontrol,
++                            struct snd_ctl_elem_value *uvalue)
++{
++      if (down_interruptible (&audio_mixer_control[0].sem))
++              return -EINTR;
++
++      uvalue->value.integer.value[0] = audio_mixer_control[0].vol_for_output[OP_LINEOUT];
++
++      up (&audio_mixer_control[0].sem);
++
++      return 0;
++}
++
++struct snd_kcontrol_new bmi_control_lo_vol0 __devinitdata = {
++      .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++      .name = "Lineout Playback Volume/Mute",
++      .index = 0x00,
++      .info = bmi_lo_volume_info0,
++      .get = bmi_lo_volume_get0,
++      .put = bmi_lo_volume_put0,
++      .private_value = 0xffab6,
++};
++
++// PIM_AUDIO24
++static int bmi_lo_volume_put1 (struct snd_kcontrol *kcontrol,
++                            struct snd_ctl_elem_value *uvalue)
++{
++      struct i2c_adapter *adap = 0;
++      int volume;
++
++      // calculate register value
++      volume = uvalue->value.integer.value[0];
++
++      // get I2C dapter
++      if (bmi_audio[1].active) {
++              adap = bmi_device_get_i2c_adapter (bmi_audio[1].bdev);
++      } else if (bmi_audio[3].active) {
++              adap = bmi_device_get_i2c_adapter (bmi_audio[3].bdev);
++      }
++
++#ifdef CODEC
++      // set volume
++      if (adap) {
++              // write page register
++              if (WriteByte_CODEC (adap, 0x0, 0x0))
++                      return -ENODEV;
++              if (volume == 0) {
++                      if (WriteByte_CODEC (adap, CODEC_LLOPM, 0x0))
++                              return -ENODEV;
++                      if (WriteByte_CODEC (adap, CODEC_RLOPM, 0x0))
++                              return -ENODEV;
++              } else {
++                      if (WriteByte_CODEC (adap, CODEC_LLOPM, CODEC_HPX_LC(volume)
++                                      | CODEC_HPX_EN | CODEC_HPX_PD | CODEC_HPX_PC))
++                              return -ENODEV;
++                      if (WriteByte_CODEC (adap, CODEC_RLOPM, CODEC_HPX_LC(volume)
++                                      | CODEC_HPX_EN | CODEC_HPX_PD | CODEC_HPX_PC))
++                              return -ENODEV;
++              }
++      } else {
++              return -1;
++      }
++#endif        // CODEC
++
++      if (down_interruptible (&audio_mixer_control[1].sem))
++              return -EINTR;
++
++      audio_mixer_control[1].vol_for_output[OP_LINEOUT] = uvalue->value.integer.value[0];
++
++      up (&audio_mixer_control[1].sem);
++
++      return 0;
++}
++static int bmi_lo_volume_info1 (struct snd_kcontrol *kcontrol,
++                             struct snd_ctl_elem_info *uinfo)
++{
++
++      uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
++      uinfo->count = 1;
++      uinfo->value.integer.min = 0;
++      uinfo->value.integer.max = 9;
++      uinfo->value.integer.step = 1;
++      return 0;
++}
++
++static int bmi_lo_volume_get1 (struct snd_kcontrol *kcontrol,
++                            struct snd_ctl_elem_value *uvalue)
++{
++      if (down_interruptible (&audio_mixer_control[1].sem))
++              return -EINTR;
++
++      uvalue->value.integer.value[0] = audio_mixer_control[1].vol_for_output[OP_LINEOUT];
++
++      up (&audio_mixer_control[1].sem);
++
++      return 0;
++}
++
++struct snd_kcontrol_new bmi_control_lo_vol1 __devinitdata = {
++      .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++      .name = "Lineout Playback Volume/Mute",
++      .index = 0x00,
++      .info = bmi_lo_volume_info1,
++      .get = bmi_lo_volume_get1,
++      .put = bmi_lo_volume_put1,
++      .private_value = 0xffab6,
++};
++
++/*
++  * This function registers the control components of ALSA Mixer
++  * It is called by ALSA PCM init.
++  *
++  * @param    card    pointer to the ALSA sound card structure.
++  * @param    device  SSI interface
++  *
++  * @return              0 on success, -ve otherwise.
++  */
++int bug_alsa_create_ctl (struct snd_card *card, void *p_value, int device)
++{
++      int rc = 0;
++
++      if (device == 0) {
++              if ((rc =
++                      snd_ctl_add (card, snd_ctl_new1 (&bmi_control_pb_vol0, p_value))) < 0)
++                      return rc;
++      } else {
++              if ((rc =
++                      snd_ctl_add (card, snd_ctl_new1 (&bmi_control_pb_vol1, p_value))) < 0)
++                      return rc;
++      }
++
++      if (device == 0) {
++              if ((rc =
++                      snd_ctl_add (card, snd_ctl_new1 (&bmi_control_li_vol0, p_value))) < 0)
++                      return rc;
++      } else {
++              if ((rc =
++                      snd_ctl_add (card, snd_ctl_new1 (&bmi_control_li_vol1, p_value))) < 0)
++                      return rc;
++      }
++
++      if (device == 0) {
++              if ((rc =
++                      snd_ctl_add (card, snd_ctl_new1 (&bmi_control_mic_vol0, p_value))) < 0)
++                      return rc;
++      } else {
++              if ((rc =
++                      snd_ctl_add (card, snd_ctl_new1 (&bmi_control_mic_vol1, p_value))) < 0)
++                      return rc;
++      }
++
++      if (device == 0) {
++              if ((rc =
++                      snd_ctl_add (card, snd_ctl_new1 (&bmi_control_emic_vol0, p_value))) < 0)
++                      return rc;
++      } else {
++              if ((rc =
++                      snd_ctl_add (card, snd_ctl_new1 (&bmi_control_emic_vol1, p_value))) < 0)
++                      return rc;
++      }
++
++      if (device == 0) {
++              if ((rc =
++                      snd_ctl_add (card, snd_ctl_new1 (&bmi_control_hp_vol0, p_value))) < 0)
++                      return rc;
++      } else {
++              if ((rc =
++                      snd_ctl_add (card, snd_ctl_new1 (&bmi_control_hp_vol1, p_value))) < 0)
++                      return rc;
++      }
++
++      if (device == 0) {
++              if ((rc =
++                      snd_ctl_add (card, snd_ctl_new1 (&bmi_control_spkr_vol0, p_value))) < 0)
++                      return rc;
++      } else {
++              if ((rc =
++                      snd_ctl_add (card, snd_ctl_new1 (&bmi_control_spkr_vol1, p_value))) < 0)
++                      return rc;
++      }
++
++      if (device == 0) {
++              if ((rc =
++                      snd_ctl_add (card, snd_ctl_new1 (&bmi_control_lo_vol0, p_value))) < 0)
++                      return rc;
++      } else {
++              if ((rc =
++                      snd_ctl_add (card, snd_ctl_new1 (&bmi_control_lo_vol1, p_value))) < 0)
++                      return rc;
++      }
++
++      return 0;
++}
++
++/**************************************************************************
++ * Module initialization and termination functions.
++ *
++ * Note that if this code is compiled into the kernel, then the
++ * module_init() function will be called within the device_initcall()
++ * group.
++ **************************************************************************
++ */
++
++/*
++ * @name Audio Driver Loading/Unloading Functions
++ * These non-exported internal functions are used to support the audio
++ * device driver initialization and de-initialization operations.
++ */
++
++/*
++ * @brief This is the audio device driver initialization function.
++ *
++ * This function is called by the kernel when this device driver is first
++ * loaded.
++ */
++
++char const input_name0[MAX_STRG] = "bmi_audio_status_m1";
++char const input_name1[MAX_STRG] = "bmi_audio_status_m2";
++char const input_name2[MAX_STRG] = "bmi_audio_status_m3";
++char const input_name3[MAX_STRG] = "bmi_audio_status_m4";
++
++static int __init bmi_audio_init (void)
++{
++      int             rc = 0;
++      dev_t           dev_id;
++      int             idn;
++      int             iidn;
++      struct snd_card *card;
++      struct snd_card *card1;
++
++      printk (KERN_INFO "BMI Audio driver loading...\n");
++
++      // alloc char driver with 4 minor numbers
++      rc = alloc_chrdev_region (&dev_id, 0, 4, "BMI AUDIO Driver");
++      if (rc) {
++              printk (KERN_ERR "bmi_audio_init: Can't allocate chrdev region\n");
++              return -ENODEV;
++      }
++      major = MAJOR(dev_id);
++
++      // Allocate and Register input devices - bmi_audio_status_m[1234]
++      for (idn = BMI_AUDIO_M1; idn < BMI_AUDIO_PIM_NUM; idn++) {
++              bmi_audio[idn].input_dev = input_allocate_device();
++              if (!bmi_audio[idn].input_dev) {
++                      for (iidn = BMI_AUDIO_M1; iidn < idn; iidn++)
++                              input_unregister_device (bmi_audio[iidn].input_dev);
++                      unregister_chrdev_region (dev_id, 4);
++                      printk (KERN_ERR "bmi_audio_init: Can't allocate input_dev[%d]\n", idn);
++                      return -ENOMEM;
++              }
++
++              // set up input device
++              switch (idn) {
++                  case BMI_AUDIO_M1:
++                      bmi_audio[idn].input_dev->name = input_name0;
++                      bmi_audio[idn].input_dev->phys = input_name0;
++                      break;
++                  case BMI_AUDIO_M2:
++                      bmi_audio[idn].input_dev->name = input_name1;
++                      bmi_audio[idn].input_dev->phys = input_name1;
++                      break;
++                  case BMI_AUDIO_M3:
++                      bmi_audio[idn].input_dev->name = input_name2;
++                      bmi_audio[idn].input_dev->phys = input_name2;
++                      break;
++                  case BMI_AUDIO_M4:
++                      bmi_audio[idn].input_dev->name = input_name3;
++                      bmi_audio[idn].input_dev->phys = input_name3;
++                      break;
++              }
++              bmi_audio[idn].input_dev->id.bustype = BUS_BMI;
++              //bmi_audio[idn].input_dev->private = &bmi_audio[idn];
++              bmi_audio[idn].input_dev->evbit[BIT_WORD(EV_ABS)] |= BIT_MASK(EV_ABS);
++              bmi_audio[idn].input_dev->absbit[BIT_WORD(ABS_MISC)] |= BIT_MASK(ABS_MISC);
++
++              // register input device
++              if (input_register_device (bmi_audio[idn].input_dev)) {
++                      printk (KERN_ERR "bmi_audio_init() - input_register_device failed.\n");
++                      for (iidn = BMI_AUDIO_M1; iidn < idn; iidn++)
++                              input_unregister_device (bmi_audio[iidn].input_dev);
++                      unregister_chrdev_region (dev_id, 4);
++                      return -ENODEV;
++              }
++      }
++
++              // clear bmi devices and active bits
++      bmi_audio[0].bdev = NULL;
++      bmi_audio[1].bdev = NULL;
++      bmi_audio[2].bdev = NULL;
++      bmi_audio[3].bdev = NULL;
++      bmi_audio[0].active = 0;
++      bmi_audio[1].active = 0;
++      bmi_audio[2].active = 0;
++      bmi_audio[3].active = 0;
++
++      // allocate private structure
++      mxc_audio[0] = kcalloc (1, sizeof (mxc_bmi_audio_t), GFP_KERNEL);
++      if (mxc_audio[0] == NULL) {
++              for (idn = BMI_AUDIO_M1; idn < BMI_AUDIO_PIM_NUM; idn++)
++                      input_unregister_device (bmi_audio[idn].input_dev);
++              unregister_chrdev_region (dev_id, 4);
++              return -ENODEV;
++      }
++
++      // allocate private structure
++      mxc_audio[1] = kcalloc (1, sizeof (mxc_bmi_audio_t), GFP_KERNEL);
++      if (mxc_audio[1] == NULL) {
++              kfree (mxc_audio[0]);
++              for (idn = BMI_AUDIO_M1; idn < BMI_AUDIO_PIM_NUM; idn++)
++                      input_unregister_device (bmi_audio[idn].input_dev);
++              unregister_chrdev_region (dev_id, 4);
++              return -ENODEV;
++      }
++
++      // register the soundcards
++      // modules 1 and 3
++      card = snd_card_new (1, id13, THIS_MODULE, sizeof (mxc_bmi_audio_t));
++      if (card == NULL) {
++              kfree (mxc_audio[1]);
++              kfree (mxc_audio[0]);
++              for (idn = BMI_AUDIO_M1; idn < BMI_AUDIO_PIM_NUM; idn++)
++                      input_unregister_device (bmi_audio[idn].input_dev);
++              unregister_chrdev_region (dev_id, 4);
++              return -ENODEV;
++      }
++
++      card->private_data = (void *) mxc_audio[0];
++      card->private_free = snd_mxc_audio_free;
++
++      // register pcm
++      mxc_audio[0]->card = card;
++      if ((rc = snd_card_mxc_audio_pcm (mxc_audio[0], 0)) < 0) {
++              snd_card_free (card);
++              kfree (mxc_audio[1]);
++              kfree (mxc_audio[0]);
++              for (idn = BMI_AUDIO_M1; idn < BMI_AUDIO_PIM_NUM; idn++)
++                      input_unregister_device (bmi_audio[idn].input_dev);
++              unregister_chrdev_region (dev_id, 4);
++              return -ENODEV;
++      }
++
++      // register mixer
++      if (0 == bug_alsa_create_ctl (card, (void *) &audio_mixer_control[0], 0))
++              printk (KERN_INFO "Control ALSA component registered\n");
++
++      spin_lock_init (&(mxc_audio[0]->s[0].dma_lock));
++      spin_lock_init (&(mxc_audio[0]->s[1].dma_lock));
++
++      strcpy (card->driver, "PIM_AUDIO13");
++      strcpy (card->shortname, "PIM13-audio");
++      sprintf (card->longname, "PIM13 Freescale MX31");
++
++      // register sound card
++      if ((rc = snd_card_register (card)) == 0) {
++              PRINTK(KERN_INFO "MXC PIM13 audio support initialized\n");
++      } else {
++              snd_card_free (card);
++              kfree (mxc_audio[1]);
++              kfree (mxc_audio[0]);
++              for (idn = BMI_AUDIO_M1; idn < BMI_AUDIO_PIM_NUM; idn++)
++                      input_unregister_device (bmi_audio[idn].input_dev);
++              unregister_chrdev_region (dev_id, 4);
++              return -ENODEV;
++      }
++
++      // modules 2 and 4
++      card1 = snd_card_new (2, id24, THIS_MODULE, sizeof (mxc_bmi_audio_t));
++      if (card1 == NULL) {
++              snd_card_free (card);
++              kfree (mxc_audio[1]);
++              kfree (mxc_audio[0]);
++              for (idn = BMI_AUDIO_M1; idn < BMI_AUDIO_PIM_NUM; idn++)
++                      input_unregister_device (bmi_audio[idn].input_dev);
++              unregister_chrdev_region (dev_id, 4);
++              return -ENODEV;
++      }
++
++      card1->private_data = (void *) mxc_audio[1];
++      card1->private_free = snd_mxc_audio_free;
++
++      // register pcm
++      mxc_audio[1]->card = card1;
++      if ((rc = snd_card_mxc_audio_pcm (mxc_audio[1], 1)) < 0) {
++              snd_card_free (card1);
++              snd_card_free (card);
++              kfree (mxc_audio[1]);
++              kfree (mxc_audio[0]);
++              for (idn = BMI_AUDIO_M1; idn < BMI_AUDIO_PIM_NUM; idn++)
++                      input_unregister_device (bmi_audio[idn].input_dev);
++              unregister_chrdev_region (dev_id, 4);
++              return -ENODEV;
++      }
++
++      // register mixer
++      if (0 == bug_alsa_create_ctl (card1, (void *) &audio_mixer_control[1], 1))
++              printk (KERN_INFO "Control ALSA component registered\n");
++
++      spin_lock_init (&(mxc_audio[1]->s[0].dma_lock));
++      spin_lock_init (&(mxc_audio[1]->s[1].dma_lock));
++
++      strcpy (card1->driver, "PIM_AUDIO24");
++      strcpy (card1->shortname, "PIM24-audio");
++      sprintf (card1->longname, "PIM24 Freescale MX31");
++
++      // register sound card
++      if ((rc = snd_card_register (card1)) == 0) {
++              PRINTK(KERN_INFO "MXC PIM24 audio support initialized\n");
++      } else {
++              snd_card_free (card1);
++              snd_card_free (card);
++              kfree (mxc_audio[1]);
++              kfree (mxc_audio[0]);
++              for (idn = BMI_AUDIO_M1; idn < BMI_AUDIO_PIM_NUM; idn++)
++                      input_unregister_device (bmi_audio[idn].input_dev);
++              unregister_chrdev_region (dev_id, 4);
++      }
++
++      // register with BMI
++      rc = bmi_register_driver (&bmi_audio_driver);
++      if (rc) {
++              printk (KERN_ERR "bmi_audio.c: Can't register bmi_audio_driver\n");
++              snd_card_free (card1);
++              snd_card_free (card);
++              kfree (mxc_audio[1]);
++              kfree (mxc_audio[0]);
++              for (idn = BMI_AUDIO_M1; idn < BMI_AUDIO_PIM_NUM; idn++)
++                      input_unregister_device (bmi_audio[idn].input_dev);
++              unregister_chrdev_region (dev_id, 4);
++              return rc;
++      }
++
++      // turn on I2S transceiver
++      bmi_activate_audio_ports();
++
++      //configure DAM and SSI
++      configure_dam_bmi_master (0);
++      configure_dam_bmi_master (1);
++      configure_ssi_rx (0);
++      configure_ssi_rx (1);
++      configure_ssi_tx (0);
++      configure_ssi_tx (1);
++
++      printk (KERN_INFO "bmi_audio.c: BMI_AUDIO Driver v%s \n", BMIAUDIO_VERSION);
++      if(fcc_test)
++              printk (KERN_INFO "bmi_audio.c: FCC Test mode enabled\n");
++      if(output_ints)
++              printk (KERN_INFO "bmi_audio.c: Output Jack Interrupts enabled\n");
++      return 0;
++}
++
++/*
++ * @brief This is the audio device driver de-initialization function.
++ *
++ * This function is called by the kernel when this device driver is about
++ * to be unloaded.
++ */
++static void __exit bmi_audio_exit (void)
++{
++      dev_t dev_id;
++      int idn;
++
++      printk (KERN_INFO "BMI Audio driver unloading...\n");
++
++      // delete scheduled work
++      flush_scheduled_work ();
++
++      // remove bmi functionality
++      bmi_unregister_driver (&bmi_audio_driver);
++
++      // free sound cards
++      snd_card_free (mxc_audio[0]->card);
++      snd_card_free (mxc_audio[1]->card);
++
++      // free data structures
++      kfree (mxc_audio[0]);
++      kfree (mxc_audio[1]);
++
++      // remove input devices
++      for (idn = BMI_AUDIO_M1; idn < BMI_AUDIO_PIM_NUM; idn++)
++              input_unregister_device (bmi_audio[idn].input_dev);
++
++      // remove control cdev
++      dev_id = MKDEV(major, 0);
++      unregister_chrdev_region (dev_id, 4);
++
++      // turn off I2S transceiver
++      bmi_inactivate_audio_ports();
++
++      printk (KERN_INFO "BMI Audio driver unloaded.\n");
++      return;
++}
++
++/*
++ * Module entry points and description information.
++ */
++
++module_init (bmi_audio_init);
++module_exit (bmi_audio_exit);
++
++module_param(fcc_test, ushort, S_IRUGO);
++MODULE_PARM_DESC(fcc_test, "FCC Test code enable");
++
++module_param(output_ints, ushort, S_IRUGO);
++MODULE_PARM_DESC(fcc_test, "Output Jack Interrupts enable");
++
++MODULE_DESCRIPTION("BMI driver for ALSA");
++MODULE_AUTHOR("EnCADIS Design, Inc. <p.giacomini@encadis.com>");
++MODULE_LICENSE("GPL");
++MODULE_SUPPORTED_DEVICE("PIM_AUDIO13");
++MODULE_SUPPORTED_DEVICE("PIM_AUDIO24");
++MODULE_SUPPORTED_DEVICE("bmi_audio_ctrl_m[1234]");
++MODULE_SUPPORTED_DEVICE("bmi_audio_status_m[1234]");
++
+--- /dev/null
++++ git/drivers/bmi/pims/vonhippel/Makefile
+@@ -0,0 +1,6 @@
++#
++# BMI PIMS
++#
++
++obj-$(CONFIG_BMI_VH)          += bmi_vh.o
++
+--- /dev/null
++++ git/drivers/bmi/pims/vonhippel/bmi_vh.c
+@@ -0,0 +1,942 @@
++/*
++ *    bmi_vh.c
++ *
++ *    BMI von Hippel device driver basic functionality
++ *
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*
++ *    Include files
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/fs.h>
++#include <linux/cdev.h>
++#include <linux/interrupt.h>
++#include <linux/i2c.h>
++#include <linux/spi/spi.h>
++#include <linux/delay.h>
++#include <linux/jiffies.h>
++#include <linux/timer.h>
++
++#include <asm/uaccess.h>
++#include <asm/io.h>
++#include <mach/hardware.h>
++
++#include <linux/i2c.h>
++
++#include <linux/bmi.h>
++#include <linux/bmi/bmi-slot.h>
++#include <linux/bmi/bmi_vh.h>
++
++#define BMIVH_VERSION "1.0"
++#define RDAC_3_3V     (0xAC)  // 16.5K = 3.3V
++
++/*
++ *    Global variables
++ */
++
++static struct i2c_board_info iox_info = {
++  I2C_BOARD_INFO("VH_IOX", BMI_IOX_I2C_ADDRESS),
++};
++
++static struct i2c_board_info rdac_info = {
++  I2C_BOARD_INFO("VH_RDAC", VH_RDAC_I2C_ADDRESS),
++};
++
++static struct i2c_board_info adc_info = {
++  I2C_BOARD_INFO("VH_ADC", VH_ADC_I2C_ADDRESS),
++};
++
++static struct i2c_board_info dac_info = {
++  I2C_BOARD_INFO("VH_DAC", VH_DAC_I2C_ADDRESS),
++};
++
++
++static ushort factory_test = 0;
++static ushort fcc_test = 0;
++static struct timer_list fcc_timer;
++static int fcc_state = 0x3;
++
++// private device structure
++struct bmi_vh
++{
++  struct bmi_device   *bdev;                  // BMI device
++  struct cdev         cdev;                   // control device
++  struct device       *class_dev;             // control class device
++  int                 open_flag;              // single open flag
++  char                        int_name[20];           // interrupt name
++  struct i2c_client *iox;
++  struct i2c_client *rdac;
++  struct i2c_client *dac;
++  struct i2c_client *adc;
++  struct spi_device *spi;     // SPI device
++  struct spi_board_info vh_spi_info;
++  char                        rbuf[BUF_MAX_SIZE];     // SPI read buffer
++  char                        wbuf[BUF_MAX_SIZE];     // SPI write buffer
++};
++
++static struct bmi_vh bmi_vh[4];       // per slot device structure
++static int major;             // control device major
++
++/*
++ *    BMI set up
++ */
++
++// BMI device ID table
++static struct bmi_device_id bmi_vh_tbl[] =
++{
++      {
++              .match_flags = BMI_DEVICE_ID_MATCH_VENDOR | BMI_DEVICE_ID_MATCH_PRODUCT,
++              .vendor   = BMI_VENDOR_BUG_LABS,
++              .product  = BMI_PRODUCT_VON_HIPPEL,
++              .revision = BMI_ANY,
++      },
++      { 0, },   /* terminate list */
++};
++MODULE_DEVICE_TABLE(bmi, bmi_vh_tbl);
++
++int   bmi_vh_probe (struct bmi_device *bdev);
++void  bmi_vh_remove (struct bmi_device *bdev);
++
++// BMI driver structure
++static struct bmi_driver bmi_vh_driver =
++{
++      .name = "bmi_vh",
++      .id_table = bmi_vh_tbl,
++      .probe   = bmi_vh_probe,
++      .remove  = bmi_vh_remove,
++};
++
++/*
++ *    I2C set up
++ */
++
++// IOX
++// read byte from I2C IO expander
++static int ReadByte_IOX (struct i2c_client *client, unsigned char offset, unsigned char *data)
++{
++      int     ret = 0;
++
++      ret = i2c_master_send(client, &offset, 1);
++      if (ret == 1)
++        ret = i2c_master_recv(client, data, 1);
++      if (ret < 0)
++        printk (KERN_ERR "ReadByte_IOX() - i2c_transfer() failed...%d\n",ret);
++      return ret;
++}
++
++// write byte to I2C IO expander
++static int WriteByte_IOX (struct i2c_client *client, unsigned char offset, unsigned char data)
++{
++      int     ret = 0;
++      unsigned char msg[2];
++
++      msg[0] = offset;
++      msg[1] = data;
++      ret = i2c_master_send(client, msg, sizeof(msg));
++
++      if (ret < 0)
++        printk (KERN_ERR "WriteByte_IOX() - i2c_transfer() failed...%d\n",ret);
++
++      return ret;
++}
++
++// RDAC
++// read byte from I2C LDO RDAC
++static int ReadByte_RDAC (struct i2c_client *client, unsigned char command, unsigned char *data)
++{
++      int     ret = 0;
++
++      ret = i2c_master_send(client, &command, 1);
++
++      if (ret < 0)
++        {
++          printk (KERN_ERR "ReadByte_RDAC() - i2c_master_send() failed...%d\n",ret);
++          return ret;
++        }
++      ret = i2c_master_recv(client, data, 1);
++      if (ret < 0)
++        printk (KERN_ERR "ReadByte_RDAC() - i2c_master_recv() failed...%d\n",ret);
++      return ret;
++}
++
++// write byte to I2C LDO RDAC
++static int WriteByte_RDAC (struct i2c_client *client, unsigned char command,
++                              unsigned char data, int send_data)
++{
++      int     ret = 0;
++
++      unsigned char msg[2];
++
++      msg[0] = command;
++      msg[1] = data;
++
++      if (send_data)
++        ret = i2c_master_send(client, msg, 2);
++      else
++        ret = i2c_master_send(client, &msg[0], 1);
++      if (ret < 0)
++        printk (KERN_ERR "WriteByte_RDAC() - i2c_transfer() failed...%d\n",ret);
++
++      return ret;
++}
++
++// ADC
++// read data from I2C ADC
++static int ReadByte_ADC (struct i2c_client *client, unsigned char *data)
++{
++      int     ret = 0;
++
++      ret = i2c_master_recv(client, data, 3);
++
++      if (ret < 0)
++        printk (KERN_ERR "ReadByte_ADC() - i2c_transfer() failed...%d\n",ret);
++      return ret;
++}
++
++// write command to I2C ADC
++static int WriteByte_ADC (struct i2c_client *client, unsigned char w1, unsigned char w2)
++{
++      int     ret = 0;
++      unsigned char msg[2];
++
++      msg[0] = w1;
++      msg[1] = w2;
++      ret = i2c_master_send(client, msg, sizeof(msg));
++
++      if (ret < 0)
++        printk (KERN_ERR "WriteByte_ADC() - i2c_transfer() failed...%d\n",ret);
++      return ret;
++}
++
++// DAC
++// read data from I2C DAC
++static int ReadByte_DAC (struct i2c_client *client, unsigned char command, unsigned char *data)
++{
++      int     ret = 0;
++
++      ret = i2c_master_send(client, &command, 1);
++      if (ret == 1)
++        ret = i2c_master_recv(client, data, 2);
++
++      if (ret < 0)
++        printk (KERN_ERR "ReadByte_DAC() - i2c_transfer() failed...%d\n",ret);
++      return ret;
++}
++
++// write command to I2C DAC
++static int WriteByte_DAC (struct i2c_client *client, unsigned char w1, unsigned char w2, int send_w2)
++{
++      int     ret = 0;
++      unsigned char msg[2];
++
++      msg[0] = w1;
++      msg[1] = w2;
++      if (send_w2)
++        ret = i2c_master_send(client, msg, sizeof(msg));
++      else
++        ret = i2c_master_send(client, &msg[0], 1);
++
++      if (ret < 0)
++        printk (KERN_ERR "WriteByte_DAC() - i2c_transfer() failed...%d\n",ret);
++      return ret;
++}
++
++
++/*
++ *    control device operations
++ */
++
++// open
++int cntl_open(struct inode *inode, struct file *file)
++{
++      struct bmi_vh *vh;
++
++      vh = container_of (inode->i_cdev, struct bmi_vh, cdev);
++
++      // Enforce single-open behavior
++
++      if (vh->open_flag) {
++              return -EBUSY;
++      }
++      vh->open_flag = 1;
++
++      // Save vh_dev pointer for later.
++
++      file->private_data = vh;
++      return 0;
++
++}
++
++// release
++int cntl_release(struct inode *inode, struct file *file)
++{
++      struct bmi_vh *vh;
++
++      vh = (struct bmi_vh *)(file->private_data);
++      vh->open_flag = 0;
++      return 0;
++}
++
++// ioctl
++int cntl_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
++                 unsigned long arg)
++{
++      struct i2c_adapter *adap;
++      unsigned char iox_data;
++      unsigned char rdac_data;
++      //      unsigned char buf[4];
++      int ret = 0;
++
++      struct bmi_vh *vh;
++      int slot;
++
++      vh = (struct bmi_vh *)(file->private_data);
++
++      // error if vh not present
++      if(vh->bdev == 0)
++              return -ENODEV;
++
++      slot = vh->bdev->slot->slotnum;
++      adap = vh->bdev->slot->adap;
++
++      // ioctl's
++      switch (cmd) {
++
++      case BMI_VH_RLEDOFF:
++              bmi_slot_gpio_set (slot, ~VH_GPIO_RED_LED); // Red LED=OFF
++              break;
++
++      case BMI_VH_RLEDON:
++              bmi_slot_gpio_set (slot, VH_GPIO_RED_LED); // Red LED=ON
++              break;
++
++      case BMI_VH_GLEDOFF:
++              bmi_slot_gpio_set (slot, ~VH_GPIO_GREEN_LED); // Green LED=OFF
++              break;
++
++      case BMI_VH_GLEDON:
++              bmi_slot_gpio_set (slot, VH_GPIO_GREEN_LED); // Green LED=ON
++              break;
++
++      case BMI_VH_GETSTAT:
++              {
++                      int read_data;
++
++                      if (ReadByte_IOX (vh->iox, IOX_INPUT_REG, &iox_data))
++                              return -ENODEV;
++
++                      read_data = iox_data | (bmi_slot_gpio_get(slot) << 8);
++
++                      if (put_user (read_data, (int __user *) arg))
++                              return -EFAULT;
++              }
++              break;
++
++      case BMI_VH_MKGPIO_OUT:
++              if ((arg < VH_GPIO_0) || (arg > VH_GPIO_RED_LED))
++                      return -EINVAL;
++              //bmi_set_module_gpio_dir (slot, arg, BMI_GPIO_OUT);
++              break;
++
++      case BMI_VH_MKGPIO_IN:
++              if ((arg < VH_GPIO_0) || (arg > VH_GPIO_RED_LED))
++                      return -EINVAL;
++              //bmi_set_module_gpio_dir (slot, arg, BMI_GPIO_IN);
++              break;
++
++      case BMI_VH_SETGPIO:
++              if ((arg < VH_GPIO_0) || (arg > VH_GPIO_RED_LED))
++                      return -EINVAL;
++              //bmi_set_module_gpio_data (slot, arg, 0x1);
++              break;
++
++      case BMI_VH_CLRGPIO:
++              if ((arg < VH_GPIO_0) || (arg > VH_GPIO_RED_LED))
++                      return -EINVAL;
++              //bmi_set_module_gpio_data (slot, arg, 0x0);
++              break;
++
++      case BMI_VH_MKIOX_OUT:
++              if ((arg < VH_IOX_B0) || (arg > VH_IOX_B5))
++                      return -EINVAL;
++              {
++                      unsigned char read_data;
++
++                      if (ReadByte_IOX (vh->iox, IOX_CONTROL, &iox_data))
++                              return -ENODEV;
++
++                      read_data = iox_data & ~(0x1 << arg);
++
++                      if (WriteByte_IOX (vh->iox, IOX_CONTROL, read_data))
++                              return -ENODEV;
++              }
++              break;
++
++      case BMI_VH_MKIOX_IN:
++              if ((arg < VH_IOX_B0) || (arg > VH_IOX_B5))
++                      return -EINVAL;
++              {
++                      unsigned char read_data;
++
++                      if (ReadByte_IOX (vh->iox, IOX_CONTROL, &iox_data))
++                              return -ENODEV;
++
++                      read_data = iox_data & (0x1 << arg);
++
++                      if (WriteByte_IOX (vh->iox, IOX_CONTROL, read_data))
++                              return -ENODEV;
++              }
++              break;
++
++      case BMI_VH_SETIOX:
++              if ((arg < VH_IOX_B0) || (arg > VH_IOX_USB_VEN))
++                      return -EINVAL;
++              {
++                      unsigned char read_data;
++
++                      if (ReadByte_IOX (vh->iox, IOX_OUTPUT_REG, &iox_data))
++                              return -ENODEV;
++
++                      read_data = iox_data | (0x1 << arg);
++
++                      if (WriteByte_IOX (vh->iox, IOX_OUTPUT_REG, read_data))
++                              return -ENODEV;
++              }
++              break;
++
++      case BMI_VH_CLRIOX:
++              if ((arg < VH_IOX_B0) || (arg > VH_IOX_USB_VEN))
++                      return -EINVAL;
++              {
++                      unsigned char read_data;
++
++                      if (ReadByte_IOX (vh->iox, IOX_OUTPUT_REG, &iox_data))
++                              return -ENODEV;
++
++                      read_data = iox_data & ~(0x1 << arg);
++
++                      if (WriteByte_IOX (vh->iox, IOX_OUTPUT_REG, read_data))
++                              return -ENODEV;
++              }
++              break;
++
++      case BMI_VH_SETRDAC:
++              rdac_data = (unsigned char) (arg & 0xFF);
++
++              if (WriteByte_RDAC (vh->rdac, VH_RD_CMD_RDAC, rdac_data, 1))
++                      return -ENODEV;
++
++              if (WriteByte_RDAC (vh->rdac, VH_RD_CMD_EE, rdac_data, 1))
++                      return -ENODEV;
++
++              break;
++
++      case BMI_VH_RDRDAC:
++
++              if (ReadByte_RDAC (vh->rdac, VH_RD_CMD_RDAC, &rdac_data))
++                      return -ENODEV;
++
++              if(copy_to_user((unsigned int *) arg, &rdac_data, sizeof(int)))
++                      ret = -EFAULT;
++              else
++                      ret = 0;
++
++              break;
++
++      case BMI_VH_ADCWR:
++              {
++                      struct vh_adc_wr *adc_wr = NULL;
++
++                      if ((adc_wr = kmalloc(sizeof(struct vh_adc_wr), GFP_KERNEL)) == NULL)
++                              return -ENOMEM;
++                      if (copy_from_user(adc_wr, (struct vh_adc_wr *)arg, sizeof(struct vh_adc_wr))) {
++                              kfree (adc_wr);
++                              return -EFAULT;
++                      }
++                      if (WriteByte_ADC (vh->adc, adc_wr->w1, adc_wr->w2)) {
++                              kfree (adc_wr);
++                              return -ENODEV;
++                      }
++                      kfree (adc_wr);
++              }
++              break;
++
++      case BMI_VH_ADCRD:
++              {
++                      unsigned char adc_data[3];
++                      unsigned int ret_data;
++
++                      if (ReadByte_ADC(vh->adc, adc_data))    // read ADC conversion
++                              return -ENODEV;
++
++                      ret_data = (unsigned int) ((adc_data[0] << 16) | (adc_data[1] << 8) | adc_data[2]);
++                      if(copy_to_user((unsigned int *) arg, &ret_data, sizeof(int)))
++                              ret = -EFAULT;
++                      else
++                              ret = 0;
++              }
++
++              break;
++
++      case BMI_VH_DACWR:
++              {
++                      struct vh_dac_wr *dac_wr = NULL;
++
++                      if ((dac_wr = kmalloc(sizeof(struct vh_dac_wr), GFP_KERNEL)) == NULL)
++                              return -ENOMEM;
++                      if (copy_from_user(dac_wr, (struct vh_dac_wr *)arg, sizeof(struct vh_dac_wr))) {
++                              kfree (dac_wr);
++                              return -EFAULT;
++                      }
++                      if (dac_wr->w1 == VH_DAC_W1_UALL) {
++                              if (WriteByte_DAC (vh->dac, dac_wr->w1, dac_wr->w2, 0)) {
++                                      kfree (dac_wr);
++                                      return -ENODEV;
++                              }
++                      } else {
++                              if (WriteByte_DAC (vh->dac, dac_wr->w1, dac_wr->w2, 1)) {
++                                      kfree (dac_wr);
++                                      return -ENODEV;
++                              }
++                      }
++                      kfree (dac_wr);
++              }
++              break;
++
++      case BMI_VH_DACRD:
++              {
++                      unsigned char dac_data[2];
++                      unsigned int command;
++                      unsigned int ret_data;
++
++                      if (copy_from_user(&command, (unsigned int *)arg, sizeof(int))) {
++                              return -EFAULT;
++                      }
++
++                      if (!((command == VH_DAC_W1_RDA) || (command == VH_DAC_W1_RDB))) {
++                              return -EINVAL;
++                      }
++
++                      if (ReadByte_DAC(vh->dac, (unsigned char) command, dac_data)) { // read DAC value
++                              return -ENODEV;
++                      }
++
++                      ret_data = (unsigned int) ((dac_data[0] << 8) | dac_data[1]);
++                      if(copy_to_user((unsigned int *) arg, &ret_data, sizeof(int))) {
++                              ret = -EFAULT;
++                      } else {
++                              ret = 0;
++                      }
++              }
++
++              break;
++
++      default:
++              return -ENOTTY;
++      }
++
++      return 0;
++}
++
++// control file operations
++struct file_operations cntl_fops = {
++      .owner = THIS_MODULE,
++      .ioctl = cntl_ioctl,
++      .open = cntl_open,
++      .release = cntl_release,
++};
++
++/*
++ *    PIM functions
++ */
++
++// FCC test timer
++void ftimer(unsigned long arg)
++{
++      struct bmi_vh *bmi_vh = (struct bmi_vh *) arg;
++      int slot = bmi_vh->bdev->slot->slotnum;
++
++      /*      bmi_set_module_gpio_data (slot, VH_GPIO_RED_LED, (fcc_state & 0x2) >> 1);
++              bmi_set_module_gpio_data (slot, VH_GPIO_GREEN_LED, fcc_state & 0x1);*/
++      fcc_state = (fcc_state + 1) % 4;
++      del_timer (&fcc_timer);
++      fcc_timer.expires = jiffies + (2 * HZ);
++      add_timer (&fcc_timer);
++}
++
++// interrupt handler
++static irqreturn_t module_irq_handler(int irq, void *dummy)
++{
++  /*if (!factory_test) {
++              printk (KERN_ERR "Von Hippel USB power error - slot ");
++              switch (irq) {
++                      case M1_IRQ:
++                              printk (KERN_ERR "1 - powering off\n");
++                              bmi_slot_power_off (0);
++                              break;
++                      case M2_IRQ:
++                              printk (KERN_ERR "2 - powering off\n");
++                              bmi_slot_power_off (1);
++                              break;
++                      case M3_IRQ:
++                              printk (KERN_ERR "3 - powering off\n");
++                              bmi_slot_power_off (2);
++                              break;
++                      case M4_IRQ:
++                              printk (KERN_ERR "3 - powering off\n");
++                              bmi_slot_power_off (3);
++                              break;
++              }
++      }
++      disable_irq(irq);*/
++      return IRQ_HANDLED;
++}
++
++/*
++ *    BMI functions
++ */
++
++// probe - insert PIM
++int bmi_vh_probe(struct bmi_device *bdev)
++{
++      int err;
++      int slot;
++      struct bmi_vh *vh;
++              struct i2c_adapter *adap;
++      struct cdev *cdev;
++      struct class *bmi_class;
++      dev_t dev_id;
++      int irq;
++      unsigned char rdac_data[1];
++      unsigned char adc_data[3];
++      unsigned char dac_data[2];
++      unsigned long speed = 1000000;
++      unsigned char mode = SPI_MODE_2; // von Hippel chip select must be low active
++      unsigned char bits_per_word = 32;
++      unsigned char iox_data;
++      unsigned char buf[4];
++      struct spi_xfer spi_xfer;
++      int gpio_int;
++
++      err = 0;
++      slot = bdev->slot->slotnum;
++              adap = bdev->slot->adap;
++      vh = &bmi_vh[slot];
++
++      vh->bdev = 0;
++      vh->open_flag = 0;
++
++      // Create 1 minor device
++      cdev = &vh->cdev;
++      cdev_init (cdev, &cntl_fops);
++
++      dev_id = MKDEV(major, slot);
++      err = cdev_add (cdev, dev_id, 1);
++      if (err) {
++              return err;
++      }
++
++      // Create class device
++      bmi_class = bmi_get_class ();
++      vh->class_dev = device_create (bmi_class, NULL, MKDEV (major, slot), NULL, "bmi_vh_control_m%i", slot+1);
++
++      if (IS_ERR(vh->class_dev)) {
++              printk (KERN_ERR "Unable to create "
++                     "class_device for bmi_vh_m%i; errno = %ld\n",
++                     slot+1, PTR_ERR(vh->class_dev));
++              vh->class_dev = NULL;
++              cdev_del (&vh->cdev);
++              return -ENODEV;
++      }
++
++      // bind driver and bmi_device
++      vh->bdev = bdev;
++
++
++      printk (KERN_INFO "bmi_vh.c: probe slot %d\n", slot);
++      vh->iox = i2c_new_device(bdev->slot->adap, &iox_info);
++      if (vh->iox == NULL)
++        printk(KERN_ERR "IOX NULL...\n");
++      vh->rdac = i2c_new_device(bdev->slot->adap, &rdac_info);
++      if (vh->rdac == NULL)
++        printk(KERN_ERR "RDAC NULL...\n");
++      vh->adc = i2c_new_device(bdev->slot->adap, &adc_info);
++      if (vh->adc == NULL)
++        printk(KERN_ERR "ADC NULL...\n");
++      vh->dac = i2c_new_device(bdev->slot->adap, &dac_info);
++      if (vh->dac == NULL)
++        printk(KERN_ERR "DAC NULL...\n");
++
++      // SPI
++      strcpy(vh->vh_spi_info.modalias, "spidev");
++      vh->vh_spi_info.max_speed_hz = speed;
++      vh->vh_spi_info.bus_num = bdev->slot->spi_bus_num;
++      vh->vh_spi_info.chip_select = bdev->slot->spi_cs;
++      vh->vh_spi_info.mode = mode;
++
++      vh->spi = spi_new_device(spi_busnum_to_master(vh->vh_spi_info.bus_num), &vh->vh_spi_info) ;
++      if (!vh->spi)
++        printk(KERN_WARNING "VH: spi_new_device failed\n");
++
++      bmi_device_set_drvdata (bdev, vh);
++      // configure IOX
++      if (factory_test) {
++              if (WriteByte_IOX(vh->iox, IOX_OUTPUT_REG, 0x55) < 0) {  // all outputs high
++                goto err1;
++              }
++
++              if (WriteByte_IOX(vh->iox, IOX_CONTROL, 0xAA) < 0) {     // IOX[7,5,3,1]=IN, IOX[6,4,2,0]=OUT
++                goto err1;
++              }
++      } else {
++              if (WriteByte_IOX(vh->iox, IOX_OUTPUT_REG, 0x7F) < 0) {  // USB power on, other outputs high
++                goto err1;
++              }
++
++              if (WriteByte_IOX(vh->iox, IOX_CONTROL, 0x80) < 0) {     // IOX[7]=IN, IOX[6:0]=OUT
++                goto err1;
++              }
++      }
++
++      mdelay(100);
++
++      // read RDAC
++      if (ReadByte_RDAC(vh->rdac, VH_RD_CMD_RDAC, rdac_data) < 0) {  // read LDO RDAC register
++        goto err1;
++      }
++
++      printk (KERN_INFO "bmi_vh.c: probe RDAC = 0x%x\n", *rdac_data);
++
++      if (factory_test) {
++
++              mdelay(100);    // RDAC recovery time
++
++              // set LDO voltage to 3.3V
++              *rdac_data = (unsigned char) RDAC_3_3V;
++
++              if (WriteByte_RDAC (vh->rdac, VH_RD_CMD_RDAC, *rdac_data, 1) < 0) {
++                goto err1;
++              }
++
++              mdelay(100);
++
++              if (WriteByte_RDAC (vh->rdac, VH_RD_CMD_EE, *rdac_data, 1) < 0) {
++                goto err1;
++              }
++
++              mdelay(100);
++
++              // read EEPROM
++              if (ReadByte_RDAC(vh->rdac, VH_RD_CMD_EE, rdac_data) < 0) {  // read LDO EEPROM
++                goto err1;
++              }
++
++              printk (KERN_INFO "bmi_vh.c: probe EEPROM = 0x%x\n", *rdac_data);
++
++              mdelay(100);
++      }
++
++      // read ADC
++      if (ReadByte_ADC(vh->adc, adc_data) < 0) {  // read initial ADC conversion
++        goto err1;
++      }
++
++      printk (KERN_INFO "bmi_vh.c: probe ADC = 0x%x%x%x\n", adc_data[0], adc_data[1], adc_data[2]);
++
++      if (factory_test) {
++
++              // power up DAC
++              if (WriteByte_DAC(vh->dac, VH_DAC_W1_EC, VH_DAC_BCH | VH_DAC_PU, 1) < 0) {
++                goto err1;
++              }
++
++              // Write DAC data
++              if (WriteByte_DAC(vh->dac, VH_DAC_W1_ALL | 0x0, 0xF0, 1) < 0) {  // write A, B, inputs and update
++                goto err1;
++              }
++      }
++
++      // read DAC
++      if (ReadByte_DAC(vh->dac, VH_DAC_W1_RDA, dac_data) < 0) {  // read initial DAC A value
++        goto err1;
++      }
++
++      printk (KERN_INFO "bmi_vh.c: probe DAC = 0x%x%x\n", dac_data[0], dac_data[1]);
++
++
++
++      // Initialize GPIOs (turn LED's on)
++      if (factory_test) {
++              bmi_slot_gpio_configure  (slot, VH_GPIO_RED_LED);                       // (test I2S)
++              bmi_slot_gpio_configure  (slot, VH_GPIO_GREEN_LED);                     // (test I2S)
++              bmi_slot_gpio_configure  (slot, VH_GPIO_1);                             // (test I2S)
++              bmi_slot_gpio_configure (slot, VH_GPIO_0 | VH_GPIO_1);                  // (test interrupt)
++      } else {
++              bmi_slot_gpio_configure (slot, RED_LED |GREEN_LED );    // Red LED=ON
++              bmi_slot_gpio_set (slot, ~(RED_LED | GREEN_LED));
++              mdelay(200);
++
++              // turn LED's off
++              bmi_slot_gpio_set (slot, (RED_LED | GREEN_LED));                // Red, Green LED=OFF
++
++              if (WriteByte_IOX(vh->iox, IOX_OUTPUT_REG, 0x70) < 0) {  // USB power on, IOX[3:0] low, other outputs high
++                      printk (KERN_ERR "bmi_vh.c: probe() - write IOX failed\n");
++                      //bmi_device_spi_cleanup(bdev);
++                      goto err1;
++              }
++      }
++
++      // request PIM interrupt
++      irq = bdev->slot->status_irq;
++      sprintf (vh->int_name, "bmi_vh%d", slot);
++      if (request_irq(irq, &module_irq_handler, 0, vh->int_name, vh)) {
++              printk (KERN_ERR "bmi_vh.c: Can't allocate irq %d or find von Hippel in slot %d\n",
++                      irq, slot);
++              //bmi_device_spi_cleanup(bdev);
++              goto err1;
++
++              //return -EBUSY;
++      }
++
++      if (fcc_test) {
++              init_timer (&fcc_timer);
++              fcc_timer.data = (unsigned long) &bmi_vh[slot];
++              fcc_timer.expires = jiffies + (2 * HZ);
++              fcc_timer.function = ftimer;
++              add_timer (&fcc_timer);
++      }
++
++
++      return 0;
++
++ err1:
++      vh->class_dev = NULL;
++      cdev_del (&vh->cdev);
++      device_destroy (bmi_class, MKDEV(major, slot));
++      bmi_device_set_drvdata (bdev, 0);
++      vh->bdev = 0;
++      i2c_unregister_device(vh->iox);
++      i2c_unregister_device(vh->rdac);
++      i2c_unregister_device(vh->adc);
++      i2c_unregister_device(vh->dac);
++      spi_unregister_device(vh->spi);
++      return -ENODEV;
++}
++
++// remove PIM
++void bmi_vh_remove(struct bmi_device *bdev)
++{
++      int slot;
++      struct bmi_vh *vh;
++      struct class *bmi_class;
++      int irq;
++
++      printk(KERN_INFO "bmi_vh: Module Removed...\n");
++      slot = bdev->slot->slotnum;
++      vh = &bmi_vh[slot];
++
++      i2c_unregister_device(vh->iox);
++      i2c_unregister_device(vh->rdac);
++      i2c_unregister_device(vh->adc);
++      i2c_unregister_device(vh->dac);
++      spi_unregister_device(vh->spi);
++
++      if (factory_test) {
++              // disable uart transceiver
++              bmi_slot_uart_disable (slot);
++      }
++
++      if (fcc_test)
++              del_timer (&fcc_timer);
++
++      irq = bdev->slot->status_irq;
++      free_irq (irq, vh);
++
++      bmi_slot_gpio_configure(slot, 0);
++      //bmi_device_spi_cleanup(bdev);
++
++      bmi_class = bmi_get_class ();
++      device_destroy (bmi_class, MKDEV(major, slot));
++
++      vh->class_dev = 0;
++
++      cdev_del (&vh->cdev);
++
++      // de-attach driver-specific struct from bmi_device structure
++      bmi_device_set_drvdata (bdev, 0);
++      vh->bdev = 0;
++
++      return;
++}
++
++/*
++ *    module routines
++ */
++
++static void __exit bmi_vh_cleanup(void)
++{
++      dev_t dev_id;
++
++      bmi_unregister_driver (&bmi_vh_driver);
++
++      dev_id = MKDEV(major, 0);
++      unregister_chrdev_region (dev_id, 4);
++      return;
++}
++
++static int __init bmi_vh_init(void)
++{
++      dev_t   dev_id;
++      int     retval;
++
++      // alloc char driver with 4 minor numbers
++      retval = alloc_chrdev_region (&dev_id, 0, 4, "BMI VH Driver");
++      if (retval) {
++              return -ENODEV;
++      }
++
++      major = MAJOR(dev_id);
++      retval = bmi_register_driver (&bmi_vh_driver);
++      if (retval) {
++              unregister_chrdev_region(dev_id, 4);
++              return -ENODEV;
++      }
++
++      if(factory_test)
++              printk (KERN_INFO "bmi_vh.c: Factory Test mode enabled\n");
++
++      if(fcc_test)
++              printk (KERN_INFO "bmi_vh.c: FCC Test mode enabled\n");
++
++      printk (KERN_INFO "bmi_vh.c: BMI_VH Driver v%s \n", BMIVH_VERSION);
++
++      return 0;
++}
++
++
++module_init(bmi_vh_init);
++module_exit(bmi_vh_cleanup);
++
++module_param(factory_test, ushort, S_IRUGO);
++MODULE_PARM_DESC(factory_test, "Factory Test code enable");
++
++module_param(fcc_test, ushort, S_IRUGO);
++MODULE_PARM_DESC(fcc_test, "FCC Test code enable");
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Buglabs Inc.");
++MODULE_DESCRIPTION("BMI von Hippel device driver");
++MODULE_SUPPORTED_DEVICE("bmi_vh_control_mX");
++
+--- /dev/null
++++ git/drivers/bmi/pims/zb/Makefile
+@@ -0,0 +1,5 @@
++#
++# BMI PIMS ZigBee
++#
++bmi_zb-objs := bmi_zigbee.o bmi_zaccel.o bmi_zprotocol.o bmi_znetdev.o
++obj-$(CONFIG_BMI_ZB)              += bmi_zb.o
+--- /dev/null
++++ git/drivers/bmi/pims/zb/bmi_zaccel.c
+@@ -0,0 +1,684 @@
++/*
++ *
++ *      bmi_zaccel.c
++ *
++ *      API to Zaccel device
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++#include <linux/delay.h>
++#include <linux/bmi/bmi_zb.h>
++#include "bmi_zigbee.h"
++#include "bmi_zaccel.h"
++
++int reset_count = 0;
++
++int zb_ReadConfiguration(struct bmi_zb *zb, unsigned char configId, unsigned char *buf)
++{
++      unsigned char data[128];
++      unsigned char i, len;
++
++      data[0] = 1;
++      data[1] = ZB_READ_CONFIG_REQ_0;
++      data[2] = ZB_READ_CONFIG_REQ_1;
++      data[3] = configId;
++
++      // Write to the device
++      if(zaccel_spi_req(zb, data, 128) < 0)
++      {
++              return -1;
++      }
++
++      /*
++       * Return value has format shown below.
++       *      data[0] = Zaccetl return status
++       *      data[1] = configID
++       *      data[2] = len
++       *      data[3-130] = value
++       */
++      len = data[0];
++
++      /*
++       * truncate output to 128 bytes if it is longer than 128 byte.
++       * Zaccel data sheet indicates 0-128 bytes value.
++       * Add 3 byte header to the total length
++       */
++      if(len > 128)
++              len = 128;
++
++      for(i = 0; i < (len + 3); i++)
++      {
++              buf[i] = data[i];
++      }
++
++      return(len);
++}
++
++unsigned char zb_WriteConfiguration(struct bmi_zb *zb, unsigned char configId, unsigned char len, unsigned char *value)
++{
++      unsigned char data[128];
++      int rc;
++
++      if(len > 128)
++      {
++              /* Len exceeds the max size */
++              rc = -1;
++      }
++      data[0] = 2 + len;
++      data[1] = ZB_WRITE_CONFIG_REQ_0;
++      data[2] = ZB_WRITE_CONFIG_REQ_1;
++      data[3] = configId;
++      data[4] = len;
++
++      memcpy((unsigned char *)(&data[5]),value,len);
++
++      /* Write to the device. */
++      zaccel_spi_req(zb, data, 128);
++
++      /* read return status */
++      rc = data[3];
++
++      return rc;
++}
++
++void zb_SoftReset(struct bmi_zb *zb)
++{
++      unsigned char data[8];
++
++      data[0] = 1;
++      data[1] = SYS_RESET_REQ_0;
++      data[2] = SYS_RESET_REQ_1;
++      data[3] = 0;
++
++      /* Write to the device. */
++      zaccel_spi_req(zb, data, 8);
++}
++
++void zb_sysVersion(struct bmi_zb *zb)
++{
++      unsigned char data[16];
++
++      /* SYS_VERSION command returns 5 bytes of data */
++
++      data[0] = 0;
++      data[1] = SYS_VER_0;
++      data[2] = SYS_VER_1;
++
++      /* Write to the device. */
++      zaccel_spi_req(zb, data, 16);
++}
++
++int zb_sysRFpowerAmp(struct bmi_zb *zb, unsigned char pa, unsigned char power)
++{
++      unsigned char data[32];
++      int rc = 0;
++
++      if(power > SYS_RF_PA_MIN)
++      {
++              return -EINVAL;
++      }
++
++      data[0] = 2;
++      data[1] = SYS_RF_POWER_AMP_0;
++      data[2] = SYS_RF_POWER_AMP_1;
++      data[3] = pa;
++      data[4] = power;
++
++      /* Write to the device */
++      zaccel_spi_req(zb, data, 32);
++
++      /* compare the return values */
++      if((data[3] != pa) || (data[4] != power))
++      {
++              rc = -1;
++      }
++
++      return rc;
++}
++
++unsigned char zb_device_info_len[] = {1, 8, 2, 2, 8, 1, 2, 8};
++
++int zb_GetDeviceInfo(struct bmi_zb *zb, unsigned char param,unsigned char *buf)
++{
++      unsigned char len;
++      unsigned char data[32];
++      unsigned char i;
++
++      if(param > ZB_DEVICE_LAST)
++      {
++              printk(KERN_WARNING "zb: invalid device info %d\n",param);
++              return -EINVAL;
++      }
++
++      data[0] = 1;
++      data[1] = ZB_GET_DEVICE_INFO_0;
++      data[2] = ZB_GET_DEVICE_INFO_1;
++      data[3] = param;
++
++      /* Write to the device. */
++      zaccel_spi_req(zb, data, 32);
++
++      /* data points to the value byte */
++      len = zb_device_info_len[param];
++      for(i = 0; i < len; i++)
++      {
++              buf[i] = data[i+4];
++      }
++
++      return(len);
++}
++
++void zb_FindDeviceRequest(struct bmi_zb *zb, unsigned char *searchKey)
++{
++      unsigned char data[16];
++
++      data[0] = 8;
++      data[1] = ZB_FIND_DEVICE_REQ_0;
++      data[2] = ZB_FIND_DEVICE_REQ_1;
++
++      memcpy(&data[3],searchKey,8);
++
++      /* Write to the device. */
++      zaccel_spi_req(zb, data, 16);
++}
++
++void zb_StartDevice(struct bmi_zb *zb, unsigned char option)
++{
++      zb_WriteConfiguration(zb,ZCD_NV_STARTUP_OPTION,1,&option);
++      zb_Reset(zb,ZB_RESET);
++      udelay(10);
++      zb_Reset(zb,ZB_RELEASE);
++}
++
++int zb_StartRequest(struct bmi_zb *zb)
++{
++      unsigned char data[8];
++
++      data[0] = 0;
++      data[1] = ZB_START_REQ_0;
++      data[2] = ZB_START_REQ_1;
++
++      zb->z_info.msg_flag &= ~START_CNF_BIT;
++
++      /* Write to the device */
++      zaccel_spi_req(zb, data, 8);
++
++      return 0;
++}
++
++unsigned char zb_PermitJoiningRequest(struct bmi_zb *zb, unsigned char *dest, unsigned char timeout)
++{
++      unsigned char data[8];
++      unsigned char rc;
++
++      data[0] = 3;
++      data[1] = ZB_PERMIT_JOINING_REQ_0;
++      data[2] = ZB_PERMIT_JOINING_REQ_1;
++      data[3] = dest[0];           /* LSB of short address */
++      data[4] = dest[1];           /* MSB of short address */
++      data[5] = timeout;
++
++      /* Write to the device */
++      zaccel_spi_req(zb, data, 8);
++
++      rc = data[3];
++
++      if(rc != Z_SUCCESS)
++      {
++              printk(KERN_WARNING "zb_PermitJoiningReques invalid 0x%x\n",rc);
++      }
++
++      return rc;
++}
++
++void zb_AllowBind(struct bmi_zb *zb, unsigned char timeout)
++{
++      unsigned char data[8];
++
++      data[0] = 1;
++      data[1] = ZB_ALLOW_BIND_0;
++      data[2] = ZB_ALLOW_BIND_1;
++      data[3] = timeout;
++
++      /* Write to the device */
++      zaccel_spi_req(zb, data, 8);
++}
++
++unsigned char zb_AppRegisterRequest(struct bmi_zb *zb, unsigned char len, unsigned char *app_info)
++{
++      unsigned char *data;
++      unsigned char rc;
++
++      data = kmalloc((len + ZCMD_HEADER), GFP_KERNEL);
++
++      data[0] = len;
++      data[1] = ZB_APP_REGISTER_REQ_0;
++      data[2] = ZB_APP_REGISTER_REQ_1;
++
++      memcpy(&data[3],app_info,len);
++
++      zaccel_spi_req(zb,data, (len + ZCMD_HEADER));
++
++      /* Read return status */
++      rc = data[3];
++      if(rc == Z_SUCCESS)
++      {
++              zb->z_info.app_type = SAPI_TYPE;
++      }
++
++      kfree(data);
++
++      return rc;
++
++}
++
++unsigned char zb_AFRegisterRequest(struct bmi_zb *zb, unsigned char len, unsigned char *app_info)
++{
++      unsigned char *data;
++      unsigned char rc;
++
++      data = kmalloc((len + ZCMD_HEADER), GFP_KERNEL);
++
++      data[0] = len;
++      data[1] = AF_REGISTER_0;
++      data[2] = AF_REGISTER_1;
++
++      memcpy(&data[3],app_info,len);
++
++      zaccel_spi_req(zb,data, (len + ZCMD_HEADER));
++
++      /* Read return status */
++      rc = data[3];
++      if(rc == Z_SUCCESS)
++      {
++              zb->z_info.app_type = AF_INTERFACE_TYPE;
++      }
++
++      kfree(data);
++
++      return rc;
++}
++
++void zb_BindRequest(struct bmi_zb *zb, unsigned char create, unsigned char *bind_info)
++{
++      unsigned char data[16];
++
++      data[0] = 0x0B;
++      data[1] = ZB_BIND_DEVICE_0;
++      data[2] = ZB_BIND_DEVICE_1;
++      data[3] = create;
++
++      memcpy(&data[4], bind_info, 10);
++
++      zaccel_spi_req(zb,data, 16);
++}
++
++int zb_SendDataRequest(struct bmi_zb *zb, unsigned char *buf, unsigned char len)
++{
++      unsigned char *data;
++
++      /*
++       * The user sends data to the remote ZigBee.
++       * Check if we use the SAPI or the AF send message.
++       * We expect that the user format the content of the
++       * message correctly.
++       */
++      data = kmalloc((len + ZCMD_HEADER),GFP_KERNEL);
++      data[0] = len;
++
++      if(zb->z_info.app_type == AF_INTERFACE_TYPE)
++      {
++              data[1] = AF_DATA_REQ_0;
++              data[2] = AF_DATA_REQ_1;
++      }
++      else
++      {
++              /* anything else will use SAPI */
++              data[1] = ZB_SEND_DATA_REQ_0;
++              data[2] = ZB_SEND_DATA_REQ_1;
++      }
++
++      memcpy((unsigned char *)(&data[3]), buf, len );
++
++      zaccel_spi_req(zb,data,(len + ZCMD_HEADER));
++      return 0;
++}
++
++int zb_SysTestLoopback(struct bmi_zb *zb)
++{
++      unsigned char *data;
++      unsigned char i, len;
++      unsigned char buf_len;
++      unsigned char pattern[32];
++      int rc;
++
++      len = 4;
++      buf_len = len + ZCMD_HEADER;
++      data = kmalloc(buf_len,GFP_KERNEL);
++
++      data[0] = len;
++      data[1] = SYS_TEST_LOOPBACK_REQ_0;
++      data[2] = SYS_TEST_LOOPBACK_REQ_1;
++
++      /* Prepare test pattern */
++      pattern[0] = 0xAA;
++      pattern[1] = 0x55;
++      pattern[2] = 0x07;
++      pattern[3] = 0x5A;
++      pattern[4] = 0x63;
++      pattern[5] = 0x58;
++      pattern[6] = 0x74;
++      pattern[7] = 0x55;
++      pattern[8] = 0x02;
++      pattern[9] = 0x04;
++      pattern[10] = 0x08;
++      pattern[11] = 0x10;
++      pattern[12] = 0x20;
++      pattern[13] = 0xAA;
++      pattern[14] = 0x55;
++
++      memcpy(&data[3],pattern,len);
++
++#define TEST_LOOPBACKx
++#ifdef TEST_LOOPBACK
++      printk("Loopback pattern: ");
++      for(i = 0; i < buf_len; i++)
++      {
++              printk("%x ",data[i]);
++      }
++      printk(KERN_DEBUG "\n");
++#endif
++
++      zaccel_spi_req(zb,data,buf_len);
++
++      /* Verify loopback results */
++      if((data[1] == (SYS_TEST_LOOPBACK_REQ_0 | RSPS_CMD)) &&
++         (data[2] == SYS_TEST_LOOPBACK_REQ_1))
++      {
++              if(data[0] == len)
++              {
++                      rc = 0;
++                      for(i = 0; i < len; i++)
++                      {
++                              if(data[ZCMD_HEADER + i] != pattern[i])
++                              {
++                                      rc++;
++                                      printk(KERN_WARNING "error: zb test byte %d expects %x, gets %x\n",i,pattern[i],data[ZCMD_HEADER + i]);
++                              }
++                      }
++              }
++              else
++              {
++                      rc = -2;
++              }
++      }
++      else
++      {
++              rc = -1;
++      }
++
++      return rc;
++}
++
++void zDeviceReport(struct bmi_zb *zb,unsigned char type, unsigned char len,unsigned char *buf)
++{
++      unsigned char *msg;
++
++      msg = kmalloc((ZCMD_HEADER + len),GFP_KERNEL);
++
++      msg[0] = len;
++      msg[1] = ZB_DEVICE_INFO_CHG_0;
++      msg[2] = ZB_DEVICE_INFO_CHG_0;
++      memcpy(&msg[3],buf,len);
++
++      len = ZCMD_HEADER + len;
++
++#ifdef VE_OUT
++      /* Send message to the application layer through control socket */
++      zb_rx(zb->netdev,msg,len,Z_CONTROL_SOCK);
++#endif
++
++      kfree(msg);
++}
++
++/*
++ * This routine send data originated by the user layer to
++ * the Z-Accel.
++ */
++void zaccel_xmt(struct work_struct *work)
++{
++      struct bmi_zb *zb;
++      struct zaccel_info *z_info;
++      struct zaccel_xmt_msg *msg;
++
++      zb = container_of(work, struct bmi_zb, xmt_work);
++      z_info = &zb->z_info;
++
++      while(!list_empty(&z_info->xmt_list))
++      {
++              msg = list_entry(z_info->xmt_list.next, struct zaccel_xmt_msg, list);
++
++              zb_SendDataRequest(zb, msg->buf, msg->len);
++
++              list_del(z_info->xmt_list.next);
++              kfree(msg);
++      }
++}
++
++/*
++ * zaccel_cmd_proc processes messages from the Zaccel.
++ */
++
++void zaccel_cmd_proc(struct bmi_zb *zb, unsigned char *buf)
++{
++      struct zaccel_info *z_info;
++      struct net_zb *priv;
++      unsigned char len;
++      unsigned short cmd;
++      int rc;
++
++      z_info = &zb->z_info;
++
++      len = buf[0] + ZCMD_HEADER;
++
++      /* process the message from Z-Accel */
++
++      cmd = ((((unsigned short)buf[1] << 8) & 0xFF00) |
++              ((unsigned short)buf[2] & 0x00FF));
++
++      switch(cmd)
++      {
++              case SYS_RESET_IND:
++
++                      if(buf[3] == 2)
++                      {
++                              /* count number of reset by watch-dog */
++                              reset_count++;
++                      }
++
++                      printk(KERN_INFO "zb%d SYS_RESET_IND %d \n",zb->slot,reset_count);
++                                      /* rcv Z-Accel reset indication. */
++                      z_info->msg_flag |= RESET_IND_BIT;
++                      wake_up_interruptible(&z_info->wait_queue);
++
++                      zb_rx(zb->netdev,buf,len,Z_CONTROL_SOCK);
++                      break;
++
++              case ZB_START_CONFIRM:
++                      /*
++                       *      Z-Stack starts.  Device is ready to run applicaton.
++                       */
++                      z_info->msg_flag |= START_CNF_BIT;
++                      wake_up_interruptible(&z_info->wait_queue);
++                      break;
++
++              case ZB_RCV_DATA_IND:
++              case AF_INCOMING_MSG:
++                      /*
++                       * Receive a packet from a remote device
++                       * Send it to the user throught packet socket.
++                       */
++                      len = buf[0];
++
++                      if(zb->netdev)
++                      {
++                              rc = zb_rx(zb->netdev,&buf[3],len,Z_PACKET_SOCK);
++                              priv = netdev_priv(zb->netdev);
++                              if(rc >= 0)
++                              {
++                                      priv->stats.rx_packets++;
++                                      priv->stats.rx_bytes += len;
++                              }
++                              else
++                              {
++                                      priv->stats.rx_dropped++;
++                              }
++                      }
++                      break;
++
++              case ZB_BIND_CONFIRM:
++                      printk(KERN_DEBUG "Rec BIND CNF - cmd %x %x rc %x len %d\n",
++                               buf[3],buf[4],buf[5],len);
++                      zb_rx(zb->netdev,buf,len,Z_CONTROL_SOCK);
++                      break;
++
++              case ZB_SEND_DATA_CONFIRM:
++                      /* Return the results from zb_SendDataRequest */
++                      if(zb->netdev)
++                      {
++                              priv = netdev_priv(zb->netdev);
++                              if(buf[4] == Z_SUCCESS)
++                                      priv->stats.tx_packets++;
++                              else
++                              {
++                                      printk(KERN_WARNING "ZB: send data failed 0x%x\n",buf[4]);
++                                      priv->stats.tx_dropped++;
++                              }
++                              zb_rx(zb->netdev,buf,len,Z_CONTROL_SOCK);
++                      }
++                      break;
++
++              case ZDO_STATE_CHANGE_IND:
++                      if((z_info->msg_flag & START_CNF_BIT) == 0)
++                      {
++                              z_info->msg_flag |= START_CNF_BIT;
++                              wake_up_interruptible(&z_info->wait_queue);
++                      }
++                      break;
++
++              default:
++
++                      /* send data to the user application */
++                      zb_rx(zb->netdev,buf,len,Z_CONTROL_SOCK);
++                      break;
++      }
++}
++
++int init_zaccel(struct bmi_zb *zb)
++{
++      struct zaccel_info *z_info;
++      int rc = 0;
++
++      z_info = &zb->z_info;
++      memset(z_info,0, sizeof(struct zaccel_info));
++
++      init_waitqueue_head(&z_info->wait_queue);
++
++      INIT_LIST_HEAD(&z_info->xmt_list);
++
++      INIT_WORK(&zb->xmt_work, zaccel_xmt);
++
++      z_info->msg_flag = 0;
++      z_info->app_type = NO_APP_TYPE;
++
++      /* Release Z-Accel */
++      zb_Reset(zb,ZB_RELEASE);
++
++      printk(KERN_DEBUG "wait for ZACCEL_RESET_IND\n");
++      /* Wait for the reset indication message from Z-Accel */
++      rc = wait_event_interruptible_timeout(z_info->wait_queue,
++                     ((z_info->msg_flag & RESET_IND_BIT) != 0),Z_RESET_TIMEOUT);
++
++      /*
++       * Run Loopback test to test SPI Interface.  If this test fails, and
++       * SPI interface is bad, we probably would not get the reset indication
++       * message that we were waiting for previously.
++       */
++
++      if(rc == 0)
++      {
++              printk(KERN_ERR "bmi_zaccel: Z-Accel device failed\n");
++              return -ENODEV;
++
++      }
++      else
++      {
++              /* a short delay to make sure that Z-Accel is done
++               * initializing.   Advice from TI ZigBee Forum discussion.
++               */
++              mdelay(2000);
++              /* SPI loopback test */
++              rc  = zb_SysTestLoopback(zb);
++              if(rc != 0)
++              {
++                      printk(KERN_ERR "bmi_zaccel: SPI Loopback test FAILED %d\n",rc);
++                      return -ENODEV;
++              }
++      }
++
++      /* print string for python factory test. Don't remove */
++      printk(KERN_INFO "bmi_zaccel: SPI Loopback test PASSED\n");
++
++      printk(KERN_INFO "bmi_zaccel: Z-Accel is ready\n");
++
++      return 0;
++}
++
++void remove_zaccel(struct bmi_zb *zb)
++{
++      /* hold Zaccel reset */
++      zb_Reset(zb,ZB_RESET);
++}
++
++
++void zaccel_getdev(struct bmi_zb *zb)
++{
++      struct zaccel_info *z_info;
++      struct zaccel_device zdev;
++
++      z_info = &zb->z_info;
++
++      zb_GetDeviceInfo(zb,ZB_DEVICE_STATE,
++                                  (unsigned char *)&zdev.state);
++      zb_GetDeviceInfo(zb,ZB_DEVICE_IEEE_ADDR,
++                                  (unsigned char *)&zdev.device_ieee);
++      zb_GetDeviceInfo(zb,ZB_DEVICE_SHORT_ADDR,
++                                  (unsigned char *)&zdev.device_short);
++      zb_GetDeviceInfo(zb,ZB_PARENT_SHORT_ADDR,
++                                  (unsigned char *)&zdev.parent_short);
++      zb_GetDeviceInfo(zb,ZB_PARENT_IEEE_ADDR,
++                                  (unsigned char *)&zdev.parent_ieee);
++      zb_GetDeviceInfo(zb,ZB_DEVICE_CHANNEL,
++                                  (unsigned char *)&zdev.channel);
++      zb_GetDeviceInfo(zb,ZB_DEVICE_PANID,
++                                  (unsigned char *)&zdev.panid);
++      zb_GetDeviceInfo(zb,ZB_DEVICE_EXT_PANID,
++                                  (unsigned char *)&zdev.ext_panid);
++
++      z_info->device.state = zdev.state;
++      memcpy(&z_info->device.device_ieee,&zdev.device_ieee,8);
++      memcpy(&z_info->device.device_short,&zdev.device_short,2);
++      memcpy(&z_info->device.parent_short,&zdev.parent_short,2);
++      memcpy(&z_info->device.parent_ieee,&zdev.parent_ieee,8);
++      z_info->device.channel = zdev.channel;
++      memcpy(&z_info->device.panid,&zdev.panid,2);
++      memcpy(&z_info->device.ext_panid,&zdev.ext_panid,8);
++}
+--- /dev/null
++++ git/drivers/bmi/pims/zb/bmi_zaccel.h
+@@ -0,0 +1,288 @@
++/*
++ * File:         drivers/bmi/pims/zb/zaccel.h
++ * Author:       V. Thavisri <v.thavisri@encadis.com>
++ *
++ *            This is the header file for the CC2480 TI on
++ *            ZigBee module. It is derived from the following source
++ *
++ */
++
++
++#ifndef _ZACCEL_H
++#define _ZACCEL_H
++
++#define RSPS_CMD                     0x40
++/* SYS Interface commands */
++#define SYS_RESET_REQ_0              0x41
++#define SYS_RESET_REQ_1              0x00
++#define SYS_RESET_IND                0x4180
++#define       SYS_VER_0                    0x21
++#define       SYS_VER_1                    0x02
++#define SYS_OSAL_NV_READ             0x2108
++#define SYS_OSAL_NV_WRITE            0x2109
++#define SYS_OSAL_START_TIMER         0x210A
++#define SYS_OSAL_TIMER_EXPIRED       0x4181
++#define SYS_RANDOM                   0X210C
++#define SYS_ADC_READ                 0x210D
++#define SYS_GPIO                     0x210E
++#define SYS_TEST_RF_0                0x41
++#define SYS_TEST_RF_1                0x40
++#define SYS_TEST_LOOPBACK_REQ        0x2141
++#define SYS_TEST_LOOPBACK_REQ_0      0x21
++#define SYS_TEST_LOOPBACK_REQ_1      0x41
++#define SYS_TEST_LOOPBACK_RSP        0x6141
++#define SYS_RF_POWER_AMP_0           0x21
++#define SYS_RF_POWER_AMP_1           0x10
++#define SYS_RF_POWER_AMP_RSP         0x6110
++
++/* Configuration Interface Commands */
++#define ZB_READ_CONFIG_REQ_0         0x26
++#define ZB_READ_CONFIG_REQ_1         0x04
++#define ZB_WRITE_CONFIG_REQ_0        0x26
++#define ZB_WRITE_CONFIG_REQ_1        0x05
++#define ZB_WRITE_CONFIG_RSP          0x6605
++
++/* ZigBee PIM specific commands     */
++#define ZB_DEVICE_INFO_CHG_0           0xFF
++#define ZB_DEVICE_INFO_CHG_1           0x00
++
++// Simple API Interface
++#define ZB_APP_REGISTER_REQ_0        0x26
++#define ZB_APP_REGISTER_REQ_1        0x0A
++#define ZB_START_REQ_0               0x26
++#define ZB_START_REQ_1               0x00
++#define ZB_START_CONFIRM             0x4680
++#define ZB_PERMIT_JOINING_REQ_0      0x26
++#define ZB_PERMIT_JOINING_REQ_1      0x08
++#define ZB_BIND_DEVICE_0             0x26
++#define ZB_BIND_DEVICE_1             0x01
++#define ZB_BIND_CONFIRM              0x4681
++#define ZB_ALLOW_BIND_0              0x26
++#define ZB_ALLOW_BIND_1              0x02
++#define ZB_ALLOW_BIND_CONFIRM        0x4682
++#define ZB_SEND_DATA_REQ_0           0x26
++#define ZB_SEND_DATA_REQ_1           0x03
++#define ZB_SEND_DATA_CONFIRM         0x4683
++#define ZB_RCV_DATA_IND              0x4687
++#define ZB_GET_DEVICE_INFO_0         0x26
++#define ZB_GET_DEVICE_INFO_1         0x06
++#define ZB_FIND_DEVICE_REQ_0         0x26
++#define ZB_FIND_DEVICE_REQ_1         0x07
++#define ZB_FIND_DEVICE_CONFIRM       0X4685
++
++// AF Interface
++#define AF_REGISTER_0                0x24
++#define AF_REGISTER_1                0x00
++#define AF_DATA_REQ_0                0x24
++#define AF_DATA_REQ_1                0x01
++#define AF_DATA_CONFIRM              0x4480
++#define AF_INCOMING_MSG              0x4481
++
++// ZDO Interface
++#define ZDO_NWK_ADDR_REQ             0x2500
++#define ZDO_IEEE_ADDR_REQ            0x2501
++#define ZDO_NODE_DESC_REQ            0x2502
++#define ZDO_NODE_DESC_RES            0x2582
++#define ZDO_SIMPLE_DESC_REQ          0x2504
++#define ZDO_SIMPLE_DESC_RSP          0x4584
++#define ZDO_ACTIVE_EP_REQ            0x2505
++#define ZDO_ACTIVE_EP_RSP            0x4585
++#define ZDO_MATCH_DESC_REQ           0x2506
++#define ZDO_MATCH_DESC_RSP           0x4586
++#define ZDO_MATCH_DESC_RSP_SENT      0x45C2
++#define ZDO_USER_DESC_REQ            0x2508
++#define ZDO_USER_DESC_RSP            0x4588
++#define ZDO_USER_DESC_SET            0x250B
++#define ZDO_USER_DESC_CONF           0x4589
++#define ZDO_END_DEVICE_ANNCE         0x250A
++#define ZDO_END_DEVICE_ANNCE_IND     0x45C1
++#define ZDO_END_DEVICE_BIND_REQ      0x2520
++#define ZDO_END_DEVICE_BIND_RES_RSP  0x45A0
++#define ZDO_BIND_REQ                 0x2521
++#define ZDO_BIND_RSP                 0x45A1
++#define ZDO_UNBIND_REQ               0x2522
++#define ZDO_UNBIND_RSP               0x45A2
++#define ZDO_MGMT_LQI_REQ             0x2531
++#define ZDO_MGMT_LQI_RSP             0x45B1
++#define ZDO_MGMT_LEAVE_REQ           0x2534
++#define ZDO_MGMT_LEAVE_RSP           0x45B4
++#define ZDO_MGMT_PERMIT_JOIN_REQ     0x2536
++#define ZDO_MGMT_PERMIT_JOIN_RSP     0x45B6
++#define ZDO_STATE_CHANGE_IND         0x45C0
++
++// ZCD_NV_STARTUP_OPTION value
++#define ZCD_STARTOPT_DEFAULT_CONFIG   0x01
++#define ZCD_STARTOPT_DEFAULT_NETWORK  0x02
++#define ZCD_STARTOPT_AUTO_START       0x04
++#define ZCD_STARTOPT_VALID            0x02    // max valid option value
++#define ZCD_STARTOPT_MASK             0x03
++
++// ZCD_NV_LOGICAL_TYPE
++#define ZB_COORDINATOR    0x00
++#define ZB_ROUTER         0x01
++#define ZB_ENDDEVICE      0x02
++#define ZB_VALID_DEVICE   0x02
++#define ZB_DEVICE_MASK    0x03
++#define ZB_INVALID_DEVICE 0xFF
++
++// ZB_GET_DEVICE_INFO parameters
++#define ZB_DEVICE_STATE      0x00
++#define ZB_DEVICE_IEEE_ADDR  0x01
++#define ZB_DEVICE_SHORT_ADDR 0x02
++#define ZB_PARENT_SHORT_ADDR 0x03
++#define ZB_PARENT_IEEE_ADDR  0x04
++#define ZB_DEVICE_CHANNEL    0x05
++#define ZB_DEVICE_PANID      0x06
++#define ZB_DEVICE_EXT_PANID  0x07
++#define ZB_DEVICE_LAST       0x07
++
++/* Z-Accel command return value */
++#define Z_SUCCESS            0x00
++#define Z_FAILURE            0x01
++#define Z_INVALID_PARAM      0x02
++
++#define Z_ALLOW_BIND        0xFF
++#define Z_DENY_BIND         0x00
++
++#define Z_PERMIT_JOIN       0xFF
++#define Z_DENY_JOIN         0x00
++
++#define Z_BIND_CREATE       0x01
++#define Z_BIND_REMOVE       0x00
++
++#define Z_CONFIG_OFFSET     6
++
++#define SYS_RF_PA_MIN       25    /* valid power level 0 - 25 */
++
++// ZB_DEVICE_STATE definition
++typedef enum
++{
++  DEV_HOLD,               // Initialized - not started automatically
++  DEV_INIT,               // Initialized - not connected to anything
++  DEV_NWK_DISC,           // Discovering PAN's to join
++  DEV_NWK_JOINING,        // Joining a PAN
++  DEV_NWK_REJOIN,         // ReJoining a PAN, only for end devices
++  DEV_END_DEVICE_UNAUTH,  // Joined but not yet authenticated by trust center
++  DEV_END_DEVICE,         // Started as device after authentication
++  DEV_ROUTER,             // Device joined, authenticated and is a router
++  DEV_COORD_STARTING,     // Started as Zigbee Coordinator
++  DEV_ZB_COORD,           // Started as Zigbee Coordinator
++  DEV_NWK_ORPHAN          // Device has lost information about its parent..
++} devStates_t;
++
++// zstate - Z-Accel device state
++#define ZACCEL_RESET           0
++#define ZACCEL_WAIT_RELEASE    1
++#define ZACCEL_RESET_IND       2
++#define ZACCEL_START_REQ       3
++#define ZACCEL_START_CNF       4
++#define ZACCEL_START_FAIL      5
++#define ZACCEL_APP_START       6
++#define ZACCEL_TERMINATE       7
++#define ZACCEL_POLL_DONE       8
++#define ZACCEL_UNDEFINE        0xFF
++
++/* periodic timer runs every 50 ms */
++#define Z_TIMER                (50*HZ)/1000
++#define Z_RESET_TIMEOUT        (20*HZ)
++#define Z_CNF_TIMEOUT          (15*HZ)
++#define Z_POLL_TIMER           (50*HZ)/1000
++#define Z_SRDY_TIMEOUT         (4*HZ)
++
++/* frequency to update zbinfo sysfs = (Z_TIMER * UPDATE_TICKS) */
++#define UPDATE_TICKS       20
++
++/* Reset option for ioctl */
++#define Z_DONT_RESET           0
++#define Z_HW_RESET             1
++#define Z_SW_RESET             2
++
++#define ZCMD_BUF       (256 + 3)
++#define ZCMD_HEADER      3
++
++struct zaccel_app_id
++{
++      unsigned char  endpoint;
++      unsigned short profile_id;
++      unsigned short device_id;
++      unsigned char  device_ver;
++      unsigned char  unused;
++      unsigned char  icmd_num;
++
++};
++struct zaccel_app_struct
++{
++      struct zaccel_app_id info;
++      unsigned char  commands[1];
++};
++
++struct zaccel_version
++{
++      unsigned char transportRev;
++      unsigned char product;
++      unsigned char majorRel;
++      unsigned char minorRel;
++      unsigned char hwRev;
++};
++
++struct zaccel_config
++{
++      unsigned char device;          // ZCD_NV_LOGICAL_TYPE
++      unsigned long chanlist;
++      unsigned short panid;
++};
++
++extern unsigned char zb_device_info_len[];
++#define ZDEVICE_INFO_NUM   8
++
++struct zaccel_device
++{
++      unsigned char state;
++      unsigned char device_ieee[8];
++      unsigned char device_short[2];
++      unsigned char parent_short[2];
++      unsigned char parent_ieee[8];
++      unsigned char channel;
++      unsigned char panid[2];
++      unsigned char ext_panid[8];
++};
++
++#define ZBIND_NUM_MAX 64
++struct zaccel_info
++{
++      unsigned char lastReset;
++      struct zaccel_version ver;
++      struct zaccel_device device;
++
++      struct list_head xmt_list;
++      wait_queue_head_t wait_queue;
++      unsigned short msg_flag;
++      unsigned short app_type;
++};
++
++#define NO_APP_TYPE         0
++#define SAPI_TYPE           1
++#define AF_INTERFACE_TYPE   2
++
++#define ZBUF_MAX_SIZE   150
++
++/* struct zaccel_info msg_flag bit definition */
++#define START_CNF_BIT    0x0001
++#define RESET_IND_BIT    0x0002
++
++/*
++ * XMT_MSG_SIZE = Maximum length of the ZB_SEND_DATA_REQUEST content.
++ * 2 bytes Destination, 2 bytes Command ID, 1 byte Handle
++ * 1 byte Ack, 1 byte Radius, 1 byte len, up to 84 bytes data.
++ */
++#define XMT_MSG_SIZE  92
++
++struct zaccel_xmt_msg
++{
++      struct list_head list;
++      unsigned char len;
++      unsigned char buf[XMT_MSG_SIZE];
++};
++
++
++#endif // _ZACCEL_H
+--- /dev/null
++++ git/drivers/bmi/pims/zb/bmi_zigbee.c
+@@ -0,0 +1,1296 @@
++/*
++ *    bmi_zigbee.c
++ *
++ *    BMI zigbee device driver
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*
++ * Include files
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/cdev.h>
++#include <linux/interrupt.h>
++#include <linux/i2c.h>
++#include <linux/spi/spi.h>
++#include <linux/delay.h>
++#include <linux/jiffies.h>
++#include <linux/timer.h>
++#include <linux/if.h>
++#include <asm/uaccess.h>
++#include <linux/bmi/bmi_zb.h>
++#include "bmi_zigbee.h"
++#include "bmi_zaccel.h"
++
++#define BMIZIGBEE_VERSION "1.1"
++
++// Global variables
++
++static struct bmi_zb bmi_zb[4];
++static int major;
++
++/*
++ *    BMI set up
++ */
++
++      // BMI device ID table
++static struct bmi_device_id bmi_zb_tbl[] =
++{
++      {
++              .match_flags = BMI_DEVICE_ID_MATCH_VENDOR | BMI_DEVICE_ID_MATCH_PRODUCT,
++              .vendor      = BMI_VENDOR_BUG_LABS,
++              .product     = BMI_PRODUCT_ZIGBEE,
++              .revision    = BMI_ANY,
++      },
++      { 0, },    /* terminate list */
++};
++
++MODULE_DEVICE_TABLE(bmi, bmi_zb_tbl);
++
++int  bmi_zb_probe(struct bmi_device *bdev);
++void bmi_zb_remove(struct bmi_device *bdev);
++
++static struct semaphore spi_sem;
++
++// BMI driver structure
++static struct bmi_driver bmi_zb_driver =
++{
++      .name     = "bmi_zb",
++      .id_table = bmi_zb_tbl,
++      .probe    = bmi_zb_probe,
++      .remove   = bmi_zb_remove,
++};
++
++// IOX
++// read byte from I2C IO expander
++static int ReadByte_IOX(struct i2c_adapter *adap, unsigned char offset, unsigned char *data)
++{
++      int    ret = 0;
++      struct i2c_msg rmsg[2];
++      int    num_msgs;
++
++
++      // Read Byte with Pointer
++      rmsg[0].addr = BMI_IOX_I2C_ADDRESS;
++      rmsg[0].flags = 0;                     // write
++      rmsg[0].len = 1;
++      rmsg[0].buf = &offset;
++
++      rmsg[1].addr = BMI_IOX_I2C_ADDRESS;
++      rmsg[1].flags = I2C_M_RD;              // read
++      rmsg[1].len = 1;
++      rmsg[1].buf = data;
++
++      num_msgs = 2;
++      ret = i2c_transfer(adap, rmsg, num_msgs);
++
++      if(ret == 2)
++      {
++              ret = 0;
++      }
++      else
++      {
++              printk(KERN_ERR "ReadByte_IOX() - i2c_transfer() zb failed.\n");
++              ret = -1;
++      }
++      return ret;
++}
++
++// IOX
++// write byte from I2C IO expander
++static int WriteByte_IOX(struct i2c_adapter *adap, unsigned char offset, unsigned char data)
++{
++      int    ret = 0;
++      struct i2c_msg wmsg[2];
++      int    num_msgs;
++
++      // Write Byte with Pointer
++      wmsg[0].addr = BMI_IOX_I2C_ADDRESS;
++      wmsg[0].flags = 0;                     // write
++      wmsg[0].len = 1;
++      wmsg[0].buf = &offset;
++
++      wmsg[1].addr = BMI_IOX_I2C_ADDRESS;
++      wmsg[1].flags = 0;                     // write
++      wmsg[1].len = 1;
++      wmsg[1].buf = &data;
++
++      num_msgs = 2;
++      ret = i2c_transfer(adap, wmsg, num_msgs);
++
++      if(ret == 2)
++      {
++              ret = 0;
++      }
++      else
++      {
++              printk(KERN_ERR "WriteByte_IOX() - i2c_transfer() zb failed.\n");
++              ret = -1;
++      }
++      return ret;
++}
++
++// char device file operation controls the module LEDs and reset
++
++// open
++int cntl_open(struct inode *inode, struct file *file)
++{
++      struct bmi_zb *zb;
++
++      zb = container_of(inode->i_cdev, struct bmi_zb, cdev);
++
++      zb->open_flag++;
++
++      // Save zb pointer for later.
++      file->private_data = zb;
++      return 0;
++}
++
++// release
++int cntl_release(struct inode *inode, struct file *file)
++{
++      struct bmi_zb *zb;
++
++      zb = (struct bmi_zb *)(file->private_data);
++      zb->open_flag = 0;
++      return 0;
++}
++
++
++// ioctl
++int cntl_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
++              unsigned long arg)
++{
++      struct i2c_adapter *adap;
++      struct bmi_zb *zb;
++      unsigned char buf[80];
++      int slot;
++      int i;
++
++      zb = (struct bmi_zb *)(file->private_data);
++
++      // error if zb not present
++      if(zb->bdev == 0)
++              return -ENODEV;
++
++      slot = zb->slot;
++      adap = zb->adap;
++
++      zb->adap = adap;
++
++      switch(cmd)
++      {
++              case BMI_ZB_RLEDOFF:
++                      bmi_slot_gpio_write_bit(slot, ZB_GPIO_RED_LED, ZB_GPIO_LED_OFF);
++                      break;
++
++              case BMI_ZB_RLEDON:
++                      bmi_slot_gpio_write_bit(slot, ZB_GPIO_RED_LED, ZB_GPIO_LED_ON);
++                      break;
++
++              case BMI_ZB_GLEDOFF:
++                      bmi_slot_gpio_write_bit(slot, ZB_GPIO_GREEN_LED, ZB_GPIO_LED_OFF);
++                      break;
++
++              case BMI_ZB_GLEDON:
++                      bmi_slot_gpio_write_bit(slot, ZB_GPIO_GREEN_LED, ZB_GPIO_LED_ON);
++                      break;
++
++              /*
++               * Below are unpublished commands, used for testing only.
++               */
++
++              case BMI_ZB_RESET:
++                      i = (__user arg) & 0xF;
++
++                      if(i == 0)
++                      {
++                              printk("external reset\n");
++                              zb_Reset(zb,ZB_RESET);
++                              mdelay(10);
++                              zb_Reset(zb,ZB_RELEASE);
++                      }
++                      else if (i == 1)
++                      {
++                              printk("soft reset\n");
++                              zb_SoftReset(zb);
++                      }
++                      else if (i == 2)
++                      {
++                              printk("set startup option to default\n");
++                              buf[0] = 3;
++                              zb_WriteConfiguration(zb,ZCD_NV_STARTUP_OPTION,1,(unsigned char *)&buf[0]);
++                      }
++
++                      break;
++
++              case BMI_ZB_SPI_SIG:
++                      zb_ReadSRDY(zb,1);
++                      zb_ReadMRDY(zb);
++                      break;
++
++              case BMI_ZB_LOOPBACK:
++                      zb_SysTestLoopback(zb);
++                      break;
++
++              case BMI_ZB_STARTREQ:
++                      zb_StartRequest(zb);
++                      break;
++
++              case BMI_ZB_UPDATE_STATE:
++                      zaccel_getdev(zb);
++                      break;
++
++              default:
++                      return -ENOTTY;
++      }
++
++      return 0;
++
++}
++
++struct file_operations zb_fops =
++{
++      .owner = THIS_MODULE,
++      .ioctl = cntl_ioctl,
++      .open = cntl_open,
++      .release = cntl_release,
++};
++
++
++void set_MRDY(struct bmi_zb *zb)
++{
++      /* Assert MRDY and SS pins */
++      bmi_slot_gpio_write_bit(zb->slot, ZB_GPIO_MRDY, 0);
++      bmi_slot_gpio_write_bit(zb->slot, ZB_GPIO_SS, 0);
++}
++
++
++void clr_MRDY(struct bmi_zb *zb)
++{
++      /* De-assert MRDY and SS pins */
++      bmi_slot_gpio_write_bit(zb->slot, ZB_GPIO_MRDY, 1);
++      bmi_slot_gpio_write_bit(zb->slot, ZB_GPIO_SS, 1);
++}
++
++static unsigned long jiff_interval(unsigned long start_time)
++{
++      unsigned long tick;
++
++      tick = jiffies;
++      if(tick >= start_time)
++      {
++              tick = tick - start_time;
++      }
++      else
++      {
++              tick = (0xFFFFFFFF - start_time) + tick;
++      }
++
++      return tick;
++}
++
++void zenable_irq(struct bmi_zb *zb)
++{
++      zb->enable = 1;
++#ifdef VE_OUT
++      printk("e-IRQ %d depth %d\n",zb->irq,zb->int_depth);
++#endif
++      if(zb->int_depth != 0)
++      {
++              zb->int_depth--;
++              enable_irq(zb->irq);
++      }
++      else
++      {
++              printk("zenable_irq: unbalance irq %d\n",zb->irq);
++      }
++}
++
++int wait_for_srdy(struct bmi_zb *zb,unsigned char type)
++{
++      int rc = 0;
++      int err = 0;
++
++      zb->srdy_state = ZB_SPI_WAIT_SRDY_H;
++      zb->start_time = jiffies;
++
++      /*
++       * Queue work to poll for SRDY high.
++       * From experimenting in the lab, I found that sometimes it took longer
++       * for the SRDY to go high when the host sent an SREQ command
++       * than when the host responded to the device AREQ (SPI_POLL_TYPE) command.
++       * So we delay the work to poll SRDY in SPI_REQ_TYPE.
++       * This delay is more of a fine tune process, and can be changed
++       * as long as it doesn't exceed the SPI transaction processing
++       * to over 1 second.
++       */
++
++      if(type == SPI_POLL_TYPE)
++      {
++              zb->delay = 0;
++      }
++      else if(type == SPI_REQ_TYPE)
++      {
++              zb->delay = SPI_CHK_SRDY_JIFFIES;
++      }
++
++      queue_delayed_work(zb->srdy_wq, &zb->srdy_work,zb->delay);
++
++      /*
++       * I use wait_event_interruptible instead of
++       * wait_event_interruptible_timeout here because we schedule
++       * work queue to poll SRDY.  The work schedules another
++       * work queue, if SRDY has not been changed.
++       * Using wait_event_interruptible_timeout can cause a race
++       * condition if the wait_event_interrupt_timeout timeout occurs while
++       * the work queue is running.
++       *
++       * The code wakes up when SRDY is high or when the work queue
++       * decides that it has waited too long.
++       */
++      err = wait_event_interruptible(zb->srdy_queue,
++                               ((zb->srdy_state == ZB_SPI_SRDY_HIGH) ||
++                                 (zb->srdy_state == ZB_SPI_SRDY_EXP)));
++
++      if(err != 0)
++      {
++              printk(KERN_WARNING "zb-%d wait_for_srdy err %d\n",zb->slot,err);
++      }
++
++      if(zb->srdy_state == ZB_SPI_SRDY_EXP)
++      {
++              rc = -1;
++      }
++
++      return rc;
++}
++
++void zaccel_spi_poll(struct bmi_zb *zb)
++{
++      struct spi_message msg;
++      unsigned char buf[ZCMD_HEADER + 256];
++      unsigned char len;
++#define AREQ_DEBUGx
++#ifdef AREQ_DEBUG
++      int i;
++#endif
++
++      struct spi_transfer t =
++      {
++              .len = SPI_MSG_HEADER_SIZE,
++              .cs_change = 0,
++              .delay_usecs = 0,
++      };
++
++      down(&spi_sem);
++      if(zb_ReadSRDY(zb,0) != 0)
++      {
++              /*
++               * check if SRDY is low.   If not, don't run the routine.
++               *
++               * This routine is the IRQ bottom half, scheduled in the IRQ
++               * service routine.
++               * Sometimes, the SRDY goes high before the routine is executed.
++               * That happens when the zaccel_spi_req, which is scheduled to
++               * run on the same queue, is executed before
++               * zaccel_spi_poll is executed.   Sometimes,
++               * the IRQ puts zaccel_spi_poll on the workqueue multiple times,
++               * each time when it sees SRDY low.
++               */
++#ifdef DEBUG_OUT
++              printk("zaccel_spi_poll SRDY high, depth %d\n",zb->int_depth);
++#endif
++
++              if(zb->int_depth != 0)
++              {
++                      /* If the interrupt is disabled, enable it */
++                      zenable_irq(zb);
++              }
++
++              up(&spi_sem);
++              return;
++      }
++
++      set_MRDY(zb);
++
++      buf[0] = 0;
++      buf[1] = 0;
++      buf[2] = 0;
++
++      t.tx_buf = (const void *)buf;
++      t.rx_buf = buf;
++      t.len = SPI_MSG_HEADER_SIZE;
++
++      /* Send three bytes of POLL command */
++      spi_message_init(&msg);
++      spi_message_add_tail(&t, &msg);
++
++      if((spi_sync(zb->spi, &msg) != 0) || (msg.status != 0))
++      {
++              /* error reading the data. */
++              printk(KERN_WARNING "send spi_sync error %d\n",msg.status);
++              clr_MRDY(zb);
++              up(&spi_sem);
++              zenable_irq(zb);
++              return;
++      }
++
++      if(wait_for_srdy(zb,SPI_POLL_TYPE) < 0)
++      {
++              /* time out */
++              printk(KERN_WARNING "%d - SRDY() high poll timeout\n",zb->slot);
++              clr_MRDY(zb);
++              up(&spi_sem);
++              zenable_irq(zb);
++              return;
++      }
++
++      /* Read three bytes to get the message length */
++      buf[0] = 0;
++      buf[1] = 0;
++      buf[2] = 0;
++
++      t.tx_buf = (const void *)buf;
++      t.rx_buf = buf;
++      t.len = SPI_MSG_HEADER_SIZE,
++      t.cs_change = 0,
++      t.delay_usecs = 0,
++
++      spi_message_init(&msg);
++      spi_message_add_tail(&t, &msg);
++
++      if((spi_sync(zb->spi, &msg) != 0) || (msg.status != 0))
++      {
++              /* error reading the data. */
++              printk(KERN_WARNING "rcv1 spi_sync error %d\n",msg.status);
++              clr_MRDY(zb);
++              up(&spi_sem);
++              zenable_irq(zb);
++              return;
++      }
++
++      /* buf[0] contains the length of the message */
++
++      if((buf[0] != 0) && (buf[0] != 0xFF))
++      {
++              /*
++               * Read the rest of the message, if length != 0 */
++              t.len = buf[0];
++
++              t.rx_buf = &buf[ZCMD_HEADER];
++              spi_message_init(&msg);
++
++              spi_message_add_tail(&t, &msg);
++              if((spi_sync(zb->spi, &msg) != 0) || (msg.status != 0))
++              {
++                      // error reading the data.   Set length to zero.
++                      buf[0] = 0;
++                      printk(KERN_WARNING "rcv2 spi_sync error %d\n",msg.status);
++              }
++      }
++
++      clr_MRDY(zb);
++      up(&spi_sem);
++      zenable_irq(zb);
++
++      /* buf[0] has message length */
++      len = buf[0];
++
++      if((buf[0] != 0xFF) && (buf[0] != 0))
++      {
++#ifdef AREQ_DEBUG
++              printk("AREQ-%d: ",zb->slot);
++              for(i = 0; i < (len + 3); i++)
++              {
++                      printk("%x ",buf[i]);
++              }
++
++              printk("\n");
++#endif
++      }
++      else
++      {
++              if(buf[0] == 0xFF)
++                      printk(KERN_WARNING "invalid 0xFF\n");
++              return;
++      }
++
++      zaccel_cmd_proc(zb,buf);
++      return;
++}
++
++void zaccel_chk_srdy(struct work_struct *work)
++{
++      struct bmi_zb *zb;
++
++      zb = container_of(work, struct bmi_zb, srdy_work);
++
++      /*
++       * check SRDY value.   If it matches what we are waiting
++       * for, we wake up the work on the queue.
++       * If not, we check the timer for timeout.
++       * If the timer is not expired, queue another zb->srdy_work, to
++       * check for the signal next time.
++       * If the timer is expired, set srdy_state to indicate timeout
++       * and wake up the work.
++       */
++
++      if((zb_ReadSRDY(zb,0) == 0) && (zb->srdy_state == ZB_SPI_WAIT_SRDY_L))
++      {
++              zb->srdy_state = ZB_SPI_SRDY_LOW;
++              wake_up_interruptible(&zb->srdy_queue);
++              return;
++      }
++      else if((zb_ReadSRDY(zb,0) == 1) && (zb->srdy_state == ZB_SPI_WAIT_SRDY_H))
++      {
++              zb->srdy_state = ZB_SPI_SRDY_HIGH;
++              wake_up_interruptible(&zb->srdy_queue);
++              return;
++      }
++      else if(jiff_interval(zb->start_time) < SPI_SRDY_H_TIMEOUT)
++      {
++              queue_delayed_work(zb->srdy_wq, &zb->srdy_work,zb->delay);
++      }
++      else
++      {
++              zb_ReadSRDY(zb,1);
++              printk(KERN_WARNING "zaccel_chk_srdy state %d\n",zb->srdy_state);
++              zb->srdy_state = ZB_SPI_SRDY_EXP;
++              wake_up_interruptible(&zb->srdy_queue);
++      }
++
++}
++
++/* work handler to process Z-Accel request */
++void zaccel_poll_proc(struct work_struct *work)
++{
++      struct bmi_zb *zb;
++
++      zb = container_of(work, struct bmi_zb, spi_work);
++
++      zaccel_spi_poll(zb);
++}
++
++void zaccel_sreq_proc(struct work_struct *work)
++{
++      struct bmi_zb *zb;
++
++      unsigned char buf[320];
++      struct spi_transfer t =
++      {
++              .tx_buf = (const void *)buf,
++              .rx_buf = buf,
++              .cs_change = 0,
++              .delay_usecs = 0,
++      };
++
++      unsigned char *rbuf;
++      struct spi_message msg;
++      unsigned char type;
++      unsigned short len;
++      int i;
++      int rc = 0;
++
++      zb = container_of(work, struct bmi_zb, sreq_work);
++
++      down(&spi_sem);
++
++      rbuf = zb->sreq_buf;
++      len  =  (size_t)(rbuf[0] + ZCMD_HEADER);
++      type =  rbuf[1] & SPI_CMD_TYPE_MASK;
++
++      t.len = len;
++      t.tx_buf = rbuf;
++
++#define SREQ_DEBUGx
++#ifdef SREQ_DEBUG
++      printk("SREQ-%d: ",zb->slot);
++
++      for(i = 0; i < len; i++)
++      {
++              printk("%x ",rbuf[i]);
++      }
++      printk("\n");
++
++#endif
++
++      set_MRDY(zb);
++
++      zb->srdy_state = ZB_SPI_WAIT_SRDY_L;
++
++      if(zb->enable == 1)
++      {
++              rc = wait_event_interruptible_timeout(zb->srdy_queue,zb->srdy_state == ZB_SPI_SRDY_LOW,SPI_SRDY_L_TIMEOUT);
++              if(rc == 0)
++              {
++                      printk(KERN_WARNING "bmi_zb-%d: SRDY low timeout\n",zb->slot);
++                      clr_MRDY(zb);
++                      zb->srdy_state = ZB_SPI_POLL;
++                      up(&spi_sem);
++                      zb->sreq_ret = -1;
++                      wake_up_interruptible(&zb->sreq_queue);
++                      return;
++              }
++      }
++      else
++      {
++              /*
++               * The interrupt has been disabled, because SRDY is low
++               * prior to enter this routine.   We proceed ahead with the
++               * SPI transaction.
++               */
++
++              if(zb_ReadSRDY(zb,0) != 0)
++              {
++                      /* Double check that SRDY is low, if not, give warning */
++                      printk(KERN_WARNING "zaccel_req_proc interrupt disable SRDY high\n");
++              }
++      }
++
++      i = 0;
++
++      spi_message_init(&msg);
++      spi_message_add_tail (&t, &msg);
++
++      if(spi_sync(zb->spi, &msg) != 0 || msg.status != 0)
++      {
++              printk(KERN_WARNING "bmi_zb: a - spi_sync error %d\n",msg.status);
++              zb->sreq_ret = -ENODEV;
++              goto done;
++      }
++
++      if(wait_for_srdy(zb,SPI_REQ_TYPE) < 0)
++      {
++              printk(KERN_WARNING "bmi_zb: SRDY wait to go high timeout\n");
++              zb->sreq_ret = -1;
++              goto done;
++      }
++
++      if(type == SPI_CMD_AREQ)
++      {
++              zb->sreq_ret = 0;
++              goto done;
++      }
++
++      buf[0] = 0;             /* Poll command has zero byte */
++      buf[1] = 0;             /* Poll command */
++      buf[2] = 0;             /* Poll command */
++
++      t.tx_buf = buf;
++      t.len = SPI_MSG_HEADER_SIZE;
++
++      spi_message_init(&msg);
++
++      spi_message_add_tail(&t, &msg);
++      if(spi_sync(zb->spi, &msg) != 0 || msg.status != 0)
++      {
++              printk(KERN_WARNING "bmi_zb: b- spi_sync error %d\n",msg.status);
++              zb->sreq_ret = -ENODEV;
++              goto done;
++      }
++
++      /* Read the length of the data */
++      if(buf[0] != 0)
++      {
++              // Set len to the length of the message and offset
++              // the buffer to after the header field.
++              t.len = buf[0];
++
++              t.tx_buf = (unsigned char *)buf + SPI_MSG_HEADER_SIZE;
++              t.rx_buf = (unsigned char *)buf + SPI_MSG_HEADER_SIZE;
++              spi_message_init(&msg);
++
++              spi_message_add_tail(&t, &msg);
++
++              rc = spi_sync(zb->spi, &msg);
++              clr_MRDY(zb);
++
++              if(rc != 0 || msg.status != 0)
++              {
++                      printk(KERN_WARNING "bmi_zb: c - spi_sync error %d\n",msg.status);
++                      zb->sreq_ret = -ENODEV;
++                      goto done;
++              }
++      }
++
++      clr_MRDY(zb);
++      up(&spi_sem);
++      zenable_irq(zb);
++
++      /*
++       * copy data back to the buffer.  Make sure that we don't
++       * copy more data than the space available.
++       */
++
++      if(buf[0] != 0xFF)
++      {
++              /* copy data to the return buffer, as much as the length
++               * of the data or the buffer size (zb->sreq_len)
++               */
++              if(zb->sreq_len > (buf[0] + 3))
++              {
++                      len = buf[0] + 3;
++              }
++              else
++              {
++                      len = zb->sreq_len;
++              }
++              memcpy(rbuf,buf,len);
++              zb->sreq_ret = zb->sreq_len;
++      }
++      else
++      {
++              zb->sreq_ret = -2;
++      }
++
++      /* We're done.   Wake up the SREQ work */
++      zb->srdy_state = ZB_SPI_POLL;
++      wake_up_interruptible(&zb->sreq_queue);
++
++#define SRSP_DEBUGx
++#ifdef SRSP_DEBUG
++      printk("SRSP-%d: ",zb->slot);
++      if(buf[0] != 0xFF)
++      {
++              for(i = 0; i < len; i++)
++              {
++                              printk("%x ",buf[i]);
++              }
++      }
++      else
++      {
++              printk("Invalid length\n");
++      }
++      printk("\n");
++#endif
++
++      /*
++       * Sometimes, back-to-back write configuration
++       * can chock the Z-Accel, result in fail SPI transaction.
++       * Delay the return (wait_event_interruptible_timeout
++       * will timeout - no one wakes up the queue), to prevent the problem.
++       */
++      rc = 0;
++      wait_event_interruptible_timeout(zb->delay_queue,(rc != 0), 5);
++
++      return;
++
++done:
++      clr_MRDY(zb);
++      zb->srdy_state = ZB_SPI_POLL;
++      up(&spi_sem);
++      zenable_irq(zb);
++      wake_up_interruptible(&zb->sreq_queue);
++      return;
++}
++
++int config_ports(struct bmi_zb *zb)
++{
++      struct i2c_adapter *adap;
++      int slot;
++      unsigned char iox_data;
++
++      slot = zb->slot;
++      adap = zb->adap;
++
++      /*
++       * Configure GPIO_RED_LED and GPIO_GREEN_LED as output
++       * and set them to low -- LEDs on
++       */
++
++      bmi_slot_gpio_configure_as_output(slot,ZB_GPIO_RED_LED,0);
++      bmi_slot_gpio_configure_as_output(slot,ZB_GPIO_GREEN_LED,0);
++
++      /*
++       * Configure GPIO_SS and GPIO_MRDY as output
++       * and set them to high -- deassert
++       */
++
++      bmi_slot_gpio_configure_as_output(slot,ZB_GPIO_MRDY,1);
++      bmi_slot_gpio_configure_as_output(slot,ZB_GPIO_SS,1);
++
++      /*
++       * Set ZB_RST to output port.
++       * Set LSR_MRDY_IOX and LSR_SRDY_IOX to input port.
++       */
++
++      if(ReadByte_IOX(adap, IOX_CONTROL, &iox_data))
++      {
++              printk(KERN_ERR "Unable to ReadByte_IOX - zb slot %d\n",slot);
++              return -ENODEV;
++      }
++
++      /* Set SRDY and MRDY port to input and RST to output */
++      iox_data |= (ZB_IOX_SRDY | ZB_IOX_MRDY);
++      iox_data &= ~(ZB_IOX_RST);
++
++      if(WriteByte_IOX(adap, IOX_CONTROL, iox_data))
++      {
++              printk(KERN_ERR "Unable to WriteByte_IOX - zb slot %d\n",slot);
++              return -ENODEV;
++      }
++
++      return 0;
++}
++
++// interrupt handler
++static irqreturn_t module_irq_handler(int irq, void *dummy)
++{
++      struct bmi_zb *zb;
++
++      disable_irq_nosync(irq);
++
++      switch(irq)
++      {
++              case M1_IRQ:
++                      zb = &bmi_zb[0];
++                      break;
++              case M2_IRQ:
++                      zb = &bmi_zb[1];
++                      break;
++              case M3_IRQ:
++                      zb = &bmi_zb[2];
++                      break;
++              case M4_IRQ:
++                      zb = &bmi_zb[3];
++                      break;
++              default:
++                      return IRQ_HANDLED;
++      }
++
++      zb->enable = 0;
++      zb->int_depth++;
++
++      if(zb->srdy_state == ZB_INT_WAIT_SRDY)
++      {
++              /*
++               * This interrupt is a part of host SREQ or AREQ.
++               * Set srdy flag to 0 to indicate that SRDY pin is asserted.
++               * Wake up the zb->spi_queue that is waiting for the event.
++               */
++              zb->srdy_state = ZB_INT_SRDY_LOW;
++              wake_up_interruptible(&zb->srdy_queue);
++      }
++      else
++      {
++              /*
++               * Z-Accel has an AREQ frame to send.
++               * Schedule SPI receive task to pull data out.
++               */
++              queue_work(zb->spi_wq, &zb->spi_work);
++      }
++
++      return IRQ_HANDLED;
++}
++
++/*
++ *    BMI functions
++ */
++
++int bmi_zb_probe(struct bmi_device *bdev)
++{
++      struct bmi_zb *zb;
++      struct i2c_adapter *adap;
++      struct class *bmi_class;
++      struct cdev *cdev;
++      struct net_device *netdev;
++      struct net_zb *priv;
++      dev_t dev_id;
++      int slot;
++      int irq;
++      int err;
++      char name[IFNAMSIZ];
++
++      err = 0;
++      slot = bmi_device_get_slot(bdev);
++      adap = bmi_device_get_i2c_adapter(bdev);
++
++      zb = &bmi_zb[slot];
++
++      zb->slot = slot;
++      zb->adap = adap;
++
++      dev_id = MKDEV(major, slot);
++
++      // Initialize GPIOs, turn on Red and Green LEDs.
++      if(config_ports(zb))
++      {
++              printk(KERN_ERR "Unable to configure ZB port pins slot %d\n",(slot+1));
++              return -EFAULT;
++      }
++
++      // Hold Z-Accel reset
++      zb_Reset(zb,ZB_RESET);
++
++      // setup SPI
++      printk(KERN_INFO "ZB SPI_MODE_2 clock %d\n",ZB_SPI_SPEED);
++      if(bmi_device_spi_setup(bdev, ZB_SPI_SPEED, SPI_MODE_2, ZB_SPI_BPW))
++      {
++              printk(KERN_ERR "Unable to setup spi\n");
++              return -EFAULT;
++      }
++      bmi_slot_spi_enable(slot);
++
++      zb->spi = &bdev->spi;
++      zb->srdy_state = ZB_SPI_POLL;
++
++      INIT_WORK(&zb->spi_work, zaccel_poll_proc);
++      INIT_WORK(&zb->sreq_work, zaccel_sreq_proc);
++      INIT_DELAYED_WORK(&zb->srdy_work, zaccel_chk_srdy);
++
++      init_waitqueue_head(&zb->sreq_queue);
++      init_waitqueue_head(&zb->srdy_queue);
++      init_waitqueue_head(&zb->delay_queue);
++
++      /*
++       * create a thread to handle SPI access.
++       * spi_sem allows one ZigBee module to perform and complete its
++       * SPI transaction before other Zigbee does its SPI.
++       */
++      if(slot == 0)
++      {
++              zb->spi_wq = create_singlethread_workqueue("zaccel_spi0");
++              zb->srdy_wq = create_singlethread_workqueue("zaccel_srdy0");
++      }
++      else if(slot == 1)
++      {
++              zb->spi_wq = create_singlethread_workqueue("zaccel_spi1");
++              zb->srdy_wq = create_singlethread_workqueue("zaccel_srdy1");
++      }
++      else if(slot == 2)
++      {
++              zb->spi_wq = create_singlethread_workqueue("zaccel_spi2");
++              zb->srdy_wq = create_singlethread_workqueue("zaccel_srdy2");
++      }
++      else if(slot == 3)
++      {
++              zb->spi_wq = create_singlethread_workqueue("zaccel_spi3");
++              zb->srdy_wq = create_singlethread_workqueue("zaccel_srdy3");
++      }
++
++
++      if((!zb->spi_wq) && (!zb->srdy_wq))
++      {
++              printk(KERN_ERR "ZB: create workqueue failed %d\n",slot);
++              if(zb->spi_wq)
++              {
++                      destroy_workqueue(zb->spi_wq);
++              }
++
++              if(zb->srdy_wq)
++              {
++                      destroy_workqueue(zb->srdy_wq);
++              }
++
++              bmi_slot_spi_disable(slot);
++              bmi_device_spi_cleanup(bdev);
++              return -ENOMEM;
++      }
++
++      // request PIM interrupt
++      irq = bmi_device_get_status_irq(bdev);
++      zb->irq = irq;
++      zb->int_depth = 0;
++
++      sprintf(zb->int_name, "bmi_zb%d", slot);
++      err = request_irq(irq, &module_irq_handler, 0, zb->int_name, zb);
++      if(err)
++      {
++              printk(KERN_ERR "bmi_zb.c: Can't allocate irq %d nor find ZB in slot %d \n", irq, slot);
++              destroy_workqueue(zb->spi_wq);
++              destroy_workqueue(zb->srdy_wq);
++              bmi_slot_spi_disable(slot);
++              bmi_device_spi_cleanup(bdev);
++              return -EBUSY;
++      }
++
++      printk(KERN_INFO "bmi_zb.c: ZIGBEE create class device\n");
++      bmi_class = bmi_get_bmi_class();
++      zb->class_dev = device_create(bmi_class, NULL, dev_id, zb,
++                                             "bmi_zb%i", slot + 1);
++
++      if(IS_ERR(zb->class_dev))
++      {
++              printk(KERN_ERR "Unable to create "
++                              "class_device for bmi_zb_%i; errno = %ld\n",
++                              slot+1, PTR_ERR(zb->class_dev));
++              zb->class_dev = NULL;
++              err = -ENODEV;
++              goto error;
++      }
++
++      /* Allocate network device */
++      sprintf(name, "zb%d",(slot+1));
++      netdev = alloc_netdev(sizeof(struct net_zb),name,zb_net_setup);
++      if(!netdev)
++      {
++              printk(KERN_ERR "zb%d: cannot register net device \n",slot);
++              err = -ENOMEM;
++              goto error0;
++
++      }
++
++      priv = netdev_priv(netdev);
++      priv->zb = zb;
++
++      err = init_zaccel(zb);
++      if(err < 0)
++      {
++              printk(KERN_ERR "zb%d: Z-Accel device not start\n",(slot+1));
++              goto error1;
++      }
++
++      err = register_netdev(netdev);
++      if(err < 0)
++      {
++              printk(KERN_WARNING "zb: cannot register net device\n");
++              goto error1;
++      }
++
++      zb_create_sysfs(netdev);
++
++      zb->netdev = netdev;
++
++      // bind driver and bmi_device
++      zb->bdev = bdev;
++      bmi_device_set_drvdata(bdev,zb);
++
++      cdev = &zb->cdev;
++      cdev_init(cdev, &zb_fops);
++      err = cdev_add(cdev, dev_id, 1);
++      if(err < 0)
++      {
++              printk(KERN_ERR "Unable to add cdev for ZigBee module\n");
++              goto error2;
++      }
++
++      /* turn LED's off */
++      bmi_set_module_gpio_data(slot, ZB_GPIO_RED_LED, ZB_GPIO_LED_OFF);
++      bmi_set_module_gpio_data(slot, ZB_GPIO_GREEN_LED, ZB_GPIO_LED_OFF);
++
++      return 0;
++
++error2:
++      zb_remove_sysfs(netdev);
++      zb->bdev = NULL;
++      bmi_device_set_drvdata(bdev,0);
++
++      zb->netdev = NULL;
++      unregister_netdev(netdev);
++
++error1:
++      remove_zaccel(zb);
++      free_netdev(netdev);
++
++error0:
++      zb->class_dev = NULL;
++      device_destroy(bmi_class,dev_id);
++
++error:
++
++      free_irq(irq, zb);
++      zb->irq = 0;
++      destroy_workqueue(zb->spi_wq);
++      destroy_workqueue(zb->srdy_wq);
++      bmi_slot_spi_disable(slot);
++      bmi_device_spi_cleanup(bdev);
++
++      printk(KERN_ERR "bmi_zb: modprobe error %d\n",err);
++      return err;
++}
++
++/* remove PIM */
++void bmi_zb_remove(struct bmi_device *bdev)
++{
++      int slot;
++      int irq;
++      struct bmi_zb *zb;
++      struct class *bmi_class;
++      struct net_device *netdev;
++
++      slot = bmi_device_get_slot(bdev);
++      zb = &bmi_zb[slot];
++
++      /* Free the interrupt first.  This is to prevent stranded interrupt
++       * when we hold the Z-Accel reset.
++       */
++      irq = bmi_device_get_status_irq(bdev);
++      free_irq(irq, zb);
++
++      destroy_workqueue(zb->spi_wq);
++      destroy_workqueue(zb->srdy_wq);
++
++      remove_zaccel(zb);
++
++      cdev_del(&zb->cdev);
++
++      /* Unregister and deallocate net_device  */
++      netdev = zb->netdev;
++      zb_remove_sysfs(netdev);
++      unregister_netdev(netdev);
++      free_netdev(netdev);
++      zb->netdev = NULL;
++
++      zb->irq = 0;
++      zb->spi = (struct spi_device *)NULL;
++      bmi_slot_spi_disable(slot);
++      bmi_device_spi_cleanup(bdev);
++
++      bmi_slot_gpio_configure_all_as_inputs(slot);
++
++      bmi_class = bmi_get_bmi_class();
++      device_destroy(bmi_class, MKDEV(major,slot));
++      zb->class_dev = 0;
++
++      /* de-attach driver-specific struct from bmi_device structure */
++      bmi_device_set_drvdata(bdev,0);
++      zb->bdev = 0;
++
++      printk(KERN_INFO "bmi_zb: remove completed\n");
++      return;
++}
++
++int zaccel_spi_req(struct bmi_zb *zb, unsigned char *rbuf, unsigned short buf_len)
++{
++      int err;
++
++      zb->sreq_buf = rbuf;
++      zb->sreq_len = buf_len;
++
++      queue_work(zb->spi_wq, &zb->sreq_work);
++      zb->sreq_ret = 0xFF;
++      err = wait_event_interruptible_timeout(zb->sreq_queue,zb->sreq_ret != 0xFF,(5*HZ));
++      if(err == 0)
++      {
++              printk(KERN_ERR "zaccel_spi_req timeout %d\n",zb->sreq_ret);
++              zb->sreq_ret = -ENODEV;
++      }
++
++      return zb->sreq_ret;
++}
++
++void zb_ReadMRDY(struct bmi_zb *zb)
++{
++      int mrdy;
++      int ss;
++
++      mrdy = bmi_slot_gpio_read_bit(zb->slot,ZB_GPIO_MRDY);
++      ss = bmi_slot_gpio_read_bit(zb->slot,ZB_GPIO_SS);
++      printk("zb-SPI: MRDY %d SS %d\n",mrdy,ss);
++}
++
++int zb_ReadSRDY(struct bmi_zb *zb, int print)
++{
++      int irq_pin;
++      int value;
++
++      irq_pin = bmi_slot_status_irq_state(zb->slot);
++
++      if(irq_pin == 1)
++              value = 0;
++      else
++              value = 1;
++
++      if(print == 1)
++              printk("zb-SPI: srdy %d\n",value);
++      return value;
++}
++
++/* Z-Accel hardware reset */
++int zb_Reset(struct bmi_zb *zb, unsigned char state)
++{
++      unsigned char iox_data;
++
++      if(ReadByte_IOX (zb->adap, IOX_OUTPUT_REG, &iox_data))
++              return -ENODEV;
++
++      if(state == ZB_RESET)
++      {
++              iox_data &= ~ZB_IOX_RST;
++      }
++      else if(state == ZB_RELEASE)
++      {
++              zb->z_info.msg_flag &= ~RESET_IND_BIT;
++              iox_data |= ZB_IOX_RST;
++      }
++
++      if(WriteByte_IOX (zb->adap, IOX_OUTPUT_REG, iox_data))
++              return -ENODEV;
++
++      return 0;
++}
++
++static void __exit bmi_zb_cleanup(void)
++{
++      dev_t dev_id;
++
++      bmi_unregister_driver(&bmi_zb_driver);
++
++      /* Unregister PF_ZACCEL socket */
++      z_sock_exit();
++
++      dev_id = MKDEV(major, 0);
++      unregister_chrdev_region(dev_id, 4);
++
++      return;
++}
++
++static int __init bmi_zb_init(void)
++{
++      dev_t dev_id;
++      int   retval;
++
++      // allocate char device for the module control.
++      retval = alloc_chrdev_region(&dev_id, 0, 4, "BMI ZigBee Driver");
++      if(retval)
++      {
++              printk(KERN_ERR "Unable to allocate zb chardev_region\n");
++              return -1;
++      }
++      major = MAJOR(dev_id);
++
++      /* Register PF_ZACCEL protocol socket */
++      retval = z_sock_init();
++      if(retval)
++      {
++              unregister_chrdev_region(dev_id, 4);
++              printk(KERN_ERR "ZB: protocol register failed %d \n", retval);
++              return -1;
++      }
++
++      init_MUTEX(&spi_sem);
++
++      retval = bmi_register_driver(&bmi_zb_driver);
++      if(retval)
++      {
++              z_sock_exit();
++              unregister_chrdev_region(dev_id, 4);
++
++              printk(KERN_ERR "ZB: bmi_unregister_driver failed %d\n", retval);
++              return -1;
++      }
++
++      printk(KERN_INFO "bmi_zb.c: BMI_ZIGBEE Driver v%s 0x%x\n", BMI_ZB_VERSION,BMI_PRODUCT_ZIGBEE);
++
++      return 0;
++}
++
++
++module_init(bmi_zb_init);
++module_exit(bmi_zb_cleanup);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("V. Thavisri <v.thavisri@encadis.com>");
++MODULE_DESCRIPTION("BMI ZigBee device driver");
++MODULE_SUPPORTED_DEVICE("bmi_zigbee_control");
+--- /dev/null
++++ git/drivers/bmi/pims/zb/bmi_zigbee.h
+@@ -0,0 +1,194 @@
++/*
++ * File:
++ * Author:   V. Thavisri <v.thavisri@encadis.com>
++ *
++ *           Header file for the ZB module on the MX31 BUG platform.
++ */
++#ifndef BMI_ZB_H
++#define BMI_ZB_H
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/fs.h>
++#include <linux/device.h>
++#include <linux/cdev.h>
++#include <linux/i2c.h>
++#include <linux/spi/spi.h>
++#include <linux/jiffies.h>
++#include <linux/timer.h>
++#include <linux/workqueue.h>
++#include <linux/netdevice.h>
++#include <linux/interrupt.h>
++#include <linux/bmi.h>
++#include <linux/bmi/bmi-control.h>
++#include <linux/bmi/bmi_ioctl.h>
++#include <linux/bmi/bmi_zb.h>
++#include "bmi_zaccel.h"
++
++#define BMI_ZB_VERSION   "1.0"
++#define VE_DEBUG
++
++// GPIO
++#define ZB_GPIO_RED_LED   3
++#define ZB_GPIO_GREEN_LED 2
++#define ZB_GPIO_MRDY      1
++#define ZB_GPIO_SS        0
++
++#define ZB_GPIO_LED_ON    0
++#define ZB_GPIO_LED_OFF   1
++
++#define BMI_IOX_I2C_ADDRESS 0x71
++// I2C IOX register addressess
++#define IOX_INPUT_REG           0x0
++#define IOX_OUTPUT_REG          0x1
++#define IOX_POLARITY_REG        0x2
++#define IOX_CONTROL             0x3
++
++#define ZB_IOX_RST              0x1
++#define ZB_IOX_MRDY             0x2
++#define ZB_IOX_SRDY             0x4
++
++// SPI parameters
++#define ZB_SPI_SPEED            2000000
++#define ZB_SPI_BPW              8
++
++// SPI state
++// check the state when SRDY is asserted to determine which
++// SPI transaction the host wants to perform.
++#define ZB_SPI_POLL            0
++#define ZB_SPI_WAIT_SRDY_L     1
++#define ZB_SPI_SRDY_LOW        2
++#define ZB_SPI_WAIT_SRDY_H     3
++#define ZB_SPI_SRDY_HIGH       4
++#define ZB_SPI_TIME2POLL       5
++#define ZB_SPI_SRDY_EXP        6
++#define ZB_SPI_WAIT_SRDY_Q     7
++
++#define ZB_INT_POLL            0
++#define ZB_INT_WAIT_SRDY       1
++#define ZB_INT_SRDY_LOW        2
++
++#define SPI_POLL_TYPE  0
++#define SPI_REQ_TYPE   1
++
++#define ZB_RESET      0
++#define ZB_RELEASE    1
++
++#define SPI_BUF_MAX_SIZE        ZBUF_MAX_SIZE
++#define SPI_MSG_HEADER_SIZE     3
++
++#define SPI_CMD_POLL            0x00
++#define SPI_CMD_SREQ            0x20
++#define SPI_CMD_AREQ            0x40
++#define SPI_CMD_TYPE_MASK       (SPI_CMD_SREQ | SPI_CMD_AREQ)
++
++#define SPI_CHK_SRDY_JIFFIES    1
++#define SPI_CHK_SRDY_TIME       4000
++#define SPI_SRDY_L_TIMEOUT      (HZ>>1)
++#define SPI_SRDY_H_TIMEOUT      (HZ>>1)
++
++// Zigbee network private information
++struct net_zb
++{
++      struct net_device *dev;
++      struct bmi_zb *zb;
++      struct net_device_stats stats;
++      unsigned char net_open;
++      unsigned char socket[Z_NUM_SOCK];
++};
++
++struct bmi_zb
++{
++      struct bmi_device    *bdev;
++      struct cdev          cdev;
++      struct net_device    *netdev;
++      struct device  *class_dev;
++      struct i2c_adapter    *adap;
++      struct spi_device    *spi;          /* SPI device */
++
++      struct work_struct   spi_work;      /* work to process Poll req */
++      struct work_struct   xmt_work;      /* work to xmt to device */
++      struct work_struct   sreq_work;     /* work to process sreq */
++      struct work_struct   state_work;    /* work to check device state */
++
++      struct delayed_work  srdy_work;     /* work to chk for SRDY */
++
++      unsigned long start_time;
++      unsigned long delay;
++
++      struct workqueue_struct *spi_wq;
++      struct workqueue_struct *srdy_wq;
++
++      wait_queue_head_t    srdy_queue;
++      unsigned char        srdy_state;
++      unsigned char        enable;
++      unsigned char        int_depth;
++
++      wait_queue_head_t    sreq_queue;
++      unsigned char        *sreq_buf;
++      unsigned short       sreq_len;
++      int                  sreq_ret;
++
++      wait_queue_head_t    delay_queue;
++
++      char                 int_name[20];  /* interrupt name */
++      int                  slot;          /* base unit slot number */
++      int                  open_flag;     /* single open flag */
++      int                  irq;
++      struct zaccel_info   z_info;
++};
++
++extern int  zb_Reset(struct bmi_zb *zb, unsigned char state);
++extern void zb_StartDevice(struct bmi_zb *zb, unsigned char option);
++extern int zb_StartRequest(struct bmi_zb *zb);
++extern void zb_spi_poll(void *arg);
++extern int zaccel_spi_req(struct bmi_zb *zb, unsigned char *data, unsigned short buf_len);
++extern int zaccel_SRDY_poll(struct bmi_zb *zb, unsigned char polarity);
++extern int zb_GetDeviceInfo(struct bmi_zb *zb, unsigned char param, unsigned char *buf);
++extern unsigned char zb_WriteConfiguration(struct bmi_zb *zb, unsigned char configId, unsigned char len, unsigned char *data);
++extern int zb_ReadConfiguration(struct bmi_zb *zb, unsigned char configId,
++                        unsigned char *buf);
++extern int zb_zcommand(struct bmi_zb *zb, unsigned short cmd, unsigned char len,
++                        unsigned char *buf);
++extern void zb_SoftReset(struct bmi_zb *zb);
++extern unsigned char zb_AppRegisterRequest(struct bmi_zb *zb, unsigned char len,
++                      unsigned char *app_info);
++extern unsigned char zb_PermitJoiningRequest(struct bmi_zb *zb,
++                        unsigned char *dest, unsigned char timeout);
++extern void zb_AllowBind(struct bmi_zb *zb, unsigned char timeout);
++extern void zb_BindRequest(struct bmi_zb *zb, unsigned char create,
++                        unsigned char *bind_info);
++extern int zb_SendDataRequest(struct bmi_zb *zb, unsigned char *buf,
++                        unsigned char len);
++extern void zb_FindDeviceRequest(struct bmi_zb *zb, unsigned char *searchKey);
++extern unsigned char zb_AFRegisterRequest(struct bmi_zb *zb, unsigned char len, unsigned char *app_info);
++extern int zb_sysRFpowerAmp(struct bmi_zb *zb, unsigned char pa, unsigned char power);
++
++extern void zaccel_cmd_proc(struct bmi_zb *zb,unsigned char *buf);
++extern int zb_rx(struct net_device *dev, unsigned char *buf,
++                        unsigned char len, unsigned short type);
++extern int z_sock_init(void);
++extern int zdev_setopt(struct net_device *dev,int cmd, int len,
++                      unsigned char *buf);
++extern int zdev_getopt(struct net_device *dev, int cmd, int *len,
++                        unsigned char *buf);
++
++extern void zb_net_setup(struct net_device *dev);
++extern void zaccel_getdev(struct bmi_zb *zb);
++
++extern void z_sock_exit(void);
++extern int z_sock_init(void);
++extern void zb_create_sysfs(struct net_device *net);
++extern void zb_remove_sysfs(struct net_device *net);
++extern int init_zaccel(struct bmi_zb *zb);
++extern void remove_zaccel(struct bmi_zb *zb);
++extern int zb_ReadSRDY(struct bmi_zb *zb, int print);
++extern void zb_ReadMRDY(struct bmi_zb *zb);
++extern void zaccel_spi_poll(struct bmi_zb *zb);
++extern int zb_SysTestLoopback(struct bmi_zb *zb);
++extern void  zb_sysVersion(struct bmi_zb *zb);
++extern int zaccel_get_chanlist(struct bmi_zb *zb);
++
++
++
++#endif // BMI_ZB_H
+--- /dev/null
++++ git/drivers/bmi/pims/zb/bmi_znetdev.c
+@@ -0,0 +1,977 @@
++/*
++ * bmi_znetdev.c
++ *
++ * This file contains the zaccel network device driver codes.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/if.h>
++#include <linux/sysfs.h>
++#include <linux/bmi/bmi_zb.h>
++#include "bmi_zigbee.h"
++#include "bmi_zaccel.h"
++
++static int zb_open(struct net_device *dev)
++{
++      struct bmi_zb *zb;
++      struct net_zb *priv;
++      struct zaccel_device *zdev;
++
++      printk(KERN_DEBUG "bmi_znetdev: zb_open\n");
++      priv = netdev_priv(dev);
++      zb = priv->zb;
++      zdev = &zb->z_info.device;
++
++      priv->net_open = 1;
++      netif_start_queue(dev);
++      return 0;
++}
++
++static int zb_close(struct net_device *dev)
++{
++      struct net_zb *priv;
++
++      printk(KERN_DEBUG "bmi_znetdev: zb_close\n");
++      priv = netdev_priv(dev);
++
++      priv->net_open = 0;
++      netif_stop_queue(dev);
++
++      return 0;
++}
++
++static int zb_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
++{
++      unsigned char len_chk;
++      unsigned char offset;
++      struct net_zb *priv;
++      struct bmi_zb *zb;
++      struct zaccel_info *z_info;
++
++      unsigned char *zapp;
++      unsigned char buf[32];
++      unsigned short len;
++      unsigned char type;
++      unsigned char reason = 0;
++      unsigned char *user_pt;
++      unsigned char flag;
++      unsigned char state;
++      int i;
++      int rc = 0;
++
++      priv = netdev_priv(dev);
++      zb = priv->zb;
++      z_info = &zb->z_info;
++
++      switch(cmd)
++      {
++              case SIOCSRESET:
++                      if(copy_from_user(buf, ifr->ifr_data, (2*sizeof(char))))
++                      {
++                              printk(KERN_ERR "BMI_ZB_ANY_REQ cannot get commands\n");
++                              return -EFAULT;
++                      }
++
++                      switch(buf[0])
++                      {
++                              case Z_HW_RESET:
++                                      if(dev->flags & IFF_UP)
++                                      {
++                                              /* set flag to remember that IF is up previously */
++                                              flag = IFF_UP;
++                                              dev->flags &= ~IFF_UP;
++                                              netif_stop_queue(dev);
++                                      }
++
++                                      zb_Reset(zb,ZB_RESET);
++                                      udelay(10);
++                                      zb_Reset(zb,ZB_RELEASE);
++
++                                      break;
++
++                              case Z_SW_RESET:
++                                      if(dev->flags & IFF_UP)
++                                      {
++                                              flag = IFF_UP;
++                                              dev->flags &= ~IFF_UP;
++                                              netif_stop_queue(dev);
++                                      }
++
++                                      zb_SoftReset(zb);
++                                      break;
++
++                              case Z_DONT_RESET:
++                                      return 0;
++
++                              default:
++                                      printk(KERN_WARNING "zb ioctl reset - unknow reset type %d\n",buf[1]);
++                                      return -EINVAL;
++                      }
++
++                      /*
++                       * If reset the device, wait for it to come back and
++                       * start Z-stack.
++                       */
++                      rc = wait_event_interruptible_timeout(z_info->wait_queue,
++                           ((z_info->msg_flag & RESET_IND_BIT) != 0),Z_RESET_TIMEOUT);
++
++                      if(rc == 0)
++                      {
++                              /* timeout and no indication received */
++                              reason = 1;
++                              printk(KERN_ERR "zb: wait for reset IND timeout\n");
++                              rc = -EAGAIN;
++                      }
++                      else
++                      {
++
++#ifdef VE_OUT
++                              if(flag & IFF_UP)
++                              {
++                                      netif_start_queue(dev);
++                                      dev->flags |= IFF_UP;
++                              }
++#endif
++
++                              rc = 0;
++                      }
++
++                      if(rc == -EAGAIN)
++                      {
++                              /* copy extra code to the user space */
++                              if(copy_to_user(ifr->ifr_data,(void *)&reason,1))
++                              {
++                                      return -EFAULT;
++                              }
++                      }
++
++                      break;
++
++              case SIOCGDEVICEINFO:
++
++                      if(copy_from_user(buf, ifr->ifr_data, 1))
++                      {
++                              printk(KERN_ERR "SIOCGDEVICEINFO cannot get parameter\n");
++                              return -EFAULT;
++                      }
++
++                      len = zb_GetDeviceInfo(zb,buf[0],buf);
++
++                      if(copy_to_user(ifr->ifr_data, buf, len))
++                      {
++                              return -EFAULT;
++                      }
++
++                      rc = (int)len;
++                      break;
++
++              case SIOCSAPPREGISTER:
++                      if(copy_from_user(buf, ifr->ifr_data, sizeof(char)))
++                      {
++                              printk(KERN_ERR "SIOCSAPPREGISTER cannot get parameter\n");
++                              return -EFAULT;
++                      }
++
++                      len = (unsigned short)buf[0];
++
++                      /*
++                       * Input Format:
++                       *      1-byte  message length
++                       *      x-bytes  message (see below comment for msg format.
++                       */
++
++                      zapp = kmalloc(len,GFP_KERNEL);
++                      if(zapp == NULL)
++                      {
++                              printk(KERN_WARNING "zb_ioctl no buf for cmd 0x%x\n",cmd);
++                              return -ENOMEM;
++                      }
++
++                      user_pt = (unsigned char *)ifr->ifr_data;
++                      if(copy_from_user((void *)zapp, &user_pt[1], (unsigned long)len))
++                      {
++                              kfree(zapp);
++                              return -EFAULT;
++                      }
++
++                      /*
++                       * verify the length of the data.
++                       * Format of message is (number in parenthesis = num of bytes)
++                       *
++                       *  zapp[offset]        content
++                       *      0                   appEndpoint(1)
++                       *      1                   appProfileID(2)
++                       *      3                   deviceId(2)
++                       *      5                   deviceVersion(1)
++                       *      6                   unused(1)
++                       *      7                   inputCommandNum(1)
++                       *        [8]                  [inputCommand(2),inputCommand(2), ...]
++                       *      8 + (inputNum * 2)  outputCommandNum(1)
++                       *                             [outputCommand(2),outputCommand(2), ...]
++                       */
++
++                      /* 8 bytes between appEndpoint to inputCommandNum */
++                      len_chk = 8;
++
++                      /*
++                       * Get the offset to outputCommandNum byte
++                       * and add the number of inputCommand bytes and outputCommandNum
++                       * byte to the len_chk.
++                       */
++                      offset = (zapp[7] << 1) + 8;
++                      len_chk += (zapp[7] << 1) + 1;
++
++                      /* Add the number of output command bytes */
++                      len_chk += (zapp[offset] << 1);
++
++                      if(len_chk != len)
++                      {
++                              /*
++                               * The len of the input declared is less than the
++                               * number of data required.
++                               */
++                              kfree(zapp);
++                              printk(KERN_WARNING "SIOCSAPPREGISTER: inconsistence len %d %d\n",len_chk,len);
++                              return -EINVAL;
++                      }
++
++                      buf[0] = zb_AppRegisterRequest(zb,len,zapp);
++
++                      if(buf[0] != 0)
++                      {
++                              rc = -1;
++                      }
++
++                      if(copy_to_user(ifr->ifr_data,buf,1))
++                      {
++                              printk(KERN_WARNING "SIOCAPP result dropped\n");
++                      }
++
++                      kfree(zapp);
++
++                      break;
++
++              case SIOCSALLOWBIND:
++                      if(copy_from_user(buf, ifr->ifr_data, sizeof(char)))
++                      {
++                              printk(KERN_ERR "SIOCSALLOWBIND cannot get parameter\n");
++                              return -EFAULT;
++                      }
++
++                      /*
++                       * Input format:\
++                       *     1-bytes timeout
++                       */
++
++                      zb_AllowBind(zb,buf[0]);
++
++                      break;
++
++              case SIOCSSTARTREQ:
++                      zb_StartRequest(zb);
++                      rc = wait_event_interruptible_timeout(z_info->wait_queue,
++                      ((z_info->msg_flag & START_CNF_BIT) != 0),Z_CNF_TIMEOUT);
++
++                      if(rc == 0)
++                      {
++                              /* timeout - We didn't receive START_CNF message nor
++                               * ZDO_STATE_CHANGE_IND.   This can happens if the
++                               * end-device or router does not find a network.
++                               * Check if the device state had changed from DEV_HOLD
++                               * to anything else.   If it does, the stack has started.
++                               */
++                              zb_GetDeviceInfo(zb,ZB_DEVICE_STATE,(unsigned char *)&state);
++                              if((state != DEV_HOLD) || (state != DEV_INIT))
++                              {
++                                      printk(KERN_DEBUG "stack starts, state %d\n",state);
++                                      rc = 0;
++                              }
++                              else
++                              {
++                                      rc = -1;
++                                      printk(KERN_DEBUG "Stack fails to start\n");
++                              }
++                      }
++                      else
++                      {
++                              printk(KERN_DEBUG "rcv ZB_START_CONFIRM\n");
++                              rc = 0;
++                      }
++
++                      break;
++
++              case SIOCSPERMITJOINING:
++                      if(copy_from_user(buf, ifr->ifr_data, 3))
++                      {
++                              printk(KERN_ERR "SIOCSPERMITJOINING: read error\n");
++                              return -EFAULT;
++                      }
++
++                      /*
++                       * Input format:
++                       *     2-bytes 16-bit device address
++                       *     1-bytes timeout
++                       */
++#ifdef VE_OUT
++                      printk(KERN_DEBUG "permitjoining address 0x%x timeout 0x%x\n",*(unsigned short *)buf,buf[2]);
++#endif
++
++                      buf[0] = zb_PermitJoiningRequest(zb,&buf[0],buf[2]);
++
++                      if(buf[0] != 0)
++                      {
++                              rc = -1;
++                      }
++
++                      if(copy_to_user(ifr->ifr_data,buf,1))
++                      {
++                              printk(KERN_WARNING "SIOCSPERMIT result dropped\n");
++                      }
++
++                      break;
++
++              case SIOCSBIND:
++                      if(copy_from_user(buf, ifr->ifr_data, 12))
++                      {
++                              printk(KERN_ERR "SIOCSBIND cannot get parameter\n");
++                              return -EFAULT;
++                      }
++
++                      if((buf[0] != Z_BIND_CREATE) && (buf[0] != Z_BIND_REMOVE))
++                      {
++                              return -EINVAL;
++                      }
++
++                      zb_BindRequest(zb,buf[0],&buf[1]);
++
++                      break;
++
++              case SIOCSFINDDEVICE:
++                      if(copy_from_user(buf, ifr->ifr_data, 8))
++                      {
++                              printk(KERN_ERR "SIOCSFINDDEVICE cannot get parameter\n");
++                              return -EFAULT;
++                      }
++                      zb_FindDeviceRequest(zb,buf);
++                      break;
++
++              case SIOCSAFREGISTER:
++                      if(copy_from_user(buf, ifr->ifr_data, sizeof(char)))
++                      {
++                              printk(KERN_ERR "SIOCSAPPREGISTER cannot get parameter\n");
++                              return -EFAULT;
++                      }
++
++                      len = (unsigned short)buf[0];
++
++                      /*
++                       * Input Format:
++                       *      1-byte  message length
++                       *      x-bytes  message (see below comment for msg format.
++                       */
++
++                      zapp = kmalloc(len,GFP_KERNEL);
++                      if(zapp == NULL)
++                      {
++                              printk(KERN_WARNING "zb_ioctl no buf for cmd 0x%x\n",cmd);
++                              return -ENOMEM;
++                      }
++
++                      user_pt = (unsigned char *)ifr->ifr_data;
++                      if(copy_from_user((void *)zapp, &user_pt[1], (unsigned long)len))
++                      {
++                              kfree(zapp);
++                              return -EFAULT;
++                      }
++
++                      buf[0] = zb_AFRegisterRequest(zb,len,zapp);
++                      if(buf[0] != 0)
++                      {
++                              rc = -1;
++                      }
++
++                      if(copy_to_user(ifr->ifr_data,buf,1))
++                      {
++                              printk(KERN_WARNING "SIOCAPP result dropped\n");
++                      }
++
++                      kfree(zapp);
++                      break;
++
++              case SIOCSPOWERAMP:
++                      if(copy_from_user(buf, ifr->ifr_data, 2))
++                      {
++                              printk(KERN_ERR "SIOCSPOWERAMP cannot get parameter\n");
++                              return -EFAULT;
++                      }
++
++                      rc = zb_sysRFpowerAmp(zb,buf[0],buf[1]);
++                      break;
++
++              case SIOCSZCOMMAND:
++
++                      /*
++                       * This command passes any Z-Accel command to the device and
++                       * returns the reply back to the user.
++                       * Message format:
++                       *              1-byte  length of data field
++                       *              2-bytes command
++                       *              0-128 bytes data
++                       */
++                      if(copy_from_user(buf, ifr->ifr_data, 1))
++                      {
++                              printk(KERN_ERR "SIOCSZCOMMAND cannot get parameter\n");
++                              return -EFAULT;
++                      }
++
++                      user_pt = (unsigned char *)ifr->ifr_data;
++                      len = (unsigned short)buf[0] + 3;
++
++                      if(len  > ZCMD_BUF)
++                      {
++                              printk(KERN_WARNING "SIOCSZCOMMAND message is too long\n");
++                              return -EINVAL;
++                      }
++
++                      zapp = kmalloc(ZCMD_BUF,GFP_KERNEL);
++                      if(zapp == NULL)
++                      {
++                              printk(KERN_WARNING "SIOCSZCOMMAND no buf for the cmd\n");
++                              return -ENOMEM;
++                      }
++
++                      if(copy_from_user(zapp, ifr->ifr_data, len))
++                      {
++                              printk(KERN_ERR "SIOCSZCOMMAND cannot get parameter\n");
++                              return -EFAULT;
++                      }
++                      type = zapp[1] & SPI_CMD_TYPE_MASK;
++
++#define VE_DEBUG
++#ifdef VE_DEBUGx
++                      printk("len %d: ",len);
++                      for(i = 0; i < len; i++)
++                      {
++                              printk("%x ",zapp[i]);
++                      }
++                      printk("\n");
++#endif
++
++                      zaccel_spi_req(zb,zapp,len);
++
++                      /*
++                       * read the length of the data, if it's SREQ command.
++                       */
++
++                      if(type != SPI_CMD_AREQ)
++                      {
++                              len = zapp[0];
++
++                              if(copy_to_user(ifr->ifr_data,zapp,(len + 3)))
++                              {
++                                      return -EFAULT;
++                              }
++                      }
++                      rc = 0;
++
++                      break;
++
++              default:
++                      printk("zb_ioctl default cmd\n");
++                      rc = -EINVAL;
++                      break;
++
++      }
++
++      return rc;
++}
++
++/*
++ * zb_rx passes data from Z-Accel to the user via socket
++ */
++int zb_rx(struct net_device *dev, unsigned char *buf, unsigned char len, unsigned short type)
++{
++      struct sk_buff *skb;
++      struct net_zb *priv;
++
++      if(!dev)
++              return -EINVAL;
++
++
++      priv = netdev_priv(dev);
++
++      if(priv->socket[type] == Z_NO_SOCK)
++      {
++              return -EINVAL;
++      }
++
++      /*
++       * Check if the device is bound to a socket.
++       * If not, drop the message.
++       */
++
++      dev->last_rx = jiffies;
++
++      skb = dev_alloc_skb(len);
++      if(skb)
++      {
++              memcpy(skb_put(skb,len),buf,len);
++
++              /*
++               * Set the device to zigbee.
++               * Set protocol number to zero, so the kernel will not
++               * pass it through the protocol stack.
++               */
++
++              skb->dev = dev;
++              skb->protocol = type;
++
++              if(type == Z_PACKET_SOCK)
++              {
++                      /*
++                       * Increment packet count and notify kernel of
++                       * the new packet.
++                       */
++                      priv->stats.rx_packets++;
++              }
++
++              netif_rx(skb);
++      }
++      else
++      {
++              if(type == Z_PACKET_SOCK)
++                      priv->stats.rx_dropped++;
++      }
++
++      return 0;
++}
++
++int zb_tx(struct sk_buff *skb, struct net_device *dev)
++{
++      struct bmi_zb *zb;
++      struct net_zb *priv;
++      struct zaccel_xmt_msg *msg;
++      unsigned char *buf;
++
++      priv = netdev_priv(dev);
++      zb = priv->zb;
++
++      if(skb->len > XMT_MSG_SIZE)
++      {
++              dev_kfree_skb(skb);
++              return -EINVAL;
++      }
++
++      msg = (struct zaccel_xmt_msg *)kmalloc(sizeof(struct zaccel_xmt_msg), GFP_KERNEL);
++      buf = msg->buf;
++
++      memcpy(buf,skb->data,skb->len);
++
++      msg->len = skb->len;
++
++      /*
++       * zb_tx is called by dev_queue_xmit, which requires atomic
++       * operation.  We cannot call zb_SendDataRequest directly here
++       * to schedule SPI transfer to the Z-Accel because
++       * it causes "BUG: scheduling while atomic exception."
++       * We put the data in a message queue and
++       * schedule a work queue to call zb_SendDataRequest later.
++       */
++
++      list_add_tail(&msg->list, &zb->z_info.xmt_list);
++      schedule_work(&zb->xmt_work);
++
++      /* Move this statistic to a real packet transmission location later */
++      priv->stats.tx_packets++;
++
++      dev->trans_start = jiffies;
++
++      /* Free sku buffer */
++      dev_kfree_skb(skb);
++
++      return 0;
++}
++
++struct net_device_stats *zb_stats(struct net_device *dev)
++{
++      struct net_zb *priv = netdev_priv(dev);
++
++      return &priv->stats;
++}
++
++void zb_net_setup(struct net_device *dev)
++{
++      struct net_zb *priv;
++
++      priv = netdev_priv(dev);
++
++      priv->dev = dev;
++      priv->socket[Z_PACKET_SOCK] = Z_NO_SOCK;
++      priv->socket[Z_CONTROL_SOCK] = Z_NO_SOCK;
++
++      dev->open = zb_open;
++      dev->stop = zb_close;
++      dev->hard_start_xmit = zb_tx;
++      dev->tx_queue_len = 32;
++      dev->get_stats = zb_stats;
++      dev->do_ioctl = zb_ioctl;
++      dev->flags = 0;
++}
++
++int zdev_setopt(struct net_device *dev,int cmd, int len, unsigned char *buf)
++{
++      struct net_zb *priv = netdev_priv(dev);
++      struct bmi_zb *zb;
++      int rc;
++
++      zb = priv->zb;
++      rc = (int)zb_WriteConfiguration(zb,(unsigned char)cmd,(unsigned char)len,buf);
++      return rc;
++}
++
++int zdev_getopt(struct net_device *dev, int cmd, int *len, unsigned char *buf)
++{
++      struct net_zb *priv = netdev_priv(dev);
++      struct bmi_zb *zb;
++
++      zb = priv->zb;
++
++      *len = (int)zb_ReadConfiguration(zb,(unsigned char)cmd,buf);
++      if(*len != 0)
++      {
++              return 0;
++      }
++      else
++      {
++              return -EFAULT;
++      }
++
++}
++
++static ssize_t show_device(struct device *dev, struct device_attribute *attr, char *buf)
++{
++      struct net_device *net = to_net_dev(dev);
++      struct net_zb *priv = netdev_priv(net);
++      struct bmi_zb *zb = priv->zb;
++      int size = 0;
++      int rc;
++      unsigned char rbuf[8];
++
++      rc = zb_ReadConfiguration(zb,ZCD_NV_LOGICAL_TYPE,rbuf);
++      if(rc <= 0)
++      {
++                      size = sprintf(buf,"Bad read.  Try again\n");
++      }
++      switch(rbuf[Z_CONFIG_OFFSET])
++      {
++              case ZB_COORDINATOR:
++                      size = sprintf(buf,"coordinator\n");
++                      break;
++
++              case ZB_ROUTER:
++                      size = sprintf(buf,"router\n");
++                      break;
++
++              case ZB_ENDDEVICE:
++                      size = sprintf(buf,"end-device\n");
++                      break;
++
++              default:
++                      size = sprintf(buf,"device-error\n");
++                      break;
++      }
++      return size;
++}
++
++static ssize_t store_device(struct device *dev, struct device_attribute *attr, char *buf, size_t count)
++{
++      struct net_device *net = to_net_dev(dev);
++      struct net_zb *priv = netdev_priv(net);
++      struct bmi_zb *zb = priv->zb;
++      int size;
++      unsigned char device;
++
++      if(memcmp(buf, "coordinator",(count-1)) == 0)
++      {
++              printk(KERN_DEBUG "zb: config to coordinator\n");
++              device = ZB_COORDINATOR;
++      }
++      else if(memcmp(buf, "router",(count-1)) == 0)
++      {
++              printk(KERN_DEBUG "zb: config to router\n");
++              device = ZB_ROUTER;
++      }
++      else if(memcmp(buf, "end-device",(count-1)) == 0)
++      {
++              printk(KERN_DEBUG "zb: config to end-device\n");
++              device = ZB_ENDDEVICE;
++      }
++      else
++      {
++              printk(KERN_DEBUG "zb: invalid config\n");
++              size = sprintf(buf,"Invalid device.  Try again\n");
++              return count;
++      }
++
++      if(zb_WriteConfiguration(zb,ZCD_NV_LOGICAL_TYPE,1,&device) != 0)
++      {
++              size = sprintf(buf,"Bad write.  Try again\n");
++      }
++
++      return count;
++}
++
++static ssize_t store_chanlist(struct device *dev, struct device_attribute *attr, char *buf, size_t count)
++{
++      struct net_device *net = to_net_dev(dev);
++      struct net_zb *priv = netdev_priv(net);
++      struct bmi_zb *zb = priv->zb;
++      int size;
++      unsigned long chanlist;
++      unsigned char rbuf[4];
++
++      chanlist = simple_strtol(buf,NULL,16);
++      rbuf[0] = (unsigned char)(chanlist) & 0xFF;
++      rbuf[1] = (unsigned char)(chanlist >> 8) & 0xFF;
++      rbuf[2] = (unsigned char)(chanlist >> 16) & 0xFF;
++      rbuf[3] = (unsigned char)(chanlist >> 24) & 0xFF;
++
++      if(zb_WriteConfiguration(zb,ZCD_NV_CHANLIST,4,(unsigned char *)rbuf) != 0)
++      {
++              size = sprintf(buf,"Bad write.  Try again\n");
++      }
++
++      return count;
++}
++
++static ssize_t show_chanlist(struct device *dev, struct device_attribute *attr, char *buf)
++{
++      struct net_device *net = to_net_dev(dev);
++      struct net_zb *priv = netdev_priv(net);
++      struct bmi_zb *zb = priv->zb;
++      unsigned char rbuf[10];
++      int size = 0;
++      int rc;
++
++      rc = zb_ReadConfiguration(zb,ZCD_NV_CHANLIST,rbuf);
++      if(rc < 0)
++      {
++              size = sprintf(buf,"bad read.   Try again\n");
++      }
++      else
++      {
++              size  = sprintf(buf,"%0x ",rbuf[Z_CONFIG_OFFSET+3]);
++              size += sprintf((buf+size),"%0x ",rbuf[Z_CONFIG_OFFSET+2]);
++              size += sprintf((buf+size),"%0x ",rbuf[Z_CONFIG_OFFSET+1]);
++              size += sprintf((buf+size),"%0x\n",rbuf[Z_CONFIG_OFFSET]);
++      }
++      return size;
++}
++
++static ssize_t store_initop(struct device *dev, struct device_attribute *attr, char *buf, size_t count)
++{
++      struct net_device *net = to_net_dev(dev);
++      struct net_zb *priv = netdev_priv(net);
++      struct bmi_zb *zb = priv->zb;
++      unsigned char option;
++      int size;
++
++      option = (unsigned char)simple_strtol(buf,NULL,16);
++      option &= ZCD_STARTOPT_MASK;
++
++      if(zb_WriteConfiguration(zb,ZCD_NV_STARTUP_OPTION,1,(unsigned char *)&option) != 0)
++      {
++              size = sprintf(buf,"Bad write.   Try again\n");
++      }
++
++      return count;
++}
++
++static ssize_t show_initop(struct device *dev, struct device_attribute *attr, char *buf)
++{
++      struct net_device *net = to_net_dev(dev);
++      struct net_zb *priv = netdev_priv(net);
++      struct bmi_zb *zb = priv->zb;
++      unsigned char rbuf[10];
++      int size = 0;
++      int rc;
++
++      rc = zb_ReadConfiguration(zb,ZCD_NV_STARTUP_OPTION,(unsigned char *)&rbuf);
++      if(rc < 0)
++      {
++              size = sprintf(buf,"bad read.   Try again\n");
++      }
++      else
++      {
++              size = sprintf(buf,"%0x\n",rbuf[Z_CONFIG_OFFSET]);
++      }
++
++      return size;
++}
++
++static ssize_t store_panid(struct device *dev, struct device_attribute *attr, char *buf, size_t count)
++{
++      struct net_device *net = to_net_dev(dev);
++      struct net_zb *priv = netdev_priv(net);
++      struct bmi_zb *zb = priv->zb;
++      unsigned short panid;
++      unsigned char rbuf[2];
++      int size;
++
++      panid = (unsigned short)simple_strtol(buf,NULL,16);
++      rbuf[0] = (unsigned char)(panid) & 0xFF;
++      rbuf[1] = (unsigned char)(panid >> 8) & 0xFF;
++
++      if(zb_WriteConfiguration(zb,ZCD_NV_PANID,2,(unsigned char *)rbuf) != 0)
++      {
++              size = sprintf(buf,"Bad write read.   Try again\n");
++      }
++
++      printk(KERN_DEBUG "zb: config panid 0x%x\n",panid);
++      return count;
++}
++
++static ssize_t show_panid(struct device *dev, struct device_attribute *attr, char *buf)
++{
++      struct net_device *net = to_net_dev(dev);
++      struct net_zb *priv = netdev_priv(net);
++      struct bmi_zb *zb = priv->zb;
++      unsigned char rbuf[10];
++      int size = 0;
++      int rc;
++
++      rc = zb_ReadConfiguration(zb,ZCD_NV_PANID,(unsigned char *)&rbuf);
++      if(rc < 0)
++      {
++              size = sprintf(buf,"bad read.   Try again\n");
++      }
++      else
++      {
++              size = sprintf(buf,"%0x ",rbuf[Z_CONFIG_OFFSET+1]);
++              size += sprintf((buf+size),"%0x\n",rbuf[Z_CONFIG_OFFSET]);
++      }
++      return size;
++}
++
++static ssize_t show_zbinfo(struct device *dev, struct device_attribute *attr, char *buf)
++{
++      struct net_device *net = to_net_dev(dev);
++      struct net_zb *priv = netdev_priv(net);
++      struct bmi_zb *zb = priv->zb;
++      struct zaccel_device *z_dev = &zb->z_info.device;
++      int size = 0;
++
++      zaccel_getdev(zb);
++
++      switch(z_dev->state)
++      {
++              case DEV_HOLD:
++                      size = sprintf(buf,"DEV_HOLD\n");
++                      break;
++
++              case DEV_INIT:
++                      size = sprintf(buf,"DEV_INIT\n");
++                      break;
++
++              case DEV_NWK_DISC:
++                      size = sprintf(buf,"DEV_NWK_DISC\n");
++                      break;
++
++              case DEV_NWK_JOINING:
++                      size = sprintf(buf,"DEV_NWK_JOINING\n");
++                      break;
++
++              case DEV_NWK_REJOIN:
++                      size = sprintf(buf,"DEV_NWK_REJOIN\n");
++                      break;
++
++              case DEV_END_DEVICE_UNAUTH:
++                      size = sprintf(buf,"DEV_END_DEVICE_UNAUTH\n");
++                      break;
++
++              case DEV_END_DEVICE:
++                      size = sprintf(buf,"DEV_END_DEVICE\n");
++                      break;
++
++              case DEV_ROUTER:
++                      size = sprintf(buf,"DEV_ROUTER\n");
++                      break;
++
++              case DEV_COORD_STARTING:
++                      size = sprintf(buf,"DEV_COORD_STARTING\n");
++                      break;
++
++              case DEV_ZB_COORD:
++                      size = sprintf(buf,"DEV_ZB_COORD\n");
++                      break;
++
++              case DEV_NWK_ORPHAN:
++                      size = sprintf(buf,"DEV_NWK_ORHAN\n");
++                      break;
++
++              default:
++                      size = sprintf(buf,"UNKNOWN STATE %d\n",z_dev->state);
++                      break;
++      }
++
++      size += sprintf((buf+size),"device IEEE address:  %x:%x:%x:%x:%x:%x:%x:%x\n",
++               z_dev->device_ieee[7],z_dev->device_ieee[6],z_dev->device_ieee[5],
++               z_dev->device_ieee[4],z_dev->device_ieee[3],z_dev->device_ieee[2],
++               z_dev->device_ieee[1],z_dev->device_ieee[0]);
++      size += sprintf((buf+size),"device short address: 0x%x %x\n",
++               z_dev->device_short[1],z_dev->device_short[0]);
++      size += sprintf((buf+size),"parent short address: 0x%x %x\n",
++               z_dev->parent_short[1],z_dev->parent_short[0]);
++      size += sprintf((buf+size),"parent IEEE address:  %x:%x:%x:%x:%x:%x:%x:%x\n",
++               z_dev->parent_ieee[7],z_dev->parent_ieee[6],z_dev->parent_ieee[5],
++               z_dev->parent_ieee[4],z_dev->parent_ieee[3],z_dev->parent_ieee[2],
++               z_dev->parent_ieee[1],z_dev->parent_ieee[0]);
++      size += sprintf((buf+size),"channel:              0x%0x\n",z_dev->channel);
++      size += sprintf((buf+size),"PAN ID:               0x%0x %0x\n",
++               z_dev->panid[1],z_dev->panid[0]);
++      size += sprintf((buf+size),"extended PAN ID:      %x:%x:%x:%x:%x:%x:%x:%x\n",
++               z_dev->ext_panid[7],z_dev->ext_panid[6],z_dev->ext_panid[5],
++               z_dev->ext_panid[4],z_dev->ext_panid[3],z_dev->ext_panid[2],
++               z_dev->ext_panid[1],z_dev->ext_panid[0]);
++      return size;
++}
++
++
++DEVICE_ATTR(device, (S_IRUGO | S_IWUSR), show_device, store_device);
++DEVICE_ATTR(panid, (S_IRUGO | S_IWUSR), show_panid, store_panid);
++DEVICE_ATTR(chanlist, (S_IRUGO | S_IWUSR), show_chanlist, store_chanlist);
++DEVICE_ATTR(initop, (S_IRUGO | S_IWUSR), show_initop, store_initop);
++DEVICE_ATTR(zbinfo, S_IRUGO, show_zbinfo, NULL);
++
++void zb_create_sysfs(struct net_device *net)
++{
++      struct device *dev = &(net->dev);
++
++      if(device_create_file(dev,&dev_attr_device) < 0)
++              printk(KERN_WARNING "zb: failed to create device attribute\n");
++
++      if(device_create_file(dev,&dev_attr_panid) < 0)
++              printk(KERN_WARNING "zb: failed to create panid attribute\n");
++
++      if(device_create_file(dev,&dev_attr_chanlist) < 0)
++              printk(KERN_WARNING "zb: failed to create chanlist attribute\n");
++
++      if(device_create_file(dev,&dev_attr_initop) < 0)
++              printk(KERN_WARNING "zb: failed to create initop attribute\n");
++
++      if(device_create_file(dev,&dev_attr_zbinfo) < 0)
++              printk(KERN_WARNING "zb: failed to create zinfo attribute\n");
++}
++
++void zb_remove_sysfs(struct net_device *net)
++{
++      struct device *dev = &(net->dev);
++
++      device_remove_file(dev,&dev_attr_device);
++      device_remove_file(dev,&dev_attr_panid);
++      device_remove_file(dev,&dev_attr_chanlist);
++      device_remove_file(dev,&dev_attr_initop);
++      device_remove_file(dev,&dev_attr_zbinfo);
++}
++
+--- /dev/null
++++ git/drivers/bmi/pims/zb/bmi_zprotocol.c
+@@ -0,0 +1,619 @@
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/net.h>
++#include <linux/inet.h>
++#include <linux/skbuff.h>
++#include <net/sock.h>
++
++#include <net/inet_common.h>
++#include <linux/bmi/bmi_zb.h>
++#include "bmi_zigbee.h"
++
++HLIST_HEAD(zaccel_list);
++DEFINE_RWLOCK(zaccel_list_lock);
++
++struct zaccel_sock {
++      struct sock   sk;
++      struct        packet_type zpacket_type;
++      spinlock_t    bind_lock;
++      struct sockaddr_zb sockaddr;
++      struct net_device *dev;
++
++};
++
++static inline struct zaccel_sock *z_sk(struct sock *sk)
++{
++      return (struct zaccel_sock *)sk;
++}
++
++static void zaccel_sock_destruct(struct sock *sk)
++{
++      if(!sock_flag(sk,SOCK_DEAD)) {
++              printk("Attempt to release alive packet socket: %p\n",sk);
++              return;
++      }
++
++      sk_refcnt_debug_dec(sk);
++}
++
++static int z_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer)
++{
++      struct sock *sk;
++      struct zaccel_sock *zsock;
++      struct sockaddr_zb *zaddr;
++
++      printk("z_packet_getname\n");
++      zaddr = (struct sockaddr_zb *)uaddr;
++
++      sk = sock->sk;
++      zsock = z_sk(sk);
++
++      if(zsock->dev == 0)
++      {
++
++              printk(KERN_WARNING "sock not bound \n");
++              /* the socket is not bound */
++              return -ENODATA;
++      }
++
++      zaddr->z_family = AF_ZACCEL;
++      zaddr->z_ifindex = zsock->sockaddr.z_ifindex;
++      zaddr->z_protocol = zsock->sockaddr.z_protocol;
++      memcpy(&zaddr->z_name, &zsock->sockaddr.z_name, 15);
++
++      *uaddr_len = sizeof(struct sockaddr_zb);
++      return 0;
++
++}
++
++static struct proto zaccel_proto = {
++      .name     = "Z_PACKET",
++      .owner    =  THIS_MODULE,
++      .obj_size = sizeof(struct zaccel_sock),
++};
++
++static int z_control_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
++{
++      struct sock *sk;
++
++      sk = pt->af_packet_priv;
++
++      /* put packet in receive queue */
++      if(sock_queue_rcv_skb(sk,skb) == 0)
++      {
++              return 0;
++      }
++
++      printk(KERN_WARNING "z_control_rcv drop\n");
++      kfree_skb(skb);
++      return 0;
++
++}
++
++static int z_packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
++{
++      struct sock *sk;
++
++      sk = pt->af_packet_priv;
++
++      /*
++       * put the packet in the receive queue.
++       */
++
++      if(sock_queue_rcv_skb(sk,skb) == 0)
++      {
++              return 0;
++      }
++
++      printk(KERN_WARNING "z_packet_rcv drop\n");
++      kfree_skb(skb);
++      return 0;
++}
++
++/*
++ *    Pull a packet from our recieve queue and hand it to the user.
++ */
++
++static int z_recvmsg(struct kiocb *iocb, struct socket *sock,
++                     struct msghdr *msg, size_t len, int flags)
++{
++      struct sock *sk;
++      struct sk_buff *skb;
++      int skb_len;
++      struct net_device *dev;
++      struct zaccel_sock *zsock;
++      int ifindex;
++      int err;
++
++      err = -EINVAL;
++      if(flags & ~(MSG_PEEK|MSG_DONTWAIT|MSG_TRUNC|MSG_CMSG_COMPAT))
++      {
++              goto out;
++      }
++
++      sk = sock->sk;
++
++      zsock = z_sk(sk);
++
++      ifindex = zsock->sockaddr.z_ifindex;
++
++      dev = dev_get_by_index(&init_net, ifindex);
++      if(dev == NULL)
++      {
++              printk(KERN_WARNING "bmi_zprotocol: dev not found\n");
++              return (-ENXIO);
++      }
++
++      if(!(dev->flags & IFF_UP))
++      {
++              printk("interface not up %d\n",(-ENETDOWN));
++              dev_put(dev);
++              return -ENETDOWN;
++      }
++
++      dev_put(dev);
++
++      /*
++       * Get a datagram skbuff
++       */
++      skb = skb_recv_datagram(sk,flags,flags&MSG_DONTWAIT,&err);
++
++      if(skb == NULL)
++      {
++              goto out;
++      }
++
++      /*
++       * If the input buffer is smaller than the message, truncate
++       * it.  The user loses any data beyond it.
++       */
++      skb_len = skb->len;
++      if(skb_len > len)
++      {
++              skb_len = len;
++              msg->msg_flags |= MSG_TRUNC;
++      }
++
++      err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, skb_len);
++      if(err)
++              goto out_free;
++
++      sock_recv_timestamp(msg, sk, skb);
++
++      /* err returns data  length if the copy is successful */
++      err = skb_len;
++
++out_free:
++      skb_free_datagram(sk,skb);
++
++out:
++      return err;
++}
++
++static int z_sendmsg(struct kiocb *iocb, struct socket *sock,
++                     struct msghdr *msg, size_t len)
++{
++      struct sock *sk = sock->sk;
++      struct sk_buff *skb;
++      struct net_device *dev;
++      struct zaccel_sock *zsock;
++      int ifindex;
++      int err;
++
++      zsock = z_sk(sk);
++
++      if(zsock->zpacket_type.type == Z_CONTROL_SOCK)
++      {
++              return -EPROTOTYPE;
++      }
++
++      ifindex = zsock->sockaddr.z_ifindex;
++
++      dev = dev_get_by_index(&init_net, ifindex);
++      if(dev == NULL)
++      {
++              printk(KERN_WARNING "bmi_zprotocol: dev not found\n");
++              dev_put(dev);
++              return (-ENXIO);
++      }
++
++      if(!(dev->flags & IFF_UP))
++      {
++              printk(KERN_WARNING "bmi_zprotocol: interface not up %d\n",(-ENETDOWN));
++              dev_put(dev);
++              return -ENETDOWN;
++      }
++
++      if(len > 92)
++      {
++              /* message is too long */
++              dev_put(dev);
++              return -EINVAL;
++      }
++
++      skb = sock_alloc_send_skb(sk, len, msg->msg_flags & MSG_DONTWAIT, &err);
++      if(skb == NULL)
++      {
++              dev_put(dev);
++              printk(KERN_WARNING "bmi_zprotocol: sock_allock_send_skb failed %d\n",err);
++              return -ENOMEM;
++      }
++
++      err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len);
++      if(err)
++      {
++              kfree_skb(skb);
++              dev_put(dev);
++              return -EFAULT;
++      }
++
++      skb->dev = dev;
++
++      /*
++       * dev_queue_xmit sends the packet directly to the driver.
++       */
++
++      err = dev_queue_xmit(skb);
++      if (err > 0)
++      {
++              kfree_skb(skb);
++              printk(KERN_WARNING "bmi_zprotocol: dev_queue_xmit failed %d\n",err);
++              dev_put(dev);
++              return(-ENETDOWN);
++      }
++
++      dev_put(dev);
++      return(len);
++}
++
++
++static int z_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
++{
++      struct sock *sk = sock->sk;
++      char name[15];
++      struct net_device *dev;
++      struct sockaddr_zb *z_addr;
++      struct zaccel_sock *zsock;
++      struct net_zb *priv;
++      unsigned char type;
++      int rc;
++
++      z_addr = (struct sockaddr_zb *)uaddr;
++
++      /* Get the name of the device */
++      strlcpy(name,z_addr->z_name,sizeof(name));
++
++      rc = (int)strlen(name);
++      if(rc > 3)
++      {
++              return -EINVAL;
++      }
++
++      if(memcmp(name,"zb",2))
++      {
++              printk(KERN_WARNING "bmi_zprotocol: invalid name %s\n",name);
++              return -EINVAL;
++      }
++
++      if((name[2] < 0x31) && (name[2] > 0x34))
++      {
++              printk(KERN_WARNING "bmi_zprotocol: invalid slot %c\n",name[2]);
++              return -EINVAL;
++      }
++
++
++      zsock = z_sk(sk);
++      type =  zsock->zpacket_type.type;
++
++      /* search for the network interface by name */
++      dev = dev_get_by_name(&init_net, name);
++
++      /*
++       * check if the device has been bound to this socket type.
++       * If it has, return with error.
++       */
++
++      priv = netdev_priv(dev);
++      if(priv->socket[type] != Z_NO_SOCK)
++      {
++              dev_put(dev);
++              return -EISCONN;
++      }
++
++      if(dev)
++      {
++              lock_sock(sk);
++              spin_lock(&zsock->bind_lock);
++
++              if(zsock->dev && (zsock->dev != dev))
++              {
++                      /* This socket was bound.   Unbind it first.  */
++                      printk(KERN_INFO "unbound to previous device\n");
++                      __sock_put(sk);
++
++                      priv = netdev_priv(zsock->dev);
++                      priv->socket[type] = Z_NO_SOCK;
++
++                      zsock->dev = NULL;
++                      spin_unlock(&zsock->bind_lock);
++                      dev_remove_pack(&zsock->zpacket_type);
++                      spin_lock(&zsock->bind_lock);
++              }
++
++              zsock->zpacket_type.dev = dev;
++              zsock->zpacket_type.af_packet_priv = sk;
++
++              /* socket-dev information used by sendmsg */
++              zsock->sockaddr.z_ifindex = dev->ifindex;
++              strlcpy(zsock->sockaddr.z_name,name,15);
++
++              zsock->dev = dev;
++
++              /* Add a packet handler to the networking stack. */
++              dev_add_pack(&zsock->zpacket_type);
++              /* increment sk_refcnt */
++              sock_hold(sk);
++
++              /* Tell the device that it is bound to a socket */
++              priv = netdev_priv(dev);
++              priv->socket[type] = 1;
++
++              spin_unlock(&zsock->bind_lock);
++              release_sock(sk);
++              dev_put(dev);
++              return 0;
++      }
++      else
++      {
++              printk(KERN_WARNING "zb: dev %s not found\n",name);
++              return -ENODEV;
++      }
++}
++
++static int z_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
++{
++      int rc;
++
++      switch(cmd)
++      {
++              case SIOCGIFFLAGS:
++              case SIOCGIFNAME:
++              case SIOCGIFMTU:
++              case SIOCGIFINDEX:
++              case SIOCETHTOOL:
++              case SIOCSIFNAME:
++              case SIOCSIFFLAGS:
++              case SIOCSIFMTU:
++                      /*
++                       * return -ENOIOCTLCMD to sock_ioctl
++                       * sock_ioctl will call dev_ioctl to take care of these cmds.
++                       */
++                      rc = -ENOIOCTLCMD;
++                      break;
++              default:
++                      rc = 0;
++                      break;
++      }
++
++      return rc;
++}
++
++static int z_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen)
++{
++      struct sock *sk = sock->sk;
++      struct zaccel_sock *zsock;
++      unsigned char buf[135];  /* 128 data + 6 fixed header + 1 just in case */
++
++      zsock = z_sk(sk);
++
++      if(!zsock->dev)
++      {
++              printk(KERN_WARNING "bmi_zprotocol: device not attached\n");
++              /*
++               * socket has no device attached
++               */
++              return -ENOTCONN;
++      }
++
++      if(level != SOL_ZACCEL)
++      {
++              return -ENOPROTOOPT;
++      }
++
++      if(optlen > 135)
++      {
++              return -EINVAL;
++      }
++
++      if(copy_from_user(buf,optval,optlen))
++      {
++              return -EFAULT;
++      }
++
++      if(zdev_setopt(zsock->dev,optname,optlen,buf))
++      {
++              return -EINVAL;
++      }
++
++      return 0;
++}
++
++static int z_getsockopt(struct socket *sock, int level, int optname,
++                        char __user *optval, int __user *optlen)
++
++{
++      struct sock *sk = sock->sk;
++      struct zaccel_sock *zsock;
++      unsigned char buf[135];  /* 128 data + 6 fixed header + 1 just in case */
++      int len;
++      int rc;
++
++      zsock = z_sk(sk);
++
++      if(!zsock->dev)
++      {
++              /* socket has no device attached */
++              return -ENOTCONN;
++      }
++
++      if(level != SOL_ZACCEL)
++              return -ENOPROTOOPT;
++
++      rc = zdev_getopt(zsock->dev,optname,&len,buf);
++
++      if(!rc)
++      {
++              if(put_user(len, optlen))
++                      return -EFAULT;
++              /* Include 3 header bytes to the message */
++              if(copy_to_user(optval, buf, (len+3)))
++                      return -EFAULT;
++      }
++
++      return rc;
++
++}
++
++static int z_release(struct socket *sock)
++{
++      struct sock *sk;
++      struct zaccel_sock *zsock;
++      struct net_zb *priv;
++
++      sk = sock->sk;
++
++      if(!sk)
++              return 0;
++
++      zsock = z_sk(sk);
++
++      write_lock_bh(&zaccel_list_lock);
++      sk_del_node_init(sk);
++      write_unlock_bh(&zaccel_list_lock);
++
++      if(zsock->dev)
++      {
++              priv = netdev_priv(zsock->dev);
++              priv->socket[zsock->zpacket_type.type] = Z_NO_SOCK;
++
++              /* remove protocol handler */
++              dev_remove_pack(&zsock->zpacket_type);
++              __sock_put(sk);
++      }
++
++      /* detach socket from process context */
++      sock_orphan(sk);
++      sock->sk = NULL;
++
++      /* Purge queues */
++      skb_queue_purge(&sk->sk_receive_queue);
++
++      sk_refcnt_debug_release(sk);
++
++      sock_put(sk);
++      return 0;
++}
++
++static const struct proto_ops z_protocol_ops = {
++      .family =      PF_ZACCEL,
++      .owner  =      THIS_MODULE,
++      .release =     z_release,
++      .bind =        z_bind,
++      .connect =     sock_no_connect,
++      .socketpair =  sock_no_socketpair,
++      .accept =      sock_no_accept,
++      .getname =     z_getname,
++      .poll =        sock_no_poll,
++      .ioctl =       z_ioctl,
++      .listen =      sock_no_listen,
++      .shutdown =    sock_no_shutdown,
++      .setsockopt =  z_setsockopt,
++      .getsockopt =  z_getsockopt,
++      .sendmsg =     z_sendmsg,
++      .recvmsg =     z_recvmsg,
++      .mmap =        sock_no_mmap,
++      .sendpage =    sock_no_sendpage,
++};
++
++int z_protocol_create(struct net *net, struct socket *sock, int protocol)
++{
++      struct sock *sk;
++      struct zaccel_sock *zsock;
++
++      if (net != &init_net)
++      {
++              return -EAFNOSUPPORT;
++      }
++
++      sock->state = SS_UNCONNECTED;
++      if(sock->type != SOCK_RAW)
++      {
++              return -ESOCKTNOSUPPORT;
++      }
++
++      sock->ops = &z_protocol_ops;
++
++      sk = sk_alloc(net, AF_ZACCEL, GFP_KERNEL, &zaccel_proto);
++      if(sk == NULL)
++      {
++              return -ENOMEM;
++      }
++
++      sock_init_data(sock, sk);
++      sk->sk_protocol = protocol;
++      sk->sk_family = PF_ZACCEL;
++      sk->sk_destruct = zaccel_sock_destruct;
++      sk_refcnt_debug_inc(sk);
++
++      zsock = z_sk(sk);
++
++      spin_lock_init(&zsock->bind_lock);
++
++      if(protocol == Z_CONTROL_SOCK)
++      {
++              zsock->zpacket_type.func = z_control_rcv;
++              zsock->zpacket_type.type = Z_CONTROL_SOCK;
++              sk->sk_protocol = Z_CONTROL_SOCK;
++      }
++      else
++      {
++              zsock->zpacket_type.func = z_packet_rcv;
++              zsock->zpacket_type.type = Z_PACKET_SOCK;
++              sk->sk_protocol = Z_PACKET_SOCK;
++      }
++      zsock->zpacket_type.af_packet_priv = sk;
++      zsock->zpacket_type.dev = NULL;
++
++      zsock->dev = NULL;
++
++      /* Add a socket to the bound sockets list */
++      write_lock_bh(&zaccel_list_lock);
++      sk_add_node(sk,&zaccel_list);
++      write_unlock_bh(&zaccel_list_lock);
++
++      return 0;
++
++}
++
++static struct net_proto_family zaccel_family_ops = {
++      .family  = PF_ZACCEL,
++      .create  = z_protocol_create,
++      .owner   = THIS_MODULE,
++};
++
++void z_sock_exit(void)
++{
++      sock_unregister(PF_ZACCEL);
++}
++
++int z_sock_init(void)
++{
++      int res;
++
++      res = sock_register(&zaccel_family_ops);
++      if(res) {
++              printk(KERN_WARNING "Failed to register PF_ZACCEL\n");
++      }
++
++      return res;
++}
+--- /dev/null
++++ git/drivers/bmi/slots/Kconfig
+@@ -0,0 +1,21 @@
++#
++# BMI Slot Drivers
++#
++
++menu "BMI Hardware Slot support"
++
++config BUG_SLOT
++      tristate "Buglabs BUGBase BMI Slots"
++      default 'n'
++      depends on BMI && MACH_BUG
++      help
++        If you say yes to this option, support will be included for the Buglabs BUGBase BMI Slot/Module Ports.
++
++config OMAP_SLOT
++              tristate "TI BeagBoard BMI Slots"
++      default 'n'
++      depends on BMI
++      help
++        If you say yes to this option, support will be included for the BeagleBoard Slot.
++
++endmenu
+--- /dev/null
++++ git/drivers/bmi/slots/Makefile
+@@ -0,0 +1,6 @@
++#
++# Makefile for BMI Slot drivers
++#
++
++obj-$(CONFIG_BUG_SLOT) += slots_bug.o
++obj-$(CONFIG_OMAP_SLOT) += slots_beagle.o
+--- /dev/null
++++ git/drivers/bmi/slots/slots_beagle.c
+@@ -0,0 +1,267 @@
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/i2c.h>
++#include <linux/spi/spi.h>
++#include <linux/gpio.h>
++#include <linux/irq.h>
++#include <linux/bmi.h>
++
++#include <mach/board.h>
++
++#define BMI_GPIO_0 139
++#define BMI_GPIO_1 158
++#define BMI_GPIO_2 137
++#define BMI_GPIO_3 136
++
++static int bl_present(struct bmi_slot* slot)
++{
++  unsigned gpio = irq_to_gpio(slot->present_irq);
++  if (gpio_get_value(gpio))
++    return 0;
++  else
++    return 1;
++}
++
++static void bl_power_on(struct bmi_slot* slot)
++{
++  return;
++}
++
++static void bl_power_off(struct bmi_slot* slot)
++{
++  return;
++}
++
++static void bl_gpio_config(struct bmi_slot* slot, int mask)   /*Configure gpios as inputs/ouputs*/
++{
++  int i;
++
++  unsigned char *gpio = (unsigned char*) slot->slot_data;
++
++  for (i = 0; i < 4 ; i++)
++    {
++      if ((mask >> i) & 0x1)
++      gpio_direction_output(gpio[i], 0);
++      else
++      gpio_direction_input(gpio[i]);
++    }
++  return;
++}
++
++static int bl_gpio_get(struct bmi_slot* slot)
++{
++  int i;
++  unsigned char *gpio = (unsigned char*) slot->slot_data;
++  unsigned char ret = 0;
++
++  for (i = 3; i > -1 ; i--)
++    {
++      ret = (ret << 1) | gpio_get_value(gpio[i]);
++    }
++
++  return ret;
++}
++
++static void bl_gpio_set(struct bmi_slot* slot, int mask)
++{
++  int i;
++  unsigned char *gpio = (unsigned char*) slot->slot_data;
++
++  for (i = 0; i < 4 ; i++)
++    {
++      if ((mask >> i) & 0x1)
++      gpio_set_value(gpio[i], 1);
++      else
++      gpio_set_value(gpio[i], 0);
++    }
++  return;
++}
++
++static void bl_uart_enable(struct bmi_slot* slot)
++{
++  return;
++}
++
++static void bl_uart_disable(struct bmi_slot* slot)
++{
++  return;
++}
++
++static void bl_spi_enable(struct bmi_slot* slot)
++{
++  return;
++}
++
++static void bl_spi_disable(struct bmi_slot* slot)
++{
++  return;
++}
++
++static void bl_audio_enable(struct bmi_slot* slot)
++{
++  return;
++}
++
++static void bl_audio_disable(struct bmi_slot* slot)
++{
++  return;
++}
++
++static void bl_batt_enable(struct bmi_slot* slot)
++{
++  return;
++}
++
++static void bl_batt_disable(struct bmi_slot* slot)
++{
++  return;
++}
++
++
++struct slot_actions bl_actions = {
++  .present = bl_present,
++  .power_on = bl_power_on,
++  .power_off = bl_power_off,
++  .gpio_config = bl_gpio_config,
++  .gpio_get = bl_gpio_get,
++  .gpio_set = bl_gpio_set,
++  .uart_enable = bl_uart_enable,
++  .uart_disable = bl_uart_disable,
++  .spi_enable = bl_spi_enable,
++  .spi_disable = bl_spi_disable,
++  .audio_enable = bl_audio_enable,
++  .audio_disable = bl_audio_disable,
++  .batt_enable = bl_batt_enable,
++  .batt_disable = bl_batt_disable,
++};
++
++static int omapbmi_slot_suspend(struct platform_device *pdev, pm_message_t state)
++{
++  return 0;
++}
++
++static int omapbmi_slot_resume(struct platform_device *pdev)
++{
++  return 0;
++}
++
++static int omapbmi_slot_probe(struct platform_device *pdev)
++{
++  struct bmi_slot *slot;
++  struct resource *irq_pres, *irq_stat;
++  // struct omap_bmi_platform_data *bmi_plat_data = pdev->dev.platform_data;
++  int ret = 0;
++  unsigned char* gpio;
++
++  printk(KERN_INFO "Buglabs BeagleBUG Slots Driver...\n");
++  irq_pres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
++  if (!irq_pres) {
++    dev_err(&pdev->dev, "No presence irq resource...\n");
++    return -ENODEV;
++  }
++  irq_stat = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
++  if (!irq_stat) {
++    dev_err(&pdev->dev, "No status irq resource...\n");
++    return -ENODEV;
++  }
++
++  slot = kzalloc(sizeof(struct bmi_slot), GFP_KERNEL);
++  if (!slot) {
++    ret = -ENOMEM;
++    goto err_release;
++  }
++
++  ret = gpio_request(irq_stat->start, "BMI SINT");
++  if (ret) {
++    printk(KERN_ERR "slots_beagle: GPIO %d request failed...\n",irq_stat->start);
++    goto err_release;
++  }
++  ret = gpio_request(irq_pres->start, "BMI PINT");
++  if (ret) {
++    printk(KERN_ERR "slots_beagle: GPIO %d request failed...\n",irq_pres->start);
++    goto err_release;
++  }
++
++  ret = gpio_direction_input(irq_pres->start);
++
++  gpio = kmalloc(4, GFP_KERNEL);
++  gpio_request(139,"BMI_0");
++  gpio_request(158,"BMI_1");
++  gpio_request(137,"BMI_2");
++  gpio_request(136,"BMI_3");
++
++  gpio[0] = 139;
++  gpio[1] = 158;
++  gpio[2] = 137;
++  gpio[3] = 136;
++
++  slot->slot_data = (void*)gpio;
++  slot->present_irq = gpio_to_irq(irq_pres->start);
++  slot->status_irq = gpio_to_irq(irq_stat->start);
++  slot->owner = THIS_MODULE;
++  slot->name = "omap_bug_slot";
++  slot->slotdev.parent = &pdev->dev;
++  slot->adap = i2c_get_adapter(3);
++  slot->actions = &bl_actions;
++  slot->spi_bus_num = 3;
++  slot->spi_cs = 0;
++
++
++  ret = bmi_add_slot(slot);
++  if (ret) {
++    printk(KERN_ERR "slots_beagle: Trouble instantiating slot...%d\n", ret);
++    goto err_release;
++  }
++  return 0;
++ err_release:
++  kfree(slot->slot_data);
++  kfree(slot);
++  return ret;
++}
++
++static int omapbmi_slot_remove(struct platform_device *pdev)
++{
++      struct bmi_slot *slot = platform_get_drvdata(pdev);
++      //int id = pdev->id;
++
++      bmi_del_slot(slot);
++      platform_set_drvdata(pdev, NULL);
++      kfree(slot->slot_data);
++      kfree(slot);
++      return 0;
++}
++
++
++static struct platform_driver omapbmi_slot_driver = {
++  .driver = {
++    .name = "omap_bmi_slot",
++    .owner = THIS_MODULE,
++  },
++  .probe = omapbmi_slot_probe,
++  .remove = omapbmi_slot_remove,
++  .suspend = omapbmi_slot_suspend,
++  .resume = omapbmi_slot_resume,
++};
++
++static int __init omap_bmi_slot_init(void)
++{
++  /* Register the device driver structure. */
++  return platform_driver_register(&omapbmi_slot_driver);
++}
++
++/*!
++ * This function is used to cleanup all resources before the driver exits.
++ */
++static void __exit omap_bmi_slot_exit(void)
++{
++  platform_driver_unregister(&omapbmi_slot_driver);
++}
++
++module_init(omap_bmi_slot_init);
++module_exit(omap_bmi_slot_exit);
++
++MODULE_AUTHOR("Matt Isaacs");
++MODULE_DESCRIPTION("OMAP BMI Slot Driver");
++MODULE_LICENSE("GPL");
+--- /dev/null
++++ git/drivers/bmi/slots/slots_bug.c
+@@ -0,0 +1,231 @@
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/i2c.h>
++#include <linux/bmi.h>
++
++#include <mach/mx31bug_cpld.h>
++//#include <mach/mx31bug_gpio.h>
++#include <mach/board-bugbase.h>
++
++static int bl_present(struct bmi_slot* slot)
++{
++  int status;
++
++  status = cpld_read_module_present_status(slot->slotnum);
++  if (status & 0x04)
++    return 1;
++  else
++    return 0;
++}
++
++static void bl_power_on(struct bmi_slot* slot)
++{
++  //gpio_power_on_slot (slot->slotnum);
++  return;
++}
++
++static void bl_power_off(struct bmi_slot* slot)
++{
++  //gpio_power_off_slot (slot->slotnum);
++  return;
++}
++
++static void bl_gpio_config(struct bmi_slot* slot, int mask)   /*Configure gpios as inputs/ouputs*/
++{
++  int i;
++  for (i = 0; i < 4; i++) {
++    cpld_set_module_gpio_dir(slot->slotnum, i, (mask & 0x1));
++    mask = mask >> 1;
++  }
++  return;
++}
++
++static int bl_gpio_get(struct bmi_slot* slot)
++{
++  return cpld_read_gpio_data_reg(slot->slotnum);
++}
++
++static void bl_gpio_set(struct bmi_slot* slot, int mask)
++{
++  int i;
++  for (i = 0; i < 4; i++) {
++    cpld_set_module_gpio_data(slot->slotnum, i, (mask & 0x1));
++    mask = mask >> 1;
++  }
++  return;
++}
++
++static void bl_uart_enable(struct bmi_slot* slot)
++{
++  cpld_uart_active(slot->slotnum);
++  return;
++}
++
++static void bl_uart_disable(struct bmi_slot* slot)
++{
++  cpld_uart_inactive(slot->slotnum);
++  return;
++}
++
++static void bl_spi_enable(struct bmi_slot* slot)
++{
++  //REVIST:
++  cpld_spi_active(0);
++  return;
++}
++
++static void bl_spi_disable(struct bmi_slot* slot)
++{
++  //REVIST:
++  cpld_spi_inactive(0);
++  return;
++}
++
++static void bl_audio_enable(struct bmi_slot* slot)
++{
++  cpld_activate_audio_ports();
++  return;
++}
++
++static void bl_audio_disable(struct bmi_slot* slot)
++{
++  cpld_inactivate_audio_ports();
++  return;
++}
++
++static void bl_batt_enable(struct bmi_slot* slot)
++{
++  cpld_set_module_battery_enable(slot->slotnum);
++  return;
++}
++
++static void bl_batt_disable(struct bmi_slot* slot)
++{
++  cpld_set_module_battery_disable(slot->slotnum);
++  return;
++}
++
++/*
++static int mxcbmi_probe(struct platform_device *pdev);
++static int mxcbmi_slot_remove(struct platform_device *pdev);
++static int mxcbmi_suspend(struct platform_device *pdev, pm_message_t state);
++static int mxcbmi_resume(struct platform_device *pdev);
++*/
++
++struct slot_actions bl_actions = {
++  .present = bl_present,
++  .power_on = bl_power_on,
++  .power_off = bl_power_off,
++  .gpio_config = bl_gpio_config,
++  .gpio_get = bl_gpio_get,
++  .gpio_set = bl_gpio_set,
++  .uart_enable = bl_uart_enable,
++  .uart_disable = bl_uart_disable,
++  .spi_enable = bl_spi_enable,
++  .spi_disable = bl_spi_disable,
++  .audio_enable = bl_audio_enable,
++  .audio_disable = bl_audio_disable,
++  .batt_enable = bl_batt_enable,
++  .batt_disable = bl_batt_disable,
++};
++
++static int mxcbmi_slot_suspend(struct platform_device *pdev, pm_message_t state)
++{
++  return 0;
++}
++
++static int mxcbmi_slot_resume(struct platform_device *pdev)
++{
++  return 0;
++}
++
++static int mxcbmi_slot_probe(struct platform_device *pdev)
++{
++  struct bmi_slot *slot;
++  struct resource *res, *irq_pres, *irq_stat;
++  struct mxc_bmi_platform_data *bmi_plat_data = pdev->dev.platform_data;
++  int ret = 0;
++
++  printk(KERN_INFO "Buglabs BUGBase Slots Driver...\n");
++  irq_pres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
++  if (!irq_pres) {
++    dev_err(&pdev->dev, "No presence irq resource...\n");
++    return -ENODEV;
++  }
++  irq_stat = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
++  if (!irq_stat) {
++    dev_err(&pdev->dev, "No status irq resource...\n");
++    return -ENODEV;
++  }
++
++  slot = kzalloc(sizeof(struct bmi_slot), GFP_KERNEL);
++  if (!slot) {
++    ret = -ENOMEM;
++    goto err_release;
++  }
++
++
++  slot->present_irq = irq_pres->start;
++  slot->status_irq = irq_stat->start;
++  slot->owner = THIS_MODULE;
++  slot->name = "mxc_bug_slot";
++  slot->slotdev.parent = &pdev->dev;
++  slot->adap = i2c_get_adapter(2 + pdev->id);
++  slot->actions = &bl_actions;
++  slot->spi_bus_num = 1;
++  slot->spi_cs = pdev->id;
++  ret = bmi_add_slot(slot);
++  if (ret) {
++    printk(KERN_ERR "slots_bug: Trouble instantiating slot...%d\n", ret);
++    goto err_release;
++  }
++  ret = 0;
++ err_release:
++  return ret;
++}
++
++static int mxcbmi_slot_remove(struct platform_device *pdev)
++{
++      struct bmi_slot *slot = platform_get_drvdata(pdev);
++      //int id = pdev->id;
++
++      bmi_del_slot(slot);
++      platform_set_drvdata(pdev, NULL);
++      kfree(slot);
++      return 0;
++}
++
++
++static struct platform_driver mxcbmi_slot_driver = {
++  .driver = {
++    .name = "mxc_bmi_slot",
++    .owner = THIS_MODULE,
++  },
++  .probe = mxcbmi_slot_probe,
++  .remove = mxcbmi_slot_remove,
++  .suspend = mxcbmi_slot_suspend,
++  .resume = mxcbmi_slot_resume,
++};
++
++static int __init mxc_bmi_slot_init(void)
++{
++  /* Register the device driver structure. */
++  return platform_driver_register(&mxcbmi_slot_driver);
++}
++
++/*!
++ * This function is used to cleanup all resources before the driver exits.
++ */
++static void __exit mxc_bmi_slot_exit(void)
++{
++  platform_driver_unregister(&mxcbmi_slot_driver);
++}
++
++module_init(mxc_bmi_slot_init);
++module_exit(mxc_bmi_slot_exit);
++
++MODULE_AUTHOR("Matt Isaacs");
++MODULE_DESCRIPTION("MXC BMI Slot Driver");
++MODULE_LICENSE("GPL");
+--- /dev/null
++++ git/include/linux/bmi-ids.h
+@@ -0,0 +1,30 @@
++/*
++ *    BMI Vendor and Product IDs
++ *
++ *    Please keep sorted.
++ */
++
++/* BMI vendors */
++
++#define       BMI_VENDOR_ILLEGAL_0                    0x0
++#define BMI_VENDOR_BUG_LABS                   0x1
++#define       BMI_VENDOR_ILLEGAL_F                    0xFFFF
++
++
++/* BMI products */
++
++#define       BMI_PRODUCT_ILLEGAL_0                   0x0000
++#define BMI_PRODUCT_GPS_J32                   0x0001
++#define BMI_PRODUCT_MOT_ACCEL                 0x0002
++#define BMI_PRODUCT_LCD_SHARP_320X240         0x0003
++#define BMI_PRODUCT_CAMERA_VS6624             0x0004
++#define BMI_PRODUCT_CAMERA_OV2640             0x0005
++#define BMI_PRODUCT_FACTORY_TEST              0x0006
++#define BMI_PRODUCT_VON_HIPPEL                        0x0007
++#define BMI_PRODUCT_WIFI                      0x0008
++#define BMI_PRODUCT_ZIGBEE                    0x0009
++#define BMI_PRODUCT_AUDIO                     0x000A
++#define BMI_PRODUCT_GSM                               0x000B
++#define BMI_PRODUCT_PROJECTOR                 0x000C
++#define       BMI_PRODUCT_ILLEGAL_F                   0xFFFF
++
+--- /dev/null
++++ git/include/linux/bmi.h
+@@ -0,0 +1,142 @@
++#ifndef __LINUX_BMI_H
++#define __LINUX_BMI_H
++
++#include <linux/bmi-ids.h>
++#include <linux/bmi/bmi-eeprom.h>
++#include <linux/bmi/bmi-slot.h>
++#include <linux/device.h>
++#include <linux/i2c.h>
++#include <linux/mod_devicetable.h>
++#include <linux/mutex.h>
++#include <linux/spi/spi.h>
++
++
++/* BMI bus device table constants */
++#define BMI_ANY                                       0x0
++
++#define RED_LED               8
++#define GREEN_LED     4
++#define GPIO_1                2
++#define GPIO_0                1
++
++struct bmi_slot;
++
++struct slot_actions {
++  int (*present)(struct bmi_slot*);
++  void (*power_on)(struct bmi_slot*);
++  void (*power_off)(struct bmi_slot*);
++  void (*gpio_config)(struct bmi_slot*, int mask);    /*Configure gpios as inputs/ouputs*/
++  int (*gpio_get)(struct bmi_slot*);
++  void (*gpio_set)(struct bmi_slot*, int mask);
++  void (*uart_enable)(struct bmi_slot*);
++  void (*uart_disable)(struct bmi_slot*);
++  void (*spi_enable)(struct bmi_slot*);
++  void (*spi_disable)(struct bmi_slot*);
++  void (*audio_enable)(struct bmi_slot*);
++  void (*audio_disable)(struct bmi_slot*);
++  void (*batt_enable)(struct bmi_slot*);
++  void (*batt_disable)(struct bmi_slot*);
++};
++
++struct bmi_slot {
++  int slotnum;
++  char* name;
++  struct bmi_device *bdev;
++  struct module *owner;
++  struct device slotdev;
++  struct kref kref;
++  struct mutex pres_mutex;
++  struct list_head  event_list;
++  unsigned int event_bits[1];
++
++  int present;
++  struct i2c_adapter *adap;
++  struct i2c_client  *eeprom;
++
++
++  //  struct spi_device spi;
++  int spi_bus_num;
++  int spi_cs;
++
++  int present_irq;
++  int status_irq;
++  struct delayed_work  work;
++  struct slot_actions* actions;
++
++  void* slot_data;
++
++};
++
++
++/* BMI Device */
++
++struct bmi_device {
++  int devnum;
++
++  struct device dev;
++
++  struct mutex        lock;
++
++
++  int    present_irq_cnt;
++  int    state;       /* Make this an enum */
++
++  struct bmi_slot *slot;
++
++  struct bmi_eeprom_data ident;
++  unsigned short vendor;
++  unsigned short product;
++  unsigned short revision;
++
++  struct bmi_driver *driver;  /* which driver has allocated this device */
++
++};
++
++#define to_bmi_device(n) container_of(n, struct bmi_device, dev);
++#define work_to_slot(w)  container_of(container_of(w,         \
++                                                   struct delayed_work, \
++                                                   work),             \
++                                      struct bmi_slot,                \
++                                      work)
++
++
++static inline void *bmi_device_get_drvdata (struct bmi_device *bdev)
++{
++      return dev_get_drvdata (&bdev->dev);
++}
++
++static inline void bmi_device_set_drvdata (struct bmi_device *bdev, void *data)
++{
++      dev_set_drvdata(&bdev->dev, data);
++}
++
++
++/* BMI Driver  */
++
++struct bmi_driver {
++
++      char *name;
++      struct bmi_device_id *id_table;
++      struct device_driver  driver;
++      int  (*probe)(struct bmi_device *dev);
++      void (*remove)(struct bmi_device *dev);
++};
++
++extern struct bus_type bmi_bus_type;
++
++#define       to_bmi_driver(drv) container_of(drv,struct bmi_driver, driver)
++
++int __must_check __bmi_register_driver(struct bmi_driver *, struct module *);
++static inline int __must_check bmi_register_driver(struct bmi_driver *driver)
++{
++        return __bmi_register_driver(driver, THIS_MODULE);
++}
++
++void bmi_unregister_driver(struct bmi_driver *drv);
++
++struct bmi_device *bmi_alloc_dev(struct bmi_slot *slot);
++struct class* bmi_get_class (void);
++int bmi_add_slot(struct bmi_slot *slot);
++int bmi_del_slot(struct bmi_slot *slot);
++
++#endif
+--- /dev/null
++++ git/include/linux/bmi/at24c02.h
+@@ -0,0 +1,26 @@
++#include <linux/semaphore.h>
++#include <linux/i2c.h>
++
++/*--------------------------------
++ *
++ *   AT24C02 I2C Eeprom Device
++ *
++ *--------------------------------
++ */
++
++
++struct at24c02 {
++
++      unsigned char addr;
++      struct i2c_adapter *adap;
++};
++
++void at24c02_init (struct at24c02 *dev, u8 addr, struct i2c_adapter *adap);
++
++int at24c02_read_byte  ( struct at24c02 *dev, u8 offset, u8 *data);
++int at24c02_write_byte ( struct at24c02 *dev, u8 offset, u8 data);
++int at24c02_read ( struct at24c02 *dev, u8 offset, u8 *data, int size);
++int at24c02_write_page ( struct at24c02 *dev, u8 offset, u8 *data, int size);
++
++
++
+--- /dev/null
++++ git/include/linux/bmi/bmi-bus.h
+@@ -0,0 +1,21 @@
++#ifndef BMI_BUS_H
++#define BMI_BUS_H
++
++#include <linux/bmi.h>
++
++#define BMI_MAX_SLOTS 1
++
++struct bmi_bus {
++
++      struct bmi_device slot[BMI_MAX_SLOTS];
++};
++
++
++
++extern struct bus_type bmi_bus_type;
++
++struct bmi_device* bmi_get_bmi_device (int slot_num);
++
++
++#endif        /* BMI_BUS_H */
++
+--- /dev/null
++++ git/include/linux/bmi/bmi-control.h
+@@ -0,0 +1,303 @@
++/*
++ * Copyright 2007 EnCADIS Design, Inc. All Rights Reserved.
++ * Copyright 2007 Bug-Labs, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++#ifndef _BMI_CONTROL_H
++#define _BMI_CONTROL_H
++
++#define BMI_M1                (0x0)
++#define BMI_M2                (0x1)
++#define BMI_M3                (0x2)
++#define BMI_M4                (0x3)
++#define BMI_GPIO_IN   (0x0)
++#define BMI_GPIO_OUT  (0x1)
++#define BMI_GPIO_ON   (0x1)
++#define BMI_GPIO_OFF  (0x0)
++
++/*!
++ * This function configures the UART function for the IOMUX pins.
++ *
++ * @param  port         a UART port number (0-5)
++ * @param  no_irda      configure UART port for IRDA
++ */
++void bmi_gpio_uart_active(int port, int no_irda);
++
++/*!
++ * This function configures the UART function in the BMI.
++ *
++ * @param  port         a UART port number (0-5)
++ */
++void bmi_uart_active(int port);
++
++/*!
++ * This function configures the UART function in the BMI.
++ *
++ * @param  port         a UART port number (0-5)
++ */
++void bmi_uart_inactive(int port);
++
++/*!
++ * Setup GPIO for a CSPI device to be active
++ *
++ * @param  cspi_mod         an CSPI device
++ */
++void bmi_gpio_spi_active(int cspi_mod);
++
++/*!
++ * Setup BMI for a CSPI device to be active
++ *
++ * @param  cspi_mod         an CSPI device
++ */
++void bmi_spi_active(int cspi_mod);
++
++/*!
++ * Setup BMI for a CSPI device to be inactive
++ *
++ * @param  cspi_mod         an CSPI device
++ */
++void bmi_spi_inactive(int cspi_mod);
++
++/*!
++ * Setup GPIO for an I2C device to be active
++ *
++ * @param  i2c_num         an I2C device
++ */
++void bmi_gpio_i2c_active(int i2c_num);
++
++/*!
++ * Setup BMI for an I2C device to be active
++ */
++void bmi_i2c_active(void);
++
++/*!
++ * Setup BMI for an I2C device to be inactive
++ */
++void bmi_i2c_inactive(void);
++
++/*
++ * Setup GPIO for an I2S device to be active
++ */
++void bmi_gpio_activate_audio_ports(void);
++
++/*!
++ * Setup CPLD for an I2S device to be active
++ */
++void bmi_activate_audio_ports(void);
++
++/*!
++ * Setup CPLD for an I2S device to be inactive
++ */
++void bmi_inactivate_audio_ports(void);
++
++/*!
++ * Setup GPIO for the plug-in module LCD interface to be active
++ */
++void bmi_gpio_lcd_active(void);
++
++/*!
++ * Setup BMI for plug-in module LCD to be active
++ *
++ * @param  port LCD serializer (0 or 1)
++ * @param  pllc LCD serializer PLL divisor (0-7)
++ * @param  mode LCD serializer bus mode (LCD_MODE_I80 or LCD_MODE_M68)
++ *
++ */
++void bmi_lcd_active(int port, int pllc, int mode);
++
++/*!
++ * Setup BMI for plug-in module LCD chip select to be active
++ *
++ * @param  cs LCD chip select (LCD_MxCS x = 1,2,3,4)
++ *
++ */
++void bmi_lcd_cs_active(int cs);
++
++/*!
++ * Setup BMI for plug-in module LCD to be inactive
++ *
++ * @param  port LCD serializer (0 or 1)
++ *
++ */
++void bmi_lcd_inactive(int port);
++
++/*!
++ * Setup BMI for plug-in module LCD chip select to be inactive
++ *
++ * @param  cs LCD chip select (LCD_MxCS x = 1,2,3,4)
++ *
++ */
++void bmi_lcd_cs_inactive(int cs);
++
++/*!
++ * Setup pins for SLCD to be active
++ *
++ */
++void bmi_slcd_gpio_config(void);
++
++/*!
++ * Setup GPIO for sensor to be active
++ *
++ */
++void bmi_gpio_sensor_active(void);
++
++/*!
++ * Setup BMI for sensor to be active
++ *
++ * @param rclk_r pixclk edge (CAM_CLK_RISE or CAM_CLK_FALL)
++ */
++void bmi_sensor_active(int rclk_r);
++
++/*!
++ * Setup BMI for sensor to be inactive
++ */
++void bmi_sensor_inactive(void);
++
++/*!
++ * read BMI for sensor lock status
++ *
++ *    @return camera serializer lock status (1 == locked)
++ */
++int bmi_sensor_lock_status(void);
++
++/*
++ * USB Host 2 GPIO config
++ *
++ * @return 0
++ */
++int bmi_gpio_usbh2_active(void);
++
++/*
++ * USB Host 2 BMI config
++ *
++ * @param mtt - number of MTT's enabled in hub (USB_HUB_1_MTT or USB_HUB_4_MTT)
++ */
++void bmi_usbh2_active(int mtt);
++
++/*
++ * USB Host 2 BMI config inactive
++ */
++void bmi_usbh2_inactive(void);
++
++/*
++ * configure BMI Module GPIO direction
++ *
++ * @param module      plug-in module (BMI, x= 1,2,3,4)
++ * @param bit         GPIO bit (0-3)
++ * @param dir         GPIO bit (BMI_GPIO_IN or BMI_GPIO_OUT)
++ */
++void bmi_set_module_gpio_dir(int module, int bit, int dir);
++
++/*
++ * read BMI GPIO Direction register
++ *
++ * @param module      plug-in module (BMI_Mx, x= 1,2,3,4)
++ * @return                    module GPIO direction (4 LSB)
++ */
++int bmi_read_gpio_direction_reg(int module);
++
++/*
++ * set BMI Module GPIO data
++ *
++ * @param module      plug-in module (BMI_Mx, x= 1,2,3,4)
++ * @param bit         GPIO bit (0-3)
++ * @param value               GPIO bit (0x0 or 0x1)
++ */
++void bmi_set_module_gpio_data(int module, int bit, int value);
++
++/*
++ * read BMI GPIO Data register
++ *
++ * @param module      plug-in module (BMI_Mx, x= 1,2,3,4)
++ * @return                    module GPIO data (4 LSB)
++ */
++int bmi_read_gpio_data_reg(int module);
++
++/*
++ * set BMI Module battery enable
++ *
++ * @param module      plug-in module (BMI_Mx, x= 1,2,3,4)
++ */
++void bmi_set_module_battery_enable(int module);
++
++/*
++ * set BMI Module battery disable
++ *
++ * @param module      plug-in module (BMI_Mx, x= 1,2,3,4)
++ */
++void bmi_set_module_battery_disable(int module);
++
++/*
++ * read BMI module battery status
++ *
++ * @param module      plug-in module (BMI_Mx, x= 1,2,3,4)
++ * @return                    state of module battery status bit
++ */
++int bmi_read_module_battery_status(int module);
++
++/*
++ * set BMI interrupt enable
++ *
++ * @param interrupt interrupt (INT_BUGRTC .. INT_M4_PRES) (defined in mx31bug.h)
++ */
++void bmi_interrupt_enable(int interrupt);
++
++/*
++ * set BMI interrupt disable
++ *
++ * @param interrupt interrupt (INT_BUGRTC .. INT_M4_PRES) (defined in mx31bug.h)
++ */
++void bmi_interrupt_disable(int interrupt);
++
++/*
++ * get BMI interrupt status
++ *
++ * @param interrupt interrupt (INT_BUGRTC .. INT_M4_PRES) (defined in mx31bug.h)
++ * @return    1 if set, 0 otherwise
++ */
++int bmi_interrupt_status(int interrupt);
++
++/*
++ * clear BMI module present interrupt bit
++ *
++ * @param module      plug-in module (BMI_Mx, x= 1,2,3,4)
++ */
++void bmi_clear_module_present_interrupt(int module);
++
++/*
++ * enable I2C switches in BMI
++ */
++void bmi_i2c_sw_enable(void);
++
++/*
++ * disable I2C switches in BMI
++ */
++void bmi_i2c_sw_disable(void);
++
++/*
++ * read BMI module present status
++ *
++ * @param module      plug-in module (BMI_Mx, x= 1,2,3,4)
++ * @return            module present status (3 LSB = (OUT, IN, STATE_CHANGED))
++ */
++int bmi_read_module_present_status(int module);
++
++/*
++ *  BMI module present
++ *
++ * @param module      plug-in module (BMI_Mx, x= 1,2,3,4)
++ * @return            module present (1 = present, 0 = not present )
++ */
++int bmi_module_present (struct bmi_device *bdev);
++
++
++#endif // _BMI_CONTROL_H
++
+--- /dev/null
++++ git/include/linux/bmi/bmi-eeprom-data.h
+@@ -0,0 +1,83 @@
++#ifndef BMI_EEPROM_DATA_H
++#define BMI_EEPROM_DATA_H
++
++#include <linux/types.h>
++
++union _bmi_vendor {
++  __u16 vendor;
++  __u8        vendor_msb;
++  __u8        vendor_lsb;
++};
++
++union _bmi_product {
++  __u16 product;
++  __u8        product_msb;
++  __u8        product_lsb;
++};
++
++union _bmi_revision {
++  __u16 revision;
++  __u8        revision_msb;
++  __u8        revision_lsb;
++};
++
++struct bmi_eeprom_raw
++{
++      __u8 format;                    /* byte 0x00  */
++      __u8 vendor_msb;                /* byte 0x01 */
++      __u8 vendor_lsb;                /* byte 0x02 */
++      __u8 product_msb;               /* byte 0x03 */
++      __u8 product_lsb;               /* byte 0x04 */
++      __u8 revision_msb;              /* byte 0x05 */
++      __u8 revision_lsb;              /* byte 0x06 */
++      __u8 bus_usage;                 /* byte 0x07 */
++      __u8 gpio_usage;                /* byte 0x08 */
++      __u8 power_use;                 /* byte 0x09 */
++      __u8 power_charging;            /* byte 0x0A */
++      __u8 memory_size_msb;           /* byte 0x0B */
++      __u8 memory_size_lsb;           /* byte 0x0C */
++      __u8 serial_num_loc;            /* byte 0x0D */
++      __u8 serial_num_year;           /* byte 0x0E */
++      __u8 serial_num_week;           /* byte 0x0F */
++      __u8 serial_num_seq_msb;        /* byte 0x10 */
++      __u8 serial_num_seq_mid;        /* byte 0x11 */
++      __u8 serial_num_seq_lsb;        /* byte 0x12 */
++      __s8 description[108];          /* byte 0x13-0x7E */
++      __u8 checksum;                  /* byte 0x7F */
++};
++
++
++#ifdef __KERNEL__
++
++struct bmi_eeprom_id
++{
++      __u16 vendor;
++      __u16 product;
++      __u16 revision;
++};
++
++
++enum {
++      BMI_EPSTATE_UNKNOWN = 0,
++      BMI_EPSTATE_I2C_READ_ERROR,
++      BMI_EPSTATE_CHECKSUM_ERROR,
++      BMI_EPSTATE_VALID,
++};
++
++extern void bmi_eeprom_get_id (struct bmi_eeprom_raw *raw, struct bmi_eeprom_id *epid);
++extern int bmi_eeprom_checksum_validate ( struct bmi_eeprom_raw *raw );
++#endif /* __KERNEL__ */
++
++static inline __u8 bmi_eeprom_checksum ( struct bmi_eeprom_raw *raw )
++{
++      int i;
++      __u8 sum = 0;
++      __u8 *buf = (__u8*)raw;
++
++      for (i = 0; i < (sizeof (struct bmi_eeprom_raw) - 1); i++) {
++              sum ^= *buf++;
++      }
++      return sum;
++}
++
++#endif /* BMI_EEPROM_DATA_H */
+--- /dev/null
++++ git/include/linux/bmi/bmi-eeprom-driver.h
+@@ -0,0 +1,113 @@
++#ifndef BMI_EEPROM_DRIVER_H
++#define BMI_EEPROM_DRIVER_H
++
++/*******************************************************************************
++ *  Driver description:
++ *
++ *  This driver provides operations that allow an application program to
++ *  read and write the inventory eeprom on Bug Labs Bug PlugIn peripheral
++ *  hardware modules.
++ *
++ *  This driver is a character driver.
++ *
++ *  Supported system calls
++ *
++ *  This driver supports the following system calls:
++ *
++ *  open()
++ *
++ *      During the open() call, only driver initialization and house keeping
++ *      are performed. The hardware is not touched.
++ *
++ *  close()
++ *
++ *      During the close() system call, only driver house keeping is performed.
++ *      The hardware is not touched.
++ *
++ *  ioctl()
++ *
++ *      All of the ioctl() calls for this driver take 2 or 3 parameters.
++ *      They are:
++ *              file descriptor         - obtained from open() call.
++ *              ioctl command number    - described below.
++ *              void pointer to struct  - ioctl command specific.
++
++ *   ioctl() return values:
++ *
++ *      On success, all ioctl() calls return zero.
++ *
++ *      On error, all ioctl() calls return -1 and errno is set appropriatly.
++ *      Additional error information may be returned in the ioctl command
++ *      structure. See the ioctl command structure declarations for more
++ *      information.
++ *
++ *******************************************************************************
++ */
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++
++/*
++ * Include the standard type definitions.
++ * The file to include depends on whether or not we are doing a kernel or
++ * application build.
++ */
++#ifdef __KERNEL__
++    #include   <linux/types.h>
++#else
++    #include   <sys/types.h>
++    #include   <stdint.h>
++#endif /* __KERNEL__ */
++
++
++#ifdef __cplusplus
++}
++#endif
++
++//REWORK: Add documentation.
++
++//REWORK: Where should this file live so that applications can #include it ?
++
++
++/*    bmi_eeprom_request
++
++      offset: 0 - 255
++      size:   1- 256
++      offset + size must be <= 256
++
++ */
++struct bmi_eeprom_request {
++      int return_code;
++      int xfer_count;
++      int size;
++      int offset;
++      __u8 data[256];
++};
++
++
++/*******************************************************************************
++ *  Ioctl type definition:
++ *
++ *  The ioctl type (magic) number for this driver is BUG_EEPROM_IOC_TYPE
++ *
++ *******************************************************************************
++ */
++
++#define BUG_EEPROM_IOC_TYPE   0xFE
++
++/*******************************************************************************
++ *  Ioctl command definitions:
++ *
++ *  The ioctl calls supported by this driver are:
++ *
++ *******************************************************************************
++ */
++
++#define BUG_EEPROM_READ \
++              _IOR (BUG_EEPROM_IOC_TYPE, 0, struct bmi_eeprom_request)
++
++#define BUG_EEPROM_WRITE \
++              _IOW (BUG_EEPROM_IOC_TYPE, 0, struct bmi_eeprom_request)
++
++#endif
+--- /dev/null
++++ git/include/linux/bmi/bmi-eeprom.h
+@@ -0,0 +1,75 @@
++#ifndef BMI_EEPROM_H
++#define BMI_EEPROM_H
++
++#include <linux/types.h>
++
++union _bmi_vendor {
++  __u16 vendor;
++  __u8        vendor_msb;
++  __u8        vendor_lsb;
++};
++
++union _bmi_product {
++  __u16 product;
++  __u8        product_msb;
++  __u8        product_lsb;
++};
++
++union _bmi_revision {
++  __u16 revision;
++  __u8        revision_msb;
++  __u8        revision_lsb;
++};
++
++struct bmi_eeprom_data
++{
++  __u8 format;                        /* byte 0x00 */
++  __u8 vendor_msb;            /* byte 0x01 */
++  __u8 vendor_lsb;            /* byte 0x02 */
++  __u8 product_msb;           /* byte 0x03 */
++  __u8 product_lsb;           /* byte 0x04 */
++  __u8 revision_msb;          /* byte 0x05 */
++  __u8 revision_lsb;          /* byte 0x06 */
++/*   __u16 vendor; */
++/*   __u16 product; */
++/*   __u16 revision; */
++  __u8 bus_usage;                     /* byte 0x07 */
++  __u8 gpio_usage;            /* byte 0x08 */
++  __u8 power_use;                     /* byte 0x09 */
++  __u8 power_charging;                /* byte 0x0A */
++  __u8 memory_size_msb;               /* byte 0x0B */
++  __u8 memory_size_lsb;               /* byte 0x0C */
++  __u8 serial_num_loc;                /* byte 0x0D */
++  __u8 serial_num_year;               /* byte 0x0E */
++  __u8 serial_num_week;               /* byte 0x0F */
++  __u8 serial_num_seq_msb;    /* byte 0x10 */
++  __u8 serial_num_seq_mid;    /* byte 0x11 */
++  __u8 serial_num_seq_lsb;    /* byte 0x12 */
++  __s8 description[108];              /* byte 0x13-0x7E */
++  __u8 checksum;                      /* byte 0x7F */
++};
++
++
++struct bmi_eeprom_id
++{
++      __u16 vendor;
++      __u16 product;
++      __u16 revision;
++};
++
++
++enum {
++      BMI_EPSTATE_UNKNOWN = 0,
++      BMI_EPSTATE_I2C_READ_ERROR,
++      BMI_EPSTATE_CHECKSUM_ERROR,
++      BMI_EPSTATE_VALID,
++};
++
++
++//__u8 bmi_eeprom_checksum ( struct bmi_eeprom_data *raw );
++int bmi_eeprom_checksum_validate ( struct bmi_eeprom_data *raw );
++//extern void bmi_eeprom_get_id (struct bmi_eeprom_data *raw, struct bmi_eeprom_id *epid);
++//extern int bmi_eeprom_checksum_validate ( struct bmi_eeprom_data *raw );
++
++
++#endif /* BMI_EEPROM_H */
+--- /dev/null
++++ git/include/linux/bmi/bmi-slot.h
+@@ -0,0 +1,29 @@
++#ifndef BMI_SLOT_H
++#define BMI_SLOT_H
++
++//void bmi_slot_resrc_init(void);
++
++void bmi_slot_power_on  (int num);
++void bmi_slot_power_off (int num);
++
++void bmi_slot_gpio_configure (int num, int gpio);
++int bmi_slot_gpio_get (int num);
++
++void bmi_slot_gpio_set (int num, int data);
++void bmi_slot_uart_enable  (int num);
++void bmi_slot_uart_disable (int num);
++
++void bmi_slot_spi_enable (int num);
++void bmi_slot_spi_disable (int num);
++
++void bmi_slot_audio_enable  (int num);
++void bmi_slot_audio_disable (int num);
++
++void bmi_slot_battery_enable (int num);
++void bmi_slot_battery_disable (int num);
++
++int bmi_slot_module_present (int num);
++//int bmi_slot_status_irq_state (int num);
++
++
++#endif
+--- /dev/null
++++ git/include/linux/bmi/bmi_audio.h
+@@ -0,0 +1,449 @@
++/*
++ * File:         include/linux/bmi/bmi_audio.h
++ * Author:       Peter Giacomini <p.giacomini@encadis.com>
++ *
++ *            This is the application header file for the BMI bus audio plug-in
++ *            module on the MX31 BUG platform.
++ */
++
++#ifndef BMI_AUDIO_H
++#define BMI_AUDIO_H
++
++#include <linux/bmi/bmi_ioctl.h>
++
++// GPIO       defines
++typedef enum {
++      GPIO_SPARE,     // unused
++      GPIO_RESET,     // CODEC reset
++      GPIO_GREEN,     // green LED
++      GPIO_RED,       // red LED
++} BMI_AUDIO_GPIO;
++
++// GETSTAT defines
++typedef enum {
++      GETSTAT_AMP     = 0x001,        // IOX bit 0 - amplifier off (O - low active)
++      GETSTAT_ISPARE  = 0x002,        // IOX bit 1 - spare
++      GETSTAT_VOLP    = 0x004,        // IOX bit 2 - VOLP (I - interrupt)
++      GETSTAT_VOLD    = 0x008,        // IOX bit 3 - VOLD (I - interrupt)
++      GETSTAT_HP_INS  = 0x010,        // IOX bit 4 - HP_INS (I - interrupt)
++      GETSTAT_MIC_INS = 0x020,        // IOX bit 5 - MIC_INS (I - interrupt)
++      GETSTAT_LI_INS  = 0x040,        // IOX bit 6 - LI_INS (I - interrupt)
++      GETSTAT_LO_INS  = 0x080,        // IOX bit 7 - LO_INS (I - interrupt)
++      GETSTAT_GSPARE  = 0x100,        // unused
++      GETSTAT_RESET   = 0x200,        // CODEC reset
++      GETSTAT_GREEN   = 0x400,        // green LED
++      GETSTAT_RED     = 0x800,        // red LED
++} BMI_AUDIO_GETSTAT;
++
++// input event bit defintions
++typedef enum {
++      HEADPHONE_INSERTED         = 0x001,     // Detected headphone insertion
++      MICROPHONE_INSERTED        = 0x002,     // Detected microphone insertion
++      LINEOUT_INSERTED           = 0x004,     // Detected line out insertion
++      LINEIN_INSERTED            = 0x008,     // Detected line in insertion
++      VOLUME_DOWN                = 0x010,     // volume down button pressed
++      VOLUME_UP                  = 0x020,     // volume up button pressed
++} BMI_AUDIO_EVENT;
++
++// module numbers
++typedef enum {
++      BMI_AUDIO_M1,           // PIM 1
++      BMI_AUDIO_M2,           // PIM 2
++      BMI_AUDIO_M3,           // PIM 3
++      BMI_AUDIO_M4,           // PIM 4
++      BMI_AUDIO_PIM_NUM,      // Number of PIMs
++} BMI_MODULE_NUMBERS;
++
++// TI '3105 CODEC registers
++// Page 0
++#define CODEC_PAGE_SEL                        0x0                     // page select
++#define CODEC_RESET                   0x1                     // reset (self-clearing)
++      #define CODEC_RESET_RESET       0x1                     // reset (self-clearing)
++#define CODEC_SAMPLE_RATE             0x2                     // ADC/DAC sample rate
++      #define CODEC_SR1               0x0                     // ADC/DAC sample rate
++      #define CODEC_SR1_5             0x1                     // ADC/DAC sample rate
++      #define CODEC_SR2               0x2                     // ADC/DAC sample rate
++      #define CODEC_SR2_5             0x3                     // ADC/DAC sample rate
++      #define CODEC_SR3               0x4                     // ADC/DAC sample rate
++      #define CODEC_SR3_5             0x5                     // ADC/DAC sample rate
++      #define CODEC_SR4               0x6                     // ADC/DAC sample rate
++      #define CODEC_SR4_5             0x7                     // ADC/DAC sample rate
++      #define CODEC_SR5               0x8                     // ADC/DAC sample rate
++      #define CODEC_SR5_5             0x9                     // ADC/DAC sample rate
++      #define CODEC_SR6               0xA                     // ADC/DAC sample rate
++      #define CODEC_SR_SHIFT          (4)                     // ADC shift
++#define CODEC_PLLA                    0x3                     // PLL Programming A
++      #define CODEC_PLLA_EN           0x80                    // PLL enabled
++      #define CODEC_PLLA_DIS          0x00                    // PLL disabled
++      #define CODEC_PLLA_Q(x)         (((x) & 0xF) << 3)      // PLL Q
++      #define CODEC_PLLA_P(x)         ((x) & 0x7)             // PLL P
++#define CODEC_PLLB                    0x4                     // PLL Programming B
++      #define CODEC_PLLB_J(x)         (((x) & 0x3F) << 2)     // PLL J
++#define CODEC_PLLC_DMSB                       0x5                     // PLL D MSB
++#define CODEC_PLLD_DLSB                       0x6                     // PLL D LSB
++      #define CODEC_PLLD_D(x)         (((x) & 0x3F) << 2)     // PLL D LSB
++#define CODEC_DATAPATH                        0x7                     // Datapath set up
++      #define CODEC_DP_48             (0x00)                  // 48 kHz
++      #define CODEC_DP_44             (0x80)                  // 44.1 kHz
++      #define CODEC_ADR_DIS           (0x00)                  // ADC Dual Rate
++      #define CODEC_ADR_EN            (0x40)                  // ADC Dual Rate
++      #define CODEC_DDR_DIS           (0x00)                  // DAC Dual Rate
++      #define CODEC_DDR_EN            (0x20)                  // DAC Dual Rate
++      #define CODEC_DP_MUTED          (0x00)                  // DAC Data Path
++      #define CODEC_DP_NORMAL         (0x01)                  // DAC Data Path
++      #define CODEC_DP_REVERSE        (0x02)                  // DAC Data Path
++      #define CODEC_DP_MONO           (0x03)                  // DAC Data Path
++      #define CODEC_DP_L(x)           ((x) << 3)              // DAC Data Path Left
++      #define CODEC_DP_R(x)           ((x) << 1)              // DAC Data Path Right
++#define CODEC_AIFA                    0x8                     // Audio serial data IF control
++      #define CODEC_AIFA_BCLK_S       0x00                    // BCLK is input
++      #define CODEC_AIFA_BCLK_M       0x80                    // BCLK is output
++      #define CODEC_AIFA_WCLK_S       0x00                    // WCLK is input
++      #define CODEC_AIFA_WCLK_M       0x40                    // WCLK is output
++      #define CODEC_AIFA_DOUT_N       0x00                    // Dout not tri-state
++      #define CODEC_AIFA_DOUT_TS      0x20                    // Dout tri-states
++      #define CODEC_AIFA_CLK_G        0x00                    // CLKs gated (Master mode only)
++      #define CODEC_AIFA_CLK_F        0x10                    // CLKs free run (Master mode only)
++      #define CODEC_AIFA_FX_OFF       0x00                    // disable 3-D EFX
++      #define CODEC_AIFA_FX_ON        0x04                    // enable 3-D EFX
++#define CODEC_AIFB                    0x9                     // Audio serial data IF control
++      #define CODEC_AIFB_I2S          0x00                    // MODE = I2S
++      #define CODEC_AIFB_DSP          0x40                    // MODE = DSP
++      #define CODEC_AIFB_RJ           0x80                    // MODE = Right Justified
++      #define CODEC_AIFB_LJ           0xC0                    // MODE = Left Justified
++      #define CODEC_AIFB_16           0x00                    // World Length = 16 bits
++      #define CODEC_AIFB_20           0x10                    // World Length = 20 bits
++      #define CODEC_AIFB_24           0x20                    // World Length = 24 bits
++      #define CODEC_AIFB_32           0x30                    // World Length = 32 bits
++      #define CODEC_AIFB_256S         0x08                    // 256-clock transfer mode (TDM)
++      #define CODEC_AIFB_DSYNC        0x04                    // DAC resync
++      #define CODEC_AIFB_ASYNC        0x02                    // ADC resync
++      #define CODEC_AIFB_MSYNC        0x01                    // resync with soft-mute
++#define CODEC_AIF_WORD_OFFSET         0xA                     // data bit offset in frame
++#define CODEC_OVERFLOW                        0xB                     // Overflow flags
++      #define CODEC_OF_LADC           0x80                    // Left ADC
++      #define CODEC_OF_RADC           0x40                    // Right ADC
++      #define CODEC_OF_LDAC           0x20                    // Left DAC
++      #define CODEC_OF_RDAC           0x10                    // Right DAC
++      #define CODEC_OF_PLLR(x)        ((x) & 0xF)             // PLL R
++#define CODEC_FILT_CONTROL            0xC                     // Filter Control
++      #define CODEC_FC_LADC_HP45      0x40                    // Left ADC Filter Control
++      #define CODEC_FC_LADC_HP125     0x80                    // Left ADC Filter Control
++      #define CODEC_FC_LADC_HP25      0xC0                    // Left ADC Filter Control
++      #define CODEC_FC_RADC_HP45      0x10                    // Right ADC Filter Control
++      #define CODEC_FC_RADC_HP125     0x20                    // Right ADC Filter Control
++      #define CODEC_FC_RADC_HP25      0x30                    // Right ADC Filter Control
++#define CODEC_HS                      0xE                     // Headset/Button
++      #define CODEC_HS_COUPLED        0x80                    // HP outputs AC-Coupled
++      #define CODEC_HS_ADIFF          0x40                    // Output A differential
++      #define CODEC_HS_HSDET          0x10                    // headset detected
++      #define CODEC_HS_BDIFF          0x08                    // Output B differential
++#define CODEC_LADC_PGA                        0xF                     // Left ADC PGA
++#define CODEC_RADC_PGA                        0x10                    // Right ADC PGA
++      #define CODEC_ADC_PGA_MUTE      0x80                    // muted
++      #define CODEC_ADC_PGA_G(x)      ((x) & 0x7F)            // gain (0 to 59.5 dB)
++#define CODEC_M3_LPGA                 0x11                    // MIC3 -> LADC PGA
++#define CODEC_M3_RPGA                 0x12                    // MIC3 -> RADC PGA
++      #define CODEC_M3_PGA_LOFF       (0xF << 4)              // L input off
++      #define CODEC_M3_PGA_ROFF       (0xF    )               // R input off
++      #define CODEC_M3_PGA_L(x)       (((x) & 0xF) << 4)      // L input level (0 to -12 dB)
++      #define CODEC_M3_PGA_R(x)       ((x) & 0xF)             // R input level (0 to -12 dB)
++#define CODEC_L1L_LPGA                        0x13                    // L1 Left -> LADC PGA
++#define CODEC_L2L_LPGA                        0x14                    // L2 Left -> LADC PGA
++#define CODEC_L1R_LPGA                        0x15                    // L1 Right -> LADC PGA
++#define CODEC_L1R_RPGA                        0x16                    // R1 Right -> RADC PGA
++#define CODEC_L2R_RPGA                        0x17                    // L2 Right -> RADC PGA
++#define CODEC_L1L_RPGA                        0x18                    // L1 Left -> RADC PGA
++      #define CODEC_L_PGA(x)          (((x) & 0xF) << 3)      // input level (0 to -12 dB)
++      #define CODEC_LX_PGA_PU         0x04                    // L1 power up
++      #define CODEC_L1L_PGA_SS(x)     ((x) & 0x3)             // L1 soft stepping
++      #define CODEC_L2L_LPGA_BIASED   0x04                    // L2 Left weak bias
++#define CODEC_MIC_BIAS                        0x19                    // Mic Bias
++      #define CODEC_MIC_BIAS_PD       0x00                    // powered down
++      #define CODEC_MIC_BIAS_2V       0x40                    // 2V
++      #define CODEC_MIC_BIAS_2P5V     0x80                    // 2.5V
++      #define CODEC_MIC_BIAS_AVDD     0xC0                    // AVDD
++#define CODEC_MIC_LAGC_A              0x1A                    // L AGC A
++#define CODEC_MIC_RAGC_A              0x1D                    // R AGC A
++      #define CODEC_MIC_AGC_EN        0x80                    // enable
++      #define CODEC_MIC_AGC_TL(x)     (((x) & 0x7) << 4)      // target level (-5.5 to -24 dB)
++      #define CODEC_MIC_AGC_AT(x)     (((x) & 0x3) << 2)      // attack time (8 to 20 ms)
++      #define CODEC_MIC_AGC_DT(x)     ((x) & 0x3)             // decay time (100 to 500 ms)
++#define CODEC_MIC_LAGC_B              0x1B                    // L AGC B
++#define CODEC_MIC_RAGC_B              0x1E                    // R AGC B
++      #define CODEC_MIC_AGC_MG(x)     (((x) & 0x7F) << 1)     // max gain (0 to 59.5 dB)
++#define CODEC_MIC_LAGC_C              0x1C                    // L AGC C
++#define CODEC_MIC_RAGC_C              0x1F                    // R AGC C
++      #define CODEC_MIC_AGC_H(x)      (((x) & 0x3) << 6)      // NG hysteresis (1 to 3 dB, off)
++      #define CODEC_MIC_AGC_T(x)      (((x) & 0x3) << 6)      // NG Threshold (off to -90 dB)
++      #define CODEC_MIC_AGC_SC        0x1                     // clip stepping enable
++#define CODEC_MIC_LAGC_GAIN           0x20                    // L AGC gain (-12 tp 59.5 dB)
++#define CODEC_MIC_RAGC_GAIN           0x21                    // R AGC gain (-12 tp 59.5 dB)
++#define CODEC_MIC_LAGC_NGD            0x22                    // L AGC NG debounce
++#define CODEC_MIC_RAGC_NGD            0x23                    // R AGC NG debounce
++      #define CODEC_MIC_AGC_NGD_D(x)  (((x) & 0x1F) << 3)     // detect(0 to 1536 ms)
++      #define CODEC_MIC_AGC_NGD_C(x)  ((x) & 0x7)             // control (0 to 32 ms)
++#define CODEC_ADC_FLAG                        0x24                    // ADC flag
++      #define CODEC_ADC_FLAG_LPGA_S   0x80                    // L ADC PGA gain equal
++      #define CODEC_ADC_FLAG_LPWR_S   0x40                    // L ADC powered-up
++      #define CODEC_ADC_FLAG_LSIGD    0x20                    // L AGC signal detected
++      #define CODEC_ADC_FLAG_LSAT     0x10                    // L AGC saturation detected
++      #define CODEC_ADC_FLAG_RPGA_S   0x08                    // R ADC PGA gain equal
++      #define CODEC_ADC_FLAG_RPWR_S   0x04                    // R ADC powered-up
++      #define CODEC_ADC_FLAG_RSIGD    0x02                    // R AGC signal detected
++      #define CODEC_ADC_FLAG_RSAT     0x01                    // R AGC saturation detected
++#define CODEC_DAC_PWR                 0x25                    // DAC power and output driver
++#define CODEC_DAC_HPWR                        0x26                    // high-power output driver
++      #define CODEC_DAC_PWR_L_EN      0x80                    // L power up
++      #define CODEC_DAC_PWR_R_EN      0x40                    // R power up
++      #define CODEC_DAC_PWR_HP_DIFF   0x00                    // differential of HPLOUT
++      #define CODEC_DAC_PWR_HP_VCM    0x10                    // constant VCM
++      #define CODEC_DAC_PWR_HP_ISE    0x20                    // independant single ended
++      #define CODEC_DAC_HPWR_HPL_DIFF 0x18                    // short circuit protection
++      #define CODEC_DAC_HPWR_SS       0x04                    // short circuit protection
++      #define CODEC_DAC_HPWR_SS_C     0x00                    //      limit current
++      #define CODEC_DAC_HPWR_SS_P     0x02                    //      power down
++#define CODEC_DAC_HPOS                        0x28                    // high-power output stage
++      #define CODEC_DAC_HPOS_CM1P35   0x00                    // common mode = 1.35V
++      #define CODEC_DAC_HPOS_CM1P5    0x40                    // common mode = 1.5V
++      #define CODEC_DAC_HPOS_CM1P65   0x80                    // common mode = 1.65V
++      #define CODEC_DAC_HPOS_CM1P8    0xC0                    // common mode = 1.8V
++      #define CODEC_DAC_HPOS_L2L_BYP  0x00                    // L2 L bypass disabled
++      #define CODEC_DAC_HPOS_L2L_SE   0x10                    // L2 L bypass = L2LP
++      #define CODEC_DAC_HPOS_L2L_BYP  0x00                    // L2 R bypass disabled
++      #define CODEC_DAC_HPOS_L2R_SE   0x04                    // L2 R bypass = L2RP
++      #define CODEC_DAC_HPOS_FS       0x00                    // soft stepping: 1 / fs
++      #define CODEC_DAC_HPOS_2FS      0x01                    // soft stepping: 1 / 2 fs
++      #define CODEC_DAC_HPOS_SS_DIS   0x02                    // soft stepping disabled
++#define CODEC_DAC_OS                  0x29                    // output switching
++      #define CODEC_DAC_OS_L1         0x00                    // L = L1
++      #define CODEC_DAC_OS_L3         0x40                    // L = L3
++      #define CODEC_DAC_OS_L2         0x80                    // L = L2
++      #define CODEC_DAC_OS_R1         0x00                    // R = R1
++      #define CODEC_DAC_OS_R3         0x10                    // R = R3
++      #define CODEC_DAC_OS_R2         0x20                    // R = R2
++      #define CODEC_DAC_OS_VOL_S      0x00                    // volume separate
++      #define CODEC_DAC_OS_VOL_R      0x01                    //      L follows R
++      #define CODEC_DAC_OS_VOL_L      0x02                    //      R follows L
++#define CODEC_DAC_PR                  0x2A                    // pop reduction
++      #define CODEC_DAC_PR_DEL(x)     (((x) & 0xF) << 4)      // delay (0 us to 4 s)
++      #define CODEC_DAC_PR_RU(x)      (((x) & 0x3) << 2)      // ramp up (0 to 4 ms)
++      #define CODEC_DAC_CM_AVDD       0x00                    // common mode from AVDD
++      #define CODEC_DAC_CM_BG         0x02                    // common mode from band gap
++#define CODEC_DAC_LVOL                        0x2B                    // Left volume
++#define CODEC_DAC_RVOL                        0x2C                    // Right volume
++      #define CODEC_DAC_VOL_MUTE      0x80                    // muted
++      #define CODEC_DAC_VOL(x)        ((x) & 0x7F)            // volume (0 to -63.5 dB)
++#define CODEC_L2L_HPL                 0x2D                    // L2L -> HPLOUT
++#define CODEC_PGAL_HPL                        0x2E                    // PGAL -> HPLOUT
++#define CODEC_DACL1_HPL                       0x2F                    // DACL1 -> HPLOUT
++#define CODEC_L2R_HPL                 0x30                    // L2R -> HPLOUT
++#define CODEC_PGAR_HPL                        0x31                    // PGAR -> HPLOUT
++#define CODEC_DACR1_HPL                       0x32                    // DACLR -> HPLOUT
++#define CODEC_L2L_HPLCOM              0x34                    // L2L -> HPLCOM
++#define CODEC_PGAL_HPLCOM             0x35                    // PGAL -> HPLCOM
++#define CODEC_DACL1_HPLCOM            0x36                    // DACL1 -> HPLCOM
++#define CODEC_L2R_HPLCOM              0x37                    // L2R -> HPLCOM
++#define CODEC_PGAR_HPLCOM             0x38                    // PGAR -> HPLCOM
++#define CODEC_DACR1_HPLCOM            0x39                    // DACR1 -> HPLCOM
++#define CODEC_L2L_HPR                 0x3B                    // L2L -> HPROUT
++#define CODEC_PGAL_HPR                        0x3C                    // PGAL -> HPROUT
++#define CODEC_DACL1_HPR                       0x3D                    // DACL1 -> HPROUT
++#define CODEC_L2R_HPR                 0x3E                    // L2R -> HPROUT
++#define CODEC_PGAR_HPR                        0x3F                    // PGAR -> HPROUT
++#define CODEC_DACR1_HPR                       0x40                    // DACLR -> HPROUT
++#define CODEC_L2L_HPRCOM              0x42                    // L2L -> HPRCOM
++#define CODEC_PGAL_HPRCOM             0x43                    // PGAL -> HPRCOM
++#define CODEC_DACL1_HPRCOM            0x44                    // DACL1 -> HPRCOM
++#define CODEC_L2R_HPRCOM              0x45                    // L2R -> HPRCOM
++#define CODEC_PGAR_HPRCOM             0x46                    // PGAR -> HPRCOM
++#define CODEC_DACR1_HPRCOM            0x47                    // DACLR -> HPRCOM
++#define CODEC_L2L_LLOPM                       0x50
++#define CODEC_PGAL_LLOPM              0x51
++#define CODEC_DACL1_LLOPM             0x52
++#define CODEC_L2R_LLOPM                       0x53
++#define CODEC_PGAR_LLOPM              0x54
++#define CODEC_DACR1_LLOPM             0x55
++#define CODEC_L2L_RLOPM                       0x57
++#define CODEC_PGA_RLOPM                       0x58
++#define CODEC_DACL1_RLOPM             0x59
++#define CODEC_L2R_RLOPM                       0x5A
++#define CODEC_PGAR_RLOPM              0x5B
++#define CODEC_DACR1_RLOPM             0x5C
++      #define CODEC_HP_EN             0x80                    // enabled
++      #define CODEC_HP_VOL(x)         ((x) & 0x7F)            // see datasheet Table 6
++#define CODEC_HPLOUT                  0x33                    // HPLOUT output level
++#define CODEC_HPLCOM                  0x3A                    // HPLCOM output level
++#define CODEC_HPROUT                  0x41                    // HPROUT output level
++#define CODEC_HPRCOM                  0x48                    // HPRCOM output level
++#define CODEC_LLOPM                   0x56                    // LLOPM output level
++#define CODEC_RLOPM                   0x5D                    // RLOPM output level
++      #define CODEC_HPX_LC(x)         (((x) & 0xF) << 4)      // output level
++      #define CODEC_HPX_EN            0x08                    // not muted
++      #define CODEC_HPX_PD            0x04                    // power down enable
++      #define CODEC_HPX_STAT          0x02                    // gain not applied
++      #define CODEC_HPX_PC            0x01                    // fully powered up
++#define CODEC_PSR                     0x5E                    // Power Status
++      #define CODEC_PSR_LDPS          0x80                    // L DAC
++      #define CODEC_PSR_DDPS          0x40                    // R DAC
++      #define CODEC_PSR_LLOPM         0x10                    // L LOPM
++      #define CODEC_PSR_RLOPM         0x08                    // R LOPM
++      #define CODEC_PSR_HPLOUT        0x04                    // HPLOUT
++      #define CODEC_PSR_HPLCOM        0x02                    // HPLCOM
++#define CODEC_SS                      0x5F                    // driver short circuit
++      #define CODEC_SS_HPLOUT         0x80
++      #define CODEC_SS_HPROUT         0x40
++      #define CODEC_SS_HPLCOM         0x20
++      #define CODEC_SS_HPRCOM         0x10
++      #define CODEC_SS_HPLCOM_PS      0x08
++      #define CODEC_SS_HPRCOM_PS      0x04
++#define CODEC_S_INT                   0x60                    // sticky interrupt
++#define CODEC_RT_INT                  0x61                    // real-time interrupt
++      #define CODEC_INT_HPLOUT_SS     0x80
++      #define CODEC_INT_HPROUT_SS     0x40
++      #define CODEC_INT_HPLCOM_SS     0x20
++      #define CODEC_INT_HPRCOM_SS     0x10
++      #define CODEC_INT_HS_DET        0x04
++      #define CODEC_INT_LAGC_NG       0x02
++      #define CODEC_INT_RAGC_NG       0x01
++#define CODEC_CLK                     0x65                    // clock source
++      #define CODEC_CLK_PLLDIV        0x00
++      #define CODEC_CLK_CLKDIV        0x01
++#define CODEC_CLKGEN                  0x66                    // clock generation
++      #define CODEC_CLKGEN_C_M        0x02                    // MCLK -> CLK
++      #define CODEC_CLKGEN_C_G        0x42                    // GPIO2 -> CLK
++      #define CODEC_CLKGEN_C_B        0x82                    // BCLK -> CLK
++      #define CODEC_CLKGEN_P_M        0x02                    // MCLK -> PLL
++      #define CODEC_CLKGEN_P_G        0x12                    // GPIO2 -> PLL
++      #define CODEC_CLKGEN_P_B        0x22                    // BCLK -> PLL
++#define CODEC_LAGC_ATT                        0x67                    // L AGC Attack
++#define CODEC_RAGC_ATT                        0x69                    // R AGC Attack
++      #define CODEC_AGC_ATT_R26       0x00                    // source reg 36
++      #define CODEC_AGC_ATT_R103      0x80                    // source reg 103
++      #define CODEC_AGC_ATT_T(x)      (((x) & 0x3) << 5)      // time
++      #define CODEC_AGC_ATT_M(x)      (((x) & 0xF) << 2)      // multiplication
++#define CODEC_LAGC_DEC                        0x68                    // L AGC Decay
++#define CODEC_RAGC_DEC                        0x6A                    // R AGC Decay
++      #define CODEC_AGC_DEC_R26       0x00                    // source reg 36
++      #define CODEC_AGC_DEC_R104      0x80                    // source reg 104
++      #define CODEC_AGC_DEC_T(x)      (((x) & 0x3) << 5)      // time
++      #define CODEC_AGC_DEC_M(x)      (((x) & 0xF) << 2)      // multiplication
++#define CODEC_DP_I2C                  0x6B                    // digital path and I2C
++      #define CODEC_DP_I2C_LHPF_EN    0x80
++      #define CODEC_DP_I2C_RHPF_EN    0x40
++      #define CODEC_ADC_DFLDRD        0x00
++      #define CODEC_ADC_DFLDRA        0x10
++      #define CODEC_ADC_DFLARD        0x20
++      #define CODEC_ADC_DFLARA        0x30
++      #define CODEC_ADC_F_EN          0x08
++      #define CODEC_I2C_ERR_DIS       0x04
++      #define CODEC_I2C_HANG          0x01
++#define CODEC_PASB                    0x6C                    // passive analog bypass
++      #define CODEC_PASB_L2RP_RLOP    0x40
++      #define CODEC_PASB_L1RP_RLOP    0x10
++      #define CODEC_PASB_L2LP_LLOP    0x04
++      #define CODEC_PASB_L1LP_LLOP    0x01
++#define CODEC_DAC_QCA                 0x6D                    // DAC current adjust
++#define CODEC_DAC_QCA_50              0x40
++#define CODEC_DAC_QCA_100             0xC0
++// Page 1
++#define CODEC_EF_LN0M                 0x1
++#define CODEC_EF_LN0L                 0x2
++#define CODEC_EF_LN1M                 0x3
++#define CODEC_EF_LN1L                 0x4
++#define CODEC_EF_LN2M                 0x5
++#define CODEC_EF_LN2L                 0x6
++#define CODEC_EF_LN3M                 0x7
++#define CODEC_EF_LN3L                 0x8
++#define CODEC_EF_LN4M                 0x9
++#define CODEC_EF_LN4L                 0xA
++#define CODEC_EF_LN5M                 0xB
++#define CODEC_EF_LN5L                 0xC
++
++#define CODEC_EF_LD1M                 0xD
++#define CODEC_EF_LD1L                 0xE
++#define CODEC_EF_LD2M                 0xF
++#define CODEC_EF_LD2L                 0x10
++#define CODEC_EF_LD4M                 0x11
++#define CODEC_EF_LD4L                 0x12
++#define CODEC_EF_LD5M                 0x13
++#define CODEC_EF_LD5L                 0x14
++
++#define CODEC_DF_LN0M                 0x15
++#define CODEC_DF_LN0L                 0x16
++#define CODEC_DF_LN1M                 0x17
++#define CODEC_DF_LN1L                 0x18
++
++#define CODEC_DF_LD1M                 0x19
++#define CODEC_DF_LD1L                 0x1A
++
++#define CODEC_EF_RN0M                 0x1B
++#define CODEC_EF_RN0L                 0x1C
++#define CODEC_EF_RN1M                 0x1D
++#define CODEC_EF_RN1L                 0x1E
++#define CODEC_EF_RN2M                 0x1F
++#define CODEC_EF_RN2L                 0x20
++#define CODEC_EF_RN3M                 0x21
++#define CODEC_EF_RN3L                 0x22
++#define CODEC_EF_RN4M                 0x23
++#define CODEC_EF_RN4L                 0x24
++#define CODEC_EF_RN5M                 0x25
++#define CODEC_EF_RN5L                 0x26
++
++#define CODEC_EF_RD1M                 0x27
++#define CODEC_EF_RD1L                 0x28
++#define CODEC_EF_RD2M                 0x29
++#define CODEC_EF_RD2L                 0x2A
++#define CODEC_EF_RD4M                 0x2B
++#define CODEC_EF_RD4L                 0x2C
++#define CODEC_EF_RD5M                 0x2D
++#define CODEC_EF_RD5L                 0x2E
++
++#define CODEC_DF_RN0M                 0x2F
++#define CODEC_DF_RN0L                 0x30
++#define CODEC_DF_RN1M                 0x31
++#define CODEC_DF_RN1L                 0x32
++
++#define CODEC_DF_RD1M                 0x33
++#define CODEC_DF_RD1L                 0x34
++
++#define CODEC_3DAM                    0x35
++#define CODEC_3DAL                    0x36
++
++#define CODEC_LHPN0M                  0x41
++#define CODEC_LHPN0L                  0x42
++#define CODEC_LHPN1M                  0x43
++#define CODEC_LHPN1L                  0x44
++#define CODEC_LHPD1M                  0x45
++#define CODEC_LHPD1L                  0x46
++
++#define CODEC_RHPN0M                  0x47
++#define CODEC_RHPN0L                  0x48
++#define CODEC_RHPN1M                  0x49
++#define CODEC_RHPN1L                  0x4A
++#define CODEC_RHPD1M                  0x4B
++#define CODEC_RHPD1L                  0x4C
++
++struct codec_xfer {
++      unsigned char page;
++      unsigned char reg;
++      unsigned char data;
++} codec_xfer;
++
++// IOCTL commands for BMI AUDIO driver
++#define BMI_AUDIO_RLEDOFF     _IO(BMI_AUDIO_IOCTL, 0x1)                       // Turn off red LED
++#define BMI_AUDIO_RLEDON      _IO(BMI_AUDIO_IOCTL, 0x2)                       // Turn on red LED
++#define BMI_AUDIO_GLEDOFF     _IO(BMI_AUDIO_IOCTL, 0x3)                       // Turn off green LED
++#define BMI_AUDIO_GLEDON      _IO(BMI_AUDIO_IOCTL, 0x4)                       // Turn on green LED
++#define BMI_AUDIO_SPKOFF      _IO(BMI_AUDIO_IOCTL, 0x5)                       // Turn off speaker
++#define BMI_AUDIO_SPKON       _IO(BMI_AUDIO_IOCTL, 0x6)                       // Turn on speaker
++#define BMI_AUDIO_GETSTAT     _IOR(BMI_AUDIO_IOCTL, 0x9, unsigned int *)      // READ IOX register
++#define BMI_AUDIO_SETRST      _IO(BMI_AUDIO_IOCTL, 0xA)                       // Set RESET to '0'
++#define BMI_AUDIO_CLRRST      _IO(BMI_AUDIO_IOCTL, 0xB)                       // Set RESET to '1'
++#define BMI_AUDIO_ACTIVATE    _IO(BMI_AUDIO_IOCTL, 0xC)                       // Activate a module for audio capture
++#define BMI_AUDIO_DEACTIVATE  _IO(BMI_AUDIO_IOCTL, 0xD)                       // Deactivate a module for audio capture
++#define BMI_AUDIO_WCODEC      _IOW(BMI_AUDIO_IOCTL, 0xE, struct codec_xfer *) // write CODEC register
++#define BMI_AUDIO_RCODEC      _IOR(BMI_AUDIO_IOCTL, 0xF, struct codec_xfer *) // read CODEC register
++
++#endif        /* BMI_AUDIO_H */
++
+--- /dev/null
++++ git/include/linux/bmi/bmi_camera.h
+@@ -0,0 +1,36 @@
++/*
++ * File:         include/linux/bmi/bmi_camera.h
++ * Author:       Peter Giacomini <p.giacomini@encadis.com>
++ *
++ *            This is the application header file for the BMI bus camera plug-in
++ *            module on the MX31 BUG platform.
++ */
++
++#ifndef BMI_CAMERA_A_H
++#define BMI_CAMERA_A_H
++
++#include <linux/input.h>
++#include <linux/bmi/bmi_ioctl.h>
++
++      // IOCTL commands for BMI Camera driver
++
++#define BMI_CAM_FLASH_HIGH_BEAM               _IOW(BMI_CAMERA_IOCTL, 0x1, __u32)
++#define BMI_CAM_FLASH_LOW_BEAM                _IOW(BMI_CAMERA_IOCTL, 0x2, __u32)
++#define BMI_CAM_FLASH_LED_OFF         _IOW(BMI_CAMERA_IOCTL, 0x3, __u32)
++#define BMI_CAM_FLASH_LED_ON          _IOW(BMI_CAMERA_IOCTL, 0x4, __u32)
++
++#define BMI_CAM_RED_LED_OFF           _IOW(BMI_CAMERA_IOCTL, 0x5, __u32)              // Turn off red LED
++#define BMI_CAM_RED_LED_ON            _IOW(BMI_CAMERA_IOCTL, 0x6, __u32)              // Turn on red LED
++#define BMI_CAM_GREEN_LED_OFF         _IOW(BMI_CAMERA_IOCTL, 0x7, __u32)              // Turn off green LED
++#define BMI_CAM_GREEN_LED_ON          _IOW(BMI_CAMERA_IOCTL, 0x8, __u32)              // Turn on green LED
++
++#define BMI_CAM_SELECT                        _IOW(BMI_CAMERA_IOCTL, 0x9, __u32)              // Select camera module
++#define BMI_CAM_GET_SELECTED          _IOR(BMI_CAMERA_IOCTL, 0xA, __u32)              // return selected camera module
++
++      // input event definitions
++#define BN_SHUTTER    BTN_0
++#define BN_ZOOMIN     BTN_1
++#define BN_ZOOMOUT    BTN_2
++
++#endif        /* BMI_CAMERA_A_H */
++
+--- /dev/null
++++ git/include/linux/bmi/bmi_gps.h
+@@ -0,0 +1,30 @@
++/*
++ * File:         include/linux/bmi/bmi_gps.h
++ * Author:       Peter Giacomini <p.giacomini@encadis.com>
++ *
++ *            This is the application header file for the BMI bus gps plug-in
++ *            module on the MX31 BUG platform.
++ */
++
++#ifndef BMI_GPS_H
++#define BMI_GPS_H
++
++#include <linux/bmi/bmi_ioctl.h>
++
++      // IOCTL commands for BMI GPS driver
++#define BMI_GPS_RLEDOFF               _IOW(BMI_GPS_IOCTL, 0x1, unsigned int)          // Turn off red LED
++#define BMI_GPS_RLEDON                _IOW(BMI_GPS_IOCTL, 0x2, unsigned int)          // Turn on red LED
++#define BMI_GPS_GLEDOFF               _IOW(BMI_GPS_IOCTL, 0x3, unsigned int)          // Turn off green LED
++#define BMI_GPS_GLEDON                _IOW(BMI_GPS_IOCTL, 0x4, unsigned int)          // Turn on green LED
++#define BMI_GPS_SETBOOT               _IOW(BMI_GPS_IOCTL, 0x5, unsigned int)          // Set BOOT to '1'
++#define BMI_GPS_CLRBOOT               _IOW(BMI_GPS_IOCTL, 0x6, unsigned int)          // Set BOOT to '0'
++#define BMI_GPS_SETWAKE               _IOW(BMI_GPS_IOCTL, 0x7, unsigned int)          // Set WAKE to '1'
++#define BMI_GPS_CLRWAKE               _IOW(BMI_GPS_IOCTL, 0x8, unsigned int)          // Set WAKE to '0'
++#define BMI_GPS_GETSTAT               _IOR(BMI_GPS_IOCTL, 0x9, unsigned int *)        // READ IOX register
++#define BMI_GPS_SETRST                _IOW(BMI_GPS_IOCTL, 0xA, unsigned int)          // Set RESET to '0'
++#define BMI_GPS_CLRRST                _IOW(BMI_GPS_IOCTL, 0xB, unsigned int)          // Set RESET to '1'
++#define BMI_GPS_ACTIVE_ANT            _IOW(BMI_GPS_IOCTL, 0xC, unsigned int)          // Select Active Antenna
++#define BMI_GPS_PASSIVE_ANT           _IOW(BMI_GPS_IOCTL, 0xD, unsigned int)          // Select Passive Antenna
++
++#endif        /* BMI_GPS_H */
++
+--- /dev/null
++++ git/include/linux/bmi/bmi_gsm.h
+@@ -0,0 +1,33 @@
++/*
++ * File:         include/linux/bmi/bmi_gsm.h
++ * Author:       Matt Isaacs <izzy@buglabs.net>
++ *
++ *            This is the application header file for the BMI bus GSM/UMTS plug-in
++ *            module on the MX31 BUG platform.
++ */
++
++#ifndef BMI_GSM_H
++#define BMI_GSM_H
++
++#include <linux/bmi/bmi_ioctl.h>
++
++// GPIO
++#define GSM_GPIO_RED_LED              3       // default to input
++#define GSM_GPIO_GREEN_LED    2       // default to input
++#define GSM_GPIO_1            1       // default to input
++#define GSM_GPIO_0            0       // default to input
++
++#define GSM_GPIO_LED_ON               0
++#define GSM_GPIO_LED_OFF      1
++
++
++// von hippel driver ioctl definitions
++#define BMI_GSM_RLEDOFF               _IOW(BMI_GSM_IOCTL, 0x1, unsigned int)          // Turn off red LED
++#define BMI_GSM_RLEDON                _IOW(BMI_GSM_IOCTL, 0x2, unsigned int)          // Turn on red LED
++#define BMI_GSM_GLEDOFF               _IOW(BMI_GSM_IOCTL, 0x3, unsigned int)          // Turn off green LED
++#define BMI_GSM_GLEDON                _IOW(BMI_GSM_IOCTL, 0x4, unsigned int)          // Turn on green LED
++#define BMI_GSM_GETSTAT               _IOR(BMI_GSM_IOCTL, 0x5, unsigned int *)                // READ IOX register
++
++
++#endif        /* BMI_GSM_H */
++
+--- /dev/null
++++ git/include/linux/bmi/bmi_ioctl.h
+@@ -0,0 +1,27 @@
++/*
++ * File:         include/linux/bmi/bmi_ioctl.h
++ * Author:       Peter Giacomini <p.giacomini@encadis.com>
++ *
++ *            This is the header file for the BMI ioctl definitions
++ */
++
++#ifndef BMI_IOCTL_H
++#define BMI_IOCTL_H
++
++      // IOCTL Magic Numbers
++#define BMI_CAMERA_IOCTL      ('c')
++#define BMI_LCD_IOCTL         ('l')
++#define BMI_GPS_IOCTL         ('g')
++#define BMI_MDACC_IOCTL               ('m')
++#define BMI_AUDIO_IOCTL               ('a')
++#define BMI_VH_IOCTL          ('v')
++#define BMI_WIFI_IOCTL                ('W')
++#define BMI_ZIGBEE_IOCTL      ('Z')
++#define BMI_GSM_IOCTL         ('G')
++#define BMI_PROJECTOR_IOCTL   ('p')
++#define BMI_SENSOR_IOCTL      ('s')
++#define BMI_LCD2X_IOCTL               ('x')
++#define BMI_RFID_IOCTL                ('r')
++
++#endif        /* BMI_IOCTL_H */
++
+--- /dev/null
++++ git/include/linux/bmi/bmi_lcd.h
+@@ -0,0 +1,71 @@
++/*
++ * File:         include/linux/bmi/bmi_lcd.h
++ * Author:       Peter Giacomini <p.giacomini@encadis.com>
++ *
++ *            This is the application header file for the BMI bus lcd plug-in
++ *            module on the MX31 BUG platform.
++ */
++
++#ifndef BMI_LCD_H
++#define BMI_LCD_H
++
++#include <linux/input.h>
++#include <linux/bmi/bmi_ioctl.h>
++
++      // IOCTL commands for BMI LCD driver
++#define BMI_LCD_RLEDOFF               _IOW(BMI_LCD_IOCTL, 0x1, __u32)         // turn off Red LED
++#define BMI_LCD_RLEDON                _IOW(BMI_LCD_IOCTL, 0x2, __u32)         // turn on Red LED
++#define BMI_LCD_GLEDOFF               _IOW(BMI_LCD_IOCTL, 0x3, __u32)         // turn off Green LED
++#define BMI_LCD_GLEDON                _IOW(BMI_LCD_IOCTL, 0x4, __u32)         // turn on Green LED
++#define BMI_LCD_VSYNC_DIS     _IOW(BMI_LCD_IOCTL, 0x5, __u32)         // Enable VSYNC output buffer
++#define BMI_LCD_VSYNC_EN      _IOW(BMI_LCD_IOCTL, 0x6, __u32)         // Disable VSYNC output buffer
++#define BMI_LCD_EN            _IOW(BMI_LCD_IOCTL, 0x7, __u32)         // Enable LCD component
++#define BMI_LCD_DIS           _IOW(BMI_LCD_IOCTL, 0x8, __u32)         // Disable LCD component
++#define BMI_LCD_SER_EN                _IOW(BMI_LCD_IOCTL, 0x9, __u32)         // Enable Seriallizer component
++#define BMI_LCD_SER_DIS               _IOW(BMI_LCD_IOCTL, 0xa, __u32)         // Disable Seriallizer component
++#define BMI_LCD_SETRST                _IOW(BMI_LCD_IOCTL, 0xb, __u32)         // Disable entire module
++#define BMI_LCD_CLRRST                _IOW(BMI_LCD_IOCTL, 0xc, __u32)         // Enable entire module
++#define BMI_LCD_SET_BL                _IOW(BMI_LCD_IOCTL, 0xd, __u32)         // Set IOX backlight bits [2:0]
++#define BMI_LCD_GETSTAT               _IOR(BMI_LCD_IOCTL, 0xe, __u32)         // Get IOX state
++#define BMI_LCD_ACTIVATE      _IOW(BMI_LCD_IOCTL, 0xf, __u32)         // Activate SER, TS, ACCEL
++#define BMI_LCD_DEACTIVATE    _IOW(BMI_LCD_IOCTL, 0x10, __u32)        // Deactivate SER, TS, ACCEL
++#define BMI_LCD_SUSPEND               _IOW(BMI_LCD_IOCTL, 0x11, __u32)        // Power down module
++#define BMI_LCD_RESUME                _IOW(BMI_LCD_IOCTL, 0x12, __u32)        // Power up module
++
++/*Izzy Additions*/
++#define BMI_LCD_MIN_XC    0
++#define BMI_LCD_MAX_XC    0x3fff
++#define BMI_LCD_MIN_YC    0
++#define BMI_LCD_MAX_YC    0x3fff
++
++/*struct lcd_ctl
++{
++  int slot;
++  struct cdev cdev;
++  struct device *class_dev;
++};
++*/
++
++//
++// Orientation        - location of module 1-3 shorter edge (when facing LCD side)
++// when not FACEUP or FACEDOWN
++//
++// Note that orientation is only reported through bmi_lcd_ts[0-3]
++//
++#define ACC_PITCH_MSK (0xFFFF0000)
++#define ACC_ROLL_MSK  (0xFFFF)
++
++      // touch screen input devices
++enum {
++    BMI_TS_M1,                // bmi_lcd_ts0  - slot 0
++    BMI_TS_M2,                // bmi_lcd_ts1  - slot 1
++    BMI_TS_M3,                // bmi_lcd_ts2  - slot 2
++    BMI_TS_M4,                // bmi_lcd_ts3  - slot 3
++    BMI_TS_M13,               // bmi_lcd_ts4  - slot 0 and 2
++    BMI_TS_M24,               // bmi_lcd_ts5  - slot 1 and 3
++    BMI_TS_M1234,     // bmi_lcd_ts6  - slot 0-3
++    BMI_TS_NUM,
++} lcd_ts_t;
++
++#endif        /* BMI_LCD_H */
++
+--- /dev/null
++++ git/include/linux/bmi/bmi_mdacc.h
+@@ -0,0 +1,518 @@
++/*-----------------------------------------------------------------------------
++ *
++ * File:     include/linux/bmi/bug_mdacc.h
++ *
++ *-----------------------------------------------------------------------------
++ * This file contains information needed by application programs that use the
++ * Bug Motion Detector Accelerometer (MDACC) Plug-In Module.
++ *
++ * The Bug Motion Detector Accelerometer (MDACC) Plug-In Module is a circuit
++ * board that contains the following devices:
++ *
++ *     a motion sensor,
++ *     a 3-axis accelerometer
++ *     a micro-controller.
++ *     1 Red LED
++ *     1 Green LED
++ *
++ * The micro-controller behaves as an SPI-slave device. The host controls
++ * the operation of the micro-controller by issuing sequences of SPI messages.
++ * The micro-controller periodically samples the motion sensor and the
++ * accelerometer. The micro-controller generates an interrupts to the host
++ * processor. The micro-controller provides data to the host in response
++ * to received SPI messages.
++ *
++ * Application software can the MDACC Plug-in modules using the following
++ * device drivers:
++ *
++ *    BMI MDACC Control Driver
++ *    BMI MDACC Motion Detector Driver
++ *    BMI MDACC Accelerometer Driver
++ *
++ * These drivers allow for independent operation of MDACC peripheral devices.
++ *
++ * This file contains the interface definition for all 3 device drivers.
++ *
++ * ---------------------------------------------------------------------------
++ *
++ * Default Device Names:
++ *
++ * The following device nodes are created for each MDACC card present in the
++ * system.
++ *
++ *   /dev/bmi_mdacc_ctl_mX   where X = 1,2,3,4 (bmi connector number)
++ *   /dev/bmi_mdacc_mot_mX   where X = 1,2,3,4 (bmi connector number)
++ *   /dev/bmi_mdacc_acc_mX   where X = 1,2,3,4 (bmi connector number)
++ *
++ * If the MDACC is not present in a given slot, the corresponding device nodes
++ * are not created.
++ *
++ *----------------------------------------------------------------------------
++ *
++ *     BMI MDACC Control Driver
++ *
++ *----------------------------------------------------------------------------
++ *
++ *  This character driver provides access to the Red and Green LEDs via
++ *  via the ioctl() system call.
++ *
++ *  Supported system calls: open(), close(), ioctl().
++ *
++ *  The following IOCTL commands are defined for this driver.
++ *
++ *       BMI_MDACC_CTL_RED_LED_OFF
++ *       BMI_MDACC_CTL_RED_LED_ON
++ *       BMI_MDACC_CTL_GREEN_LED_OFF
++ *       BMI_MDACC_CTL_GREEN_LED_ON
++ *
++ *  Note that the 3rd argument to the ioctl system call are not used by the
++ *  ioctl commands listed above.
++ *----------------------------------------------------------------------------
++ */
++
++/*----------------------------------------------------------------------------
++ *
++ *     BMI MDACC Motion Detector Driver
++ *
++ *----------------------------------------------------------------------------
++ *
++ * This character driver provides access to the motion sensor via the SPI
++ * interface. This driver enforces single-open and stop-on-close behaviors.
++ *
++ *
++ * Supported system calls: open(), close(), ioctl(). read(), select().
++ *
++ * BMI MDACC Motion Detector ioctl() interface
++ *--------------------------------------------
++ *
++ * The following IOCTL commands are defined for this driver.
++ *
++ *      BMI_MDACC_MOTION_DETECTOR_GET_STATUS
++ *      BMI_MDACC_MOTION_DETECTOR_RUN
++ *      BMI_MDACC_MOTION_DETECTOR_STOP
++ *
++ *
++ * The BMI_MDACC_MOTION_DETECTOR_RUN command sends an SPI message to the
++ * microcontroller to enable sampling of the motion detector status pin.
++ * This command does not use the 3rd parameter to the ioctl system call.
++ *
++ * The BMI_MDACC_MOTION_DETECTOR_STOP command sends an SPI message to the
++ * microcontroller to halt sampling of the motion detector status pin.
++ * This command does not use the 3rd parameter to the ioctl system call.
++ *
++ * The BMI_MDACC_MOTION_DETECTOR_GET_STATUS command gets the motion detector
++ * status byte that is maintained by the motion detector driver.
++ * The third argument to the ioctl system call should be the address of a
++ * the receive buffer that is 1 byte in size.
++ *
++ * Motion Detect Status Bit Descriptions
++ * ---------------------------------------
++ *
++ * The Motion Detect Status byte is returned by the system calls to the
++ * MDACC Motion Detector driver:
++ *
++ *       ioctl(BMI_MDACC_MOTION_GET_STATUS)
++ *       read()
++ *
++ * The following bits are defined in the status byte.
++ *
++ * BMI_MOTION_DETECT_STATUS
++ *
++ * This bit is the present status of the the motion detector status pin.
++ * A value of 1 indicates that motion is being detected.
++ * A value of 0 indicates that motion is not being detected.
++ *
++ *
++ * BMI_MOTION_DETECT_LATCHED_STATUS
++ *
++ * This bit is the latched status of the motion sensor. This bit is set to 1
++ * when the BMI_MOTION_DETECT_STATUS bit changes from 0 to 1. This bit will
++ * be cleared as the result of an "ioctl(BMI_MDACC_MOTION_GET_STATUS)" or a
++ * read() system call.
++ *
++ * BMI_MOTION_DETECT_DELTA
++ *
++ * This bit indicates that the motion detector status has changed from 1 to 0
++ * or has changed from 0 to 1. This bit will be cleared as the result of an
++ * "ioctl(BMI_MDACC_MOTION_GET_STATUS)" or read() system calls.
++ *
++ *
++ * BMI_MOTION_DETECT_ENABLED
++ *
++ * This bits is the state of the motion detector sampling and status reporting
++ * mechanism. A value of 1 indicates that the motion detector is enabled. A
++ * value of 0 indicates that the motion detector is disabled.
++ *
++ *
++ * Motion Detect read() system call
++ * --------------------------------
++ *
++ * The read() call for this driver allows the application program to read the
++ * motion detector status only when the status has changed.
++ *
++ * Prior to issuing a read() to this driver, the application must enabled the
++ * motion detector using the "ioctl(BMI_MDACC_MOTION_DETECTOR_RUN)" command.
++ *
++ * read parameters:
++ *
++ *    buffer:   status byte destination address.
++ *    size:     1
++ *
++ * Motion Detect blocking read() behavior
++ * --------------------------------------
++ *
++ * If the motion detector status HAS NOT changed, then the driver will sleep
++ * waiting for the motion detect status to change.
++ *
++ * If the driver is awoken by a Motion Detect status change interrupt, the
++ * underlying hardware will be accessed (for a second time) and the motion
++ * detect status will be updated.
++ *
++ * The status data byte will be copied to the user-supplied buffer. The
++ * following bits will then be cleared in the motion detect status byte:
++ *
++ *     BMI_MOTION_DETECT_LATCHED_STATUS
++ *     BMI_MOTION_DETECT_DELTA
++ *
++ * The driver will then be marked as "not-ready-to-read".
++ *
++ * If the the driver is awoken by a signal, the driver will return failure (-1)
++ * and errno will be set to ERESTARTSYS.
++ *
++ *
++ * Motion Detect non-blocking read() behavior
++ * ------------------------------------------
++ * If the motion detector status HAS NOT changed prior to the non-blocking
++ * read() system call, then the driver will return failure (-1) and errno will
++ * be set to EAGAIN.
++ *
++ * If the motion detector status HAS changed prior to the non-blocking read()
++ * system call, the underlying hardware will be accessed and the motion detect
++ * status will be updated. The status data byte will be copied to the user
++ * supplied buffer. The following bits will then be cleared in the motion
++ * detect status byte:
++ *
++ *     BMI_MOTION_DETECT_LATCHED_STATUS
++ *     BMI_MOTION_DETECT_DELTA
++ *
++ * The driver will then be marked as "not-ready-to-read".
++ *
++ *
++ * Motion Detect select() system call
++ * -----------------------------------
++ *
++ * This driver supports select() for read only. Select for write and
++ * exception is not supported.
++ *
++ * When a Motion Detect interrupt occurs, the file descriptor corresponding
++ * to the Motion Detector driver will be marked as "ready for read".
++ *
++ * ---------------------------------------------------------------------------
++ */
++
++
++/*----------------------------------------------------------------------------
++ *
++ *     BMI MDACC Accelerometer Driver
++ *
++ *----------------------------------------------------------------------------
++ *
++ * This character driver provides access to the accelerometer data via an SPI
++ * interface. This driver enforces single-open and stop-on-close behaviors.
++ *
++ * Supported system calls: open(), close(), ioctl(). read(), select().
++ *
++ *
++ * MDACC Accelerometer Driver Configuration
++ * -----------------------------------------
++ *
++ * The micro-controller on the MDACC Plug-In module uses an internal 10 bit A/D
++ * converter to sample the 3 analog output channels of the accelerometer
++ * device. The analog channels are sampled periodically at a rate that can be
++ * configured by an application program. When a set of 3 channel samples has
++ * been acquired, the micro-controller generates an interrupt to the host
++ * processor. The host processor then issues SPI messages to the
++ * micro-controller to obtain the 3 channel sample set.
++ *
++ * The MDACC Accelerometer Driver provides a read queue to store sample data
++ * until it can be read by the application program. The size of the read queue
++ * and a read-queue "ready" threshold can both be specified by the application
++ * program.
++ *
++ *
++ * MDACC Accelerometer Driver ioctl() interface
++ * --------------------------------------------
++
++ * The following IOCTL commands are defined for this driver.
++ *
++ *     BMI_MDACC_ACCELEROMETER_SET_CONFIG
++ *     BMI_MDACC_ACCELEROMETER_GET_CONFIG
++ *     BMI_MDACC_ACCELEROMETER_RUN
++ *     BMI_MDACC_ACCELEROMETER_STOP
++ *
++ *
++ * BMI_MDACC_ACCELEROMETER_SET_CONFIG
++ *
++ * This ioctl command transfers an mdacc_accel_config structure from the
++ * application program to the MDACC Accelerometer Driver.
++ * The third argument to this ioctl system call is the address of the an
++ * mdacc_accel_config structure.
++ *
++ * In the mdacc_accel_config structure, if the delay_mode field is 0,
++ * the values of the delay and delay resolution fields are ignored and
++ * and a default delay value of 4 milliseconds is used.
++ *
++ * BMI_MDACC_ACCELEROMETER_GET_CONFIG
++ *
++ * This ioctl command transfers an mdacc_accel_config structure from the
++ * MDACC Accelerometer Drive to the application program.
++ * The third argument to this ioctl system call is the address of the an
++ * mdacc_accel_config structure.
++ *
++ *
++ * BMI_MDACC_ACCELEROMETER_RUN
++ *
++ * This ioctl command will enable the accelerometer data aquistion in the MDACC
++ * Accelerometer Driver and in the MDACC micro-controller. The behavior of this
++ * ioctl command can also be invoked by an
++
++ *    "ioctl(BMI_MDACC_ACCELEROMETER_SET_CONFIG)" system call with
++ *    "mdacc_accel_config.run = 1".
++ *
++ * BMI_MDACC_ACCELEROMETER_STOP
++ *
++ * This ioctl command will disable the accelerometer data aquistion in the MDACC
++ * Accelerometer Driver and in the MDACC micro-controller. The behavior of this
++ * ioctl command can also be invoked by an
++ *
++ *    "ioctl(BMI_MDACC_ACCELEROMETER_SET_CONFIG)" system call with
++ *    "mdacc_accel_config.run = 0".
++ *
++ * Note that this behavior is also invoked in the close() system call if the
++ * accelerometer had previously been enabled.
++ *
++ *
++ * MDACC Accelerometer Driver read() interface
++ * -------------------------------------------
++ *
++ * The read() call for this driver allows the application program to read
++ * motion detector status only when the status has changed.
++ *
++ * Prior to issuing a read() to this driver, the application must enabled the
++ * motion detector using the "ioctl(BMI_MDACC_MOTION_DETECTOR_RUN)" command.
++ *
++ * read parameters:
++ *
++ *     buffer:   address of an array of mdacc_accel_sample structures.
++ *     size:     size of the mdacc_accel_sample array in bytes.
++ *
++ * Accelerometer blocking read() behavior
++ * --------------------------------------
++ *
++ * If the accelerometer read queue DOES NOT contain at least "read-threshold"
++ * number of sample set entries, then the driver will sleep.
++ *
++ * If the the driver is awoken by a signal, the driver will return failure (-1)
++ * and errno will be set to ERESTARTSYS.
++
++ * Otherwise, the requested number of sample sets are removed from the driver
++ * read queue and copied to user space. The number of bytes transfers will be
++ * returned to the application.
++ *
++ * At the end of the transfer, if the number of read queue entries is below the
++ * read-threshold, the the driver will then be marked as "not-ready-to-read".
++ *
++ *
++ * Accelerometer non-blocking read() behavior
++ * ------------------------------------------
++ * If the accelerometer read queue DOES NOT contain at least "read-threshold"
++ * number of sample set entries, then the driver will return failure (-1) and
++ * errno will  be set to EAGAIN.
++ *
++ * Otherwise, the requested number of sample sets are removed from the driver
++ * read queue and copied to user space. The number of bytes transfers will be
++ * returned to the application.
++ *
++ * At the end of the transfer, if the number of read queue entries is below the
++ * read-threshold, the the driver will then be marked as "not-ready-to-read".
++ *
++ *
++ * Accelerometer select() system call
++ * -----------------------------------
++ *
++ * This driver supports select() for read only. Select for write and
++ * exception is not supported.
++ *
++ * When a data arrives and is inserted into the read queue and the number of
++ * queue entries meets or exceeds the read-threshold, the file descriptor
++ * corresponding to the Accelerometer driver will be marked as
++ * "ready for read".
++ * ---------------------------------------------------------------------------
++ *
++ *  Accelerometer Data Samples
++ *  ---------------------------
++ *
++ *  The accelerometer analog outputs are sampled with a 10 bit A/D converter
++ *  using 2.9V as a reference.
++ *
++ *  An accelerometer output of 1.45V corresponds to "0g".
++ *
++ *  The accelerometer outputs are scaled by the sensitivity settings.
++ *
++ *  sensitivity   scale factor
++ *  ---------------------------
++ *  0 = 2.5G,     421 mV/G
++ *  1 = 3.3G,     316 mV/G
++ *  2 = 6.7G,     158 mV/G
++ *  3 = 10G,      105 mV/G
++ *
++ *  The following equation converts an A/D sample to a G-Force value.
++ *
++ *  G-force = ( ((digital sample) * (X mV/bit)) - 1450 mV) / (scale factor )
++ *
++ * ---------------------------------------------------------------------------
++ *
++ * Accelerometer Coordinate System.
++ *
++ *
++ *          z axis:   perpendicular to PCB.
++ *          y axis:   parallel to the long edge of the connector.
++ *          x axis:  perpendicular to the short edge of the connector.
++ *
++ *
++ *                      Top View                              Side View
++ *
++ *          +--------------------------------------+          +-+
++ *          |               +x               LEDS  |          | |
++ *          |     +------------------------+       |          | +-----+
++ *          | -y  |  connector underneath  |  +y   |          |       |
++ *          |     +------------------------+       |          | +-----+
++ *          |               ____                   |          | |
++ *          |             /      \                 |          | |
++ *          |            |        |                |      -z  | |  +z
++ *          |             \ ____ /                 |          | |
++ *          |                                      |          | |
++ *          |        motion sensor on top          |          | |
++ *          |                                      |          | |
++ *          |               -x                     |          | |
++ *          +--------------------------------------+          +-+
++ *
++ * ---------------------------------------------------------------------------
++ */
++#ifndef LINUX_BMI_BMI_MDACC_H
++#define LINUX_BMI_BMI_MDACC_H
++
++#include <linux/bmi/bmi_ioctl.h>
++
++/* -------------------------
++ *
++ *  MDACC Control Driver
++ *
++ *--------------------------
++ */
++#define BMI_MDACC_CTL_RED_LED_OFF \
++              _IOW(BMI_MDACC_IOCTL, 0, char)          // Turn off red LED
++
++#define BMI_MDACC_CTL_RED_LED_ON \
++              _IOW(BMI_MDACC_IOCTL, 1, char)          // Turn on red LED
++
++#define BMI_MDACC_CTL_GREEN_LED_OFF \
++      _IOW(BMI_MDACC_IOCTL, 2, char)          // Turn off green LED
++
++#define BMI_MDACC_CTL_GREEN_LED_ON \
++      _IOW(BMI_MDACC_IOCTL, 3, char)          // Turn on green LED
++
++
++/* -------------------------------
++ *
++ *  MDACC Motion Detector Driver
++ *
++ *--------------------------------
++ */
++
++/* Status Byte Bit Definitions */
++
++#define BMI_MOTION_DETECT_STATUS         (1<<3)
++#define BMI_MOTION_DETECT_LATCHED_STATUS (1<<2)
++#define BMI_MOTION_DETECT_DELTA          (1<<1)
++#define BMI_MOTION_DETECT_ENABLED        (1<<0)
++
++/* Ioctl Commands */
++
++#define BMI_MDACC_MOTION_DETECTOR_GET_STATUS \
++              _IOR (BMI_MDACC_IOCTL, 4, char)
++
++#define BMI_MDACC_MOTION_DETECTOR_RUN \
++              _IOW (BMI_MDACC_IOCTL, 5, char)
++
++#define BMI_MDACC_MOTION_DETECTOR_STOP \
++              _IOW (BMI_MDACC_IOCTL, 6, char)
++
++
++/* -------------------------------
++ *
++ *  MDACC Accelerometer Driver
++ *
++ *--------------------------------
++ */
++struct mdacc_accel_sample {
++
++      unsigned short adc_0; //accelerometer channel Z, 10 bit, left justified
++                              //referenced to VCC = 2.9V
++
++      unsigned short adc_1; //accelerometer channel Y, 10 bit, left justified.
++                              //referenced to VCC = 2.9V.
++
++      unsigned short adc_2; //accelerometer channel X, 10 bit, left justified.
++                              //referenced to VCC = 2.9 V.
++};
++
++
++struct mdacc_accel_config {
++
++      int read_queue_size;    // number of 6-byte sample sets.
++
++      int read_queue_threshold; // number of 6-byte sample sets to queue
++                                // before ready.
++
++      unsigned short delay;   // timer ticks between the start of 2
++                              // sucessive sample sets.
++
++      unsigned char  delay_resolution; // timer tick resolution
++                                       // 1 =    1 usec,
++                                       // 2 =    8 usec,
++                                       // 3 =   64 usec,
++                                       // 4 =  256 usec,
++                                       // 5 = 1024 usec
++
++      unsigned char delay_mode;       //0 = default delay = 5 millisecond,
++                                      //    ignore delay and delay_resolution
++                                      //1 = configured delay
++
++      unsigned char run;              //0 = sampling disabled
++                                      //1 = sampling enabled
++
++      unsigned char sensitivity;      // 0 = 2.5G, 421 mV/G
++                                      // 1 = 3.3G, 316 mV/G
++                                      // 2 = 6.7G, 158 mV/G
++                                      // 3 = 10G,  105 mV/G
++
++};
++
++
++
++#define BMI_MDACC_ACCELEROMETER_SET_CONFIG \
++              _IOW (BMI_MDACC_IOCTL, 7, struct mdacc_accel_config)
++
++#define BMI_MDACC_ACCELEROMETER_GET_CONFIG \
++              _IOR (BMI_MDACC_IOCTL, 8, struct mdacc_accel_config)
++
++
++#define BMI_MDACC_ACCELEROMETER_RUN \
++              _IOW (BMI_MDACC_IOCTL, 9, char)
++
++#define BMI_MDACC_ACCELEROMETER_STOP \
++              _IOW (BMI_MDACC_IOCTL, 10, char)
++
++#define BMI_MDACC_LAST_USED (10)
++#endif
+--- /dev/null
++++ git/include/linux/bmi/bmi_projector.h
+@@ -0,0 +1,33 @@
++/*\r
++ * File:         include/linux/bmi/bmi_projector.h\r
++ * Author:      Suresh Rao\r
++ *\r
++ *            This is the application header file for the BMI bus projector plug-in\r
++ *            module on the MX31 BUG platform.\r
++ */\r
++\r
++#ifndef BMI_PROJECTOR_H\r
++#define BMI_PROJECTOR_H\r
++\r
++#include <linux/input.h>\r
++#include <linux/bmi/bmi_ioctl.h>\r
++\r
++// IOCTL commands for BMI PROJECTOR driver\r
++#define BMI_PROJECTOR_ON      _IOW(BMI_PROJECTOR_IOCTL, 0x1, __u32)   // turn on projector\r
++#define BMI_PROJECTOR_MODE    _IOW(BMI_PROJECTOR_IOCTL, 0x2, __u32)   // turn on projector\r
++#define BMI_PROJECTOR_OFF     _IOW(BMI_PROJECTOR_IOCTL, 0x3, __u32)   // turn off projector\r
++#define BMI_PROJECTOR_BATTERY _IOW(BMI_PROJECTOR_IOCTL, 0x4, __u32)   // Battery charger on to bug from  projector\r
++\r
++// IOCTL commands for Encoder control\r
++#define BMI_PROJECTOR_HUE             _IOW(BMI_PROJECTOR_IOCTL, 0x5, __u32)   // Hue control in Encoder\r
++#define BMI_PROJECTOR_SATURATION      _IOW(BMI_PROJECTOR_IOCTL, 0x6, __u32)   // Saturation control in Encoder\r
++#define BMI_PROJECTOR_BRIGHTNESS      _IOW(BMI_PROJECTOR_IOCTL, 0x7, __u32)   // Brightness control in Encoder\r
++#define BMI_PROJECTOR_SHARPNESS               _IOW(BMI_PROJECTOR_IOCTL, 0x8, __u32)   // Sharpness control in Encoder\r
++#define BMI_PROJECTOR_CONTRAST                _IOW(BMI_PROJECTOR_IOCTL, 0x9, __u32)   // Contrast control in Encoder\r
++\r
++/* BMI_PROJECTOR_MODE settings */\r
++#define PROJECTOR_ECONOMY_MODE        0x0\r
++#define PROJECTOR_BRIGHT_MODE 0x1\r
++\r
++#endif        /* BMI_PROJECTOR_H */\r
++\r
+--- /dev/null
++++ git/include/linux/bmi/bmi_sensor.h
+@@ -0,0 +1,673 @@
++/*
++ * File:         include/linux/bmi/bmi_sensor.h
++ * Author:       Peter Giacomini <p.giacomini@encadis.com>
++ *
++ *            This is the application header file for the BMI bus sensor plug-in
++ *            module on the MX31 BUG platform.
++ */
++
++#ifndef BMI_SENSOR_H
++#define BMI_SENSOR_H
++
++#include <linux/types.h>
++#include <linux/bmi/bmi_ioctl.h>
++
++// GPIO
++#define SENSOR_GPIO_RED_LED   3       // output
++#define SENSOR_GPIO_GREEN_LED 2       // output
++#define SENSOR_GPIO_PDOUT     1       // input - aproximity detector state
++#define SENSOR_GPIO_MOT_DET   0       // input - motion detector state
++
++#define SENSOR_GPIO_LED_ON            0
++#define SENSOR_GPIO_LED_OFF           1
++
++// I2C
++// I2C Slave Addresses
++#define BMI_MEE_I2C_ADDRESS   0x51    // 7-bit address - Module specific EEPROM
++#define BMI_IOX_I2C_ADDRESS   0x74    // 7-bit address - 2 banks I2C IO expander
++#define BMI_ADC_I2C_ADDRESS   0x48    // 7-bit address - ADC - humidity/acompass/sound/alight/aproximity
++#define BMI_PL_I2C_ADDRESS    0x44    // 7-bit address - digital proximity/light
++#define BMI_DLIGHT_I2C_ADDRESS        0x44    // 7-bit address - digital light
++#define BMI_TEMP_I2C_ADDRESS  0x4C    // 7-bit address - temperature
++#define BMI_ACCEL_I2C_ADDRESS 0x1D    // 7-bit address - accelerometer
++#define BMI_DCOMP_I2C_ADDRESS 0x1C    // 7-bit address - digital compass
++
++// I2C IOX register addresses
++#define IOX_INPUT0_REG                0x0
++#define IOX_INPUT1_REG                0x1
++#define IOX_OUTPUT0_REG               0x2
++#define IOX_OUTPUT1_REG               0x3
++#define IOX_POLARITY0_REG     0x4
++#define IOX_POLARITY1_REG     0x5
++#define IOX_CONTROL0_REG      0x6
++#define IOX_CONTROL1_REG      0x7
++
++// IOX bit definitions
++// bank 0
++#define       SENSOR_IOX_ACC_INT1     0       // Input - Accelerometer interrupt 1
++#define       SENSOR_IOX_ACC_INT2     1       // Input - Accelerometer interrupt 2
++#define       SENSOR_IOX_USB_FL_N     2       // Input - USB power interrupt
++#define       SENSOR_IOX_USB_EN       3       // Output - USB power enable
++#define       SENSOR_IOX_HUM_EN       4       // Output - Humidity sensor power enable
++#define       SENSOR_IOX_MOT_DET      5       // Input - Motion Detector interrupt
++#define       SENSOR_IOX_MOT_EN       6       // Output - Motion Detector interrupt enable
++#define       SENSOR_IOX_COMP_RS_N    7       // Output - A/D Compass Reset (see Honeywell AN213)
++// bank 1
++#define       SENSOR_IOX_PROX_RST_N   0       // Output - Analog Proximity sensor reset
++#define       SENSOR_IOX_PROX_EN_N    1       // Output - Analog Proximity sensor enable
++#define       SENSOR_IOX_PROX_OUT     2       // Input - Analog Proximity sensor output
++#define       SENSOR_IOX_S_PK_CLR_N   3       // Output - Sound peak detector clear
++#define       SENSOR_IOX_TEMP_INT     4       // Input - Termperature interrupt
++#define       SENSOR_IOX_PL_INT       5       // Input - Proximity/Light interrupt
++#define       SENSOR_IOX_MIC_EN       6       // Output - Sound power enanle
++#define       SENSOR_IOX_DCOMP_INT    7       // Input - Digital Compass Interrupt
++
++// EEPROM contents
++struct sensor_eeprom_raw
++{
++      __u8 xsf_msb;                   /* byte 0x00  */ // analog and digital compass
++      __u8 xsf_lsb;                   /* byte 0x01  */ // analog and digital compass
++      __u8 ysf_msb;                   /* byte 0x02  */ // analog and digital compass
++      __u8 ysf_lsb;                   /* byte 0x03  */ // analog and digital compass
++      __u8 zsf_msb;                   /* byte 0x04  */ // analog and digital compass
++      __u8 zsf_lsb;                   /* byte 0x05  */ // analog and digital compass
++      __u8 xoff_msb;                  /* byte 0x06  */ // analog and digital compass
++      __u8 xoff_lsb;                  /* byte 0x07  */ // analog and digital compass
++      __u8 yoff_msb;                  /* byte 0x08  */ // analog and digital compass
++      __u8 yoff_lsb;                  /* byte 0x09  */ // analog and digital compass
++      __u8 zoff_msb;                  /* byte 0x0A  */ // analog and digital compass
++      __u8 zoff_lsb;                  /* byte 0x0B  */ // analog and digital compass
++      __u8 xdac;                      /* byte 0x0C  */ // digital compass
++      __u8 ydac;                      /* byte 0x0D  */ // digital compass
++      __u8 zdac;                      /* byte 0x0E  */ // digital compass
++      __u8 adc_present;               /* byte 0x0F  - 0x1 == present */ // TI/Burr-Brown ADS7828
++      __u8 humidity_present;          /* byte 0x10  - 0x1 == present */ // Honeywell HIH3030
++      __u8 acompass_present;          /* byte 0x11  - 0x1 == present */ // Honeywell HMC6042/HMC1041Z
++      __u8 light_proximity_present;   /* byte 0x12  - 0x1 == present */ // Intersil ISL29018
++      __u8 sound_present;             /* byte 0x13  - 0x1 == present */ // discrete components
++      __u8 temperature_present;       /* byte 0x14  - 0x1 == present */ // National LM95235
++      __u8 motion_present;            /* byte 0x15  - 0x1 == present */ // Panasonic AMN44121
++      __u8 accel_present;             /* byte 0x16  - 0x1 == present */ // Analog Devices ADXL345
++      __u8 dcompass_present;          /* byte 0x17  - 0x1 == present */ // AsahiKASEI AK8973
++      __u8 aproximity_present;        /* byte 0x18  - 0x1 == present */ // Avago APDS-9700
++      __u8 alight_present;            /* byte 0x19 - 0x1 == present */  // Avago APDS-9002
++      __u8 dlight_present;            /* byte 0x1A - 0x1 == present */  // Intersil ISL29003
++      __u8 acc302_present;            /* byte 0x1B - 0x1 == present */  // ST LIS302DL
++};
++#define       SENSOR_DEVICE_NOT_PRESENT       (0x0)
++#define       SENSOR_DEVICE_PRESENT           (0x1)
++#define SENSOR_EE_SF_START            (0x00)
++#define SENSOR_EE_OFF_START           (0x06)
++#define SENSOR_EE_XDAC                        (0x0C)
++#define SENSOR_EE_YDAC                        (0x0D)
++#define SENSOR_EE_ZDAC                        (0x0E)
++#define SENSOR_PRESENT_START          (0x0F)
++#define SENSOR_PRESENT_END            (0x1B)
++
++struct sensor_comp_cal
++{
++      unsigned int xsf;
++      unsigned int ysf;
++      unsigned int zsf;
++      unsigned int xoff;
++      unsigned int yoff;
++      unsigned int zoff;
++};
++
++struct sensor_comp_dac
++{
++      unsigned char xdac;
++      unsigned char ydac;
++      unsigned char zdac;
++};
++
++// ADC (ADS7828) - humidity/acompass/sound/alight/aproximity
++// command write
++#define SENSOR_ADC_D10P               (0x00 << 4)     // positive diff - ch0 & ch1
++#define SENSOR_ADC_D23P               (0x01 << 4)     // positive diff - ch2 & ch3
++#define SENSOR_ADC_D45P               (0x02 << 4)     // positive diff - ch4 & ch5
++#define SENSOR_ADC_D67P               (0x03 << 4)     // positive diff - ch6 & ch7
++#define SENSOR_ADC_D10N               (0x04 << 4)     // negative diff - ch0 & ch1
++#define SENSOR_ADC_D23N               (0x05 << 4)     // negative diff - ch2 & ch3
++#define SENSOR_ADC_D45N               (0x06 << 4)     // negative diff - ch4 & ch5
++#define SENSOR_ADC_D67N               (0x07 << 4)     // negative diff - ch6 & ch7
++#define SENSOR_ADC_CH0                (0x08 << 4)     // single ended ch0
++#define SENSOR_ADC_CH2                (0x09 << 4)     // single ended ch2
++#define SENSOR_ADC_CH4                (0x0A << 4)     // single ended ch4
++#define SENSOR_ADC_CH6                (0x0B << 4)     // single ended ch6
++#define SENSOR_ADC_CH1                (0x0C << 4)     // single ended ch1
++#define SENSOR_ADC_CH3                (0x0D << 4)     // single ended ch3
++#define SENSOR_ADC_CH5                (0x0E << 4)     // single ended ch5
++#define SENSOR_ADC_CH7                (0x0F << 4)     // single ended ch7
++#define SENSOR_ADC_PD_OFF     (0x00 << 2)     // full power down
++#define SENSOR_ADC_PD_IR      (0x01 << 2)     // power down internal reference
++#define SENSOR_ADC_PD_ADC     (0x02 << 2)     // power down ADC
++#define SENSOR_ADC_PD_ON      (0x03 << 2)     // power up ADC
++// data read
++#define SENSOR_ADC_DATA_MSB   (0x0F)
++#define SENSOR_ADC_DATA_LSB   (0xFF)
++
++// ADC mapping
++#define SENSOR_ADC_SOUND_PEAK SENSOR_ADC_CH7
++#define SENSOR_ADC_SOUND_AVG  SENSOR_ADC_CH6
++#define SENSOR_ADC_APROXIMITY SENSOR_ADC_CH5  // Analog proximity
++#define SENSOR_ADC_HUMIDITY   SENSOR_ADC_CH4
++#define SENSOR_ADC_LIGHT      SENSOR_ADC_CH3  // Analog light
++#define SENSOR_ADC_ACOMPASS_Z SENSOR_ADC_CH2  // Analog compass
++#define SENSOR_ADC_ACOMPASS_Y SENSOR_ADC_CH1  // Analog compass
++#define SENSOR_ADC_ACOMPASS_X SENSOR_ADC_CH0  // Analog compass
++
++// Light/Proximity
++#define SENSOR_PL_CMD1                                (0x00)          // command I
++      #define SENSOR_PL_CMD1_PD               (0x00 << 5)     // power down
++      #define SENSOR_PL_CMD1_ALS_1X           (0x01 << 5)     // ALS once
++      #define SENSOR_PL_CMD1_IR_1X            (0x02 << 5)     // IR once
++      #define SENSOR_PL_CMD1_PROX_1X          (0x03 << 5)     // Proximity once
++      #define SENSOR_PL_CMD1_ALS_CONT         (0x05 << 5)     // ALS continuous
++      #define SENSOR_PL_CMD1_IR_CONT          (0x06 << 5)     // IR continuous
++      #define SENSOR_PL_CMD1_PROX_CONT        (0x07 << 5)     // Proximity continuous
++      #define SENSOR_PL_CMD1_INT_TIMING       (0x00)          // Proximity continuous
++      #define SENSOR_PL_CMD1_EXT_TIMING       (0x10)          // Proximity continuous
++      #define SENSOR_PL_CMD1_DATA_ADC         (0x00)          // data is ADC value
++      #define SENSOR_PL_CMD1_DATA_TIMING      (0x08)          // data is ADC value
++      #define SENSOR_PL_CMD1_INT_STAT         (0x04)          // interrupt status
++      #define SENSOR_PL_CMD1_INT_1MS          (0x00)          // interrupt persist = 1 ms
++      #define SENSOR_PL_CMD1_INT_4MS          (0x01)          // interrupt persist = 4 ms
++      #define SENSOR_PL_CMD1_INT_8MS          (0x02)          // interrupt persist = 8 ms
++      #define SENSOR_PL_CMD1_INT_16MS         (0x03)          // interrupt persist = 16 ms
++#define SENSOR_PL_CMD2                                (0x01)          // command II
++      #define SENSOR_PL_CMD2_IR_LED_A         (0x00)          // sense IR from LED and ambient
++      #define SENSOR_PL_CMD2_IR_LED           (0x80)          // sense IR from LED only
++      #define SENSOR_PL_CMD2_MOD_DC           (0x00)          // IR LED modulation = DC
++      #define SENSOR_PL_CMD2_MOD_327K         (0x40)          // IR LED modulation = 327.7 kHz
++      #define SENSOR_PL_CMD2_DRIVE_12M        (0x00 << 4)     // IR drive current = 12.5 mA
++      #define SENSOR_PL_CMD2_DRIVE_25M        (0x01 << 4)     // IR drive current = 25 mA
++      #define SENSOR_PL_CMD2_DRIVE_50M        (0x02 << 4)     // IR drive current = 50 mA
++      #define SENSOR_PL_CMD2_DRIVE_100M       (0x03 << 4)     // IR drive current = 100 mA
++      #define SENSOR_PL_CMD2_ADC_RES_16       (0x00 << 2)     // ADC resolution = 16 bits
++      #define SENSOR_PL_CMD2_ADC_RES_12       (0x01 << 2)     // ADC resolution = 12 bits
++      #define SENSOR_PL_CMD2_ADC_RES_8        (0x02 << 2)     // ADC resolution = 8 bits
++      #define SENSOR_PL_CMD2_ADC_RES_4        (0x03 << 2)     // ADC resolution = 4 bits
++      #define SENSOR_PL_CMD2_ALS_RNG_1        (0x00)          // ALS sensing = 1000 LUX
++      #define SENSOR_PL_CMD2_ALS_RNG_4        (0x01)          // ALS sensing = 4000 LUX
++      #define SENSOR_PL_CMD2_ALS_RNG_16       (0x02)          // ALS sensing = 16000 LUX
++      #define SENSOR_PL_CMD2_ALS_RNG_64       (0x03)          // ALS sensing = 64000 LUX
++#define SENSOR_PL_DATA_LSB                    (0x02)          // Data
++#define SENSOR_PL_DATA_MSB                    (0x03)          // Data
++#define SENSOR_PL_INT_LT_LSB                  (0x04)          // Low interrupt threshold LSB
++#define SENSOR_PL_INT_LT_MSB                  (0x05)          // Low interrupt threshold MSB
++#define SENSOR_PL_INT_HT_LSB                  (0x06)          // High interrupt threshold LSB
++#define SENSOR_PL_INT_HT_MSB                  (0x07)          // High interrupt threshold MSB
++#define SENSOR_PL_EXT_SYNC                    (0x80)          // write address to restart ADC integration
++
++struct sensor_pl_rw { // see the datasheet
++      unsigned char cmd1;
++      unsigned char cmd2;
++      unsigned char dl;
++      unsigned char dm;
++      unsigned char int_lt_lsb;
++      unsigned char int_lt_msb;
++      unsigned char int_ht_lsb;
++      unsigned char int_ht_msb;
++};
++
++// Digital Light
++#define SENSOR_DL_CMD                         (0x00)          // command
++      #define SENSOR_DL_CMD_ADC_EN            (0x80)          // enable ADC core
++      #define SENSOR_DL_CMD_ADC_DIS           (0x00)          // disable ADC core
++      #define SENSOR_DL_CMD_PD                (0x40)          // power down
++      #define SENSOR_DL_CMD_EXT_SYNC          (0x20)          // external sync
++      #define SENSOR_DL_CMD_MODE_D1           (0x00)          // ADC work mode = Diode 1, 16 bits
++      #define SENSOR_DL_CMD_MODE_D2           (0x04)          // ADC work mode = Diode 2, 16 bits
++      #define SENSOR_DL_CMD_MODE_DIFF         (0x08)          // ADC work mode = I1-I2, 15 bits
++      #define SENSOR_DL_CMD_W16               (0x00)          // 2^16 cycles
++      #define SENSOR_DL_CMD_W12               (0x01)          // 2^12 cycles
++      #define SENSOR_DL_CMD_W8                (0x02)          // 2^8 cycles
++      #define SENSOR_DL_CMD_W4                (0x03)          // 2^4 cycles
++#define SENSOR_DL_CONT                                (0x01)          // control
++      #define SENSOR_DL_CONT_INT              (0x20)          // interrupt status
++      #define SENSOR_DL_G1                    (0x00)          // gain < 1000 LUX
++      #define SENSOR_DL_G4                    (0x04)          // gain < 4000 LUX
++      #define SENSOR_DL_G16                   (0x08)          // gain < 16000 LUX
++      #define SENSOR_DL_G64                   (0x0C)          // gain < 64000 LUX
++      #define SENSOR_DL_IP1                   (0x00)          // interrupt persistence = 1 cycle
++      #define SENSOR_DL_IP4                   (0x01)          // interrupt persistence = 4 cycle
++      #define SENSOR_DL_IP8                   (0x02)          // interrupt persistence = 8 cycle
++      #define SENSOR_DL_IP16                  (0x03)          // interrupt persistence = 16 cycle
++#define SENSOR_DL_INT_THI                     (0x02)          //
++#define SENSOR_DL_INT_TLO                     (0x03)          //
++#define SENSOR_DL_SENSOR_LSB                  (0x04)          //
++#define SENSOR_DL_SENSOR_MSB                  (0x05)          //
++#define SENSOR_DL_TIMER_LSB                   (0x06)          //
++#define SENSOR_DL_TIMER_MSB                   (0x07)          //
++#define SENSOR_DL_EXT_SYNC                    (0x80)          //
++#define SENSOR_DL_INT_CLR                     (0x40)          //
++
++struct sensor_dl_rw { // see the datasheet
++      unsigned char cmd;
++      unsigned char control;
++      unsigned char int_thi;
++      unsigned char int_tlo;
++      unsigned int sensor_data;
++};
++
++// Temperature
++#define SENSOR_TEMP_LOC_MSB                   (0x00)          // Local temperature MSB
++#define SENSOR_TEMP_ROFF_HIGH                 (0x11)          // Remote offset high
++      // 10-bit plus sign format
++      #define SENSOR_TEMP_LOC_MSB_10B_SIGN    (0x80)          // Sign
++      #define SENSOR_TEMP_LOC_MSB_10B_64      (0x40)
++      #define SENSOR_TEMP_LOC_MSB_10B_32      (0x20)
++      #define SENSOR_TEMP_LOC_MSB_10B_16      (0x10)
++      #define SENSOR_TEMP_LOC_MSB_10B_8       (0x08)
++      #define SENSOR_TEMP_LOC_MSB_10B_4       (0x04)
++      #define SENSOR_TEMP_LOC_MSB_10B_2       (0x02)
++      #define SENSOR_TEMP_LOC_MSB_10B_1       (0x01)
++#define SENSOR_TEMP_LOC_LSB                   (0x30)          // Local temperature LSB
++#define SENSOR_TEMP_ROFF_LOW                  (0x12)          // Remote offset low
++      // 10-bit plus sign format
++      #define SENSOR_TEMP_LOC_LSB_10B_P5      (0x80)
++      #define SENSOR_TEMP_LOC_LSB_10B_P25     (0x40)
++      #define SENSOR_TEMP_LOC_LSB_10B_P125    (0x20)
++#define SENSOR_TEMP_REM_MSB                   (0x01)          // Remote temperature MSB
++      // 12-bit plus sign format
++      #define SENSOR_TEMP_REM_MSB_12B_SIGN    (0x80)          // Sign
++      #define SENSOR_TEMP_REM_MSB_12B_64      (0x40)
++      #define SENSOR_TEMP_REM_MSB_12B_32      (0x20)
++      #define SENSOR_TEMP_REM_MSB_12B_16      (0x10)
++      #define SENSOR_TEMP_REM_MSB_12B_8       (0x08)
++      #define SENSOR_TEMP_REM_MSB_12B_4       (0x04)
++      #define SENSOR_TEMP_REM_MSB_12B_2       (0x02)
++      #define SENSOR_TEMP_REM_MSB_12B_1       (0x01)
++#define SENSOR_TEMP_REM_LSB                   (0x10)          // Remote temperature LSB
++      // 12-bit plus sign format with filter off
++      #define SENSOR_TEMP_REM_LSB_12B_P5      (0x80)
++      #define SENSOR_TEMP_REM_LSB_12B_P25     (0x40)
++      #define SENSOR_TEMP_REM_LSB_12B_P125    (0x20)
++      // 12-bit plus sign format with filter on
++      #define SENSOR_TEMP_REM_LSB_12B_P0625   (0x10)
++      #define SENSOR_TEMP_REM_LSB_12B_P03125  (0x04)
++#define SENSOR_TEMP_UREM_MSB                  (0x31)          // Remote unsigned temperature MSB
++      // 13-bit usigned format
++      #define SENSOR_TEMP_UREM_MSB_12B_128    (0x80)
++      #define SENSOR_TEMP_UREM_MSB_12B_64     (0x40)
++      #define SENSOR_TEMP_UREM_MSB_12B_32     (0x20)
++      #define SENSOR_TEMP_UREM_MSB_12B_16     (0x10)
++      #define SENSOR_TEMP_UREM_MSB_12B_8      (0x08)
++      #define SENSOR_TEMP_UREM_MSB_12B_4      (0x04)
++      #define SENSOR_TEMP_UREM_MSB_12B_2      (0x02)
++      #define SENSOR_TEMP_UREM_MSB_12B_1      (0x01)
++#define SENSOR_TEMP_UREM_LSB                  (0x32)          // Remote unsigned temperature LSB
++      // 13-bit usigned format with filter off
++      #define SENSOR_TEMP_UREM_LSB_12B_P5     (0x80)
++      #define SENSOR_TEMP_UREM_LSB_12B_P25    (0x40)
++      #define SENSOR_TEMP_UREM_LSB_12B_P125   (0x20)
++      // 13-bit usigned format with filter on
++      #define SENSOR_TEMP_UREM_LSB_12B_P0625  (0x10)
++      #define SENSOR_TEMP_UREM_LSB_12B_P03125 (0x04)
++#define SENSOR_TEMP_CONF2                     (0xBF)          // Diode configuration
++      #define SENSOR_TEMP_CONF2_A0            (0x40)          // A0 pin function
++      #define SENSOR_TEMP_CONF2_OS            (0x00)          // A0 pin function
++      #define SENSOR_TEMP_CONF2_OS_ON         (0x20)          // OS fault mask on
++      #define SENSOR_TEMP_CONF2_OS_OFF        (0x00)          // OS fault mask off
++      #define SENSOR_TEMP_CONF2_TCRIT_ON      (0x10)          // TCRIT fault mask on
++      #define SENSOR_TEMP_CONF2_TCRIT_OFF     (0x00)          // TCRIT fault mask off
++      #define SENSOR_TEMP_CONF2_DMOD1         (0x00)          // Diode model 1
++      #define SENSOR_TEMP_CONF2_DMOD2         (0x08)          // Diode model 1
++      #define SENSOR_TEMP_CONF2_FILT_OFF      (0x00 << 1)     // Filter off
++      #define SENSOR_TEMP_CONF2_FILT_ON       (0x03 << 1)     // Filter on
++#define SENSOR_TEMP_CONF1_RD                  (0x03)          // General configuration
++#define SENSOR_TEMP_CONF1_WR                  (0x09)          // General configuration
++      #define SENSOR_TEMP_CONF1_RUN           (0x00)          // Active/Converting
++      #define SENSOR_TEMP_CONF1_STOP          (0x40)          // Standby
++      #define SENSOR_TEMP_R_TCRIT_MASK_OFF    (0x00)          // Remote TCRIT
++      #define SENSOR_TEMP_R_TCRIT_MASK_ON     (0x10)          // Remote TCRIT
++      #define SENSOR_TEMP_R_OS_MASK_OFF       (0x00)          // Remote OS
++      #define SENSOR_TEMP_R_OS_MASK_ON        (0x08)          // Remote OS
++      #define SENSOR_TEMP_L_TCRIT_MASK_OFF    (0x00)          // Local TCRIT
++      #define SENSOR_TEMP_L_TCRIT_MASK_ON     (0x04)          // Local TCRIT
++      #define SENSOR_TEMP_L_OS_MASK_OFF       (0x00)          // Local OS
++      #define SENSOR_TEMP_L_OS_MASK_ON        (0x02)          // Local OS
++#define SENSOR_TEMP_CONV_RD                   (0x04)          // Conversion rate
++#define SENSOR_TEMP_CONV_WR                   (0x0A)          // Conversion rate
++      #define SENSOR_TEMP_CONV_CONT           (0x00)          // Continuous
++      #define SENSOR_TEMP_CONV_P364           (0x01)          // .364 seconds
++      #define SENSOR_TEMP_CONV_1              (0x02)          // 1 second
++      #define SENSOR_TEMP_CONV_2P5            (0x03)          // 2.5 seconds
++#define SENSOR_TEMP_ONE_SHOT                  (0x0F)          // Remote offset low
++#define SENSOR_TEMP_STAT1                     (0x02)          // Status 1
++      #define SENSOR_TEMP_STAT1_BUSY          (0x80)          // Converting
++      #define SENSOR_TEMP_STAT1_ROS           (0x10)          // Remote OS
++      #define SENSOR_TEMP_STAT1_DFAULT        (0x04)          // Diode Fault
++      #define SENSOR_TEMP_STAT1_RTCRIT        (0x02)          // Remote TCRIT
++      #define SENSOR_TEMP_STAT1_LOC           (0x01)          // Local OS & TCRIT
++#define SENSOR_TEMP_STAT2                     (0x33)          // Status 2
++      #define SENSOR_TEMP_STAT2_NR            (0x80)          // Not Ready - 30 ms power-up
++      #define SENSOR_TEMP_STAT2_TT            (0x40)          // TruTherm Diode detected
++#define SENSOR_TEMP_REM_OS_LIM_RD             (0x07)          // Remote OS limit
++#define SENSOR_TEMP_REM_OS_LIM_WR             (0x0D)          // Remote OS limit
++#define SENSOR_TEMP_LOC_OS_LIM                        (0x20)          // Local OS limit
++#define SENSOR_TEMP_REM_TCRIT_LIM             (0x19)          // Remote T_Crit limit
++      #define SENSOR_TEMP_LIM_128             (0x80)
++      #define SENSOR_TEMP_LIM_64              (0x40)
++      #define SENSOR_TEMP_LIM_32              (0x20)
++      #define SENSOR_TEMP_LIM_16              (0x10)
++      #define SENSOR_TEMP_LIM_8               (0x08)
++      #define SENSOR_TEMP_LIM_4               (0x04)
++      #define SENSOR_TEMP_LIM_2               (0x02)
++      #define SENSOR_TEMP_LIM_1               (0x01)
++#define SENSOR_TEMP_HYSTERESIS                        (0x21)          // Common hysteresis
++      #define SENSOR_TEMP_HYS_16              (0x10)
++      #define SENSOR_TEMP_HYS_8               (0x08)
++      #define SENSOR_TEMP_HYS_4               (0x04)
++      #define SENSOR_TEMP_HYS_2               (0x02)
++      #define SENSOR_TEMP_HYS_1               (0x01)
++#define SENSOR_TEMP_MAN_ID                    (0xFE)          // Manufacture ID
++      #define SENSOR_TEMP_MAN_ID_DATA         (0x01)          // Manufacture ID
++#define SENSOR_TEMP_REV_ID                    (0xFF)          // Revision ID
++      #define SENSOR_TEMP_REV_ID_DATA         (0xB1)          // Revision ID
++
++struct sensor_temp_rw {       // see the datasheet
++      unsigned char address;
++      unsigned char d1;
++};
++
++// accelerometer
++// ADXL345
++#define SENSOR_ACC_ID                         (0x00)          // Device ID
++      #define SENSOR_ACC_ID_DATA              (0xE5)          // Device ID
++#define SENSOR_ACC_TT                         (0x1D)          // Tap threshold (62.5 mg/LSB)
++#define SENSOR_ACC_OFSX                               (0x1E)          // X axis offset (15.6 mg/LSB)
++#define SENSOR_ACC_OFSY                               (0x1F)          // Y axis offset (15.6 mg/LSB)
++#define SENSOR_ACC_OFSZ                               (0x20)          // Z axis offset (15.6 mg/LSB)
++#define SENSOR_ACC_DUR                                (0x21)          // Tap duration (625 us/LSB)
++#define SENSOR_ACC_LAT                                (0x22)          // Tap latency (1.25 ms/LSB)
++#define SENSOR_ACC_WIN                                (0x23)          // Tap window (1.25 ms/LSB)
++#define SENSOR_ACC_TAT                                (0x24)          // Activity threshold (62.5 mg/LSB)
++#define SENSOR_ACC_TINAT                      (0x25)          // Inactivity threshold (62.5 mg/LSB)
++#define SENSOR_ACC_TIM_INAT                   (0x26)          // Inactivity time (1 s/LSB)
++#define SENSOR_ACC_AT_CONTROL                 (0x27)          // Activity/Inactivity control
++      #define SENSOR_ACC_ATC_DC               (0x00)          // Active DC coupled
++      #define SENSOR_ACC_ATC_AC               (0x80)          // Active AC coupled
++      #define SENSOR_ACC_ATC_XE               (0x40)          // Active X enable
++      #define SENSOR_ACC_YTC_XE               (0x20)          // Active X enable
++      #define SENSOR_ACC_ZTC_XE               (0x10)          // Active X enable
++      #define SENSOR_ACC_ITC_DC               (0x00)          // Inactive DC coupled
++      #define SENSOR_ACC_ITC_AC               (0x08)          // Inactive AC coupled
++      #define SENSOR_ACC_ITC_XE               (0x04)          // Inactive X enable
++      #define SENSOR_ACC_ITC_YE               (0x02)          // Inactive Y enable
++      #define SENSOR_ACC_ITC_ZE               (0x01)          // Inactive Z enable
++#define SENSOR_ACC_T_FF                               (0x28)          // Freefall Threshold (62.5 mg/LSB)
++#define SENSOR_ACC_TIM_FF                     (0x29)          // Freefall Time (5 ms/LSB)
++#define SENSOR_ACC_TAP_AXES                   (0x2A)          // Tap Axis control
++      #define SENSOR_ACC_TA_SUPRESS           (0x08)          // Supress Double Tap
++      #define SENSOR_ACC_TA_XYZE              (0x07)          // X,Y,Z Tap Enable
++      #define SENSOR_ACC_TA_XE                (0x04)          // X Tap Enable
++      #define SENSOR_ACC_TA_YE                (0x02)          // Y Tap Enable
++      #define SENSOR_ACC_TA_ZE                (0x01)          // Z Tap Enable
++#define SENSOR_ACC_TAP_STAT                   (0x2B)          // Tap Status
++      #define SENSOR_ACC_TS_XA                (0x40)          // X Activity
++      #define SENSOR_ACC_TS_YA                (0x20)          // Y Activity
++      #define SENSOR_ACC_TS_ZA                (0x10)          // Z Activity
++      #define SENSOR_ACC_TS_XT                (0x04)          // X Tap
++      #define SENSOR_ACC_TS_YT                (0x02)          // Y Tap
++      #define SENSOR_ACC_TS_ZT                (0x01)          // Z Tap
++#define SENSOR_ACC_RATE                               (0x2C)          // Data Rate control
++      #define SENSOR_ACC_RATE_LP              (0x10)          // Low Power Mode
++      #define SENSOR_ACC_RC_3200_1600         (0x0F)          // _OUTPUT-DATA_BANDWIDTH
++      #define SENSOR_ACC_RC_1600_800          (0x0E)
++      #define SENSOR_ACC_RC_800_400           (0x0D)
++      #define SENSOR_ACC_RC_400_200           (0x0C)
++      #define SENSOR_ACC_RC_200_100           (0x0B)
++      #define SENSOR_ACC_RC_100_50            (0x0A)
++      #define SENSOR_ACC_RC_50_25             (0x09)
++      #define SENSOR_ACC_RC_25_12P5           (0x08)
++      #define SENSOR_ACC_RC_12P5_6P25         (0x07)
++      #define SENSOR_ACC_RC_6P25_3P125        (0x06)
++      #define SENSOR_ACC_RC_3P125_1P563       (0x05)
++      #define SENSOR_ACC_RC_1P563_P782        (0x04)
++      #define SENSOR_ACC_RC_P782_P39          (0x03)
++      #define SENSOR_ACC_RC_P39_P195          (0x02)
++      #define SENSOR_ACC_RC_P195_P098         (0x01)
++      #define SENSOR_ACC_RC_P098_P048         (0x00)
++#define SENSOR_ACC_POWER                      (0x2D)          // Power control
++      #define SENSOR_ACC_P_LINK               (0x20)          // Activity/Inactivity Link mode
++      #define SENSOR_ACC_P_APM                (0x10)          // Auto Low Power
++      #define SENSOR_ACC_P_SM                 (0x00)          // Standby
++      #define SENSOR_ACC_P_NORM               (0x08)          // Powered Up
++      #define SENSOR_ACC_P_SLEEP_NORM         (0x00)          // Not Sleep
++      #define SENSOR_ACC_P_SLEEP              (0x04)          // Sleep
++      #define SENSOR_ACC_P_W8                 (0x00)          // wakeup Frequency = 8 Hz
++      #define SENSOR_ACC_P_W4                 (0x01)          // wakeup Frequency = 4 Hz
++      #define SENSOR_ACC_P_W2                 (0x02)          // wakeup Frequency = 2 Hz
++      #define SENSOR_ACC_P_W1                 (0x03)          // wakeup Frequency = 1 Hz
++#define SENSOR_ACC_IE                         (0x2E)          // Interrupt Enable
++#define SENSOR_ACC_IM                         (0x2F)          // Interrupt Map
++#define SENSOR_ACC_IS                         (0x30)          // Interrupt Source
++      #define SENSOR_ACC_I_DR                 (0x80)          // Data Ready
++      #define SENSOR_ACC_I_ST                 (0x40)          // Single Tap
++      #define SENSOR_ACC_I_DT                 (0x20)          // Double Tap
++      #define SENSOR_ACC_I_A                  (0x10)          // Activity
++      #define SENSOR_ACC_I_I                  (0x08)          // Inactivity
++      #define SENSOR_ACC_I_FF                 (0x04)          // Freefall
++      #define SENSOR_ACC_I_WM                 (0x02)          // Watermark
++      #define SENSOR_ACC_I_OR                 (0x01)          // Overrun
++#define SENSOR_ACC_DF                         (0x31)          // Data Format
++      #define SENSOR_ACC_DF_SELF_TEST         (0x80)          // Self Test
++      #define SENSOR_ACC_DF_SPI_MODE4         (0x00)          // SPI 4-Wire
++      #define SENSOR_ACC_DF_SPI_MODE3         (0x40)          // SPI 3-Wire
++      #define SENSOR_ACC_DF_INT_INVERT        (0x20)          // Interrupt Active Low
++      #define SENSOR_ACC_DF_LENGTH            (0x08)          // 13-bit, 16g Enable
++      #define SENSOR_ACC_DF_POS               (0x04)          // MSB Left Justified
++      #define SENSOR_ACC_DF_R2                (0x00)          // 2g
++      #define SENSOR_ACC_DF_R4                (0x01)          // 4g
++      #define SENSOR_ACC_DF_R8                (0x02)          // 8g
++      #define SENSOR_ACC_DF_R16               (0x03)          // 16g
++#define SENSOR_ACC_DX0                                (0x32)          // Data X axis 0 (LSB)
++#define SENSOR_ACC_DX1                                (0x33)          // Data X axis 1 (MSB)
++#define SENSOR_ACC_DY0                                (0x34)          // Data Y axis 0 (LSB)
++#define SENSOR_ACC_DY1                                (0x35)          // Data Y axis 1 (MSB)
++#define SENSOR_ACC_DZ0                                (0x36)          // Data Z axis 0 (LSB)
++#define SENSOR_ACC_DZ1                                (0x37)          // Data Z axis 1 (MSB)
++#define SENSOR_ACC_FC                         (0x38)          // FIFO Control
++      #define SENSOR_ACC_FC_BYP               (0x00 << 6)     // Bypass
++      #define SENSOR_ACC_FC_HOLD              (0x01 << 6)     // Hold after 32
++      #define SENSOR_ACC_FC_OF                (0x02 << 6)     // Discard after 32
++      #define SENSOR_ACC_FC_TRIG              (0x03 << 6)     // Hold on TRIGGER
++      #define SENSOR_ACC_FC_TRIG1             (0x00)          // TRIGGER = INT1
++      #define SENSOR_ACC_FC_TRIG2             (0x20)          // TRIGGER = INT2
++      #define SENSOR_ACC_FC_SAMP(x)           (x)             // See ADXL345 datasheet
++#define SENSOR_ACC_FS                         (0x39)          // FIFO Status
++      #define SENSOR_ACC_FS_TRIG              (0x80)          // TRIGGER occurred
++      #define SENSOR_ACC_FS_ENTRIES_MSK       (0x1F)          // See ADXL345 datasheet
++
++// ST LIS302DL
++#define SENSOR_A3_WAI                         (0x0F)          // Device ID
++      #define SENSOR_A3_WAI_ID                (0x3B)          // Device ID
++#define SENSOR_A3_CTRL1                               (0x20)          // Control Register
++      #define SENSOR_A3_CTRL1_DR100           (0x00)          // sample data rate = 100 Hz
++      #define SENSOR_A3_CTRL1_DR400           (0x80)          // sample data rate = 400 Hz
++      #define SENSOR_A3_CTRL1_PD              (0x00)          // power down
++      #define SENSOR_A3_CTRL1_PU              (0x40)          // power up
++      #define SENSOR_A3_CTRL1_FS              (0x20)          // See data sheet
++      #define SENSOR_A3_CTRL1_STP             (0x10)          // See data sheet
++      #define SENSOR_A3_CTRL1_STM             (0x08)          // See data sheet
++      #define SENSOR_A3_CTRL1_XYZEN           (0x07)          // X,Y,Z axis enable
++      #define SENSOR_A3_CTRL1_ZEN             (0x04)          // Z axis enable
++      #define SENSOR_A3_CTRL1_YEN             (0x02)          // Y axis enable
++      #define SENSOR_A3_CTRL1_XEN             (0x01)          // X axis enable
++#define SENSOR_A3_CTRL2                               (0x21)          // Control Register
++      #define SENSOR_A3_CTRL2_SIM             (0x80)          // SPI mode
++      #define SENSOR_A3_CTRL2_BOOT            (0x40)          // copy calibration from FLASH
++      #define SENSOR_A3_CTRL2_FILT_OFF        (0x00)          // internal filter bypassed
++      #define SENSOR_A3_CTRL2_FILT_ON         (0x10)          // internal filter enabled
++      #define SENSOR_A3_CTRL2_F2              (0x08)          // WU2 filter enable
++      #define SENSOR_A3_CTRL2_F1              (0x04)          // WU1 filter enable
++      #define SENSOR_A3_CTRL2_COEFF(x)        (x & 0x3)       // See data sheet
++#define SENSOR_A3_CTRL3                               (0x22)          // Control Register
++      #define SENSOR_A3_CTRL3_IH              (0x00)          // Interrupt active high
++      #define SENSOR_A3_CTRL3_IL              (0x80)          // Interrupt active low
++      #define SENSOR_A3_CTRL3_IPP             (0x00)          // Interrupt push/pull
++      #define SENSOR_A3_CTRL3_IOD             (0x40)          // Interrupt open drain
++      #define SENSOR_A3_CTRL3_I2C(x)          ((x&0x7) << 3)  // I2 config - See data sheet
++      #define SENSOR_A3_CTRL3_I1C(x)          ((x&0x7))       // I1 config - See data sheet
++#define SENSOR_A3_HPF_RST                     (0x23)          // High Pass Filter Reset - See data sheet
++#define SENSOR_A3_STAT                                (0x27)          // Status
++      #define SENSOR_A3_STAT_ZYXOR            (0x80)          // ZYX overrun
++      #define SENSOR_A3_STAT_ZOR              (0x40)          // Z overrun
++      #define SENSOR_A3_STAT_YOR              (0x20)          // Y overrun
++      #define SENSOR_A3_STAT_XOR              (0x10)          // X overrun
++      #define SENSOR_A3_STAT_ZYXDA            (0x08)          // ZYX data available
++      #define SENSOR_A3_STAT_ZDA              (0x04)          // Z data available
++      #define SENSOR_A3_STAT_YDA              (0x02)          // Y data available
++      #define SENSOR_A3_STAT_XDA              (0x01)          // X data available
++#define SENSOR_A3_OUTX                                (0x29)          // X Output
++#define SENSOR_A3_OUTY                                (0x2B)          // Y Output
++#define SENSOR_A3_OUTZ                                (0x2D)          // Z Output
++#define SENSOR_A3_CFG1                                (0x30)          // Configuration
++#define SENSOR_A3_CFG2                                (0x34)          // Configuration
++      #define SENSOR_A3_CFG_AOI               (0x80)          // AND/OR interrupts
++      #define SENSOR_A3_CFG_LIR               (0x40)          // latch interrupts into SRC
++      #define SENSOR_A3_CFG_ZHIE              (0x20)          // Z high enable
++      #define SENSOR_A3_CFG_ZLIE              (0x10)          // Z low enable
++      #define SENSOR_A3_CFG_YHIE              (0x08)          // Y high enable
++      #define SENSOR_A3_CFG_YLIE              (0x04)          // Y low enable
++      #define SENSOR_A3_CFG_XHIE              (0x02)          // X high enable
++      #define SENSOR_A3_CFG_XLIE              (0x01)          // X low enable
++#define SENSOR_A3_SRC1                                (0x31)          // Source
++#define SENSOR_A3_SRC2                                (0x35)          // Source
++      #define SENSOR_A3_SRC_IA                (0x40)          // interrupt active
++      #define SENSOR_A3_SRC_ZH                (0x20)          // Z high
++      #define SENSOR_A3_SRC_ZL                (0x10)          // Z low
++      #define SENSOR_A3_SRC_YH                (0x08)          // Y high
++      #define SENSOR_A3_SRC_YL                (0x04)          // Y low
++      #define SENSOR_A3_SRC_XH                (0x02)          // X high
++      #define SENSOR_A3_SRC_XL                (0x01)          // X low
++#define SENSOR_A3_THS1                                (0x32)          // Threshold
++#define SENSOR_A3_THS2                                (0x36)          // Threshold
++      #define SENSOR_A3_THS_DCRM              (0x80)          // Resetting mode - See data sheet
++      #define SENSOR_A3_THS_THS(x)            (x & 0x7F)      // FF/wakeup threshold
++#define SENSOR_A3_DUR1                                (0x33)          // Duration - See data sheet
++#define SENSOR_A3_DUR2                                (0x37)          // Duration - See data sheet
++#define SENSOR_A3_CCFG                                (0x38)          // Click Configuration
++#define SENSOR_A3_CSRC                                (0x39)          // Click Source
++      #define SENSOR_A3_CCS_LIR               (0x40)          // latch interrupt into SRC
++      #define SENSOR_A3_CCS_DZ                (0x20)          // double Z enable
++      #define SENSOR_A3_CCS_SZ                (0x10)          // single Z enable
++      #define SENSOR_A3_CCS_DY                (0x08)          // double Y enable
++      #define SENSOR_A3_CCS_SY                (0x04)          // single Y enable
++      #define SENSOR_A3_CCS_DX                (0x02)          // double X enable
++      #define SENSOR_A3_CCS_SX                (0x01)          // single X enable
++#define SENSOR_A3_CTHXY                               (0x3B)          // Click X, Y Threshold
++      #define SENSOR_A3_CTHYX_Y(x)            ((x&0xF) << 4)  // Y Threshold
++      #define SENSOR_A3_CTHYX_X(x)            (x&0xF)         // X Threshold
++#define SENSOR_A3_CTHZ                                (0x3C)          // Click Z Threshold
++      #define SENSOR_A3_CTHYX_Z(x)            (x&0xF)         // Z Threshold
++#define SENSOR_A3_CTL                         (0x3D)          // Click Time Limit
++#define SENSOR_A3_CLAT                                (0x3E)          // Click Latency
++#define SENSOR_A3_CWIN                                (0x3F)          // Click Window
++
++// count always = 1 for LIS302DL
++struct sensor_acc_rw {        // see the datasheets
++      unsigned char address;
++      unsigned int count;     // number of bytes to read (1 or 2)
++      unsigned char data[2];
++};
++
++// digital compass
++#define SENSOR_DCOMP_ST                               (0xC0)          // Status (RO)
++      #define SENSOR_DCOMP_ST_INT             (0x01)          // Interrupt
++      #define SENSOR_DCOMP_ST_EERW            (0x02)          // EEPROM R/W
++#define SENSOR_DCOMP_TMPS                     (0xC1)          // Temperature(C) = 35+(120-TMPS)/1.6
++#define SENSOR_DCOMP_H1X                      (0xC2)          // X Heading
++#define SENSOR_DCOMP_H1Y                      (0xC3)          // Y Heading
++#define SENSOR_DCOMP_H1Z                      (0xC4)          // Z Heading
++#define SENSOR_DCOMP_MS1                      (0xE0)          // Mode
++      #define SENSOR_DCOMP_MS1_SENSOR         (0x0)           // sensor mode
++      #define SENSOR_DCOMP_MS1_EEPROM         (0x2)           // EEPROM R/W
++      #define SENSOR_DCOMP_MS1_PD             (0x3)           // power down
++      #define SENSOR_DCOMP_MS1_EEWEN          (0xA8)          // EEPROM Write Enable
++#define SENSOR_DCOMP_HXDA                     (0xE1)          // X DAC offset - see table 3 in datasheet
++#define SENSOR_DCOMP_HYDA                     (0xE2)          // Y DAC offset - see table 3 in datasheet
++#define SENSOR_DCOMP_HZDA                     (0xE3)          // Z DAC offset - see table 3 in datasheet
++#define SENSOR_DCOMP_HXGA                     (0xE4)          // X gain - see table 4 in datasheet
++#define SENSOR_DCOMP_HYGA                     (0xE5)          // Y gain - see table 4 in datasheet
++#define SENSOR_DCOMP_HZGA                     (0xE6)          // Z gain - see table 4 in datasheet
++#define SENSOR_DCOMP_TS1                      (0x5D)          // FACTORY TEST - DO NOT USE
++#define SENSOR_DCOMP_EE_WRAL1                 (0x60)          // EE - batch write adress
++#define SENSOR_DCOMP_EE_ETS                   (0x62)          // EE - temperature offset
++#define SENSOR_DCOMP_EE_EVIR                  (0x63)          // EE - VREF/IREF adjustment
++#define SENSOR_DCOMP_EE_EIHE                  (0x64)          // EE - HE drive/OSC
++#define SENSOR_DCOMP_EE_ETST                  (0x65)          // EE - test
++#define SENSOR_DCOMP_EE_EHXGA                 (0x66)          // EE - X gain adjustment
++#define SENSOR_DCOMP_EE_EHYGA                 (0x67)          // EE - Y gain adjustment
++#define SENSOR_DCOMP_EE_EHZGA                 (0x68)          // EE - Z gain adjustment
++
++// generic address/data byte R/W
++struct sensor_rw {
++      unsigned char address;
++      unsigned char data;
++};
++
++// Sensor driver ioctl definitions
++#define BMI_SENSOR_ON (1)
++#define BMI_SENSOR_OFF        (0)
++#define BMI_SENSOR_RLEDOFF    _IOW(BMI_SENSOR_IOCTL, 0x1, unsigned int)               // Turn off red LED
++#define BMI_SENSOR_RLEDON     _IOW(BMI_SENSOR_IOCTL, 0x2, unsigned int)               // Turn on red LED
++#define BMI_SENSOR_GLEDOFF    _IOW(BMI_SENSOR_IOCTL, 0x3, unsigned int)               // Turn off green LED
++#define BMI_SENSOR_GLEDON     _IOW(BMI_SENSOR_IOCTL, 0x4, unsigned int)               // Turn on green LED
++#define BMI_SENSOR_GETSTAT    _IOR(BMI_SENSOR_IOCTL, 0x5, unsigned int *)             // Read IOX/GPIO (== GPIO<<16 | IOX1<<8 | IOX0)
++#define BMI_SENSOR_ADCWR      _IOW(BMI_SENSOR_IOCTL, 0x6, unsigned int)               // write ADC
++#define BMI_SENSOR_ADCRD      _IOR(BMI_SENSOR_IOCTL, 0x7, unsigned int *)             // read ADC
++#define BMI_SENSOR_HUMRD      _IOR(BMI_SENSOR_IOCTL, 0x8, unsigned int *)             // read ADC - Humidity sensor
++#define BMI_SENSOR_ACOMPRST   _IO(BMI_SENSOR_IOCTL, 0x9)                              // analog Compass reset (toggle off/on)
++#define BMI_SENSOR_ACOMPXRD   _IOR(BMI_SENSOR_IOCTL, 0xa, unsigned int *)             // read ADC - Compass X axis
++#define BMI_SENSOR_ACOMPYRD   _IOR(BMI_SENSOR_IOCTL, 0xb, unsigned int *)             // read ADC - Compass Y axis
++#define BMI_SENSOR_ACOMPZRD   _IOR(BMI_SENSOR_IOCTL, 0xc, unsigned int *)             // read ADC - Compass Z axis
++#define BMI_SENSOR_PLWR               _IOW(BMI_SENSOR_IOCTL, 0xd, struct sensor_pl_rw *)      // write Proximity/Light sensor
++#define BMI_SENSOR_PLRD               _IOR(BMI_SENSOR_IOCTL, 0xe, struct sensor_pl_rw *)      // read Proximity/Light sensor
++#define BMI_SENSOR_PL_SYNC    _IO(BMI_SENSOR_IOCTL, 0xf)                              // generate external SYNC for Proximity/Light or Digital Light
++#define BMI_SENSOR_PL_IWAIT   _IOR(BMI_SENSOR_IOCTL, 0x10, struct sensor_pl_rw *)     // wait for Proximity/Light interrupt - application sets up INT configuration
++#define BMI_SENSOR_SNDARD     _IOR(BMI_SENSOR_IOCTL, 0x11, unsigned int *)            // read ADC - Sound Average level
++#define BMI_SENSOR_SNDPRD     _IOR(BMI_SENSOR_IOCTL, 0x12, unsigned int *)            // read ADC - Sound Peak level read/clear
++#define BMI_SENSOR_SNDIRD     _IOR(BMI_SENSOR_IOCTL, 0x13, unsigned int *)            // read ADC - Instantaneous level read/clear
++#define BMI_SENSOR_TEMPWR     _IOW(BMI_SENSOR_IOCTL, 0x14, struct sensor_temp_rw *)   // write Temperature sensor
++#define BMI_SENSOR_TEMPRD     _IOR(BMI_SENSOR_IOCTL, 0x15, struct sensor_temp_rw *)   // read Temperature sensor
++#define BMI_SENSOR_TEMPRD_SL  _IOR(BMI_SENSOR_IOCTL, 0x16, unsigned int *)            // Read signed local
++#define BMI_SENSOR_TEMPRD_SR  _IOR(BMI_SENSOR_IOCTL, 0x17, unsigned int *)            // Read signed remote
++#define BMI_SENSOR_TEMPRD_UR  _IOR(BMI_SENSOR_IOCTL, 0x18, unsigned int *)            // Read unsigned remote
++#define BMI_SENSOR_TEMP_IWAIT _IO(BMI_SENSOR_IOCTL, 0x19)                             // wait for Temperature interrupt - application sets up INT configuration
++#define BMI_SENSOR_MOTRD      _IOR(BMI_SENSOR_IOCTL, 0x1a, unsigned int *)            // read real-time Motion state
++#define BMI_SENSOR_MOT_IWAIT  _IOR(BMI_SENSOR_IOCTL, 0x1b, unsigned int *)            // wait for Motion interrupt
++#define BMI_SENSOR_ACCWR      _IOW(BMI_SENSOR_IOCTL, 0x1c, struct sensor_acc_rw *)    // write Accelerometer
++#define BMI_SENSOR_ACCRD      _IOR(BMI_SENSOR_IOCTL, 0x1d, struct sensor_acc_rw *)    // read Accelerometer
++#define BMI_SENSOR_ACCXRD     _IOR(BMI_SENSOR_IOCTL, 0x1e, unsigned int *)            // read Accelerometer X
++#define BMI_SENSOR_ACCYRD     _IOR(BMI_SENSOR_IOCTL, 0x1f, unsigned int *)            // read Accelerometer Y
++#define BMI_SENSOR_ACCZRD     _IOR(BMI_SENSOR_IOCTL, 0x20, unsigned int *)            // read Accelerometer Z
++#define BMI_SENSOR_ACC_I1WAIT _IO(BMI_SENSOR_IOCTL, 0x21)                             // wait for Accelerometer interrupt 1 - application sets up INT configuration
++#define BMI_SENSOR_ACC_I2WAIT _IO(BMI_SENSOR_IOCTL, 0x22)                             // wait for Accelerometer interrupt 2 - application sets up INT configuration
++#define BMI_SENSOR_EEWR               _IOW(BMI_SENSOR_IOCTL, 0x23, struct sensor_rw *)        // write EEPROM
++#define BMI_SENSOR_EERD               _IOR(BMI_SENSOR_IOCTL, 0x24, struct sensor_rw *)        // read EEPROM
++#define BMI_SENSOR_MOT_IE     _IOW(BMI_SENSOR_IOCTL, 0x25, unsigned int)              // Motion interrupt enable (on = BMI_SENSOR_ON)
++#define BMI_SENSOR_USB_IWAIT  _IO(BMI_SENSOR_IOCTL, 0x26)                             // wait for USB power flag interrupt
++#define BMI_SENSOR_USB_PWR_EN _IOW(BMI_SENSOR_IOCTL, 0x27, unsigned int)              // USB power enable (on = BMI_SENSOR_ON)
++#define BMI_SENSOR_HUM_PWR_EN _IOW(BMI_SENSOR_IOCTL, 0x28, unsigned int)              // Humidity power enable (on = BMI_SENSOR_ON)
++#define BMI_SENSOR_DCOM_RST   _IOW(BMI_SENSOR_IOCTL, 0x29, unsigned int)              // Digital Compass Reset (on = BMI_SENSOR_ON)
++#define BMI_SENSOR_COM_GCAL   _IOR(BMI_SENSOR_IOCTL, 0x2a, struct sensor_comp_cal *)  // Get compass calibation
++#define BMI_SENSOR_COM_SCAL   _IOW(BMI_SENSOR_IOCTL, 0x2b, struct sensor_comp_cal *)  // Set compass calibation
++#define BMI_SENSOR_DCWR               _IOW(BMI_SENSOR_IOCTL, 0x2c, struct sensor_rw *)        // write digital compass
++#define BMI_SENSOR_DCRD               _IOR(BMI_SENSOR_IOCTL, 0x2d, struct sensor_rw *)        // read digital compass
++#define BMI_SENSOR_DC_GDAC    _IOR(BMI_SENSOR_IOCTL, 0x2e, struct sensor_comp_dac *)  // Get digital compass DAC settings
++#define BMI_SENSOR_DC_SDAC    _IOW(BMI_SENSOR_IOCTL, 0x2f, struct sensor_comp_dac *)  // Set digital compass DAC settings
++#define BMI_SENSOR_DC_IWAIT   _IO(BMI_SENSOR_IOCTL, 0x30)                             // wait for digital compass interrupt - application sets up INT configuration
++#define BMI_SENSOR_APROX_DUR  _IOW(BMI_SENSOR_IOCTL, 0x31, unsigned int)              // Analog Proximity LED burst time (in ms 2 <= arg <= 100)
++#define BMI_SENSOR_APROXRD    _IOR(BMI_SENSOR_IOCTL, 0x32, unsigned int *)            // read Analog proximity = (PDOUT << 16) | ADC_DATA
++#define BMI_SENSOR_ALIGHTRD   _IOR(BMI_SENSOR_IOCTL, 0x33, unsigned int *)            // read Analog Light
++#define BMI_SENSOR_DLIGHTWR   _IOW(BMI_SENSOR_IOCTL, 0x34, struct sensor_dl_rw *)     // write Digital Light sensor
++#define BMI_SENSOR_DLIGHTRD   _IOR(BMI_SENSOR_IOCTL, 0x35, unsigned int)              // read Digital Light sensor
++#define BMI_SENSOR_DLIGHT_IC  _IO(BMI_SENSOR_IOCTL, 0x36)                             // Digital Light interrupt clear
++#define BMI_SENSOR_DLIGHT_IWAIT       _IOR(BMI_SENSOR_IOCTL, 0x37, struct sensor_dl_rw *)     // wait for Digital Light interrupt - application sets up INT configuration
++#define BMI_SENSOR_MIC_EN     _IOW(BMI_SENSOR_IOCTL, 0x38, unsigned int)              // Sound power enable (on = BMI_SENSOR_ON)
++
++#endif        /* BMI_SENSOR_H */
++
+--- /dev/null
++++ git/include/linux/bmi/bmi_vh.h
+@@ -0,0 +1,135 @@
++/*
++ * File:         include/linux/bmi/bmi_vh.h
++ * Author:       Peter Giacomini <p.giacomini@encadis.com>
++ *
++ *            This is the application header file for the BMI bus voh Hippel plug-in
++ *            module on the MX31 BUG platform.
++ */
++
++#ifndef BMI_VH_H
++#define BMI_VH_H
++
++#include <linux/bmi/bmi_ioctl.h>
++
++// GPIO
++#define VH_GPIO_RED_LED               3       // default to input
++#define VH_GPIO_GREEN_LED     2       // default to input
++#define VH_GPIO_1             1       // default to input
++#define VH_GPIO_0             0       // default to input
++
++#define VH_GPIO_LED_ON                0
++#define VH_GPIO_LED_OFF               1
++
++// I2C
++// I2C Slave Addresses
++#define BMI_IOX_I2C_ADDRESS   0x71    // 7-bit address
++#define VH_RDAC_I2C_ADDRESS   0x18    // 7-bit address
++#define VH_ADC_I2C_ADDRESS    0x24    // 7-bit address
++#define VH_DAC_I2C_ADDRESS    0x58    // 7-bit address
++
++// I2C IOX register addresses
++#define IOX_INPUT_REG         0x0
++#define IOX_OUTPUT_REG                0x1
++#define IOX_POLARITY_REG      0x2
++#define IOX_CONTROL           0x3
++
++#define       VH_IOX_USB_FLG_N        7       // Input - H=normal, L=fault
++#define       VH_IOX_USB_VEN          6       // output - H=power on, L=power off
++#define       VH_IOX_B5               5       // set to output driven high to prevent interrupts
++#define       VH_IOX_B4               4       // set to output driven high to prevent interrupts
++#define       VH_IOX_B3               3       // set to output driven high to prevent interrupts
++#define       VH_IOX_B2               2       // set to output driven high to prevent interrupts
++#define       VH_IOX_B1               1       // set to output driven high to prevent interrupts
++#define       VH_IOX_B0               0       // set to output driven high to prevent interrupts
++
++// programmable LDO digital resistor
++#define VH_RD_CMD_RDAC                0x00    // RDAC interface
++#define VH_RD_CMD_EE          0x20    // EEPROM interface
++      #define VH_TOL_HA       0x1E    // Tolerance MSB
++      #define VH_TOL_LA       0x1F    // Tolerance LSB
++#define VH_RD_CMD_WP          0x40    // EEPROM write protect
++#define VH_RD_CMD_NOP         0x80    // NOP
++#define VH_RD_CMD_ETOR                0xA0    // EEPROM -> RDAC
++#define VH_RD_CMD_RTOE                0xC0    // RDAC -> EEPROM
++
++// ADC
++#define VH_ADC_W1_EN          0xA0                    // Word 1 Enable
++#define VH_ADC_W1_CH01                0x00                    // diff - 0, 1
++#define VH_ADC_W1_CH23                0x01                    // diff - 2, 3
++#define VH_ADC_W1_CH10                0x08                    // diff - 1, 0
++#define VH_ADC_W1_CH32                0x09                    // diff - 3, 2
++#define VH_ADC_W1_CH0         0x10                    // single-ended - 0
++#define VH_ADC_W1_CH1         0x18                    // single-ended - 1
++#define VH_ADC_W1_CH2         0x11                    // single-ended - 2
++#define VH_ADC_W1_CH3         0x19                    // single-ended - 3
++#define VH_ADC_W2_EN          0x80                    // Word 2 Enable
++#define VH_ADC_W2_IM          0x40                    // internal temp
++#define VH_ADC_W2_F(x)                (((x) % 0x3) << 4)      // rejection mode
++#define VH_ADC_W2_SPD         0x08                    // speed 2X
++#define VH_ADC_W2_G(x)                ((x) % 0x7)             // gain
++
++struct vh_adc_wr {    // see the datasheet
++      unsigned char w1;       // VH_ADC_W1_*
++      unsigned char w2;       // VH_ADC_W2_*
++};
++
++// DAC
++#define VH_DAC_W1_UA          0x00    // update DAC A output
++#define VH_DAC_W1_UB          0x10    // update DAC B output
++#define VH_DAC_W1_LA          0x40    // load DAC A input
++#define VH_DAC_W1_LB          0x50    // load DAC B input
++#define VH_DAC_W1_ALLA                0x80    // load DAC A input, update all outputs
++#define VH_DAC_W1_ALLB                0x90    // load DAC B input, update all outputs
++#define VH_DAC_W1_ALL         0xC0    // load all inputs, update all outputs
++#define VH_DAC_W1_ALLI                0xD0    // load all inputs
++#define VH_DAC_W1_UALL                0xE0    // update all - don't send data
++#define VH_DAC_W1_EC          0xF0    // Extended command
++      #define VH_DAC_BCH      0x0C    // both channel A & B
++      #define VH_DAC_CHB      0x08    // channel B
++      #define VH_DAC_CHA      0x04    // channel A
++      #define VH_DAC_PD100K   0x03    // power down - 100K pull down
++      #define VH_DAC_PD1K     0x02    // power down - 1K pull down
++      #define VH_DAC_PDF      0x01    // power down - float
++      #define VH_DAC_PU       0x00    // power up
++#define VH_DAC_W1_RDA         0xF1    // Read A
++#define VH_DAC_W1_RDB         0xF2    // Read B
++
++struct vh_dac_wr {
++      unsigned char w1;       // cmd | d[7:3]
++      unsigned char w2;       // (d[3:0] << 4) || (VH_DAC_CH* | VH_DAC_P*)
++};
++
++// SPI
++#define BUF_MAX_SIZE  (20)
++
++// SPI transfer structure
++struct spi_xfer {
++      unsigned char addr;
++      unsigned char data[2];
++} spi_xfer;
++
++// von hippel driver ioctl definitions
++#define BMI_VH_RLEDOFF                _IOW(BMI_VH_IOCTL, 0x1, unsigned int)           // Turn off red LED
++#define BMI_VH_RLEDON         _IOW(BMI_VH_IOCTL, 0x2, unsigned int)           // Turn on red LED
++#define BMI_VH_GLEDOFF                _IOW(BMI_VH_IOCTL, 0x3, unsigned int)           // Turn off green LED
++#define BMI_VH_GLEDON         _IOW(BMI_VH_IOCTL, 0x4, unsigned int)           // Turn on green LED
++#define BMI_VH_GETSTAT                _IOR(BMI_VH_IOCTL, 0x5, unsigned int *)         // READ IOX register
++#define BMI_VH_MKGPIO_OUT     _IOW(BMI_VH_IOCTL, 0x6, unsigned int)           // make a GPIO bit an output
++#define BMI_VH_MKGPIO_IN      _IOW(BMI_VH_IOCTL, 0x7, unsigned int)           // make a GPIO bit an input
++#define BMI_VH_SETGPIO                _IOW(BMI_VH_IOCTL, 0x8, unsigned int)           // set a GPIO output to 1
++#define BMI_VH_CLRGPIO                _IOW(BMI_VH_IOCTL, 0x9, unsigned int)           // set a GPIO output to 0
++#define BMI_VH_MKIOX_OUT      _IOW(BMI_VH_IOCTL, 0xa, unsigned int)           // make a IOX bit an output
++#define BMI_VH_MKIOX_IN               _IOW(BMI_VH_IOCTL, 0xb, unsigned int)           // make a IOX bit an input
++#define BMI_VH_SETIOX         _IOW(BMI_VH_IOCTL, 0xc, unsigned int)           // set a IOX output to 1
++#define BMI_VH_CLRIOX         _IOW(BMI_VH_IOCTL, 0xd, unsigned int)           // set a IOX output to 0
++#define BMI_VH_SETRDAC                _IOW(BMI_VH_IOCTL, 0xe, unsigned int)           // set LDO RDAC resistance
++#define BMI_VH_RDRDAC         _IOW(BMI_VH_IOCTL, 0xf, unsigned int *)         // read LDO RDAC resistance
++#define BMI_VH_ADCWR          _IOW(BMI_VH_IOCTL, 0x10, struct vh_adc_wr *)    // write ADC
++#define BMI_VH_ADCRD          _IOW(BMI_VH_IOCTL, 0x11, unsigned int *)        // read ADC
++#define BMI_VH_DACWR          _IOW(BMI_VH_IOCTL, 0x12, struct vh_dac_wr *)    // write DAC
++#define BMI_VH_DACRD          _IOW(BMI_VH_IOCTL, 0x13, unsigned int *)        // read DAC
++#define BMI_VH_READ_SPI               _IOR(BMI_VH_IOCTL, 0x14, struct spi_xfer *)     // read SPI - requires SPI EEPROM
++#define BMI_VH_WRITE_SPI      _IOR(BMI_VH_IOCTL, 0x15, struct spi_xfer *)     // write SPI - requires SPI EEPROM
++
++#endif        /* BMI_VH_H */
++
+--- /dev/null
++++ git/include/linux/bmi/bmi_zb.h
+@@ -0,0 +1,83 @@
++/*
++ * File:    include/linux/bmi/bmi_gps.h
++ * Author:  V. Thavisri <v.thavisri@encadis.com
++ *
++ * This is the application header file for the BMI ZigBee plug-in
++ * module on the MX31 BUG platform.
++ */
++
++#ifndef BMI_ZBCNTL_H
++#define BMI_ZBCNTL_H
++
++#include <linux/bmi/bmi_ioctl.h>
++#include <linux/sockios.h>
++
++/* IOCTL commands for BMI ZB driver - char device portion */
++
++#define BMI_ZB_RLEDOFF            _IO(BMI_ZIGBEE_IOCTL, 0x1)
++#define BMI_ZB_RLEDON             _IO(BMI_ZIGBEE_IOCTL, 0x2)
++#define BMI_ZB_GLEDOFF            _IO(BMI_ZIGBEE_IOCTL, 0x3)
++#define BMI_ZB_GLEDON             _IO(BMI_ZIGBEE_IOCTL, 0x4)
++#define BMI_ZB_RESET              _IO(BMI_ZIGBEE_IOCTL, 0x5)
++#define BMI_ZB_SPI_SIG            _IO(BMI_ZIGBEE_IOCTL, 0x6)
++#define BMI_ZB_LOOPBACK           _IO(BMI_ZIGBEE_IOCTL, 0x7)
++#define BMI_ZB_STARTREQ           _IO(BMI_ZIGBEE_IOCTL, 0x8)
++#define BMI_ZB_UPDATE_STATE       _IO(BMI_ZIGBEE_IOCTL, 0x9)
++
++
++/* IOCTL commands for BMI ZB driver - network device portion */
++
++#define SIOCSAPPREGISTER       (SIOCDEVPRIVATE + 1)
++#define SIOCSALLOWBIND         (SIOCDEVPRIVATE + 2)
++#define SIOCSPERMITJOINING     (SIOCDEVPRIVATE + 3)
++#define SIOCGDEVICEINFO        (SIOCDEVPRIVATE + 4)
++#define SIOCSRESET             (SIOCDEVPRIVATE + 5)
++#define SIOCSBIND              (SIOCDEVPRIVATE + 6)
++#define SIOCSZCOMMAND          (SIOCDEVPRIVATE + 7)
++#define SIOCSSTARTREQ          (SIOCDEVPRIVATE + 8)
++#define SIOCSFINDDEVICE        (SIOCDEVPRIVATE + 9)
++#define SIOCSAFREGISTER        (SIOCDEVPRIVATE + 10)
++#define SIOCSPOWERAMP          (SIOCDEVPRIVATE + 11)
++#define SIOCDEBUG              (SIOCDEVPRIVATE + 15)
++
++struct sockaddr_zb
++{
++      unsigned short z_family;
++      int            z_ifindex;
++      unsigned char  z_name[15];
++      unsigned short z_protocol;
++};
++
++/* move this #define to include/linux/socket.h */
++#define SOL_ZACCEL 275
++
++#define Z_PACKET_SOCK  0
++#define Z_CONTROL_SOCK 1
++#define Z_NUM_SOCK     2
++#define Z_NO_SOCK      0xFF
++
++/* Device-Specification Configuration Parameters */
++#define ZCD_NV_STARTUP_OPTION             0x03
++#define ZCD_NV_LOGICAL_TYPE               0x87
++#define ZCD_NV_POLL_RATE                  0x24
++#define ZCD_NV_QUEUED_POLL_RATE           0x25
++#define ZCD_NV_RESPONSE_POLL_RATE         0x26
++#define ZCD_NV_POLL_FAILURE_RETRIES       0x29
++#define ZCD_NV_INDIRECT_MSG_TIMEOUT       0x2B
++#define ZCD_NV_APS_FRAME_RETRIES          0x43
++#define ZCD_NV_APS_ACK_WAIT_DURATION      0x44
++#define ZCD_NV_BINDING_TIME               0x46
++#define ZCD_NV_USERDESC                   0x81
++
++// Network-Specification Configuration Parameters
++#define ZCD_NV_PANID                      0x83
++#define ZCD_NV_CHANLIST                   0x84
++#define ZCD_NV_PRECFGKEY                  0x62
++#define ZCD_NV_PRECFGKEYS_ENABLE          0x63
++#define ZCD_NV_SECURITY_MODE              0x64
++#define ZCD_NV_BCAST_RETRIES              0x2E
++#define ZCD_NV_PASSIVE_ACK_TIMEOUT        0x2F
++#define ZCD_NV_BCAST_DELIVERY_TIME        0x30
++#define ZCD_NV_ROUTE_EXPIRY_TIME          0x2C
++
++#endif /* BMI_ZBCNTL_H */
+--- git.orig/include/linux/mod_devicetable.h
++++ git/include/linux/mod_devicetable.h
+@@ -341,10 +341,23 @@ struct eisa_device_id {
+       kernel_ulong_t driver_data;
+ };
+ #define EISA_DEVICE_MODALIAS_FMT "eisa:s%s"
++/* Bug Labs BeagleBug */
++
++struct bmi_device_id {
++  __u16 match_flags;
++  __u16 vendor;
++  __u16 product;
++  __u16 revision;
++};
++
++#define BMI_DEVICE_ID_MATCH_VENDOR    (1)
++#define BMI_DEVICE_ID_MATCH_PRODUCT   (2)
++#define BMI_DEVICE_ID_MATCH_REVISION  (4)
++
+ struct parisc_device_id {
+       __u8    hw_type;        /* 5 bits used */
+       __u8    hversion_rev;   /* 4 bits */
+       __u16   hversion;       /* 12 bits */
+       __u32   sversion;       /* 20 bits */
+--- git.orig/scripts/mod/file2alias.c
++++ git/scripts/mod/file2alias.c
+@@ -286,10 +286,26 @@ static int do_pci_entry(const char *file
+       ADD(alias, "i", interface_mask == 0xFF, interface);
+       add_wildcard(alias);
+       return 1;
+ }
++/* Looks like: bmi:vNpNrN. */
++static int do_bmi_entry(const char *filename,
++                      struct bmi_device_id *id, char *alias)
++{
++      id->match_flags = TO_NATIVE(id->match_flags);
++      id->vendor = TO_NATIVE(id->vendor);
++      id->product = TO_NATIVE(id->product);
++      id->revision = TO_NATIVE(id->revision);
++
++      strcpy(alias, "bmi:");
++      ADD(alias, "v", id->match_flags & BMI_DEVICE_ID_MATCH_VENDOR, id->vendor);
++      ADD(alias, "p", id->match_flags & BMI_DEVICE_ID_MATCH_PRODUCT, id->product);
++      ADD(alias, "r", id->match_flags & BMI_DEVICE_ID_MATCH_REVISION, id->revision);
++      return 1;
++}
++
+ /* looks like: "ccw:tNmNdtNdmN" */
+ static int do_ccw_entry(const char *filename,
+                       struct ccw_device_id *id, char *alias)
+ {
+       id->match_flags = TO_NATIVE(id->match_flags);
+@@ -779,10 +795,14 @@ void handle_moddevtable(struct module *m
+                        do_hid_entry, mod);
+       else if (sym_is(symname, "__mod_ieee1394_device_table"))
+               do_table(symval, sym->st_size,
+                        sizeof(struct ieee1394_device_id), "ieee1394",
+                        do_ieee1394_entry, mod);
++      else if (sym_is(symname, "__mod_bmi_device_table"))
++              do_table(symval, sym->st_size,
++                       sizeof(struct bmi_device_id), "bmi",
++                       do_bmi_entry, mod);
+       else if (sym_is(symname, "__mod_ccw_device_table"))
+               do_table(symval, sym->st_size,
+                        sizeof(struct ccw_device_id), "ccw",
+                        do_ccw_entry, mod);
+       else if (sym_is(symname, "__mod_ap_device_table"))
index 18382b6..56e6107 100644 (file)
@@ -172,6 +172,7 @@ SRC_URI_append_beagleboard = " file://logo_linux_clut224.ppm \
                                           file://beagle-asoc.patch;patch=1 \
                                file://tincantools-puppy.diff;patch=1 \
                                file://tincantools-zippy.diff;patch=1 \
+                              file://beaglebug/beaglebug-full.patch;patch=1 \
 "
 
 SRC_URI_append_omap3evm = " \