diff options
Diffstat (limited to 'recipes/linux/linux-omap-2.6.29/beaglebug/beaglebug-full.patch')
-rw-r--r-- | recipes/linux/linux-omap-2.6.29/beaglebug/beaglebug-full.patch | 35774 |
1 files changed, 35774 insertions, 0 deletions
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 = ®s->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 = ®s->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 = ®s->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 = ®s->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 = ®s->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 = ®s->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 = ®s->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 = ®s->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 = ®s->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 = ®s->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 = ®s->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 = ®s->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 = ®s->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 = ®s->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 = ®s->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 = ®s->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 = ®s->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 = ®s->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 = ®s->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 = ®s->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 = ®s->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 = ®s->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 = ®s->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 = ®s->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 = ®s->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 = ®s->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 = ®s->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 = ®s->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 = ®s->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 = ®s->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 *)®, 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 *)®, 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")) |