aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarcin Juszkiewicz <marcin@buglabs.net>2009-09-09 10:55:18 +0200
committerMarcin Juszkiewicz <marcin@juszkiewicz.com.pl>2009-09-09 11:26:11 +0200
commit30c1e63389bb65008f8fec09ff5e12b19609c3e8 (patch)
treeb38cb65a2caba22339a02fc2e9adcc62143f375b
parent3e0e303e7ad1c6e34a446e37c7ba8fcfb3b72125 (diff)
downloadopenembedded-30c1e63389bb65008f8fec09ff5e12b19609c3e8.tar.gz
linux-omap: added support for BeagleBUG extension board
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.
-rw-r--r--conf/machine/include/omap3.inc2
-rw-r--r--recipes/linux/linux-omap-2.6.29/beagleboard/defconfig24
-rw-r--r--recipes/linux/linux-omap-2.6.29/beaglebug/beaglebug-full.patch35774
-rw-r--r--recipes/linux/linux-omap_2.6.29.bb1
4 files changed, 35798 insertions, 3 deletions
diff --git a/conf/machine/include/omap3.inc b/conf/machine/include/omap3.inc
index 889e0f6478..c52cbddf18 100644
--- a/conf/machine/include/omap3.inc
+++ b/conf/machine/include/omap3.inc
@@ -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"
diff --git a/recipes/linux/linux-omap-2.6.29/beagleboard/defconfig b/recipes/linux/linux-omap-2.6.29/beagleboard/defconfig
index c9f8e9962b..a1848d59a4 100644
--- a/recipes/linux/linux-omap-2.6.29/beagleboard/defconfig
+++ b/recipes/linux/linux-omap-2.6.29/beagleboard/defconfig
@@ -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
index 0000000000..f556f420e4
--- /dev/null
+++ b/recipes/linux/linux-omap-2.6.29/beaglebug/beaglebug-full.patch
@@ -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 @@
++#
++# BMI PIMS
++#
++
++obj-$(CONFIG_VIDEO_BMI_PROJECTOR) += bmi_projector_core.o
++bmi_projector_core-objs := bmi_projector.o ch7024.o
++
+--- /dev/null
++++ git/drivers/bmi/pims/projector/bmi_projector.c
+@@ -0,0 +1,674 @@
++/*
++ * bmi_projector.c
++ *
++ * BMI PROJECTOR device driver
++ *
++ * Derived from: bmi_lcd.c
++ */
++
++/*
++ * 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 <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_projector.h>
++#include <mach/ipu.h>
++
++#include "ch7024.h"
++
++#define DEBUG_PROJECTOR
++#undef DEBUG_PROJECTOR
++
++#define BMIPROJECTOR_VERSION "1.0" // driver version
++#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
++#define PROJ_DEF_MODE 0x09 // Projector default mode of operation
++
++ // projector
++struct projector_interface {
++ char projector_type[MAX_STRG]; // text description of PROJECTOR 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 projector_interface projector_interface = {
++ .projector_type = "MXCFB_PROJECTOR",
++ .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 Projector driver
++};
++
++extern void projector_config(int disp);
++extern int projector_disp_on(int disp);
++extern int projector_disp_regset(int disp, unsigned short reg, unsigned short val);
++
++struct bmi_projector;
++static int disp_mode_reg = 0x09; // Bit 3 of GPIO control register should always be maintained high
++//static int proj_mode = 0x1; // Bit 3 of GPIO control register should always be maintained high
++
++struct bmi_projector_ops {
++ void *(*config) (int disp); // Projector configuration/initialization
++ void *(*reset) (int slot); // Projector reset
++ int *(*suspend) (struct bmi_projector *bprojector); // power management
++ int *(*resume) (struct bmi_projector *bprojector); // power management
++ int *(*disp_on) (int disp); // display on
++ int *(*disp_off) (int disp); // display off
++ int (*activate) (struct bmi_projector *projector, int slot); // enable Projector
++ int (*deactivate) (struct bmi_projector *projector, int slot); // disable Projector
++};
++
++struct bmi_projector_ops bmi_projector_ops;
++
++struct bmi_projector {
++ struct projector_interface interface; // pointer to this struct is returned by config()
++ struct bmi_projector_ops projector_ops; // function pointers
++};
++
++static struct bmi_projector bmi_projector;
++
++int register_bmi_projector(struct bmi_projector *bprojector, int slot);
++int unregister_bmi_projector(struct bmi_projector *bprojector, int slot);
++
++ // private device structure
++struct pbmi_projector
++{
++ int open_flag; // force single open
++ unsigned int projector_cnt; // number of Projector's present
++ unsigned int active; // indication of Projector's presence
++ unsigned int activated[BMI_SLOT_NUM]; // indication of Projector's presence
++ int proj_mode[BMI_SLOT_NUM]; // Indicate the state of projector on the slot
++ //int disp_mode_reg[BMI_SLOT_NUM];
++
++ struct bmi_projector *bprojector[BMI_SLOT_NUM]; // BMI Projector 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
++};
++
++static struct pbmi_projector pbmi_projector; // Projector device sructure
++
++/*
++ * BMI set up
++ */
++
++ // BMI device ID table
++static struct bmi_device_id bmi_projector_tbl[] =
++{
++ {
++ .match_flags = BMI_DEVICE_ID_MATCH_VENDOR | BMI_DEVICE_ID_MATCH_PRODUCT,
++ .vendor = BMI_VENDOR_BUG_LABS,
++ .product = BMI_PRODUCT_PROJECTOR,
++ .revision = BMI_ANY,
++ },
++ { 0, }, /* terminate list */
++};
++
++MODULE_DEVICE_TABLE(bmi, bmi_projector_tbl);
++
++int bmi_projector_probe(struct bmi_device *bdev);
++void bmi_projector_remove(struct bmi_device *bdev);
++
++// BMI driver structure
++static struct bmi_driver bmi_projector_driver =
++{
++ .name = "bmi_projector",
++ .id_table = bmi_projector_tbl,
++ .probe = bmi_projector_probe,
++ .remove = bmi_projector_remove,
++};
++
++void bmi_projector_config(struct bmi_projector *projector, int disp);
++
++ // probe
++int bmi_projector_probe(struct bmi_device *bdev)
++{
++ int slot = bdev->info->slot;
++ struct i2c_adapter *adap;
++ struct bmi_projector *projector;
++ /*int first_time = 1;*/
++
++ printk(KERN_INFO "bmi_projector.c: probe slot %d\n", slot);
++
++ // check for opposite side already active
++ switch(slot) { // opposite side
++ case 0:
++ if(pbmi_projector.activated[2] == 1) {
++ printk(KERN_INFO "bmi_projector.c: probe slot %d not allowed (slot 2 already active)\n", slot);
++ bmi_slot_power_off(0);
++ pbmi_projector.bdev[0] = bdev;
++ return 0;
++ }
++ break;
++ case 1:
++ if(pbmi_projector.activated[3] == 1) {
++ printk(KERN_INFO "bmi_projector.c: probe slot %d not allowed (slot 3 already active)\n", slot);
++ bmi_slot_power_off(1);
++ pbmi_projector.bdev[1] = bdev;
++ return 0;
++ }
++ break;
++ case 2:
++ if(pbmi_projector.activated[0] == 1) {
++ printk(KERN_INFO "bmi_projector.c: probe slot %d not allowed (slot 0 already active)\n", slot);
++ bmi_slot_power_off(2);
++ pbmi_projector.bdev[2] = bdev;
++ return 0;
++ }
++ break;
++ case 3:
++ if(pbmi_projector.activated[1] == 1) {
++ printk(KERN_INFO "bmi_projector.c: probe slot %d not allowed (slot 1 already active)\n", slot);
++ bmi_slot_power_off(3);
++ pbmi_projector.bdev[3] = bdev;
++ return 0;
++ }
++ break;
++ }
++
++ adap = &bdev->adap;
++
++// bmi_slot_power_on(slot);
++
++ mdelay(500);
++
++ if (!ch7024_detect (adap))
++ {
++ /* setup for NTSC */
++ ch7024_setup (adap, PROJOUT_FMT_NTSC);
++#ifdef DEBUG_PROJECTOR
++ printk ("\nFound encoder on slot %d \n", slot);
++#endif
++ ch7024_enable (adap);
++ }
++ else
++ {
++ printk ("\nError! Failed to detect encoder chip\n");
++ return 0;
++ }
++
++ // reset serial link (master)
++ if((slot == 0) || (slot == 2)) {
++ bmi_lcd_inactive(0); // We are using Same CPLD pins for projector
++ } else {
++ bmi_lcd_inactive(1);
++ }
++
++ // FPGA PROG_0 - Active low signal
++ bmi_set_module_gpio_data(slot, 0, 0);
++ bmi_set_module_gpio_dir(slot, 0, BMI_GPIO_OUT);
++
++ /* Reset the FPGA */
++ bmi_set_module_gpio_data(slot, 1, 1);
++ bmi_set_module_gpio_dir(slot, 0, BMI_GPIO_OUT);
++ mdelay(100);
++ bmi_set_module_gpio_data(slot, 1, 0);
++
++ // 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_projector pointers
++ bmi_device_set_drvdata(bdev, &pbmi_projector);
++ pbmi_projector.bdev[slot] = bdev;
++
++ // complete pbmi_projector set-up
++ pbmi_projector.projector_cnt++;
++ pbmi_projector.active = 1;
++ pbmi_projector.activated[slot] = 1;
++ pbmi_projector.proj_mode[slot] = 1;
++
++ mdelay(100);
++
++ projector = pbmi_projector.bprojector[slot];
++ if((slot == 0) || (slot == 2)) {
++ mdelay(2);
++ bmi_projector_config(projector, 0);
++ mdelay(2);
++ } else {
++ mdelay(2);
++ bmi_projector_config(projector, 1);
++ mdelay(2);
++ }
++
++ // Turn on Projctor
++ disp_mode_reg = PROJ_DEF_MODE;
++ projector_disp_regset((slot & 0x1), 0x1, disp_mode_reg);
++ // check GPIO status
++ printk(KERN_INFO "bmi_projector.c: slot %d gpio = %x\n", slot, bmi_read_gpio_data_reg(slot));
++ printk(KERN_INFO "bmi_projector.c: Projector count = %d\n", pbmi_projector.projector_cnt);
++
++ return 0;
++}
++
++ // remove
++void bmi_projector_remove(struct bmi_device *bdev)
++{
++ int slot = bdev->info->slot;
++
++ if(pbmi_projector.activated[slot] == 0)
++ return;
++
++ 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);
++
++ //de-attach driver-specific struct from bmi_device structure
++ bmi_device_set_drvdata (bdev, NULL);
++
++ // deactivate
++ pbmi_projector.activated[slot] = 0;
++ pbmi_projector.bdev[slot] = 0;
++ pbmi_projector.projector_cnt--;
++
++ if((pbmi_projector.activated[0] == 0) && (pbmi_projector.activated[2] == 0)) {
++ bmi_lcd_inactive(0); // disable serializer
++ }
++
++ if((pbmi_projector.activated[1] == 0) && (pbmi_projector.activated[3] == 0)) {
++ bmi_lcd_inactive(1); // disable serializer
++ }
++
++ if((pbmi_projector.activated[0] == 0) && (pbmi_projector.activated[1] == 0) &&
++ (pbmi_projector.activated[2] == 0) && (pbmi_projector.activated[3] == 0)) {
++ pbmi_projector.active = -1;
++ }
++
++ // enable Projector on opposite side
++ switch(slot) {
++ case 0:
++ if(pbmi_projector.bdev[2] != 0)
++ bmi_projector_probe(pbmi_projector.bdev[2]);
++ break;
++ case 1:
++ if(pbmi_projector.bdev[3] != 0)
++ bmi_projector_probe(pbmi_projector.bdev[3]);
++ break;
++ case 2:
++ if(pbmi_projector.bdev[0] != 0)
++ bmi_projector_probe(pbmi_projector.bdev[0]);
++ break;
++ case 3:
++ if(pbmi_projector.bdev[1] != 0)
++ bmi_projector_probe(pbmi_projector.bdev[1]);
++ break;
++ }
++
++ printk(KERN_INFO "bmi_projector.c: projector count = %d\n", pbmi_projector.projector_cnt);
++
++ return;
++}
++
++/*
++ * control device operations
++ */
++
++/*
++ * control device operations
++ */
++
++// open
++int cntl_open(struct inode *inode, struct file *filp)
++{
++ if(pbmi_projector.open_flag) {
++ return - EBUSY;
++ }
++ pbmi_projector.open_flag = 1;
++ filp->private_data = &pbmi_projector;
++ return 0;
++}
++
++// release
++int cntl_release(struct inode *inode, struct file *filp)
++{
++ pbmi_projector.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;
++ int slot = (__user arg) & 0xF;
++ int disp = 0;
++ int ret = 0;
++
++ // error if no projector active.
++ if(pbmi_projector.active == -1)
++ return -ENODEV;
++
++ // error if slot invalid
++ if((slot < CPLD_M1) || (slot > CPLD_M4))
++ return -ENODEV;
++
++ disp = slot & 0x1; // disp=0 for Slot 0 and 2, disp=1 for 1 and 3
++#ifdef DEBUG_PROJECTOR
++ printk (KERN_INFO "Slot No is:%d\n", slot);
++ printk (KERN_INFO "Disp No is:%d\n", disp);
++#endif
++
++ // error if no projector in chosen slot
++ if(pbmi_projector.bdev[slot] == 0)
++ return -ENODEV;
++
++ // i2c adapter
++ adap = &pbmi_projector.bdev[slot]->adap;
++
++ if( (cmd != BMI_PROJECTOR_ON) && (pbmi_projector.proj_mode[slot]/*proj_mode*/ == 0) )
++ {
++ printk(KERN_ERR "Project is in OFF state !!!\n");
++ return -EINVAL;
++ }
++
++ // ioctl's
++ switch (cmd) {
++ case BMI_PROJECTOR_ON:
++ {
++ printk(KERN_INFO "BMI_PROJECTOR turning on\n");
++ disp_mode_reg &= ~(0x3);
++ disp_mode_reg |= 0x1;
++ ch7024_enable(adap);
++ projector_disp_regset(disp, 0x1, disp_mode_reg);
++ mdelay(100);
++ projector_disp_regset(disp, 0x0, 0x1);
++ //proj_mode = 0x1;
++ pbmi_projector.proj_mode[slot] = 0x1;
++ }
++ break;
++
++ case BMI_PROJECTOR_MODE:
++ {
++ int mode = ((__user arg) & 0xF0) >> 4;
++ printk(KERN_INFO "BMI_PROJECTOR setting mode to 0x%x \n",mode);
++
++ disp_mode_reg &= ~(0x3);
++ switch(mode)
++ {
++ case PROJECTOR_ECONOMY_MODE:
++ disp_mode_reg |= 0x2; //Economy mode
++ break;
++ case PROJECTOR_BRIGHT_MODE:
++ disp_mode_reg |= 0x1;
++ break;
++ default:
++ printk(KERN_ERR "Invalid Mode\n");
++ return -EINVAL;
++ }
++
++ projector_disp_regset(disp, 0x1, disp_mode_reg);
++ }
++ break;
++
++ case BMI_PROJECTOR_OFF:
++ {
++ disp_mode_reg &= ~(0x3);
++ disp_mode_reg |= 0x3;
++ ch7024_disable(adap);
++#ifdef DEBUG_PROJECTOR
++ printk (KERN_INFO "Mode reg value is:0x%X\n", disp_mode_reg);
++#endif
++ projector_disp_regset(disp, 0x1, disp_mode_reg);
++ //proj_mode = 0x0;
++ pbmi_projector.proj_mode[slot] = 0x0;
++ }
++ break;
++
++ case BMI_PROJECTOR_BATTERY:
++ {
++ printk(KERN_INFO "BMI_PROJECTOR Staring Battery Charger for BUG\n");
++ ch7024_disable(adap);
++ projector_disp_regset(disp, 0x1, 0xF);
++ //proj_mode = 0x0;
++ pbmi_projector.proj_mode[slot] = 0x0;
++ }
++
++ break;
++ case BMI_PROJECTOR_HUE:
++ {
++ int val = ((__user arg) >> 8) & 0xff;
++ printk(KERN_INFO "BMI_PROJECTOR setting Hue to 0x%x\n",val);
++ ret = ch7024_set_hue(adap, val);
++ }
++ break;
++ case BMI_PROJECTOR_SATURATION:
++ {
++ int val = ((__user arg) >> 8) & 0xff;
++ printk(KERN_INFO "BMI_PROJECTOR setting Saturation to 0x%x\n",val);
++ ret = ch7024_set_sat(adap, val);
++ }
++ break;
++ case BMI_PROJECTOR_CONTRAST:
++ {
++ int val = ((__user arg) >> 8) & 0xff;
++ printk(KERN_INFO "BMI_PROJECTOR setting Contrast to 0x%x\n",val);
++ ret = ch7024_set_cont(adap, val);
++ }
++ break;
++ case BMI_PROJECTOR_BRIGHTNESS:
++ {
++ int val = ((__user arg) >> 8) & 0xff;
++ printk(KERN_INFO "BMI_PROJECTOR setting Brightness to 0x%x\n",val);
++ ret = ch7024_set_bright(adap, val);
++ }
++ break;
++ case BMI_PROJECTOR_SHARPNESS:
++ {
++ int val = ((__user arg) >> 8) & 0xff;
++ printk(KERN_INFO "BMI_PROJECTOR setting Sharpness to 0x%x\n",val);
++ ret = ch7024_set_sharp(adap, val);
++ }
++ break;
++ default:
++ return -ENOTTY;
++ }
++ return ret;
++}
++
++ // control file operations
++struct file_operations cntl_fops = {
++ .owner = THIS_MODULE,
++ .ioctl = cntl_ioctl,
++ .open = cntl_open,
++ .release = cntl_release,
++};
++
++ // BMI Projector fops
++void bmi_projector_config(struct bmi_projector *projector, int disp)
++{
++ if(pbmi_projector.active == -1) {
++ return;
++ }
++
++ if((projector) && (projector->projector_ops.config)) {
++ projector->projector_ops.config(disp);
++ }
++}
++
++void bmi_projector_reset(struct bmi_projector *projector, int slot)
++{
++ if(pbmi_projector.active == -1) {
++ return;
++ }
++
++ if((projector) && (projector->projector_ops.reset)) {
++ projector->projector_ops.reset(slot);
++ }
++}
++
++int register_bmi_projector(struct bmi_projector *projector, int slot) //pjg - placeholder for multiple Projector types
++{
++ if(!projector) {
++ return -1;
++ }
++ if((slot < 0) || (slot > 3)) {
++ return -1;
++ }
++ if(pbmi_projector.bprojector[slot]) {
++ return -1;
++ }
++ else {
++ pbmi_projector.bprojector[slot] = projector;
++ }
++
++ if(projector->projector_ops.activate) {
++ projector->projector_ops.activate(projector, slot);
++ }
++
++ return 0;
++}
++
++int unregister_bmi_projector(struct bmi_projector *projector, int slot) //pjg - placeholder for multiple projector types
++{
++ if (!projector) {
++ return -1;
++ }
++ if ((slot < 0) || (slot > 3)) {
++ return -1;
++ }
++ if (pbmi_projector.bprojector[slot] != projector) {
++ return -1;
++ }
++ else {
++ pbmi_projector.bprojector [slot] = 0;
++ projector->projector_ops.deactivate(projector, slot);
++ }
++ return 0;
++}
++
++static struct miscdevice cntl_dev = {
++ MISC_DYNAMIC_MINOR,
++ "bmi_projector",
++ &cntl_fops
++};
++
++static __init int bmi_projector_init(void)
++{
++ int rc = 0;
++
++ // No projector is active.
++ pbmi_projector.active = -1;
++ pbmi_projector.activated[0] = 0;
++ pbmi_projector.activated[1] = 0;
++ pbmi_projector.activated[2] = 0;
++ pbmi_projector.activated[3] = 0;
++ pbmi_projector.proj_mode[0] = 0;
++ pbmi_projector.proj_mode[1] = 0;
++ pbmi_projector.proj_mode[2] = 0;
++ pbmi_projector.proj_mode[3] = 0;
++
++ // set up control character device - bmi_projector_control
++ rc = misc_register(&cntl_dev);
++ if(rc) {
++ printk(KERN_ERR "bmi_projector.c: Can't allocate bmi_projector_control device\n");
++ return rc;
++ }
++
++ pbmi_projector.projector_cnt = 0;
++
++ // hardware specfic set-up
++ bmi_projector.interface = projector_interface,
++ bmi_projector_ops.config = (void(*)) &projector_config;
++ bmi_projector_ops.reset = NULL; //pjg - placeholder for multiple projector hardware types
++ bmi_projector_ops.suspend = NULL; //pjg - placeholder for multiple projector hardware types
++ bmi_projector_ops.resume = NULL; //pjg - placeholder for multiple projector hardware types
++ bmi_projector_ops.disp_on = NULL; //pjg - placeholder for multiple projector hardware types
++ bmi_projector_ops.disp_off = NULL; //pjg - placeholder for multiple projector hardware types
++ bmi_projector_ops.activate = NULL; //pjg - placeholder for multiple Projector hardware types
++ bmi_projector_ops.deactivate = NULL; //pjg - placeholder for multiple Projector hardware types
++ bmi_projector.projector_ops = bmi_projector_ops;
++ pbmi_projector.bprojector[0] = &bmi_projector;
++ pbmi_projector.bprojector[1] = &bmi_projector;
++ pbmi_projector.bprojector[2] = &bmi_projector;
++ pbmi_projector.bprojector[3] = &bmi_projector;
++
++ // register with BMI
++ rc = bmi_register_driver(&bmi_projector_driver);
++ if(rc) {
++ printk(KERN_ERR "bmi_projector.c: Can't register bmi_projector_driver\n");
++
++ misc_deregister(&cntl_dev);
++
++ return rc;
++ }
++
++ printk("bmi_projector.c: BMI_Projector Driver v%s \n", BMIPROJECTOR_VERSION);
++
++ return 0;
++}
++
++static void __exit bmi_projector_clean(void)
++{
++
++ // remove control device
++ misc_deregister(&cntl_dev);
++
++ // remove bmi driver
++ bmi_unregister_driver(&bmi_projector_driver);
++
++ return;
++}
++
++module_init(bmi_projector_init);
++module_exit(bmi_projector_clean);
++
++// Exported symbols
++EXPORT_SYMBOL(register_bmi_projector);
++EXPORT_SYMBOL(unregister_bmi_projector);
++
++
++MODULE_AUTHOR("Suresh Rao");
++MODULE_DESCRIPTION("BMI projector device driver");
++MODULE_SUPPORTED_DEVICE("bmi_projector_control");
++MODULE_LICENSE("GPL");
++
+--- /dev/null
++++ git/drivers/bmi/pims/projector/ch7024.c
+@@ -0,0 +1,476 @@
++/*
++ * Copyright 2007 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
++ */
++
++ /*!
++ * @file ch7024.c
++ * @brief Driver for CH7024 TV encoder
++ *
++ * @ingroup Framebuffer
++ */
++//#define DEBUG
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/i2c.h>
++#include <asm/uaccess.h>
++
++#include "ch7024.h"
++
++#define DEBUG_CH7024
++
++static int ch7024_found = 0;
++static struct i2c_adapter *ch7024_adap = NULL;
++
++static int i2c_ch7024_client_xfer( char *reg, int reg_len, char *buf, int num,
++ int tran_flag)
++{
++ struct i2c_msg msg[2];
++ int ret;
++ if ((ch7024_adap == NULL))
++ {
++ printk (KERN_ERR "ch7024_adap is NULL\n");
++ return -1;
++ }
++ msg[0].addr = CH7024_I2C_ADDR;
++ msg[0].len = reg_len;
++ msg[0].buf = reg;
++ msg[0].flags = tran_flag;
++ msg[0].flags &= ~I2C_M_RD;
++
++ msg[1].addr = CH7024_I2C_ADDR;
++ msg[1].len = num;
++ msg[1].buf = buf;
++
++ msg[1].flags = tran_flag;
++ if (tran_flag & I2C_M_RD) {
++ msg[1].flags |= I2C_M_RD;
++ } else {
++ msg[1].flags &= ~I2C_M_RD;
++ }
++
++ ret = i2c_transfer(ch7024_adap, msg, 2);
++ return ret;
++}
++
++static int bug_i2c_ch7024_polling_read(char *reg, int reg_len, char *buf, int num)
++{
++ return i2c_ch7024_client_xfer(reg, reg_len, buf, num,I2C_M_RD);
++}
++
++static int bug_i2c_ch7024_polling_write(char *reg, int reg_len, char *buf,
++ int num)
++{
++ return i2c_ch7024_client_xfer(reg, reg_len, buf, num, 0);
++
++}
++
++static int ch7024_read_reg(u32 reg, u32 * word, u32 len)
++{
++ int i;
++ u8 *wp = (u8 *) word;
++
++ *word = 0;
++
++ for (i = 0; i < len; i++) {
++ int ret = bug_i2c_ch7024_polling_read((char *)&reg, 1, wp, 1);
++ if (ret < 0)
++ return ret;
++ wp++;
++ reg++;
++ }
++ return 0;
++}
++
++static int ch7024_write_reg(u32 reg, u32 word, u32 len)
++{
++ return bug_i2c_ch7024_polling_write((char *)&reg, 1, (u8 *) & word, len);
++}
++
++/**
++ * PAL B/D/G/H/K/I clock and timting structures
++ */
++static struct ch7024_clock ch7024_clk_pal = {
++ .A = 0x0,
++ .P = 0x36b00,
++ .N = 0x41eb00,
++ .T = 0x3f,
++ .PLLN1 = 0x0,
++ .PLLN2 = 0x1b,
++ .PLLN3 = 0x12,
++};
++
++static struct ch7024_input_timing ch7024_timing_pal = {
++ .HTI = 950,
++ .VTI = 560,
++ .HAI = 640,
++ .VAI = 480,
++ .HW = 60,
++ .HO = 250,
++ .VW = 40,
++ .VO = 40,
++ .VOS = CH7024_VOS_PAL_BDGHKI,
++};
++
++/**
++ * NTSC_M clock and timting structures
++ * TODO: change values to work well.
++ */
++static struct ch7024_clock ch7024_clk_ntsc = {
++ .A = 0x0,
++ .P = 0x2ac90,
++ .N = 0x36fc90,
++ .T = 0x3f,
++ .PLLN1 = 0x0,
++ .PLLN2 = 0x1b,
++ .PLLN3 = 0x12,
++};
++
++static struct ch7024_input_timing ch7024_timing_ntsc = {
++ .HTI = 801,
++ .VTI = 554,
++ .HAI = 640,
++ .VAI = 480,
++ .HW = 60,
++ .HO = 101,
++ .VW = 20,
++ .VO = 54,
++ .VOS = CH7024_VOS_NTSC_M,
++};
++
++/**
++ * ch7024_setup
++ * initial the CH7024 chipset by setting register
++ * @param:
++ * vos: output video format
++ * @return:
++ * 0 successful
++ * otherwise failed
++ */
++int ch7024_setup(struct i2c_adapter *adap,int vos)
++{
++ struct ch7024_input_timing *ch_timing;
++ struct ch7024_clock *ch_clk;
++#ifdef DEBUG_CH7024
++ int i, val;
++#endif
++ ch7024_adap = adap;
++#if 0
++ if (!ch7024_found) {
++ printk(KERN_ERR "CH7024: no such device to setup!\n");
++ return -ENODEV;
++ }
++#endif
++ /* select output video format */
++ if (vos == PROJOUT_FMT_PAL) {
++ ch_timing = &ch7024_timing_pal;
++ ch_clk = &ch7024_clk_pal;
++ pr_debug("CH7024: change to PAL video\n");
++ } else if (vos == PROJOUT_FMT_NTSC) {
++ ch_timing = &ch7024_timing_ntsc;
++ ch_clk = &ch7024_clk_ntsc;
++ pr_debug("CH7024: change to NTSC video\n");
++ } else if (vos == PROJOUT_FMT_QVGA) {
++ ch_timing = &ch7024_timing_ntsc;
++ ch_clk = &ch7024_clk_ntsc;
++ pr_debug("CH7024: change to NTSC video\n");
++ }
++ else {
++
++ pr_debug("CH7024: no such video format.\n");
++ return -EINVAL;
++ }
++ printk("Resetting Chrontel Card\n");
++ ch7024_write_reg(CH7024_POWER, 0x0C, 1); /* power on, disable DAC */
++ ch7024_write_reg(CH7024_RESET, 0x00, 1); /* Reset */
++ ch7024_write_reg(CH7024_RESET, 0x03, 1); /* Reset */
++ mdelay(10);
++
++ ch7024_write_reg(CH7024_POWER, 0x0C, 1); /* power on, disable DAC */
++ ch7024_write_reg(CH7024_XTAL, CH7024_XTAL_13MHZ, 1); /* 13MHz cystal */
++ ch7024_write_reg(CH7024_SYNC, 0x0D, 1); /* Master mode, and TTL */
++ ch7024_write_reg(CH7024_IDF1, 0x00, 1);
++ ch7024_write_reg(CH7024_TVFILTER1, 0x00, 1); /* set XCH=0 */
++
++ /* set input clock and divider */
++ /* set PLL */
++ ch7024_write_reg(CH7024_PLL1, ch_clk->PLLN1, 1);
++ ch7024_write_reg(CH7024_PLL2, ch_clk->PLLN2, 1);
++ ch7024_write_reg(CH7024_PLL3, ch_clk->PLLN3, 1);
++
++ /* set A register */
++ ch7024_write_reg(CH7024_PCLK_A1, 0x00, 1);
++ ch7024_write_reg(CH7024_PCLK_A2, 0x00, 1);
++ ch7024_write_reg(CH7024_PCLK_A3, 0x00, 1);
++ ch7024_write_reg(CH7024_PCLK_A4, 0x00, 1);
++ /* set P register */
++ ch7024_write_reg(CH7024_CLK_P1, (ch_clk->P >> 16) & 0xFF, 1);
++ ch7024_write_reg(CH7024_CLK_P2, (ch_clk->P >> 8) & 0xFF, 1);
++ ch7024_write_reg(CH7024_CLK_P3, ch_clk->P & 0xFF, 1);
++ /* set N register */
++ ch7024_write_reg(CH7024_CLK_N1, (ch_clk->N >> 16) & 0xFF, 1);
++ ch7024_write_reg(CH7024_CLK_N2, (ch_clk->N >> 8) & 0xFF, 1);
++ ch7024_write_reg(CH7024_CLK_N3, ch_clk->N & 0xFF, 1);
++ /* set T register */
++ ch7024_write_reg(CH7024_CLK_T, ch_clk->T & 0xFF, 1);
++
++ /* set sub-carrier frequency generation method */
++ ch7024_write_reg(CH7024_ACIV, 0x10, 1); /* ACIV = 1, automatical SCF */
++ /* TV out pattern and DAC switch */
++ ch7024_write_reg(CH7024_OUT_FMT, (0x10 | ch_timing->VOS) & 0xFF, 1);
++
++if (vos != PROJOUT_FMT_QVGA)
++{
++
++ /* input settings */
++ ch7024_write_reg(CH7024_IDF2, 0x033, 1);
++ /* HAI/HTI VAI */
++ ch7024_write_reg(CH7024_IN_TIMING1, ((ch_timing->HTI >> 5) & 0x38) |
++ ((ch_timing->HAI >> 8) & 0x07), 1);
++ ch7024_write_reg(CH7024_IN_TIMING2, ch_timing->HAI & 0xFF, 1);
++ ch7024_write_reg(CH7024_IN_TIMING8, ch_timing->VAI & 0xFF, 1);
++ /* HTI VTI */
++ ch7024_write_reg(CH7024_IN_TIMING3, ch_timing->HTI & 0xFF, 1);
++ ch7024_write_reg(CH7024_IN_TIMING9, ch_timing->VTI & 0xFF, 1);
++ /* HW/HO(h) VW */
++ ch7024_write_reg(CH7024_IN_TIMING4, ((ch_timing->HW >> 5) & 0x18) |
++ ((ch_timing->HO >> 8) & 0x7), 1);
++ ch7024_write_reg(CH7024_IN_TIMING6, ch_timing->HW & 0xFF, 1);
++ ch7024_write_reg(CH7024_IN_TIMING11, ch_timing->VW & 0x3F, 1);
++ /* HO(l) VO/VAI/VTI */
++ ch7024_write_reg(CH7024_IN_TIMING5, ch_timing->HO & 0xFF, 1);
++ ch7024_write_reg(CH7024_IN_TIMING7, ((ch_timing->VO >> 4) & 0x30) |
++ ((ch_timing->VTI >> 6) & 0x0C) |
++ ((ch_timing->VAI >> 8) & 0x03), 1);
++ ch7024_write_reg(CH7024_IN_TIMING10, ch_timing->VO & 0xFF, 1);
++
++}
++ /* adjust the brightness */
++ ch7024_write_reg(CH7024_TVBRI, 0x90, 1);
++
++ ch7024_write_reg(CH7024_OUT_TIMING1, 0x4, 1);
++ ch7024_write_reg(CH7024_OUT_TIMING2, 0xe0, 1);
++
++ if (vos == PROJOUT_FMT_PAL) {
++ ch7024_write_reg(CH7024_V_POS1, 0x03, 1);
++ ch7024_write_reg(CH7024_V_POS2, 0x7d, 1);
++ } else {
++ ch7024_write_reg(CH7024_V_POS1, 0x02, 1);
++ ch7024_write_reg(CH7024_V_POS2, 0x7b, 1);
++ }
++
++ /* Set up the sub carrier frequency */
++ if (vos == PROJOUT_FMT_PAL) {
++ }
++ else {
++ /* We have crystal of 13MHz */
++ ch7024_write_reg(CH7024_SC_FREQ4, 0x7E, 1);
++ ch7024_write_reg(CH7024_SC_FREQ3, 0xEA, 1);
++ ch7024_write_reg(CH7024_SC_FREQ2, 0x33, 1);
++ ch7024_write_reg(CH7024_SC_FREQ1, 0x02, 1);
++
++ }
++
++#ifdef DEBUG_CH7024
++ for (i = 0; i < CH7024_SC_FREQ4; i++) {
++
++ ch7024_read_reg(i, &val, 1);
++ pr_debug("CH7024, reg[0x%x] = %x\n", i, val);
++ }
++#endif
++ return 0;
++}
++
++/**
++ * ch7024_enable
++ * Enable the ch7024 Power to begin TV encoder
++ */
++void ch7024_enable(struct i2c_adapter *adap)
++{
++ ch7024_adap = adap;
++ if (ch7024_found) {
++ ch7024_write_reg(CH7024_POWER, 0x00, 1);
++ printk("CH7024 power on.\n");
++ }
++}
++
++/**
++ * ch7024_disable
++ * Disable the ch7024 Power to stop TV encoder
++ */
++void ch7024_disable(struct i2c_adapter *adap)
++{
++ ch7024_adap = adap;
++ if (ch7024_found) {
++ ch7024_write_reg(CH7024_POWER, 0x0D, 1);
++ printk("CH7024 power off.\n");
++ }
++}
++
++int ch7024_dump (struct i2c_adapter *adap)
++ {
++ int i;
++ u32 data;
++ ch7024_adap = adap;
++ for (i =0; i <= CH7024_SC_FREQ4; i++)
++ {
++ ch7024_read_reg(i, &data, 1);
++ printk ("Offset :0%X Value :0%X\n", i, data);
++ }
++ ch7024_read_reg(0x62, &data, 1);
++ printk ("Offset :0x62 Value :0%X\n", data);
++ ch7024_read_reg(0x63, &data, 1);
++ printk ("Offset :0x63 Value :0%X\n", data);
++ ch7024_read_reg(0x7E, &data, 1);
++ printk ("Offset :0x7E Value :0%X\n", data);
++ return 0;
++ }
++EXPORT_SYMBOL(ch7024_dump);
++
++int encoder_read_reg (struct i2c_adapter *adap, u32 offset, u32 *data)
++ {
++ int ret;
++ ch7024_adap = adap;
++ ret = ch7024_read_reg(offset, data, 1);
++ if (ret < 0)
++ {
++ printk ("Encoder read register failed at offset 0x%X\n", offset);
++ return ret;
++ }
++ return 0;
++
++ }
++EXPORT_SYMBOL(encoder_read_reg);
++
++int encoder_write_reg (struct i2c_adapter *adap, u32 offset, u32 data)
++ {
++ int ret;
++ ch7024_adap = adap;
++ ret = ch7024_write_reg(offset, data, 1);
++ if (ret < 0)
++ {
++ printk ("Encoder write2 register failed at offset 0x%X\n", offset);
++ return ret;
++ }
++ return 0;
++
++ }
++EXPORT_SYMBOL(encoder_write_reg);
++
++int ch7024_detect (struct i2c_adapter *adap)
++{
++ int ret;
++ u32 id;
++ ch7024_adap = adap;
++ /*TODO client detection */
++ ret = ch7024_read_reg(CH7024_DEVID, &id, 1);
++ if (ret < 0 || id != CH7024_DEVICE_ID) {
++ printk(KERN_ERR
++ "ch7024: TV encoder not present: %d, read ret %d\n", id,
++ ret);
++ return -1;
++ }
++ printk(KERN_ERR "ch7024: TV encoder present: %x, read ret %x\n", id,
++ ret);
++ ch7024_found = 1;
++ return 0;
++
++}
++EXPORT_SYMBOL(ch7024_detect);
++
++int ch7024_set_bright (struct i2c_adapter *adap,u32 val)
++{
++ ch7024_adap = adap;
++ if (val & ~0xFF) {
++ printk ("Brighness value is out of range[0-255] %d\n", val);
++ return -1;
++ } else {
++ ch7024_write_reg(CH7024_TVBRI, val, 1);
++ }
++ return 0;
++}
++EXPORT_SYMBOL(ch7024_set_bright);
++
++int ch7024_set_cont (struct i2c_adapter *adap,u32 val)
++{
++ ch7024_adap = adap;
++ if (val & ~0x7F) {
++ printk ("Contrast value is out of range[0-127] %d\n", val);
++ return -1;
++ } else {
++ ch7024_write_reg(CH7024_TVCTA, val, 1);
++ }
++ return 0;
++}
++EXPORT_SYMBOL(ch7024_set_cont);
++
++int ch7024_set_hue (struct i2c_adapter *adap,u32 val)
++{
++ ch7024_adap = adap;
++ if (val & ~0x7F) {
++ printk ("Hue value is out of range[0-127] %d\n", val);
++ return -1;
++ } else {
++ ch7024_write_reg(CH7024_TVHUE, val, 1);
++ }
++ return 0;
++}
++EXPORT_SYMBOL(ch7024_set_hue);
++
++int ch7024_set_sharp (struct i2c_adapter *adap,u32 val)
++{
++ ch7024_adap = adap;
++ if (val & ~0x07) {
++ printk ("Sharpness value is out of range[0-8] %d\n", val);
++ return -1;
++ } else {
++ ch7024_write_reg(CH7024_TVSHARP, val, 1);
++ }
++ return 0;
++}
++EXPORT_SYMBOL(ch7024_set_sharp);
++
++int ch7024_set_sat (struct i2c_adapter *adap,u32 val)
++{
++ ch7024_adap = adap;
++ if (val & ~0x7F) {
++ printk ("Saturation value is out of range[0-127] %d\n", val);
++ return -1;
++ } else {
++ ch7024_write_reg(CH7024_TVSAT, val, 1);
++ }
++ return 0;
++}
++EXPORT_SYMBOL(ch7024_set_sat);
++
++void ch7024_set_attr (struct i2c_adapter *adap,struct ch7024_attr *attributes)
++{
++ if (!attributes)
++ return;
++ ch7024_set_bright (adap, attributes->brghtness & 0xFF);
++ ch7024_set_cont (adap, attributes->contrast & 0xFF);
++ ch7024_set_hue (adap, attributes->hue & 0xFF);
++ ch7024_set_sharp (adap, attributes->sharpness & 0xFF);
++ ch7024_set_sat (adap,attributes->saturation & 0xFF);
++ return;
++}
++
++EXPORT_SYMBOL(ch7024_set_attr);
++
++
++EXPORT_SYMBOL(ch7024_setup);
++EXPORT_SYMBOL(ch7024_enable);
++EXPORT_SYMBOL(ch7024_disable);
++
++
++
+--- /dev/null
++++ git/drivers/bmi/pims/projector/ch7024.h
+@@ -0,0 +1,166 @@
++/*
++ * Copyright 2007 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
++ */
++
++/*!
++ * @file ch7024.h
++ * @brief Driver for CH7024 TV encoder
++ *
++ * @ingroup Framebuffer
++ */
++#ifndef _CH7024_H_
++#define _CH7024_H_
++
++#ifdef __KERNEL__
++
++
++/* I2C bus id and device address of CH7024 chip */
++
++#define CH7024_I2C_ADDR 0x76 /* 7bits I2C address */
++
++/*!
++ * CH7024 registers
++ */
++#define CH7024_DEVID 0x00
++#define CH7024_REVID 0x01
++#define CH7024_PG 0x02
++
++#define CH7024_RESET 0x03
++#define CH7024_POWER 0x04
++#define CH7024_TVHUE 0x05
++#define CH7024_TVSAT 0x06
++#define CH7024_TVCTA 0x07
++#define CH7024_TVBRI 0x08
++#define CH7024_TVSHARP 0x09
++#define CH7024_OUT_FMT 0x0A
++#define CH7024_XTAL 0x0B
++#define CH7024_IDF1 0x0C
++#define CH7024_IDF2 0x0D
++#define CH7024_SYNC 0x0E
++#define CH7024_TVFILTER1 0x0F
++#define CH7024_TVFILTER2 0x10
++#define CH7024_IN_TIMING1 0x11
++#define CH7024_IN_TIMING2 0x12
++#define CH7024_IN_TIMING3 0x13
++#define CH7024_IN_TIMING4 0x14
++#define CH7024_IN_TIMING5 0x15
++#define CH7024_IN_TIMING6 0x16
++#define CH7024_IN_TIMING7 0x17
++#define CH7024_IN_TIMING8 0x18
++#define CH7024_IN_TIMING9 0x19
++#define CH7024_IN_TIMING10 0x1A
++#define CH7024_IN_TIMING11 0x1B
++#define CH7024_ACIV 0x1C
++#define CH7024_OUT_TIMING1 0x1E
++#define CH7024_OUT_TIMING2 0x1F
++#define CH7024_V_POS1 0x20
++#define CH7024_V_POS2 0x21
++#define CH7024_H_POS1 0x22
++#define CH7024_H_POS2 0x23
++#define CH7024_PCLK_A1 0x24
++#define CH7024_PCLK_A2 0x25
++#define CH7024_PCLK_A3 0x26
++#define CH7024_PCLK_A4 0x27
++#define CH7024_CLK_P1 0x28
++#define CH7024_CLK_P2 0x29
++#define CH7024_CLK_P3 0x2A
++#define CH7024_CLK_N1 0x2B
++#define CH7024_CLK_N2 0x2C
++#define CH7024_CLK_N3 0x2D
++#define CH7024_CLK_T 0x2E
++#define CH7024_PLL1 0x2F
++#define CH7024_PLL2 0x30
++#define CH7024_PLL3 0x31
++#define CH7024_SC_FREQ1 0x34
++#define CH7024_SC_FREQ2 0x35
++#define CH7024_SC_FREQ3 0x36
++#define CH7024_SC_FREQ4 0x37
++#define CH7024_DATA_IO 0x63
++
++/*!
++ * CH7024 register values
++ */
++/* video output formats */
++#define CH7024_VOS_NTSC_M 0x0
++#define CH7024_VOS_NTSC_J 0x1
++#define CH7024_VOS_NTSC_443 0x2
++#define CH7024_VOS_PAL_BDGHKI 0x3
++#define CH7024_VOS_PAL_M 0x4
++#define CH7024_VOS_PAL_N 0x5
++#define CH7024_VOS_PAL_NC 0x6
++#define CH7024_VOS_PAL_60 0x7
++/* crystal predefined */
++#define CH7024_XTAL_13MHZ 0x4
++#define CH7024_XTAL_26MHZ 0xB
++#define CH7024_XTAL_27MHZ 0xC
++
++/* chip ID */
++#define CH7024_DEVICE_ID 0x45
++
++/* clock source define */
++#define CLK_HIGH 0
++#define CLK_LOW 1
++
++/* CH7024 presets structs */
++struct ch7024_clock {
++ u32 A;
++ u32 P;
++ u32 N;
++ u32 T;
++ u8 PLLN1;
++ u8 PLLN2;
++ u8 PLLN3;
++};
++
++struct ch7024_input_timing {
++ u32 HTI;
++ u32 VTI;
++ u32 HAI;
++ u32 VAI;
++ u32 HW;
++ u32 HO;
++ u32 VW;
++ u32 VO;
++ u32 VOS;
++};
++
++struct ch7024_attr{
++ u32 brghtness;
++ u32 sharpness;
++ u32 hue;
++ u32 contrast;
++ u32 saturation;
++};
++
++/* function declare, used by bmi projector module */
++int ch7024_setup (struct i2c_adapter *adap,int vos);
++void ch7024_enable (struct i2c_adapter *adap);
++void ch7024_disable (struct i2c_adapter *adap);
++int ch7024_detect (struct i2c_adapter *adap);
++void ch7024_set_attr (struct i2c_adapter *adap, struct ch7024_attr *attributes);
++int ch7024_set_sat (struct i2c_adapter *adap, u32 val);
++int ch7024_set_sharp (struct i2c_adapter *adap, u32 val);
++int ch7024_set_hue (struct i2c_adapter *adap, u32 val);
++int ch7024_set_cont (struct i2c_adapter *adap, u32 val);
++int ch7024_set_bright (struct i2c_adapter *adap, u32 val);
++int ch7024_dump (struct i2c_adapter *adap);
++int encoder_read_reg (struct i2c_adapter *adap, u32 offset, u32 *data);
++int encoder_write_reg (struct i2c_adapter *adap, u32 offset, u32 data);
++
++#endif /* __KERNEL__ */
++
++/* output video format */
++#define PROJOUT_FMT_PAL 0x01
++#define PROJOUT_FMT_NTSC 0x02
++#define PROJOUT_FMT_QVGA 0x03
++
++#endif /* _CH7024_H_ */
+--- /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 @@
++/*
++ * File: include/linux/bmi/bmi_projector.h
++ * Author: Suresh Rao
++ *
++ * This is the application header file for the BMI bus projector plug-in
++ * module on the MX31 BUG platform.
++ */
++
++#ifndef BMI_PROJECTOR_H
++#define BMI_PROJECTOR_H
++
++#include <linux/input.h>
++#include <linux/bmi/bmi_ioctl.h>
++
++// IOCTL commands for BMI PROJECTOR driver
++#define BMI_PROJECTOR_ON _IOW(BMI_PROJECTOR_IOCTL, 0x1, __u32) // turn on projector
++#define BMI_PROJECTOR_MODE _IOW(BMI_PROJECTOR_IOCTL, 0x2, __u32) // turn on projector
++#define BMI_PROJECTOR_OFF _IOW(BMI_PROJECTOR_IOCTL, 0x3, __u32) // turn off projector
++#define BMI_PROJECTOR_BATTERY _IOW(BMI_PROJECTOR_IOCTL, 0x4, __u32) // Battery charger on to bug from projector
++
++// IOCTL commands for Encoder control
++#define BMI_PROJECTOR_HUE _IOW(BMI_PROJECTOR_IOCTL, 0x5, __u32) // Hue control in Encoder
++#define BMI_PROJECTOR_SATURATION _IOW(BMI_PROJECTOR_IOCTL, 0x6, __u32) // Saturation control in Encoder
++#define BMI_PROJECTOR_BRIGHTNESS _IOW(BMI_PROJECTOR_IOCTL, 0x7, __u32) // Brightness control in Encoder
++#define BMI_PROJECTOR_SHARPNESS _IOW(BMI_PROJECTOR_IOCTL, 0x8, __u32) // Sharpness control in Encoder
++#define BMI_PROJECTOR_CONTRAST _IOW(BMI_PROJECTOR_IOCTL, 0x9, __u32) // Contrast control in Encoder
++
++/* BMI_PROJECTOR_MODE settings */
++#define PROJECTOR_ECONOMY_MODE 0x0
++#define PROJECTOR_BRIGHT_MODE 0x1
++
++#endif /* BMI_PROJECTOR_H */
++
+--- /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"))
diff --git a/recipes/linux/linux-omap_2.6.29.bb b/recipes/linux/linux-omap_2.6.29.bb
index 18382b60ef..56e6107a4c 100644
--- a/recipes/linux/linux-omap_2.6.29.bb
+++ b/recipes/linux/linux-omap_2.6.29.bb
@@ -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 = " \