aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 = " \