From 9d40ac5867b9aefe0722bc1f110b965ff294d30d Mon Sep 17 00:00:00 2001 From: Kevin Date: Sat, 15 Nov 2014 10:00:36 +0800 Subject: add via modify part source code for wm8880 4.4 kitkat --- ANDROID_3.4.5/drivers/input/Kconfig | 5 + ANDROID_3.4.5/drivers/input/Makefile | 4 + ANDROID_3.4.5/drivers/input/keyboard/Kconfig | 18 + ANDROID_3.4.5/drivers/input/keyboard/Makefile | 2 + ANDROID_3.4.5/drivers/input/keyboard/wmt_kpad.c | 466 +++ ANDROID_3.4.5/drivers/input/keyboard/wmt_saradc.c | 718 ++++ ANDROID_3.4.5/drivers/input/physics_key/Kconfig | 27 + ANDROID_3.4.5/drivers/input/physics_key/Makefile | 41 + ANDROID_3.4.5/drivers/input/physics_key/pkey.c | 261 ++ ANDROID_3.4.5/drivers/input/remote_input.c | 195 ++ ANDROID_3.4.5/drivers/input/rmtctl/Kconfig | 25 + ANDROID_3.4.5/drivers/input/rmtctl/Makefile | 8 + ANDROID_3.4.5/drivers/input/rmtctl/oem-dev.h | 186 + ANDROID_3.4.5/drivers/input/rmtctl/wmt-rmtctl.c | 1515 +++++++++ ANDROID_3.4.5/drivers/input/rmtctl/wmt-rmtctl.h | 50 + ANDROID_3.4.5/drivers/input/sensor/Kconfig | 224 ++ ANDROID_3.4.5/drivers/input/sensor/Makefile | 26 + .../drivers/input/sensor/TP_DRIVER_NOT_USE/Kconfig | 50 + .../input/sensor/TP_DRIVER_NOT_USE/Makefile | 13 + .../TP_DRIVER_NOT_USE/dmt08_gsensor/Makefile | 6 + .../sensor/TP_DRIVER_NOT_USE/dmt08_gsensor/dmt08.c | 870 +++++ .../sensor/TP_DRIVER_NOT_USE/dmt08_gsensor/dmt08.h | 105 + .../TP_DRIVER_NOT_USE/dmt10_gsensor/Makefile | 6 + .../sensor/TP_DRIVER_NOT_USE/dmt10_gsensor/dmt10.c | 950 ++++++ .../sensor/TP_DRIVER_NOT_USE/dmt10_gsensor/dmt10.h | 187 + .../input/sensor/TP_DRIVER_NOT_USE/gsensor.c | 180 + .../input/sensor/TP_DRIVER_NOT_USE/gsensor.h | 43 + .../TP_DRIVER_NOT_USE/kxti9_gsensor/Makefile | 6 + .../sensor/TP_DRIVER_NOT_USE/kxti9_gsensor/kxti9.c | 1134 +++++++ .../sensor/TP_DRIVER_NOT_USE/kxti9_gsensor/kxti9.h | 103 + ANDROID_3.4.5/drivers/input/sensor/cm3232/Makefile | 34 + ANDROID_3.4.5/drivers/input/sensor/cm3232/cm3232.c | 855 +++++ .../drivers/input/sensor/dmard06_gsensor/Makefile | 34 + .../drivers/input/sensor/dmard06_gsensor/dmard06.c | 980 ++++++ .../drivers/input/sensor/dmard08_gsensor/Makefile | 34 + .../input/sensor/dmard08_gsensor/cyclequeue.c | 68 + .../input/sensor/dmard08_gsensor/cyclequeue.h | 18 + .../drivers/input/sensor/dmard08_gsensor/dmard08.c | 1019 ++++++ .../drivers/input/sensor/dmard08_gsensor/dmard08.h | 75 + .../drivers/input/sensor/dmard09_gsensor/Makefile | 35 + .../drivers/input/sensor/dmard09_gsensor/dmt09.c | 1685 +++++++++ .../drivers/input/sensor/dmard09_gsensor/dmt09.h | 183 + .../drivers/input/sensor/dmard10_gsensor/Makefile | 34 + .../drivers/input/sensor/dmard10_gsensor/dmt10.c | 1702 ++++++++++ .../drivers/input/sensor/dmard10_gsensor/dmt10.h | 192 ++ .../drivers/input/sensor/isl29023_lsensor/Makefile | 34 + .../input/sensor/isl29023_lsensor/isl29023.c | 1164 +++++++ .../drivers/input/sensor/kionix_gsensor/Makefile | 35 + .../input/sensor/kionix_gsensor/kionix_accel.c | 2427 +++++++++++++ .../input/sensor/kionix_gsensor/kionix_accel.h | 85 + .../drivers/input/sensor/kxte9_gsensor/Makefile | 34 + .../drivers/input/sensor/kxte9_gsensor/kxte9.c | 1798 ++++++++++ .../drivers/input/sensor/kxte9_gsensor/kxte9.h | 116 + .../drivers/input/sensor/kxte9_gsensor/readme.txt | 47 + .../drivers/input/sensor/l3g4200d_gyro/Makefile | 5 + .../drivers/input/sensor/l3g4200d_gyro/l3g4200d.h | 108 + .../input/sensor/l3g4200d_gyro/l3g4200d_gyr.c | 1681 +++++++++ .../drivers/input/sensor/mc3230_gsensor/Makefile | 34 + .../drivers/input/sensor/mc3230_gsensor/mc32x0.c | 2580 ++++++++++++++ .../input/sensor/mc3230_gsensor/mc32x0_driver.c | 505 +++ .../input/sensor/mc3230_gsensor/mc32x0_driver.h | 219 ++ .../drivers/input/sensor/mc3xxx_gsensor/Makefile | 34 + .../drivers/input/sensor/mc3xxx_gsensor/mc3xxx.c | 2719 +++++++++++++++ .../drivers/input/sensor/mma7660_gsensor/Makefile | 34 + .../drivers/input/sensor/mma7660_gsensor/mma7660.c | 1052 ++++++ .../drivers/input/sensor/mma7660_gsensor/mma7660.h | 106 + .../drivers/input/sensor/mma8452q_gsensor/Makefile | 34 + .../input/sensor/mma8452q_gsensor/mma8x5x.c | 982 ++++++ .../input/sensor/mma8452q_gsensor/mma8x5x.h | 107 + .../drivers/input/sensor/mmc328x_msensor/Makefile | 4 + .../drivers/input/sensor/mmc328x_msensor/mecs.c | 433 +++ .../drivers/input/sensor/mmc328x_msensor/mecs.h | 60 + .../drivers/input/sensor/mmc328x_msensor/mmc328x.c | 505 +++ .../drivers/input/sensor/mmc328x_msensor/mmc328x.h | 91 + .../drivers/input/sensor/mxc622x_gsensor/Makefile | 34 + .../drivers/input/sensor/mxc622x_gsensor/mxc622x.c | 1151 +++++++ .../drivers/input/sensor/mxc622x_gsensor/mxc622x.h | 83 + ANDROID_3.4.5/drivers/input/sensor/sensor.c | 114 + ANDROID_3.4.5/drivers/input/sensor/sensor.h | 91 + .../drivers/input/sensor/stk3310/Makefile | 34 + .../drivers/input/sensor/stk3310/stk3310.c | 644 ++++ .../drivers/input/sensor/stk8312_gsensor/Makefile | 34 + .../drivers/input/sensor/stk8312_gsensor/stk8312.h | 51 + .../drivers/input/sensor/stk8312_gsensor/stk8313.h | 52 + .../drivers/input/sensor/stk8312_gsensor/stk831x.c | 3590 ++++++++++++++++++++ .../drivers/input/sensor/us5182_lpsensor/Makefile | 34 + .../drivers/input/sensor/us5182_lpsensor/us5182.c | 1098 ++++++ .../drivers/input/sensor/us5182_lpsensor/us5182.h | 255 ++ ANDROID_3.4.5/drivers/input/touchscreen/Kconfig | 24 + ANDROID_3.4.5/drivers/input/touchscreen/Makefile | 16 + .../input/touchscreen/aw5306_ts/AW5306_Base.b | Bin 0 -> 41612 bytes .../input/touchscreen/aw5306_ts/AW5306_Clb.b | Bin 0 -> 32804 bytes .../input/touchscreen/aw5306_ts/AW5306_Drv.b | Bin 0 -> 114476 bytes .../input/touchscreen/aw5306_ts/AW5306_Drv.h | 158 + .../input/touchscreen/aw5306_ts/AW5306_Reg.h | 187 + .../input/touchscreen/aw5306_ts/AW5306_ts.c | 1614 +++++++++ .../input/touchscreen/aw5306_ts/AW5306_userpara.c | 196 ++ .../input/touchscreen/aw5306_ts/AW5306_userpara.h | 99 + .../drivers/input/touchscreen/aw5306_ts/Kconfig | 11 + .../drivers/input/touchscreen/aw5306_ts/Makefile | 35 + .../drivers/input/touchscreen/aw5306_ts/irq_gpio.c | 149 + .../drivers/input/touchscreen/aw5306_ts/irq_gpio.h | 13 + .../drivers/input/touchscreen/cyp140_ts/Kconfig | 16 + .../drivers/input/touchscreen/cyp140_ts/Makefile | 33 + .../input/touchscreen/cyp140_ts/cyp140_i2c.c | 1412 ++++++++ .../drivers/input/touchscreen/cyp140_ts/cyttsp.h | 696 ++++ .../touchscreen/cyp140_ts/cyttsp_fw_upgrade.c | 993 ++++++ .../drivers/input/touchscreen/cyp140_ts/debug.txt | 3 + .../drivers/input/touchscreen/cyp140_ts/wmt_ts.c | 1094 ++++++ .../drivers/input/touchscreen/cyp140_ts/wmt_ts.h | 120 + .../drivers/input/touchscreen/ft5x0x/Kconfig | 11 + .../drivers/input/touchscreen/ft5x0x/Makefile | 34 + .../input/touchscreen/ft5x0x/ft5402_config.c | 2295 +++++++++++++ .../input/touchscreen/ft5x0x/ft5402_config.h | 71 + .../input/touchscreen/ft5x0x/ft5402_ini_config.h | 411 +++ .../drivers/input/touchscreen/ft5x0x/ft5x0x.c | 937 +++++ .../drivers/input/touchscreen/ft5x0x/ft5x0x.h | 207 ++ .../drivers/input/touchscreen/ft5x0x/ft5x0x_upg.c | 506 +++ .../drivers/input/touchscreen/ft5x0x/ini.c | 406 +++ .../drivers/input/touchscreen/ft5x0x/ini.h | 43 + .../drivers/input/touchscreen/ft6x0x/Kconfig | 11 + .../drivers/input/touchscreen/ft6x0x/Makefile | 34 + .../input/touchscreen/ft6x0x/focaltech_ctl.h | 27 + .../input/touchscreen/ft6x0x/ft5402_config.c | 2295 +++++++++++++ .../input/touchscreen/ft6x0x/ft5402_config.h | 71 + .../input/touchscreen/ft6x0x/ft5402_ini_config.h | 411 +++ .../drivers/input/touchscreen/ft6x0x/ft5x0x.c | 896 +++++ .../drivers/input/touchscreen/ft6x0x/ft5x0x.h | 205 ++ .../drivers/input/touchscreen/ft6x0x/ft5x0x_upg.c | 506 +++ .../input/touchscreen/ft6x0x/ft6x06_ex_fun.c | 1021 ++++++ .../input/touchscreen/ft6x0x/ft6x06_ex_fun.h | 79 + .../drivers/input/touchscreen/ft6x0x/ft6x06_ts.c | 511 +++ .../drivers/input/touchscreen/ft6x0x/ft6x06_ts.h | 52 + .../drivers/input/touchscreen/ft6x0x/ini.c | 406 +++ .../drivers/input/touchscreen/ft6x0x/ini.h | 43 + .../drivers/input/touchscreen/gsl1680_ts/Kconfig | 16 + .../drivers/input/touchscreen/gsl1680_ts/Makefile | 33 + .../drivers/input/touchscreen/gsl1680_ts/gslX680.c | 1416 ++++++++ .../drivers/input/touchscreen/gsl1680_ts/gslX680.h | 35 + .../input/touchscreen/gsl1680_ts/gsl_point_id.b | Bin 0 -> 38321 bytes .../drivers/input/touchscreen/gsl1680_ts/wmt_ts.c | 1102 ++++++ .../drivers/input/touchscreen/gsl1680_ts/wmt_ts.h | 117 + .../drivers/input/touchscreen/gt9xx_ts/Kconfig | 11 + .../drivers/input/touchscreen/gt9xx_ts/Makefile | 34 + .../input/touchscreen/gt9xx_ts/goodix_tool.c | 615 ++++ .../drivers/input/touchscreen/gt9xx_ts/gt9xx.c | 2163 ++++++++++++ .../drivers/input/touchscreen/gt9xx_ts/gt9xx.h | 278 ++ .../input/touchscreen/gt9xx_ts/gt9xx_firmware.h | 6 + .../input/touchscreen/gt9xx_ts/gt9xx_update.c | 1939 +++++++++++ .../drivers/input/touchscreen/icn83xx_ts/Kconfig | 16 + .../drivers/input/touchscreen/icn83xx_ts/Makefile | 32 + .../drivers/input/touchscreen/icn83xx_ts/flash.c | 973 ++++++ .../drivers/input/touchscreen/icn83xx_ts/icn83xx.c | 2034 +++++++++++ .../drivers/input/touchscreen/icn83xx_ts/icn83xx.h | 434 +++ .../input/touchscreen/icn83xx_ts/icn83xx_fw.h | 3 + .../drivers/input/touchscreen/icn85xx_ts/Kconfig | 16 + .../drivers/input/touchscreen/icn85xx_ts/Makefile | 32 + .../drivers/input/touchscreen/icn85xx_ts/icn85xx.c | 2431 +++++++++++++ .../drivers/input/touchscreen/icn85xx_ts/icn85xx.h | 500 +++ .../input/touchscreen/icn85xx_ts/icn85xx_flash.c | 1050 ++++++ .../input/touchscreen/icn85xx_ts/icn85xx_fw.h | 2517 ++++++++++++++ .../drivers/input/touchscreen/lw86x0_ts/Kconfig | 11 + .../drivers/input/touchscreen/lw86x0_ts/Makefile | 34 + .../input/touchscreen/lw86x0_ts/lw86x0_ts.c | 1321 +++++++ .../input/touchscreen/lw86x0_ts/lw86x0_ts.h | 53 + .../drivers/input/touchscreen/lw86x0_ts/wmt_ts.c | 1165 +++++++ .../drivers/input/touchscreen/lw86x0_ts/wmt_ts.h | 98 + .../drivers/input/touchscreen/metusb/Makefile | 33 + .../drivers/input/touchscreen/metusb/metusb.c | 856 +++++ .../drivers/input/touchscreen/semisens/Makefile | 33 + .../touchscreen/semisens/sn310m-touch-pdata.h | 201 ++ .../input/touchscreen/semisens/sn310m-touch.c | 332 ++ .../input/touchscreen/semisens/sn310m-touch.h | 97 + .../drivers/input/touchscreen/semisens/touch.c | 1121 ++++++ .../drivers/input/touchscreen/semisens/touch.h | 54 + .../input/touchscreen/sis_usbhid_ts/Kconfig | 16 + .../input/touchscreen/sis_usbhid_ts/Makefile | 32 + .../input/touchscreen/sis_usbhid_ts/hid-sis.c | 1104 ++++++ .../drivers/input/touchscreen/sitronix/Kconfig | 11 + .../drivers/input/touchscreen/sitronix/Makefile | 34 + .../drivers/input/touchscreen/sitronix/irq_gpio.c | 148 + .../drivers/input/touchscreen/sitronix/irq_gpio.h | 13 + .../input/touchscreen/sitronix/sitronix_i2c.c | 817 +++++ .../input/touchscreen/sitronix/sitronix_i2c.h | 137 + .../drivers/input/touchscreen/ssd253x_ts/Kconfig | 16 + .../drivers/input/touchscreen/ssd253x_ts/Makefile | 32 + .../input/touchscreen/ssd253x_ts/ssd253x-ts.c | 1827 ++++++++++ .../input/touchscreen/ssd253x_ts/ssd253x-ts.h | 28 + .../drivers/input/touchscreen/ssd253x_ts/wmt_ts.c | 810 +++++ .../drivers/input/touchscreen/ssd253x_ts/wmt_ts.h | 116 + .../drivers/input/touchscreen/vt1609_ts/Makefile | 4 + .../input/touchscreen/vt1609_ts/vt1609_dual.c | 692 ++++ .../input/touchscreen/vt1609_ts/vt1609_ts.c | 1481 ++++++++ .../input/touchscreen/vt1609_ts/vt1609_ts.h | 301 ++ .../drivers/input/touchscreen/zet6221_ts/Kconfig | 16 + .../drivers/input/touchscreen/zet6221_ts/Makefile | 32 + .../drivers/input/touchscreen/zet6221_ts/wmt_ts.c | 833 +++++ .../drivers/input/touchscreen/zet6221_ts/wmt_ts.h | 149 + .../touchscreen/zet6221_ts/zet6221_downloader.c | 1209 +++++++ .../input/touchscreen/zet6221_ts/zet6221_i2c.c | 2786 +++++++++++++++ .../input/touchscreen/zet6221_ts/zet6221_ts.h | 6 + 201 files changed, 92890 insertions(+) create mode 100755 ANDROID_3.4.5/drivers/input/keyboard/wmt_kpad.c create mode 100755 ANDROID_3.4.5/drivers/input/keyboard/wmt_saradc.c create mode 100755 ANDROID_3.4.5/drivers/input/physics_key/Kconfig create mode 100755 ANDROID_3.4.5/drivers/input/physics_key/Makefile create mode 100755 ANDROID_3.4.5/drivers/input/physics_key/pkey.c create mode 100755 ANDROID_3.4.5/drivers/input/remote_input.c create mode 100755 ANDROID_3.4.5/drivers/input/rmtctl/Kconfig create mode 100755 ANDROID_3.4.5/drivers/input/rmtctl/Makefile create mode 100755 ANDROID_3.4.5/drivers/input/rmtctl/oem-dev.h create mode 100755 ANDROID_3.4.5/drivers/input/rmtctl/wmt-rmtctl.c create mode 100755 ANDROID_3.4.5/drivers/input/rmtctl/wmt-rmtctl.h create mode 100755 ANDROID_3.4.5/drivers/input/sensor/Kconfig create mode 100755 ANDROID_3.4.5/drivers/input/sensor/Makefile create mode 100755 ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/Kconfig create mode 100755 ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/Makefile create mode 100755 ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/dmt08_gsensor/Makefile create mode 100755 ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/dmt08_gsensor/dmt08.c create mode 100755 ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/dmt08_gsensor/dmt08.h create mode 100755 ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/dmt10_gsensor/Makefile create mode 100755 ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/dmt10_gsensor/dmt10.c create mode 100755 ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/dmt10_gsensor/dmt10.h create mode 100755 ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/gsensor.c create mode 100755 ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/gsensor.h create mode 100755 ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/kxti9_gsensor/Makefile create mode 100755 ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/kxti9_gsensor/kxti9.c create mode 100755 ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/kxti9_gsensor/kxti9.h create mode 100755 ANDROID_3.4.5/drivers/input/sensor/cm3232/Makefile create mode 100755 ANDROID_3.4.5/drivers/input/sensor/cm3232/cm3232.c create mode 100755 ANDROID_3.4.5/drivers/input/sensor/dmard06_gsensor/Makefile create mode 100755 ANDROID_3.4.5/drivers/input/sensor/dmard06_gsensor/dmard06.c create mode 100755 ANDROID_3.4.5/drivers/input/sensor/dmard08_gsensor/Makefile create mode 100755 ANDROID_3.4.5/drivers/input/sensor/dmard08_gsensor/cyclequeue.c create mode 100755 ANDROID_3.4.5/drivers/input/sensor/dmard08_gsensor/cyclequeue.h create mode 100755 ANDROID_3.4.5/drivers/input/sensor/dmard08_gsensor/dmard08.c create mode 100755 ANDROID_3.4.5/drivers/input/sensor/dmard08_gsensor/dmard08.h create mode 100755 ANDROID_3.4.5/drivers/input/sensor/dmard09_gsensor/Makefile create mode 100755 ANDROID_3.4.5/drivers/input/sensor/dmard09_gsensor/dmt09.c create mode 100755 ANDROID_3.4.5/drivers/input/sensor/dmard09_gsensor/dmt09.h create mode 100755 ANDROID_3.4.5/drivers/input/sensor/dmard10_gsensor/Makefile create mode 100755 ANDROID_3.4.5/drivers/input/sensor/dmard10_gsensor/dmt10.c create mode 100755 ANDROID_3.4.5/drivers/input/sensor/dmard10_gsensor/dmt10.h create mode 100755 ANDROID_3.4.5/drivers/input/sensor/isl29023_lsensor/Makefile create mode 100755 ANDROID_3.4.5/drivers/input/sensor/isl29023_lsensor/isl29023.c create mode 100755 ANDROID_3.4.5/drivers/input/sensor/kionix_gsensor/Makefile create mode 100755 ANDROID_3.4.5/drivers/input/sensor/kionix_gsensor/kionix_accel.c create mode 100755 ANDROID_3.4.5/drivers/input/sensor/kionix_gsensor/kionix_accel.h create mode 100755 ANDROID_3.4.5/drivers/input/sensor/kxte9_gsensor/Makefile create mode 100755 ANDROID_3.4.5/drivers/input/sensor/kxte9_gsensor/kxte9.c create mode 100755 ANDROID_3.4.5/drivers/input/sensor/kxte9_gsensor/kxte9.h create mode 100755 ANDROID_3.4.5/drivers/input/sensor/kxte9_gsensor/readme.txt create mode 100755 ANDROID_3.4.5/drivers/input/sensor/l3g4200d_gyro/Makefile create mode 100755 ANDROID_3.4.5/drivers/input/sensor/l3g4200d_gyro/l3g4200d.h create mode 100755 ANDROID_3.4.5/drivers/input/sensor/l3g4200d_gyro/l3g4200d_gyr.c create mode 100755 ANDROID_3.4.5/drivers/input/sensor/mc3230_gsensor/Makefile create mode 100755 ANDROID_3.4.5/drivers/input/sensor/mc3230_gsensor/mc32x0.c create mode 100755 ANDROID_3.4.5/drivers/input/sensor/mc3230_gsensor/mc32x0_driver.c create mode 100755 ANDROID_3.4.5/drivers/input/sensor/mc3230_gsensor/mc32x0_driver.h create mode 100644 ANDROID_3.4.5/drivers/input/sensor/mc3xxx_gsensor/Makefile create mode 100644 ANDROID_3.4.5/drivers/input/sensor/mc3xxx_gsensor/mc3xxx.c create mode 100755 ANDROID_3.4.5/drivers/input/sensor/mma7660_gsensor/Makefile create mode 100755 ANDROID_3.4.5/drivers/input/sensor/mma7660_gsensor/mma7660.c create mode 100755 ANDROID_3.4.5/drivers/input/sensor/mma7660_gsensor/mma7660.h create mode 100755 ANDROID_3.4.5/drivers/input/sensor/mma8452q_gsensor/Makefile create mode 100755 ANDROID_3.4.5/drivers/input/sensor/mma8452q_gsensor/mma8x5x.c create mode 100755 ANDROID_3.4.5/drivers/input/sensor/mma8452q_gsensor/mma8x5x.h create mode 100755 ANDROID_3.4.5/drivers/input/sensor/mmc328x_msensor/Makefile create mode 100755 ANDROID_3.4.5/drivers/input/sensor/mmc328x_msensor/mecs.c create mode 100755 ANDROID_3.4.5/drivers/input/sensor/mmc328x_msensor/mecs.h create mode 100755 ANDROID_3.4.5/drivers/input/sensor/mmc328x_msensor/mmc328x.c create mode 100755 ANDROID_3.4.5/drivers/input/sensor/mmc328x_msensor/mmc328x.h create mode 100755 ANDROID_3.4.5/drivers/input/sensor/mxc622x_gsensor/Makefile create mode 100755 ANDROID_3.4.5/drivers/input/sensor/mxc622x_gsensor/mxc622x.c create mode 100755 ANDROID_3.4.5/drivers/input/sensor/mxc622x_gsensor/mxc622x.h create mode 100755 ANDROID_3.4.5/drivers/input/sensor/sensor.c create mode 100755 ANDROID_3.4.5/drivers/input/sensor/sensor.h create mode 100755 ANDROID_3.4.5/drivers/input/sensor/stk3310/Makefile create mode 100755 ANDROID_3.4.5/drivers/input/sensor/stk3310/stk3310.c create mode 100755 ANDROID_3.4.5/drivers/input/sensor/stk8312_gsensor/Makefile create mode 100755 ANDROID_3.4.5/drivers/input/sensor/stk8312_gsensor/stk8312.h create mode 100755 ANDROID_3.4.5/drivers/input/sensor/stk8312_gsensor/stk8313.h create mode 100755 ANDROID_3.4.5/drivers/input/sensor/stk8312_gsensor/stk831x.c create mode 100755 ANDROID_3.4.5/drivers/input/sensor/us5182_lpsensor/Makefile create mode 100755 ANDROID_3.4.5/drivers/input/sensor/us5182_lpsensor/us5182.c create mode 100755 ANDROID_3.4.5/drivers/input/sensor/us5182_lpsensor/us5182.h create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_Base.b create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_Clb.b create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_Drv.b create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_Drv.h create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_Reg.h create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_ts.c create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_userpara.c create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_userpara.h create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/Kconfig create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/Makefile create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/irq_gpio.c create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/irq_gpio.h create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/Kconfig create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/Makefile create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/cyp140_i2c.c create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/cyttsp.h create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/cyttsp_fw_upgrade.c create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/debug.txt create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/wmt_ts.c create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/wmt_ts.h create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/Kconfig create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/Makefile create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ft5402_config.c create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ft5402_config.h create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ft5402_ini_config.h create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ft5x0x.c create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ft5x0x.h create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ft5x0x_upg.c create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ini.c create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ini.h create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/Kconfig create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/Makefile create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/focaltech_ctl.h create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft5402_config.c create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft5402_config.h create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft5402_ini_config.h create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft5x0x.c create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft5x0x.h create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft5x0x_upg.c create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft6x06_ex_fun.c create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft6x06_ex_fun.h create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft6x06_ts.c create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft6x06_ts.h create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ini.c create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ini.h create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/Kconfig create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/Makefile create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/gslX680.c create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/gslX680.h create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/gsl_point_id.b create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/wmt_ts.c create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/wmt_ts.h create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/Kconfig create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/Makefile create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/goodix_tool.c create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/gt9xx.c create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/gt9xx.h create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/gt9xx_firmware.h create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/gt9xx_update.c create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/icn83xx_ts/Kconfig create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/icn83xx_ts/Makefile create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/icn83xx_ts/flash.c create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/icn83xx_ts/icn83xx.c create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/icn83xx_ts/icn83xx.h create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/icn83xx_ts/icn83xx_fw.h create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/icn85xx_ts/Kconfig create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/icn85xx_ts/Makefile create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/icn85xx_ts/icn85xx.c create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/icn85xx_ts/icn85xx.h create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/icn85xx_ts/icn85xx_flash.c create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/icn85xx_ts/icn85xx_fw.h create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/lw86x0_ts/Kconfig create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/lw86x0_ts/Makefile create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/lw86x0_ts/lw86x0_ts.c create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/lw86x0_ts/lw86x0_ts.h create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/lw86x0_ts/wmt_ts.c create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/lw86x0_ts/wmt_ts.h create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/metusb/Makefile create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/metusb/metusb.c create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/semisens/Makefile create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/semisens/sn310m-touch-pdata.h create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/semisens/sn310m-touch.c create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/semisens/sn310m-touch.h create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/semisens/touch.c create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/semisens/touch.h create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/sis_usbhid_ts/Kconfig create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/sis_usbhid_ts/Makefile create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/sis_usbhid_ts/hid-sis.c create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/sitronix/Kconfig create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/sitronix/Makefile create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/sitronix/irq_gpio.c create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/sitronix/irq_gpio.h create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/sitronix/sitronix_i2c.c create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/sitronix/sitronix_i2c.h create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/ssd253x_ts/Kconfig create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/ssd253x_ts/Makefile create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/ssd253x_ts/ssd253x-ts.c create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/ssd253x_ts/ssd253x-ts.h create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/ssd253x_ts/wmt_ts.c create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/ssd253x_ts/wmt_ts.h create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/vt1609_ts/Makefile create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/vt1609_ts/vt1609_dual.c create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/vt1609_ts/vt1609_ts.c create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/vt1609_ts/vt1609_ts.h create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/zet6221_ts/Kconfig create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/zet6221_ts/Makefile create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/zet6221_ts/wmt_ts.c create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/zet6221_ts/wmt_ts.h create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/zet6221_ts/zet6221_downloader.c create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/zet6221_ts/zet6221_i2c.c create mode 100755 ANDROID_3.4.5/drivers/input/touchscreen/zet6221_ts/zet6221_ts.h (limited to 'ANDROID_3.4.5/drivers/input') diff --git a/ANDROID_3.4.5/drivers/input/Kconfig b/ANDROID_3.4.5/drivers/input/Kconfig index 69d36863..3eb8298e 100644 --- a/ANDROID_3.4.5/drivers/input/Kconfig +++ b/ANDROID_3.4.5/drivers/input/Kconfig @@ -186,8 +186,13 @@ source "drivers/input/tablet/Kconfig" source "drivers/input/touchscreen/Kconfig" +source "drivers/input/rmtctl/Kconfig" + +source "drivers/input/physics_key/Kconfig" + source "drivers/input/misc/Kconfig" +source "drivers/input/sensor/Kconfig" endif menu "Hardware I/O ports" diff --git a/ANDROID_3.4.5/drivers/input/Makefile b/ANDROID_3.4.5/drivers/input/Makefile index cf643bee..b53e788c 100644 --- a/ANDROID_3.4.5/drivers/input/Makefile +++ b/ANDROID_3.4.5/drivers/input/Makefile @@ -21,8 +21,12 @@ obj-$(CONFIG_INPUT_MOUSE) += mouse/ obj-$(CONFIG_INPUT_JOYSTICK) += joystick/ obj-$(CONFIG_INPUT_TABLET) += tablet/ obj-$(CONFIG_INPUT_TOUCHSCREEN) += touchscreen/ +obj-$(CONFIG_INPUT_RMTCTL) += rmtctl/ +obj-$(CONFIG_INPUT_PKEY) += physics_key/ obj-$(CONFIG_INPUT_MISC) += misc/ obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o obj-$(CONFIG_INPUT_OF_MATRIX_KEYMAP) += of_keymap.o obj-$(CONFIG_INPUT_KEYRESET) += keyreset.o +obj-$(CONFIG_INPUT_SENSOR) += sensor/ +obj-m += remote_input.o diff --git a/ANDROID_3.4.5/drivers/input/keyboard/Kconfig b/ANDROID_3.4.5/drivers/input/keyboard/Kconfig index f354813a..906d86aa 100644 --- a/ANDROID_3.4.5/drivers/input/keyboard/Kconfig +++ b/ANDROID_3.4.5/drivers/input/keyboard/Kconfig @@ -502,6 +502,24 @@ config KEYBOARD_DAVINCI To compile this driver as a module, choose M here: the module will be called davinci_keyscan. +config KEYBOARD_WMT + tristate "WMT keypad support" + depends on INPUT && INPUT_KEYBOARD + ---help--- + Say Y here if you want to use keypad on WMT based EVB. + + To compile this driver as a module, choose M here: the + module will be called wmt_keypad. + +config SARADC_WMT + tristate "WMT saradc support" + depends on INPUT && INPUT_KEYBOARD + ---help--- + Say Y here if you want to use keypad on WMT based EVB. + + To compile this driver as a module, choose M here: the + module will be called wmt_saradc. + config KEYBOARD_OMAP tristate "TI OMAP keypad support" depends on (ARCH_OMAP1 || ARCH_OMAP2) diff --git a/ANDROID_3.4.5/drivers/input/keyboard/Makefile b/ANDROID_3.4.5/drivers/input/keyboard/Makefile index df7061f1..587a9f25 100644 --- a/ANDROID_3.4.5/drivers/input/keyboard/Makefile +++ b/ANDROID_3.4.5/drivers/input/keyboard/Makefile @@ -51,4 +51,6 @@ obj-$(CONFIG_KEYBOARD_TEGRA) += tegra-kbc.o obj-$(CONFIG_KEYBOARD_TNETV107X) += tnetv107x-keypad.o obj-$(CONFIG_KEYBOARD_TWL4030) += twl4030_keypad.o obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o +obj-$(CONFIG_KEYBOARD_WMT) += wmt_kpad.o obj-$(CONFIG_KEYBOARD_W90P910) += w90p910_keypad.o +obj-$(CONFIG_SARADC_WMT) += wmt_saradc.o diff --git a/ANDROID_3.4.5/drivers/input/keyboard/wmt_kpad.c b/ANDROID_3.4.5/drivers/input/keyboard/wmt_kpad.c new file mode 100755 index 00000000..cf50cf1c --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/keyboard/wmt_kpad.c @@ -0,0 +1,466 @@ +/*++ +linux/drivers/input/keyboard/wmt_kpad.c + +Some descriptions of such software. Copyright (c) 2008 WonderMedia Technologies, Inc. + +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 . + +WonderMedia Technologies, Inc. +10F, 529, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C. +--*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* Debug macros */ +#if 0 +#define DPRINTK(fmt, args...) printk(KERN_ALERT "[%s]: " fmt, __func__ , ## args) +#else +#define DPRINTK(fmt, args...) +#endif + +//#define USE_HOME +#define wmt_kpad_timeout (HZ/50) + +#define WMT_KPAD_FUNCTION_NUM 7 + + +static unsigned int wmt_kpad_codes[WMT_KPAD_FUNCTION_NUM] = { + [0] = KEY_VOLUMEUP, + [1] = KEY_VOLUMEDOWN, + [2] = KEY_BACK, + [3] = KEY_HOME, + [4] = KEY_MENU, + [5] = KEY_CAMERA, + [6] = KEY_PLAYPAUSE, +}; + + +enum { + KEY_ST_up, + KEY_ST_down, + KEY_ST_debounce, +}; + +static struct input_dev *kpad_dev; + +int key_num = 0; + +struct wmt_key{ + int gpio; + int keycode; + + int status; + int debounce; + struct timer_list timer; +} ; +struct wmt_key gpio_key[5]; + +#ifdef CONFIG_CPU_FREQ +/* + * Well, the debounce time is not very critical while zac2_clk + * rescaling, but we still do it. + */ + +/* kpad_clock_notifier() + * + * When changing the processor core clock frequency, it is necessary + * to adjust the KPMIR register. + * + * Returns: 0 on success, -1 on error + */ +static int kpad_clock_notifier(struct notifier_block *nb, unsigned long event, + void *data) +{ + return 0; +} + +/* + * Notify callback while issusing zac2_clk rescale. + */ +static struct notifier_block kpad_clock_nblock = { + .notifier_call = kpad_clock_notifier, + .priority = 1 +}; +#endif + +static int wmt_kpad_gpio_requst(void) +{ + int i,j,ret; + DPRINTK("Start\n"); + for(i=0; i< key_num; i++){ + ret = gpio_request(gpio_key[i].gpio,"kpad"); + if(ret) + goto exit; + } + + DPRINTK("End\n"); + return ret; +exit: + for(j=0; j < i; j++) + gpio_free(gpio_key[j].gpio); + return ret; +} + +static int wmt_kpad_gpio_init(void) +{ + int i; + for(i=0; igpio) == 0) { /*Active Low*/ + if(gpk->status == KEY_ST_up){ + gpk->debounce = 5; + gpk->status = KEY_ST_debounce; + DPRINTK("vd down to debounce\n"); + } + + if(gpk->status == KEY_ST_debounce){ + if(--gpk->debounce == 0){ + gpk->status = KEY_ST_down; + /* report volume down key down */ + input_report_key(kpad_dev, gpk->keycode, 1); + input_sync(kpad_dev); + DPRINTK("WMT Volume up keep press\n"); + } + } + //DPRINTK("vd level is low,status=%d\n",vu_status); + + } + else {/* Level High */ + if(gpk->status == KEY_ST_down){ + gpk->status = KEY_ST_up; + /*Volume down release*/ + input_report_key(kpad_dev, gpk->keycode, 0); /*row4 key is release*/ + input_sync(kpad_dev); + DPRINTK("WMT_Volume down release key = %d \n", gpk->keycode); + } + + if(gpk->status == KEY_ST_debounce){ + if(--gpk->debounce == 0){ + gpk->status = KEY_ST_up; + } + } + + //DPRINTK("vd level is high,status=%d\n",vu_status); + + } + + mod_timer(&gpk->timer, jiffies + wmt_kpad_timeout); + //DPRINTK("End\n"); + + return; +} + +static int init_key_timer(void) +{ + int i; + for(i=0; inum_resources = 0x%x\n",pdev->num_resources); + if (pdev->num_resources < 0 || pdev->num_resources > 2) { + ret = -ENODEV; + goto kpad_probe_out; + } + + /* Register an input event device. */ + kpad_dev->name = "keypad", + kpad_dev->phys = "keypad", + + /* + * Let kpad to implement key repeat. + */ + + set_bit(EV_KEY, kpad_dev->evbit); + + for (i = 0; i < WMT_KPAD_FUNCTION_NUM; i++) + set_bit(wmt_kpad_codes[i], kpad_dev->keybit); + + kpad_dev->keycode = wmt_kpad_codes; + kpad_dev->keycodesize = sizeof(unsigned int); + kpad_dev->keycodemax = WMT_KPAD_FUNCTION_NUM; + + /* + * For better view of /proc/bus/input/devices + */ + kpad_dev->id.bustype = 0; + kpad_dev->id.vendor = 0; + kpad_dev->id.product = 0; + kpad_dev->id.version = 0; + + input_register_device(kpad_dev); + kpad_open(kpad_dev); + DPRINTK("End2\n"); +kpad_probe_out: + +#ifndef CONFIG_SKIP_DRIVER_MSG + printk(KERN_INFO "WMT keypad driver initialized: %s\n", + (ret == 0) ? "ok" : "failed"); +#endif + DPRINTK("End3\n"); + return ret; +} + +static int wmt_kpad_remove(struct platform_device *pdev) +{ + int ret; + DPRINTK("Start\n"); + kpad_close(kpad_dev); + wmt_kpad_gpio_free(); + DPRINTK("End\n"); +#ifdef CONFIG_CPU_FREQ + ret = cpufreq_unregister_notifier(&kpad_clock_nblock, \ + CPUFREQ_TRANSITION_NOTIFIER); + + if (ret) { + printk(KERN_ERR "Unable to unregister CPU frequency " \ + "change notifier (%d)\n", ret); + } +#endif + return 0; +} + +static int wmt_kpad_suspend(struct platform_device *pdev, pm_message_t state) +{ + DPRINTK("Start\n"); + + switch (state.event) { + case PM_EVENT_SUSPEND: + del_key_timer(); + break; + case PM_EVENT_FREEZE: + case PM_EVENT_PRETHAW: + + default: + break; + } + + DPRINTK("End2\n"); + return 0; +} + +static int wmt_kpad_resume(struct platform_device *pdev) +{ + DPRINTK("Start\n"); + wmt_kpad_gpio_init(); + start_key_timer(); + DPRINTK("End\n"); + return 0; +} + +static void wmt_kpad_release(struct device *dev) +{ + return ; +} + +static struct platform_driver wmt_kpad_driver = { + .driver.name = "wmt-kpad", + .probe = &wmt_kpad_probe, + .remove = &wmt_kpad_remove, + .suspend = &wmt_kpad_suspend, + .resume = &wmt_kpad_resume +}; + +static struct resource wmt_kpad_resources[] = { + [0] = { + .start = IRQ_GPIO, + .end = IRQ_GPIO, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device wmt_kpad_device = { + .name = "wmt-kpad", + .id = 0, + .num_resources = ARRAY_SIZE(wmt_kpad_resources), + .resource = wmt_kpad_resources, + .dev = { + .release = wmt_kpad_release, + } +}; + +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); + +static int __init kpad_init(void) +{ + int i,ret; + int retval; + unsigned char buf[80]; + int varlen = 80; + char *varname = "wmt.io.kpad"; + char *p=NULL; + int gpio,code; + + DPRINTK(KERN_ALERT "Start\n"); + retval = wmt_getsyspara(varname, buf, &varlen); + if (retval == 0) { + sscanf(buf,"%d:", &key_num); + if (key_num <= 0) + return -ENODEV; + p = buf; + for(i=0; i. + +WonderMedia Technologies, Inc. +10F, 529, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C. +--*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* #define COUNTTIMER */ +#ifdef COUNTTIMER +unsigned int start_time; +#endif + +/* Debug macros */ +#if 0 +#define DPRINTK(fmt, args...) printk(KERN_ALERT "[%s]: " fmt, __func__ , ## args) +#else +#define DPRINTK(fmt, args...) +#endif + +/* the shortest response time is 20 ms, original timeout (HZ/100)*100 */ +#define wmt_saradc_timeout ((HZ/100)*2) +#define WMT_SARADC_FUNCTION_NUM 6 +#define SAMETIMES 2 +unsigned int HW_Hz; +unsigned int SW_timeout; +unsigned int INT_timeout; + +enum adc_func { + FUNC_KPAD, + FUNC_BAT, + FUNC_NONE, +}; +unsigned int func = FUNC_NONE; + +/* SARADC battery */ +unsigned int BatteryCODE; +static unsigned int bat_interval = 3; +static struct delayed_work bat_work; + +static unsigned int wmt_saradc_codes[WMT_SARADC_FUNCTION_NUM] = { + [0] = KEY_VOLUMEUP, + [1] = KEY_VOLUMEDOWN, + [2] = KEY_BACK, + [3] = KEY_MENU, + [4] = KEY_HOME, + [5] = KEY_RESERVED, +}; + +/*high resolution timer */ +static struct hrtimer wmt_saradc_hrtimer; +static struct input_dev *saradc_dev; + +static struct wmt_saradc_s saradc = { + .ref = 0, + .res = NULL, + .regs = NULL, + .irq = 0, +}; + +int count_sample_rate(unsigned APB_clock, int Hz) +{ + int temp_slot; + /* the Hz that we want */ + temp_slot = APB_clock/(4096 * Hz); /* (APB clock/32)/ (128 * HZ)*/ + return temp_slot; +} + +static int saradc_sample_rate(unsigned ADC_clock, int Hz) +{ + int temp_slot; + /* the Hz that we want */ + temp_slot = ADC_clock/(128 * Hz); /* ADC clock/ (128 * HZ)*/ + return temp_slot; +} + +int saradc_event_table(unsigned int eventcode) +{ + DPRINTK("eventcode = %d\n", eventcode); + if (eventcode >= 39 && eventcode <= 42) + return 0; + else if (eventcode >= 63 && eventcode <= 64) + return 1; + else if (eventcode >= 84 && eventcode <= 85) + return 2; + else if (eventcode >= 18 && eventcode <= 20) + return 3; + else if (eventcode == 0) + return 4; + else if (eventcode >= 29 && eventcode <= 31) + return 5; + else if (eventcode == 127) + return 5; + else + return 5; +} + +static void wmt_saradc_hw_init(void) +{ + unsigned int auto_temp_slot; + //unsigned int APB_clk; + unsigned int ADC_clk; + DPRINTK("Start\n"); + + /* + * Turn on saradc clocks. + */ + auto_pll_divisor(DEV_ADC, CLK_ENABLE, 0, 0); + + /* Set the ADC clock to 4.8 MHz */ + auto_pll_divisor(DEV_ADC, SET_DIV, 1, 4800); + + /* Turn on SARADC controll power */ + saradc.regs->Ctr0 &= ~PD; + + /* Enable SARADC digital clock */ + saradc.regs->Ctr0 |= DigClkEn; + + /* Simply clean all previous saradc status. */ + saradc.regs->Ctr0 |= (ClrIntADC | ClrIntTOut); + saradc.regs->Ctr1 |= ClrIntValDet; + + if (((saradc.regs->Ctr2 & EndcIntStatus) == EndcIntStatus) || + ((saradc.regs->Ctr2 & TOutStatus) == TOutStatus) || + ((saradc.regs->Ctr2 & ValDetIntStatus) == ValDetIntStatus)) + printk(KERN_ERR "[saradc] clear status failed! status = %x\n", saradc.regs->Ctr2); + + /*Set Timeout Value*/ + saradc.regs->Ctr0 &= 0xffff0000; + saradc.regs->Ctr0 |= TOutDly(0xffff); + + /* get APB clock & count sample rate*/ + ADC_clk = auto_pll_divisor(DEV_ADC, GET_FREQ, 0, 0); + DPRINTK("[%s] ADC_clk = %d\n", __func__, ADC_clk); + /* sample rate: 500 Hz , 1 ms/sample */ + auto_temp_slot = saradc_sample_rate(ADC_clk, 500); +#if 0 + /* get APB clock & count sample rate*/ + APB_clk = auto_pll_divisor(DEV_APB, GET_FREQ, 0, 0); + /* sample rate: 1000 Hz , 1 ms/sample */ + auto_temp_slot = count_sample_rate(APB_clk, HW_Hz); + DPRINTK("[%s] APB_clk = %d\n", __func__, APB_clk); +#endif + /*Set Sample Rate*/ + saradc.regs->Ctr1 &= 0x0000ffff; + saradc.regs->Ctr1 |= (auto_temp_slot << 16); + DPRINTK("[%s] auto_temp_slot = %x ctr1: %x\n", __func__, auto_temp_slot, saradc.regs->Ctr1); + /* Set saradc as auto mode */ + saradc.regs->Ctr0 |= AutoMode; + + msleep(200); + + /* Enable value changing interrupt and Buffer data valid */ + saradc.regs->Ctr1 |= (ValDetIntEn | BufRd); + /* saradc.regs->Ctr0 |= TOutEn; */ + + DPRINTK("End\n"); +} + +enum hrtimer_restart wmt_saradc_timeout_hrtimer(struct hrtimer *timer) +{ + unsigned int SARCODE = 0xffff; + static unsigned int OLDCODE = 0xffff; + static int time, same; + static bool saradc_flag = 1; /* 0: report event state, 1: get SARCODE value state */ + int new_event = -1; + static int pre_event = -1, button_press; + ktime_t ktime; + /* count timeout value */ +#ifdef COUNTTIMER + unsigned int end_time; + end_time = wmt_read_oscr(); + printk(KERN_ERR "time = %d\n", (end_time - start_time)/3); +#endif + ktime = ktime_set(0, SW_timeout * 1000); + + DPRINTK("[%s] Start\n", __func__); + while ((saradc.regs->Ctr2 & EndcIntStatus) == 0) + ; + SARCODE = SARCode(saradc.regs->Ctr1); + + if (saradc_flag && time < 10) { + if ((SARCODE/4 - OLDCODE/4) <= 1 || (SARCODE/4 - OLDCODE/4) >= -1) { + same++; + DPRINTK("time:%d SARCODE=%u SARCODE/4=%u, OLDCODE=%u, OLDCODE/4=%u, same=%d\n", + time, SARCODE, SARCODE/4, OLDCODE, OLDCODE/4, same); + if (same == SAMETIMES) + saradc_flag = 0; /* get the new event */ + } else + same = 0; + + DPRINTK("time:%d SARCODE=%u SARCODE/4=%u, OLDCODE=%u, OLDCODE/4=%u, same=%d\n", + time, SARCODE, SARCODE/4, OLDCODE, OLDCODE/4, same); + OLDCODE = SARCODE; + time++; + + /* don't call timer when 10th get SARCODE or enough same time */ + if (time < 10 && same != SAMETIMES) { + hrtimer_start(&wmt_saradc_hrtimer, ktime, HRTIMER_MODE_REL); + /* count timer from callback function to callback function */ +#ifdef COUNTTIMER + start_time = wmt_read_oscr(); +#endif + } + /* if not get stable SARCODE value in 10 times, report SARACODE is NONE event */ + if (time == 10 && same != SAMETIMES) { + SARCODE = 508; + DPRINTK("time %d SARCODE %u", time, SARCODE); + } + } + if (time == 10 || saradc_flag == 0) + time = 0; + + /* disable BufRd */ + saradc.regs->Ctr1 &= ~BufRd; + + new_event = saradc_event_table(SARCODE/4); + + if (SARCODE == 0xffff) { + printk(KERN_ERR "Auto mode witn INT test fail\n"); + /*Disable interrupt*/ + saradc.regs->Ctr1 &= ~ValDetIntEn; + /* Clean all previous saradc status. */ + saradc.regs->Ctr0 |= (ClrIntTOut | ClrIntADC); + saradc.regs->Ctr1 |= ClrIntValDet; + } else { + /*DPRINTK("Buf_rdata = %u Buf_rdata/4 = %u\n", data, data/4);*/ + DPRINTK("SARCODE = %u SARCODE/4 = %u\n", SARCODE, SARCODE/4); + /*Disable interrupt*/ + saradc.regs->Ctr1 &= ~ValDetIntEn; + /* Clean all previous saradc status. */ + saradc.regs->Ctr0 |= (ClrIntTOut | ClrIntADC); + saradc.regs->Ctr1 |= ClrIntValDet; + } + + if (saradc_flag == 0) { + /* switch other button means release button*/ + if ((pre_event != new_event) && (SARCODE/4 != 127)) { + button_press = 0; + DPRINTK("Different event, pre_event = %d, new_event = %d\n", pre_event, new_event); + DPRINTK("WMT_ROW1_KEY_NUM release key = %d, event=%d\n", SARCODE/4, pre_event); + input_report_key(saradc_dev, wmt_saradc_codes[pre_event], 0); /* key is release*/ + input_sync(saradc_dev); + } + + if (SARCODE/4 == 127 || SARCODE/4 == 126) { /*Active Low*/ + DPRINTK("WMT_ROW1_KEY_NUM release key = %d, event=%d\n", SARCODE/4, pre_event); + input_report_key(saradc_dev, wmt_saradc_codes[pre_event], 0); /* key is release*/ + input_sync(saradc_dev); + button_press = 0; + } else { + if (button_press == 0) { + DPRINTK("new event = %d\n", new_event); + input_report_key(saradc_dev, wmt_saradc_codes[new_event], 1);/* key is press*/ + input_sync(saradc_dev); + DPRINTK("saradc code = %d\n", wmt_saradc_codes[new_event]); + button_press = 1; + } + DPRINTK("WMT_ROW1_KEY_NUM keep press key = %d, event=%d\n", SARCODE/4, new_event); + } + pre_event = new_event; + saradc_flag = 1; /* report new event to Android, get new SARCODE */ + same = 0; + } + saradc.regs->Ctr1 |= ValDetIntEn; + DPRINTK("[%s] End\n", __func__); + return HRTIMER_NORESTART; /* avoid to timer restart */ +} + +static irqreturn_t +saradc_interrupt(int irq, void *dev_id) +{ + ktime_t ktime; + ktime = ktime_set(0, INT_timeout * 1000); /* ms */ + DPRINTK("[%s] Start\n", __func__); + DPRINTK("status = %x\n", saradc.regs->Ctr2); + /* Disable interrupt */ + /* disable_irq_nosync(saradc.irq);*/ + saradc.regs->Ctr1 &= ~ValDetIntEn; + + saradc.regs->Ctr1 |= BufRd; + /* + * Get saradc interrupt status and clean interrput source. + */ + + /* if (((saradc.regs->Ctr1 & ValDetIntEn) == ValDetIntEn) && */ + if ((saradc.regs->Ctr2 & ValDetIntStatus) == ValDetIntStatus) { + /* clear value chaning interrupt */ + saradc.regs->Ctr1 |= ClrIntValDet; + /* start hrtimer */ + hrtimer_start(&wmt_saradc_hrtimer, ktime, HRTIMER_MODE_REL); + + /* count timer from interrupt to callback function */ +#ifdef COUNTTIMER + start_time = wmt_read_oscr(); +#endif + } + + if ((saradc.regs->Ctr2 & ValDetIntStatus) == ValDetIntStatus) + printk(KERN_ERR "[saradc] status clear failed!\n"); + + + /* Enable interrupt */ + /* saradc.regs->Ctr1 |= ValDetIntEn; // enable INT in wmt_saradc_timeout_timer*/ + DPRINTK("[%s] End\n", __func__); + return IRQ_HANDLED; +} + + +static unsigned int saradc_read(void) +{ + int i; + int min=0xfff,max=0; + int total=0,val; + + for(i=0; i < 7; i++){ + while ((saradc.regs->Ctr2 & EndcIntStatus) == 0); + + val = SARCode(saradc.regs->Ctr1); + //printk("%d--",val); + + if(max < val) max = val; + if(min > val) min = val; + total +=val; + } + //printk("value %d\n",(total-max-min)/5); + return (total-max-min)/5; + +} + +/* Read SARADC BATTRTY CODE */ +unsigned int ReadBattery(void) +{ + return BatteryCODE; +} +EXPORT_SYMBOL_GPL(ReadBattery); + +/* Update SARCODE BATTERY CODE */ +static void WriteBattery(unsigned int value) +{ + BatteryCODE = value; +} +static void saradc_bat_handler(struct work_struct *work) +{ + unsigned int sarcode = 0xffff; + + DPRINTK("Start\n"); + /* disable value change interrupt */ + saradc.regs->Ctr1 &= ~ValDetIntEn; + /* Switch to BATTERY channel and clear INT status */ + saradc.regs->Ctr0 |= (AdcChSel | ClrIntADC | ClrIntTOut); + saradc.regs->Ctr1 |= (ClrIntValDet); + msleep(20); + //printk("bat:\n"); + sarcode = saradc_read(); + WriteBattery(sarcode/4); + DPRINTK("sarcode = %d\n", sarcode); + /* Switch to ADC channel */ + saradc.regs->Ctr0 &= ~AdcChSel; + /* too early to clear status will cause interrupts */ + msleep(5); + /* Switch to BATTERY channel and clear INT status */ + saradc.regs->Ctr0 |= (ClrIntADC | ClrIntTOut); + saradc.regs->Ctr1 |= (ClrIntValDet); + + /* enable value change interrupt */ + saradc.regs->Ctr1 |= ValDetIntEn; + + schedule_delayed_work(&bat_work, bat_interval*HZ); + DPRINTK("End\n\n\n"); + return ; +} + +static int saradc_open(struct input_dev *dev) +{ + int ret = 0; + unsigned int i; + DPRINTK("Start saradc.ref = %d\n", saradc.ref); + + if (saradc.ref++) { + /* Return success, but not initialize again. */ + DPRINTK("End 1 saradc.ref=%d\n", saradc.ref); + return 0; + } + + if (func != FUNC_KPAD) + goto bat_init; + + ret = request_irq(saradc.irq, saradc_interrupt, IRQF_DISABLED, "saradc", dev); + + if (ret) { + printk(KERN_ERR "%s: Can't allocate irq %d\n", __func__, IRQ_TSC); + saradc.ref--; + free_irq(saradc.irq, dev); + goto saradc_open_out; + } + + /* Init hr timer */ + hrtimer_init(&wmt_saradc_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + wmt_saradc_hrtimer.function = &wmt_saradc_timeout_hrtimer; + + /* Register an input event device. */ + dev->name = "saradc", + dev->phys = "saradc", + + /* + * Let kpad to implement key repeat. + */ + + set_bit(EV_KEY, dev->evbit); + + for (i = 0; i < WMT_SARADC_FUNCTION_NUM; i++) + set_bit(wmt_saradc_codes[i], dev->keybit); + + + dev->keycode = wmt_saradc_codes; + dev->keycodesize = sizeof(unsigned int); + dev->keycodemax = WMT_SARADC_FUNCTION_NUM; + + /* + * For better view of /proc/bus/input/devices + */ + dev->id.bustype = 0; + dev->id.vendor = 0; + dev->id.product = 0; + dev->id.version = 0; + + input_register_device(dev); + +bat_init: + if (func == FUNC_BAT) { + INIT_DELAYED_WORK(&bat_work,saradc_bat_handler); + schedule_delayed_work(&bat_work, HZ); + } + + wmt_saradc_hw_init(); + + DPRINTK("End2\n"); +saradc_open_out: + DPRINTK("End3\n"); + return ret; +} + +static void saradc_close(struct input_dev *dev) +{ + DPRINTK("Start\n"); + if (--saradc.ref) { + DPRINTK("End1\n"); + return; + } + + /* Free interrupt resource */ + free_irq(saradc.irq, dev); + + /*Disable clock*/ + auto_pll_divisor(DEV_ADC, CLK_DISABLE, 0, 0); + + /* Unregister input device driver */ + input_unregister_device(dev); + DPRINTK("End2\n"); +} + +static int wmt_saradc_probe(struct platform_device *pdev) +{ + unsigned long base; + int ret = 0; + DPRINTK("Start\n"); + saradc_dev = input_allocate_device(); + if (saradc_dev == NULL) { + DPRINTK("End 1\n"); + return -1; + } + /* + * Simply check resources parameters. + */ + if (pdev->num_resources < 2 || pdev->num_resources > 3) { + ret = -ENODEV; + goto saradc_probe_out; + } + + base = pdev->resource[0].start; + + saradc.irq = pdev->resource[1].start; + + saradc.regs = (struct saradc_regs_s *)ADC_BASE_ADDR; + + if (!saradc.regs) { + ret = -ENOMEM; + goto saradc_probe_out; + } + + saradc_dev->open = saradc_open, + saradc_dev->close = saradc_close, + + saradc_open(saradc_dev); + DPRINTK("End2\n"); +saradc_probe_out: + +#ifndef CONFIG_SKIP_DRIVER_MSG + printk(KERN_INFO "WMT saradc driver initialized: %s\n", + (ret == 0) ? "ok" : "failed"); +#endif + DPRINTK("End3\n"); + return ret; +} + +static int wmt_saradc_remove(struct platform_device *pdev) +{ + DPRINTK("Start\n"); + saradc_close(saradc_dev); + + /* + * Free allocated resource + */ + /*kfree(kpad.res); + kpad.res = NULL; + + if (kpad.regs) { + iounmap(kpad.regs); + kpad.regs = NULL; + }*/ + + saradc.ref = 0; + saradc.irq = 0; + + DPRINTK("End\n"); + return 0; +} + +static int wmt_saradc_suspend(struct platform_device *pdev, pm_message_t state) +{ + DPRINTK("Start\n"); + + switch (state.event) { + case PM_EVENT_SUSPEND: + /*Disable clock*/ + auto_pll_divisor(DEV_ADC, CLK_DISABLE, 0, 0); + break; + case PM_EVENT_FREEZE: + case PM_EVENT_PRETHAW: + + default: + break; + } + + DPRINTK("End2\n"); + return 0; +} + +static int wmt_saradc_resume(struct platform_device *pdev) +{ + DPRINTK("Start\n"); + wmt_saradc_hw_init(); + DPRINTK("End\n"); + return 0; +} + +static struct platform_driver wmt_saradc_driver = { + .driver.name = "wmt-saradc", + .probe = &wmt_saradc_probe, + .remove = &wmt_saradc_remove, + .suspend = &wmt_saradc_suspend, + .resume = &wmt_saradc_resume +}; + +static struct resource wmt_saradc_resources[] = { + [0] = { + .start = ADC_BASE_ADDR, + .end = (ADC_BASE_ADDR + 0xFFFF), + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_TSC, + .end = IRQ_TSC, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device wmt_saradc_device = { + .name = "wmt-saradc", + .id = 0, + .num_resources = ARRAY_SIZE(wmt_saradc_resources), + .resource = wmt_saradc_resources, +}; + +static int __init saradc_init(void) +{ + int ret; + int retval; + unsigned char buf[80]; + int varlen = 80; + char *varname1 = "wmt.keypad.param"; + char *varname2 = "wmt.battery.param"; + char *p; + int temp = 0, enable_saradc = 0, function_sel = 0; + + DPRINTK(KERN_ALERT "Start\n"); + /*read keypad enable*/ + retval = wmt_getsyspara(varname1, buf, &varlen); + if (retval == 0) { + sscanf(buf, "%X:%d:%d:%d", &temp, &HW_Hz, &INT_timeout, &SW_timeout); + enable_saradc = temp & 0xf; + function_sel = (temp >> 4) & 0xf; + printk(KERN_ALERT "wmt.keypad.param = %x:%d:%d:%d, enable = %x, function = %x\n", + temp, HW_Hz, INT_timeout, SW_timeout, enable_saradc, function_sel); + + if (enable_saradc != 1 || function_sel != 1) { + printk(KERN_ALERT "Disable SARADC as keypad function!!\n"); + goto bat; + } else if (enable_saradc == 1 && function_sel == 1) + printk(KERN_ALERT "HW_HZ = %d, INT_time = %d, SW_timeout = %d\n", + HW_Hz, INT_timeout, SW_timeout); + if ((HW_Hz == 0) || (INT_timeout == 0) || (SW_timeout == 0)) { + HW_Hz = 1000; /* 1000 Hz */ + INT_timeout = 20000; /* 20 ms */ + SW_timeout = 1000; /* 1 ms */ + printk(KERN_ALERT "wmt.keypad.param isn't correct. Set the default value\n"); + printk(KERN_ALERT "Default HW_HZ = %d, INT_time = %d, SW_timeout = %d\n", + HW_Hz, INT_timeout, SW_timeout); + } + func = FUNC_KPAD; + } else { + printk(KERN_ALERT "##Warning: \"wmt.keypad.param\" not find\n"); + printk(KERN_ALERT "Default wmt.keypad.param = %x\n", temp); + //return -ENODEV; + } + +bat: + if (func != FUNC_KPAD) { + memset(buf, 0x00,sizeof(buf)); + /* read battery enable, dev name and */ + retval = wmt_getsyspara(varname2, buf, &varlen); + if (retval == 0) { + p = buf; + if(!strncmp(p,"saradc", 6)){ + p = strchr(p,':'); + if(p){ + p++; + sscanf(p,"%d",&bat_interval); + } + printk("Bat ADC sample period = %ds\n", bat_interval); + func = FUNC_BAT; + } + } + } + + if (func == FUNC_NONE) { + printk("SARADC not enable\n"); + return -ENODEV; + } + +/* check saradc can switch freq. +#ifdef CONFIG_CPU_FREQ + ret = cpufreq_register_notifier(&kpad_clock_nblock, \ + CPUFREQ_TRANSITION_NOTIFIER); + + if (ret) { + printk(KERN_ERR "Unable to register CPU frequency " \ + "change notifier (%d)\n", ret); + } +#endif +*/ + ret = platform_device_register(&wmt_saradc_device); + if (ret != 0) { + DPRINTK("End1 ret = %x\n", ret); + return -ENODEV; + } + + ret = platform_driver_register(&wmt_saradc_driver); + DPRINTK("End2 ret = %x\n", ret); + return ret; +} + +static void __exit saradc_exit(void) +{ + DPRINTK("Start\n"); + platform_driver_unregister(&wmt_saradc_driver); + platform_device_unregister(&wmt_saradc_device); + DPRINTK("End\n"); +} + +module_init(saradc_init); +module_exit(saradc_exit); + +MODULE_AUTHOR("WonderMedia Technologies, Inc."); +MODULE_DESCRIPTION("WMT [generic saradc] driver"); +MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/input/physics_key/Kconfig b/ANDROID_3.4.5/drivers/input/physics_key/Kconfig new file mode 100755 index 00000000..98178500 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/physics_key/Kconfig @@ -0,0 +1,27 @@ +# +# Input core configuration +# +config INPUT_PKEY + bool "physics_key" if EMBEDDED || !X86 + default y + depends on INPUT + help + Say Y here, and a list of supported remote control devices will + be displayed. This option doesn't affect the kernel. + + If unsure, say y. + +config PKEY_WonderMedia + tristate "WonderMedia physics_key support" if !PC + default y + depends on INPUT && INPUT_PKEY + help + Say Y here if you want remote control support for WonderMedia. + + If unsure, say Y. + + To compile this driver as a module, choose M here: the + module will be called wmt-pkey. + + + diff --git a/ANDROID_3.4.5/drivers/input/physics_key/Makefile b/ANDROID_3.4.5/drivers/input/physics_key/Makefile new file mode 100755 index 00000000..f6c7a3f7 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/physics_key/Makefile @@ -0,0 +1,41 @@ +# +# Makefile for the input core drivers. +# + +# Each configuration option enables a list of files. + +KERNELDIR=../../../ +#KERNELDIR=/home/hangyan/android8850/kernel/ANDROID_3.0.8 +CROSS = arm_1103_le- +CC= $(CROSS)gcc +LD= $(CROSS)ld +STRIP = $(CROSS)strip + +DEBUG = n + +# Add your debugging flag (or not) to EXTRA_CFLAGS +ifeq ($(DEBUG),y) +# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines +DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines + +else + DEBFLAGS = -O2 -Wall +endif + +EXTRA_CFLAGS += $(DEBFLAGS) + + +MY_MODULE_NAME=wmt-pkey + +$(MY_MODULE_NAME)-objs := pkey.o +obj-m := $(MY_MODULE_NAME).o + + +default: + $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules + $(STRIP) --strip-debug $(MY_MODULE_NAME).ko + rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions + +clean: + rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers + diff --git a/ANDROID_3.4.5/drivers/input/physics_key/pkey.c b/ANDROID_3.4.5/drivers/input/physics_key/pkey.c new file mode 100755 index 00000000..429b57f3 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/physics_key/pkey.c @@ -0,0 +1,261 @@ +/*++ + * + * WonderMedia input remote control driver + * + * Copyright c 2010 WonderMedia Technologies, Inc. + * + * 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 . + * + * WonderMedia Technologies, Inc. + * 4F, 533, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C +--*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include +#include + + +static struct pkey_pdata { + unsigned int gpio_no; + + struct input_dev *idev; + struct timer_list *p_key_timer; + unsigned long timer_expires; +}; + +static int key_codes[2]={KEY_F1,KEY_BACK}; + +static inline void physics_key_timeout(unsigned long fcontext) +{ + struct pkey_pdata *p_key = (struct pkey_pdata *)fcontext; + int keycode; + + keycode = __gpio_get_value(p_key->gpio_no)?key_codes[1]:key_codes[0]; + + input_report_key(p_key->idev, keycode, 1); + input_sync(p_key->idev); + mdelay(50); + input_report_key(p_key->idev, keycode, 0); + input_sync(p_key->idev); + + p_key->timer_expires = 0; +} + +static irqreturn_t physics_key_isr(int irq, void *dev_id) +{ + unsigned long expires; + struct pkey_pdata *p_key = (struct pkey_pdata *)dev_id; + + if(gpio_irqstatus(p_key->gpio_no)) + { + + wmt_gpio_ack_irq(p_key->gpio_no); + expires = jiffies + msecs_to_jiffies(50); + if (!expires) + expires = 1; + + if(!(p_key->timer_expires) || time_after(expires, p_key->timer_expires)){ + mod_timer(p_key->p_key_timer, expires); + p_key->timer_expires = expires; + } + + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static int hw_init(struct platform_device *pdev) +{ + struct pkey_pdata *p_key = pdev->dev.platform_data; + + + int ret = gpio_request(p_key->gpio_no,"physics_key"); + if(ret < 0) { + printk(KERN_ERR"gpio request fail for physics_key\n"); + return ret; + } + + gpio_direction_input(p_key->gpio_no); + wmt_gpio_set_irq_type(p_key->gpio_no,IRQ_TYPE_EDGE_BOTH); + wmt_gpio_unmask_irq(p_key->gpio_no); + + request_irq(IRQ_GPIO, physics_key_isr, IRQF_SHARED, "physics_key", p_key); + + return 0; +} + +static int physics_key_probe(struct platform_device *pdev) +{ + int i; + struct pkey_pdata *p_key = pdev->dev.platform_data; + + hw_init(pdev); + + if ((p_key->idev = input_allocate_device()) == NULL) + return -ENOMEM; + + set_bit(EV_KEY, p_key->idev->evbit); + for (i = 0; i < ARRAY_SIZE(key_codes); i++) { + set_bit(key_codes[i], p_key->idev->keybit); + } + + p_key->idev->name = "physics_key"; + p_key->idev->phys = "physics_key"; + input_register_device(p_key->idev); + + p_key->p_key_timer = (struct timer_list *)kzalloc(sizeof(struct timer_list), GFP_KERNEL); + init_timer(p_key->p_key_timer); + p_key->p_key_timer->data = (unsigned long)p_key; + p_key->p_key_timer->function = physics_key_timeout; + + + return 0; +} + +static int physics_key_remove(struct platform_device *dev) +{ + struct pkey_pdata *p_key = dev->dev.platform_data; + + if(p_key->p_key_timer) + { + del_timer_sync(p_key->p_key_timer); + free_irq(IRQ_GPIO, p_key); + input_unregister_device(p_key->idev); + input_free_device(p_key->idev); + + kfree(p_key); + } + + return 0; +} + +void pkey_pdevice_release(struct device *dev) +{ + +} + +#ifdef CONFIG_PM +static int physics_key_suspend(struct platform_device *dev, pm_message_t state) +{ + struct pkey_pdata *p_key = dev->dev.platform_data; + + del_timer_sync(p_key->p_key_timer); + + wmt_gpio_mask_irq(p_key->gpio_no); + + return 0; +} + +static int physics_key_resume(struct platform_device *dev) +{ + struct pkey_pdata *p_key = dev->dev.platform_data; + + wmt_gpio_set_irq_type(p_key->gpio_no,IRQ_TYPE_EDGE_BOTH); + wmt_gpio_unmask_irq(p_key->gpio_no); + + return 0; +} +#else +#define physics_key_suspend NULL +#define physics_key_resume NULL +#endif + + + + +static struct platform_device pkey_pdevice = { + .name = "physics_key", + .id = 0, + .dev = { + .release = pkey_pdevice_release, + }, +}; + +static struct platform_driver pkey_driver = { + .probe = physics_key_probe, + .remove = physics_key_remove, + .suspend = physics_key_suspend, + .resume = physics_key_resume, + + .driver = { + .name = "physics_key", + }, +}; + +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); + +static int __init physics_key_init(void) +{ + char buf[128]; + int ret = 0; + int varlen; + int ubootvar[1]; + + + memset(buf ,0, sizeof(buf)); + varlen = sizeof(buf); + if (wmt_getsyspara("wmt.gpo.physics_switch", buf, &varlen)) { + printk(KERN_ERR"wmt.gpo.physics_switch isn't set in u-boot env! -> Use default\n"); + return -1; + } + ret = sscanf(buf, "%d", + &ubootvar[0] + ); + + struct pkey_pdata *p_key = (struct pkey_pdata *)kzalloc(sizeof(struct pkey_pdata), GFP_KERNEL); + if (p_key == NULL) + return -ENOMEM; + + p_key->gpio_no = ubootvar[0]; + + pkey_pdevice.dev.platform_data = (void *)p_key; + + if (platform_device_register(&pkey_pdevice)) + return -1; + + ret = platform_driver_register(&pkey_driver); + + return ret; +} + +static void __exit physics_key_exit(void) +{ + platform_driver_unregister(&pkey_driver); + platform_device_unregister(&pkey_pdevice); +} + +module_init(physics_key_init); +module_exit(physics_key_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("WonderMedia Technologies, Inc."); +MODULE_DESCRIPTION("WMT driver"); + diff --git a/ANDROID_3.4.5/drivers/input/remote_input.c b/ANDROID_3.4.5/drivers/input/remote_input.c new file mode 100755 index 00000000..b5919416 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/remote_input.c @@ -0,0 +1,195 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define INPUT_IOC_MAGIC 'x' +#define INPUT_IOC_CMD_INPUT _IOR(INPUT_IOC_MAGIC, 1, int) +#define INPUT_IOC_MAXNR 1 + +static struct input_dev *g_input = NULL; +static int lcdX, lcdY; +static int g_Major; +static struct mutex ioc_mutex; +static struct class *dev_class = NULL; + +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); + +static struct input_dev *input_dev_alloc(void) +{ + int err; + struct input_dev *input_dev; + input_dev = input_allocate_device(); + if (!input_dev) { + printk("failed to allocate input device\n"); + return NULL; + } + + input_dev->name = "remote_input"; + input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) | BIT_MASK(EV_REL); + set_bit(INPUT_PROP_DIRECT, input_dev->propbit); + //set_bit(ABS_MT_TRACKING_ID, input_dev->absbit); + + input_set_abs_params(input_dev, + ABS_MT_POSITION_X, 0, lcdX, 0, 0); + input_set_abs_params(input_dev, + ABS_MT_POSITION_Y, 0, lcdY, 0, 0); + //input_set_abs_params(input_dev, + // ABS_MT_TRACKING_ID, 0, 5, 0, 0); + + set_bit(KEY_BACK, input_dev->keybit); + set_bit(KEY_HOME, input_dev->keybit); + set_bit(KEY_MENU, input_dev->keybit); + set_bit(KEY_SEARCH, input_dev->keybit); + + set_bit(KEY_ENTER, input_dev->keybit); + set_bit(KEY_UP, input_dev->keybit); + set_bit(KEY_PAGEUP, input_dev->keybit); + set_bit(KEY_LEFT, input_dev->keybit); + set_bit(KEY_RIGHT, input_dev->keybit); + set_bit(KEY_DOWN, input_dev->keybit); + set_bit(KEY_PAGEDOWN, input_dev->keybit); + set_bit(KEY_VOLUMEDOWN, input_dev->keybit); + set_bit(KEY_VOLUMEUP, input_dev->keybit); + + set_bit(BTN_LEFT, input_dev->keybit); + set_bit(BTN_RIGHT, input_dev->keybit); + set_bit(BTN_MIDDLE, input_dev->keybit); + set_bit(BTN_SIDE, input_dev->keybit); + + set_bit(REL_X, input_dev->relbit); + set_bit(REL_Y, input_dev->relbit); + set_bit(REL_WHEEL, input_dev->relbit); + + err = input_register_device(input_dev); + if (err) { + printk("input_dev_alloc: failed to register input device.\n"); + input_free_device(input_dev); + input_dev = NULL; + } + + return input_dev; +} + +static long input_ioctl(struct file *dev, unsigned int cmd, unsigned long arg) +{ + struct input_event event; + if (_IOC_TYPE(cmd) != INPUT_IOC_MAGIC){ + printk("CMD ERROR!"); + return -ENOTTY; + } + + if (_IOC_NR(cmd) > INPUT_IOC_MAXNR){ + printk("NO SUCH IO CMD!\n"); + return -ENOTTY; + } + + switch (cmd) { + case INPUT_IOC_CMD_INPUT: + copy_from_user(&event, (struct input_event*)arg, sizeof(struct input_event)); + mutex_lock(&ioc_mutex); + input_event(g_input, event.type, event.code, event.value); + mutex_unlock(&ioc_mutex); + return 0; + } + return -EINVAL; +} + +static int input_open(struct inode *inode, struct file *filp) +{ + int ret = 0; + return ret; +} + +static int input_close(struct inode *inode, struct file *filp) +{ + return 0; +} + + +static struct file_operations input_fops = { + .unlocked_ioctl = input_ioctl, + .open = input_open, + .release = input_close, +}; + + +static int __init remote_init(void) +{ + struct device *dev = NULL; + int len = 127; + char retval[128] = {0},*p=NULL; + int tmp[6]; + + mutex_init(&ioc_mutex); + + if (wmt_getsyspara("wmt.display.fb0", retval, &len)) { + printk(KERN_ERR "Can't get display param. \n"); + return -EIO; + } + p = retval; + sscanf(p, "%d:[%d:%d:%d:%d:%d", &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5]); + lcdX = tmp[4]; + lcdY = tmp[5]; + + g_input = input_dev_alloc(); + if (!g_input){ + printk(KERN_ERR "Alloc input device failed. \n"); + return -ENODEV; + } + + if ((g_Major = register_chrdev(0, "remote_input", &input_fops)) < 0) { + printk(KERN_ERR "Can't register char device. \n"); + return -EIO; + } + + dev_class = class_create(THIS_MODULE,"remote_input"); + if (IS_ERR(dev_class)) { + unregister_chrdev(g_Major, "remote_input"); + printk(KERN_ERR "Class create failed. \n"); + return PTR_ERR(dev_class); + } + + dev = device_create(dev_class, NULL, MKDEV(g_Major, 0), NULL,"remote_input"); + if(!dev){ + printk(KERN_ERR "Create device failed. \n"); + return -ENODEV; + } + + return 0; +} +module_init(remote_init); + +static void __exit remote_exit(void) +{ + device_destroy(dev_class, MKDEV(g_Major, 0)); + class_destroy(dev_class); + unregister_chrdev(g_Major, "remote_input"); + + input_unregister_device(g_input); + //input_free_device(g_input); + mutex_destroy(&ioc_mutex); +} +module_exit(remote_exit); + +MODULE_DESCRIPTION("Remote Input driver"); +MODULE_LICENSE("GPL v2"); diff --git a/ANDROID_3.4.5/drivers/input/rmtctl/Kconfig b/ANDROID_3.4.5/drivers/input/rmtctl/Kconfig new file mode 100755 index 00000000..f95174a0 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/rmtctl/Kconfig @@ -0,0 +1,25 @@ +# +# Input core configuration +# +config INPUT_RMTCTL + bool "Remote controllers" if EMBEDDED || !X86 + default y + depends on INPUT + help + Say Y here, and a list of supported remote control devices will + be displayed. This option doesn't affect the kernel. + + If unsure, say Y. + +config RMTCTL_WonderMedia + tristate "WonderMedia remote control support" if !PC + default y + depends on INPUT && INPUT_RMTCTL + help + Say Y here if you want remote control support for WonderMedia. + + If unsure, say Y. + + To compile this driver as a module, choose M here: the + module will be called atkbd. + diff --git a/ANDROID_3.4.5/drivers/input/rmtctl/Makefile b/ANDROID_3.4.5/drivers/input/rmtctl/Makefile new file mode 100755 index 00000000..7a9a2167 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/rmtctl/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for the input core drivers. +# + +# Each configuration option enables a list of files. + +obj-$(CONFIG_RMTCTL_WonderMedia) += wmt-rmtctl.o + diff --git a/ANDROID_3.4.5/drivers/input/rmtctl/oem-dev.h b/ANDROID_3.4.5/drivers/input/rmtctl/oem-dev.h new file mode 100755 index 00000000..7066753e --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/rmtctl/oem-dev.h @@ -0,0 +1,186 @@ +/*++ + * linux/drivers/input/rmtctl/oem-dev-table.h + * WonderMedia input remote control driver + * + * Copyright c 2012 WonderMedia Technologies, Inc. + * + * 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 . + * + * WonderMedia Technologies, Inc. + * 4F, 533, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C +--*/ +#ifndef OEM_DEV_TABLE_H +/* To assert that only one occurrence is included */ +#define OEM_DEV_TABLE_H + +#ifdef OEM_DEV_TABLE_H + #define EXTERN +#else + #define EXTERN extern +#endif /* ifdef OEM_DEV_TABLE_H */ + + +#define RMCTL_WMT_1 +#define RMCTL_WMT_2 +#define RMCTL_TV_BOX + + +EXTERN struct rmt_dev { + char *vendor_name; + int vender_id; + unsigned int key_codes[128]; +}; + + +EXTERN struct rmt_dev rmt_dev_tbl[ ] = { + #ifdef RMCTL_WMT_1 + { + .vendor_name = "WMT_1", + .vender_id = 0x00ff, + .key_codes = { + [0] = KEY_POWER, + [1] = KEY_RESERVED, + [2] = KEY_RESERVED, + [3] = KEY_MUTE, + [4] = KEY_CLEAR, + [5] = KEY_UP, + [6] = KEY_ESC, + [7] = KEY_SCREEN, /* P/N */ + [8] = KEY_LEFT, + [9] = KEY_ENTER, + [10] = KEY_RIGHT, + [11] = KEY_SETUP, + [12] = KEY_F1, + [13] = KEY_DOWN, + [14] = KEY_F2, + [15] = KEY_STOP, + [16] = KEY_1, + [17] = KEY_2, + [18] = KEY_3, + [19] = KEY_TIME, + [20] = KEY_4, + [21] = KEY_5, + [22] = KEY_6, + [23] = KEY_PLAYPAUSE, + [24] = KEY_7, + [25] = KEY_8, + [26] = KEY_9, + [27] = KEY_VOLUMEUP, + [28] = KEY_0, + [29] = KEY_BACK, + [30] = KEY_FORWARD, + [31] = KEY_VOLUMEDOWN + }, + }, + #endif + #ifdef RMCTL_WMT_2 + { + .vendor_name = "WMT_2", + .vender_id = 0x40bf, + .key_codes = { + [0] = KEY_RESERVED, /* KARAOKE */ + [1] = KEY_RESERVED, /* FUN- */ + [2] = KEY_RESERVED, /* ANGLE */ + [3] = KEY_VOLUMEDOWN, + [4] = KEY_CLEAR, + [5] = KEY_0, + [6] = KEY_F1, /* DIGEST */ + [7] = KEY_ZOOM, + [8] = KEY_7, + [9] = KEY_8, + [10] = KEY_NEXT, + [11] = KEY_VOLUMEUP, + [12] = KEY_4, + [13] = KEY_5, + [14] = KEY_POWER, + [15] = KEY_MUTE, + [16] = KEY_1, + [17] = KEY_2, + [18] = KEY_SUBTITLE, + [19] = KEY_RESERVED, /* RETURN */ + [20] = KEY_RECORD, + [21] = KEY_RESERVED, /* STEP */ + [22] = KEY_RESERVED, /* A-B */ + [23] = KEY_RESERVED, /* STEP B*/ + [24] = KEY_BACK, + [25] = KEY_PLAY, + [26] = KEY_EJECTCD, + [27] = KEY_RESERVED, /* FF */ + [28] = KEY_LEFT, + [29] = KEY_DOWN, + [30] = KEY_F2, /* Menu/PBC */ + [31] = KEY_PLAYPAUSE, /* SF */ + /* Keycode 32 - 63 are invalid. */ + [64] = KEY_AUDIO, + [65] = KEY_SETUP, + [66] = KEY_RESERVED, /* FUN+ */ + [67] = KEY_RESERVED, /* MARK */ + [68] = KEY_UP, + [69] = KEY_RESERVED, /* +10 */ + [70] = KEY_RESERVED, /* INVALID */ + [71] = KEY_RESERVED, /* SURR */ + [72] = KEY_RIGHT, + [73] = KEY_9, + [74] = KEY_RESERVED, /* INVALID */ + [75] = KEY_RESERVED, /* VOCAL */ + [76] = KEY_TV, + [77] = KEY_6, + [78] = KEY_RESERVED, /* INVALID */ + [79] = KEY_PROGRAM, /* PROG */ + [80] = KEY_RESERVED, /* DISPLAY */ + [81] = KEY_3, + [82] = KEY_RESERVED, /* INVALID */ + [83] = KEY_RESERVED, /* INVALID */ + [84] = KEY_GOTO, + [85] = KEY_PREVIOUS, /* Prev/ASV- */ + [86] = KEY_RESERVED, /* INVALID */ + [87] = KEY_RESERVED, /* INVALID */ + [88] = KEY_RESERVED, /* Repeat */ + [89] = KEY_STOP, + [90] = KEY_RESERVED, /* INVALID */ + [91] = KEY_RESERVED, /* INVALID */ + [92] = KEY_ENTER, + [93] = KEY_TITLE + }, + }, + #endif + #ifdef RMCTL_TV_BOX + { + .vendor_name = "TV_BOX", + .vender_id = 0x2fd, + .key_codes = { + [0x57] = KEY_END, /* power down */ + [0x56] = KEY_VOLUMEDOWN, /* vol- */ + [0x14] = KEY_VOLUMEUP, /* vol+ */ + [0x53] = KEY_HOME, /* home */ + [0x11] = KEY_MENU, /* menu */ + [0x10] = KEY_BACK, /* back */ + [0x4b] = KEY_ZOOMOUT, /* zoom out */ + [0x08] = KEY_ZOOMIN, /* zoom in */ + [0x0d] = KEY_UP, /* up */ + [0x4e] = KEY_LEFT, /* left */ + [0x19] = KEY_REPLY, /* OK */ + [0x0c] = KEY_RIGHT, /* right */ + [0x4f] = KEY_DOWN, /* down */ + [0x09] = KEY_PAGEUP, /* page up */ + [0x47] = KEY_REWIND, /* rewind */ + [0x05] = KEY_PAGEDOWN, /* page down */ + [0x04] = KEY_FASTFORWARD /* forward */ + }, + }, + #endif +}; +#undef EXTERN + +#endif diff --git a/ANDROID_3.4.5/drivers/input/rmtctl/wmt-rmtctl.c b/ANDROID_3.4.5/drivers/input/rmtctl/wmt-rmtctl.c new file mode 100755 index 00000000..44f3b30b --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/rmtctl/wmt-rmtctl.c @@ -0,0 +1,1515 @@ +/*++ + * linux/drivers/input/rmtctl/wmt-rmtctl.c + * WonderMedia input remote control driver + * + * Copyright c 2010 WonderMedia Technologies, Inc. + * + * 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 . + * + * WonderMedia Technologies, Inc. + * 4F, 533, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C +--*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wmt-rmtctl.h" + +enum CIR_CODEC_TYPE { + CIR_CODEC_NEC = 0, + CIR_CODEC_TOSHIBA = 1, + CIR_CODEC_PHILIPS_RC6 = 2, + CIR_CODEC_MAX, +}; + +struct cir_param { + enum CIR_CODEC_TYPE codec; + unsigned int param[7]; + unsigned int repeat_timeout; +}; + +struct cir_vendor_info { + char *vendor_name; + enum CIR_CODEC_TYPE codec; + + unsigned int vendor_code; + unsigned int wakeup_code; + unsigned int key_codes[258]; // usb-keyboard standard +}; + +#define RMTCTL_DEBUG 0 +#define REL_DELTA 20 +#define WMT_RMTCTL_VENDOR_ENV "wmt.io.rmtctl.vendorcode" +struct rmtctl_led{ + int gpio; + int active; + int on; + int enable; + struct timer_list timer; +}; + +struct rmtctl_rel { + int on; + unsigned int code; + struct timer_list timer; + struct input_dev *input; +}; + +struct rmtctl_priv { + enum CIR_CODEC_TYPE codec; + int vendor_index; + int table_index; + unsigned int saved_vcode; + unsigned int vendor_code; + unsigned int scan_code; + + struct input_dev *idev; + struct timer_list timer; + struct delayed_work delaywork; + + struct rmtctl_led led;//led control + + struct rmtctl_rel rel_dev;//remote cursor removing +}; + +static struct cir_param rmtctl_params[] = { + // NEC : |9ms carrier wave| + |4.5ms interval| + [CIR_CODEC_NEC] = { + .codec = CIR_CODEC_NEC, + .param = { 0x10a, 0x8e, 0x42, 0x55, 0x9, 0x13, 0x13 }, + .repeat_timeout = 17965000, + }, + + // TOSHIBA : |4.5ms carrier wave| + |4.5ms interval| + [CIR_CODEC_TOSHIBA] = { + .codec = CIR_CODEC_TOSHIBA, + .param = { 0x8e, 0x8e, 0x42, 0x55, 0x9, 0x13, 0x13 }, + .repeat_timeout = 17965000, + }, + + [CIR_CODEC_PHILIPS_RC6] = { + .codec = CIR_CODEC_PHILIPS_RC6, + .param = { 0x7, 0x15, 0x23, 0x31, 0x40, 0x4C, 0x5B }, + .repeat_timeout = 17965000, + }, +}; + +static struct cir_vendor_info rmtctl_vendors[] = { + // SRC1804 0 + { + .vendor_name = "SRC1804", + .codec = CIR_CODEC_NEC, + .vendor_code = 0x02fd, + .wakeup_code = 0x57, + .key_codes = { + [0x57] = KEY_POWER, /* power down */ + [0x56] = KEY_VOLUMEDOWN, /* vol- */ + [0x14] = KEY_VOLUMEUP, /* vol+ */ + [0x53] = KEY_HOME, /* home */ + [0x11] = KEY_MENU, /* menu */ + [0x10] = KEY_BACK, /* back */ + [0x4b] = KEY_ZOOMOUT, /* zoom out */ + [0x08] = KEY_ZOOMIN, /* zoom in */ + [0x0d] = KEY_UP, /* up */ + [0x4e] = KEY_LEFT, /* left */ + [0x19] = KEY_ENTER, /* OK */ + [0x0c] = KEY_RIGHT, /* right */ + [0x4f] = KEY_DOWN, /* down */ + [0x09] = KEY_PAGEUP, /* page up */ + [0x47] = KEY_PREVIOUSSONG, /* rewind */ + [0x05] = KEY_PAGEDOWN, /* page down */ + [0x04] = KEY_NEXTSONG /* forward */ + }, + }, + + // IH8950 1 + { + .vendor_name = "IH8950", + .codec = CIR_CODEC_NEC, + .vendor_code = 0x0909, + .wakeup_code = 0xdc, + .key_codes = { + [0xdc] = KEY_POWER, /* power down */ + [0x81] = KEY_VOLUMEDOWN, /* vol- */ + [0x80] = KEY_VOLUMEUP, /* vol+ */ + [0x82] = KEY_HOME, /* home */ + [0xc5] = KEY_BACK, /* back */ + [0xca] = KEY_UP, /* up */ + [0x99] = KEY_LEFT, /* left */ + [0xce] = KEY_ENTER, /* OK */ + [0xc1] = KEY_RIGHT, /* right */ + [0xd2] = KEY_DOWN, /* down */ + [0x9c] = KEY_MUTE, + [0x95] = KEY_PLAYPAUSE, + [0x88] = KEY_MENU, + }, + }, + + // sunday 2 + { + .vendor_name = "sunday", + .codec = CIR_CODEC_NEC, + .vendor_code = 0x02fd, + .wakeup_code = 0x1a, + .key_codes = { + [0x1a] = KEY_POWER, /* power down */ + [0x16] = KEY_VOLUMEDOWN, /* vol- */ + [0x44] = KEY_VOLUMEUP, /* vol+ */ + [0x59] = KEY_HOME, /* home */ + [0x1b] = KEY_BACK, /* back */ + [0x06] = KEY_UP, /* up */ + [0x5d] = KEY_LEFT, /* left */ + [0x1e] = KEY_ENTER, /* OK */ + [0x5c] = KEY_RIGHT, /* right */ + [0x1f] = KEY_DOWN, /* down */ + [0x55] = KEY_PLAYPAUSE, + [0x54] = KEY_REWIND, + [0x17] = KEY_FASTFORWARD, + [0x58] = KEY_AGAIN, /* recent app */ + }, + }, + + /* F1 - F12 */ + // KT-9211 3 + { + .vendor_name = "KT-9211", + .codec = CIR_CODEC_NEC, + .vendor_code = 0x02fd, + .wakeup_code = 0x57, + .key_codes = { + [0x57] = KEY_POWER, /* power down */ + [0x56] = KEY_VOLUMEDOWN, /* volume- */ + [0x15] = KEY_MUTE, /* mute */ + [0x14] = KEY_VOLUMEUP, /* volume+ */ + [0x0d] = KEY_UP, /* up */ + [0x4e] = KEY_LEFT, /* left */ + [0x19] = KEY_ENTER, /* OK */ + [0x0c] = KEY_RIGHT, /* right */ + [0x4f] = KEY_DOWN, /* down */ + [0x53] = KEY_HOME, /* home */ + [0x09] = KEY_F5, /* my photo in default */ + [0x11] = KEY_F12, /* setting apk in default */ + [0x47] = KEY_F3, /* My Music in default */ + [0x10] = KEY_BACK, /* Back */ + [0x08] = KEY_F4, /* my video in default */ + [0x17] = KEY_F1, /* web browser in default */ + + //Following items are configured manually. + [0x05] = KEY_F10, /* file browser in default */ + [0x04] = KEY_F2, /* camera in default */ + [0x4b] = KEY_F11, /* calendar in default */ + [0x16] = KEY_SCREEN, /* calculator in default */ + [0x18] = KEY_F9, /* recorder in default */ + }, + }, + + // KT-8830 4 + { + .vendor_name = "KT-8830", + .codec = CIR_CODEC_NEC, + .vendor_code = 0x866b, + .wakeup_code = 0x1c, + .key_codes = { + [0x1c] = KEY_POWER, + [0x14] = KEY_MUTE, + [0x09] = KEY_1, + [0x1d] = KEY_2, + [0x1f] = KEY_3, + [0x0d] = KEY_4, + [0x19] = KEY_5, + [0x1b] = KEY_6, + [0x11] = KEY_7, + [0x15] = KEY_8, + [0x17] = KEY_9, + [0x12] = KEY_0, + [0x16] = KEY_VOLUMEDOWN, + [0x04] = KEY_VOLUMEUP, + [0x40] = KEY_HOME, + [0x4c] = KEY_BACK, + [0x00] = KEY_F12, // setup + [0x13] = KEY_MENU, + [0x03] = KEY_UP, + [0x0e] = KEY_LEFT, + [0x1a] = KEY_RIGHT, + [0x02] = KEY_DOWN, + [0x07] = KEY_ENTER, + [0x47] = KEY_F4, // video + [0x10] = KEY_F3, // music + [0x0f] = KEY_FASTFORWARD, + [0x43] = KEY_REWIND, + [0x18] = KEY_F1, // browser + [0x0b] = KEY_YEN, // multi-functions + [0x4e] = KEY_PLAYPAUSE, + }, + }, + + // Haier-OTT 5 + { + .vendor_name = "Haier-OTT", + .codec = CIR_CODEC_NEC, + .vendor_code = 0xb34c, + .wakeup_code = 0xdc, + .key_codes = { + [0xdc] = KEY_POWER, + [0x9c] = KEY_MUTE, + [0xca] = KEY_UP, + [0x99] = KEY_LEFT, + [0xc1] = KEY_RIGHT, + [0xd2] = KEY_DOWN, + [0xce] = KEY_ENTER, + [0x80] = KEY_VOLUMEDOWN, + [0x81] = KEY_VOLUMEUP, + [0xc5] = KEY_HOME, + [0x95] = KEY_BACK, + [0x88] = KEY_MENU, + [0x82] = KEY_F12, /* setting apk in default */ + }, + }, + + // GPRC-11933 6 + { + .vendor_name = "GPRC-11933", + .codec = CIR_CODEC_NEC, + .vendor_code = 0x4040, + .wakeup_code = 0x4D, + .key_codes = { + [0x4D] = KEY_POWER, /* power down */ + [0x53] = KEY_PLAYPAUSE, + [0x5B] = KEY_F3, /* My Music in default */ + [0x57] = KEY_F1, /* web browser in default */ + [0x54] = KEY_F10, /* file browser in default */ + + [0x17] = KEY_VOLUMEDOWN, /* volume- */ + [0x43] = KEY_MUTE, /* mute */ + [0x18] = KEY_VOLUMEUP, /* volume+ */ + [0x1F] = KEY_PREVIOUSSONG, /* rewind */ + [0x1E] = KEY_NEXTSONG, /* forward */ + + [0x0B] = KEY_UP, /* up */ + [0x10] = KEY_LEFT, /* left */ + [0x0D] = KEY_ENTER, /* OK */ + [0x11] = KEY_RIGHT, /* right */ + [0x0E] = KEY_DOWN, /* down */ + [0x1A] = KEY_HOME, /* home */ + [0x42] = KEY_BACK, /* Back */ + + [0x45] = KEY_F12, /* setting apk in default */ + [0x47] = KEY_KATAKANA, /* multi-functions */ + [0x01] = KEY_1, + [0x02] = KEY_2, + [0x03] = KEY_3, + [0x04] = KEY_4, + [0x05] = KEY_5, + [0x06] = KEY_6, + [0x07] = KEY_7, + [0x08] = KEY_8, + [0x09] = KEY_9, + [0x00] = KEY_0, + [0x44] = KEY_MENU, + [0x0C] = KEY_BACKSPACE, + }, + }, + + // TS-Y118 7 + { + .vendor_name = "TS-Y118", + .codec = CIR_CODEC_NEC, + .vendor_code = 0xb34c, + .wakeup_code = 0xdc, + .key_codes = { + [0xdc] = KEY_POWER, + [0x9c] = KEY_MUTE, + [0x8d] = KEY_F12, // apk-settings + [0x88] = KEY_HOME, + [0xca] = KEY_UP, + [0xd2] = KEY_DOWN, + [0x99] = KEY_LEFT, + [0xc1] = KEY_RIGHT, + [0xce] = KEY_ENTER, + [0x95] = KEY_PLAYPAUSE, + [0xc5] = KEY_BACK, + [0x80] = KEY_VOLUMEUP, + [0x81] = KEY_VOLUMEDOWN, + [0xdd] = KEY_PAGEUP, + [0x8c] = KEY_PAGEDOWN, + [0x92] = KEY_1, + [0x93] = KEY_2, + [0xcc] = KEY_3, + [0x8e] = KEY_4, + [0x8f] = KEY_5, + [0xc8] = KEY_6, + [0x8a] = KEY_7, + [0x8b] = KEY_8, + [0xc4] = KEY_9, + [0x87] = KEY_0, + }, + }, + + // Hisense 8 + { + .vendor_name = "Hisense", + .codec = CIR_CODEC_NEC, + .vendor_code = 0x00ff, + .wakeup_code = 0x14, + .key_codes = { + [0x14] = KEY_POWER, + [0x1c] = KEY_MUTE, + [0x40] = KEY_PAGEUP, + [0x44] = KEY_PAGEDOWN, + [0x0b] = KEY_VOLUMEUP, + [0x58] = KEY_VOLUMEDOWN, + [0x01] = KEY_MENU, + [0x03] = KEY_UP, + [0x02] = KEY_DOWN, + [0x0e] = KEY_LEFT, + [0x1a] = KEY_RIGHT, + [0x07] = KEY_ENTER, + [0x48] = KEY_HOME, + [0x5c] = KEY_BACK, + [0x09] = KEY_1, + [0x1d] = KEY_2, + [0x1f] = KEY_3, + [0x0d] = KEY_4, + [0x19] = KEY_5, + [0x1b] = KEY_6, + [0x11] = KEY_7, + [0x15] = KEY_8, + [0x17] = KEY_9, + [0x12] = KEY_0, + [0x06] = KEY_DOT, + [0x16] = KEY_DELETE, + [0x0c] = KEY_ZOOMIN, + [0x4c] = KEY_F11, + [0x13] = KEY_YEN, + }, + }, + + // Mountain 9 + { + .vendor_name = "TV BOX Mountain", + .codec = CIR_CODEC_NEC, + .vendor_code = 0x00df, + .wakeup_code = 0x1c, + .key_codes = { + [0x1c] = KEY_POWER, /* power down */ + [0x08] = KEY_MUTE, /* volume mute */ + [0x1a] = KEY_UP, /* up */ + [0x47] = KEY_LEFT, /* left */ + [0x06] = KEY_ENTER, /* OK */ + [0x07] = KEY_RIGHT, /* right */ + [0x48] = KEY_DOWN, /* down */ + [0x4f] = KEY_VOLUMEDOWN, /* vol- */ + [0x4b] = KEY_VOLUMEUP, /* vol+ */ + [0x0a] = KEY_BACK, /* back */ + [0x03] = KEY_HOME, /* home */ + [0x42] = KEY_KATAKANA, /* TV */ + [0x55] = KEY_MENU, /* menu */ + }, + }, + + // GPRC-11933 10 + { + .vendor_name = "GPRC-11933A", + .codec = CIR_CODEC_NEC, + .vendor_code = 0x00FF, + .wakeup_code = 0x57, + .key_codes = { + [0x57] = KEY_POWER, /* power down */ + [0x5B] = KEY_MUTE, /* mute */ + + [0x16] = KEY_F3, /* My Musicin default */ + [0x5A] = KEY_F1, /* web browser in default */ + [0x52] = KEY_PLAYPAUSE, + [0x50] = KEY_KATAKANA, /* cursor */ + + [0x0F] = KEY_PREVIOUSSONG, /* rewind */ + [0x4C] = KEY_NEXTSONG, /* forward */ + [0x58] = KEY_VOLUMEDOWN, /* volume- */ + [0x1B] = KEY_VOLUMEUP, /* volume+ */ + + [0x4F] = KEY_F12, /* setting apk in default */ + [0x1A] = KEY_MENU, + + [0x43] = KEY_UP, /* up */ + + [0x06] = KEY_LEFT, /* left */ + [0x02] = KEY_ENTER, /* OK */ + [0x0E] = KEY_RIGHT, /* right */ + + [0x0A] = KEY_DOWN, /* down */ + + [0x4E] = KEY_HOME, /* home */ + [0x4D] = KEY_BACK, /* back */ + + [0x10] = KEY_1, + [0x11] = KEY_2, + [0x12] = KEY_3, + [0x13] = KEY_4, + [0x14] = KEY_5, + [0x15] = KEY_6, + [0x17] = KEY_7, + [0x18] = KEY_8, + [0x19] = KEY_9, + [0x1D] = KEY_0, + + [0x1C] = KEY_F1, + [0x1E] = KEY_BACKSPACE, + }, + }, + + //China Telecom White 11 + { + .vendor_name = "TS-Y118A", + .codec = CIR_CODEC_NEC, + .vendor_code = 0xb34c, + .wakeup_code = 0xdc, + .key_codes = { + [0xdc] = KEY_POWER, + + [0x98] =KEY_AUDIO, + [0x9c] = KEY_MUTE, + + [0x8d] = KEY_SETUP, + [0xd6] = KEY_LAST, + + [0xcd] = KEY_RED, + [0x91] = KEY_GREEN, + [0x83] = KEY_YELLOW, + [0xc3] = KEY_BLUE, + + [0x88] = KEY_HOMEPAGE, + [0xca] = KEY_UP, + [0x82] = KEY_HOME, + + [0x99] = KEY_LEFT, + [0xce] = KEY_SELECT, + [0xc1] = KEY_RIGHT, + + [0x95] = KEY_PLAYPAUSE, + [0xd2] = KEY_DOWN, + [0xc5] = KEY_BACK, + + [0x80] = KEY_VOLUMEUP, + [0x81] = KEY_VOLUMEDOWN, + + [0xdd] = KEY_PAGEUP, + [0x8c] = KEY_PAGEDOWN, + + [0x85] = KEY_CHANNELUP, + [0x86] = KEY_CHANNELDOWN, + + [0x92] = KEY_1, + [0x93] = KEY_2, + [0xcc] = KEY_3, + [0x8e] = KEY_4, + [0x8f] = KEY_5, + [0xc8] = KEY_6, + [0x8a] = KEY_7, + [0x8b] = KEY_8, + [0xc4] = KEY_9, + [0x87] = KEY_0, + + [0xda] = KEY_NUMERIC_STAR, + [0xd0] = KEY_NUMERIC_POUND, + }, + }, + + //China Telecom Black 12 + { + .vendor_name = "TS-Y118B", + .codec = CIR_CODEC_NEC, + .vendor_code = 0xb24d, + .wakeup_code = 0xdc, + .key_codes = { + [0xdc] = KEY_POWER, + + [0x98] =KEY_AUDIO, + [0x9c] = KEY_MUTE, + + [0x8d] = KEY_SETUP, + [0xd6] = KEY_LAST, + + [0xcd] = KEY_RED, + [0x91] = KEY_GREEN, + [0x83] = KEY_YELLOW, + [0xc3] = KEY_BLUE, + + [0x88] = KEY_HOMEPAGE, + [0xca] = KEY_UP, + [0x82] = KEY_HOME, + + [0x99] = KEY_LEFT, + [0xce] = KEY_SELECT, + [0xc1] = KEY_RIGHT, + + [0x95] = KEY_PLAYPAUSE, + [0xd2] = KEY_DOWN, + [0xc5] = KEY_BACK, + + [0x80] = KEY_VOLUMEUP, + [0x81] = KEY_VOLUMEDOWN, + + [0xdd] = KEY_PAGEUP, + [0x8c] = KEY_PAGEDOWN, + + [0x85] = KEY_CHANNELUP, + [0x86] = KEY_CHANNELDOWN, + + [0x92] = KEY_1, + [0x93] = KEY_2, + [0xcc] = KEY_3, + [0x8e] = KEY_4, + [0x8f] = KEY_5, + [0xc8] = KEY_6, + [0x8a] = KEY_7, + [0x8b] = KEY_8, + [0xc4] = KEY_9, + [0x87] = KEY_0, + + [0xda] = KEY_NUMERIC_STAR, + [0xd0] = KEY_NUMERIC_POUND, + }, + }, + + // Jensen 13 + { + .vendor_name = "Jensen", + .codec = CIR_CODEC_NEC, + .vendor_code = 0x00ff, + .wakeup_code = 0x46, + .key_codes = { + [0x08] = KEY_RESERVED, + + [0x5a] = KEY_VOLUMEUP, + [0x4a] = KEY_VOLUMEDOWN, + + [0x19] = KEY_UP, + [0x1c] = KEY_DOWN, + [0x0c] = KEY_LEFT, + [0x5e] = KEY_RIGHT, + [0x18] = KEY_ENTER, + + [0x0d] = KEY_BACK, + [0x45] = KEY_1, + [0x46] = KEY_POWER, + [0x47] = KEY_3, + [0x44] = KEY_4, + [0x40] = KEY_F1, + [0x43] = KEY_6, + [0x07] = KEY_7, + [0x15] = KEY_BACK, + [0x09] = KEY_9, + [0x16] = KEY_0, + + [0x42] = KEY_PREVIOUSSONG, /* rewind */ + [0x52] = KEY_NEXTSONG, /* forward */ + + }, + }, + // Foxconn 14 + { + .vendor_name = "CIR-9F", + .codec = CIR_CODEC_NEC, + .vendor_code = 0x009f, + .wakeup_code = 0x57, + .key_codes = { + [0x57] = KEY_POWER, /* power */ + [0x5d] = KEY_VOLUMEDOWN, /* vol- */ + [0xff] = KEY_VOLUMEUP, /* vol+ */ + [0x47] = KEY_HOME, /* home */ + [0x16] = KEY_MENU, /* menu */ + [0x4f] = KEY_BACK, /* back */ + [0x43] = KEY_UP, /* up */ + [0x06] = KEY_LEFT, /* left */ + [0x02] = KEY_ENTER, /* PLAYPAUSE */ + //[0x02] = KEY_PLAYPAUSE, /* PLAYPAUSE */ + [0x0e] = KEY_RIGHT, /* right */ + [0x0a] = KEY_DOWN, /* down */ + [0x0b] = KEY_REWIND, /* rewind data is 0x36*/ + [0x0f] = KEY_FASTFORWARD, /* forward */ + + [0x5b] = KEY_ENTER /* OK - notify */ + }, + }, + + // Philips 15 + { + .vendor_name = "PHILIPS", + .codec = CIR_CODEC_PHILIPS_RC6, + .vendor_code = 60, + .wakeup_code = 12, + .key_codes = { + [12] = KEY_POWER, + [146] = KEY_HOME, + [84] = KEY_MENU, + [92] = KEY_ENTER, + [88] = KEY_UP, + [89] = KEY_DOWN, + [90] = KEY_LEFT, + [91] = KEY_RIGHT, + [83] = BTN_DEAD, + [131] = KEY_BACK, + }, + }, + + //Ronsheng 16 + { + .vendor_name = "Ronsheng", + .codec = CIR_CODEC_NEC, + .vendor_code = 0x00FF, + .wakeup_code = 0x18, + .key_codes = { + [0x18] = KEY_POWER, /* power down */ + + [0x56] = KEY_F3, /* My Musicin default */ + [0x57] = KEY_F1, /* web browser in default */ + + [0x1f] = KEY_PREVIOUSSONG, /* rewind */ + [0x5b] = KEY_NEXTSONG, /* forward */ + + [0x14] = KEY_VOLUMEDOWN, /* volume- */ + [0x08] = KEY_MUTE, /* mute */ + [0x10] = KEY_VOLUMEUP, /* volume+ */ + + [0x17] = KEY_KATAKANA, /* cursor */ + [0x04] = KEY_MENU, + + [0x46] = KEY_UP, /* up */ + [0x47] = KEY_LEFT, /* left */ + [0x55] = KEY_ENTER, /* OK */ + [0x15] = KEY_RIGHT, /* right */ + [0x16] = KEY_DOWN, /* down */ + + [0x06] = KEY_HOME, /* home */ + [0x40] = KEY_BACK, /* back */ + + [0x54] = KEY_1, + [0x48] = KEY_2, + [0x07] = KEY_3, + [0x50] = KEY_4, + [0x12] = KEY_5, + [0x11] = KEY_6, + [0x4c] = KEY_7, + [0x0e] = KEY_8, + [0x0d] = KEY_9, + [0x0c] = KEY_0, + [0x41] = KEY_RESERVED, + [0x4b] = KEY_BACKSPACE, + + }, + }, + + // GPRC-11933 17 + { + .vendor_name = "GPRC-11933", + .codec = CIR_CODEC_NEC, + .vendor_code = 0x4040, + .wakeup_code = 0x4D, + .key_codes = { + [0x4D] = KEY_POWER, /* power down */ + [0x53] = KEY_F1, + [0x5B] = KEY_F2, + [0x57] = KEY_F3, + [0x54] = KEY_F4, + + [0x17] = KEY_VOLUMEDOWN, /* volume- */ + [0x43] = KEY_MUTE, /* mute */ + [0x18] = KEY_VOLUMEUP, /* volume+ */ + + [0x1F] = KEY_F12, /* setting */ + [0x1E] = KEY_F5, + + [0x0B] = KEY_UP, /* up */ + [0x10] = KEY_LEFT, /* left */ + [0x0D] = KEY_ENTER, /* OK */ + [0x11] = KEY_RIGHT, /* right */ + [0x0E] = KEY_DOWN, /* down */ + [0x1A] = KEY_HOME, /* home */ + [0x47] = KEY_BACK, /* Back */ + + [0x45] = KEY_MENU, /* MENU */ + [0x42] = KEY_KATAKANA, /* multi-functions */ + [0x01] = KEY_1, + [0x02] = KEY_2, + [0x03] = KEY_3, + [0x04] = KEY_4, + [0x05] = KEY_5, + [0x06] = KEY_6, + [0x07] = KEY_7, + [0x08] = KEY_8, + [0x09] = KEY_9, + [0x00] = KEY_0, + [0x44] = KEY_AGAIN, + [0x0C] = KEY_BACKSPACE, + }, + }, + + +}; + +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); +extern int wmt_setsyspara(char *varname, char *varval); + +static int rmtctl_report_rel(struct rmtctl_rel *rel_dev,const unsigned int code ) +{ + switch (code) { + case KEY_UP: + input_report_rel(rel_dev->input, REL_X, 0); + input_report_rel(rel_dev->input, REL_Y, -REL_DELTA); + input_sync(rel_dev->input); + break; + case KEY_DOWN: + input_report_rel(rel_dev->input, REL_X, 0); + input_report_rel(rel_dev->input, REL_Y, REL_DELTA); + input_sync(rel_dev->input); + break; + case KEY_LEFT: + input_report_rel(rel_dev->input, REL_X, -REL_DELTA); + input_report_rel(rel_dev->input, REL_Y, 0); + input_sync(rel_dev->input); + break; + case KEY_RIGHT: + input_report_rel(rel_dev->input, REL_X, REL_DELTA); + input_report_rel(rel_dev->input, REL_Y, 0); + input_sync(rel_dev->input); + break; + default: + break; + } + return 0; +} + +static void rmtctl_report_event(unsigned int *code, int repeat) +{ + static unsigned int last_code = KEY_RESERVED; + int ret; + struct rmtctl_priv *priv = container_of(code, struct rmtctl_priv, scan_code); + + ret = del_timer(&priv->timer); + + if (!repeat) { + // new code coming + if (ret == 1) { + // del_timer() of active timer returns 1 means that active timer has been stoped by new key, + // so report last key up event + if (RMTCTL_DEBUG) + printk("[%d] up reported caused by new key[%d]\n", last_code, *code); + + if (priv->rel_dev.on) { + switch (*code) { + case KEY_UP: + case KEY_DOWN: + case KEY_LEFT: + case KEY_RIGHT: + del_timer(&priv->rel_dev.timer); //stop report mouse + break; + case KEY_ENTER: + input_report_key(priv->rel_dev.input, BTN_LEFT, 0); + input_sync(priv->rel_dev.input); + del_timer(&priv->rel_dev.timer); //stop report mouse + break; + default: + input_report_key(priv->idev, last_code, 0); + input_sync(priv->idev); + break; + } + } + else { + input_report_key(priv->idev, last_code, 0); + input_sync(priv->idev); + } + + if (*code == KEY_KATAKANA) { + if (priv->rel_dev.on == 0) { + input_report_rel(priv->rel_dev.input, REL_X, 1); + input_report_rel(priv->rel_dev.input, REL_Y, 1); + input_sync(priv->rel_dev.input); + priv->rel_dev.on = 1; + } + else + priv->rel_dev.on = 0; + } + + } + + if (RMTCTL_DEBUG) + printk("[%d] down\n", *code); + + // report key down event, mod_timer() to report key up event later for measure key repeat. + + if (priv->rel_dev.on) { + switch (*code) { + case KEY_UP: + case KEY_DOWN: + case KEY_LEFT: + case KEY_RIGHT: + rmtctl_report_rel(&priv->rel_dev,*code); + break; + case KEY_ENTER: + input_report_key(priv->rel_dev.input, BTN_LEFT, 1); + input_sync(priv->rel_dev.input); + break; + default: + input_event(priv->idev, EV_KEY, *code, 1); + input_sync(priv->idev); + break; + } + } + else { + input_event(priv->idev, EV_KEY, *code, 1); + input_sync(priv->idev); + } + + if(priv->led.enable){ + priv->led.on = 0; + gpio_direction_output(priv->led.gpio, !priv->led.active); + mod_timer(&priv->led.timer, jiffies+HZ/20); + } + + priv->timer.data = (unsigned long)code; + mod_timer(&priv->timer, jiffies + 250*HZ/1000); + } + else { + // report key up event after report repeat event according to usb-keyboard standard + priv->timer.data = (unsigned long)code; + mod_timer(&priv->timer, jiffies + 250*HZ/1000); + + // detect 'repeat' flag, report repeat event + if (*code != KEY_POWER && *code != KEY_END) { + if (RMTCTL_DEBUG) + printk("[%d] repeat\n", *code); + + if (priv->rel_dev.on) { + switch (*code) { + case KEY_UP: + case KEY_DOWN: + case KEY_LEFT: + case KEY_RIGHT: + case KEY_ENTER: + priv->rel_dev.code = *code; + mod_timer(&priv->rel_dev.timer, jiffies+HZ/100); //ready to repeat report mouse event + break; + default: + input_event(priv->idev, EV_KEY, *code, 2); + input_sync(priv->idev); + break; + } + } + else { + input_event(priv->idev, EV_KEY, *code, 2); + input_sync(priv->idev); + } + } + } + + last_code = *code; +} + +/** no hw repeat detect, so we measure repeat timeout event by timer */ +static void rmtctl_report_event_without_hwrepeat(unsigned int *code) +{ + static unsigned int last_code = KEY_RESERVED; + static unsigned long last_jiffies = 0; + int repeat = (jiffies_to_msecs(jiffies - last_jiffies) <250 && *code==last_code) ? 1 : 0; + + last_code = *code; + last_jiffies = jiffies; + + rmtctl_report_event(code, repeat); +} + +static void rmtctl_timer_handler(unsigned long data) +{ + struct rmtctl_priv *priv = container_of((void *)data, struct rmtctl_priv, scan_code); + unsigned int code = *(unsigned int *)data; + + // report key up event + if (RMTCTL_DEBUG) + printk("[%d] up reported by timer\n", code); + + if (priv->rel_dev.on) { + switch (code) { + case KEY_UP: + case KEY_DOWN: + case KEY_LEFT: + case KEY_RIGHT: + del_timer(&priv->rel_dev.timer); + break; + case KEY_ENTER: + input_report_key(priv->rel_dev.input, BTN_LEFT, 0); + input_sync(priv->rel_dev.input); + break; + default: + input_report_key(priv->idev, code, 0); + input_sync(priv->idev); + break; + } + } + else { + input_report_key(priv->idev, code, 0); + input_sync(priv->idev); + } + + if (code == KEY_KATAKANA) { + if (priv->rel_dev.on == 0) { + input_report_rel(priv->rel_dev.input, REL_X, 1); + input_report_rel(priv->rel_dev.input, REL_Y, 1); + input_sync(priv->rel_dev.input); + priv->rel_dev.on = 1; + } + else + priv->rel_dev.on = 0; + } + + if(priv->led.enable){ + del_timer_sync(&priv->led.timer); + gpio_direction_output(priv->led.gpio,priv->led.active); + } +} + +static irqreturn_t rmtctl_interrupt(int irq, void *dev_id) +{ + unsigned int status, ir_data, ir_code,vendor, repeat; + unsigned char *key; + int i; + + struct rmtctl_priv *priv = (struct rmtctl_priv *)dev_id; + + /* get IR status. */ + status = REG32_VAL(IRSTS); + + /* check 'IR received data' flag. */ + if ((status & 0x1) == 0x0) { + printk("IR IRQ was triggered without data received. (0x%x)\n", + status); + return IRQ_NONE; + } + + /* read IR data. */ + ir_data = REG32_VAL(IRDATA(0)) ; + key = (char *) &ir_data; + + /* clear INT status*/ + REG32_VAL(IRSTS)=0x1 ; + + if (RMTCTL_DEBUG){ + printk("ir_data = 0x%08x, status = 0x%x \n", ir_data, status); + } + + if(priv->codec == CIR_CODEC_PHILIPS_RC6){ + vendor = key[1]; + ir_code = key[0]; + //trailer = key[2] & 0x01; + } + else{//NEC + /* get vendor ID. */ + vendor = (key[0] << 8) | (key[1]); + + /* check if key is valid. Key[3] is XORed t o key[2]. */ + if (key[2] & key[3]) { + printk("Invalid IR key received. (0x%x, 0x%x)\n", key[2], key[3]); + return IRQ_NONE; + } + + /* keycode mapping. */ + ir_code = key[2]; + } + + if ( priv->vendor_index >= 0 ) { + if (vendor == rmtctl_vendors[priv->vendor_index].vendor_code && + rmtctl_vendors[priv->vendor_index].codec == priv->codec) { + priv->table_index = priv->vendor_index; + priv->scan_code = rmtctl_vendors[priv->vendor_index].key_codes[ir_code]; + } + else{ + if(vendor != priv->vendor_code){ + for (i = 0; i < ARRAY_SIZE(rmtctl_vendors); i++) { + if (vendor == rmtctl_vendors[i].vendor_code && + rmtctl_vendors[i].codec == priv->codec) { + priv->table_index = i; + priv->scan_code = rmtctl_vendors[i].key_codes[ir_code]; + break; + } + } + + if(i==ARRAY_SIZE(rmtctl_vendors)) + return IRQ_HANDLED; + } + else{ + priv->scan_code = rmtctl_vendors[priv->table_index].key_codes[ir_code]; + } + } + } + else { + if(vendor != priv->vendor_code){ + for (i = 0; i < ARRAY_SIZE(rmtctl_vendors); i++) { + if (vendor == rmtctl_vendors[i].vendor_code && + rmtctl_vendors[i].codec == priv->codec) { + priv->table_index = i; + priv->scan_code = rmtctl_vendors[i].key_codes[ir_code]; + break; + } + } + + if(i==ARRAY_SIZE(rmtctl_vendors)) + return IRQ_HANDLED; + } + else{ + priv->scan_code = rmtctl_vendors[priv->table_index].key_codes[ir_code]; + } + } + + //switch to a new remote controller shoud reset cursor mode + if (priv->vendor_code != vendor) + priv->rel_dev.on = 0; + + + if ((status & 0x2) || (priv->scan_code == KEY_RESERVED)) { + /* ignore repeated or reserved keys. */ + } + else if (priv->codec == CIR_CODEC_NEC) { + /* check 'IR code repeat' flag. */ + repeat = status & 0x10; + rmtctl_report_event(&priv->scan_code, repeat); + } + else if(priv->codec == CIR_CODEC_PHILIPS_RC6){ + //repeat = !(trailer^key[2]); + //trailer = key[2]; + //printk("RCV philips rc6,repeat=%d\n",repeat); + + rmtctl_report_event_without_hwrepeat(&priv->scan_code); + } + else { + rmtctl_report_event_without_hwrepeat(&priv->scan_code); + } + + if (priv->vendor_code != vendor) { + priv->vendor_code = vendor; + /* save new vendor code to env + *1.remote controller configed index is active, no need to save it's vendor code + *2.current vendor code is saved, no need to save again + */ + if(priv->table_index != priv->vendor_index && vendor != priv->saved_vcode){ + priv->saved_vcode = vendor; + //schedule_delayed_work(&priv->delaywork, msecs_to_jiffies(20)); + } + } + + return IRQ_HANDLED; +} + +static void rmtctl_hw_suspend(unsigned long data) +{ + unsigned int wakeup_code; + int i; + struct rmtctl_priv *priv = (struct rmtctl_priv *)data; + + if (priv->vendor_index >= 0 && priv->vendor_index == priv->table_index) { + i = priv->vendor_index; + } + else { + for (i = 0; i < ARRAY_SIZE(rmtctl_vendors); i++) + if (priv->vendor_code == rmtctl_vendors[i].vendor_code && + priv->codec == rmtctl_vendors[i].codec) + break; + + if (i == ARRAY_SIZE(rmtctl_vendors)) + goto out; + } + + if(priv->codec == CIR_CODEC_PHILIPS_RC6){ + wakeup_code = + ((unsigned char)(rmtctl_vendors[i].vendor_code & 0xff) << 8) | + (unsigned char)(rmtctl_vendors[i].wakeup_code) ; + REG32_VAL(WAKEUP_CMD2(0)) = 0x10000| wakeup_code; + }else{ + wakeup_code = + ((unsigned char)(~rmtctl_vendors[i].wakeup_code) << 24) | + ((unsigned char)(rmtctl_vendors[i].wakeup_code) << 16 ) | + ((unsigned char)(rmtctl_vendors[i].vendor_code & 0xff) << 8) | + ((unsigned char)((rmtctl_vendors[i].vendor_code) >> 8) << 0 ); + + } + REG32_VAL(WAKEUP_CMD1(0)) = wakeup_code; + REG32_VAL(WAKEUP_CMD1(1)) = 0x0; + REG32_VAL(WAKEUP_CMD1(2)) = 0x0; + REG32_VAL(WAKEUP_CMD1(3)) = 0x0; + REG32_VAL(WAKEUP_CMD1(4)) = 0x0; + +out: + REG32_VAL(WAKEUP_CTRL) = 0x101; +} + +static void rmtctl_hw_init(unsigned long data) +{ + unsigned int st; + int i, retries = 0; + struct rmtctl_priv *priv = (struct rmtctl_priv *)data; + + /*setting shared pin*/ + GPIO_CTRL_GP62_WAKEUP_SUS_BYTE_VAL &= 0xFFFD; + PULL_EN_GP62_WAKEUP_SUS_BYTE_VAL |= 0x02; + PULL_CTRL_GP62_WAKEUP_SUS_BYTE_VAL |= 0x02; + + /* turn off CIR SW reset. */ + REG32_VAL(IRSWRST) = 1; + REG32_VAL(IRSWRST) = 0; + + for (i = 0; i < ARRAY_SIZE(rmtctl_params[priv->codec].param); i++) + REG32_VAL(PARAMETER(i)) = rmtctl_params[priv->codec].param[i]; + + if (priv->codec == CIR_CODEC_NEC || priv->codec == CIR_CODEC_TOSHIBA) { + printk("NEC\n"); + REG32_VAL(NEC_REPEAT_TIME_OUT_CTRL) = 0x1; + REG32_VAL(NEC_REPEAT_TIME_OUT_COUNT) = rmtctl_params[priv->codec].repeat_timeout; + REG32_VAL(IRCTL) = 0X100; //NEC repeat key + } + else if(priv->codec == CIR_CODEC_PHILIPS_RC6){ + printk("PHILIPS RC6\n"); + REG32_VAL(IRCTL) =0x40; //PHILIPS RC6 + REG32_VAL(INT_MASK_COUNT) = 40*1000000*1/4; + //REG32_VAL(IRCTL_2) =0xFE;//Enable PHILIPS RC6 mode 0,Mask mode1-7 ? + }else{ + REG32_VAL(IRCTL) = 0; //NEC repeat key + REG32_VAL(INT_MASK_COUNT) = 28*1000000*1/4; //0x47868C0/4;//count for 1 sec 0x47868C0 + } + + REG32_VAL(IRCTL) |= (0x1<<25); + REG32_VAL(INT_MASK_CTRL) = 0x1; + + /* IR_EN */ + REG32_VAL(IRCTL) |= 0x1; + while(retries++ < 100 && !(REG32_VAL(IRCTL)&0x01)){ + REG32_VAL(IRCTL) |= 0x1; + udelay(5); + } + + /* read CIR status to clear IR interrupt. */ + st = REG32_VAL(IRSTS); +} + +static void rmtctl_refresh_vendorcode(struct work_struct *work) +{ + unsigned char data[64]; + struct rmtctl_priv *priv = container_of(work, struct rmtctl_priv, delaywork.work); + sprintf(data, "0x%x", priv->vendor_code); + wmt_setsyspara(WMT_RMTCTL_VENDOR_ENV, data); +} + +static void rel_handler(unsigned long data) +{ + struct rmtctl_rel *rel = (struct rmtctl_rel *)data; + struct rmtctl_priv *priv = container_of(rel, struct rmtctl_priv, rel_dev); + + rmtctl_report_rel(&priv->rel_dev, rel->code); + mod_timer(&rel->timer, jiffies+HZ/15); // report rate 15pps +} + +static void rmtctl_rel_init(struct rmtctl_rel *rel) +{ + struct input_dev *input; + + input = input_allocate_device(); + input->name = "rmtctl-rel"; + + /* register the device as mouse */ + set_bit(EV_REL, input->evbit); + set_bit(REL_X, input->relbit); + set_bit(REL_Y, input->relbit); + + /* register device's buttons and keys */ + set_bit(EV_KEY, input->evbit); + set_bit(BTN_LEFT, input->keybit); + set_bit(BTN_RIGHT, input->keybit); + + input_register_device(input); + rel->input = input; + + init_timer(&rel->timer); + rel->timer.data = (unsigned long)rel; + rel->timer.function = rel_handler; +} + +void led_handler(unsigned long data) +{ + struct rmtctl_led *led = (struct rmtctl_led*)data; + + gpio_direction_output(led->gpio, led->on++%2); + mod_timer(&led->timer, jiffies+HZ/20); + return; +} + +static void rmtctl_led_init(struct rmtctl_led *led) +{ + init_timer(&led->timer); + led->timer.data = (unsigned long)led; + led->timer.function = led_handler; + + gpio_direction_output(led->gpio, led->active); + + return; +} + +static int rmtctl_probe(struct platform_device *dev) +{ + int i,ivendor, ikeycode; + char buf[64]; + int varlen = sizeof(buf); + struct rmtctl_priv *priv; + + priv = kzalloc(sizeof(struct rmtctl_priv), GFP_KERNEL); + if (priv == NULL) + return -ENOMEM; + platform_set_drvdata(dev, priv); + + // get codec type of cir device + if (wmt_getsyspara("wmt.io.rmtctl", buf, &varlen) == 0) { + sscanf(buf, "%d", &priv->codec); + if (priv->codec < CIR_CODEC_NEC || priv->codec >= CIR_CODEC_MAX){ + kfree(priv); + return -EINVAL; + } + } + else { + kfree(priv); + return -EINVAL; + } + + // using assigned cir device? + if (wmt_getsyspara("wmt.io.rmtctl.index", buf, &varlen) == 0) { + sscanf(buf, "%d", &priv->vendor_index); + if (priv->vendor_index >= ARRAY_SIZE(rmtctl_vendors) || + rmtctl_vendors[priv->vendor_index].codec != priv->codec) + priv->vendor_index = -1; + + priv->table_index = priv->vendor_index; + } + else + priv->vendor_index = -1; + + // get last vendor code saved in uboot environment +#if 0 + if (wmt_getsyspara(WMT_RMTCTL_VENDOR_ENV, buf, &varlen) == 0){ + sscanf(buf, "0x%x", &priv->vendor_code); + priv->saved_vcode = priv->vendor_code; + for (i = 0; i < ARRAY_SIZE(rmtctl_vendors); i++) { + if (priv->vendor_code == rmtctl_vendors[i].vendor_code && + rmtctl_vendors[i].codec == priv->codec) { + priv->table_index = i; + break; + } + } + }else +#endif + priv->vendor_code = 0xffff; + + if (wmt_getsyspara("wmt.io.rmtctl.led", buf, &varlen) == 0) { + sscanf(buf, "%d:%d", &priv->led.gpio, &priv->led.active); + priv->led.enable = 1; + } + + /* register an input device. */ + if ((priv->idev = input_allocate_device()) == NULL) + return -ENOMEM; + + set_bit(EV_KEY, priv->idev->evbit); + + for (ivendor = 0; ivendor < ARRAY_SIZE(rmtctl_vendors); ivendor++) { + if (priv->codec == rmtctl_vendors[ivendor].codec) { + for (ikeycode = 0; ikeycode < ARRAY_SIZE(rmtctl_vendors[ivendor].key_codes); ikeycode++) { + if (rmtctl_vendors[ivendor].key_codes[ikeycode]) { + set_bit(rmtctl_vendors[ivendor].key_codes[ikeycode], priv->idev->keybit); + } + } + } + } + + priv->idev->name = "rmtctl"; + priv->idev->phys = "rmtctl"; + input_register_device(priv->idev); + rmtctl_rel_init(&priv->rel_dev); + if(priv->led.enable){ + gpio_request(priv->led.gpio,"rmtctl-led"); + rmtctl_led_init(&priv->led); + } + INIT_DELAYED_WORK(&priv->delaywork, rmtctl_refresh_vendorcode); + + init_timer(&priv->timer); + priv->timer.data = (unsigned long)priv->idev; + priv->timer.function = rmtctl_timer_handler; + + /* Register an ISR */ + request_irq(IRQ_CIR, rmtctl_interrupt, IRQF_SHARED, "rmtctl", priv); + + /* Initial H/W */ + rmtctl_hw_init((unsigned long)priv); + + if (RMTCTL_DEBUG) + printk("WonderMedia rmtctl driver v0.98 initialized: ok\n"); + + return 0; +} + +static int rmtctl_remove(struct platform_device *dev) +{ + struct rmtctl_priv *priv = platform_get_drvdata(dev); + + if (RMTCTL_DEBUG) + printk("rmtctl_remove\n"); + + del_timer_sync(&priv->timer); + cancel_delayed_work_sync(&priv->delaywork); + del_timer_sync(&priv->rel_dev.timer); + input_unregister_device(priv->rel_dev.input); + input_free_device(priv->rel_dev.input); + if(priv->led.enable){ + del_timer_sync(&priv->led.timer); + gpio_direction_output(priv->led.gpio, priv->led.active); + gpio_free(priv->led.gpio); + } + + free_irq(IRQ_CIR, priv); + input_unregister_device(priv->idev); + input_free_device(priv->idev); + + kfree(priv); + + return 0; +} + +#ifdef CONFIG_PM +static int rmtctl_suspend(struct platform_device *dev, pm_message_t state) +{ + struct rmtctl_priv *priv = platform_get_drvdata(dev); + + del_timer_sync(&priv->timer); + cancel_delayed_work_sync(&priv->delaywork); + del_timer_sync(&priv->rel_dev.timer); + if(priv->led.enable){ + priv->led.on = 0; + del_timer(&priv->led.timer); + gpio_direction_output(priv->led.gpio, priv->led.active); + } + + /* Nothing to suspend? */ + rmtctl_hw_init((unsigned long)priv); + rmtctl_hw_suspend((unsigned long)priv); + + disable_irq(IRQ_CIR); + + /* Enable rmt wakeup */ + PMWE_VAL |= (1 << WKS_CIR); + + return 0; +} + +static int rmtctl_resume(struct platform_device *dev) +{ + volatile unsigned int regval; + int i =0 ; + struct rmtctl_priv *priv = platform_get_drvdata(dev); + + /* Initial H/W */ + REG32_VAL(WAKEUP_CTRL) &=~ BIT0; + + for (i=0;i<10;i++) + { + regval = REG32_VAL(WAKEUP_STS) ; + + if (regval & BIT0){ + REG32_VAL(WAKEUP_STS) |= BIT4; + + }else{ + break; + } + msleep_interruptible(5); + } + + regval = REG32_VAL(WAKEUP_STS) ; + if (regval & BIT0) + printk("CIR resume NG WAKEUP_STS 0x%08x \n",regval); + + rmtctl_hw_init((unsigned long)priv); + if(priv->led.enable) + rmtctl_led_init(&priv->led); + enable_irq(IRQ_CIR); + return 0; +} +#else +#define rmtctl_suspend NULL +#define rmtctl_resume NULL +#endif + +static struct platform_driver rmtctl_driver = { + .driver.name = "wmt-rmtctl", + //.bus = &platform_bus_type, + //.probe = rmtctl_probe, + .remove = rmtctl_remove, + .suspend = rmtctl_suspend, + .resume = rmtctl_resume +}; + +static void rmtctl_release(struct device *dev) +{ + /* Nothing to release? */ +} + +static u64 rmtctl_dmamask = 0xffffffff; + +static struct platform_device rmtctl_device = { + .name = "wmt-rmtctl", + .id = 0, + .dev = { + .release = rmtctl_release, + .dma_mask = &rmtctl_dmamask, + }, + .num_resources = 0, + .resource = NULL, +}; + +static int __init rmtctl_init(void) +{ + int ret; + + if (platform_device_register(&rmtctl_device)) + return -1; + ret = platform_driver_probe(&rmtctl_driver, rmtctl_probe); + + return ret; +} + +static void __exit rmtctl_exit(void) +{ + platform_driver_unregister(&rmtctl_driver); + platform_device_unregister(&rmtctl_device); +} + +module_init(rmtctl_init); +module_exit(rmtctl_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("WonderMedia Technologies, Inc."); +MODULE_DESCRIPTION("WMT [Remoter] driver"); diff --git a/ANDROID_3.4.5/drivers/input/rmtctl/wmt-rmtctl.h b/ANDROID_3.4.5/drivers/input/rmtctl/wmt-rmtctl.h new file mode 100755 index 00000000..7094f6dd --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/rmtctl/wmt-rmtctl.h @@ -0,0 +1,50 @@ +/*++ + * linux/drivers/input/rmtctl/wmt-rmtctl.h + * WonderMedia input remote control driver + * + * Copyright c 2010 WonderMedia Technologies, Inc. + * + * 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 . + * + * WonderMedia Technologies, Inc. + * 4F, 533, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C +--*/ + + +#define REG_BASE_IR CIR_BASE_ADDR + +#define IRSWRST REG_BASE_IR+0x00 // [0x00] IR Software Reset register +#define IRCTL REG_BASE_IR+0x04 // [0x04] IR Control register +#define IRCTL_2 REG_BASE_IR+0x08 // [0x08] IR Control register +#define IRSTS REG_BASE_IR+0x0c // [0x0c] IR Status register +#define IRDATA(i) REG_BASE_IR+0x10+i*0x4 // [0x10-0x20] IR Received Data register +#define PARAMETER(i) REG_BASE_IR+0x24+i*0x4 // [0x24-0x3c]IR Parameter Register for Remote Controller Vendor "NEC" +#define NEC_REPEAT_TIME_OUT_CTRL REG_BASE_IR+0x40 // [0X40] +#define NEC_REPEAT_TIME_OUT_COUNT REG_BASE_IR+0x44 // [0X44] +#define NEC_REPEAT_TIME_OUT_STS REG_BASE_IR+0x48 // [0X48] +#define JVC_CONTI_CTRL REG_BASE_IR+0x50 // [0X50] +#define JVC_CONTI_COUNT REG_BASE_IR+0x54 // [0X54] +#define JVC_CONTI_STS REG_BASE_IR+0x58 // [0X58] +#define INT_MASK_CTRL REG_BASE_IR+0x60 // [0X60] +#define INT_MASK_COUNT REG_BASE_IR+0x64 // [0X64] +#define INT_MASK_STS REG_BASE_IR+0x68 // [0X68] +#define WAKEUP_CMD1(i) REG_BASE_IR+0x70+i*0x4 // [0X70-0x80] +#define WAKEUP_CMD2(i) REG_BASE_IR+0x84+i*0x4 // [0X84-0x94] +#define WAKEUP_CTRL REG_BASE_IR+0x98 // [0X98] +#define WAKEUP_STS REG_BASE_IR+0x9c // [0X9C] +#define IRFSM REG_BASE_IR+0xa0 // [0Xa0] +#define IRHSPMC REG_BASE_IR+0xa4 // [0xa4] IR Host-Synchronous-Pulse Measure Counter register +#define IRHSPTC REG_BASE_IR+0xa8 // [0xa8] IR Host-Synchronous-Pulse Tolerance Counter register + + diff --git a/ANDROID_3.4.5/drivers/input/sensor/Kconfig b/ANDROID_3.4.5/drivers/input/sensor/Kconfig new file mode 100755 index 00000000..cff1aa40 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/Kconfig @@ -0,0 +1,224 @@ +# +# WMT Sensor configuration +# +menuconfig INPUT_SENSOR + bool "WMT Sensor" + default y + help + Say Y here, and a list of supported sensor will be displayed. + This option doesn't affect the kernel. + + If unsure, say Y. + +if INPUT_SENSOR + +config WMT_SENSOR_KXTE9 + tristate "KXTE9 G-Sensor Support" + depends on ARCH_WMT + default n + help + Say Y here if you have an WMT based board with g-sensor + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called s_wmt_gsensor_mc3230. +config WMT_SENSOR_KIONIX + tristate "KIONIX G-Sensor Support" + depends on ARCH_WMT + default n + help + Say Y here if you have an WMT based board with g-sensor + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called s_wmt_gsensor_kionix. +config WMT_SENSOR_MC3XXX + tristate "Mcube G-Sensor Support" + depends on ARCH_WMT + default m + help + Say Y here if you have an WMT based board with g-sensor + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called s_wmt_gsensor_mc3xxx. + +config WMT_SENSOR_DMARD08 + tristate "DMARD08 G-Sensor Support" + depends on ARCH_WMT + default y + help + Say Y here if you have an WMT based board with g-sensor + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called sensor_dmard08. +config WMT_SENSOR_DMARD06 + tristate "DMARD06 G-Sensor Support" + depends on ARCH_WMT + default y + help + Say Y here if you have an WMT based board with g-sensor + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called sensor_dmard06. +config WMT_SENSOR_DMARD10 + tristate "DMARD10 G-Sensor Support" + depends on ARCH_WMT + default y + help + Say Y here if you have an WMT based board with g-sensor + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called sensor_dmard10. +config WMT_SENSOR_DMARD09 + tristate "DMARD09 G-Sensor Support" + depends on ARCH_WMT + default y + help + Say Y here if you have an WMT based board with g-sensor + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called sensor_dmard09. +config WMT_SENSOR_MXC622X + tristate "MXC622X G-Sensor Support" + depends on ARCH_WMT + default y + help + Say Y here if you have an WMT based board with g-sensor + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called sensor_mxc622x. +config WMT_SENSOR_MMA7660 + tristate "MMA7660 G-Sensor Support" + depends on ARCH_WMT + default y + help + Say Y here if you have an WMT based board with g-sensor + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called sensor_mma7660. +config WMT_SENSOR_MMC328x + tristate "MMC328x M-Sensor Support" + depends on ARCH_WMT + default y + help + Say Y here if you have an WMT based board with m-sensor + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called sensor_mmc328x. +config WMT_SENSOR_ISL29023 + tristate "ISL29023 Light sensor Support" + depends on ARCH_WMT + default y + help + Say Y here if you have an WMT based board with l-sensor + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called sensor_isl29023. +config WMT_SENSOR_CM3232 + tristate "CM3232 Light sensor Support" + depends on ARCH_WMT + default y + help + Say Y here if you have an WMT based board with l-sensor + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called sensor_cm3232. +config WMT_SENSOR_STK3310 + tristate "STK3310 Light sensor Support" + depends on ARCH_WMT + default y + help + Say Y here if you have an WMT based board with l-sensor + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called sensor_stk3310. +config WMT_GYRO_L3G4200D + tristate "L3G4200D Gyroscope Support" + depends on ARCH_WMT + default m + help + Say Y here if you have an WMT based board with ST L3g4200d + gyroscope attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called s_wmt_gyro_l3g4200d. + +config WMT_SENSOR_US5182 + tristate "US5182 Light&Promixity sensor Support" + depends on ARCH_WMT + default m + help + Say Y here if you have an WMT based board with l&p-sensor + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called s_wmt_lsensor_us5182. + +config WMT_SENSOR_MMA8452Q + tristate "MMA8452Q G-Sensor Support" + depends on ARCH_WMT + default m + help + Say Y here if you have an WMT based board with g-sensor + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called s_wmt_gsensor_mma8542. + +config WMT_SENSOR_STK8312 + tristate "STK8312 G-Sensor Support" + depends on ARCH_WMT + default m + help + Say Y here if you have an WMT based board with g-sensor + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called s_wmt_gsensor_STK8312. + +endif diff --git a/ANDROID_3.4.5/drivers/input/sensor/Makefile b/ANDROID_3.4.5/drivers/input/sensor/Makefile new file mode 100755 index 00000000..cc06e871 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/Makefile @@ -0,0 +1,26 @@ +# +# Makefile for the Sensor driver +# + +# Each configuration option enables a list of files. + +#obj-$(CONFIG_INPUT_SENSOR) += gsensor.o +obj-y += sensor.o +obj-$(CONFIG_WMT_SENSOR_KXTE9) += kxte9_gsensor/ +obj-$(CONFIG_WMT_SENSOR_MC3XXX) += mc3xxx_gsensor/ +obj-$(CONFIG_WMT_SENSOR_DMARD08) += dmard08_gsensor/ +obj-$(CONFIG_WMT_SENSOR_DMARD06) += dmard06_gsensor/ +obj-$(CONFIG_WMT_SENSOR_MMA7660) += mma7660_gsensor/ +obj-$(CONFIG_WMT_SENSOR_ISL29023) += isl29023_lsensor/ +obj-$(CONFIG_WMT_SENSOR_CM3232) += cm3232/ +obj-$(CONFIG_WMT_SENSOR_CM3232) += stk3310/ +obj-$(CONFIG_WMT_SENSOR_DMARD10) += dmard10_gsensor/ +obj-$(CONFIG_WMT_SENSOR_DMARD09) += dmard09_gsensor/ +obj-$(CONFIG_WMT_SENSOR_MXC622X) += mxc622x_gsensor/ +obj-$(CONFIG_WMT_SENSOR_MMC328x) += mmc328x_msensor/ +#obj-$(CONFIG_WMT_SENSOR_CM3232) += cm3232/cm3232.o +obj-$(CONFIG_WMT_GYRO_L3G4200D) += l3g4200d_gyro/ +obj-$(CONFIG_WMT_SENSOR_US5182) += us5182_lpsensor/ +obj-$(CONFIG_WMT_SENSOR_MMA8452Q) += mma8452q_gsensor/ +obj-$(CONFIG_WMT_SENSOR_STK8312) += stk8312_gsensor/ +obj-$(CONFIG_WMT_SENSOR_KIONIX) += kionix_gsensor/ \ No newline at end of file diff --git a/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/Kconfig b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/Kconfig new file mode 100755 index 00000000..9bf96e92 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/Kconfig @@ -0,0 +1,50 @@ +# +# WMT Sensor configuration +# +menuconfig INPUT_SENSOR + bool "WMT Sensor" + help + Say Y here, and a list of supported sensor will be displayed. + This option doesn't affect the kernel. + + If unsure, say Y. + +if INPUT_SENSOR + + +config WMT_SENSOR_KXTI9 + tristate "KXTI9 G-Sensor Support" + depends on ARCH_WMT + help + Say Y here if you have an WMT based board with g-sensor + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called sensor_kxti9. + +config WMT_SENSOR_DMT08 + tristate "DMT08 G-Sensor Support" + depends on ARCH_WMT + help + Say Y here if you have an WMT based board with g-sensor + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called sensor_dmt08. + +config WMT_SENSOR_DMT10 + tristate "DMT10 G-Sensor Support" + depends on ARCH_WMT + help + Say Y here if you have an WMT based board with g-sensor + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called sensor_dmt10. +endif diff --git a/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/Makefile b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/Makefile new file mode 100755 index 00000000..ee1a0ac5 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/Makefile @@ -0,0 +1,13 @@ +# +# Makefile for the Sensor driver +# + +# Each configuration option enables a list of files. + +obj-$(CONFIG_INPUT_SENSOR) += gsensor.o + +obj-$(CONFIG_WMT_SENSOR_KXTI9) += kxti9_gsensor/ + +obj-$(CONFIG_WMT_SENSOR_DMT08) += dmt08_gsensor/ + +obj-$(CONFIG_WMT_SENSOR_DMT10) += dmt10_gsensor/ diff --git a/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/dmt08_gsensor/Makefile b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/dmt08_gsensor/Makefile new file mode 100755 index 00000000..6edce54a --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/dmt08_gsensor/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for the DMARD06 Sensor driver +# + +sensor_dmt08-objs := dmt08.o +obj-$(CONFIG_WMT_SENSOR_DMT08) += sensor_dmt08.o diff --git a/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/dmt08_gsensor/dmt08.c b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/dmt08_gsensor/dmt08.c new file mode 100755 index 00000000..2ed5f502 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/dmt08_gsensor/dmt08.c @@ -0,0 +1,870 @@ +/* + * @file drivers/misc/dmt0308.c + * @brief DMT g-sensor Linux device driver + * @author Domintech Technology Co., Ltd (http://www.domintech.com.tw) + * @version 1.31 + * @date 2012/3/27 + * + * @section LICENSE + * + * Copyright 2011 Domintech Technology Co., Ltd + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "dmt08.h" +#include "../gsensor.h" + +wait_queue_head_t open_wq; +atomic_t active; +static unsigned int interval; +struct mutex DMT_mutex; +struct delayed_work work; +struct work_struct irq_work; +atomic_t delay; + +static struct gsensor_conf gs_conf; + +void gsensor_write_offset_to_file(void); +void gsensor_read_offset_from_file(void); +char OffsetFileName[] = "/data/misc/dmt/offset.txt"; +static int Device_First_Time_Opened_flag=1; +//************************************************* +static char const *const ACCELEMETER_CLASS_NAME = "accelemeter"; +#define CHIP_ENABLE 137 +#if (defined(CONFIG_SENSORS_DMARD03) || defined(CONFIG_SENSORS_DMARD03_MODULE)) +static char const *const GSENSOR_DEVICE_NAME = "dmard03"; +#elif (defined(CONFIG_SENSORS_DMARD08) || defined(CONFIG_SENSORS_DMARD08_MODULE) || defined(CONFIG_WMT_SENSOR_DMT08)) +static char const *const GSENSOR_DEVICE_NAME = "dmard08"; +#endif + +static int device_init(void); +static void device_exit(void); + +static int device_open(struct inode*, struct file*); +static ssize_t device_write(struct file*, const char*, size_t, loff_t*); +static ssize_t device_read(struct file*, char*, size_t, loff_t*); +static long device_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); +static int device_close(struct inode*, struct file*); + +//static int device_i2c_suspend(struct i2c_client *client, pm_message_t mesg); +//static int device_i2c_resume(struct i2c_client *client); +static int __devinit device_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id); +static int __devexit device_i2c_remove(struct i2c_client *client); +static inline void device_i2c_correct_accel_sign(s16 *val); +void device_i2c_read_xyz(struct i2c_client *client, s16 *xyz); +void device_i2c_merge_register_values(struct i2c_client *client, s16 *val, u8 msb, u8 lsb); + +struct input_dev *input; + +static int DMT_GetOpenStatus(void) +{ +#if DMT_DEBUG_DATA + IN_FUNC_MSG; + printk("%s:start active=%d\n",__func__,active.counter); +#endif + wait_event_interruptible(open_wq, (atomic_read(&active) != 0)); + return 0; +} + +static int DMT_GetCloseStatus(void) +{ +#if DMT_DEBUG_DATA + IN_FUNC_MSG; + printk("%s:start active=%d\n",__func__,active.counter); +#endif + wait_event_interruptible(open_wq, (atomic_read(&active) <= 0)); + return 0; +} + +static void DMT_sysfs_update_active_status(int en) +{ + unsigned long dmt_delay; + if(en) + { + dmt_delay = msecs_to_jiffies(atomic_read(&delay)); + if(dmt_delay < 1) + dmt_delay = 1; + //printk("schedule_delayed_work start with delay time=%lu\n",dmt_delay); + schedule_delayed_work(&work,dmt_delay); + } + else + cancel_delayed_work_sync(&work); +} + +static ssize_t DMT_enable_acc_show( struct device *dev, struct device_attribute *attr, char *buf) +{ + buf="show"; + return 1; +} + +static ssize_t DMT_enable_acc_store( struct device *dev, struct device_attribute *attr, char const *buf, size_t count) +{ + int en; +#if DMT_DEBUG_DATA + printk("%s:buf=%x %x\n",__func__,buf[0],buf[1]); +#endif + if(buf[0]!= 0x30 && buf[0]!= 0x31) + { + printk("%s:illegle data !!\n",__func__); + return 0; + } + en= (buf[0]-0x30 > 0) ? 1:0; + DMT_sysfs_update_active_status(en); + return 1; +} + +static ssize_t DMT_delay_acc_show( struct device *dev, struct device_attribute *attr, char *buf){ + return 1; +} + +static ssize_t DMT_delay_acc_store( struct device *dev, struct device_attribute *attr,char const *buf, size_t count) +{ + int error; + unsigned long data; + error = strict_strtoul(buf, 10, &data); + if(error) { + pr_err("%s strict_strtoul error\n", __FUNCTION__); + return -1; + } + mutex_lock(&DMT_mutex); + interval=(unsigned int)data; + mutex_unlock(&DMT_mutex); + atomic_set(&delay, (unsigned int) data); +#if DMT_DEBUG_DATA + printk("Driver attribute set delay =%lu\n",data); +#endif + return 1; +} + +static struct device_attribute DMT_attributes[] = { + __ATTR(enable_acc, 0755, DMT_enable_acc_show, DMT_enable_acc_store), + __ATTR(delay_acc, 0755, DMT_delay_acc_show, DMT_delay_acc_store), + __ATTR_NULL, +}; + +static int create_device_attributes(struct device *dev, struct device_attribute *attrs) +{ + int i; + int err = 0; +#if DMT_DEBUG_DATA + IN_FUNC_MSG; +#endif + for (i = 0 ; NULL != attrs[i].attr.name ; ++i) { + err = device_create_file(dev, &attrs[i]); + if (0 != err) + break; + } + + if (0 != err) { + for (; i >= 0 ; --i) + device_remove_file(dev, &attrs[i]); + } + return err; +} + +int input_init(void) +{ + int err=0; + input=input_allocate_device(); + if (!input) + return -ENOMEM; + else + printk("input device allocate Success !!\n"); + /* Setup input device */ + set_bit(EV_ABS, input->evbit); + /* Accelerometer [-78.5, 78.5]m/s2 in Q16*/ + input_set_abs_params(input, ABS_X, -1024, 1024, 0, 0); + input_set_abs_params(input, ABS_Y, -1024, 1024, 0, 0); + input_set_abs_params(input, ABS_Z, -1024, 1024, 0, 0); + + /* Set name */ + input->name = "g-sensor"; + + /* Register */ + err = input_register_device(input); + if (err) { + input_free_device(input); + return err; + } + atomic_set(&active, 0); +#if DMT_DEBUG_DATA + printk("in driver ,active=%d\n",active.counter); +#endif + init_waitqueue_head(&open_wq); + + return err; +} + +typedef union { + struct { + s16 x; + s16 y; + s16 z; + } u; + s16 v[SENSOR_DATA_SIZE]; +} raw_data; +static raw_data offset; + +struct dev_data { + dev_t devno; + struct cdev cdev; + struct class *class; + struct i2c_client *client; +}; +static struct dev_data dev; + +s16 sensorlayout[3][3] = { +#if defined(CONFIG_GSEN_LAYOUT_PAT_1) + { 1, 0, 0}, { 0, 1, 0}, { 0, 0, 1}, +#elif defined(CONFIG_GSEN_LAYOUT_PAT_2) + { 0, 1, 0}, {-1, 0, 0}, { 0, 0, 1}, +#elif defined(CONFIG_GSEN_LAYOUT_PAT_3) + {-1, 0, 0}, { 0,-1, 0}, { 0, 0, 1}, +#elif defined(CONFIG_GSEN_LAYOUT_PAT_4) + { 0,-1, 0}, { 1, 0, 0}, { 0, 0, 1}, +#elif defined(CONFIG_GSEN_LAYOUT_PAT_5) + {-1, 0, 0}, { 0, 1, 0}, { 0, 0,-1}, +#elif defined(CONFIG_GSEN_LAYOUT_PAT_6) + { 0,-1, 0}, {-1, 0, 0}, { 0, 0,-1}, +#elif defined(CONFIG_GSEN_LAYOUT_PAT_7) + { 1, 0, 0}, { 0,-1, 0}, { 0, 0,-1}, +#elif defined(CONFIG_GSEN_LAYOUT_PAT_8) + { 0, 1, 0}, { 1, 0, 0}, { 0, 0,-1}, +#endif +}; + +void gsensor_read_accel_avg(int num_avg, raw_data *avg_p ) +{ + long xyz_acc[SENSOR_DATA_SIZE]; + s16 xyz[SENSOR_DATA_SIZE]; + int i, j; + + //initialize the accumulation buffer + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + xyz_acc[i] = 0; + + for(i = 0; i < num_avg; i++) + { + device_i2c_read_xyz(dev.client, (s16 *)&xyz); + for(j = 0; j < SENSOR_DATA_SIZE; j++) + xyz_acc[j] += xyz[j]; + } + + // calculate averages + for(i = 0; i < SENSOR_DATA_SIZE; i++) + avg_p->v[i] = (s16) (xyz_acc[i] / num_avg); +} +/* calc delta offset */ +int gsensor_calculate_offset(int gAxis,raw_data avg) +{ + switch(gAxis) + { + case CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Z_NEGATIVE: + offset.u.x = avg.u.x ; + offset.u.y = avg.u.y ; + offset.u.z = avg.u.z + DEFAULT_SENSITIVITY; + break; + case CONFIG_GSEN_CALIBRATION_GRAVITY_ON_X_POSITIVE: + offset.u.x = avg.u.x + DEFAULT_SENSITIVITY; + offset.u.y = avg.u.y ; + offset.u.z = avg.u.z ; + break; + case CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Z_POSITIVE: + offset.u.x = avg.u.x ; + offset.u.y = avg.u.y ; + offset.u.z = avg.u.z - DEFAULT_SENSITIVITY; + break; + case CONFIG_GSEN_CALIBRATION_GRAVITY_ON_X_NEGATIVE: + offset.u.x = avg.u.x - DEFAULT_SENSITIVITY; + offset.u.y = avg.u.y ; + offset.u.z = avg.u.z ; + break; + case CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Y_NEGATIVE: + offset.u.x = avg.u.x ; + offset.u.y = avg.u.y + DEFAULT_SENSITIVITY; + offset.u.z = avg.u.z ; + break; + case CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Y_POSITIVE: + offset.u.x = avg.u.x ; + offset.u.y = avg.u.y - DEFAULT_SENSITIVITY; + offset.u.z = avg.u.z ; + break; + default: + return -ENOTTY; + } + return 0; +} + +void gsensor_calibrate(int side){ + raw_data avg; + int avg_num = 16; +#if DMT_DEBUG_DATA + IN_FUNC_MSG; +#endif + // get acceleration average reading + gsensor_read_accel_avg(avg_num, &avg); + // calculate and set the offset + gsensor_calculate_offset(side, avg); +} + +void ce_on(void){ + //omap_mux_set_gpio(OMAP_PIN_INPUT_PULLUP, CHIP_ENABLE); +} + +void ce_off(void){ + //omap_mux_set_gpio(OMAP_PIN_INPUT_PULLDOWN, CHIP_ENABLE); +} + +void gsensor_reset(void){ + ce_off(); + msleep(300); + ce_on(); +} + +void gsensor_set_offset(int val[3]) +{ + int i; +#if DMT_DEBUG_DATA + IN_FUNC_MSG; +#endif + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + offset.v[i] = (s16) val[i]; +} + +static int device_i2c_suspend(struct i2c_client *client, pm_message_t mesg) +{ + return 0; +} + +static int device_i2c_resume(struct i2c_client *client) +{ + return 0; +} + +static void device_i2c_shutdown(struct i2c_client *client) +{ + flush_delayed_work_sync(&work); + cancel_delayed_work_sync(&work); +} + +struct file_operations dmt_g_sensor_fops = { + .owner = THIS_MODULE, + .read = device_read, + .write = device_write, + .unlocked_ioctl = device_ioctl, + .open = device_open, + .release = device_close, +}; + +static const struct i2c_device_id device_i2c_ids[] = { + {DEVICE_I2C_NAME, 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, device_i2c_ids); + +static struct i2c_driver device_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = DEVICE_I2C_NAME, + }, + .class = I2C_CLASS_HWMON, + .probe = device_i2c_probe, + .remove = __devexit_p(device_i2c_remove), + .suspend = device_i2c_suspend, + .resume = device_i2c_resume, + .shutdown = device_i2c_shutdown, + .id_table = device_i2c_ids, +}; + +static int device_open(struct inode *inode, struct file *filp){ +#if DMT_DEBUG_DATA + IN_FUNC_MSG; +#endif + //Device_First_Time_Opened_flag + if(Device_First_Time_Opened_flag) + { + Device_First_Time_Opened_flag=0; + //gsensor_read_offset_from_file(); + } + return 0; +} + +static ssize_t device_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos) +{ + return 0; +} + +static ssize_t device_read(struct file *filp, char *buf, size_t count, loff_t *f_pos) +{ + s16 xyz[SENSOR_DATA_SIZE]; + int i; + + device_i2c_read_xyz(dev.client, (s16 *)&xyz); + //offset compensation + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + xyz[i] -= offset.v[i]; + + if(copy_to_user(buf, &xyz, count)) + return -EFAULT; +#if DMT_DEBUG_DATA + IN_FUNC_MSG; + PRINT_X_Y_Z(xyz[0], xyz[1], xyz[2]); +#endif + + return count; +} + +static long device_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + int err = 0, ret = 0, i; + int intBuf[SENSOR_DATA_SIZE]; + s16 xyz[SENSOR_DATA_SIZE]; + //check type and number + if (_IOC_TYPE(cmd) != IOCTL_MAGIC) return -ENOTTY; + if (_IOC_NR(cmd) > SENSOR_MAXNR) return -ENOTTY; + + //check user space pointer is valid + if (_IOC_DIR(cmd) & _IOC_READ) + err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd)); + else if (_IOC_DIR(cmd) & _IOC_WRITE) + err = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd)); + if (err) return -EFAULT; + + switch(cmd) + { + case SENSOR_RESET: + //gsensor_reset(); + printk("RUN RESET"); + return ret; + + case SENSOR_CALIBRATION: + // get orientation info + if(copy_from_user(&intBuf, (int*)arg, sizeof(int))) return -EFAULT; + gsensor_calibrate(intBuf[0]); + // write in to file + gsensor_write_offset_to_file(); + + // return the offset + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + intBuf[i] = offset.v[i]; + + ret = copy_to_user((int *)arg, &intBuf, sizeof(intBuf)); + return ret; + + case SENSOR_GET_OFFSET: + // get offset from file + gsensor_read_offset_from_file(); + + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + intBuf[i] = offset.v[i]; + + ret = copy_to_user((int *)arg, &intBuf, sizeof(intBuf)); + return ret; + + case SENSOR_SET_OFFSET: + ret = copy_from_user(&intBuf, (int *)arg, sizeof(intBuf)); + gsensor_set_offset(intBuf); + // write in to file + gsensor_write_offset_to_file(); + return ret; + + case SENSOR_READ_ACCEL_XYZ: + device_i2c_read_xyz(dev.client, (s16 *)&xyz); + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + intBuf[i] = xyz[i] - offset.v[i]; + + ret = copy_to_user((int*)arg, &intBuf, sizeof(intBuf)); + return ret; + case SENSOR_SETYPR: + if(copy_from_user(&intBuf, (int*)arg, sizeof(intBuf))) + { + printk("%s:copy_from_user(&intBuf, (int*)arg, sizeof(intBuf)) ERROR, -EFAULT\n",__func__); + return -EFAULT; + } + input_report_abs(input, ABS_X, intBuf[0]); + input_report_abs(input, ABS_Y, intBuf[1]); + input_report_abs(input, ABS_Z, intBuf[2]); + input_sync(input); + //printk("%s:SENSOR_SETYPR OK! x=%d,y=%d,z=%d\n",__func__,intBuf[0],intBuf[1],intBuf[2]); + + return 1; + case SENSOR_GET_OPEN_STATUS: + //printk("%s:Going into DMT_GetOpenStatus()\n",__func__); + DMT_GetOpenStatus(); + //printk("%s:DMT_GetOpenStatus() finished\n",__func__); + return 1; + break; + case SENSOR_GET_CLOSE_STATUS: + //printk("%s:Going into DMT_GetCloseStatus()\n",__func__); + DMT_GetCloseStatus(); + //printk("%s:DMT_GetCloseStatus() finished\n",__func__); + return 1; + break; + case SENSOR_GET_DELAY: + + ret = copy_to_user((int*)arg, &interval, sizeof(interval)); + return 1; + break; + default: /* redundant, as cmd was checked against MAXNR */ + return -ENOTTY; + } + + return 0; +} + +static int device_close(struct inode *inode, struct file *filp) +{ + printk("Close device\n"); + return 0; +} + +static int device_i2c_xyz_read_reg(struct i2c_client *client,u8 *buffer, int length) +{ + struct i2c_msg msg[] = + { + {.addr = client->addr, .flags = 0, .len = 1, .buf = buffer,}, + {.addr = client->addr, .flags = I2C_M_RD, .len = length, .buf = buffer,}, + }; +#if DMT_DEBUG_DATA + IN_FUNC_MSG; +#endif + return i2c_transfer(client->adapter, msg, 2); +} + +void device_i2c_read_xyz(struct i2c_client *client, s16 *xyz_p) +{ + u8 buffer[6]; + s16 xyzTmp[SENSOR_DATA_SIZE]; + int i, j; + + //get xyz high/low bytes, 0x02~0x07 + buffer[0] = 2; + device_i2c_xyz_read_reg(client, buffer, 6); + + //merge to 11-bits value + for(i = 0; i < SENSOR_DATA_SIZE; ++i){ + xyz_p[i] = 0; + device_i2c_merge_register_values(client, (xyzTmp + i), buffer[2*i], buffer[2*i + 1]); + //transfer to the default layout + for(j = 0; j < 3; j++) + xyz_p[i] += sensorlayout[i][j] * xyzTmp[j]; + } +} + +void device_i2c_merge_register_values(struct i2c_client *client, s16 *val, u8 msb, u8 lsb) +{ + *val = (((u16)msb) << 3) | (u16)lsb; + device_i2c_correct_accel_sign(val); +} + +static inline void device_i2c_correct_accel_sign(s16 *val) +{ + *val<<= (sizeof(s16) * BITS_PER_BYTE - 11); + *val>>= (sizeof(s16) * BITS_PER_BYTE - 11); +} + +static void DMT_work_func(struct work_struct *fakework) +{ + int i; + static int firsttime=0; + s16 xyz[SENSOR_DATA_SIZE]; + unsigned long t=atomic_read(&delay); + unsigned long dmt_delay = msecs_to_jiffies(t); + if(!firsttime) + { + //gsensor_read_offset_from_file(); + firsttime=1; + } + + //dmt_delay/=1000; + +#if DMT_DEBUG_DATA + IN_FUNC_MSG; + printk("t=%lu ,dmt_delay=%lu\n",t,dmt_delay); +#endif + + device_i2c_read_xyz(dev.client, (s16 *)&xyz); + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + xyz[i] -= offset.v[i]; + +#if DMT_DEBUG_DATA + printk("x: %d, y: %d, z: %d\n", xyz[0], xyz[1], xyz[2]); +#endif + input_report_abs(input, ABS_X, xyz[gs_conf.xyz_axis[ABS_X][0]]*gs_conf.xyz_axis[ABS_X][1]); + input_report_abs(input, ABS_Y, xyz[gs_conf.xyz_axis[ABS_Y][0]]*gs_conf.xyz_axis[ABS_Y][1]); + input_report_abs(input, ABS_Z, xyz[gs_conf.xyz_axis[ABS_Z][0]]*gs_conf.xyz_axis[ABS_Z][1]); + input_sync(input); + + if(dmt_delay<1) + dmt_delay=1; + + schedule_delayed_work(&work, dmt_delay); +} + + +static int __devinit device_i2c_probe(struct i2c_client *client,const struct i2c_device_id *id) +{ + u8 buffer[4]; + int i; + + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + offset.v[i] = 0; + + if(!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + { + printk("%s, functionality check failed\n", __func__); + return -1; + } + + gsensor_reset(); + + buffer[0] = CONTROL_REGISTERS; + device_i2c_xyz_read_reg(client, buffer, 4); + if( buffer[0] == 0x00 && buffer[1] == 0x00 && buffer[2] == 0x88 && buffer[3] == 0x08) + { + printk(KERN_INFO "i2c Read 0x08 = %d!\n",buffer[0]); + printk(KERN_INFO "i2c Read 0x09 = %d!\n",buffer[1]); + printk(KERN_INFO "i2c Read 0x0a = %d!\n",buffer[2]); + printk(KERN_INFO "i2c Read 0x0b = %d!\n",buffer[3]); + printk(KERN_INFO "@@@ %s DMT_DEVICE_NAME registered I2C driver!\n",__FUNCTION__); + dev.client = client; + } + else + { + printk(KERN_INFO "err : i2c Read 0x08 = %d!\n",buffer[0]); + printk(KERN_INFO "err : i2c Read 0x09 = %d!\n",buffer[1]); + printk(KERN_INFO "err : i2c Read 0x0a = %d!\n",buffer[2]); + printk(KERN_INFO "err : i2c Read 0x0b = %d!\n",buffer[3]); + dev.client = NULL; + return -1; + } +#if DMT_DEBUG_DATA + IN_FUNC_MSG; + //check sensorlayout[i][j] + for(i = 0; i < 3; ++i) + { + for(j = 0; j < 3; j++) + printk("%d",sensorlayout[i][j]); + printk("\n"); + } +#endif + return 0; +} + +static int __devexit device_i2c_remove(struct i2c_client *client) +{ +#if DMT_DEBUG_DATA + IN_FUNC_MSG; +#endif + return 0; +} + +int dmt08_enable(int en) +{ + printk(KERN_DEBUG "%s: enable = %d\n", __func__, en); + DMT_sysfs_update_active_status(en); + return 0; +} + +int dmt08_setDelay(int mdelay) +{ + printk(KERN_DEBUG "%s: delay = %d\n", __func__, mdelay); + atomic_set(&delay, mdelay); + return 0; +} + +int dmt08_getLSG(int *lsg) +{ + *lsg = 256; + return 0; +} + +struct gsensor_data dmt08_gs_data = { + .i2c_addr = DMT08_I2C_ADDR, + .enable = dmt08_enable, + .setDelay = dmt08_setDelay, + .getLSG = dmt08_getLSG, +}; + +static int __init device_init(void) +{ + int err=-1; + struct device *device; + int ret = 0; + IN_FUNC_MSG; + + if (get_gsensor_conf(&gs_conf)) + return -1; + + if (gs_conf.op != 1) + return -1; + + printk("G-Sensor dmt08 init\n"); + + if (gsensor_register(&dmt08_gs_data)) + return -1; + + if (gsensor_i2c_register_device() < 0) + return -1; + + atomic_set(&delay, 200); + + ret = alloc_chrdev_region(&dev.devno, 0, 1, GSENSOR_DEVICE_NAME); + if(ret) + { + printk("%s, can't allocate chrdev\n", __func__); + return ret; + } + printk("%s, register chrdev(%d, %d)\n", __func__, MAJOR(dev.devno), MINOR(dev.devno)); + + cdev_init(&dev.cdev, &dmt_g_sensor_fops); + dev.cdev.owner = THIS_MODULE; + ret = cdev_add(&dev.cdev, dev.devno, 1); + if(ret < 0) + { + printk("%s, add character device error, ret %d\n", __func__, ret); + return ret; + } + dev.class = class_create(THIS_MODULE, ACCELEMETER_CLASS_NAME); + if(IS_ERR(dev.class)) + { + printk("%s, create class, error\n", __func__); + return ret; + } + device=device_create(dev.class, NULL, dev.devno, NULL, GSENSOR_DEVICE_NAME); + + mutex_init(&DMT_mutex); + + INIT_DELAYED_WORK(&work, DMT_work_func); + printk("DMT: INIT_DELAYED_WORK\n"); + + err=input_init(); + if(err) + { + printk("%s:input_init fail, error code= %d\n", __func__, err); + } + + err = create_device_attributes(device,DMT_attributes); + + return i2c_add_driver(&device_i2c_driver); +} + + +static void __exit device_exit(void) +{ + IN_FUNC_MSG; + input_unregister_device(input); + input_free_device(input); + cdev_del(&dev.cdev); + unregister_chrdev_region(dev.devno, 1); + device_destroy(dev.class, dev.devno); + class_destroy(dev.class); + i2c_del_driver(&device_i2c_driver); +} + + +void gsensor_write_offset_to_file(void) +{ + char data[18]; + unsigned int orgfs; + long lfile=-1; + spinlock_t lock; //add by yang + spin_lock_init(&lock); //add by yang + sprintf(data,"%5d %5d %5d",offset.u.x,offset.u.y,offset.u.z); + + orgfs = get_fs(); +// Set segment descriptor associated to kernel space + set_fs(KERNEL_DS); + + lfile=sys_open(OffsetFileName,O_WRONLY|O_CREAT, 0777); + if (lfile < 0) + { + printk("sys_open %s error!!. %ld\n",OffsetFileName,lfile); + } + else + { + spin_lock(&lock); //add by yang + sys_write(lfile, data,18); + sys_close(lfile); + spin_unlock(&lock); //add by yang + } + set_fs(orgfs); +} + +void gsensor_read_offset_from_file(void) +{ + unsigned int orgfs; + char data[18]; + long lfile=-1; + orgfs = get_fs(); +// Set segment descriptor associated to kernel space + set_fs(KERNEL_DS); + + lfile = sys_open(OffsetFileName, O_RDONLY, 0); + if (lfile < 0) + { + printk("sys_open %s error!!. %ld\n",OffsetFileName,lfile); + strcpy(data,"00000 00000 00000"); + + } + else + { + sys_read(lfile, data, 18); + sys_close(lfile); + } + sscanf(data,"%hd %hd %hd",&offset.u.x,&offset.u.y,&offset.u.z); + printk("%5d %5d %5d",offset.u.x,offset.u.y,offset.u.z); + set_fs(orgfs); +} + +MODULE_AUTHOR("DMT_RD"); +MODULE_DESCRIPTION("DMT Gsensor Driver"); +MODULE_LICENSE("GPL"); + +module_init(device_init); +module_exit(device_exit); diff --git a/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/dmt08_gsensor/dmt08.h b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/dmt08_gsensor/dmt08.h new file mode 100755 index 00000000..5a1ac3b7 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/dmt08_gsensor/dmt08.h @@ -0,0 +1,105 @@ +/* + * @file include/linux/dmt.h + * @brief DMARD05 & DMARD06 & DMARD07 g-sensor Linux device driver + * @author Domintech Technology Co., Ltd (http://www.domintech.com.tw) + * @version 1.31 + * @date 2012/3/27 + * + * @section LICENSE + * + * Copyright 2011 Domintech Technology Co., Ltd + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + * + */ +#ifndef DMT_H +#define DMT_H + +#if (defined(CONFIG_SENSORS_DMARD05) || defined(CONFIG_SENSORS_DMARD05_MODULE)) +#define DEVICE_I2C_NAME "dmard05" +#define DEFAULT_SENSITIVITY 64 +#define WHO_AM_I_VALUE 0x05 +#define X_OUT 0x41 +#define SW_RESET 0x53 +#define WHO_AM_I 0x0f +#elif (defined(CONFIG_SENSORS_DMARD06) || defined(CONFIG_SENSORS_DMARD06_MODULE)) +#define DEVICE_I2C_NAME "dmard06" +#define DEFAULT_SENSITIVITY 32 +#define WHO_AM_I_VALUE 0x06 +#define X_OUT 0x41 +#define SW_RESET 0x53 +#define WHO_AM_I 0x0f +#elif (defined(CONFIG_SENSORS_DMARD07) || defined(CONFIG_SENSORS_DMARD07_MODULE)) +#define DEVICE_I2C_NAME "dmard07" +#define DEFAULT_SENSITIVITY 64 +#define WHO_AM_I_VALUE 0x07 +#define X_OUT 0x41 +#define SW_RESET 0x53 +#define WHO_AM_I 0x0f +#elif (defined(CONFIG_SENSORS_DMARD03) || defined(CONFIG_SENSORS_DMARD03_MODULE)) +#define DEVICE_I2C_NAME "dmard03" +#define DEFAULT_SENSITIVITY 256 +#define CONTROL_REGISTERS 0x08 +#elif (defined(CONFIG_SENSORS_DMARD08) || defined(CONFIG_SENSORS_DMARD08_MODULE) || defined(CONFIG_WMT_SENSOR_DMT08)) +#define DEVICE_I2C_NAME "g-sensor" +#define DEFAULT_SENSITIVITY 256 +#define CONTROL_REGISTERS 0x08 +#define DMT08_I2C_ADDR 0x1c +#endif + +//#define DMT_DEBUG_DATA 1 +#define DMT_DEBUG_DATA 0 + +#if DMT_DEBUG_DATA +#define IN_FUNC_MSG printk(KERN_INFO "@DMT@ In %s\n", __func__) +#define PRINT_X_Y_Z(x, y, z) printk(KERN_INFO "@DMT@ X/Y/Z axis: %04d , %04d , %04d\n", (x), (y), (z)) +#define PRINT_OFFSET(x, y, z) printk(KERN_INFO "@offset@ X/Y/Z axis: %04d , %04d , %04d\n",offset.x,offset.y,offset.z); +#else +#define IN_FUNC_MSG +#define PRINT_X_Y_Z(x, y, z) +#define PRINT_OFFSET(x, y, z) +#endif + +//g-senor layout configuration, choose one of the following configuration +#define CONFIG_GSEN_LAYOUT_PAT_1 +//#define CONFIG_GSEN_LAYOUT_PAT_2 +//#define CONFIG_GSEN_LAYOUT_PAT_3 +//#define CONFIG_GSEN_LAYOUT_PAT_4 +//#define CONFIG_GSEN_LAYOUT_PAT_5 +//#define CONFIG_GSEN_LAYOUT_PAT_6 +//#define CONFIG_GSEN_LAYOUT_PAT_7 +//#define CONFIG_GSEN_LAYOUT_PAT_8 + +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Z_NEGATIVE 1 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Z_POSITIVE 2 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Y_NEGATIVE 3 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Y_POSITIVE 4 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_X_NEGATIVE 5 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_X_POSITIVE 6 + +#define AVG_NUM 16 + +#define IOCTL_MAGIC 0x09 +#define SENSOR_DATA_SIZE 3 + +#define SENSOR_RESET _IO(IOCTL_MAGIC, 0) +#define SENSOR_CALIBRATION _IOWR(IOCTL_MAGIC, 1, int[SENSOR_DATA_SIZE]) +#define SENSOR_GET_OFFSET _IOR(IOCTL_MAGIC, 2, int[SENSOR_DATA_SIZE]) +#define SENSOR_SET_OFFSET _IOWR(IOCTL_MAGIC, 3, int[SENSOR_DATA_SIZE]) +#define SENSOR_READ_ACCEL_XYZ _IOR(IOCTL_MAGIC, 4, int[SENSOR_DATA_SIZE]) +#define SENSOR_SETYPR _IOW(IOCTL_MAGIC, 5, int[SENSOR_DATA_SIZE]) +#define SENSOR_GET_OPEN_STATUS _IO(IOCTL_MAGIC, 6) +#define SENSOR_GET_CLOSE_STATUS _IO(IOCTL_MAGIC, 7) +#define SENSOR_GET_DELAY _IOR(IOCTL_MAGIC, 8, unsigned int*) + +#define SENSOR_MAXNR 8 + +#endif diff --git a/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/dmt10_gsensor/Makefile b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/dmt10_gsensor/Makefile new file mode 100755 index 00000000..de723bf5 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/dmt10_gsensor/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for the DMARD10 Sensor driver +# + +sensor_dmt10-objs := dmt10.o +obj-$(CONFIG_WMT_SENSOR_DMT10) += sensor_dmt10.o diff --git a/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/dmt10_gsensor/dmt10.c b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/dmt10_gsensor/dmt10.c new file mode 100755 index 00000000..e8e7b288 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/dmt10_gsensor/dmt10.c @@ -0,0 +1,950 @@ +/* + * @file drivers/misc/dmt10.c + * @brief DMT g-sensor Linux device driver + * @author Domintech Technology Co., Ltd (http://www.domintech.com.tw) + * @version 1.03 + * + * @section LICENSE + * + * Copyright 2012 Domintech Technology Co., Ltd + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + * V1.00 D10 First Release date 2012/09/21 + * V1.01 static struct dmt_data s_dmt Refresh to device_i2c_probe date 2012/11/23 + * V1.02 0x0D cck : adjustment 204.8KHz core clock date 2012/11/30 + * V1.03 write TCGYZ & TCGX : set value to 0x00 date 2012/12/10 + * + * @DMT Package version D10_General_driver v1.4 + * + */ +#include "dmt10.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../gsensor.h" + +static struct gsensor_conf gs_conf; + +static unsigned int interval; +void gsensor_write_offset_to_file(void); +void gsensor_read_offset_from_file(void); +char OffsetFileName[] = "/data/misc/dmt/offset.txt"; /* FILE offset.txt */ +static raw_data offset; +static struct dmt_data *s_dmt; +static int device_init(void); +static void device_exit(void); + +static int device_open(struct inode*, struct file*); +static long device_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); +static int device_close(struct inode*, struct file*); + +static int device_i2c_suspend(struct i2c_client *client, pm_message_t mesg); +static int device_i2c_resume(struct i2c_client *client); +static int __devinit device_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id); +static int __devexit device_i2c_remove(struct i2c_client *client); +void device_i2c_read_xyz(struct i2c_client *client, s16 *xyz); +static int device_i2c_rxdata(struct i2c_client *client, unsigned char *rxDat, int length); +static int device_i2c_txdata(struct i2c_client *client, unsigned char *txData, int length); + +static int DMT_GetOpenStatus(struct i2c_client *client){ + struct dmt_data *dmt = i2c_get_clientdata(client); + GSE_LOG("start active=%d\n",dmt->active.counter); + wait_event_interruptible(dmt->open_wq, (atomic_read(&dmt->active) != 0)); + return 0; +} + +static int DMT_GetCloseStatus(struct i2c_client *client){ + struct dmt_data *dmt = i2c_get_clientdata(client); + GSE_LOG("start active=%d\n",dmt->active.counter); + wait_event_interruptible(dmt->open_wq, (atomic_read(&dmt->active) <= 0)); + return 0; +} + +static void DMT_sysfs_update_active_status(struct dmt_data *dmt , int en){ + unsigned long dmt_delay; + if(en){ + dmt_delay = msecs_to_jiffies(atomic_read(&dmt->delay)); + if(dmt_delay < 1) + dmt_delay = 1; + + GSE_LOG("schedule_delayed_work start with delay time=%lu\n",dmt_delay); + schedule_delayed_work(&dmt->delaywork,dmt_delay); + } + else + cancel_delayed_work_sync(&dmt->delaywork); +} + +static bool get_value_as_int(char const *buf, size_t size, int *value){ + long tmp; + if (size == 0) + return false; + /* maybe text format value */ + if ((buf[0] == '0') && (size > 1)) { + if ((buf[1] == 'x') || (buf[1] == 'X')) { + /* hexadecimal format */ + if (0 != strict_strtol(buf, 16, &tmp)) + return false; + } else { + /* octal format */ + if (0 != strict_strtol(buf, 8, &tmp)) + return false; + } + } else { + /* decimal format */ + if (0 != strict_strtol(buf, 10, &tmp)) + return false; + } + + if (tmp > INT_MAX) + return false; + + *value = tmp; + return true; +} +static bool get_value_as_int64(char const *buf, size_t size, long long *value) +{ + long long tmp; + if (size == 0) + return false; + /* maybe text format value */ + if ((buf[0] == '0') && (size > 1)) { + if ((buf[1] == 'x') || (buf[1] == 'X')) { + /* hexadecimal format */ + if (0 != strict_strtoll(buf, 16, &tmp)) + return false; + } else { + /* octal format */ + if (0 != strict_strtoll(buf, 8, &tmp)) + return false; + } + } else { + /* decimal format */ + if (0 != strict_strtoll(buf, 10, &tmp)) + return false; + } + + if (tmp > LLONG_MAX) + return false; + + *value = tmp; + return true; +} + +static ssize_t dmt_sysfs_enable_show( + struct dmt_data *dmt, char *buf, int pos) +{ + char str[2][16]={"ACC enable OFF","ACC enable ON"}; + int flag; + flag=atomic_read(&dmt->enable); + return sprintf(buf, "%s\n", str[flag]); +} + +static ssize_t dmt_sysfs_enable_store( + struct dmt_data *dmt, char const *buf, size_t count, int pos) +{ + int en = 0; + if (NULL == buf) + return -EINVAL; + GSE_LOG("buf=%x %x\n", buf[0], buf[1]); + if (0 == count) + return 0; + + if (false == get_value_as_int(buf, count, &en)) + return -EINVAL; + + en = en ? 1 : 0; + + atomic_set(&dmt->enable,en); + DMT_sysfs_update_active_status(dmt , en); + return count; +} + +/***** Acceleration ***/ +static ssize_t DMT_enable_acc_show(struct device *dev, struct device_attribute *attr, char *buf){ + return dmt_sysfs_enable_show( dev_get_drvdata(dev), buf, ACC_DATA_FLAG); +} + +static ssize_t DMT_enable_acc_store( struct device *dev, struct device_attribute *attr, char const *buf, size_t count){ + return dmt_sysfs_enable_store( dev_get_drvdata(dev), buf, count, ACC_DATA_FLAG); +} + +/***** sysfs delay **************************************************/ +static ssize_t dmt_sysfs_delay_show( struct dmt_data *dmt, char *buf, int pos){ + return sprintf(buf, "%d\n", atomic_read(&dmt->delay)); +} + +static ssize_t dmt_sysfs_delay_store( struct dmt_data *dmt, char const *buf, size_t count, int pos){ + long long val = 0; + + if (NULL == buf) + return -EINVAL; + + if (0 == count) + return 0; + + if (false == get_value_as_int64(buf, count, &val)) + return -EINVAL; + + atomic_set(&dmt->delay, (unsigned int) val); + GSE_LOG("Driver attribute set delay =%lld\n", val); + + return count; +} + +/***** Accelerometer ***/ +static ssize_t DMT_delay_acc_show( struct device *dev, struct device_attribute *attr, char *buf){ + return dmt_sysfs_delay_show( dev_get_drvdata(dev), buf, ACC_DATA_FLAG); +} + +static ssize_t DMT_delay_acc_store( struct device *dev, struct device_attribute *attr,char const *buf, size_t count){ + return dmt_sysfs_delay_store( dev_get_drvdata(dev), buf, count, ACC_DATA_FLAG); +} + +static struct device_attribute DMT_attributes[] = { + __ATTR(enable_acc, 0755, DMT_enable_acc_show, DMT_enable_acc_store), + __ATTR(delay_acc, 0755, DMT_delay_acc_show, DMT_delay_acc_store), + __ATTR_NULL, +}; + +static char const *const ACCELEMETER_CLASS_NAME = "accelemeter"; +static char const *const GSENSOR_DEVICE_NAME = "dmard10"; +static char const *const device_link_name = "i2c"; +static dev_t const dmt_device_dev_t = MKDEV(MISC_MAJOR, 240); + +/***** dmt sysfs functions ******************************************/ +static int create_device_attributes(struct device *dev, struct device_attribute *attrs){ + int i; + int err = 0; + for (i = 0 ; NULL != attrs[i].attr.name ; ++i) { + err = device_create_file(dev, &attrs[i]); + if (0 != err) + break; + } + + if (0 != err) { + for (; i >= 0 ; --i) + device_remove_file(dev, &attrs[i]); + } + return err; +} + +static void remove_device_attributes( + struct device *dev, + struct device_attribute *attrs) +{ + int i; + + for (i = 0 ; NULL != attrs[i].attr.name ; ++i) + device_remove_file(dev, &attrs[i]); +} + +static int create_sysfs_interfaces(struct dmt_data *dmt) +{ + int err; + + if (NULL == dmt) + return -EINVAL; + + err = 0; + dmt->class = class_create(THIS_MODULE, ACCELEMETER_CLASS_NAME); + if (IS_ERR(dmt->class)) { + err = PTR_ERR(dmt->class); + goto exit_class_create_failed; + } + + dmt->class_dev = device_create( + dmt->class, + NULL, + dmt_device_dev_t, + dmt, + GSENSOR_DEVICE_NAME); + if (IS_ERR(dmt->class_dev)) { + err = PTR_ERR(dmt->class_dev); + goto exit_class_device_create_failed; + } + + err = sysfs_create_link( + &dmt->class_dev->kobj, + &dmt->client->dev.kobj, + device_link_name); + if (0 > err) + goto exit_sysfs_create_link_failed; + + err = create_device_attributes( + dmt->class_dev, + DMT_attributes); + if (0 > err) + goto exit_device_attributes_create_failed; +#if 0 + err = create_device_binary_attributes( + &dmt->class_dev->kobj, + dmt_bin_attributes); + if (0 > err) + goto exit_device_binary_attributes_create_failed; +#endif + + return err; + +#if 0 +exit_device_binary_attributes_create_failed: + remove_device_attributes(dmt->class_dev, dmt_attributes); +#endif +exit_device_attributes_create_failed: + sysfs_remove_link(&dmt->class_dev->kobj, device_link_name); +exit_sysfs_create_link_failed: + device_destroy(dmt->class, dmt_device_dev_t); +exit_class_device_create_failed: + dmt->class_dev = NULL; + class_destroy(dmt->class); +exit_class_create_failed: + dmt->class = NULL; + return err; +} + +static void remove_sysfs_interfaces(struct dmt_data *dmt) +{ + if (NULL == dmt) + return; + + if (NULL != dmt->class_dev) { + + remove_device_attributes( + dmt->class_dev, + DMT_attributes); + sysfs_remove_link( + &dmt->class_dev->kobj, + device_link_name); + dmt->class_dev = NULL; + } + if (NULL != dmt->class) { + device_destroy( + dmt->class, + dmt_device_dev_t); + class_destroy(dmt->class); + dmt->class = NULL; + } +} + +int input_init(struct i2c_client *client){ + struct dmt_data *dmt = i2c_get_clientdata(client); + int err=0; + dmt->input=input_allocate_device(); + if (!dmt->input){ + GSE_ERR("input device allocate ERROR !!\n"); + return -ENOMEM; + } + else + GSE_LOG("input device allocate Success !!\n"); + /* Setup input device */ + set_bit(EV_ABS, dmt->input->evbit); + /* Accelerometer [-78.5, 78.5]m/s2 in Q16 */ + input_set_abs_params(dmt->input, ABS_X, -1024, 1024, 0, 0); + input_set_abs_params(dmt->input, ABS_Y, -1024, 1024, 0, 0); + input_set_abs_params(dmt->input, ABS_Z, -1024, 1024, 0, 0); + /* Set InputDevice Name */ + dmt->input->name = INPUT_NAME_ACC; + /* Register */ + err = input_register_device(dmt->input); + if (err) { + GSE_ERR("input_register_device ERROR !!\n"); + input_free_device(dmt->input); + return err; + } + GSE_LOG("input_register_device SUCCESS %d !! \n",err); + + return err; +} + +int gsensor_calibrate(void) +{ + //struct dmt_data *dmt = i2c_get_clientdata(client); + raw_data avg; + int i, j; + long xyz_acc[SENSOR_DATA_SIZE]; + s16 xyz[SENSOR_DATA_SIZE]; + + offset.u.x=0; + offset.u.y=0; + offset.u.z=0; + /* initialize the accumulation buffer */ + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + xyz_acc[i] = 0; + + for(i = 0; i < AVG_NUM; i++) { + device_i2c_read_xyz(s_dmt->client, (s16 *)&xyz); + for(j = 0; j < SENSOR_DATA_SIZE; ++j) + xyz_acc[j] += xyz[j]; + } + /* calculate averages */ + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + avg.v[i] = (s16) (xyz_acc[i] / AVG_NUM); + + if(avg.v[2] < 0){ + offset.u.x = avg.v[0] ; + offset.u.y = avg.v[1] ; + offset.u.z = avg.v[2] + DEFAULT_SENSITIVITY; + return CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Z_POSITIVE; + } + else{ + offset.u.x = avg.v[0] ; + offset.u.y = avg.v[1] ; + offset.u.z = avg.v[2] - DEFAULT_SENSITIVITY; + return CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Z_NEGATIVE; + } + return 0; +} + +int gsensor_reset(struct i2c_client *client){ + unsigned char buffer[7], buffer2[2]; + /* 1. check D10 , VALUE_STADR = 0x55 , VALUE_STAINT = 0xAA */ + buffer[0] = REG_STADR; + buffer2[0] = REG_STAINT; + + device_i2c_rxdata(client, buffer, 2); + device_i2c_rxdata(client, buffer2, 2); + + if( buffer[0] == VALUE_STADR || buffer2[0] == VALUE_STAINT){ + GSE_LOG(" REG_STADR_VALUE = %d , REG_STAINT_VALUE = %d\n", buffer[0], buffer2[0]); + } + else{ + GSE_LOG(" REG_STADR_VALUE = %d , REG_STAINT_VALUE = %d \n", buffer[0], buffer2[0]); + return -1; + } + /* 2. Powerdown reset */ + buffer[0] = REG_PD; + buffer[1] = VALUE_PD_RST; + device_i2c_txdata(client, buffer, 2); + /* 3. ACTR => Standby mode => Download OTP to parameter reg => Standby mode => Reset data path => Standby mode */ + buffer[0] = REG_ACTR; + buffer[1] = MODE_Standby; + buffer[2] = MODE_ReadOTP; + buffer[3] = MODE_Standby; + buffer[4] = MODE_ResetDataPath; + buffer[5] = MODE_Standby; + device_i2c_txdata(client, buffer, 6); + /* 4. OSCA_EN = 1 ,TSTO = b'000(INT1 = normal, TEST0 = normal) */ + buffer[0] = REG_MISC2; + buffer[1] = VALUE_MISC2_OSCA_EN; + device_i2c_txdata(client, buffer, 2); + /* 5. AFEN = 1(AFE will powerdown after ADC) */ + buffer[0] = REG_AFEM; + buffer[1] = VALUE_AFEM_AFEN_Normal; + buffer[2] = VALUE_CKSEL_ODR_100_204; + buffer[3] = VALUE_INTC; + buffer[4] = VALUE_TAPNS_Ave_2; + buffer[5] = 0x00; // DLYC, no delay timing + buffer[6] = 0x07; // INTD=1 (push-pull), INTA=1 (active high), AUTOT=1 (enable T) + device_i2c_txdata(client, buffer, 7); + /* 6. write TCGYZ & TCGX */ + buffer[0] = REG_WDAL; // REG:0x01 + buffer[1] = 0x00; // set TC of Y,Z gain value + buffer[2] = 0x00; // set TC of X gain value + buffer[3] = 0x03; // Temperature coefficient of X,Y,Z gain + device_i2c_txdata(client, buffer, 4); + + buffer[0] = REG_ACTR; // REG:0x00 + buffer[1] = MODE_Standby; // Standby + buffer[2] = MODE_WriteOTPBuf; // WriteOTPBuf + buffer[3] = MODE_Standby; // Standby + device_i2c_txdata(client, buffer, 4); + //buffer[0] = REG_TCGYZ; + //device_i2c_rxdata(client, buffer, 2); + //GSE_LOG(" TCGYZ = %d, TCGX = %d \n", buffer[0], buffer[1]); + + /* 7. Activation mode */ + buffer[0] = REG_ACTR; + buffer[1] = MODE_Active; + device_i2c_txdata(client, buffer, 2); + return 0; +} + +void gsensor_set_offset(int val[3]){ + int i; + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + offset.v[i] = (s16) val[i]; +} + +struct file_operations dmt_g_sensor_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = device_ioctl, + .open = device_open, + .release = device_close, +}; + +static struct miscdevice dmt_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = DEVICE_I2C_NAME, + .fops = &dmt_g_sensor_fops, +}; + +static int sensor_close_dev(struct i2c_client *client){ + char buffer[3]; + buffer[0] = REG_ACTR; + buffer[1] = MODE_Standby; + buffer[2] = MODE_Off; + GSE_FUN(); + return device_i2c_txdata(client,buffer, 3); +} + +static int device_i2c_suspend(struct i2c_client *client, pm_message_t mesg){ + GSE_FUN(); + return sensor_close_dev(client); +} + +static int device_i2c_resume(struct i2c_client *client){ + GSE_FUN(); + return gsensor_reset(client); +} + +static void device_i2c_shutdown(struct i2c_client *client) +{ + struct dmt_data *dmt = i2c_get_clientdata(client); + flush_delayed_work_sync(&dmt->delaywork); + cancel_delayed_work_sync(&dmt->delaywork); +} + +static int __devexit device_i2c_remove(struct i2c_client *client){ + return 0; +} + +static const struct i2c_device_id device_i2c_ids[] = { + {DEVICE_I2C_NAME, 0}, + {} +}; + +//MODULE_DEVICE_TABLE(i2c, device_i2c_ids); + +static struct i2c_driver device_i2c_driver = +{ + .driver = { + .owner = THIS_MODULE, + .name = DEVICE_I2C_NAME, + }, + .class = I2C_CLASS_HWMON, + .id_table = device_i2c_ids, + .probe = device_i2c_probe, + .remove = __devexit_p(device_i2c_remove), + .shutdown = device_i2c_shutdown, +#ifndef CONFIG_ANDROID_POWER + .suspend = device_i2c_suspend, + .resume = device_i2c_resume, +#endif + +}; + +static int device_open(struct inode *inode, struct file *filp) +{ + return 0; +} + +static long device_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + //struct i2c_client *client = (struct i2c_client*)filp->private_data; + //struct dmt_data *dmt = (struct dmt_data*)i2c_get_clientdata(client); + + int err = 0, ret = 0, i; + int intBuf[SENSOR_DATA_SIZE]; + s16 xyz[SENSOR_DATA_SIZE]; + /* check type */ + if (_IOC_TYPE(cmd) != IOCTL_MAGIC) return -ENOTTY; + + /* check user space pointer is valid */ + if (_IOC_DIR(cmd) & _IOC_READ) + err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd)); + else if (_IOC_DIR(cmd) & _IOC_WRITE) + err = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd)); + if (err) return -EFAULT; + + switch(cmd) + { + case SENSOR_RESET: + gsensor_reset(s_dmt->client); + return ret; + + case SENSOR_CALIBRATION: + /* get orientation info */ + //if(copy_from_user(&intBuf, (int*)arg, sizeof(intBuf))) return -EFAULT; + gsensor_calibrate(); + GSE_LOG("Sensor_calibration:%d %d %d\n",offset.u.x,offset.u.y,offset.u.z); + /* save file */ + gsensor_write_offset_to_file(); + + /* return the offset */ + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + intBuf[i] = offset.v[i]; + + ret = copy_to_user((int *)arg, &intBuf, sizeof(intBuf)); + return ret; + + case SENSOR_GET_OFFSET: + /* get data from file */ + gsensor_read_offset_from_file(); + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + intBuf[i] = offset.v[i]; + + ret = copy_to_user((int *)arg, &intBuf, sizeof(intBuf)); + return ret; + + case SENSOR_SET_OFFSET: + ret = copy_from_user(&intBuf, (int *)arg, sizeof(intBuf)); + gsensor_set_offset(intBuf); + /* write in to file */ + gsensor_write_offset_to_file(); + return ret; + + case SENSOR_READ_ACCEL_XYZ: + device_i2c_read_xyz(s_dmt->client, (s16 *)&xyz); + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + intBuf[i] = xyz[i] - offset.v[i]; + + ret = copy_to_user((int*)arg, &intBuf, sizeof(intBuf)); + return ret; + + case SENSOR_SETYPR: + if(copy_from_user(&intBuf, (int*)arg, sizeof(intBuf))) { + GSE_LOG("%s:copy_from_user(&intBuf, (int*)arg, sizeof(intBuf)) ERROR, -EFAULT\n",__func__); + return -EFAULT; + } + input_report_abs(s_dmt->input, ABS_X, intBuf[0]); + input_report_abs(s_dmt->input, ABS_Y, -intBuf[1]); + input_report_abs(s_dmt->input, ABS_Z, -intBuf[2]); + input_sync(s_dmt->input); + GSE_LOG(KERN_INFO "%s:SENSOR_SETYPR OK! x=%d,y=%d,z=%d\n",__func__,intBuf[0],intBuf[1],intBuf[2]); + return 1; + + case SENSOR_GET_OPEN_STATUS: + GSE_LOG(KERN_INFO "%s:Going into DMT_GetOpenStatus()\n",__func__); + DMT_GetOpenStatus(s_dmt->client); + GSE_LOG(KERN_INFO "%s:DMT_GetOpenStatus() finished\n",__func__); + return 1; + break; + + case SENSOR_GET_CLOSE_STATUS: + GSE_LOG(KERN_INFO "%s:Going into DMT_GetCloseStatus()\n",__func__); + DMT_GetCloseStatus(s_dmt->client); + GSE_LOG(KERN_INFO "%s:DMT_GetCloseStatus() finished\n",__func__); + return 1; + break; + + case SENSOR_GET_DELAY: + ret = copy_to_user((int*)arg, &interval, sizeof(interval)); + return 1; + break; + + default: /* redundant, as cmd was checked against MAXNR */ + return -ENOTTY; + } + + return 0; +} + +static int device_close(struct inode *inode, struct file *filp) +{ + return 0; +} + +/***** I2C I/O function ***********************************************/ +static int device_i2c_rxdata( struct i2c_client *client, unsigned char *rxData, int length) +{ + struct i2c_msg msgs[] = + { + {.addr = client->addr, .flags = 0, .len = 1, .buf = rxData,}, + {.addr = client->addr, .flags = I2C_M_RD, .len = length, .buf = rxData,}, + }; + //unsigned char addr = rxData[0]; + if (i2c_transfer(client->adapter, msgs, 2) < 0) { + dev_err(&client->dev, "%s: transfer failed.", __func__); + return -EIO; + } + //DMT_DATA(&client->dev, "RxData: len=%02x, addr=%02x, data=%02x\n", + //length, addr, rxData[0]); + + return 0; +} + +static int device_i2c_txdata( struct i2c_client *client, unsigned char *txData, int length) +{ + struct i2c_msg msg[] = + { + {.addr = client->addr, .flags = 0, .len = length, .buf = txData,}, + }; + + if (i2c_transfer(client->adapter, msg, 1) < 0) { + dev_err(&client->dev, "%s: transfer failed.", __func__); + return -EIO; + } + //DMT_DATA(&client->dev, "TxData: len=%02x, addr=%02x data=%02x\n", + //length, txData[0], txData[1]); + return 0; +} +/* 1g = 128 becomes 1g = 1024 */ +static inline void device_i2c_correct_accel_sign(s16 *val){ + *val<<= 3; +} + +void device_i2c_merge_register_values(struct i2c_client *client, s16 *val, u8 msb, u8 lsb){ + *val = (((u16)msb) << 8) | (u16)lsb; + device_i2c_correct_accel_sign(val); +} + +void device_i2c_read_xyz(struct i2c_client *client, s16 *xyz_p){ + u8 buffer[11]; + s16 xyzTmp[SENSOR_DATA_SIZE]; + int i, j; + /* get xyz high/low bytes, 0x12 */ + buffer[0] = REG_STADR; + device_i2c_rxdata(client, buffer, 10); + + /* merge to 10-bits value */ + for(i = 0; i < SENSOR_DATA_SIZE; ++i){ + xyz_p[i] = 0; + device_i2c_merge_register_values(client, (xyzTmp + i), buffer[2*(i+1)+1], buffer[2*(i+1)]); + /* transfer to the default layout */ + for(j = 0; j < 3; j++) + xyz_p[i] += sensorlayout[i][j] * xyzTmp[j]; + } + GSE_LOG("xyz_p: %04d , %04d , %04d\n", xyz_p[0], xyz_p[1], xyz_p[2]); +} + +static void DMT_work_func(struct work_struct *delaywork) +{ + struct dmt_data *dmt = container_of(delaywork, struct dmt_data, delaywork.work); + int i; + static int firsttime=0; + s16 xyz[SENSOR_DATA_SIZE]; + + unsigned long t=atomic_read(&dmt->delay); + unsigned long dmt_delay = msecs_to_jiffies(t); + if(!firsttime){ + //gsensor_read_offset_from_file(); + firsttime=1; + } + + GSE_LOG("t=%lu , dmt_delay=%lu\n", t, dmt_delay); + device_i2c_read_xyz(dmt->client, (s16 *)&xyz); + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + xyz[i] -= offset.v[i]; + + GSE_LOG("@DMTRaw@ X/Y/Z axis: %04d , %04d , %04d\n", xyz[0], xyz[1], xyz[2]); + GSE_LOG("@Offset@ X/Y/Z axis: %04d , %04d , %04d\n", offset.u.x, offset.u.y, offset.u.z); + input_report_abs(dmt->input, ABS_X, xyz[gs_conf.xyz_axis[ABS_X][0]]*gs_conf.xyz_axis[ABS_X][1]); + input_report_abs(dmt->input, ABS_Y, xyz[gs_conf.xyz_axis[ABS_Y][0]]*gs_conf.xyz_axis[ABS_Y][1]); + input_report_abs(dmt->input, ABS_Z, xyz[gs_conf.xyz_axis[ABS_Z][0]]*gs_conf.xyz_axis[ABS_Z][1]); + input_sync(dmt->input); + + if(dmt_delay < 1) + dmt_delay = 1; + schedule_delayed_work(&dmt->delaywork, dmt_delay); +} + +static int __devinit device_i2c_probe(struct i2c_client *client,const struct i2c_device_id *id){ + int i, ret = 0; + //struct dmt_data *s_dmt; + + GSE_FUN(); + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + offset.v[i] = 0; + + if(!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)){ + GSE_ERR("check_functionality failed.\n"); + ret = -ENODEV; + goto exit0; + } + + /* Allocate memory for driver data */ + s_dmt = kzalloc(sizeof(struct dmt_data), GFP_KERNEL); + memset(s_dmt, 0, sizeof(struct dmt_data)); + if (s_dmt == NULL) { + GSE_ERR("alloc data failed.\n"); + ret = -ENOMEM; + goto exit1; + } + + /***** I2C initialization *****/ + s_dmt->client = client; + /* set client data */ + i2c_set_clientdata(client, s_dmt); + ret = gsensor_reset(client); + if (ret < 0) + goto exit2; + + /***** input *****/ + ret = input_init(client); + if (ret){ + GSE_ERR("input_init fail, error code= %d\n",ret); + goto exit3; + } + + /**** initialize variables in dmt_data *****/ + init_waitqueue_head(&s_dmt->open_wq); + atomic_set(&s_dmt->active, 0); + atomic_set(&s_dmt->enable, 0); + atomic_set(&s_dmt->delay, 0); + mutex_init(&s_dmt->sensor_mutex); + /***** misc *****/ + /* we have been register miscdevice in device_init, and + * marked by Eason 2013/2/4*/ + /*ret = misc_register(&dmt_device); + if (ret){ + GSE_ERR("dmt_dev register failed"); + goto exit5; + }*/ + + /***** sysfs *****/ + ret = create_sysfs_interfaces(s_dmt); + if (ret < 0){ + GSE_ERR("create sysfs failed."); + goto exit6; + } + + INIT_DELAYED_WORK(&s_dmt->delaywork, DMT_work_func); + GSE_LOG("DMT: INIT_DELAYED_WORK\n"); + return 0; + +exit6: + //misc_deregister(&dmt_device); +exit5: + input_unregister_device(s_dmt->input); +exit3: + kfree(s_dmt); +exit2: +exit1: +exit0: + return ret; +} + +int dmt10_enable(int en) +{ + printk(KERN_DEBUG "%s: enable = %d\n", __func__, en); + DMT_sysfs_update_active_status(s_dmt,en); + return 0; +} + +int dmt10_setDelay(int mdelay) +{ + printk(KERN_DEBUG "%s: delay = %d\n", __func__, mdelay); + atomic_set(&s_dmt->delay, mdelay); + return 0; +} + +int dmt10_getLSG(int *lsg) +{ + *lsg = 1024; + return 0; +} + +struct gsensor_data dmt10_gs_data = { + .i2c_addr = DMT10_I2C_ADDR, + .enable = dmt10_enable, + .setDelay = dmt10_setDelay, + .getLSG = dmt10_getLSG, +}; + +static int __init device_init(void){ + int ret = 0; + + if (get_gsensor_conf(&gs_conf)) + return -1; + + if (gs_conf.op != 3) + return -1; + printk("G-Sensor dmt10 init\n"); + + if (gsensor_register(&dmt10_gs_data)) + return -1; + + if (gsensor_i2c_register_device() < 0) + return -1; + + return i2c_add_driver(&device_i2c_driver); +} + +static void __exit device_exit(void){ + i2c_del_driver(&device_i2c_driver); +} + +void gsensor_write_offset_to_file(void){ + char data[18]; + unsigned int orgfs; + struct file *fp; + + sprintf(data,"%5d %5d %5d",offset.u.x,offset.u.y,offset.u.z); + orgfs = get_fs(); + /* Set segment descriptor associated to kernel space */ + set_fs(KERNEL_DS); + fp = filp_open(OffsetFileName, O_RDWR | O_CREAT, 0777); + if(IS_ERR(fp)){ + GSE_ERR("filp_open %s error!!.\n",OffsetFileName); + } + else{ + GSE_LOG("filp_open %s SUCCESS!!.\n",OffsetFileName); + fp->f_op->write(fp,data,18, &fp->f_pos); + filp_close(fp,NULL); + } + set_fs(orgfs); +} + +void gsensor_read_offset_from_file(void){ + unsigned int orgfs; + char data[18]; + struct file *fp; + int ux,uy,uz; + orgfs = get_fs(); + /* Set segment descriptor associated to kernel space */ + set_fs(KERNEL_DS); + + fp = filp_open(OffsetFileName, O_RDWR , 0); + GSE_FUN(); + if(IS_ERR(fp)){ + GSE_ERR("Sorry,file open ERROR !\n"); + offset.u.x=0;offset.u.y=0;offset.u.z=0; +#if AUTO_CALIBRATION + /* get acceleration average reading */ + gsensor_calibrate(); + gsensor_write_offset_to_file(); +#endif + } + else{ + GSE_LOG("filp_open %s SUCCESS!!.\n",OffsetFileName); + fp->f_op->read(fp,data,18, &fp->f_pos); + GSE_LOG("filp_read result %s\n",data); + sscanf(data,"%d %d %d",&ux,&uy,&uz); + offset.u.x=ux; + offset.u.y=uy; + offset.u.z=uz; + filp_close(fp,NULL); + } + set_fs(orgfs); +} +//********************************************************************************************************* +MODULE_AUTHOR("DMT_RD"); +MODULE_DESCRIPTION("DMT Gsensor Driver"); +MODULE_LICENSE("GPL"); + +module_init(device_init); +module_exit(device_exit); diff --git a/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/dmt10_gsensor/dmt10.h b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/dmt10_gsensor/dmt10.h new file mode 100755 index 00000000..61343657 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/dmt10_gsensor/dmt10.h @@ -0,0 +1,187 @@ +/* + * @file include/linux/dmt10.h + * @brief DMT g-sensor Linux device driver + * @author Domintech Technology Co., Ltd (http://www.domintech.com.tw) + * @version 1.02 + * @date 2012/12/10 + * + * @section LICENSE + * + * Copyright 2012 Domintech Technology Co., Ltd + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + * @DMT Package version D10_General_driver v1.4 + * + * + */ +#ifndef DMT10_H +#define DMT10_H +#include +#include +#include +#include +#include +#include +#include +#include + +#define AUTO_CALIBRATION 0 + +#define DMT_DEBUG_DATA 0 +#define GSE_TAG "[DMT_Gsensor]" +#if DMT_DEBUG_DATA +#define GSE_ERR(fmt, args...) printk(KERN_ERR GSE_TAG"%s %d : "fmt, __FUNCTION__, __LINE__, ##args) +#define GSE_LOG(fmt, args...) printk(KERN_INFO GSE_TAG fmt, ##args) +#define GSE_FUN(f) printk(KERN_INFO GSE_TAG" %s: %s: %i\n", __FILE__, __func__, __LINE__) +#define DMT_DATA(dev, ...) dev_dbg((dev), ##__VA_ARGS__) +#else +#define GSE_ERR(fmt, args...) +#define GSE_LOG(fmt, args...) +#define GSE_FUN(f) +#define DMT_DATA(dev, format, ...) +#endif + +#define DMT10_I2C_ADDR 0x18 + + +#define INPUT_NAME_ACC "g-sensor" /* Input Device Name */ +#define DEVICE_I2C_NAME "g-sensor" /* Device name for DMARD10 misc. device */ +#define REG_ACTR 0x00 +#define REG_WDAL 0x01 +#define REG_TAPNS 0x0f +#define REG_MISC2 0x1f +#define REG_AFEM 0x0c +#define REG_CKSEL 0x0d +#define REG_INTC 0x0e +#define REG_STADR 0x12 +#define REG_STAINT 0x1C +#define REG_PD 0x21 +#define REG_TCGYZ 0x26 +#define REG_X_OUT 0x41 + +#define MODE_Off 0x00 +#define MODE_ResetAtOff 0x01 +#define MODE_Standby 0x02 +#define MODE_ResetAtStandby 0x03 +#define MODE_Active 0x06 +#define MODE_Trigger 0x0a +#define MODE_ReadOTP 0x12 +#define MODE_WriteOTP 0x22 +#define MODE_WriteOTPBuf 0x42 +#define MODE_ResetDataPath 0x82 + +#define VALUE_STADR 0x55 +#define VALUE_STAINT 0xAA +#define VALUE_AFEM_AFEN_Normal 0x8f// AFEN set 1 , ATM[2:0]=b'000(normal),EN_Z/Y/X/T=1 +#define VALUE_AFEM_Normal 0x0f// AFEN set 0 , ATM[2:0]=b'000(normal),EN_Z/Y/X/T=1 +#define VALUE_INTC 0x00// INTC[6:5]=b'00 +#define VALUE_INTC_Interrupt_En 0x20// INTC[6:5]=b'01 (Data ready interrupt enable, active high at INT0) +#define VALUE_CKSEL_ODR_0_204 0x04// ODR[3:0]=b'0000 (0.78125Hz), CCK[3:0]=b'0100 (204.8kHZ) +#define VALUE_CKSEL_ODR_1_204 0x14// ODR[3:0]=b'0001 (1.5625Hz), CCK[3:0]=b'0100 (204.8kHZ) +#define VALUE_CKSEL_ODR_3_204 0x24// ODR[3:0]=b'0010 (3.125Hz), CCK[3:0]=b'0100 (204.8kHZ) +#define VALUE_CKSEL_ODR_6_204 0x34// ODR[3:0]=b'0011 (6.25Hz), CCK[3:0]=b'0100 (204.8kHZ) +#define VALUE_CKSEL_ODR_12_204 0x44// ODR[3:0]=b'0100 (12.5Hz), CCK[3:0]=b'0100 (204.8kHZ) +#define VALUE_CKSEL_ODR_25_204 0x54// ODR[3:0]=b'0101 (25Hz), CCK[3:0]=b'0100 (204.8kHZ) +#define VALUE_CKSEL_ODR_50_204 0x64// ODR[3:0]=b'0110 (50Hz), CCK[3:0]=b'0100 (204.8kHZ) +#define VALUE_CKSEL_ODR_100_204 0x74// ODR[3:0]=b'0111 (100Hz), CCK[3:0]=b'0100 (204.8kHZ) + +#define VALUE_TAPNS_NoFilter 0x00 // TAP1/TAP2 NO FILTER +#define VALUE_TAPNS_Ave_2 0x11 // TAP1/TAP2 Average 2 +#define VALUE_TAPNS_Ave_4 0x22 // TAP1/TAP2 Average 4 +#define VALUE_TAPNS_Ave_8 0x33 // TAP1/TAP2 Average 8 +#define VALUE_TAPNS_Ave_16 0x44 // TAP1/TAP2 Average 16 +#define VALUE_TAPNS_Ave_32 0x55 // TAP1/TAP2 Average 32 +#define VALUE_MISC2_OSCA_EN 0x08 +#define VALUE_PD_RST 0x52 + +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Z_NEGATIVE 1 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Z_POSITIVE 2 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Y_NEGATIVE 3 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Y_POSITIVE 4 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_X_NEGATIVE 5 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_X_POSITIVE 6 + +#define AVG_NUM 16 +#define SENSOR_DATA_SIZE 3 +#define DEFAULT_SENSITIVITY 1024 + +#define IOCTL_MAGIC 0x09 +#define SENSOR_RESET _IO(IOCTL_MAGIC, 0) +#define SENSOR_CALIBRATION _IOWR(IOCTL_MAGIC, 1, int[SENSOR_DATA_SIZE]) +#define SENSOR_GET_OFFSET _IOR(IOCTL_MAGIC, 2, int[SENSOR_DATA_SIZE]) +#define SENSOR_SET_OFFSET _IOWR(IOCTL_MAGIC, 3, int[SENSOR_DATA_SIZE]) +#define SENSOR_READ_ACCEL_XYZ _IOR(IOCTL_MAGIC, 4, int[SENSOR_DATA_SIZE]) +#define SENSOR_SETYPR _IOW(IOCTL_MAGIC, 5, int[SENSOR_DATA_SIZE]) +#define SENSOR_GET_OPEN_STATUS _IO(IOCTL_MAGIC, 6) +#define SENSOR_GET_CLOSE_STATUS _IO(IOCTL_MAGIC, 7) +#define SENSOR_GET_DELAY _IOR(IOCTL_MAGIC, 8, unsigned int*) +#define SENSOR_MAXNR 8 + +/* g-senor layout configuration, choose one of the following configuration */ +#define CONFIG_GSEN_LAYOUT_PAT_1 1 +#define CONFIG_GSEN_LAYOUT_PAT_2 0 +#define CONFIG_GSEN_LAYOUT_PAT_3 0 +#define CONFIG_GSEN_LAYOUT_PAT_4 0 +#define CONFIG_GSEN_LAYOUT_PAT_5 0 +#define CONFIG_GSEN_LAYOUT_PAT_6 0 +#define CONFIG_GSEN_LAYOUT_PAT_7 0 +#define CONFIG_GSEN_LAYOUT_PAT_8 0 + +s16 sensorlayout[3][3] = { +#if CONFIG_GSEN_LAYOUT_PAT_1 + { 1, 0, 0}, { 0, 1, 0}, { 0, 0, 1}, +#elif CONFIG_GSEN_LAYOUT_PAT_2 + { 0, 1, 0}, {-1, 0, 0}, { 0, 0, 1}, +#elif CONFIG_GSEN_LAYOUT_PAT_3 + {-1, 0, 0}, { 0,-1, 0}, { 0, 0, 1}, +#elif CONFIG_GSEN_LAYOUT_PAT_4 + { 0,-1, 0}, { 1, 0, 0}, { 0, 0, 1}, +#elif CONFIG_GSEN_LAYOUT_PAT_5 + {-1, 0, 0}, { 0, 1, 0}, { 0, 0,-1}, +#elif CONFIG_GSEN_LAYOUT_PAT_6 + { 0,-1, 0}, {-1, 0, 0}, { 0, 0,-1}, +#elif CONFIG_GSEN_LAYOUT_PAT_7 + { 1, 0, 0}, { 0,-1, 0}, { 0, 0,-1}, +#elif CONFIG_GSEN_LAYOUT_PAT_8 + { 0, 1, 0}, { 1, 0, 0}, { 0, 0,-1}, +#endif +}; + +typedef union { + struct { + s16 x; + s16 y; + s16 z; + } u; + s16 v[SENSOR_DATA_SIZE]; +} raw_data; + +struct dmt_data { + dev_t devno; + struct cdev cdev; + struct device *class_dev; + struct class *class; + struct input_dev *input; + struct i2c_client *client; + struct delayed_work delaywork; + struct work_struct work; + struct mutex sensor_mutex; + wait_queue_head_t open_wq; + atomic_t active; + atomic_t delay; + atomic_t enable; +}; + +#define ACC_DATA_FLAG 0 +#define MAG_DATA_FLAG 1 +#define ORI_DATA_FLAG 2 +#define DMT_NUM_SENSORS 3 +#endif diff --git a/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/gsensor.c b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/gsensor.c new file mode 100755 index 00000000..bd0b16af --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/gsensor.c @@ -0,0 +1,180 @@ +/*++ +Copyright (c) 2012 WonderMedia Technologies, Inc. All Rights Reserved. +This PROPRIETARY SOFTWARE is the property of WonderMedia Technologies, Inc. +and may contain trade secrets and/or other confidential information of +WonderMedia Technologies, Inc. This file shall not be disclosed to any +third party, in whole or in part, without prior written consent of +WonderMedia. + +THIS PROPRIETARY SOFTWARE AND ANY RELATED DOCUMENTATION ARE PROVIDED +AS IS, WITH ALL FAULTS, AND WITHOUT WARRANTY OF ANY KIND EITHER EXPRESS +OR IMPLIED, AND WonderMedia TECHNOLOGIES, INC. DISCLAIMS ALL EXPRESS +OR IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, +QUIET ENJOYMENT OR NON-INFRINGEMENT. +--*/ + +#include +#include +#include +#include +#include +#include "gsensor.h" + +#define GSENSOR_I2C_NAME "g-sensor" + +#ifdef CONFIG_WMT_SENSOR_DMT08 +#define GSENSOR_I2C_ADDR 0x1c +#elif defined CONFIG_WMT_SENSOR_KXTI9 +#define GSENSOR_I2C_ADDR 0x0f +#endif + +struct gsensor_data *gs_data; + +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); + +struct i2c_board_info gsensor_i2c_board_info = { + .type = GSENSOR_I2C_NAME, + .flags = 0x00, + .platform_data = NULL, + .archdata = NULL, + .irq = -1, +}; + +int gsensor_i2c_register_device (void) +{ + struct i2c_board_info *gsensor_i2c_bi; + struct i2c_adapter *adapter = NULL; + struct i2c_client *client = NULL; + gsensor_i2c_bi = &gsensor_i2c_board_info; + adapter = i2c_get_adapter(0);/*in bus 0*/ + + if (NULL == adapter) { + printk("can not get i2c adapter, client address error\n"); + return -1; + } + gsensor_i2c_bi->addr = gs_data->i2c_addr; + client = i2c_new_device(adapter, gsensor_i2c_bi); + if (client == NULL) { + printk("allocate i2c client failed\n"); + return -1; + } + i2c_put_adapter(adapter); + return 0; +} + +/* + * Get the configure of sensor from u-boot. + * Return: 0--success, other--error. + */ +int get_gsensor_conf(struct gsensor_conf *gs_conf) +{ + char varbuf[64]; + int n; + int varlen; + + memset(varbuf, 0, sizeof(varbuf)); + varlen = sizeof(varbuf); + if (wmt_getsyspara("wmt.io.gsensor", varbuf, &varlen)) { + printk("wmt.io.gsensor not defined!\n"); + return -1; + } else { + n = sscanf(varbuf, "%d:%d:%d:%d:%d:%d:%d:%d", + &gs_conf->op, + &gs_conf->samp, + &(gs_conf->xyz_axis[0][0]), + &(gs_conf->xyz_axis[0][1]), + &(gs_conf->xyz_axis[1][0]), + &(gs_conf->xyz_axis[1][1]), + &(gs_conf->xyz_axis[2][0]), + &(gs_conf->xyz_axis[2][1])); + printk(KERN_INFO "wmt.io.gsensor = %d:%d:%d:%d:%d:%d:%d:%d\n", + gs_conf->op, + gs_conf->samp, + gs_conf->xyz_axis[0][0], + gs_conf->xyz_axis[0][1], + gs_conf->xyz_axis[1][0], + gs_conf->xyz_axis[1][1], + gs_conf->xyz_axis[2][0], + gs_conf->xyz_axis[2][1]); + if (n != 8) { + printk("wmt.io.gsensor format is incorrect!\n"); + return -1; + } + + if (gs_conf->op <= 0) { + printk(KERN_INFO "wmt.io.gsensor is disabled\n"); + return -1; + } + } + return 0; +} + +static long gsensor_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + void __user *argp = (void __user *)arg; + int flag; + + if (!gs_data) + return -1; + + switch (cmd) { + case WMT_IOCTL_APP_SET_AFLAG: + if (copy_from_user(&flag, argp, sizeof(flag))) + return -EFAULT; + else { + if (flag < 0 || flag > 1) + return -EINVAL; + gs_data->enable(flag); + } + break; + case WMT_IOCTL_APP_GET_AFLAG: + if (copy_to_user(argp, &flag, sizeof(flag))) + return -EFAULT; + break; + case WMT_IOCTL_APP_SET_DELAY: + if (copy_from_user(&flag, argp, sizeof(flag))) + return -EFAULT; + else + gs_data->setDelay(flag); + + break; + case WMT_IOCTL_APP_GET_DELAY: + if (copy_to_user(argp, &flag, sizeof(flag))) + return -EFAULT; + break; + case WMT_IOCTL_APP_GET_LSG: + gs_data->getLSG(&flag); + if (copy_to_user(argp, &flag, sizeof(flag))) + return -EFAULT; + break; + default: + return -ENOTTY; + } + return 0; +} + +struct file_operations gsensor_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = gsensor_ioctl, +}; + +struct miscdevice gsensor_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "g-sensor", + .fops = &gsensor_fops, +}; + +int gsensor_register(struct gsensor_data *data) +{ + int err=-1; + + gs_data = data; + err = misc_register(&gsensor_device); + if (err) + printk(KERN_ERR "%s: gsensor misc register failed\n", __func__); + return err; +} + +EXPORT_SYMBOL_GPL(gsensor_i2c_register_device); +EXPORT_SYMBOL_GPL(get_gsensor_conf); +EXPORT_SYMBOL_GPL(gsensor_register); diff --git a/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/gsensor.h b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/gsensor.h new file mode 100755 index 00000000..db644d77 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/gsensor.h @@ -0,0 +1,43 @@ +/*++ +Copyright (c) 2012 WonderMedia Technologies, Inc. All Rights Reserved. +This PROPRIETARY SOFTWARE is the property of WonderMedia Technologies, Inc. +and may contain trade secrets and/or other confidential information of +WonderMedia Technologies, Inc. This file shall not be disclosed to any +third party, in whole or in part, without prior written consent of +WonderMedia. + +THIS PROPRIETARY SOFTWARE AND ANY RELATED DOCUMENTATION ARE PROVIDED +AS IS, WITH ALL FAULTS, AND WITHOUT WARRANTY OF ANY KIND EITHER EXPRESS +OR IMPLIED, AND WonderMedia TECHNOLOGIES, INC. DISCLAIMS ALL EXPRESS +OR IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, +QUIET ENJOYMENT OR NON-INFRINGEMENT. +--*/ + +#ifndef __GSENSOR_H__ +#define __GSENSOR_H__ + +#define IOCTL_WMT 0x01 +#define WMT_IOCTL_APP_SET_AFLAG _IOW(IOCTL_WMT, 0x01, int) +#define WMT_IOCTL_APP_SET_DELAY _IOW(IOCTL_WMT, 0x02, int) +#define WMT_IOCTL_APP_GET_AFLAG _IOW(IOCTL_WMT, 0x03, int) +#define WMT_IOCTL_APP_GET_DELAY _IOW(IOCTL_WMT, 0x04, int) +#define WMT_IOCTL_APP_GET_LSG _IOW(IOCTL_WMT, 0x05, int) + +struct gsensor_conf { + int op; + int samp; + int xyz_axis[3][2]; +}; + +struct gsensor_data { + int i2c_addr; + int (*enable) (int en); + int (*setDelay) (int mdelay); + int (*getLSG) (int *lsg); +}; + +extern int gsensor_i2c_register_device (void); +extern int get_gsensor_conf(struct gsensor_conf *gs_conf); +extern int gsensor_register(struct gsensor_data *gs_data); + +#endif \ No newline at end of file diff --git a/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/kxti9_gsensor/Makefile b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/kxti9_gsensor/Makefile new file mode 100755 index 00000000..3df5b74c --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/kxti9_gsensor/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for the KXTI9 Sensor driver +# + +sensor_kxti9-objs := kxti9.o +obj-$(CONFIG_WMT_SENSOR_KXTI9) += sensor_kxti9.o diff --git a/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/kxti9_gsensor/kxti9.c b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/kxti9_gsensor/kxti9.c new file mode 100755 index 00000000..c385842e --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/kxti9_gsensor/kxti9.c @@ -0,0 +1,1134 @@ +/* + * Copyright (C) 2009 Kionix, Inc. + * Written by Chris Hudson + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307, USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef KXTI9_INT_MODE +#include +#include +#include +#endif +#include +#include +#include +#include "kxti9.h" +#include "../gsensor.h" + +#define NAME "g-sensor" +#define G_MAX 2048 //8000 +/* OUTPUT REGISTERS */ +#define XOUT_L 0x06 +#define INT_SRC_REG1 0x15 +#define INT_STATUS_REG 0x16 +#define TILT_POS_CUR 0x10 +#define INT_REL 0x1A +#define WHO_AM_I 0x0F +/* CONTROL REGISTERS */ +#define DATA_CTRL 0x21 +#define CTRL_REG1 0x1B +#define INT_CTRL1 0x1E +#define CTRL_REG3 0x1D +#define TILT_TIMER 0x28 +#define WUF_TIMER 0x29 +#define WUF_THRESH 0x5A +#define TDT_TIMER 0x2B +/* CONTROL REGISTER 1 BITS */ +#define PC1_OFF 0x00 +#define PC1_ON 0x80 +/* INTERRUPT SOURCE 2 BITS */ +#define TPS 0x01 +#define TDTS0 0x04 +#define TDTS1 0x08 +/* INPUT_ABS CONSTANTS */ +#define FUZZ 0 //32 +#define FLAT 0 //32 +/* RESUME STATE INDICES */ +#define RES_DATA_CTRL 0 +#define RES_CTRL_REG1 1 +#define RES_INT_CTRL1 2 +#define RES_TILT_TIMER 3 +#define RES_CTRL_REG3 4 +#define RES_WUF_TIMER 5 +#define RES_WUF_THRESH 6 +#define RES_TDT_TIMER 7 +#define RES_TDT_H_THRESH 8 +#define RES_TDT_L_THRESH 9 +#define RES_TAP_TIMER 10 +#define RES_TOTAL_TIMER 11 +#define RES_LAT_TIMER 12 +#define RES_WIN_TIMER 13 +#define RESUME_ENTRIES 14 + +static struct gsensor_conf gs_conf; +static struct kxti9_data *gs_ti9; + +extern int gsensor_i2c_register_device (void); + +struct kxti9_platform_data kxti9_pdata = { + .min_interval = 1, + .poll_interval = 200,//1000, + + .g_range = KXTI9_G_2G, + .shift_adj = SHIFT_ADJ_2G, + + .axis_map_x = 0, + .axis_map_y = 1, + .axis_map_z = 2, + + .negate_x = 0, + .negate_y = 0, + .negate_z = 0, + + .data_odr_init = ODR12_5F, +#ifdef KXTI9_INT_MODE + .ctrl_reg1_init = KXTI9_G_8G | RES_12BIT | TDTE | WUFE | TPE, + .int_ctrl_init = KXTI9_IEN | KXTI9_IEA | KXTI9_IEL, +#else + .ctrl_reg1_init = KXTI9_G_2G | RES_12BIT, + .int_ctrl_init = 0, +#endif + .tilt_timer_init = 0x03, + .engine_odr_init = OTP12_5 | OWUF50 | OTDT400, + .wuf_timer_init = 0x16, + .wuf_thresh_init = 0x28, + .tdt_timer_init = 0x78, + .tdt_h_thresh_init = 0xFF, + .tdt_l_thresh_init = 0x14, + .tdt_tap_timer_init = 0x53, + .tdt_total_timer_init = 0x24, + .tdt_latency_timer_init = 0x10, + .tdt_window_timer_init = 0xA0, +}; + +/* + * The following table lists the maximum appropriate poll interval for each + * available output data rate. + */ +struct { + unsigned int cutoff; + u8 mask; +} kxti9_odr_table[] = { + { + 3, ODR800F}, { + 5, ODR400F}, { + 10, ODR200F}, { + 20, ODR100F}, { + 40, ODR50F}, { + 80, ODR25F}, { + 0, ODR12_5F}, +}; + +struct kxti9_data { + struct i2c_client *client; + struct kxti9_platform_data *pdata; + struct mutex lock; + struct delayed_work input_work; + struct input_dev *input_dev; +#ifdef KXTI9_INT_MODE + struct work_struct irq_work; +#endif + + int hw_initialized; + atomic_t enabled; + u8 resume[RESUME_ENTRIES]; + int res_interval; +#ifdef KXTI9_INT_MODE + int irq; +#endif +}; + +static int kxti9_i2c_read(struct kxti9_data *ti9, u8 addr, u8 *data, int len) +{ + int err; + + struct i2c_msg msgs[] = { + { + .addr = ti9->client->addr, + .flags = ti9->client->flags & I2C_M_TEN, + .len = 1, + .buf = &addr, + }, + { + .addr = ti9->client->addr, + .flags = (ti9->client->flags & I2C_M_TEN) | I2C_M_RD, + .len = len, + .buf = data, + }, + }; + err = i2c_transfer(ti9->client->adapter, msgs, 2); + + if (err != 2) + dev_err(&ti9->client->dev, "read transfer error\n"); + else + err = 0; + + return err; +} + +static int kxti9_i2c_write(struct kxti9_data *ti9, u8 addr, u8 *data, int len) +{ + int err; + int i; + u8 buf[len + 1]; + + struct i2c_msg msgs[] = { + { + .addr = ti9->client->addr, + .flags = ti9->client->flags & I2C_M_TEN, + .len = len + 1, + .buf = buf, + }, + }; + + buf[0] = addr; + for (i = 0; i < len; i++) { + buf[i + 1] = data[i]; + } + + err = i2c_transfer(ti9->client->adapter, msgs, 1); + + if (err != 1) + dev_err(&ti9->client->dev, "write transfer error\n"); + else + err = 0; + + return err; +} + +static int kxti9_verify(struct kxti9_data *ti9) +{ + int err; + u8 buf; + + err = kxti9_i2c_read(ti9, WHO_AM_I, &buf, 1); + /*** DEBUG OUTPUT - REMOVE ***/ + dev_info(&ti9->client->dev, "WHO_AM_I = 0x%02x\n", buf); + /*** DEBUG OUTPUT - REMOVE ***/ + if (err < 0) + dev_err(&ti9->client->dev, "read err int source\n"); + if (buf != 0x04 && buf != 0x08) // jakie add 0x8 for kxtj9 + err = -1; + return err; +} + +int kxti9_update_g_range(struct kxti9_data *ti9, u8 new_g_range) +{ + int err; + u8 shift; + u8 buf; + + switch (new_g_range) { + case KXTI9_G_2G: + shift = SHIFT_ADJ_2G; + break; + case KXTI9_G_4G: + shift = SHIFT_ADJ_4G; + break; + case KXTI9_G_8G: + shift = SHIFT_ADJ_8G; + break; + default: + dev_err(&ti9->client->dev, "invalid g range request\n"); + return -EINVAL; + } + if (shift != ti9->pdata->shift_adj) { + if (ti9->pdata->shift_adj > shift) + ti9->resume[RES_WUF_THRESH] >>= + (ti9->pdata->shift_adj - shift); + if (ti9->pdata->shift_adj < shift) + ti9->resume[RES_WUF_THRESH] <<= + (shift - ti9->pdata->shift_adj); + + if (atomic_read(&ti9->enabled)) { + buf = PC1_OFF; + err = kxti9_i2c_write(ti9, CTRL_REG1, &buf, 1); + if (err < 0) + return err; + buf = ti9->resume[RES_WUF_THRESH]; + err = kxti9_i2c_write(ti9, WUF_THRESH, &buf, 1); + if (err < 0) + return err; + buf = (ti9->resume[RES_CTRL_REG1] & 0xE7) | new_g_range; + err = kxti9_i2c_write(ti9, CTRL_REG1, &buf, 1); + if (err < 0) + return err; + ti9->resume[RES_CTRL_REG1] = buf; + ti9->pdata->shift_adj = shift; + } + } + return 0; +} + +int kxti9_update_odr(struct kxti9_data *ti9, int poll_interval) +{ + int err = -1; + int i; + u8 config; + + /* Convert the poll interval into an output data rate configuration + * that is as low as possible. The ordering of these checks must be + * maintained due to the cascading cut off values - poll intervals are + * checked from shortest to longest. At each check, if the next slower + * ODR cannot support the current poll interval, we stop searching */ + for (i = 0; i < ARRAY_SIZE(kxti9_odr_table); i++) { + config = kxti9_odr_table[i].mask; + if (poll_interval < kxti9_odr_table[i].cutoff) + break; + } + + if (atomic_read(&ti9->enabled)) { + err = kxti9_i2c_write(ti9, DATA_CTRL, &config, 1); + if (err < 0) + return err; + /* + * Latch on input_dev - indicates that kxti9_input_init passed + * and this workqueue is available + */ + if (ti9->input_dev) { + cancel_delayed_work_sync(&ti9->input_work); + schedule_delayed_work(&ti9->input_work, + msecs_to_jiffies(poll_interval)); + } + } + ti9->resume[RES_DATA_CTRL] = config; + + return 0; +} + +static int kxti9_hw_init(struct kxti9_data *ti9) +{ + int err = -1; + u8 buf[7]; + + buf[0] = PC1_OFF; + err = kxti9_i2c_write(ti9, CTRL_REG1, buf, 1); + if (err < 0) + return err; + err = kxti9_i2c_write(ti9, DATA_CTRL, &ti9->resume[RES_DATA_CTRL], 1); + if (err < 0) + return err; + err = kxti9_i2c_write(ti9, CTRL_REG3, &ti9->resume[RES_CTRL_REG3], 1); + if (err < 0) + return err; + err = kxti9_i2c_write(ti9, TILT_TIMER, &ti9->resume[RES_TILT_TIMER], 1); + if (err < 0) + return err; + err = kxti9_i2c_write(ti9, WUF_TIMER, &ti9->resume[RES_WUF_TIMER], 1); + if (err < 0) + return err; + err = kxti9_i2c_write(ti9, WUF_THRESH, &ti9->resume[RES_WUF_THRESH], 1); + if (err < 0) + return err; + buf[0] = ti9->resume[RES_TDT_TIMER]; + buf[1] = ti9->resume[RES_TDT_H_THRESH]; + buf[2] = ti9->resume[RES_TDT_L_THRESH]; + buf[3] = ti9->resume[RES_TAP_TIMER]; + buf[4] = ti9->resume[RES_TOTAL_TIMER]; + buf[5] = ti9->resume[RES_LAT_TIMER]; + buf[6] = ti9->resume[RES_WIN_TIMER]; + err = kxti9_i2c_write(ti9, TDT_TIMER, buf, 7); + if (err < 0) + return err; + err = kxti9_i2c_write(ti9, INT_CTRL1, &ti9->resume[RES_INT_CTRL1], 1); + if (err < 0) + return err; + buf[0] = (ti9->resume[RES_CTRL_REG1] | PC1_ON); + err = kxti9_i2c_write(ti9, CTRL_REG1, buf, 1); + if (err < 0) + return err; + ti9->resume[RES_CTRL_REG1] = buf[0]; + ti9->hw_initialized = 1; + + return 0; +} + +static void kxti9_device_power_off(struct kxti9_data *ti9) +{ + int err; + u8 buf = PC1_OFF; + + err = kxti9_i2c_write(ti9, CTRL_REG1, &buf, 1); + if (err < 0) + dev_err(&ti9->client->dev, "soft power off failed\n"); +#ifdef KXTI9_INT_MODE + disable_irq(ti9->irq); +#endif + if (ti9->pdata->power_off) + ti9->pdata->power_off(); + ti9->hw_initialized = 0; +} + +static int kxti9_device_power_on(struct kxti9_data *ti9) +{ + int err; + + if (ti9->pdata->power_on) { + err = ti9->pdata->power_on(); + if (err < 0) + return err; + } +#ifdef KXTI9_INT_MODE + enable_irq(ti9->irq); +#endif + if (!ti9->hw_initialized) { + msleep(100); + err = kxti9_hw_init(ti9); + if (err < 0) { + kxti9_device_power_off(ti9); + return err; + } + } + + return 0; +} + +#ifdef KXTI9_INT_MODE +static irqreturn_t kxti9_isr(int irq, void *dev) +{ + struct kxti9_data *ti9 = dev; + + disable_irq_nosync(irq); + schedule_work(&ti9->irq_work); + + return IRQ_HANDLED; +} +#endif + +static u8 kxti9_resolve_dir(struct kxti9_data *ti9, u8 dir) +{ + switch (dir) { + case 0x20: /* -X */ + if (ti9->pdata->negate_x) + dir = 0x10; + if (ti9->pdata->axis_map_y == 0) + dir >>= 2; + if (ti9->pdata->axis_map_z == 0) + dir >>= 4; + break; + case 0x10: /* +X */ + if (ti9->pdata->negate_x) + dir = 0x20; + if (ti9->pdata->axis_map_y == 0) + dir >>= 2; + if (ti9->pdata->axis_map_z == 0) + dir >>= 4; + break; + case 0x08: /* -Y */ + if (ti9->pdata->negate_y) + dir = 0x04; + if (ti9->pdata->axis_map_x == 1) + dir <<= 2; + if (ti9->pdata->axis_map_z == 1) + dir >>= 2; + break; + case 0x04: /* +Y */ + if (ti9->pdata->negate_y) + dir = 0x08; + if (ti9->pdata->axis_map_x == 1) + dir <<= 2; + if (ti9->pdata->axis_map_z == 1) + dir >>= 2; + break; + case 0x02: /* -Z */ + if (ti9->pdata->negate_z) + dir = 0x01; + if (ti9->pdata->axis_map_x == 2) + dir <<= 4; + if (ti9->pdata->axis_map_y == 2) + dir <<= 2; + break; + case 0x01: /* +Z */ + if (ti9->pdata->negate_z) + dir = 0x02; + if (ti9->pdata->axis_map_x == 2) + dir <<= 4; + if (ti9->pdata->axis_map_y == 2) + dir <<= 2; + break; + default: + return -EINVAL; + } + + return dir; +} + +static int kxti9_get_acceleration_data(struct kxti9_data *ti9, int *xyz) +{ + int err; + /* Data bytes from hardware xL, xH, yL, yH, zL, zH */ + u8 acc_data[6]; + /* x,y,z hardware values */ + int hw_d[3]; + + err = kxti9_i2c_read(ti9, XOUT_L, acc_data, 6); + if (err < 0) + return err; + + hw_d[0] = (int) (((acc_data[1]) << 8) | acc_data[0]); + hw_d[1] = (int) (((acc_data[3]) << 8) | acc_data[2]); + hw_d[2] = (int) (((acc_data[5]) << 8) | acc_data[4]); + + hw_d[0] = (hw_d[0] & 0x8000) ? ((hw_d[0] | 0xFFFF0000) + 1) : (hw_d[0]); + hw_d[1] = (hw_d[1] & 0x8000) ? ((hw_d[1] | 0xFFFF0000) + 1) : (hw_d[1]); + hw_d[2] = (hw_d[2] & 0x8000) ? ((hw_d[2] | 0xFFFF0000) + 1) : (hw_d[2]); + + hw_d[0] >>= 4; + hw_d[1] >>= 4; + hw_d[2] >>= 4; + + xyz[0] = ((ti9->pdata->negate_x) ? (-hw_d[ti9->pdata->axis_map_x]) + : (hw_d[ti9->pdata->axis_map_x])); + xyz[1] = ((ti9->pdata->negate_y) ? (-hw_d[ti9->pdata->axis_map_y]) + : (hw_d[ti9->pdata->axis_map_y])); + xyz[2] = ((ti9->pdata->negate_z) ? (-hw_d[ti9->pdata->axis_map_z]) + : (hw_d[ti9->pdata->axis_map_z])); + + /*** DEBUG OUTPUT - REMOVE ***/ + //dev_info(&ti9->client->dev, "x:%d y:%d z:%d\n", xyz[0], xyz[1], xyz[2]); + /*** DEBUG OUTPUT - REMOVE ***/ + + return err; +} + +static void kxti9_report_values(struct kxti9_data *ti9, int *xyz) +{ + input_report_abs(ti9->input_dev, ABS_X, xyz[gs_conf.xyz_axis[ABS_X][0]]*gs_conf.xyz_axis[ABS_X][1]); + input_report_abs(ti9->input_dev, ABS_Y, xyz[gs_conf.xyz_axis[ABS_Y][0]]*gs_conf.xyz_axis[ABS_Y][1]); + input_report_abs(ti9->input_dev, ABS_Z, xyz[gs_conf.xyz_axis[ABS_Z][0]]*gs_conf.xyz_axis[ABS_Z][1]); + input_sync(ti9->input_dev); +} + +#ifdef KXTI9_INT_MODE +static void kxti9_irq_work_func(struct work_struct *work) +{ +/* + * int_status output: + * [INT_SRC_REG2][INT_SRC_REG1][TILT_POS_PRE][TILT_POS_CUR] + * INT_SRC_REG1, TILT_POS_PRE, and TILT_POS_CUR directions are translated + * based on platform data variables. + */ + + int err; + int int_status = 0; + u8 status; + u8 buf[2]; + + struct kxti9_data *ti9 + = container_of(work, struct kxti9_data, irq_work); + + err = kxti9_i2c_read(ti9, INT_STATUS_REG, &status, 1); + if (err < 0) + dev_err(&ti9->client->dev, "read err int source\n"); + int_status = status << 24; + if ((status & TPS) > 0) { + err = kxti9_i2c_read(ti9, TILT_POS_CUR, buf, 2); + if (err < 0) + dev_err(&ti9->client->dev, "read err tilt dir\n"); + int_status |= kxti9_resolve_dir(ti9, buf[0]); + int_status |= kxti9_resolve_dir(ti9, buf[1]) << 8; + /*** DEBUG OUTPUT - REMOVE ***/ + dev_info(&ti9->client->dev, "IRQ TILT [%x]\n", + kxti9_resolve_dir(ti9, buf[0])); + /*** DEBUG OUTPUT - REMOVE ***/ + } + if (((status & TDTS0) | (status & TDTS1)) > 0) { + err = kxti9_i2c_read(ti9, INT_SRC_REG1, buf, 1); + if (err < 0) + dev_err(&ti9->client->dev, "read err tap dir\n"); + int_status |= (kxti9_resolve_dir(ti9, buf[0])) << 16; + /*** DEBUG OUTPUT - REMOVE ***/ + dev_info(&ti9->client->dev, "IRQ TAP%d [%x]\n", + ((status & TDTS1) ? (2) : (1)), kxti9_resolve_dir(ti9, buf[0])); + /*** DEBUG OUTPUT - REMOVE ***/ + } + /*** DEBUG OUTPUT - REMOVE ***/ + if ((status & 0x02) > 0) { + if (((status & TDTS0) | (status & TDTS1)) > 0) + dev_info(&ti9->client->dev, "IRQ WUF + TAP\n"); + else + dev_info(&ti9->client->dev, "IRQ WUF\n"); + } + /*** DEBUG OUTPUT - REMOVE ***/ + if (int_status & 0x2FFF) { + input_report_abs(ti9->input_dev, ABS_MISC, int_status); + input_sync(ti9->input_dev); + } + err = kxti9_i2c_read(ti9, INT_REL, buf, 1); + if (err < 0) + dev_err(&ti9->client->dev, + "error clearing interrupt status: %d\n", err); + + enable_irq(ti9->irq); +} +#endif + +static int kxti9_enable(struct kxti9_data *ti9) +{ + int err; + int int_status = 0; + u8 buf; + + if (!atomic_cmpxchg(&ti9->enabled, 0, 1)) { + err = kxti9_device_power_on(ti9); + err = kxti9_i2c_read(ti9, INT_REL, &buf, 1); + if (err < 0) { + dev_err(&ti9->client->dev, + "error clearing interrupt: %d\n", err); + atomic_set(&ti9->enabled, 0); + return err; + } + if ((ti9->resume[RES_CTRL_REG1] & TPE) > 0) { + err = kxti9_i2c_read(ti9, TILT_POS_CUR, &buf, 1); + if (err < 0) { + dev_err(&ti9->client->dev, + "read err current tilt\n"); + int_status |= kxti9_resolve_dir(ti9, buf); + input_report_abs(ti9->input_dev, ABS_MISC, int_status); + input_sync(ti9->input_dev); + } + } + schedule_delayed_work(&ti9->input_work, + msecs_to_jiffies(ti9->res_interval)); + } + + return 0; +} + +static int kxti9_disable(struct kxti9_data *ti9) +{ + if (atomic_cmpxchg(&ti9->enabled, 1, 0)) { + cancel_delayed_work_sync(&ti9->input_work); + kxti9_device_power_off(ti9); + } + + return 0; +} + +static void kxti9_input_work_func(struct work_struct *work) +{ + struct kxti9_data *ti9 = container_of((struct delayed_work *)work, + struct kxti9_data, input_work); + int xyz[3] = { 0 }; + + mutex_lock(&ti9->lock); + + if (kxti9_get_acceleration_data(ti9, xyz) == 0) + kxti9_report_values(ti9, xyz); + + schedule_delayed_work(&ti9->input_work, + msecs_to_jiffies(ti9->res_interval)); + + mutex_unlock(&ti9->lock); +} + +int kxti9_input_open(struct input_dev *input) +{ + struct kxti9_data *ti9 = input_get_drvdata(input); + + return kxti9_enable(ti9); +} + +void kxti9_input_close(struct input_dev *dev) +{ + struct kxti9_data *ti9 = input_get_drvdata(dev); + + kxti9_disable(ti9); +} + +static int kxti9_input_init(struct kxti9_data *ti9) +{ + int err; + + INIT_DELAYED_WORK(&ti9->input_work, kxti9_input_work_func); + ti9->input_dev = input_allocate_device(); + if (!ti9->input_dev) { + err = -ENOMEM; + dev_err(&ti9->client->dev, "input device allocate failed\n"); + goto err0; + } + //ti9->input_dev->open = kxti9_input_open; + //ti9->input_dev->close = kxti9_input_close; + + input_set_drvdata(ti9->input_dev, ti9); + + set_bit(EV_ABS, ti9->input_dev->evbit); + set_bit(ABS_MISC, ti9->input_dev->absbit); + + input_set_abs_params(ti9->input_dev, ABS_X, -G_MAX, G_MAX, FUZZ, FLAT); + input_set_abs_params(ti9->input_dev, ABS_Y, -G_MAX, G_MAX, FUZZ, FLAT); + input_set_abs_params(ti9->input_dev, ABS_Z, -G_MAX, G_MAX, FUZZ, FLAT); + + ti9->input_dev->name = "g-sensor"; + + err = input_register_device(ti9->input_dev); + if (err) { + dev_err(&ti9->client->dev, + "unable to register input polled device %s: %d\n", + ti9->input_dev->name, err); + goto err1; + } + + return 0; +err1: + input_free_device(ti9->input_dev); +err0: + return err; +} + +static void kxti9_input_cleanup(struct kxti9_data *ti9) +{ + input_unregister_device(ti9->input_dev); +} + +/* sysfs */ +static ssize_t kxti9_delay_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct kxti9_data *ti9 = i2c_get_clientdata(client); + return sprintf(buf, "%d\n", ti9->res_interval); +} + +static ssize_t kxti9_delay_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct kxti9_data *ti9 = i2c_get_clientdata(client); + int val = simple_strtoul(buf, NULL, 10); + + ti9->res_interval = max(val, ti9->pdata->min_interval); + kxti9_update_odr(ti9, ti9->res_interval); + + return count; +} + +static ssize_t kxti9_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct kxti9_data *ti9 = i2c_get_clientdata(client); + return sprintf(buf, "%d\n", atomic_read(&ti9->enabled)); +} + +static ssize_t kxti9_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct kxti9_data *ti9 = i2c_get_clientdata(client); + int val = simple_strtoul(buf, NULL, 10); + if (val) + kxti9_enable(ti9); + else + kxti9_disable(ti9); + return count; +} + +static ssize_t kxti9_tilt_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct kxti9_data *ti9 = i2c_get_clientdata(client); + u8 tilt; + + if (ti9->resume[RES_CTRL_REG1] & TPE) { + kxti9_i2c_read(ti9, TILT_POS_CUR, &tilt, 1); + return sprintf(buf, "%d\n", kxti9_resolve_dir(ti9, tilt)); + } else { + return sprintf(buf, "%d\n", 0); + } +} + +static ssize_t kxti9_tilt_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct kxti9_data *ti9 = i2c_get_clientdata(client); + int val = simple_strtoul(buf, NULL, 10); + if (val) + ti9->resume[RES_CTRL_REG1] |= TPE; + else + ti9->resume[RES_CTRL_REG1] &= (~TPE); + kxti9_i2c_write(ti9, CTRL_REG1, &ti9->resume[RES_CTRL_REG1], 1); + return count; +} + +static ssize_t kxti9_wake_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct kxti9_data *ti9 = i2c_get_clientdata(client); + u8 val = ti9->resume[RES_CTRL_REG1] & WUFE; + if (val) + return sprintf(buf, "%d\n", 1); + else + return sprintf(buf, "%d\n", 0); +} + +static ssize_t kxti9_wake_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct kxti9_data *ti9 = i2c_get_clientdata(client); + int val = simple_strtoul(buf, NULL, 10); + if (val) + ti9->resume[RES_CTRL_REG1] |= WUFE; + else + ti9->resume[RES_CTRL_REG1] &= (~WUFE); + kxti9_i2c_write(ti9, CTRL_REG1, &ti9->resume[RES_CTRL_REG1], 1); + return count; +} + +static ssize_t kxti9_tap_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct kxti9_data *ti9 = i2c_get_clientdata(client); + u8 val = ti9->resume[RES_CTRL_REG1] & TDTE; + if (val) + return sprintf(buf, "%d\n", 1); + else + return sprintf(buf, "%d\n", 0); +} + +static ssize_t kxti9_tap_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct kxti9_data *ti9 = i2c_get_clientdata(client); + int val = simple_strtoul(buf, NULL, 10); + if (val) + ti9->resume[RES_CTRL_REG1] |= TDTE; + else + ti9->resume[RES_CTRL_REG1] &= (~TDTE); + kxti9_i2c_write(ti9, CTRL_REG1, &ti9->resume[RES_CTRL_REG1], 1); + return count; +} + +static ssize_t kxti9_selftest_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct kxti9_data *ti9 = i2c_get_clientdata(client); + int val = simple_strtoul(buf, NULL, 10); + u8 ctrl = 0x00; + if (val) + ctrl = 0xCA; + kxti9_i2c_write(ti9, 0x3A, &ctrl, 1); + return count; +} + +static DEVICE_ATTR(delay, S_IRUGO|S_IWUSR, kxti9_delay_show, kxti9_delay_store); +static DEVICE_ATTR(enable, S_IRUGO|S_IWUSR, kxti9_enable_show, + kxti9_enable_store); +static DEVICE_ATTR(tilt, S_IRUGO|S_IWUSR, kxti9_tilt_show, kxti9_tilt_store); +static DEVICE_ATTR(wake, S_IRUGO|S_IWUSR, kxti9_wake_show, kxti9_wake_store); +static DEVICE_ATTR(tap, S_IRUGO|S_IWUSR, kxti9_tap_show, kxti9_tap_store); +static DEVICE_ATTR(selftest, S_IWUSR, NULL, kxti9_selftest_store); + +static struct attribute *kxti9_attributes[] = { + &dev_attr_delay.attr, + &dev_attr_enable.attr, + &dev_attr_tilt.attr, + &dev_attr_wake.attr, + &dev_attr_tap.attr, + &dev_attr_selftest.attr, + NULL +}; + +static struct attribute_group kxti9_attribute_group = { + .attrs = kxti9_attributes +}; +/* /sysfs */ +static int __devinit kxti9_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int err = -1; + struct kxti9_data *ti9 = kzalloc(sizeof(*ti9), GFP_KERNEL); + gs_ti9 = ti9; + if (ti9 == NULL) { + dev_err(&client->dev, + "failed to allocate memory for module data\n"); + err = -ENOMEM; + goto err0; + } + /* + if (client->dev.platform_data == NULL) { + dev_err(&client->dev, "platform data is NULL; exiting\n"); + err = -ENODEV; + goto err0; + } + */ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, "client not i2c capable\n"); + err = -ENODEV; + goto err0; + } + mutex_init(&ti9->lock); + mutex_lock(&ti9->lock); + ti9->client = client; + i2c_set_clientdata(client, ti9); + +#ifdef KXTI9_INT_MODE + INIT_WORK(&ti9->irq_work, kxti9_irq_work_func); +#endif + ti9->pdata = kmalloc(sizeof(*ti9->pdata), GFP_KERNEL); + if (ti9->pdata == NULL) + goto err1; + + err = sysfs_create_group(&client->dev.kobj, &kxti9_attribute_group); + if (err) + goto err1; + + //memcpy(ti9->pdata, client->dev.platform_data, sizeof(*ti9->pdata)); + memcpy(ti9->pdata, &kxti9_pdata, sizeof(*ti9->pdata)); + + if (ti9->pdata->init) { + err = ti9->pdata->init(); + if (err < 0) + goto err2; + } + +#ifdef KXTI9_INT_MODE + ti9->irq = gpio_to_irq(ti9->pdata->gpio); +#endif + + memset(ti9->resume, 0, ARRAY_SIZE(ti9->resume)); + ti9->resume[RES_DATA_CTRL] = ti9->pdata->data_odr_init; + ti9->resume[RES_CTRL_REG1] = ti9->pdata->ctrl_reg1_init; + ti9->resume[RES_INT_CTRL1] = ti9->pdata->int_ctrl_init; + ti9->resume[RES_TILT_TIMER] = ti9->pdata->tilt_timer_init; + ti9->resume[RES_CTRL_REG3] = ti9->pdata->engine_odr_init; + ti9->resume[RES_WUF_TIMER] = ti9->pdata->wuf_timer_init; + ti9->resume[RES_WUF_THRESH] = ti9->pdata->wuf_thresh_init; + ti9->resume[RES_TDT_TIMER] = ti9->pdata->tdt_timer_init; + ti9->resume[RES_TDT_H_THRESH] = ti9->pdata->tdt_h_thresh_init; + ti9->resume[RES_TDT_L_THRESH] = ti9->pdata->tdt_l_thresh_init; + ti9->resume[RES_TAP_TIMER] = ti9->pdata->tdt_tap_timer_init; + ti9->resume[RES_TOTAL_TIMER] = ti9->pdata->tdt_total_timer_init; + ti9->resume[RES_LAT_TIMER] = ti9->pdata->tdt_latency_timer_init; + ti9->resume[RES_WIN_TIMER] = ti9->pdata->tdt_window_timer_init; + ti9->res_interval = ti9->pdata->poll_interval; + + err = kxti9_device_power_on(ti9); + if (err < 0) + goto err3; + atomic_set(&ti9->enabled, 1); + + err = kxti9_verify(ti9); + if (err < 0) { + dev_err(&client->dev, "unresolved i2c client\n"); + goto err4; + } + + err = kxti9_update_g_range(ti9, ti9->pdata->g_range); + if (err < 0) + goto err4; + + err = kxti9_update_odr(ti9, ti9->res_interval); + if (err < 0) + goto err4; + + err = kxti9_input_init(ti9); + if (err < 0) + goto err4; + + kxti9_device_power_off(ti9); + atomic_set(&ti9->enabled, 0); + +#ifdef KXTI9_INT_MODE + err = request_irq(ti9->irq, kxti9_isr, + IRQF_TRIGGER_RISING | IRQF_DISABLED, "kxti9-irq", ti9); + if (err < 0) { + pr_err("%s: request irq failed: %d\n", __func__, err); + goto err5; + } + disable_irq_nosync(ti9->irq); +#endif + + mutex_unlock(&ti9->lock); + + return 0; + +#ifdef KXTI9_INT_MODE +err5: +#endif + kxti9_input_cleanup(ti9); +err4: + kxti9_device_power_off(ti9); +err3: + if (ti9->pdata->exit) + ti9->pdata->exit(); +err2: + kfree(ti9->pdata); + sysfs_remove_group(&client->dev.kobj, &kxti9_attribute_group); +err1: + mutex_unlock(&ti9->lock); + kfree(ti9); +err0: + return err; +} + +static int __devexit kxti9_remove(struct i2c_client *client) +{ + struct kxti9_data *ti9 = i2c_get_clientdata(client); + +#ifdef KXTI9_INT_MODE + free_irq(ti9->irq, ti9); + gpio_free(ti9->pdata->gpio); +#endif + kxti9_input_cleanup(ti9); + kxti9_device_power_off(ti9); + if (ti9->pdata->exit) + ti9->pdata->exit(); + kfree(ti9->pdata); + sysfs_remove_group(&client->dev.kobj, &kxti9_attribute_group); + kfree(ti9); + + return 0; +} + +#ifdef CONFIG_PM +static int kxti9_resume(struct i2c_client *client) +{ + //struct kxti9_data *ti9 = i2c_get_clientdata(client); + //return kxti9_enable(ti9); + return 0; +} + +static int kxti9_suspend(struct i2c_client *client, pm_message_t mesg) +{ + //struct kxti9_data *ti9 = i2c_get_clientdata(client); + //return kxti9_disable(ti9); + return 0; +} + +static void kxti9_shutdown(struct i2c_client *client) +{ + struct kxti9_data *ti9 = i2c_get_clientdata(client); + if (atomic_read(&ti9->enabled)) { + flush_delayed_work_sync(&ti9->input_work); + cancel_delayed_work_sync(&ti9->input_work); + } +} +#endif + +static const struct i2c_device_id kxti9_id[] = { + {NAME, 0}, + {}, +}; + +MODULE_DEVICE_TABLE(i2c, kxti9_id); + +static struct i2c_driver kxti9_driver = { + .driver = { + .name = NAME, + }, + .probe = kxti9_probe, + .remove = __devexit_p(kxti9_remove), + .resume = kxti9_resume, + .suspend = kxti9_suspend, + .shutdown = kxti9_shutdown, + .id_table = kxti9_id, +}; + +int kxti9_enable_accel(int en) +{ + printk(KERN_DEBUG "%s: enable = %d\n", __func__, en); + if (en) + kxti9_enable(gs_ti9); + else + kxti9_disable(gs_ti9); + return 0; +} + +int kxti9_setDelay(int mdelay) +{ + printk(KERN_DEBUG "%s: delay = %d\n", __func__, mdelay); + gs_ti9->res_interval = mdelay; + return kxti9_update_odr(gs_ti9, gs_ti9->res_interval); +} + +int kxti9_getLSG(int *lsg) +{ + int max_count; + if (gs_ti9->resume[RES_CTRL_REG1] & RES_12BIT) + max_count = 2048; + else + max_count = 128; + + if ((gs_ti9->resume[RES_CTRL_REG1] & 0x18) == KXTI9_G_2G) + *lsg = max_count >> 1; + else if ((gs_ti9->resume[RES_CTRL_REG1] & 0x18) == KXTI9_G_4G) + *lsg = max_count >> 2; + else if ((gs_ti9->resume[RES_CTRL_REG1] & 0x18) == KXTI9_G_8G) + *lsg = max_count >> 3; + + printk(KERN_DEBUG "%s: LSG = %d\n", __func__, *lsg); + return 0; +} + +struct gsensor_data kxti9_gs_data = { + .i2c_addr = KXTI9_I2C_ADDR, + .enable = kxti9_enable_accel, + .setDelay = kxti9_setDelay, + .getLSG = kxti9_getLSG, +}; + +static int __init kxti9_init(void) +{ + if (get_gsensor_conf(&gs_conf)) + return -1; + + if (gs_conf.op != 2) + return -1; + + printk("G-Sensor kxti9 init\n"); + + if (gsensor_register(&kxti9_gs_data)) + return -1; + + if (gsensor_i2c_register_device() < 0) + return -1; + + return i2c_add_driver(&kxti9_driver); +} + +static void __exit kxti9_exit(void) +{ + i2c_del_driver(&kxti9_driver); +} + +module_init(kxti9_init); +module_exit(kxti9_exit); + +MODULE_DESCRIPTION("KXTI9 accelerometer driver"); +MODULE_AUTHOR("Chris Hudson "); +MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/kxti9_gsensor/kxti9.h b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/kxti9_gsensor/kxti9.h new file mode 100755 index 00000000..c66c740a --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/kxti9_gsensor/kxti9.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2009, Kionix, Inc. All Rights Reserved. + * Written by Chris Hudson + * + * 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 3 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 . + * + */ + +#ifndef __KXTI9_H__ +#define __KXTI9_H__ + +#define KXTI9_I2C_ADDR 0x0F +/* CONTROL REGISTER 1 BITS */ +#define RES_12BIT 0x40 +#define KXTI9_G_2G 0x00 +#define KXTI9_G_4G 0x08 +#define KXTI9_G_8G 0x10 +#define SHIFT_ADJ_2G 4 +#define SHIFT_ADJ_4G 3 +#define SHIFT_ADJ_8G 2 +#define TPE 0x01 /* tilt position function enable bit */ +#define WUFE 0x02 /* wake-up function enable bit */ +#define TDTE 0x04 /* tap/double-tap function enable bit */ +/* CONTROL REGISTER 3 BITS */ +#define OTP1_6 0x00 /* tilt ODR masks */ +#define OTP6_3 0x20 +#define OTP12_5 0x40 +#define OTP50 0x60 +#define OWUF25 0x00 /* wuf ODR masks */ +#define OWUF50 0x01 +#define OWUF100 0x02 +#define OWUF200 0x03 +#define OTDT50 0x00 /* tdt ODR masks */ +#define OTDT100 0x04 +#define OTDT200 0x08 +#define OTDT400 0x0C +/* INTERRUPT CONTROL REGISTER 1 BITS */ +#define KXTI9_IEN 0x20 /* interrupt enable */ +#define KXTI9_IEA 0x10 /* interrupt polarity */ +#define KXTI9_IEL 0x08 /* interrupt response */ +#define IEU 0x04 /* alternate unlatched response */ +/* DATA CONTROL REGISTER BITS */ +#define ODR800F 0x06 /* lpf output ODR masks */ +#define ODR400F 0x05 +#define ODR200F 0x04 +#define ODR100F 0x03 +#define ODR50F 0x02 +#define ODR25F 0x01 +#define ODR12_5F 0x00 + +#ifdef __KERNEL__ +struct kxti9_platform_data { + int poll_interval; + int min_interval; + + u8 g_range; + u8 shift_adj; + + u8 axis_map_x; + u8 axis_map_y; + u8 axis_map_z; + + u8 negate_x; + u8 negate_y; + u8 negate_z; + + u8 data_odr_init; + u8 ctrl_reg1_init; + u8 int_ctrl_init; + u8 tilt_timer_init; + u8 engine_odr_init; + u8 wuf_timer_init; + u8 wuf_thresh_init; + u8 tdt_timer_init; + u8 tdt_h_thresh_init; + u8 tdt_l_thresh_init; + u8 tdt_tap_timer_init; + u8 tdt_total_timer_init; + u8 tdt_latency_timer_init; + u8 tdt_window_timer_init; + + int (*init)(void); + void (*exit)(void); + int (*power_on)(void); + int (*power_off)(void); + + int gpio; +}; +#endif /* __KERNEL__ */ + +#endif /* __KXTI9_H__ */ + diff --git a/ANDROID_3.4.5/drivers/input/sensor/cm3232/Makefile b/ANDROID_3.4.5/drivers/input/sensor/cm3232/Makefile new file mode 100755 index 00000000..06c28edd --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/cm3232/Makefile @@ -0,0 +1,34 @@ +KERNELDIR=../../../../ +#KERNELDIR=/home/hangyan/android8850/kernel/ANDROID_3.0.8 +CROSS = arm_1103_le- +CC= $(CROSS)gcc +LD= $(CROSS)ld +STRIP = $(CROSS)strip + +DEBUG = n + +# Add your debugging flag (or not) to EXTRA_CFLAGS +ifeq ($(DEBUG),y) +# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines +DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines + +else + DEBFLAGS = -O2 -Wall +endif + +EXTRA_CFLAGS += $(DEBFLAGS) + + +MY_MODULE_NAME=s_wmt_lsensor_cm3232 + +obj-m := $(MY_MODULE_NAME).o +$(MY_MODULE_NAME)-objs := cm3232.o + +default: + $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules + $(STRIP) --strip-debug $(MY_MODULE_NAME).ko + rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions + +clean: + rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers + diff --git a/ANDROID_3.4.5/drivers/input/sensor/cm3232/cm3232.c b/ANDROID_3.4.5/drivers/input/sensor/cm3232/cm3232.c new file mode 100755 index 00000000..207ddd3a --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/cm3232/cm3232.c @@ -0,0 +1,855 @@ +/* + * cm3232.c - Intersil cm3232 ALS & Proximity Driver + * + * By Intersil Corp + * Michael DiGioia + * + * Based on isl29011.c + * by Mike DiGioia + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +//#include + +#include "../sensor.h" + +/* Insmod parameters */ +//I2C_CLIENT_INSMOD_1(cm3232); +#define SENSOR_I2C_NAME "cm3232" +#define SENSOR_I2C_ADDR 0x10 +#define MODULE_NAME "cm3232" + +#define REG_CMD_1 0x00 +#define REG_CMD_2 0x01 +#define REG_DATA_LSB 0x02 +#define REG_DATA_MSB 0x03 +#define ISL_MOD_MASK 0xE0 +#define ISL_MOD_POWERDOWN 0 +#define ISL_MOD_ALS_ONCE 1 +#define ISL_MOD_IR_ONCE 2 +#define ISL_MOD_RESERVED 4 +#define ISL_MOD_ALS_CONT 5 +#define ISL_MOD_IR_CONT 6 +#define IR_CURRENT_MASK 0xC0 +#define IR_FREQ_MASK 0x30 +#define SENSOR_RANGE_MASK 0x03 +#define ISL_RES_MASK 0x0C + + +#undef dbg +#define dbg(fmt, args...) //printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__ , ## args) + +#undef errlog +#undef klog +#define errlog(fmt, args...) printk(KERN_ERR "[%s]: " fmt, __FUNCTION__, ## args) +#define klog(fmt, args...) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__, ## args) + +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); +static int no_adc_map = 1; +static int last_mod; + +static struct i2c_client *this_client = NULL; + +struct isl_device { + struct input_polled_dev* input_poll_dev; + struct i2c_client* client; + int resolution; + int range; + int isdbg; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend earlysuspend; +#endif + +}; + +static struct isl_device* l_sensorconfig = NULL; +static struct kobject *android_lsensor_kobj = NULL; +static int l_enable = 0; // 0:don't report data, 1 + +static DEFINE_MUTEX(mutex); + +#if 0 +static int isl_set_mod(struct i2c_client *client, int mod) +{ + int ret, val, freq; + + switch (mod) { + case ISL_MOD_POWERDOWN: + case ISL_MOD_RESERVED: + goto setmod; + case ISL_MOD_ALS_ONCE: + case ISL_MOD_ALS_CONT: + freq = 0; + break; + case ISL_MOD_IR_ONCE: + case ISL_MOD_IR_CONT: + freq = 1; + break; + default: + return -EINVAL; + } + /* set IR frequency */ + val = i2c_smbus_read_byte_data(client, REG_CMD_2); + if (val < 0) + return -EINVAL; + val &= ~IR_FREQ_MASK; + if (freq) + val |= IR_FREQ_MASK; + ret = i2c_smbus_write_byte_data(client, REG_CMD_2, val); + if (ret < 0) + return -EINVAL; + +setmod: + /* set operation mod */ + val = i2c_smbus_read_byte_data(client, REG_CMD_1); + if (val < 0) + return -EINVAL; + val &= ~ISL_MOD_MASK; + val |= (mod << 5); + ret = i2c_smbus_write_byte_data(client, REG_CMD_1, val); + if (ret < 0) + return -EINVAL; + + if (mod != ISL_MOD_POWERDOWN) + last_mod = mod; + + return mod; +} + +static int isl_get_res(struct i2c_client *client) +{ + int val; + + printk(KERN_INFO MODULE_NAME ": %s cm3232 get_res call, \n", __func__); + val = i2c_smbus_read_word_data(client, 0)>>8 & 0xff; + + if (val < 0) + return -EINVAL; + + val &= ISL_RES_MASK; + val >>= 2; + + switch (val) { + case 0: + return 65536; + case 1: + return 4096; + case 2: + return 256; + case 3: + return 16; + default: + return -EINVAL; + } +} + +static int isl_get_range(struct i2c_client* client) +{ + switch (i2c_smbus_read_word_data(client, 0)>>8 & 0xff & 0x3) { + case 0: return 1000; + case 1: return 4000; + case 2: return 16000; + case 3: return 64000; + default: return -EINVAL; + } +} +#endif +//Fixme plan to transfer the adc value to the config.xml lux 2013-5-10 +static __u16 uadc[8] = {2, 8, 100, 400, 900, 1000, 1500, 1900};//customize +static __u16 ulux[9] = {128, 200, 1300, 2000, 3000, 4000, 5000, 6000, 7000}; +static __u16 adc_to_lux(__u16 adc) +{ + static long long var = 0; + int i = 0; //length of array is 8,9 + for (i=0; i<8; i++) { + if ( adc < uadc[i]){ + break; + } + } + if ( i<9) + { + var++; + if (var%2) + return ulux[i]+0; + else + return ulux[i]+1; + } + return ulux[4]; +} + + + +static int isl_get_lux_data(struct i2c_client* client) +{ + //struct isl_device* idev = i2c_get_clientdata(client); + + //__u16 resH = 0, resL = 0; + __s16 resH = 0, resL = 0; + //int range; + resL = i2c_smbus_read_word_data(client, 0x50); + //resH = i2c_smbus_read_word_data(client, 0x51)&0xff00; + if ((resL < 0) || (resH < 0)) + { + errlog("Error to read lux_data!\n"); + + return 3000;//??? + //return -1; + } + //Fixme plan to transfer the adc value to the config.xml lux 2013-5-10 + if (!no_adc_map) + resL = adc_to_lux(resL); + //printk("<<<< lux %d\n", resL); + return resL ;//* idev->range / idev->resolution; + return (resH | resL) ;//* idev->range / idev->resolution; +} + + +static int isl_set_default_config(struct i2c_client *client) +{ + //struct isl_device* idev = i2c_get_clientdata(client); + + int ret=0; + //ret = _cm3232_I2C_Write_Byte(CM3232_SLAVE_addr, CM3232_ALS_RESET); + ret = i2c_smbus_write_byte_data(client, 0, (1 << 6)); + if (ret < 0) + return -EINVAL; + //if(ret<0) + //return ret; + msleep(10); + + //ret = _cm3232_I2C_Write_Byte(CM3232_SLAVE_addr, CM3232_ALS_IT_200ms | CM3232_ALS_HS_HIGH ); + ret = i2c_smbus_write_byte_data(client, 0, (1 << 2)|(1 << 1)); + if (ret < 0) + return -EINVAL; + msleep(10); + return 0; +/* We don't know what it does ... */ +// ret = i2c_smbus_write_byte_data(client, REG_CMD_1, 0xE0); +// ret = i2c_smbus_write_byte_data(client, REG_CMD_2, 0xC3); +/* Set default to ALS continuous */ + ret = i2c_smbus_write_byte_data(client, REG_CMD_1, 0xA0); + if (ret < 0) + return -EINVAL; +/* Range: 0~16000, number of clock cycles: 65536 */ + ret = i2c_smbus_write_byte_data(client, REG_CMD_2, 0x02); // vivienne + if (ret < 0) + return -EINVAL; + //idev->resolution = isl_get_res(client); + //idev->range = isl_get_range(client);; + dbg("cm3232 set_default_config call, \n"); + + return 0; +} + +/* Return 0 if detection is successful, -ENODEV otherwise */ +static int cm3232_detect(struct i2c_client *client/*, int kind, + struct i2c_board_info *info*/) +{ + + + return 0; +} + +int isl_input_open(struct input_dev* input) +{ + return 0; +} + +void isl_input_close(struct input_dev* input) +{ +} + +static void isl_input_lux_poll(struct input_polled_dev *dev) +{ + struct isl_device* idev = dev->private; + struct input_dev* input = idev->input_poll_dev->input; + struct i2c_client* client = idev->client; + static unsigned int val=0; + + //printk("%s\n", __FUNCTION__); + if (l_enable != 0) + { + mutex_lock(&mutex); + //pm_runtime_get_sync(dev); + #if 0 + if(val>0x2000) + val=0; + val+=100; + #endif + //printk(KERN_ALERT "by flashchen val is %x",val); + input_report_abs(input, ABS_MISC, isl_get_lux_data(client)); + //input_report_abs(input, ABS_MISC, val);//isl_get_lux_data(client)); + input_sync(input); + //pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + } +} + +static struct i2c_device_id cm3232_id[] = { + {"cm3232", 0}, + {} +}; + +#if 0 +static int cm3232_runtime_suspend(struct device *dev) +{ + + dev_dbg(dev, "suspend\n"); + + mutex_lock(&mutex); + pm_runtime_get_sync(dev); + //isl_set_mod(client, ISL_MOD_POWERDOWN); + pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + + printk(KERN_INFO MODULE_NAME ": %s cm3232 suspend call, \n", __func__); + return 0; +} + +static int cm3232_runtime_resume(struct device *dev) +{ + + dev_dbg(dev, "resume\n"); + + mutex_lock(&mutex); + pm_runtime_get_sync(dev); + //isl_set_mod(client, last_mod); + pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + + printk(KERN_INFO MODULE_NAME ": %s cm3232 resume call, \n", __func__); + return 0; +} +#endif +MODULE_DEVICE_TABLE(i2c, cm3232_id); + +/*static const struct dev_pm_ops cm3232_pm_ops = { + .runtime_suspend = cm3232_runtime_suspend, + .runtime_resume = cm3232_runtime_resume, +}; + +static struct i2c_board_info isl_info = { + I2C_BOARD_INFO("cm3232", 0x44), +}; + +static struct i2c_driver cm3232_driver = { + .driver = { + .name = "cm3232", + .pm = &cm3232_pm_ops, + }, + .probe = cm3232_probe, + .remove = cm3232_remove, + .id_table = cm3232_id, + .detect = cm3232_detect, + //.address_data = &addr_data, +};*/ + +static int mmad_open(struct inode *inode, struct file *file) +{ + dbg("Open the l-sensor node...\n"); + return 0; +} + +static int mmad_release(struct inode *inode, struct file *file) +{ + dbg("Close the l-sensor node...\n"); + return 0; +} + +static ssize_t mmad_read(struct file *fl, char __user *buf, size_t cnt, loff_t *lf) +{ + int lux_data = 0; + + mutex_lock(&mutex); + lux_data = isl_get_lux_data(l_sensorconfig->client); + mutex_unlock(&mutex); + if (lux_data < 0) + { + errlog("Failed to read lux data!\n"); + return -1; + } + printk(KERN_ALERT "lux_data is %x\n",lux_data); + //return 0; + copy_to_user(buf, &lux_data, sizeof(lux_data)); + return sizeof(lux_data); +} + +static long +mmad_ioctl(/*struct inode *inode,*/ struct file *file, unsigned int cmd, + unsigned long arg) +{ + void __user *argp = (void __user *)arg; + //char rwbuf[5]; + short enable; //amsr = -1; + unsigned int uval; + + dbg("l-sensor ioctr...\n"); + //memset(rwbuf, 0, sizeof(rwbuf)); + switch (cmd) { + case LIGHT_IOCTL_SET_ENABLE: + // enable/disable sensor + if (copy_from_user(&enable, argp, sizeof(short))) + { + printk(KERN_ERR "Can't get enable flag!!!\n"); + return -EFAULT; + } + dbg("enable=%d\n",enable); + if ((enable >=0) && (enable <=1)) + { + dbg("driver: disable/enable(%d) gsensor.\n", enable); + + //l_sensorconfig.sensor_enable = enable; + dbg("Should to implement d/e the light sensor!\n"); + l_enable = enable; + + } else { + printk(KERN_ERR "Wrong enable argument in %s !!!\n", __FUNCTION__); + return -EINVAL; + } + break; + case WMT_IOCTL_SENSOR_GET_DRVID: +#define CM3232_DRVID 0 + uval = CM3232_DRVID ; + if (copy_to_user((unsigned int*)arg, &uval, sizeof(unsigned int))) + { + return -EFAULT; + } + dbg("cm3232_driver_id:%d\n",uval); + default: + break; + } + + return 0; +} + + +static struct file_operations mmad_fops = { + .owner = THIS_MODULE, + .open = mmad_open, + .release = mmad_release, + .read = mmad_read, + .unlocked_ioctl = mmad_ioctl, +}; + + +static struct miscdevice mmad_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "lsensor_ctrl", + .fops = &mmad_fops, +}; + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void cm3232_early_suspend(struct early_suspend *h) +{ + struct i2c_client *client = l_sensorconfig->client; + + dbg("start\n"); + mutex_lock(&mutex); + //pm_runtime_get_sync(dev); + //isl_set_mod(client, ISL_MOD_POWERDOWN); + //pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + dbg("exit\n"); +} + +static void cm3232_late_resume(struct early_suspend *h) +{ + struct i2c_client *client = l_sensorconfig->client; + + dbg("start\n"); + mutex_lock(&mutex); + //pm_runtime_get_sync(dev); + //isl_set_mod(client, last_mod); + isl_set_default_config(client); + //pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + dbg("exit\n"); +} +#endif +static ssize_t adc_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + + int i; + int size = sizeof(uadc)/sizeof(uadc[0]); + printk("<<<%s\n", __FUNCTION__); + for (i=0; i>>\n", buf); + n = sscanf(buf, "%d:%d", &index, &tmp); + printk("<<<=0 && index=0; i--) + device_remove_file(dev, &attr[i]);//&attr[i].attr + } + return err; +} + +static void device_remove_attribute(struct device *dev, struct device_attribute *attr) +{ + int i; + for (i=0; attr[i].attr.name != NULL; i++) + device_remove_file(dev, &attr[i]); //&attr[i].attr +} + + +static int get_adc_val(void) +{ + int i, varlen, n; + __u32 buf[8]; + char varbuf[50]; + char *name = "wmt.io.lsensor"; + + varlen = sizeof(varbuf); + if (wmt_getsyspara(name, varbuf, &varlen)) + { + printk("<<<dev); + idev->input_poll_dev = input_allocate_polled_device(); + if(!idev->input_poll_dev) + { + res = -ENOMEM; + goto err_input_allocate_device; + } + idev->client = client; + idev->input_poll_dev->private = idev; + idev->input_poll_dev->poll = isl_input_lux_poll; + idev->input_poll_dev->poll_interval = 100;//50; + idev->input_poll_dev->input->open = isl_input_open; + idev->input_poll_dev->input->close = isl_input_close; + idev->input_poll_dev->input->name = "lsensor_lux"; + idev->input_poll_dev->input->id.bustype = BUS_I2C; + idev->input_poll_dev->input->dev.parent = &client->dev; + input_set_drvdata(idev->input_poll_dev->input, idev); + input_set_capability(idev->input_poll_dev->input, EV_ABS, ABS_MISC); + input_set_abs_params(idev->input_poll_dev->input, ABS_MISC, 0, 16000, 0, 0); + i2c_set_clientdata(client, idev); + /* set default config after set_clientdata */ + res = isl_set_default_config(client); + res = misc_register(&mmad_device); + if (res) { + errlog("mmad_device register failed\n"); + goto err_misc_register; + } + res = input_register_polled_device(idev->input_poll_dev); + if(res < 0) + goto err_input_register_device; + // suspend/resume register +#ifdef CONFIG_HAS_EARLYSUSPEND + idev->earlysuspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + idev->earlysuspend.suspend = cm3232_early_suspend; + idev->earlysuspend.resume = cm3232_late_resume; + register_early_suspend(&(idev->earlysuspend)); +#endif + + dbg("cm3232 probe succeed!\n"); + //create class device sysdevice 2013-5-10 + //get_adc_val(); + sclass = class_create(THIS_MODULE, "cm3232"); + if (IS_ERR(sclass)) + { + printk("<<<%s fail to create class!\n", __FUNCTION__); + return 0; + } + + + sret = alloc_chrdev_region(&sdev_no, 0, 1, "cm3232_devno"); + if (sret) + { + printk("<<<<%s alloc_chrdev_region fail!\n", __FUNCTION__); + class_destroy(sclass); + return 0; + } + sdevice = device_create(sclass, NULL, sdev_no, NULL, "cm3232_dev"); + if (IS_ERR(sdevice)) + { + printk("<<<%s device_create fail!\n", __FUNCTION__); + class_destroy(sclass); + return 0; + } + device_create_attribute(sdevice, cm3232_attr); + + return 0; +err_input_register_device: + misc_deregister(&mmad_device); + input_free_polled_device(idev->input_poll_dev); +err_misc_register: +err_input_allocate_device: + //__pm_runtime_disable(&client->dev, false); + + kobject_del(android_lsensor_kobj); + + kfree(idev); + return res; +} + +static int cm3232_remove(struct i2c_client *client) +{ + struct isl_device* idev = i2c_get_clientdata(client); + if (!IS_ERR(sdevice)) + { + device_remove_attribute(sdevice, cm3232_attr); + device_destroy(sclass, sdev_no); + class_destroy(sclass); + + } + //unregister_early_suspend(&(idev->earlysuspend)); + misc_deregister(&mmad_device); + input_unregister_polled_device(idev->input_poll_dev); + input_free_polled_device(idev->input_poll_dev); + //sysfs_remove_group(android_lsensor_kobj, &m_isl_gr); + kobject_del(android_lsensor_kobj); + //__pm_runtime_disable(&client->dev, false); + kfree(idev); + printk(KERN_INFO MODULE_NAME ": %s cm3232 remove call, \n", __func__); + return 0; +} +//****************add platform_device & platform_driver for suspend &resume 2013-7-2 +static int ls_probe(struct platform_device *pdev){ + //printk("<<<%s\n", __FUNCTION__); + return 0; +} +static int ls_remove(struct platform_device *pdev){ + //printk("<<<%s\n", __FUNCTION__); + return 0; +} +static int ls_suspend(struct platform_device *pdev, pm_message_t state){ + printk("<<<%s\n", __FUNCTION__); + + return 0; +} + +static int ls_resume(struct platform_device *pdev){ + //return 0; + int ret = 0; + int count = 0; + printk("<<<%s\n", __FUNCTION__); +RETRY: + ret = isl_set_default_config(this_client); + if (ret < 0){ + printk("%s isl_set_default_config fail!\n", __FUNCTION__); + count++; + if (count < 5){ + mdelay(2); + goto RETRY; + } + else + return ret; + } + return 0; + +} +static void lsdev_release(struct device *dev) +{ + return; +} +static struct platform_device lsdev = { + .name = "lsdevice", + .id = -1, + .dev = { + .release = lsdev_release, + }, +}; +static struct platform_driver lsdrv = { + .probe = ls_probe, + .remove = ls_remove, + .suspend = ls_suspend, + .resume = ls_resume, + .driver = { + .name = "lsdevice", + }, +}; +//******************************************************************** + +static int __init sensor_cm3232_init(void) +{ + int ret = 0; + printk(KERN_INFO MODULE_NAME ": %s cm3232 init call, \n", __func__); + /* + * Force device to initialize: i2c-15 0x44 + * If i2c_new_device is not called, even cm3232_detect will not run + * TODO: rework to automatically initialize the device + */ + //i2c_new_device(i2c_get_adapter(15), &isl_info); + //return i2c_add_driver(&cm3232_driver); + if (!(this_client = sensor_i2c_register_device(2, SENSOR_I2C_ADDR, SENSOR_I2C_NAME))) + { + printk(KERN_EMERG"Can't register gsensor i2c device!\n"); + return -1; + } + if (cm3232_detect(this_client)) + { + errlog("Can't find light sensor cm3232!\n"); + goto detect_fail; + } + get_adc_val(); + if(cm3232_probe(this_client)) + { + errlog("Erro for probe!\n"); + goto detect_fail; + } + + ret = platform_device_register(&lsdev); + if (ret){ + printk("<< +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include + +////////////////////////////////////////////////////////// +#define AKMIO 0xA1 + +/* IOCTLs for AKM library */ +#define ECS_IOCTL_INIT _IO(AKMIO, 0x01) +#define ECS_IOCTL_WRITE _IOW(AKMIO, 0x02, char[5]) +#define ECS_IOCTL_READ _IOWR(AKMIO, 0x03, char[5]) +#define ECS_IOCTL_RESET _IO(AKMIO, 0x04) +#define ECS_IOCTL_INT_STATUS _IO(AKMIO, 0x05) +#define ECS_IOCTL_FFD_STATUS _IO(AKMIO, 0x06) +#define ECS_IOCTL_SET_MODE _IOW(AKMIO, 0x07, short) +#define ECS_IOCTL_GETDATA _IOR(AKMIO, 0x08, char[RBUFF_SIZE+1]) +#define ECS_IOCTL_GET_NUMFRQ _IOR(AKMIO, 0x09, char[2]) +#define ECS_IOCTL_SET_PERST _IO(AKMIO, 0x0A) +#define ECS_IOCTL_SET_G0RST _IO(AKMIO, 0x0B) +#define ECS_IOCTL_SET_YPR _IOW(AKMIO, 0x0C, short[12]) +#define ECS_IOCTL_GET_OPEN_STATUS _IOR(AKMIO, 0x0D, int) +#define ECS_IOCTL_GET_CLOSE_STATUS _IOR(AKMIO, 0x0E, int) +#define ECS_IOCTL_GET_CALI_DATA _IOR(AKMIO, 0x0F, char[MAX_CALI_SIZE]) +#define ECS_IOCTL_GET_DELAY _IOR(AKMIO, 0x30, short) + +/* IOCTLs for APPs */ +#define ECS_IOCTL_APP_SET_MODE _IOW(AKMIO, 0x10, short) +#define ECS_IOCTL_APP_SET_MFLAG _IOW(AKMIO, 0x11, short) +#define ECS_IOCTL_APP_GET_MFLAG _IOW(AKMIO, 0x12, short) +//#define ECS_IOCTL_APP_SET_AFLAG _IOW(AKMIO, 0x13, short) +#define ECS_IOCTL_APP_GET_AFLAG _IOR(AKMIO, 0x14, short) +#define ECS_IOCTL_APP_SET_TFLAG _IOR(AKMIO, 0x15, short) +#define ECS_IOCTL_APP_GET_TFLAG _IOR(AKMIO, 0x16, short) +#define ECS_IOCTL_APP_RESET_PEDOMETER _IO(AKMIO, 0x17) +//#define ECS_IOCTL_APP_SET_DELAY _IOW(AKMIO, 0x18, short) +#define ECS_IOCTL_APP_GET_DELAY ECS_IOCTL_GET_DELAY +#define ECS_IOCTL_APP_SET_MVFLAG _IOW(AKMIO, 0x19, short) /* Set raw magnetic vector flag */ +#define ECS_IOCTL_APP_GET_MVFLAG _IOR(AKMIO, 0x1A, short) /* Get raw magnetic vector flag */ + +#define WMTGSENSOR_IOCTL_MAGIC 0x09 +#define WMT_IOCTL_SENSOR_CAL_OFFSET _IOW(WMTGSENSOR_IOCTL_MAGIC, 0x01, int) //offset calibration +#define ECS_IOCTL_APP_SET_AFLAG _IOW(WMTGSENSOR_IOCTL_MAGIC, 0x02, short) +#define ECS_IOCTL_APP_SET_DELAY _IOW(WMTGSENSOR_IOCTL_MAGIC, 0x03, short) +#define WMT_IOCTL_SENSOR_GET_DRVID _IOW(WMTGSENSOR_IOCTL_MAGIC, 0x04, unsigned int) + + +/* IOCTLs for pedometer */ +#define ECS_IOCTL_SET_STEP_CNT _IOW(AKMIO, 0x20, short) +////////////////////////////////////////////////////////////////// +#define SENSOR_DELAY_FASTEST 0 +#define SENSOR_DELAY_GAME 20 +#define SENSOR_DELAY_UI 60 +#define SENSOR_DELAY_NORMAL 200 + +#define DMARD06_DRVID 3 + +///////////////////////////////////////////////////////////////// + +#undef dbg +#define dbg(fmt, args...) if (l_sensorconfig.isdbg) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__, ## args) + +#undef errlog +#undef klog +#define errlog(fmt, args...) printk(KERN_ERR "[%s]: " fmt, __FUNCTION__, ## args) +#define klog(fmt, args...) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__, ## args) + +#define DMARD06_I2C_NAME "dmard06" +#define DMARD06_I2C_ADDR 0x1c + +#define GSENSOR_PROC_NAME "gsensor_config" +#define GSENSOR_MAJOR 161 +#define GSENSOR_NAME "dmard06" +#define GSENSOR_DRIVER_NAME "dmard06_drv" + +#define GSENDMARD06_UBOOT_NAME "wmt.io.d06sensor" + +#define MAX_WR_DMARD06_LEN (1+1) + +#define LSG 32 + +static char const *const ACCELEMETER_CLASS_NAME = "accelemeter"; +static char const *const DMARD06_DEVICE_NAME = "dmard06"; +//////////////////////////////////////////////////////////// +#define ID_REG_ADDR 0x0F +#define SWRESET_REG_ADDR 0x53 +#define T_REG_ADDR 0x40 +#define XYZ_REG_ADDR 0x41 +#define CTR1_REG_ADDR 0x44 +#define CTR2_REG_ADDR 0x45 +#define CTR3_REG_ADDR 0x46 +#define CTR4_REG_ADDR 0x47 +#define CTR5_REG_ADDR 0x48 +#define STAT_REG_ADDR 0x49 + + + +static int dmard06_init(void); +static void dmard06_exit(void); + +static int dmard06_file_open(struct inode*, struct file*); +static ssize_t dmard06_file_write(struct file*, const char*, size_t, loff_t*); +static ssize_t dmard06_file_read(struct file*, char*, size_t, loff_t*); +static int dmard06_file_close(struct inode*, struct file*); + +static int dmard06_i2c_suspend(struct platform_device *pdev, pm_message_t state); +static int dmard06_i2c_resume(struct platform_device *pdev); +static int dmard06_i2c_probe(void); +static int dmard06_i2c_remove(void); +static void dmard06_i2c_read_xyz(s8 *x, s8 *y, s8 *z); +static void dmard06_i2c_accel_value(s8 *val); +static int dmard06_probe( + struct platform_device *pdev); +static int dmard06_remove(struct platform_device *pdev); +static int dmard06_i2c_xyz_read_reg(u8* index ,u8 *buffer, int length); + + + +//extern int wmt_i2c_xfer_continue_if_4(struct i2c_msg *msg, unsigned int num, int bus_id); +extern int i2c_api_do_send(int bus_id, char chip_addr, char sub_addr, char *buf, unsigned int size); +extern int i2c_api_do_recv(int bus_id, char chip_addr, char sub_addr, char *buf, unsigned int size); + +extern int wmt_setsyspara(char *varname, unsigned char *varval); + +///////////////////////////////////////////////////////////////// +struct work_struct poll_work; +static struct mutex sense_data_mutex; + + +struct dmard06_config +{ + int op; + int int_gpio; //0-3 + int samp; + int xyz_axis[3][3]; // (axis,direction) + int irq; + struct proc_dir_entry* sensor_proc; + //int sensorlevel; + //int shake_enable; // 1--enable shake, 0--disable shake + //int manual_rotation; // 0--landance, 90--vertical + struct input_dev *input_dev; + //struct work_struct work; + struct delayed_work work; // for polling + struct workqueue_struct *queue; + int isdbg; // 0-- no debug log, 1--show debug log + int sensor_samp; // + int sensor_enable; // 0 --> disable sensor, 1 --> enable sensor + int test_pass; + spinlock_t spinlock; + int pollcnt; // the counts of polling + int offset[3]; // for calibration +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend earlysuspend; +#endif +}; + +static struct dmard06_config l_sensorconfig = { + .op = 0, + .int_gpio = 3, + .samp = 16, + .xyz_axis = { + {ABS_X, -1}, + {ABS_Y, 1}, + {ABS_Z, -1}, + }, + .irq = 6, + .int_gpio = 3, + .sensor_proc = NULL, + //.sensorlevel = SENSOR_GRAVITYGAME_MODE, + //.shake_enable = 0, // default enable shake + .isdbg = 0, + .sensor_samp = 1, // 1 sample/second + .sensor_enable = 1, // enable sensor + .test_pass = 0, // for test program + .pollcnt = 0, // Don't report the x,y,z when the driver is loaded until 2~3 seconds + .offset = {0, 0, 0}, +}; + +static struct class* l_dev_class = NULL; +static struct device *l_clsdevice = NULL; + + +struct raw_data +{ + short x; + short y; + short z; +}; + +struct dev_data +{ + dev_t devno; + struct cdev cdev; + struct class *class; + struct i2c_client *client; +}; + +static struct dev_data dev; + +struct file_operations dmard06_fops = +{ + .owner = THIS_MODULE, + .read = dmard06_file_read, + .write = dmard06_file_write, + .open = dmard06_file_open, + .release = dmard06_file_close, +}; + +static int dmard06_file_open(struct inode *inode, struct file *filp) +{ + dbg("open...\n"); + + return 0; +} + +static ssize_t dmard06_file_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos) +{ + dbg("write...\n"); + + return 0; +} + +unsigned int sample_rate_2_memsec(unsigned int rate) +{ + return (1000/rate); +} + +static int dmard06_packet_rptValue(int x, int y, int z) +{ + return ((0xFF&z) | ((0xFF&y)<<8) | ((0xFF&x)<<16)); +} + + +static void dmard06_work_func(struct work_struct *work) +{ + u8 buffer[3]; + //buffer[0] = 0x41; + u8 index = 0x41; + s8 x,y,z; + int xyz,tx,ty,tz; + + mutex_lock(&sense_data_mutex); + //read data + dmard06_i2c_xyz_read_reg(&index, buffer, 3); + mutex_unlock(&sense_data_mutex); + // check whether it's valid + // report the data + x = (s8)buffer[0]; + y = (s8)buffer[1]; + z = (s8)buffer[2]; + dmard06_i2c_accel_value(&x); + dmard06_i2c_accel_value(&y); + dmard06_i2c_accel_value(&z); + tx = x*l_sensorconfig.xyz_axis[0][1]+l_sensorconfig.offset[0]; + ty = y*l_sensorconfig.xyz_axis[1][1]+l_sensorconfig.offset[1]; + tz = z*l_sensorconfig.xyz_axis[2][1]+l_sensorconfig.offset[2]; + xyz = dmard06_packet_rptValue(tx, ty, tz); + input_report_abs(l_sensorconfig.input_dev, ABS_X, xyz); + + //input_report_abs(l_sensorconfig.input_dev, l_sensorconfig.xyz_axis[0][0], + // x*l_sensorconfig.xyz_axis[0][1]+l_sensorconfig.offset[0]); + //input_report_abs(l_sensorconfig.input_dev, l_sensorconfig.xyz_axis[1][0], + // y*l_sensorconfig.xyz_axis[1][1]+l_sensorconfig.offset[1]); + //input_report_abs(l_sensorconfig.input_dev, l_sensorconfig.xyz_axis[2][0], + //z*l_sensorconfig.xyz_axis[2][1]+l_sensorconfig.offset[2]); + input_sync(l_sensorconfig.input_dev); + dbg("x=%2x(tx=%2x),y=%2x(ty=%2x),z=%2x(tz=%2x),xyz=%x", + (char)x, (char)tx, (char)y, (char)ty, (char)z, (char)tz, xyz); + + // for next polling + queue_delayed_work(l_sensorconfig.queue, &l_sensorconfig.work, msecs_to_jiffies(sample_rate_2_memsec(l_sensorconfig.sensor_samp))); + //klog("%d=%d,%d=%d,%d=%d\n", l_sensorconfig.xyz_axis[0][0], x*l_sensorconfig.xyz_axis[0][1], + // l_sensorconfig.xyz_axis[1][0], y*l_sensorconfig.xyz_axis[1][1], + // l_sensorconfig.xyz_axis[2][0], z*l_sensorconfig.xyz_axis[2][1]); + //klog("the polling period:%d\n", msecs_to_jiffies(sample_rate_2_memsec(l_sensorconfig.sensor_samp))); + +} + + +static ssize_t dmard06_file_read(struct file *filp, char *buf, size_t count, loff_t *f_pos) +{ + int ret; + s8 x, y, z; + struct raw_data rdata; + + dbg("read...\n"); + mutex_lock(&sense_data_mutex); + dmard06_i2c_read_xyz(&x, &y, &z); + rdata.x = x; + rdata.y = y; + rdata.z = z; + + ret = copy_to_user(buf, &rdata, count); + mutex_unlock(&sense_data_mutex); + + return count; +} + +static int dmard06_file_close(struct inode *inode, struct file *filp) +{ + dbg("close...\n"); + + return 0; +} + +static void dmard06_platform_release(struct device *device) +{ + return; +} + + +static struct platform_device dmard06_device = { + .name = GSENSOR_NAME, + .id = 0, + .dev = { + .release = dmard06_platform_release, + }, +}; + +static struct platform_driver dmard06_driver = { + .probe = dmard06_probe, + .remove = dmard06_remove, + .suspend = dmard06_i2c_suspend, + .resume = dmard06_i2c_resume, + .driver = { + .name = GSENSOR_NAME, + }, +}; + +static int dmard06_i2c_xyz_write_reg(u8* index ,u8 *buffer, int length) +{ + /*int ret = 0; + u8 buf[MAX_WR_DMARD06_LEN]; + struct i2c_msg msg[1]; + + buf[0] = *index; + memcpy(buf+1, buffer, length); + msg[0].addr = DMARD06_I2C_ADDR; + msg[0].flags = 0 ; + msg[0].flags &= ~(I2C_M_RD); + msg[0].len = length+1; + msg[0].buf = buf; + if ((ret = wmt_i2c_xfer_continue_if_4(msg,1,0)) <= 0) + { + errlog("write error!\n"); + } + return ret;*/ + return i2c_api_do_send(0, DMARD06_I2C_ADDR, index, buffer, length); +} + +static int dmard06_i2c_xyz_read_reg(u8* index ,u8 *buffer, int length) +{ + /*int ret = 0; + + struct i2c_msg msg[] = + { + {.addr = DMARD06_I2C_ADDR, .flags = 0, .len = 1, .buf = index,}, + {.addr = DMARD06_I2C_ADDR, .flags = I2C_M_RD, .len = length, .buf = buffer,}, + }; + ret = wmt_i2c_xfer_continue_if_4(msg, 2,0); + if (ret <= 0) + { + errlog("read error!\n"); + } + return ret;*/ + return i2c_api_do_recv(0, DMARD06_I2C_ADDR, index, buffer, length); +} + +static void dmard06_i2c_read_xyz(s8 *x, s8 *y, s8 *z) +{ + + u8 buffer[3]; + //buffer[0] = 0x41; + u8 index = 0x41; + + dmard06_i2c_xyz_read_reg(&index, buffer, 3); + *x = (s8)buffer[0]; + *y = (s8)buffer[1]; + *z = (s8)buffer[2]; + dmard06_i2c_accel_value(x); + dmard06_i2c_accel_value(y); + dmard06_i2c_accel_value(z); + if (ABS_X == l_sensorconfig.xyz_axis[0][0]) + { + *x = l_sensorconfig.xyz_axis[0][1]*(*x); + *y = l_sensorconfig.xyz_axis[1][1]*(*y); + } else { + *x = l_sensorconfig.xyz_axis[0][1]*(*y); + *y = l_sensorconfig.xyz_axis[1][1]*(*x); + } + *z = l_sensorconfig.xyz_axis[2][1]*(*z); + + dbg("dmrd06:x=%x,y=%x,z=%x\n", *x, *y, *z); +} + +static void dmard06_i2c_accel_value(s8 *val) +{ + *val >>= 1; +} + +static int dmard06_CalOffset(int side) +{ + u8 buffer[3]; + //buffer[0] = 0x41; + u8 index = 0x41; + s8 x,y,z; + + //mutex_lock(&sense_data_mutex); + //read data + dmard06_i2c_xyz_read_reg(&index, buffer, 3); + //mutex_unlock(&sense_data_mutex); + // check whether it's valid + // report the data + x = (s8)buffer[0]; + y = (s8)buffer[1]; + z = (s8)buffer[2]; + dmard06_i2c_accel_value(&x); + dmard06_i2c_accel_value(&y); + dmard06_i2c_accel_value(&z); + l_sensorconfig.offset[0] = 0 - x*l_sensorconfig.xyz_axis[0][1]; + l_sensorconfig.offset[1] = 0 - y*l_sensorconfig.xyz_axis[1][1]; + l_sensorconfig.offset[2] = LSG - z*l_sensorconfig.xyz_axis[2][1]; + return 0; + +} + +static int dmard06_i2c_suspend(struct platform_device *pdev, pm_message_t state) +{ + dbg("...\n"); + cancel_delayed_work_sync(&l_sensorconfig.work); + + return 0; +} + +static int is_dmard06(void) +{ + int err = 0; + u8 cAddress = 0, cData = 0; + char buf[4]; + + cAddress = 0x53; + //i2c_master_send( client, (char*)&cAddress, 1); + //i2c_master_recv( client, (char*)&cData, 1); + if (dmard06_i2c_xyz_read_reg(&cAddress, &cData,1) <= 0) + { + errlog("Error to read SW_RESET register!\n"); + } + dbg("i2c Read 0x53 = %x \n", cData); + + cAddress = 0x0f; + //i2c_master_send( client, (char*)&cAddress, 1); + //i2c_master_recv( client, (char*)&cData, 1); + if (dmard06_i2c_xyz_read_reg(&cAddress, &cData,1) <= 0) + { + errlog("Can't find dmard06!\n"); + return -1; + } + dbg("i2c Read 0x0f = %d \n", cData); + + if(( cData&0x00FF) == 0x0006) + { + klog("Find DMARD06!\n"); + } + else + { + errlog("ID isn't 0x06.(0x%x) !\n",cData); + return -1; + } + + return 0; +} + +static int dmard06_i2c_remove(void) +{ + + return 0; +} + +static int dmard06_i2c_resume(struct platform_device *pdev) +{ + dbg("...\n"); + queue_delayed_work(l_sensorconfig.queue, &l_sensorconfig.work, msecs_to_jiffies(sample_rate_2_memsec(l_sensorconfig.sensor_samp))); + + + return 0; +} + +static int sensor_writeproc( struct file *file, + const char *buffer, + unsigned long count, + void *data ) +{ + + int inputval = -1; + int enable, sample = -1; + char tembuf[8]; + unsigned int amsr = 0; + int test = 0; + + mutex_lock(&sense_data_mutex); + memset(tembuf, 0, sizeof(tembuf)); + // get sensor level and set sensor level + if (sscanf(buffer, "isdbg=%d\n", &l_sensorconfig.isdbg)) + { + // only set the dbg flag + } else if (sscanf(buffer, "samp=%d\n", &sample)) + { + if (sample > 0) + { + if (sample != l_sensorconfig.sensor_samp) + { + } + //printk(KERN_ALERT "sensor samp=%d(amsr:%d) has been set.\n", sample, amsr); + } else { + printk(KERN_ALERT "Wrong sample argumnet of sensor.\n"); + } + } else if (sscanf(buffer, "enable=%d\n", &enable)) + { + if ((enable < 0) || (enable > 1)) + { + printk(KERN_ERR "The argument to enable/disable g-sensor should be 0 or 1 !!!\n"); + } else if (enable != l_sensorconfig.sensor_enable) + { + //mma_enable_disable(enable); + l_sensorconfig.sensor_enable = enable; + } + } else if (sscanf(buffer, "sensor_test=%d\n", &test)) + { // for test begin + l_sensorconfig.test_pass = 0; + } else if (sscanf(buffer, "sensor_testend=%d\n", &test)) + { // Don nothing only to be compatible the before testing program + } + mutex_unlock(&sense_data_mutex); + return count; +} + +static int sensor_readproc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = 0; + + len = sprintf(page, + "test_pass=%d\nisdbg=%d\nrate=%d\nenable=%d\n", + l_sensorconfig.test_pass, + l_sensorconfig.isdbg, + l_sensorconfig.sensor_samp, + l_sensorconfig.sensor_enable + ); + return len; +} + + +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); +static int get_axisset(void* param) +{ + char varbuf[64]; + int n; + int varlen; + + memset(varbuf, 0, sizeof(varbuf)); + varlen = sizeof(varbuf); + if (wmt_getsyspara("wmt.io.d06sensor", varbuf, &varlen)) { + printk(KERN_DEBUG "Can't get gsensor config in u-boot!!!!\n"); + return -1; + } else { + n = sscanf(varbuf, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", + &l_sensorconfig.op, + &l_sensorconfig.int_gpio, + &l_sensorconfig.samp, + &(l_sensorconfig.xyz_axis[0][0]), + &(l_sensorconfig.xyz_axis[0][1]), + &(l_sensorconfig.xyz_axis[1][0]), + &(l_sensorconfig.xyz_axis[1][1]), + &(l_sensorconfig.xyz_axis[2][0]), + &(l_sensorconfig.xyz_axis[2][1]), + &l_sensorconfig.offset[0], + &l_sensorconfig.offset[1], + &l_sensorconfig.offset[2]); + if (n != 12) { + printk(KERN_ERR "gsensor format is error in u-boot!!!\n"); + return -1; + } + l_sensorconfig.sensor_samp = l_sensorconfig.samp; + + dbg("get the sensor config: %d:%d:%d:%d:%d:%d:%d:%d:%d\n", + l_sensorconfig.op, + l_sensorconfig.int_gpio, + l_sensorconfig.samp, + l_sensorconfig.xyz_axis[0][0], + l_sensorconfig.xyz_axis[0][1], + l_sensorconfig.xyz_axis[1][0], + l_sensorconfig.xyz_axis[1][1], + l_sensorconfig.xyz_axis[2][0], + l_sensorconfig.xyz_axis[2][1] + ); + } + return 0; +} + +// To contol the g-sensor for UI +static int mmad_open(struct inode *inode, struct file *file) +{ + dbg("Open the g-sensor node...\n"); + return 0; +} + +static int mmad_release(struct inode *inode, struct file *file) +{ + dbg("Close the g-sensor node...\n"); + return 0; +} + + +static int +mmad_ioctl(/*struct inode *inode,*/ struct file *file, unsigned int cmd, + unsigned long arg) +{ + void __user *argp = (void __user *)arg; + char rwbuf[5]; + short delay, enable, amsr = -1; + unsigned int sample; + int ret = 0; + int side; + char varbuff[80]; + unsigned int uval = 0; + + dbg("g-sensor ioctr...\n"); + memset(rwbuf, 0, sizeof(rwbuf)); + mutex_lock(&sense_data_mutex); + switch (cmd) { + case ECS_IOCTL_APP_SET_DELAY: + // set the rate of g-sensor + if (copy_from_user(&delay, argp, sizeof(short))) + { + printk(KERN_ALERT "Can't get set delay!!!\n"); + ret = -EFAULT; + goto errioctl; + } + klog("set delay=%d \n", delay); + //klog("before change sensor sample:%d...\n", l_sensorconfig.sensor_samp); + if ((delay >=0) && (delay < 20)) + { + delay = 20; + } else if (delay > 200) + { + delay = 200; + } + if (delay > 0) + { + l_sensorconfig.sensor_samp = 1000/delay; + } else { + errlog("error delay argument(delay=%d)!!!\n",delay); + ret = -EFAULT; + goto errioctl; + } + break; + case ECS_IOCTL_APP_SET_AFLAG: + // enable/disable sensor + if (copy_from_user(&enable, argp, sizeof(short))) + { + printk(KERN_ERR "Can't get enable flag!!!\n"); + ret = -EFAULT; + goto errioctl; + } + if ((enable >=0) && (enable <=1)) + { + dbg("driver: disable/enable(%d) gsensor.\n", enable); + + if (enable != l_sensorconfig.sensor_enable) + { + //mma_enable_disable(enable); + /*if (enable != 0) + { + queue_delayed_work(l_sensorconfig.queue, &l_sensorconfig.work, msecs_to_jiffies(sample_rate_2_memsec(l_sensorconfig.sensor_samp))); + } else { + cancel_delayed_work_sync(&l_sensorconfig.work); + flush_workqueue(l_sensorconfig.queue); + }*/ + l_sensorconfig.sensor_enable = enable; + + } + } else { + printk(KERN_ERR "Wrong enable argument in %s !!!\n", __FUNCTION__); + ret = -EFAULT; + goto errioctl; + } + break; + case WMT_IOCTL_SENSOR_GET_DRVID: + uval = DMARD06_DRVID; + if (copy_to_user((unsigned int*)arg, &uval, sizeof(unsigned int))) + { + ret = -EFAULT; + goto errioctl; + } + dbg("dmard06_driver_id:%d\n",uval); + break; + case WMT_IOCTL_SENSOR_CAL_OFFSET: + klog("-->WMT_IOCTL_SENSOR_CAL_OFFSET\n"); + if(copy_from_user(&side, (int*)argp, sizeof(int))) + { + ret = -EFAULT; + goto errioctl; + } + dbg("side=%d\n",side); + if (dmard06_CalOffset(side) != 0) + { + ret = -EFAULT; + goto errioctl; + } + // save the param + sprintf(varbuff, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", + l_sensorconfig.op, + l_sensorconfig.int_gpio, + 10,//l_sensorconfig.samp, + (l_sensorconfig.xyz_axis[0][0]), + (l_sensorconfig.xyz_axis[0][1]), + (l_sensorconfig.xyz_axis[1][0]), + (l_sensorconfig.xyz_axis[1][1]), + (l_sensorconfig.xyz_axis[2][0]), + (l_sensorconfig.xyz_axis[2][1]), + l_sensorconfig.offset[0], + l_sensorconfig.offset[1], + l_sensorconfig.offset[2] + ); + wmt_setsyspara(GSENDMARD06_UBOOT_NAME, varbuff); + ret = 0; + break; + default: + break; + } + + + /*switch (cmd) { + case ECS_IOCTL_READ: + if (copy_to_user(argp, &rwbuf, sizeof(rwbuf))) + return -EFAULT; + break; + default: + break; + }*/ +errioctl: + mutex_unlock(&sense_data_mutex); + return ret; +} + + +static struct file_operations mmad_fops = { + .owner = THIS_MODULE, + .open = mmad_open, + .release = mmad_release, + .unlocked_ioctl = mmad_ioctl, +}; + + +static struct miscdevice mmad_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "sensor_ctrl", + .fops = &mmad_fops, +}; + +static int dmard06_probe( + struct platform_device *pdev) +{ + int err = 0; + + //register ctrl dev + err = misc_register(&mmad_device); + if (err != 0) + { + errlog("Can't register mma_device!\n"); + return -1; + } + // register rd/wr proc + l_sensorconfig.sensor_proc = create_proc_entry(GSENSOR_PROC_NAME, 0666, NULL/*&proc_root*/); + if (l_sensorconfig.sensor_proc != NULL) + { + l_sensorconfig.sensor_proc->write_proc = sensor_writeproc; + l_sensorconfig.sensor_proc->read_proc = sensor_readproc; + } + // init work queue + l_sensorconfig.queue = create_singlethread_workqueue("sensor-data-report"); + //INIT_WORK(&l_sensorconfig.work, mma_work_func); + INIT_DELAYED_WORK(&l_sensorconfig.work, dmard06_work_func); + mutex_init(&sense_data_mutex); + l_sensorconfig.input_dev = input_allocate_device(); + if (!l_sensorconfig.input_dev) { + err = -ENOMEM; + errlog("Failed to allocate input device\n"); + goto exit_input_dev_alloc_failed; + } + //set_bit(EV_KEY, l_sensorconfig.input_dev->evbit); + //set_bit(EV_ABS, l_sensorconfig.input_dev->evbit); + l_sensorconfig.input_dev->evbit[0] = BIT(EV_ABS) | BIT_MASK(EV_KEY); + //set_bit(KEY_NEXTSONG, l_sensorconfig.input_dev->keybit); + + /* yaw */ + //input_set_abs_params(l_sensorconfig.input_dev, ABS_RX, 0, 360*100, 0, 0); + /* pitch */ + //input_set_abs_params(l_sensorconfig.input_dev, ABS_RY, -180*100, 180*100, 0, 0); + /* roll */ + //input_set_abs_params(l_sensorconfig.input_dev, ABS_RZ, -90*100, 90*100, 0, 0); + /* x-axis acceleration */ + input_set_abs_params(l_sensorconfig.input_dev, ABS_X, -128, 128, 0, 0); + /* y-axis acceleration */ + input_set_abs_params(l_sensorconfig.input_dev, ABS_Y, -128, 128, 0, 0); + /* z-axis acceleration */ + input_set_abs_params(l_sensorconfig.input_dev, ABS_Z, -128, 128, 0, 0); + + l_sensorconfig.input_dev->name = "g-sensor"; + + err = input_register_device(l_sensorconfig.input_dev); + + if (err) { + errlog("Unable to register input device: %s\n", + l_sensorconfig.input_dev->name); + goto exit_input_register_device_failed; + } + + return 0; +exit_input_register_device_failed: + input_free_device(l_sensorconfig.input_dev); +exit_input_dev_alloc_failed: + // release proc + remove_proc_entry(GSENSOR_PROC_NAME, NULL); + l_sensorconfig.sensor_proc = NULL; + // unregister the ctrl dev + misc_deregister(&mmad_device); + return err; +} + +static int dmard06_remove(struct platform_device *pdev) +{ + if (NULL != l_sensorconfig.queue) + { + cancel_delayed_work_sync(&l_sensorconfig.work); + flush_workqueue(l_sensorconfig.queue); + destroy_workqueue(l_sensorconfig.queue); + l_sensorconfig.queue = NULL; + } + if (l_sensorconfig.sensor_proc != NULL) + { + remove_proc_entry(GSENSOR_PROC_NAME, NULL); + l_sensorconfig.sensor_proc = NULL; + } + misc_deregister(&mmad_device); + return 0; +} +#if 0 +static void dmard06_early_suspend(struct early_suspend *h) +{ + dbg("start\n"); + cancel_delayed_work_sync(&l_sensorconfig.work); + dbg("exit\n"); +} + +static void dmard06_late_resume(struct early_suspend *h) +{ + dbg("start\n"); + // init + queue_delayed_work(l_sensorconfig.queue, &l_sensorconfig.work, msecs_to_jiffies(sample_rate_2_memsec(l_sensorconfig.sensor_samp))); + dbg("exit\n"); +} +#endif + +static int __init dmard06_init(void) +{ + int ret = 0; + + // detech the device + if (is_dmard06() != 0) + { + return -1; + } + // parse g-sensor u-boot arg + ret = get_axisset(NULL); + if (ret < 0) + { + printk("<<<<<%s user choose to no sensor chip!\n", __func__); + return ret; + } + /*if ((ret != 0) || !l_sensorconfig.op) + return -EINVAL; + */ + + // Create device node + if (register_chrdev (GSENSOR_MAJOR, GSENSOR_NAME, &dmard06_fops)) { + printk (KERN_ERR "unable to get major %d\n", GSENSOR_MAJOR); + return -EIO; + } + + l_dev_class = class_create(THIS_MODULE, GSENSOR_NAME); + if (IS_ERR(l_dev_class)){ + ret = PTR_ERR(l_dev_class); + printk(KERN_ERR "Can't class_create gsensor device !!\n"); + return ret; + } + l_clsdevice = device_create(l_dev_class, NULL, MKDEV(GSENSOR_MAJOR, 0), NULL, GSENSOR_NAME); + if (IS_ERR(l_clsdevice)){ + ret = PTR_ERR(l_clsdevice); + printk(KERN_ERR "Failed to create device %s !!!",GSENSOR_NAME); + return ret; + } + INIT_WORK(&poll_work, dmard06_work_func); + + + if((ret = platform_device_register(&dmard06_device))) + { + printk(KERN_ERR "%s Can't register mma7660 platform devcie!!!\n", __FUNCTION__); + return ret; + } + if ((ret = platform_driver_register(&dmard06_driver)) != 0) + { + printk(KERN_ERR "%s Can't register mma7660 platform driver!!!\n", __FUNCTION__); + return ret; + } +#ifdef CONFIG_HAS_EARLYSUSPEND + l_sensorconfig.earlysuspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + l_sensorconfig.earlysuspend.suspend = dmard06_early_suspend; + l_sensorconfig.earlysuspend.resume = dmard06_late_resume; + register_early_suspend(&l_sensorconfig.earlysuspend); +#endif + + klog("dmard06 g-sensor driver load!\n"); + queue_delayed_work(l_sensorconfig.queue, &l_sensorconfig.work, msecs_to_jiffies(sample_rate_2_memsec(l_sensorconfig.sensor_samp))); + + return 0; +} + +static void __exit dmard06_exit(void) +{ + //unregister_early_suspend(&l_sensorconfig.earlysuspend); + platform_driver_unregister(&dmard06_driver); + platform_device_unregister(&dmard06_device); + device_destroy(l_dev_class, MKDEV(GSENSOR_MAJOR, 0)); + unregister_chrdev(GSENSOR_MAJOR, GSENSOR_NAME); + class_destroy(l_dev_class); + +} + +MODULE_AUTHOR("DMT_RD"); +MODULE_DESCRIPTION("DMARD06 g-sensor Driver"); +MODULE_LICENSE("GPL"); + +module_init(dmard06_init); +module_exit(dmard06_exit); diff --git a/ANDROID_3.4.5/drivers/input/sensor/dmard08_gsensor/Makefile b/ANDROID_3.4.5/drivers/input/sensor/dmard08_gsensor/Makefile new file mode 100755 index 00000000..82f27563 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/dmard08_gsensor/Makefile @@ -0,0 +1,34 @@ +KERNELDIR=../../../../ +#KERNELDIR=/home/hangyan/android8850/kernel/ANDROID_3.0.8 +CROSS = arm_1103_le- +CC= $(CROSS)gcc +LD= $(CROSS)ld +STRIP = $(CROSS)strip + +DEBUG = n + +# Add your debugging flag (or not) to EXTRA_CFLAGS +ifeq ($(DEBUG),y) +# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines +DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines + +else + DEBFLAGS = -O2 -Wall +endif + +EXTRA_CFLAGS += $(DEBFLAGS) + + +MY_MODULE_NAME=s_wmt_gsensor_dmard08 + +obj-m := $(MY_MODULE_NAME).o +$(MY_MODULE_NAME)-objs := dmard08.o cyclequeue.o + +default: + $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules + $(STRIP) --strip-debug $(MY_MODULE_NAME).ko + rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions + +clean: + rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers + diff --git a/ANDROID_3.4.5/drivers/input/sensor/dmard08_gsensor/cyclequeue.c b/ANDROID_3.4.5/drivers/input/sensor/dmard08_gsensor/cyclequeue.c new file mode 100755 index 00000000..4d6b97cd --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/dmard08_gsensor/cyclequeue.c @@ -0,0 +1,68 @@ +#include + + +#include "cyclequeue.h" + +static struct que_data que[QUEUE_LEN]; +static unsigned int head = -1; // point to the first valaid queue data +static unsigned int tail = 0; // point to the next to the last valaid queue data +static DEFINE_MUTEX(que_mutex); + +// Whether queue is full +// return 1--full,0 -- no full +int clque_is_full(void) +{ + int ret = 0; + + mutex_lock(&que_mutex); + ret = ((tail+1)%QUEUE_LEN) == head ? 1 : 0; + mutex_unlock(&que_mutex); + return ret; +} + +// Whether queue is empty +// return 1--empty,0--no empty +int clque_is_empty(void) +{ + int ret = 0; + + mutex_lock(&que_mutex); + ret = (tail == head) ? 1: 0; + mutex_unlock(&que_mutex); + return ret; +} + +// add to queue +// return:0--successful,-1--queue is full +int clque_in(struct que_data* data) +{ + /*if (clque_is_full()) + { + return -1; + }*/ + mutex_lock(&que_mutex); + que[tail].data[0] = data->data[0]; + que[tail].data[1] = data->data[1]; + que[tail].data[2] = data->data[2]; + tail = (tail+1)%QUEUE_LEN; + mutex_unlock(&que_mutex); + return 0; +} + +// out to queue +// return:0--successful,-1--queue is empty +int clque_out(struct que_data* data) +{ + /*if (clque_is_empty()) + { + return -1; + }*/ + mutex_lock(&que_mutex); + data->data[0]= que[head].data[0]; + data->data[1]= que[head].data[1]; + data->data[2]= que[head].data[2]; + head = (head+1)%QUEUE_LEN; + mutex_unlock(&que_mutex); + return 0; +} + diff --git a/ANDROID_3.4.5/drivers/input/sensor/dmard08_gsensor/cyclequeue.h b/ANDROID_3.4.5/drivers/input/sensor/dmard08_gsensor/cyclequeue.h new file mode 100755 index 00000000..52b9996f --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/dmard08_gsensor/cyclequeue.h @@ -0,0 +1,18 @@ +#ifndef __CYCLEQUEUE_163704111637_H +#define __CYCLEQUEUE_163704111637_H + +#define DATA_TYPE short +#define QUEUE_LEN 16 + +struct que_data { + DATA_TYPE data[3]; +}; + +extern int clque_in(struct que_data* data); +extern int clque_out(struct que_data* data); +extern int clque_is_full(void); +extern int clque_is_empty(void); +#endif + + + diff --git a/ANDROID_3.4.5/drivers/input/sensor/dmard08_gsensor/dmard08.c b/ANDROID_3.4.5/drivers/input/sensor/dmard08_gsensor/dmard08.c new file mode 100755 index 00000000..3cbe2ac7 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/dmard08_gsensor/dmard08.c @@ -0,0 +1,1019 @@ +/* + * @file drivers/i2c/dmard08.c + * @brief DMARD08 g-sensor Linux device driver + * @author Domintech Technology Co., Ltd (http://www.domintech.com.tw) + * @version 1.22 + * @date 2011/12/01 + * + * @section LICENSE + * + * Copyright 2011 Domintech Technology Co., Ltd + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +// ****Add by Steve Huang*********2011-11-18******** +#include +#include "../sensor.h" +//#include "cyclequeue.h" +// ************************************************ + +#define GSENSOR_I2C_NAME "dmard08" +#define GSENSOR_I2C_ADDR 0x1c + +#define SENSOR_DATA_SIZE 3 + +static struct i2c_client *this_client = NULL; +static struct mutex sense_data_mutex; +static struct class* l_dev_class = NULL; + +static struct wmt_gsensor_data l_sensorconfig = { + .op = 0, + .int_gpio = 3, + .samp = 5, + .xyz_axis = { + {ABS_X, -1}, + {ABS_Y, 1}, + {ABS_Z, -1}, + }, + .sensor_proc = NULL, + .isdbg = 0, + .sensor_samp = 10, // 1 sample/second + .sensor_enable = 1, // enable sensor + .test_pass = 0, // for test program + .offset={0,0,0}, +}; + + +// ****Add by Steve Huang*********2011-11-18******** +/*void gsensor_write_offset_to_file(void); +void gsensor_read_offset_from_file(void); +char OffsetFileName[] = "/data/misc/dmt/offset.txt";*/ +//************************************************** + + + +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); + +/*static int dmard08_i2c_suspend(struct i2c_client *client, pm_message_t mesg); +static int dmard08_i2c_resume(struct i2c_client *client);*/ +//static int __devinit dmard08_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id); +//static int __devexit dmard08_i2c_remove(struct i2c_client *client); +void dmard08_i2c_read_xyz(struct i2c_client *client, s16 *xyz); +static inline void dmard08_i2c_correct_accel_sign(s16 *val); //check output is correct +void dmard08_i2c_merge_register_values(struct i2c_client *client, s16 *val, u8 msb, u8 lsb); //merge the register values + +struct raw_data { + short x; + short y; + short z; +}; + +struct raw_data rdata; +//static struct raw_data offset; + +struct dev_data +{ + dev_t devno; + struct cdev cdev; + struct class *class; + struct i2c_client *client; +}; +//static struct dev_data dev; + + +unsigned int sample_rate_2_memsec(unsigned int rate) +{ + return (1000/rate); +} + + +/*void gsensor_read_accel_avg(int num_avg, raw_data *avg_p) // marked by eason check again!! +{ + long xyz_acc[SENSOR_DATA_SIZE]; + s16 xyz[SENSOR_DATA_SIZE]; + int i, j; + + //initialize the accumulation buffer + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + xyz_acc[i] = 0; + + for(i = 0; i < num_avg; i++) + { + device_i2c_read_xyz(l_sensorconfig.client, (s16 *)&xyz); + for(j = 0; j < SENSOR_DATA_SIZE; j++) + xyz_acc[j] += xyz[j]; + } + + // calculate averages + for(i = 0; i < SENSOR_DATA_SIZE; i++) + avg_p->v[i] = (s16) (xyz_acc[i] / num_avg); +}*/ + +/*void gsensor_calibrate(int side) //marked by eason check again +{ + raw_data avg; + int avg_num = 16; + + //IN_FUNC_MSG; + // get acceleration average reading + gsensor_read_accel_avg(avg_num, &avg); + // calculate and set the offset + gsensor_calculate_offset(side, avg); +}*/ + +/*void ce_on(void) //marked by eason check again +{ + int gppdat; + gppdat = __raw_readl(S3C64XX_GPPDAT); + gppdat |= (1 << 0); + + __raw_writel(gppdat,S3C64XX_GPPDAT); +} + +void ce_off(void) +{ + int gppdat; + gppdat = __raw_readl(S3C64XX_GPPDAT); + gppdat &= ~(1 << 0); + + __raw_writel(gppdat,S3C64XX_GPPDAT); +} + +void config_ce_pin(void) +{ + unsigned int value; + //D08's CE (pin#12) is connected to S3C64XX AP processor's port P0 + //Below codes set port P0 as digital output + value = readl(S3C64XX_GPPCON); + value &= ~ (0x3); + value |= 1 ; //Output =01 , Input = 00 , Ext. Interrupt = 10 + writel(value, S3C64XX_GPPCON); //save S3C64XX_GPPCON change +} + +void gsensor_reset(void) +{ + ce_off(); + msleep(300); + ce_on(); +}*/ + +/*void gsensor_set_offset(int val[3]) //marked by eason check again +{ + int i; + IN_FUNC_MSG; + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + offset.v[i] = (s16) val[i]; +}*/ + +/* +static const struct i2c_device_id dmard08_i2c_ids[] = +{ + {GSENSOR_I2C_NAME, 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, dmard08_i2c_ids); + + +static struct i2c_driver dmard08_i2c_driver = +{ + .driver = { + .owner = THIS_MODULE, + .name = GSENSOR_I2C_NAME, + }, + .class = I2C_CLASS_HWMON, + .probe = dmard08_i2c_probe, + .remove = __devexit_p(dmard08_i2c_remove), + //.suspend = dmard08_i2c_suspend, + //.resume = dmard08_i2c_resume, + .id_table = dmard08_i2c_ids, +}; +*/ + +static int dmard08_i2c_xyz_read_reg(struct i2c_client *client,u8 *buffer, int length) //OK +{ + + struct i2c_msg msg[] = + { + {.addr = client->addr, .flags = 0, .len = 1, .buf = buffer,}, + {.addr = client->addr, .flags = I2C_M_RD, .len = length, .buf = buffer,}, + }; + return i2c_transfer(client->adapter, msg, 2); +} + +static int dmard08_i2c_xyz_write_reg(struct i2c_client *client,u8 *buffer, int length) //write reg OK +{ + struct i2c_msg msg[] = + { + {.addr = client->addr, .flags = 0, .len = length, .buf = buffer,}, + }; + return i2c_transfer(client->adapter, msg, 1); +} + +//static void dmard08_i2c_read_xyz(struct i2c_client, s16 *x, s16 *y, s16 *z) //add by eason +void dmard08_i2c_read_xyz(struct i2c_client *client, s16 *xyz_p) +{ +// s16 xTmp,yTmp,zTmp; //added by eason + s16 xyzTmp[SENSOR_DATA_SIZE]; + int i; +/*get xyz high/low bytes, 0x02~0x07*/ + u8 buffer[6]; + buffer[0] = 0x2; + mutex_lock(&sense_data_mutex); + dmard08_i2c_xyz_read_reg(client, buffer, 6); + mutex_unlock(&sense_data_mutex); + + //merge to 11-bits value + for(i = 0; i < SENSOR_DATA_SIZE; ++i){ + dmard08_i2c_merge_register_values(client, (xyzTmp + i), buffer[2*i], buffer[2*i + 1]); + } + //transfer to the default layout + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + { + xyz_p[i] = xyzTmp[i]; // add by eason +/* xyz_p[i] = 0; + for(j = 0; j < 3; j++) + xyz_p[i] += sensorlayout[i][j] * xyzTmp[j]; */ + } + dbg("%x,%x,%x,",xyz_p[0], xyz_p[1], xyz_p[2]); + //printk("@DMT@ dmard08_i2c_read_xyz: X-axis: %d ,Y-axis: %d ,Z-axis: %d\n", xyz_p[0], xyz_p[1], xyz_p[2]); +} + +void dmard08_i2c_merge_register_values(struct i2c_client *client, s16 *val, u8 msb, u8 lsb) +{ + + *val = (((u16)msb) << 3) | (u16)lsb; + dmard08_i2c_correct_accel_sign(val); +} + +static inline void dmard08_i2c_correct_accel_sign(s16 *val) +{ + + *val<<= (sizeof(s16) * BITS_PER_BYTE - 11); + *val>>= (sizeof(s16) * BITS_PER_BYTE - 11); +} + +/* +static int dmard08_i2c_suspend(struct i2c_client *client, pm_message_t mesg) +{ + dbg("...\n"); + return 0; +} +*/ + +//static int __devinit dmard08_i2c_probe(struct i2c_client *client,const struct i2c_device_id *id) +static int __devinit dmard08_hw_init(struct i2c_client *client/*,const struct i2c_device_id *id*/) +{ + char cAddress = 0 , cData = 0; + u8 buffer[2]; + + //for(i = 0; i < SENSOR_DATA_SIZE; ++i) //marked by eason check again + // offset.v[i] = 0; + + + if(!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + { + dbg("I2C_FUNC_I2C not support\n"); + return -1; + } + //config_ce_pin(); //how used? + //gsensor_reset(); //how used? + /* check SW RESET */ + cAddress = 0x08; + i2c_master_send( client, (char*)&cAddress, 1); + i2c_master_recv( client, (char*)&cData, 1); + dbg( "i2c Read 0x08 = %d \n", cData); + if( cData == 0x00) + { + cAddress = 0x09; + i2c_master_send( client, (char*)&cAddress, 1); + i2c_master_recv( client, (char*)&cData, 1); + dbg( "i2c Read 0x09 = %d \n", cData); + if( cData == 0x00) + { + cAddress = 0x0a; + i2c_master_send( client, (char*)&cAddress, 1); + i2c_master_recv( client, (char*)&cData, 1); + dbg( "i2c Read 0x0a = %d \n", cData); + if( cData == 0x88) + { + cAddress = 0x0b; + i2c_master_send( client, (char*)&cAddress, 1); + i2c_master_recv( client, (char*)&cData, 1); + dbg( "i2c Read 0x0b = %d \n", cData); + if( cData == 0x08) + { + dbg( "DMT_DEVICE_NAME registered I2C driver!\n"); + l_sensorconfig.client = client; + } + else + { + dbg( "err : i2c Read 0x0B = %d!\n",cData); + l_sensorconfig.client = NULL; + return -1; + } + } + else + { + dbg( "err : i2c Read 0x0A = %d!\n",cData); + l_sensorconfig.client = NULL; + return -1; + } + } + else + { + dbg( "err : i2c Read 0x09 = %d!\n",cData); + l_sensorconfig.client = NULL; + return -1; + } + } + else + { + dbg( "err : i2c Read 0x08 = %d!\n",cData); + l_sensorconfig.client = NULL; + + return -1; + } + + /* set sampling period if samp = 1, set the sampling frequency = 684 + otherwise set the sample frequency = 342 (default) added by eason 2012/3/7*/ + if (l_sensorconfig.samp == 1) { + buffer[0] = 0x08; + buffer[1] = 0x04; + dmard08_i2c_xyz_write_reg(client, buffer, 2); + } + + /*check sensorlayout[i][j] //eason + for(i = 0; i < 3; ++i) + { + for(j = 0; j < 3; j++) + printk("%d",sensorlayout[i][j]); + printk("\n"); + } */ + + return 0; +} + +static int __devexit dmard08_i2c_remove(struct i2c_client *client) //OK +{ + dbg("...\n"); + + return 0; +} + +/* +static int dmard08_i2c_resume(struct i2c_client *client) //OK +{ + dbg("...\n"); + + return 0; +} +*/ +static int get_axisset(void) +{ + char varbuf[64]; + int n; + int varlen; + + memset(varbuf, 0, sizeof(varbuf)); + varlen = sizeof(varbuf); + if (wmt_getsyspara("wmt.io.dm08sensor", varbuf, &varlen)) { + errlog("Can't get gsensor config in u-boot!!!!\n"); + return -1; + } else { + n = sscanf(varbuf, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", + &l_sensorconfig.op, + &l_sensorconfig.int_gpio, + &l_sensorconfig.samp, + &(l_sensorconfig.xyz_axis[0][0]), + &(l_sensorconfig.xyz_axis[0][1]), + &(l_sensorconfig.xyz_axis[1][0]), + &(l_sensorconfig.xyz_axis[1][1]), + &(l_sensorconfig.xyz_axis[2][0]), + &(l_sensorconfig.xyz_axis[2][1]), + &(l_sensorconfig.offset[0]), + &(l_sensorconfig.offset[1]), + &(l_sensorconfig.offset[2]) + ); + if (n != 12) { + errlog("gsensor format is error in u-boot!!!\n"); + return -1; + } + l_sensorconfig.sensor_samp = l_sensorconfig.samp; + + dbg("get the sensor config: %d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d\n", + l_sensorconfig.op, + l_sensorconfig.int_gpio, + l_sensorconfig.samp, + l_sensorconfig.xyz_axis[0][0], + l_sensorconfig.xyz_axis[0][1], + l_sensorconfig.xyz_axis[1][0], + l_sensorconfig.xyz_axis[1][1], + l_sensorconfig.xyz_axis[2][0], + l_sensorconfig.xyz_axis[2][1], + l_sensorconfig.offset[0], + l_sensorconfig.offset[1], + l_sensorconfig.offset[2] + ); + } + return 0; +} + +static void dmard08_platform_release(struct device *device) +{ + dbg("...\n"); + return; +} + + +static struct platform_device dmard08_device = { + .name = GSENSOR_I2C_NAME, + .id = 0, + .dev = { + .release = dmard08_platform_release, + }, +}; + +static int dmard08_suspend(struct platform_device *pdev, pm_message_t state) +{ + dbg("...\n"); + cancel_delayed_work_sync(&l_sensorconfig.work); + + return 0; +} + + +static int dmard08_open(struct inode *node, struct file *fle) +{ + dbg("open...\n"); + return 0; +} + +/* release command for dmard08 device file */ +static int dmard08_close(struct inode *node, struct file *fle) +{ + dbg("close...\n"); + return 0; +} + +/* ioctl command for dmard08 device file */ +static long dmard08_ioctl(/*struct inode *inode,*/ struct file *file, unsigned int cmd, unsigned long arg) +{ + int err = 0; + //unsigned char data[6]; + short delay = 0; + short enable = 0; + unsigned int uval = 0; + + if (WMT_IOCTL_SENSOR_CAL_OFFSET == cmd) + { + return 0;// now do nothing + } + + /* cmd mapping */ + mutex_lock(&sense_data_mutex); + switch(cmd) + { + + case ECS_IOCTL_APP_SET_DELAY: + // set the rate of g-sensor + dbg("ECS_IOCTL_APP_SET_DELAY\n"); + if (copy_from_user(&delay,(short*)arg, sizeof(short))) + { + errlog("Can't get set delay!!!\n"); + err = -EFAULT; + goto errioctl; + } + klog("set delay=%d \n", delay); + //klog("before change sensor sample:%d...\n", l_sensorconfig.sensor_samp); + if ((delay >=0) && (delay < 20)) + { + delay = 20; + } else if (delay > 200) + { + delay = 200; + } + if (delay > 0) + { + l_sensorconfig.sensor_samp = 1000/delay; + } else { + errlog("error delay argument(delay=%d)!!!\n",delay); + err = -EFAULT; + goto errioctl; + } + break; + case ECS_IOCTL_APP_SET_AFLAG: + dbg("ECS_IOCTL_APP_SET_AFLAG\n"); + // enable/disable sensor + if (copy_from_user(&enable, (short*)arg, sizeof(short))) + { + errlog("Can't get enable flag!!!\n"); + err = -EFAULT; + goto errioctl; + } + if ((enable >=0) && (enable <=1)) + { + dbg("driver: disable/enable(%d) gsensor.\n", enable); + + if (enable != l_sensorconfig.sensor_enable) + { + // do sth ??? + //mma_enable_disable(enable); + /*if (enable != 0) + { + queue_delayed_work(l_sensorconfig.queue, &l_sensorconfig.work, msecs_to_jiffies(sample_rate_2_memsec(l_sensorconfig.sensor_samp))); + } else { + cancel_delayed_work_sync(&l_sensorconfig.work); + flush_workqueue(l_sensorconfig.queue); + }*/ + l_sensorconfig.sensor_enable = enable; + + } + } else { + errlog("Wrong enable argument!!!\n"); + err = -EFAULT; + goto errioctl; + } + break; + case WMT_IOCTL_SENSOR_GET_DRVID: + uval = DMARD08_DRVID; + if (copy_to_user((unsigned int*)arg, &uval, sizeof(unsigned int))) + { + return -EFAULT; + } + dbg("dmard08_driver_id:%d\n",uval); + break; + default: + break; + } +errioctl: + mutex_unlock(&sense_data_mutex); + return err; +} + +/* +static ssize_t dmard08_read(struct file *file, char __user *buf, size_t count, loff_t *offset) +{ + struct que_data data; + short xyz_temp[3]; + + // read data from cycle queue + while (clque_is_empty()) msleep(10); + clque_out(&data); + xyz_temp[0] = data.data[0]; + xyz_temp[1] = data.data[1]; + xyz_temp[2] = data.data[2]; + + + if(copy_to_user(buf, &xyz_temp, sizeof(xyz_temp))) + return -EFAULT; + dbg("x=%x,y=%x,z=%x\n",xyz_temp[0], xyz_temp[1], xyz_temp[2]); + return sizeof(xyz_temp); +} +*/ +/* +static ssize_t dmard08_write(struct file *file, const char __user *buf, size_t count, loff_t *offset) +{ + dbg("write...\n"); + return 0; +} +*/ + +static const struct file_operations d08_fops = { + .owner = THIS_MODULE, + .open = dmard08_open, + .release = dmard08_close, + //.read = dmard08_read, + //.wirte = dmard08_write, + .unlocked_ioctl = dmard08_ioctl, +}; + +static struct miscdevice d08_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = GSENSOR_DEV_NODE, + .fops = &d08_fops, +}; + + +static int dmard08_resume(struct platform_device *pdev) +{ + char buffer[2]; + dbg("...\n"); + + if (l_sensorconfig.samp == 1) { + buffer[0] = 0x08; + buffer[1] = 0x04; + dmard08_i2c_xyz_write_reg(l_sensorconfig.client, buffer, 2); + } + + queue_delayed_work(l_sensorconfig.queue, &l_sensorconfig.work, msecs_to_jiffies(sample_rate_2_memsec(l_sensorconfig.sensor_samp))); + return 0; +} + +static int sensor_writeproc( struct file *file, + const char *buffer, + unsigned long count, + void *data ) +{ + + //int inputval = -1; + int enable, sample = -1; + char tembuf[8]; + //unsigned int amsr = 0; + int test = 0; + + mutex_lock(&sense_data_mutex); + memset(tembuf, 0, sizeof(tembuf)); + // get sensor level and set sensor level + if (sscanf(buffer, "isdbg=%d\n", &l_sensorconfig.isdbg)) + { + // only set the dbg flag + } else if (sscanf(buffer, "samp=%d\n", &sample)) + { + if (sample > 0) + { + if (sample != l_sensorconfig.sensor_samp) + { + // should do sth + } + //printk(KERN_ALERT "sensor samp=%d(amsr:%d) has been set.\n", sample, amsr); + } else { + klog("Wrong sample argumnet of sensor.\n"); + } + } else if (sscanf(buffer, "enable=%d\n", &enable)) + { + if ((enable < 0) || (enable > 1)) + { + klog("The argument to enable/disable g-sensor should be 0 or 1 !!!\n"); + } else if (enable != l_sensorconfig.sensor_enable) + { + //mma_enable_disable(enable); + l_sensorconfig.sensor_enable = enable; + } + } else if (sscanf(buffer, "sensor_test=%d\n", &test)) + { // for test begin + l_sensorconfig.test_pass = 0; + } else if (sscanf(buffer, "sensor_testend=%d\n", &test)) + { // Don nothing only to be compatible the before testing program + } + mutex_unlock(&sense_data_mutex); + return count; +} + +static int sensor_readproc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = 0; + + len = sprintf(page, + "test_pass=%d\nisdbg=%d\nrate=%d\nenable=%d\n", + l_sensorconfig.test_pass, + l_sensorconfig.isdbg, + l_sensorconfig.sensor_samp, + l_sensorconfig.sensor_enable + ); + return len; +} + +static void read_work_func(struct work_struct *work) +{ + s16 xyz[SENSOR_DATA_SIZE]; + s16 txyz[SENSOR_DATA_SIZE]; + + if (! l_sensorconfig.sensor_enable) + { + // no report data + queue_delayed_work(l_sensorconfig.queue, &l_sensorconfig.work, msecs_to_jiffies(sample_rate_2_memsec(l_sensorconfig.sensor_samp))); + return; + } + // read data to one cycle que + //dbg("read...\n"); + dmard08_i2c_read_xyz(l_sensorconfig.client, (s16 *)xyz); + + // x + txyz[0] = xyz[l_sensorconfig.xyz_axis[0][0]]*l_sensorconfig.xyz_axis[0][1]+l_sensorconfig.offset[0]; + // y + txyz[1] = xyz[l_sensorconfig.xyz_axis[1][0]]*l_sensorconfig.xyz_axis[1][1]+l_sensorconfig.offset[1]; + // z + txyz[2] = xyz[l_sensorconfig.xyz_axis[2][0]]*l_sensorconfig.xyz_axis[2][1]+l_sensorconfig.offset[2]; + + input_report_abs(l_sensorconfig.input_dev, ABS_X, txyz[0]); + input_report_abs(l_sensorconfig.input_dev, ABS_Y, txyz[1]); + input_report_abs(l_sensorconfig.input_dev, ABS_Z, txyz[2]); + input_sync(l_sensorconfig.input_dev); + l_sensorconfig.test_pass = 1; // for testing + // read next + queue_delayed_work(l_sensorconfig.queue, &l_sensorconfig.work, msecs_to_jiffies(sample_rate_2_memsec(l_sensorconfig.sensor_samp))); +} + + +static int dmard08_probe(struct platform_device *pdev) +{ + int err = 0; + + //register ctrl dev + err = misc_register(&d08_device); + if (err !=0) { + errlog("Can't register d08_device!\n"); + return -1; + } + // register rd/wr proc + l_sensorconfig.sensor_proc = create_proc_entry(GSENSOR_PROC_NAME, 0666, NULL/*&proc_root*/); + if (l_sensorconfig.sensor_proc != NULL) + { + l_sensorconfig.sensor_proc->write_proc = sensor_writeproc; + l_sensorconfig.sensor_proc->read_proc = sensor_readproc; + } + // init work queue + l_sensorconfig.queue = create_singlethread_workqueue("sensor-report"); + INIT_DELAYED_WORK(&l_sensorconfig.work, read_work_func); + mutex_init(&sense_data_mutex); + // init input device + l_sensorconfig.input_dev = input_allocate_device(); + if (!l_sensorconfig.input_dev) { + err = -ENOMEM; + errlog("Failed to allocate input device\n"); + goto exit_input_dev_alloc_failed; + } + l_sensorconfig.input_dev->evbit[0] = BIT(EV_ABS) | BIT_MASK(EV_KEY); + /* x-axis acceleration */ + input_set_abs_params(l_sensorconfig.input_dev, ABS_X, -1024, 1024, 0, 0); + /* y-axis acceleration */ + input_set_abs_params(l_sensorconfig.input_dev, ABS_Y, -1024, 1024, 0, 0); + /* z-axis acceleration */ + input_set_abs_params(l_sensorconfig.input_dev, ABS_Z, -1024, 1024, 0, 0); + + l_sensorconfig.input_dev->name = GSENSOR_INPUT_NAME; + + err = input_register_device(l_sensorconfig.input_dev); + + if (err) { + errlog("Unable to register input device: %s\n", + l_sensorconfig.input_dev->name); + goto exit_input_register_device_failed; + } + + return 0; +exit_input_register_device_failed: + // free inut + input_free_device(l_sensorconfig.input_dev); +exit_input_dev_alloc_failed: + // free queue + destroy_workqueue(l_sensorconfig.queue); + l_sensorconfig.queue = NULL; + // free proc + if (l_sensorconfig.sensor_proc != NULL) + { + remove_proc_entry(GSENSOR_PROC_NAME, NULL); + l_sensorconfig.sensor_proc = NULL; + } + // free work + // unregister ctrl dev + misc_deregister(&d08_device); + return err; +} + +static int dmard08_remove(struct platform_device *pdev) +{ + if (NULL != l_sensorconfig.queue) + { + cancel_delayed_work_sync(&l_sensorconfig.work); + flush_workqueue(l_sensorconfig.queue); + destroy_workqueue(l_sensorconfig.queue); + l_sensorconfig.queue = NULL; + } + if (l_sensorconfig.sensor_proc != NULL) + { + remove_proc_entry(GSENSOR_PROC_NAME, NULL); + l_sensorconfig.sensor_proc = NULL; + } + misc_deregister(&d08_device); + input_unregister_device(l_sensorconfig.input_dev); + return 0; +} + + +static struct platform_driver dmard08_driver = { + .probe = dmard08_probe, + .remove = dmard08_remove, + .suspend = dmard08_suspend, + .resume = dmard08_resume, + .driver = { + .name = GSENSOR_I2C_NAME, + }, +}; + +#if 0 +static void dmard08_early_suspend(struct early_suspend *h) +{ + dbg("start\n"); + cancel_delayed_work_sync(&l_sensorconfig.work); + dbg("exit\n"); +} + +static void dmard08_late_resume(struct early_suspend *h) +{ + dbg("start\n"); + // init + queue_delayed_work(l_sensorconfig.queue, &l_sensorconfig.work, msecs_to_jiffies(sample_rate_2_memsec(l_sensorconfig.sensor_samp))); + dbg("exit\n"); +} +#endif + +static int __init dmard08_init(void) //OK +{ + int ret = 0; + + // parse g-sensor u-boot arg + ret = get_axisset(); + if (ret < 0) + { + printk("<<<<<%s user choose to no sensor chip!\n", __func__); + return ret; + } + /*if ((ret != 0) || !l_sensorconfig.op) + { + dbg("Can't load gsensor dmar08 driver for error u-boot arg!\n"); + return -EINVAL; + }*/ + if (!(this_client = sensor_i2c_register_device(0, GSENSOR_I2C_ADDR, GSENSOR_I2C_NAME))) + { + printk(KERN_EMERG"Can't register gsensor i2c device!\n"); + return -1; + } + // find the device + /*if(i2c_add_driver(&dmard08_i2c_driver) != 0) + { + ret = -1; + dbg("Can't find gsensor dmard08!\n"); + goto err_i2c_add_driver; + }*/ + if(dmard08_hw_init(this_client)) + { + ret = -1; + dbg("Can't find gsensor dmard08!\n"); + goto err_i2c_add_driver; + } + + + // create the platform device + l_dev_class = class_create(THIS_MODULE, GSENSOR_I2C_NAME); + if (IS_ERR(l_dev_class)){ + ret = PTR_ERR(l_dev_class); + printk(KERN_ERR "Can't class_create gsensor device !!\n"); + return ret; + } + if((ret = platform_device_register(&dmard08_device))) + { + klog("Can't register mc3230 platform devcie!!!\n"); + return ret; + } + if ((ret = platform_driver_register(&dmard08_driver)) != 0) + { + errlog("Can't register mc3230 platform driver!!!\n"); + return ret; + } +#ifdef CONFIG_HAS_EARLYSUSPEND + l_sensorconfig.earlysuspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + l_sensorconfig.earlysuspend.suspend = dmard08_early_suspend; + l_sensorconfig.earlysuspend.resume = dmard08_late_resume; + register_early_suspend(&l_sensorconfig.earlysuspend); +#endif + + queue_delayed_work(l_sensorconfig.queue, &l_sensorconfig.work, msecs_to_jiffies(sample_rate_2_memsec(l_sensorconfig.sensor_samp))); + + return 0; + +err_i2c_add_driver: + sensor_i2c_unregister_device(this_client); + return ret; +} + +static void __exit dmard08_exit(void) //OK +{ + platform_driver_unregister(&dmard08_driver); + platform_device_unregister(&dmard08_device); + class_destroy(l_dev_class); + sensor_i2c_unregister_device(this_client); +} + +//********************************************************************************************************* +// 2011-11-30 +// Add by Steve Huang +// function definition +/* +void gsensor_write_offset_to_file(void) +{ + char data[18]; + unsigned int orgfs; + long lfile=-1; + + //sprintf(data,"%5d %5d %5d",offset.u.x,offset.u.y,offset.u.z); //marked by eason check again + + orgfs = get_fs(); +// Set segment descriptor associated to kernel space + set_fs(KERNEL_DS); + + lfile=sys_open(OffsetFileName,O_WRONLY|O_CREAT, 0777); + if (lfile < 0) + { + printk("sys_open %s error!!. %ld\n",OffsetFileName,lfile); + } + else + { + sys_write(lfile, data,18); + sys_close(lfile); + } + set_fs(orgfs); + + return; +} + +void gsensor_read_offset_from_file(void) +{ + unsigned int orgfs; + char data[18]; + long lfile=-1; + orgfs = get_fs(); +// Set segment descriptor associated to kernel space + set_fs(KERNEL_DS); + + lfile=sys_open(OffsetFileName, O_RDONLY, 0); + if (lfile < 0) + { + printk("sys_open %s error!!. %ld\n",OffsetFileName,lfile); + if(lfile==-2) + { + lfile=sys_open(OffsetFileName,O_WRONLY|O_CREAT, 0777); + if(lfile >=0) + { + strcpy(data,"00000 00000 00000"); + printk("sys_open %s OK!!. %ld\n",OffsetFileName,lfile); + sys_write(lfile,data,18); + sys_read(lfile, data, 18); + sys_close(lfile); + } + else + printk("sys_open %s error!!. %ld\n",OffsetFileName,lfile); + } + + } + else + { + sys_read(lfile, data, 18); + sys_close(lfile); + } + //sscanf(data,"%hd %hd %hd",&offset.u.x,&offset.u.y,&offset.u.z); //marked by eason check again + set_fs(orgfs); + +} +*/ +//********************************************************************************************************* +MODULE_AUTHOR("DMT_RD"); +MODULE_DESCRIPTION("DMARD08 g-sensor Driver"); +MODULE_LICENSE("GPL"); + +module_init(dmard08_init); +module_exit(dmard08_exit); + diff --git a/ANDROID_3.4.5/drivers/input/sensor/dmard08_gsensor/dmard08.h b/ANDROID_3.4.5/drivers/input/sensor/dmard08_gsensor/dmard08.h new file mode 100755 index 00000000..e6a6c935 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/dmard08_gsensor/dmard08.h @@ -0,0 +1,75 @@ +/* + * @file include/linux/dmard08.h + * @brief DMT g-sensor Linux device driver + * @author Domintech Technology Co., Ltd (http://www.domintech.com.tw) + * @version 1.2 + * @date 2011/11/14 + * + * @section LICENSE + * + * Copyright 2011 Domintech Technology Co., Ltd + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + * + */ +#ifndef DMARD08_H +#define DMARD08_H + +#define GSENSOR_I2C_NAME "dmard08" +#define GSENSOR_I2C_ADDR 0x1c +/* +#define DEVICE_I2C_NAME "dmard08" + +//#define DMT_DEBUG_DATA 1 +#define DMT_DEBUG_DATA 0 + +#if DMT_DEBUG_DATA +#define IN_FUNC_MSG printk(KERN_INFO "@DMT@ In %s\n", __func__) +#define PRINT_X_Y_Z(x, y, z) printk(KERN_INFO "@DMT@ X/Y/Z axis: %04d , %04d , %04d\n", (x), (y), (z)) +#define PRINT_OFFSET(x, y, z) printk(KERN_INFO "@offset@ X/Y/Z axis: %04d , %04d , %04d\n",offset.x,offset.y,offset.z); +#else +#define IN_FUNC_MSG +#define PRINT_X_Y_Z(x, y, z) +#define PRINT_OFFSET(x, y, z) +#endif +*/ + +//g-senor layout configuration, choose one of the following configuration +#define CONFIG_GSEN_LAYOUT_PAT_1 +//#define CONFIG_GSEN_LAYOUT_PAT_2 +//#define CONFIG_GSEN_LAYOUT_PAT_3 +//#define CONFIG_GSEN_LAYOUT_PAT_4 +//#define CONFIG_GSEN_LAYOUT_PAT_5 +//#define CONFIG_GSEN_LAYOUT_PAT_6 +//#define CONFIG_GSEN_LAYOUT_PAT_7 +//#define CONFIG_GSEN_LAYOUT_PAT_8 + +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Z_NEGATIVE 1 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Z_POSITIVE 2 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Y_NEGATIVE 3 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Y_POSITIVE 4 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_X_NEGATIVE 5 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_X_POSITIVE 6 + +#define DEFAULT_SENSITIVITY 256 +#define IOCTL_MAGIC 0x09 +#define SENSOR_DATA_SIZE 3 + +#define SENSOR_RESET _IO(IOCTL_MAGIC, 0) +#define SENSOR_CALIBRATION _IOWR(IOCTL_MAGIC, 1, int[SENSOR_DATA_SIZE]) +#define SENSOR_GET_OFFSET _IOR(IOCTL_MAGIC, 2, int[SENSOR_DATA_SIZE]) +#define SENSOR_SET_OFFSET _IOWR(IOCTL_MAGIC, 3, int[SENSOR_DATA_SIZE]) +#define SENSOR_READ_ACCEL_XYZ _IOR(IOCTL_MAGIC, 4, int[SENSOR_DATA_SIZE]) + +#define SENSOR_MAXNR 4 + +#endif + diff --git a/ANDROID_3.4.5/drivers/input/sensor/dmard09_gsensor/Makefile b/ANDROID_3.4.5/drivers/input/sensor/dmard09_gsensor/Makefile new file mode 100755 index 00000000..d9242020 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/dmard09_gsensor/Makefile @@ -0,0 +1,35 @@ +KERNELDIR=../../../../ +#KERNELDIR=/home/hangyan/android8850/kernel/ANDROID_3.0.8 +CROSS = arm_1103_le- +CC= $(CROSS)gcc +LD= $(CROSS)ld +STRIP = $(CROSS)strip + +DEBUG = n + +# Add your debugging flag (or not) to EXTRA_CFLAGS +ifeq ($(DEBUG),y) +# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines +DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines + +else + DEBFLAGS = -O2 -Wall +endif + + +EXTRA_CFLAGS += $(DEBFLAGS) + + +MY_MODULE_NAME=s_wmt_gsensor_dmard09 + +obj-m := $(MY_MODULE_NAME).o +$(MY_MODULE_NAME)-objs := dmt09.o + +default: + $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules + $(STRIP) --strip-debug $(MY_MODULE_NAME).ko + rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions + +clean: + rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers + diff --git a/ANDROID_3.4.5/drivers/input/sensor/dmard09_gsensor/dmt09.c b/ANDROID_3.4.5/drivers/input/sensor/dmard09_gsensor/dmt09.c new file mode 100755 index 00000000..90b03aa3 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/dmard09_gsensor/dmt09.c @@ -0,0 +1,1685 @@ +/* + * @file drivers/misc/dmt09.c + * @brief DMT g-sensor Linux device driver + * @author Domintech Technology Co., Ltd (http://www.domintech.com.tw) + * @version 1.06 + * @date 2013/08/14 + * @section LICENSE + * + * Copyright 2012 Domintech Technology Co., Ltd + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ +#include "dmt09.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../sensor.h" + +////////////////////////////////////////////////////////// +static struct wmt_gsensor_data l_sensorconfig = { + .op = 0, + .int_gpio = 3, + .samp = 5, + .xyz_axis = { + {ABS_X, -1}, + {ABS_Y, 1}, + {ABS_Z, -1}, + }, + .sensor_proc = NULL, + .isdbg = 0, + .sensor_samp = 10, // 1 sample/second + .sensor_enable = 1, // enable sensor + .test_pass = 0, // for test program + .offset={0,0,0}, +}; + +static struct class* l_dev_class = NULL; +static void update_var(void); + +//////////////////////////////////////////////////////////// + + +static unsigned int interval; +static int D09_write_offset_to_file(struct i2c_client *client); +void D09_read_offset_from_file(struct i2c_client *client); +#define DMT_BROADCAST_APK_ENABLE +char D09_OffsetFileName[] = "/data/misc/gsensor_offset.txt";//"/system/vendor/dmt/gsensor_offset.txt";// /* FILE offset.txt */ +char DmtXXFileName[] = "/data/misc/dmt_sensor.txt";//"/system/vendor/dmt/dmt_sensor.txt";// +static int create_devidfile(void); +static struct dmt_data *s_dmt; +static int device_init(void); +static void device_exit(void); + +static int device_open(struct inode*, struct file*); +static long device_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); +static int device_close(struct inode*, struct file*); + +static int dmard09_suspend(struct platform_device *pdev, pm_message_t state); +static int dmard09_resume(struct platform_device *pdev); + +/*static int device_i2c_suspend(struct i2c_client *client, pm_message_t mesg); +static int device_i2c_resume(struct i2c_client *client); +static int __devinit device_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id); +static int __devexit device_i2c_remove(struct i2c_client *client);*/ +static int D09_i2c_read_xyz(struct i2c_client *client, int *xyz); +static int device_i2c_rxdata(struct i2c_client *client, unsigned char *rxDat, int length); +static int device_i2c_txdata(struct i2c_client *client, unsigned char *txData, int length); + +static int dmt_get_filter(struct i2c_client *client); +static int dmt_set_filter(struct i2c_client *client,int); +static int dmt_get_position(struct i2c_client *client); +static int dmt_set_position(struct i2c_client *client,int); +static int DMT_GetOpenStatus(struct i2c_client *client){ + struct dmt_data *dmt = i2c_get_clientdata(client); + GSE_LOG("start active=%d\n",dmt->active.counter); + wait_event_interruptible(dmt->open_wq, (atomic_read(&dmt->active) != 0)); + return 0; +} + +static int DMT_GetCloseStatus(struct i2c_client *client){ + struct dmt_data *dmt = i2c_get_clientdata(client); + GSE_LOG("start active=%d\n",dmt->active.counter); + wait_event_interruptible(dmt->open_wq, (atomic_read(&dmt->active) <= 0)); + return 0; +} + +static void DMT_sysfs_update_active_status(struct dmt_data *dmt , int en){ + unsigned long dmt_delay; + if(en){ + dmt_delay=msecs_to_jiffies(atomic_read(&dmt->delay)); + if(dmt_delay<1) + dmt_delay=1; + + GSE_LOG("schedule_delayed_work start with delay time=%lu\n",dmt_delay); + schedule_delayed_work(&dmt->delaywork,dmt_delay); + } + else + cancel_delayed_work_sync(&dmt->delaywork); +} + +static bool get_value_as_int(char const *buf, size_t size, int *value){ + long tmp; + if (size == 0) + return false; + /* maybe text format value */ + if ((buf[0] == '0') && (size > 1)) { + if ((buf[1] == 'x') || (buf[1] == 'X')) { + /* hexadecimal format */ + if (0 != strict_strtol(buf, 16, &tmp)) + return false; + } else { + /* octal format */ + if (0 != strict_strtol(buf, 8, &tmp)) + return false; + } + } else { + /* decimal format */ + if (0 != strict_strtol(buf, 10, &tmp)) + return false; + } + + if (tmp > INT_MAX) + return false; + + *value = tmp; + return true; +} +static bool get_value_as_int64(char const *buf, size_t size, long long *value) +{ + long long tmp; + if (size == 0) + return false; + /* maybe text format value */ + if ((buf[0] == '0') && (size > 1)) { + if ((buf[1] == 'x') || (buf[1] == 'X')) { + /* hexadecimal format */ + if (0 != strict_strtoll(buf, 16, &tmp)) + return false; + } else { + /* octal format */ + if (0 != strict_strtoll(buf, 8, &tmp)) + return false; + } + } else { + /* decimal format */ + if (0 != strict_strtoll(buf, 10, &tmp)) + return false; + } + + if (tmp > LLONG_MAX) + return false; + + *value = tmp; + return true; +} +/* sysfs enable show & store */ +static ssize_t dmt_sysfs_enable_show( + struct dmt_data *dmt, char *buf, int pos) +{ + char str[2][16]={"ACC enable OFF","ACC enable ON"}; + int flag; + flag=atomic_read(&dmt->enable); + return sprintf(buf, "%s\n", str[flag]); +} + +static ssize_t dmt_sysfs_enable_store( + struct dmt_data *dmt, char const *buf, size_t count, int pos) +{ + int en = 0; + if (NULL == buf) + return -EINVAL; + //GSE_LOG("buf=%x %x\n", buf[0], buf[1]); + if (0 == count) + return 0; + + if (false == get_value_as_int(buf, count, &en)) + return -EINVAL; + + en = en ? 1 : 0; + + atomic_set(&dmt->enable,en); + DMT_sysfs_update_active_status(dmt , en); + return count; +} + +static ssize_t dmt_enable_show(struct device *dev, struct device_attribute *attr, char *buf){ + return dmt_sysfs_enable_show( dev_get_drvdata(dev), buf, ACC_DATA_FLAG); +} + +static ssize_t dmt_enable_store( struct device *dev, struct device_attribute *attr, char const *buf, size_t count){ + return dmt_sysfs_enable_store( dev_get_drvdata(dev), buf, count, ACC_DATA_FLAG); +} + +/* sysfs delay show & store*/ +static ssize_t dmt_sysfs_delay_show( struct dmt_data *dmt, char *buf, int pos){ + return sprintf(buf, "%d\n", atomic_read(&dmt->delay)); +} + +static ssize_t dmt_sysfs_delay_store( struct dmt_data *dmt, char const *buf, size_t count, int pos){ + long long val = 0; + + if (NULL == buf) + return -EINVAL; + + if (0 == count) + return 0; + + if (false == get_value_as_int64(buf, count, &val)) + return -EINVAL; + + atomic_set(&dmt->delay, (unsigned int) val); + GSE_LOG("Driver attribute set delay =%lld\n", val); + + return count; +} + +static ssize_t dmt_delay_show( struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return dmt_sysfs_delay_show( dev_get_drvdata(dev), buf, ACC_DATA_FLAG); +} + +static ssize_t dmt_delay_store( struct device *dev, + struct device_attribute *attr, + char const *buf, + size_t count) +{ + return dmt_sysfs_delay_store( dev_get_drvdata(dev), buf, count, ACC_DATA_FLAG); +} +/* sysfs position show & store */ +static ssize_t dmt_position_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct dmt_data *dmt = input_get_drvdata(input); + + return sprintf(buf, "%d\n", dmt_get_position(dmt->client)); +} + +static ssize_t dmt_position_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct input_dev *input = to_input_dev(dev); + struct dmt_data *dmt = input_get_drvdata(input); + unsigned long position; + int ret; + + ret = strict_strtoul(buf, 10, &position); + if (ret < 0) + return count; + + dmt_set_position(dmt->client, position); + return count; +} +/* sysfs offset show & store */ +static ssize_t dmt_offset_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct dmt_data *dmt = input_get_drvdata(input); + return sprintf(buf, "( %d %d %d )\n", dmt->offset.u.x, dmt->offset.u.y, dmt->offset.u.z); +} + +static ssize_t dmt_offset_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct input_dev *input = to_input_dev(dev); + struct dmt_data *dmt = input_get_drvdata(input); + sscanf(buf, "%d %d %d", (int *)&dmt->offset.v[0], (int *)&dmt->offset.v[1], (int *)&dmt->offset.v[2]); + D09_write_offset_to_file(dmt->client); + update_var(); + return count; +} +/* sysfs filter show & store */ +static ssize_t dmt_filter_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct dmt_data *dmt = input_get_drvdata(input); + + return sprintf(buf, "%d\n", dmt_get_filter(dmt->client)); +} + +static ssize_t dmt_filter_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct input_dev *input = to_input_dev(dev); + struct dmt_data *dmt = input_get_drvdata(input); + unsigned long filter; + int ret; + + ret = strict_strtoul(buf, 10, &filter); + if (ret < 0) + return count; + + dmt_set_filter(dmt->client, filter); + return count; +} + +/* sysfs data show */ +static ssize_t dmt_acc_private_data_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct dmt_data *dmt = input_get_drvdata(input); + raw_data accel; + + mutex_lock(&dmt->data_mutex); + accel = dmt->last; + mutex_unlock(&dmt->data_mutex); + + return sprintf(buf, "( %d %d %d )\n", dmt->last.v[0], dmt->last.v[1], dmt->last.v[2]); +} +/* sysfs id show */ +static ssize_t dmt_id_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + char str[8]={GSENSOR_ID}; + return sprintf(buf, "%s\n", str); +} +/* sysfs debug_suspend show & store */ +#ifdef DMT_DEBUG_DATA +static ssize_t dmt_debug_suspend_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct dmt_data *dmt = input_get_drvdata(input); + int suspend = dmt->suspend; + + mutex_lock(&dmt->suspend_mutex); + suspend = sprintf(buf, "%d\n", dmt->suspend); + mutex_unlock(&dmt->suspend_mutex); + return suspend; +} + +static ssize_t dmt_debug_suspend_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct input_dev *input = to_input_dev(dev); + struct dmt_data *dmt = input_get_drvdata(input); + unsigned long suspend; + pm_message_t msg; + int ret; + + ret = strict_strtoul(buf, 10, &suspend); + if (ret < 0) + return count; + + memset(&msg, 0, sizeof(pm_message_t)); + + mutex_lock(&dmt->suspend_mutex); + + if (suspend) { + dmard09_suspend(dmt->pdevice, msg); + dmt->suspend = 1; + } else { + dmard09_resume(dmt->pdevice); + dmt->suspend = 0; + } + + mutex_unlock(&dmt->suspend_mutex); + + return count; +} +/* sysfs reg_read show & store */ +static ssize_t dmt_reg_read_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct dmt_data *dmt = dev_get_drvdata(dev); + int err; + unsigned char i2c[1]; + + i2c[0] = (unsigned char)atomic_read(&dmt->addr); + err = device_i2c_rxdata(dmt->client, i2c, 1); + if (err < 0) + return err; + + return sprintf(buf, "0x%02X\n", i2c[0]); +} + +static ssize_t dmt_reg_read_store(struct device *dev, + struct device_attribute *attr, + char const *buf, + size_t count) +{ + struct dmt_data *dmt = dev_get_drvdata(dev); + int addr = 0; + + if (NULL == buf) + return -EINVAL; + + if (0 == count) + return 0; + + if (false == get_value_as_int(buf, count, &addr)) + return -EINVAL; + + if (addr < 0 || 128 < addr) + return -EINVAL; + + atomic_set(&dmt->addr, addr); + + return 1; +} +#endif /* DEBUG */ +/********************************************************************* + * + * SysFS attribute functions + * + * directory : /sys/class/accelemeter/dmardXX/ + * files : + * - enable_acc [rw] [t] : enable flag for accelerometer + * - delay_acc [rw] [t] : delay in nanosecond for accelerometer + * - position [rw] [t] : chip mounting position + * - offset [rw] [t] : offset + * - data [r] [t] : raw data + * - id [r] [t] : chip id + * + * debug : + * - debug_suspend [w] [t] : suspend test + * - reg_read [rw] [t] : Read register + * - reg_write [rw] [t] : Weite register + * + * [rw]= read/write + * [r] = read only + * [w] = write only + * [b] = binary format + * [t] = text format + */ + +static struct device_attribute DMT_attributes[] = { + __ATTR(enable_acc, 0660, dmt_enable_show, dmt_enable_store), + __ATTR(delay_acc, 0660, dmt_delay_show, dmt_delay_store), + __ATTR(position, 0660, dmt_position_show, dmt_position_store), + __ATTR(offset, 0660, dmt_offset_show, dmt_offset_store), + __ATTR(filter, 0660, dmt_filter_show, dmt_filter_store), + __ATTR(data, 0660, dmt_acc_private_data_show, NULL), + __ATTR(id, 0660, dmt_id_show, NULL), +#ifdef DMT_DEBUG_DATA + __ATTR(debug_suspend, 0660, dmt_debug_suspend_show,dmt_debug_suspend_store), + __ATTR(reg_read, 0660, dmt_reg_read_show, dmt_reg_read_store), + __ATTR(reg_write, 0660, NULL, NULL), +#endif // DEBUG + __ATTR_NULL, +}; + +static char const *const ACCELEMETER_CLASS_NAME = "accelemeter"; +static char const *const GSENSOR_DEVICE_NAME = SENSOR_I2C_NAME; +static char const *const device_link_name = "i2c"; +static dev_t const dmt_device_dev_t = MKDEV(MISC_MAJOR, MISC_DYNAMIC_MINOR); + +// dmt sysfs functions +static int create_device_attributes(struct device *dev, struct device_attribute *attrs){ + int i; + int err = 0; + for (i = 0 ; NULL != attrs[i].attr.name ; ++i) { + err = device_create_file(dev, &attrs[i]); + if (0 != err) + break; + } + + if (0 != err) { + for (; i >= 0 ; --i) + device_remove_file(dev, &attrs[i]); + } + return err; +} + +static void remove_device_attributes( + struct device *dev, + struct device_attribute *attrs) +{ + int i; + + for (i = 0 ; NULL != attrs[i].attr.name ; ++i) + device_remove_file(dev, &attrs[i]); +} + +static int create_sysfs_interfaces(struct dmt_data *dmt) +{ + int err; + + if (NULL == dmt) + return -EINVAL; + + err = 0; + dmt->class = class_create(THIS_MODULE, ACCELEMETER_CLASS_NAME); + if (IS_ERR(dmt->class)) { + err = PTR_ERR(dmt->class); + goto exit_class_create_failed; + } + + dmt->class_dev = device_create( + dmt->class, + NULL, + dmt_device_dev_t, + dmt, + GSENSOR_DEVICE_NAME); + if (IS_ERR(dmt->class_dev)) { + err = PTR_ERR(dmt->class_dev); + goto exit_class_device_create_failed; + } + + err = sysfs_create_link( + &dmt->class_dev->kobj, + &dmt->client->dev.kobj, + device_link_name); + if (0 > err) + goto exit_sysfs_create_link_failed; + + err = create_device_attributes( + dmt->class_dev, + DMT_attributes); + if (0 > err) + goto exit_device_attributes_create_failed; +#if 0 + err = create_device_binary_attributes( + &dmt->class_dev->kobj, + dmt_bin_attributes); + if (0 > err) + goto exit_device_binary_attributes_create_failed; +#endif + + return err; + +#if 0 +exit_device_binary_attributes_create_failed: + remove_device_attributes(dmt->class_dev, dmt_attributes); +#endif +exit_device_attributes_create_failed: + sysfs_remove_link(&dmt->class_dev->kobj, device_link_name); +exit_sysfs_create_link_failed: + device_destroy(dmt->class, dmt_device_dev_t); +exit_class_device_create_failed: + dmt->class_dev = NULL; + class_destroy(dmt->class); +exit_class_create_failed: + dmt->class = NULL; + return err; +} + +static void remove_sysfs_interfaces(struct dmt_data *dmt){ + if (NULL == dmt) + return; + + if (NULL != dmt->class_dev) { + + remove_device_attributes( + dmt->class_dev, + DMT_attributes); + sysfs_remove_link( + &dmt->class_dev->kobj, + device_link_name); + dmt->class_dev = NULL; + } + if (NULL != dmt->class) { + device_destroy( + dmt->class, + dmt_device_dev_t); + class_destroy(dmt->class); + dmt->class = NULL; + } +} + +int D09_input_init(struct i2c_client *client){ + struct dmt_data *dmt = i2c_get_clientdata(client); + int err = 0; + dmt->input = input_allocate_device(); + if (!dmt->input){ + GSE_ERR("input device allocate ERROR !!\n"); + return -ENOMEM; + } + else + GSE_LOG("input device allocate Success !!\n"); + /* Setup input device */ + //dmt->input->name = SENSOR_I2C_NAME; + set_bit(EV_ABS, dmt->input->evbit); + /* Accelerometer [-78.5, 78.5]m/s2 in Q16 */ + input_set_abs_params(dmt->input, ABS_X, ABSMIN, ABSMAX, 0, 0); + input_set_abs_params(dmt->input, ABS_Y, ABSMIN, ABSMAX, 0, 0); + input_set_abs_params(dmt->input, ABS_Z, ABSMIN, ABSMAX, 0, 0); + /* Set InputDevice Name */ + dmt->input->name = INPUT_NAME_ACC; + /* Register */ + err = input_register_device(dmt->input); + if (err) { + GSE_ERR("input_register_device ERROR !!\n"); + input_free_device(dmt->input); + return err; + } + GSE_LOG("input_register_device SUCCESS %d !! \n",err); + + return err; +} + +int D09_calibrate(struct i2c_client *client) +{ + struct dmt_data *dmt = i2c_get_clientdata(client); + raw_data avg; + int i, j; + long xyz_acc[SENSOR_DATA_SIZE]; + int xyz[SENSOR_DATA_SIZE]; + /* initialize the offset value */ + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + dmt->offset.v[i] = 0; + /* initialize the accumulation buffer */ + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + xyz_acc[i] = 0; + + for(i = 0; i < AVG_NUM; i++) { + D09_i2c_read_xyz(client, (int *)&xyz); + for(j = 0; j < SENSOR_DATA_SIZE; ++j) + xyz_acc[j] += xyz[j]; + } + /* calculate averages */ + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + avg.v[i] = xyz_acc[i] / AVG_NUM; + + if(avg.v[2] < 0){ + dmt->offset.u.x = avg.v[0] ; + dmt->offset.u.y = avg.v[1] ; + dmt->offset.u.z = avg.v[2] + DEFAULT_SENSITIVITY; + return CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Z_POSITIVE; + } + else{ + dmt->offset.u.x = avg.v[0] ; + dmt->offset.u.y = avg.v[1] ; + dmt->offset.u.z = avg.v[2] - DEFAULT_SENSITIVITY; + return CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Z_NEGATIVE; + } + return 0; +} + +int dmard09_init(struct i2c_client *client){ + + //struct dmt_data *dmt = i2c_get_clientdata(client); + unsigned char buffer[7]; + /* 1. Active Mode */ + buffer[0] = REG_ACTR; + buffer[1] = MODE_ACTIVE; + device_i2c_txdata(client, buffer, 2); + /* 2. check D09 who am I */ + buffer[0] = REG_DC; + device_i2c_rxdata(client, buffer, 1); + if (buffer[0] == VALUE_WHO_AM_I) + { + printk(KERN_INFO GSE_TAG"D09 WHO_AM_I_VALUE = %d \n", buffer[0]); + GSE_LOG("D09 registered I2C driver!\n"); + } + else + { + GSE_ERR("gsensor I2C err = %d!\n", buffer[0]); + return -1; + } + /* 3. Set Data conversion rate*/ + buffer[0] = REG_CNT_L1; + buffer[1] = VALUE_ODR_100; + buffer[2] = VALUE_CNT_L2; + device_i2c_txdata(client, buffer, 3); + /* 4. open hardware filter */ + buffer[0] = REG_ODF; + buffer[1] = ODF_Ave_4; + buffer[2] = 0x00; + device_i2c_txdata(client, buffer, 3); + /* 5. check hardware filter again */ + buffer[0] = REG_ODF; //0x07 smooth filter 1/8 Bandwidth */ + device_i2c_rxdata(client, buffer, 2); + printk(KERN_INFO GSE_TAG" REG_ODF = %x , %x\n", buffer[0] , buffer[1]); + + return 0; +} + +void D09_set_offset(struct i2c_client *client, int val[3]){ + struct dmt_data *dmt = i2c_get_clientdata(client); + int i; + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + dmt->offset.v[i] = val[i]; +} + +struct file_operations sensor_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = device_ioctl, + .open = device_open, + .release = device_close, +}; + +static struct miscdevice dmt_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = SENSOR_I2C_NAME, + .fops = &sensor_fops, +}; + +static int sensor_close_dev(struct i2c_client *client){ + char buffer[3]; + buffer[0] = REG_ACTR; + device_i2c_rxdata(client, buffer, 2); + buffer[1] = buffer[0] & 0xFE; //Mask off last bit (POWER DOWN MODE) + //buffer[1] = MODE_POWERDOWN; + device_i2c_txdata(client,buffer, 2); + return 0; +} + +static void dmard09_shutdown(struct platform_device *pdev) +{ + flush_delayed_work_sync(&s_dmt->delaywork); + DMT_sysfs_update_active_status(s_dmt , 0); +} + + +//static int device_i2c_suspend(struct i2c_client *client, pm_message_t mesg){ +static int dmard09_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct dmt_data *dmt = i2c_get_clientdata(s_dmt->client); + flush_delayed_work_sync(&dmt->delaywork); + DMT_sysfs_update_active_status(dmt , 0); + return sensor_close_dev(dmt->client); +} + +//static int device_i2c_resume(struct i2c_client *client){ +static int dmard09_resume(struct platform_device *pdev) +{ + struct dmt_data *dmt = i2c_get_clientdata(s_dmt->client); + int en = 1; + GSE_FUN(); + printk("dmt->enable=%d",dmt->enable); + dmard09_init(dmt->client); + atomic_set(&dmt->enable,en); + DMT_sysfs_update_active_status(dmt , en); + return 0; +} +/* +static int __devexit device_i2c_remove(struct i2c_client *client){ + return 0; +} + +static const struct i2c_device_id device_i2c_ids[] = { + { SENSOR_I2C_NAME, 0}, + { } +}; + +static struct i2c_driver device_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = SENSOR_I2C_NAME, + }, + .class = I2C_CLASS_HWMON, + .id_table = device_i2c_ids, + .probe = device_i2c_probe, + .remove = __devexit_p(device_i2c_remove), +#ifdef CONFIG_HAS_EARLYSUSPEND + .suspend = device_i2c_suspend, + .resume = device_i2c_resume, +#endif +}; +*/ +static int device_open(struct inode *inode, struct file *filp){ + return 0; +} + +static long device_ioctl(struct file *file, unsigned int cmd, unsigned long arg){ + //struct i2c_client *client = (struct i2c_client *)file->private_data; + //struct dmt_data *dmt = (struct dmt_data*)i2c_get_clientdata(client); + + int err = 0, ret = 0, i; + int intBuf[SENSOR_DATA_SIZE], xyz[SENSOR_DATA_SIZE]; + /* check type */ + if (_IOC_TYPE(cmd) != IOCTL_MAGIC) return -ENOTTY; + + /* check user space pointer is valid */ + if (_IOC_DIR(cmd) & _IOC_READ) + err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd)); + else if (_IOC_DIR(cmd) & _IOC_WRITE) + err = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd)); + if (err) return -EFAULT; + + switch(cmd) { + case SENSOR_RESET: + ret = dmard09_init(s_dmt->client); + return ret; + + case SENSOR_CALIBRATION: + /* get orientation info */ + //if(copy_from_user(&intBuf, (int*)arg, sizeof(intBuf))) return -EFAULT; + D09_calibrate(s_dmt->client); + GSE_LOG("Sensor_calibration:%d %d %d\n", s_dmt->offset.u.x, s_dmt->offset.u.y, s_dmt->offset.u.z); + /* save file */ + D09_write_offset_to_file(s_dmt->client); + update_var(); + + /* return the offset */ + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + intBuf[i] = s_dmt->offset.v[i]; + + ret = copy_to_user((int *)arg, &intBuf, sizeof(intBuf)); + return ret; + + case SENSOR_GET_OFFSET: + /* get data from file */ + D09_read_offset_from_file(s_dmt->client); + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + intBuf[i] = s_dmt->offset.v[i]; + + ret = copy_to_user((int *)arg, &intBuf, sizeof(intBuf)); + return ret; + + case SENSOR_SET_OFFSET: + ret = copy_from_user(&intBuf, (int *)arg, sizeof(intBuf)); + D09_set_offset(s_dmt->client , intBuf); + /* write into file */ + D09_write_offset_to_file(s_dmt->client); + update_var(); + return ret; + + case SENSOR_READ_ACCEL_XYZ: + D09_i2c_read_xyz(s_dmt->client, (int *)&xyz); + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + intBuf[i] = xyz[i] - s_dmt->offset.v[i]; + + ret = copy_to_user((int*)arg, &intBuf, sizeof(intBuf)); + return ret; + + case SENSOR_SETYPR: + if(copy_from_user(&intBuf, (int*)arg, sizeof(intBuf))) { + GSE_LOG("%s: -EFAULT\n",__func__); + return -EFAULT; + } + input_report_abs(s_dmt->input, ABS_X, intBuf[0]); + input_report_abs(s_dmt->input, ABS_Y, intBuf[1]); + input_report_abs(s_dmt->input, ABS_Z, intBuf[2]); + input_sync(s_dmt->input); + GSE_LOG("SENSOR_SETYPR OK! x=%d,y=%d,z=%d\n",intBuf[0],intBuf[1],intBuf[2]); + return ret; + + case SENSOR_GET_OPEN_STATUS: + GSE_LOG("Going into DMT_GetOpenStatus()\n"); + ret = DMT_GetOpenStatus(s_dmt->client); + return ret; + + case SENSOR_GET_CLOSE_STATUS: + GSE_LOG("Going into DMT_GetCloseStatus()\n"); + ret = DMT_GetCloseStatus(s_dmt->client); + return ret; + + case SENSOR_GET_DELAY: + ret = copy_to_user((int*)arg, &interval, sizeof(interval)); + return ret; + + default: /* redundant, as cmd was checked against MAXNR */ + return -ENOTTY; + } + + return 0; +} + +static int device_close(struct inode *inode, struct file *filp){ + return 0; +} + +/***** I2C I/O function ***********************************************/ +static int device_i2c_rxdata( struct i2c_client *client, unsigned char *rxData, int length){ + struct i2c_msg msgs[] = { + {.addr = client->addr, .flags = 0, .len = 1, .buf = rxData,}, + {.addr = client->addr, .flags = I2C_M_RD, .len = length, .buf = rxData,}, + }; + //unsigned char addr = rxData[0]; + if (i2c_transfer(client->adapter, msgs, 2) < 0) { + dev_err(&client->dev, "%s: transfer failed.", __func__); + return -EIO; + } + //DMT_DATA(&client->dev, "RxData: len=%02x, addr=%02x, data=%02x\n", + //length, addr, rxData[0]); + + return 0; +} + +static int device_i2c_txdata( struct i2c_client *client, unsigned char *txData, int length){ + struct i2c_msg msg[] = { + {.addr = client->addr, .flags = 0, .len = length, .buf = txData,}, + }; + + if (i2c_transfer(client->adapter, msg, 1) < 0) { + dev_err(&client->dev, "%s: transfer failed.", __func__); + return -EIO; + } + //DMT_DATA(&client->dev, "TxData: len=%02x, addr=%02x data=%02x\n", + //length, txData[0], txData[1]); + return 0; +} + +static int D09_i2c_read_xyz(struct i2c_client *client, int *xyz_p){ + + struct dmt_data *dmt = i2c_get_clientdata(client); + u8 buffer[11]; + s16 xyzTmp[SENSOR_DATA_SIZE]; + int pos = dmt->position; + int i, j , k; + /* get xyz high/low bytes, 0x0A */ + buffer[0] = REG_STAT; + /* Read acceleration data */ + if (device_i2c_rxdata(client, buffer, 8)!= 0) + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + { + xyz_p[i] = 0; + xyzTmp[i] = 0; + } + else + for(i = 0; i < SENSOR_DATA_SIZE; ++i){ + xyz_p[i] = 0; + xyzTmp[i] = 0; + /* merge xyz high/low bytes & 1g = 128 becomes 1g = 1024 */ + mutex_lock(&dmt->data_mutex); + xyzTmp[i] =(((int16_t)((buffer[2*(i+1)+1] << 8)) | buffer[2*(i+1)] ) >> 3) << 5; + mutex_unlock(&dmt->data_mutex); + } +#ifdef SW_FILTER + if( dmt->aveflag >= dmt->filter){ + for(i = 0; i < SENSOR_DATA_SIZE; ++i){ + dmt->sum[i] = dmt->sum[i] - dmt->bufferave[i][dmt->pointer] + xyzTmp[i]; + } + /* transfer to the default layout */ + for(i = 0; i < SENSOR_DATA_SIZE; ++i){ + for(j = 0; j < SENSOR_DATA_SIZE; j++) + xyz_p[i] += (int)(dmt->sum[j]/dmt->filter * dmt_position_map[pos][i][j]); + } + } + else{ + /* init dmt->sum */ + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + dmt->sum[i] = xyzTmp[i]; +#endif + /* transfer to the default layout */ + for(i = 0; i < SENSOR_DATA_SIZE; ++i){ + for(j = 0; j < SENSOR_DATA_SIZE; j++){ + xyz_p[i] += (int)(xyzTmp[j] * dmt_position_map[pos][i][j]); + //GSE_LOG("%04d, %04d,%d \n", xyz_p[i], xyzTmp[j], dmt_position_map[pos][i][j]); + } + } + //GSE_LOG("xyz_p: %04d , %04d , %04d\n", xyz_p[0], xyz_p[1], xyz_p[2]); +#ifdef SW_FILTER + dmt->aveflag++; + } + /* init dmt->sum */ + for(i = 0; i < SENSOR_DATA_SIZE; ++i){ + dmt->sum[i] = 0; + } + dmt->pointer++; + dmt->pointer %= dmt->filter; + for(i = 0; i < SENSOR_DATA_SIZE; ++i){ + dmt->bufferave[i][dmt->pointer] = xyzTmp[i]; + } + for(i = 0; i < SENSOR_DATA_SIZE; ++i){ + for(k = 0; k < dmt->filter; ++k){ + dmt->sum[i] += dmt->bufferave[i][k]; + } + } +#endif + return 0; +} + +static void DMT_work_func(struct work_struct *delaywork){ + struct dmt_data *dmt = container_of(delaywork, struct dmt_data, delaywork.work); + int i; + //static bool firsttime=true; + raw_data xyz; + unsigned long dmt_delay = msecs_to_jiffies(atomic_read(&dmt->delay)); + + + D09_i2c_read_xyz(dmt->client, (int *)&xyz.v); + /* dmt->last = RawData - Offset */ + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + dmt->last.v[i] = xyz.v[i] - dmt->offset.v[i]; + //GSE_LOG("@DMTRaw @ X/Y/Z axis: %04d , %04d , %04d\n", xyz.v[0], xyz.v[1], xyz.v[2]); + //GSE_LOG("@Offset @ X/Y/Z axis: %04d , %04d , %04d\n", dmt->offset.u.x, dmt->offset.u.y, dmt->offset.u.z); + //GSE_LOG("@Raw-Offset@ X/Y/Z axis: %04d , %04d , %04d ,dmt_delay=%d\n", dmt->last.u.x, dmt->last.u.y, dmt->last.u.z, atomic_read(&dmt->delay)); + +#ifdef STABLE_VALUE_FUNCTION + if(abs(dmt->last.v[0])< RANGE_XYZ){ dmt->last.v[0] = 0;} + if(abs(dmt->last.v[1])< RANGE_XYZ){ dmt->last.v[1] = 0;} + if(abs(dmt->last.v[2])< RANGE_XYZ){ dmt->last.v[2] = 0;} +#endif + + + input_report_abs(dmt->input, ABS_X, -dmt->last.v[l_sensorconfig.xyz_axis[0][0]]*l_sensorconfig.xyz_axis[0][1]);//dmt->last.v[0]); + input_report_abs(dmt->input, ABS_Y, -dmt->last.v[l_sensorconfig.xyz_axis[1][0]]*l_sensorconfig.xyz_axis[1][1]);//dmt->last.v[1]); + input_report_abs(dmt->input, ABS_Z, -dmt->last.v[l_sensorconfig.xyz_axis[2][0]]*l_sensorconfig.xyz_axis[2][1]);//dmt->last.v[2]); + input_sync(dmt->input); + + if(dmt_delay < 1) + dmt_delay = 1; + schedule_delayed_work(&dmt->delaywork, dmt_delay); +} + +static int mma09_open(struct inode *node, struct file *fle) +{ + GSE_LOG("open...\n"); + return 0; +} + +static int mma09_close(struct inode *node, struct file *fle) +{ + GSE_LOG("close...\n"); + return 0; +} + +static long mma09_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + int err = 0; + //unsigned char data[6]; + void __user *argp = (void __user *)arg; + short delay, enable; + unsigned int uval = 0; + + + /* cmd mapping */ + switch(cmd) + { + case ECS_IOCTL_APP_SET_DELAY: + // set the rate of g-sensor + if (copy_from_user(&delay, argp, sizeof(short))) + { + printk(KERN_ALERT "Can't get set delay!!!\n"); + return -EFAULT; + } + klog("Get delay=%d\n", delay); + + if ((delay >=0) && (delay < 20)) + { + delay = 20; + } else if (delay > 200) + { + delay = 200; + } + l_sensorconfig.sensor_samp = 1000/delay; + atomic_set(&s_dmt->delay, 1000/delay); + break; + case ECS_IOCTL_APP_SET_AFLAG: + // enable/disable sensor + if (copy_from_user(&enable, argp, sizeof(short))) + { + printk(KERN_ERR "Can't get enable flag!!!\n"); + return -EFAULT; + } + klog("enable=%d\n",enable); + if ((enable >=0) && (enable <=1)) + { + //KMSGINF("driver: disable/enable(%d) gsensor.\n", enable); + + l_sensorconfig.sensor_enable = enable; + atomic_set(&s_dmt->enable,enable); + DMT_sysfs_update_active_status(s_dmt , enable); + + } else { + printk(KERN_ERR "Wrong enable argument in %s !!!\n", __FUNCTION__); + return -EINVAL; + } + break; + case WMT_IOCTL_SENSOR_GET_DRVID: + uval = DMARD09_DRVID;//; + if (copy_to_user((unsigned int*)arg, &uval, sizeof(unsigned int))) + { + return -EFAULT; + } + GSE_LOG("dmard09_driver_id:%d\n",uval); + break; + case WMT_IOCTL_SENOR_GET_RESOLUTION: + uval = (10<<8) | 1; + if (copy_to_user((unsigned int *)arg, &uval, sizeof(unsigned int))) + { + return -EFAULT; + } + printk("<<<<<< 0) + { + if (sample != l_sensorconfig.sensor_samp) + { + // should do sth + } + //printk(KERN_ALERT "sensor samp=%d(amsr:%d) has been set.\n", sample, amsr); + } else { + klog("Wrong sample argumnet of sensor.\n"); + } + } else if (sscanf(buffer, "enable=%d\n", &enable)) + { + if ((enable < 0) || (enable > 1)) + { + klog("The argument to enable/disable g-sensor should be 0 or 1 !!!\n"); + } else if (enable != l_sensorconfig.sensor_enable) + { + //mma_enable_disable(enable); + l_sensorconfig.sensor_enable = enable; + } + } else if (sscanf(buffer, "sensor_test=%d\n", &test)) + { // for test begin + l_sensorconfig.test_pass = 0; + atomic_set(&s_dmt->enable,1); + DMT_sysfs_update_active_status(s_dmt , 1); + } else if (sscanf(buffer, "sensor_testend=%d\n", &test)) + { // Don nothing only to be compatible the before testing program + atomic_set(&s_dmt->enable,0); + DMT_sysfs_update_active_status(s_dmt , 0); + } + //mutex_unlock(&sense_data_mutex); + return count; +} + +static int sensor_readproc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = 0; + + len = sprintf(page, + "test_pass=%d\nisdbg=%d\nrate=%d\nenable=%d\n", + l_sensorconfig.test_pass, + l_sensorconfig.isdbg, + l_sensorconfig.sensor_samp, + l_sensorconfig.sensor_enable + ); + return len; +} + + +//static int __devinit device_i2c_probe(struct i2c_client *client,const struct i2c_device_id *id){ +static int __devinit dmard09_probe(struct platform_device *pdev) +{ + int i, k, ret = 0; + //struct dmt_data *s_dmt = i2c_get_clientdata(client); + //struct dmt_data *s_dmt; + GSE_FUN(); +/* + if(!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)){ + GSE_ERR("check_functionality failed.\n"); + ret = -ENODEV; + goto exit0; + } + + // Allocate memory for driver data + s_dmt = kzalloc(sizeof(struct dmt_data), GFP_KERNEL); + memset(s_dmt, 0, sizeof(struct dmt_data)); + if (s_dmt == NULL) { + GSE_ERR("alloc data failed.\n"); + ret = -ENOMEM; + goto exit1; + } +*/ + /*for(i = 0; i < SENSOR_DATA_SIZE; ++i) + s_dmt->offset.v[i] = 0;*/ +#ifdef SW_FILTER + s_dmt->pointer = 0; + s_dmt->aveflag = 0; + for(i = 0; i < SENSOR_DATA_SIZE; ++i){ + s_dmt->sum[i] = 0; + for(k = 0; k < SENSOR_DATA_AVG; ++k){ + s_dmt->bufferave[i][k] = 0; + } + } + s_dmt->filter = SENSOR_DATA_AVG; + GSE_LOG("D09_DEFAULT_FILTER: %d\n", s_dmt->filter); +#endif + /* I2C initialization */ + //s_dmt->client = client; + + /* set client data */ + i2c_set_clientdata(s_dmt->client, s_dmt); + /*ret = dmard09_init(client); + if (ret < 0) + goto exit2; + */ + /* input */ + ret = D09_input_init(s_dmt->client); + if (ret){ + GSE_ERR("D09_input_init fail, error code= %d\n",ret); + goto exit3; + } + + /* initialize variables in dmt_data */ + mutex_init(&s_dmt->data_mutex); + mutex_init(&s_dmt->enable_mutex); +#ifdef DMT_DEBUG_DATA + mutex_init(&s_dmt->suspend_mutex); +#endif + init_waitqueue_head(&s_dmt->open_wq); + atomic_set(&s_dmt->active, 0); + atomic_set(&s_dmt->enable, 0); + atomic_set(&s_dmt->delay, 0); + atomic_set(&s_dmt->addr, 0); + /* DMT Acceleration Sensor Mounting Position on Board */ + s_dmt->position = D09_DEFAULT_POSITION; + GSE_LOG("D09_DEFAULT_POSITION: %d\n", s_dmt->position); + //s_dmt->position = (CONFIG_INPUT_DMT_ACCELEROMETER_POSITION); + //GSE_LOG("CONFIG_INPUT_DMT_ACCELEROMETER_POSITION: %d\n", s_dmt->position); + /* Misc device */ + if (misc_register(&dmt_device) < 0){ + GSE_ERR("dmt_dev register failed"); + goto exit4; + } + + /* Setup sysfs */ + if (create_sysfs_interfaces(s_dmt) < 0){ + GSE_ERR("create sysfs failed."); + goto exit5; + } +#ifdef CONFIG_HAS_EARLYSUSPEND + s_dmt->early_suspend.suspend = device_i2c_suspend; + s_dmt->early_suspend.resume = device_i2c_resume; + register_early_suspend(&s_dmt->early_suspend); +#endif + /* Setup driver interface */ + INIT_DELAYED_WORK(&s_dmt->delaywork, DMT_work_func); + GSE_LOG("DMT: INIT_DELAYED_WORK\n"); + + //register ctrl dev + ret = misc_register(&d09_device); + if (ret !=0) { + errlog("Can't register d09_device!\n"); + return -1; + } + // register rd/wr proc + l_sensorconfig.sensor_proc = create_proc_entry(GSENSOR_PROC_NAME, 0666, NULL/*&proc_root*/); + if (l_sensorconfig.sensor_proc != NULL) + { + l_sensorconfig.sensor_proc->write_proc = sensor_writeproc; + l_sensorconfig.sensor_proc->read_proc = sensor_readproc; + } + + //create offset file after factory reset + D09_read_offset_from_file(s_dmt->client); + + return 0; + +exit5: + misc_deregister(&dmt_device); +exit4: + input_unregister_device(s_dmt->input); +exit3: + kfree(s_dmt); +/*exit2: +exit1: +exit0:*/ + return ret; +} +/* +static struct i2c_board_info dmard09_board_info={ + .type = SENSOR_I2C_NAME, + .addr = SENSOR_I2C_ADDR, +}; +*/ +//static struct i2c_client *client; + +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); +static int get_axisset(void) +{ + char varbuf[64]; + int n; + int varlen; + + memset(varbuf, 0, sizeof(varbuf)); + varlen = sizeof(varbuf); + if (wmt_getsyspara("wmt.io.dm09sensor", varbuf, &varlen)) { + errlog("Can't get gsensor config in u-boot!!!!\n"); + return -1; + } else { + n = sscanf(varbuf, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", + &l_sensorconfig.op, + &l_sensorconfig.int_gpio, + &l_sensorconfig.samp, + &(l_sensorconfig.xyz_axis[0][0]), + &(l_sensorconfig.xyz_axis[0][1]), + &(l_sensorconfig.xyz_axis[1][0]), + &(l_sensorconfig.xyz_axis[1][1]), + &(l_sensorconfig.xyz_axis[2][0]), + &(l_sensorconfig.xyz_axis[2][1]), + &(l_sensorconfig.offset[0]), + &(l_sensorconfig.offset[1]), + &(l_sensorconfig.offset[2]) + ); + if (n != 12) { + errlog("gsensor format is error in u-boot!!!\n"); + return -1; + } + l_sensorconfig.sensor_samp = l_sensorconfig.samp; + + dbg("get the sensor config: %d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d\n", + l_sensorconfig.op, + l_sensorconfig.int_gpio, + l_sensorconfig.samp, + l_sensorconfig.xyz_axis[0][0], + l_sensorconfig.xyz_axis[0][1], + l_sensorconfig.xyz_axis[1][0], + l_sensorconfig.xyz_axis[1][1], + l_sensorconfig.xyz_axis[2][0], + l_sensorconfig.xyz_axis[2][1], + l_sensorconfig.offset[0], + l_sensorconfig.offset[1], + l_sensorconfig.offset[2] + ); + } + return 0; +} + +static void dmard09_platform_release(struct device *device) +{ + GSE_LOG("...\n"); + return; +} + +static int __devexit dmard09_remove(struct platform_device *pdev) +{ + if (l_sensorconfig.sensor_proc != NULL) + { + remove_proc_entry(GSENSOR_PROC_NAME, NULL); + l_sensorconfig.sensor_proc = NULL; + } + //misc_deregister(&d09_device); + return 0; +} + + +static struct platform_device dmard09_device = { + .name = SENSOR_I2C_NAME, + .id = 0, + .dev = { + .release = dmard09_platform_release, + }, +}; + +static struct platform_driver dmard09_driver = { + .probe = dmard09_probe, + .remove = dmard09_remove, + .shutdown = dmard09_shutdown, + .suspend = dmard09_suspend, + .resume = dmard09_resume, + .driver = { + .name = SENSOR_I2C_NAME, + }, +}; + + +static int __init device_init(void){ + //struct device *device; + struct i2c_client *this_client; + int ret = 0; + + // parse g-sensor u-boot arg + ret = get_axisset(); + if (ret < 0) + { + printk("<<<<<%s user choose to no sensor chip!\n", __func__); + return ret; + } + GSE_LOG("D09 gsensor driver: initialize.\n"); + + if (!(this_client = sensor_i2c_register_device(0, DEVICE_I2C_ADDR, SENSOR_I2C_NAME))) + { + printk(KERN_ERR"Can't register gsensor i2c device!\n"); + return -1; + } + + if (dmard09_init(this_client)) + { + GSE_ERR("Failed to init dmard09!\n"); + sensor_i2c_unregister_device(this_client); + return -1; + } + + /* Allocate memory for driver data */ + s_dmt = kzalloc(sizeof(struct dmt_data), GFP_KERNEL); + //memset(s_dmt, 0, sizeof(struct dmt_data)); + if (s_dmt == NULL) { + GSE_ERR("alloc data failed.\n"); + return -ENOMEM; + } + + s_dmt->client = this_client; + s_dmt->pdevice = &dmard09_device; + s_dmt->offset.u.x = l_sensorconfig.offset[0]; + s_dmt->offset.u.y = l_sensorconfig.offset[1]; + s_dmt->offset.u.z = l_sensorconfig.offset[2]; + + + // create the platform device + l_dev_class = class_create(THIS_MODULE, SENSOR_I2C_NAME); + if (IS_ERR(l_dev_class)){ + ret = PTR_ERR(l_dev_class); + printk(KERN_ERR "Can't class_create gsensor device !!\n"); + return ret; + } + if((ret = platform_device_register(&dmard09_device))) + { + GSE_ERR("Can't register dmard09 platform devcie!!!\n"); + return ret; + } + if ((ret = platform_driver_register(&dmard09_driver)) != 0) + { + GSE_ERR("Can't register dmard09 platform driver!!!\n"); + return ret; + } + + return 0; +} + +static void __exit device_exit(void){ + //i2c_unregister_device(client); + //i2c_del_driver(&device_i2c_driver); + GSE_LOG("D09 gsensor driver: release.\n"); + + flush_delayed_work_sync(&s_dmt->delaywork); + cancel_delayed_work_sync(&s_dmt->delaywork); + + input_unregister_device(s_dmt->input); + input_free_device(s_dmt->input); + misc_deregister(&dmt_device); + misc_deregister(&d09_device); + platform_driver_unregister(&dmard09_driver); + platform_device_unregister(&dmard09_device); + sensor_i2c_unregister_device(s_dmt->client); + class_destroy(l_dev_class); + + remove_sysfs_interfaces(s_dmt); + kfree(s_dmt); +} + +static int dmt_get_filter(struct i2c_client *client){ + struct dmt_data *dmt = i2c_get_clientdata(client); + return dmt->filter; +} + +static int dmt_set_filter(struct i2c_client *client, int filter){ + struct dmt_data *dmt = i2c_get_clientdata(client); + if (!((filter >= 1) && (filter <= 32))) + return -1; + dmt->filter = filter; + return 0; +} + +static int dmt_get_position(struct i2c_client *client){ + struct dmt_data *dmt = i2c_get_clientdata(client); + return dmt->position; +} + +static int dmt_set_position(struct i2c_client *client, int position){ + struct dmt_data *dmt = i2c_get_clientdata(client); + if (!((position >= 0) && (position <= 7))) + return -1; + dmt->position = position; + return 0; +} + +extern int wmt_setsyspara(char *varname, char *varval); +static void update_var(void) +{ + char varbuf[64]; + int varlen; + + memset(varbuf, 0, sizeof(varbuf)); + varlen = sizeof(varbuf); + + sprintf(varbuf, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", + l_sensorconfig.op, + l_sensorconfig.int_gpio, + l_sensorconfig.samp, + l_sensorconfig.xyz_axis[0][0], + l_sensorconfig.xyz_axis[0][1], + l_sensorconfig.xyz_axis[1][0], + l_sensorconfig.xyz_axis[1][1], + l_sensorconfig.xyz_axis[2][0], + l_sensorconfig.xyz_axis[2][1], + s_dmt->offset.u.x, + s_dmt->offset.u.y, + s_dmt->offset.u.z + ); + + wmt_setsyspara("wmt.io.dm09sensor",varbuf); +} + +static int D09_write_offset_to_file(struct i2c_client *client){ + struct dmt_data *dmt = i2c_get_clientdata(client); + char r_buf[18] = {0}; + char w_buf[18] = {0}; + //unsigned int orgfs; + struct file *fp; + mm_segment_t fs; + ssize_t ret; + //int8_t i; + + sprintf(w_buf,"%5d %5d %5d", dmt->offset.u.x, dmt->offset.u.y, dmt->offset.u.z); + /* Set segment descriptor associated to kernel space */ + fp = filp_open(D09_OffsetFileName, O_RDWR | O_CREAT, 0777); + if(IS_ERR(fp)){ + GSE_ERR("filp_open %s error!!.:%d\n",D09_OffsetFileName,fp); + return -1; + } + else{ + fs = get_fs(); + //set_fs(KERNEL_DS); + set_fs(get_ds()); + GSE_LOG("filp_open %s SUCCESS!!.\n",D09_OffsetFileName); + //fp->f_op->write(fp,data,18, &fp->f_pos); + //filp_close(fp,NULL); + ret = fp->f_op->write(fp,w_buf,18,&fp->f_pos); + if(ret != 18) + { + printk(KERN_ERR "%s: write error!\n", __func__); + filp_close(fp,NULL); + return -EIO; + } + //fp->f_pos=0x00; + ret = fp->f_op->read(fp,r_buf, 18,&fp->f_pos); + if(ret < 0) + { + printk(KERN_ERR "%s: read error!\n", __func__); + filp_close(fp,NULL); + return -EIO; + } + set_fs(fs); + + // + //printk(KERN_INFO "%s: read ret=%d!", __func__, ret); + /* for(i=0; i<18 ;i++) + { + if(r_buf[i] != w_buf[i]) + { + printk(KERN_ERR "%s: read back error, r_buf[%x](0x%x) != w_buf[%x](0x%x)\n", + __func__, i, r_buf[i], i, w_buf[i]); + filp_close(fp,NULL); + return -EIO; + } + } + */ + + } + filp_close(fp,NULL); + return 0; +} + +void D09_read_offset_from_file(struct i2c_client *client){ + struct dmt_data *dmt = i2c_get_clientdata(client); + unsigned int orgfs; + char data[18]; + struct file *fp; + int ux,uy,uz; + orgfs = get_fs(); + /* Set segment descriptor associated to kernel space */ + set_fs(KERNEL_DS); + + fp = filp_open(D09_OffsetFileName, O_RDWR , 0); + GSE_FUN(); + if(IS_ERR(fp)){ + GSE_ERR("Sorry,file open ERROR !\n"); + if(l_sensorconfig.op){ //first time + l_sensorconfig.op=0; +#if AUTO_CALIBRATION + /* get acceleration average reading */ + D09_calibrate(client); + update_var(); + D09_write_offset_to_file(client); +#endif +#ifdef DMT_BROADCAST_APK_ENABLE + create_devidfile(); + return; +#endif + } + D09_write_offset_to_file(client); + } + else{ + GSE_LOG("filp_open %s SUCCESS!!.\n",D09_OffsetFileName); + fp->f_op->read(fp,data,18, &fp->f_pos); + GSE_LOG("filp_read result %s\n",data); + sscanf(data,"%d %d %d",&ux,&uy,&uz); + dmt->offset.u.x=ux; + dmt->offset.u.y=uy; + dmt->offset.u.z=uz; + } + set_fs(orgfs); +} +static int create_devidfile(void) +{ + char data[18]; + unsigned int orgfs; + struct file *fp; + + sprintf(data,"%5d %5d %5d",0,0,0); + orgfs = get_fs(); + /* Set segment descriptor associated to kernel space */ + set_fs(KERNEL_DS); + GSE_FUN(); + fp = filp_open(DmtXXFileName, O_RDWR | O_CREAT, 0777); + if(IS_ERR(fp)){ + GSE_ERR("Sorry,file open ERROR !\n"); + return -1; + } + fp->f_op->write(fp,data,18, &fp->f_pos); + set_fs(orgfs); + filp_close(fp,NULL); + return 0; +} +//********************************************************************************************************* +MODULE_AUTHOR("DMT_RD"); +MODULE_DESCRIPTION("DMT Gsensor Driver"); +MODULE_LICENSE("GPL"); + +module_init(device_init); +module_exit(device_exit); diff --git a/ANDROID_3.4.5/drivers/input/sensor/dmard09_gsensor/dmt09.h b/ANDROID_3.4.5/drivers/input/sensor/dmard09_gsensor/dmt09.h new file mode 100755 index 00000000..d30e606a --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/dmard09_gsensor/dmt09.h @@ -0,0 +1,183 @@ +/* @version 1.03 + * Copyright 2011 Domintech Technology Co., Ltd + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#ifndef DMT09_H +#define DMT09_H +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#define AUTO_CALIBRATION 0 +#define SW_FILTER /* Enable or Disable Software filter */ +#define SENSOR_DATA_AVG 4//8 /* AVG sensor data */ + +#define STABLE_VALUE_FUNCTION +#define RANGE_XYZ 40 + +//#define DMT_DEBUG_DATA +#define GSE_TAG "[DMT_Gsensor]" +#ifdef DMT_DEBUG_DATA +#define GSE_ERR(fmt, args...) printk(KERN_ERR GSE_TAG"%s %d : "fmt, __FUNCTION__, __LINE__, ##args) +#define GSE_LOG(fmt, args...) printk(KERN_INFO GSE_TAG fmt, ##args) +#define GSE_FUN(f) printk(KERN_INFO GSE_TAG" %s: %s: %i\n", __FILE__, __func__, __LINE__) +#define DMT_DATA(dev, ...) dev_dbg((dev), ##__VA_ARGS__) +#else +#define GSE_ERR(fmt, args...) +#define GSE_LOG(fmt, args...) +#define GSE_FUN(f) +#define DMT_DATA(dev, format, ...) +#endif + +#define GSENSOR_ID "DMARD09" +#define INPUT_NAME_ACC "g-sensor"//"DMT_accel"//"g-sensor"// /* Input Device Name */ +#define SENSOR_I2C_NAME "dmard09"//"dmt"// /* Device name for DMARD09 misc. device */ +#define DEVICE_I2C_ADDR 0x1d +#define REG_ACTR 0x00 +#define REG_STAT 0x0A +#define REG_DX 0x0C +#define REG_DY 0x0E +#define REG_DZ 0x10 +#define REG_DT 0x12 +#define REG_INL 0x16 +#define REG_DC 0x18 +#define REG_CNT_L1 0x1B +#define REG_CNT_L2 0x1C +#define REG_CNT_L3 0x1D +#define REG_INC 0x1E +#define REG_ODF 0x20 +#define REG_THR1 0x62 +#define REG_THR2 0x64 + +#define MODE_ACTIVE 0x61 /* active */ +#define MODE_POWERDOWN 0x60 /* powerdown */ + +#define VALUE_WHO_AM_I 0x95 /* D09 WMI */ +#define VALUE_ODR_200 0x9C /* conversion rate 200Hz */ +#define VALUE_ODR_100 0x98 /* conversion rate 100Hz */ +#define VALUE_ODR_50 0x94 /* conversion rate 50Hz */ +#define VALUE_ODR_20 0x90 /* conversion rate 20Hz */ +#define VALUE_ODR_10 0x8C /* conversion rate 10Hz */ +#define VALUE_ODR_5 0x88 /* conversion rate 5Hz */ +#define VALUE_ODR_1 0x84 /* conversion rate 1Hz */ +#define VALUE_ODR_0_5 0x80 /* conversion rate 0.5Hz */ +#define VALUE_CNT_L2 0xE4 /* Disable IEN */ +/* Optional Digital Filter [Low Byte and High Byte Order] */ +#define ODF_NoFilter 0x00 /* No filter */ +#define ODF_Ave_4 0x03 /* smooth filter 1/4 Bandwidth */ +#define ODF_Ave_8 0x07 /* smooth filter 1/8 Bandwidth */ +#define ODF_Ave_16 0x0f /* smooth filter 1/16 Bandwidth */ + + +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Z_NEGATIVE 1 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Z_POSITIVE 2 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Y_NEGATIVE 3 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Y_POSITIVE 4 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_X_NEGATIVE 5 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_X_POSITIVE 6 + +#define AVG_NUM 16 +#define SENSOR_DATA_SIZE 3 +#define DEFAULT_SENSITIVITY 1024 + +#define IOCTL_MAGIC 0x09 +#define SENSOR_RESET _IO(IOCTL_MAGIC, 0) +#define SENSOR_CALIBRATION _IOWR(IOCTL_MAGIC, 1, int[SENSOR_DATA_SIZE]) +#define SENSOR_GET_OFFSET _IOR(IOCTL_MAGIC, 2, int[SENSOR_DATA_SIZE]) +#define SENSOR_SET_OFFSET _IOWR(IOCTL_MAGIC, 3, int[SENSOR_DATA_SIZE]) +#define SENSOR_READ_ACCEL_XYZ _IOR(IOCTL_MAGIC, 4, int[SENSOR_DATA_SIZE]) +#define SENSOR_SETYPR _IOW(IOCTL_MAGIC, 5, int[SENSOR_DATA_SIZE]) +#define SENSOR_GET_OPEN_STATUS _IO(IOCTL_MAGIC, 6) +#define SENSOR_GET_CLOSE_STATUS _IO(IOCTL_MAGIC, 7) +#define SENSOR_GET_DELAY _IOR(IOCTL_MAGIC, 8, unsigned int*) +#define SENSOR_MAXNR 8 +/* Default sensorlayout parameters */ +#define D09_DEFAULT_POSITION 6 + +/* Transformation matrix for chip mounting position */ +static const int dmt_position_map[][3][3] = { + { { 1, 0, 0}, { 0,-1, 0}, { 0, 0,-1}, }, /* top/upper-left */ + { { 0, 1, 0}, { 1, 0, 0}, { 0, 0,-1}, }, /* top/lower-left */ + { {-1, 0, 0}, { 0, 1, 0}, { 0, 0,-1}, }, /* top/lower-right */ + { { 0,-1, 0}, {-1, 0, 0}, { 0, 0,-1}, }, /* top/upper-right */ + { {-1, 0, 0}, { 0,-1, 0}, { 0, 0, 1}, }, /* bottom/upper-right*/ + { { 0,-1, 0}, {-1, 0, 0}, { 0, 0, 1}, }, /* bottom/upper-left */ + { { 1, 0, 0}, { 0, 1, 0}, { 0, 0, 1}, }, /* bottom/lower-right*/ + { { 0, 1,0}, { 1, 0, 0}, { 0, 0, 1}, }, /* bottom/lower-left */ +}; + +typedef union { + struct { + int x; + int y; + int z; + } u; + int v[SENSOR_DATA_SIZE]; +} raw_data; + +struct dmt_data { + struct platform_device *pdevice; + struct device *class_dev; + struct class *class; + struct input_dev *input; + struct i2c_client *client; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif + struct delayed_work delaywork; + struct work_struct work; + struct mutex data_mutex; + struct mutex enable_mutex; /* for suspend */ + raw_data last; /* RawData */ + raw_data offset; /* Offset */ +#ifdef SW_FILTER + int sum[SENSOR_DATA_SIZE]; /* SW_FILTER sum */ + int bufferave[3][32]; + s8 aveflag; /* FULL bufferave[][] */ + s8 pointer; /* last update data */ +#endif + wait_queue_head_t open_wq; + atomic_t active; + atomic_t delay; + atomic_t enable; + int filter; + int position; /* must int type ,for Kconfig setup */ + atomic_t addr; +#ifdef DMT_DEBUG_DATA + struct mutex suspend_mutex; + int suspend; +#endif +}; + +#define ACC_DATA_FLAG 0 +#define MAG_DATA_FLAG 1 +#define ORI_DATA_FLAG 2 +#define DMT_NUM_SENSORS 3 + +/* ABS axes parameter range [um/s^2] (for input event) */ +#define GRAVITY_EARTH 9806550 +#define ABSMAX (GRAVITY_EARTH * 2) +#define ABSMIN (-GRAVITY_EARTH * 2) + +#endif diff --git a/ANDROID_3.4.5/drivers/input/sensor/dmard10_gsensor/Makefile b/ANDROID_3.4.5/drivers/input/sensor/dmard10_gsensor/Makefile new file mode 100755 index 00000000..3241f881 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/dmard10_gsensor/Makefile @@ -0,0 +1,34 @@ +KERNELDIR=../../../../ +#KERNELDIR=/home/hangyan/android8850/kernel/ANDROID_3.0.8 +CROSS = arm_1103_le- +CC= $(CROSS)gcc +LD= $(CROSS)ld +STRIP = $(CROSS)strip + +DEBUG = n + +# Add your debugging flag (or not) to EXTRA_CFLAGS +ifeq ($(DEBUG),y) +# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines +DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines + +else + DEBFLAGS = -O2 -Wall +endif + +EXTRA_CFLAGS += $(DEBFLAGS) + + +MY_MODULE_NAME=s_wmt_gsensor_dmard10 + +obj-m := $(MY_MODULE_NAME).o +$(MY_MODULE_NAME)-objs := dmt10.o + +default: + $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules + $(STRIP) --strip-debug $(MY_MODULE_NAME).ko + rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions + +clean: + rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers + diff --git a/ANDROID_3.4.5/drivers/input/sensor/dmard10_gsensor/dmt10.c b/ANDROID_3.4.5/drivers/input/sensor/dmard10_gsensor/dmt10.c new file mode 100755 index 00000000..9810ea3a --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/dmard10_gsensor/dmt10.c @@ -0,0 +1,1702 @@ +/* + * @file drivers/misc/dmt10.c + * @brief DMT g-sensor Linux device driver + * @author Domintech Technology Co., Ltd (http://www.domintech.com.tw) + * @version 1.06 + * @date 2013/08/14 + * @section LICENSE + * + * Copyright 2012 Domintech Technology Co., Ltd + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ +#include "dmt10.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../sensor.h" + +////////////////////////////////////////////////////////// +static struct wmt_gsensor_data l_sensorconfig = { + .op = 0, + .int_gpio = 3, + .samp = 5, + .xyz_axis = { + {ABS_X, -1}, + {ABS_Y, 1}, + {ABS_Z, -1}, + }, + .sensor_proc = NULL, + .isdbg = 0, + .sensor_samp = 10, // 1 sample/second + .sensor_enable = 1, // enable sensor + .test_pass = 0, // for test program + .offset={0,0,0}, +}; + +static struct class* l_dev_class = NULL; +static void update_var(void); + +//////////////////////////////////////////////////////////// + + +static unsigned int interval; +static int D10_write_offset_to_file(struct i2c_client *client); +void D10_read_offset_from_file(struct i2c_client *client); +#define DMT_BROADCAST_APK_ENABLE +char D10_OffsetFileName[] = "/data/misc/gsensor_offset.txt"; /* FILE offset.txt */ +char DmtXXFileName[] = "/data/misc/dmt_sensor.txt"; +static int create_devidfile(void); +static struct dmt_data *s_dmt; +static int device_init(void); +static void device_exit(void); + +static int device_open(struct inode*, struct file*); +static long device_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); +static int device_close(struct inode*, struct file*); + +static int dmard10_suspend(struct platform_device *pdev, pm_message_t state); +static int dmard10_resume(struct platform_device *pdev); + +/*static int device_i2c_suspend(struct i2c_client *client, pm_message_t mesg); +static int device_i2c_resume(struct i2c_client *client); +static int __devinit device_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id); +static int __devexit device_i2c_remove(struct i2c_client *client);*/ +static int D10_i2c_read_xyz(struct i2c_client *client, int *xyz); +static int device_i2c_rxdata(struct i2c_client *client, unsigned char *rxDat, int length); +static int device_i2c_txdata(struct i2c_client *client, unsigned char *txData, int length); + +static int dmt_get_filter(struct i2c_client *client); +static int dmt_set_filter(struct i2c_client *client,int); +static int dmt_get_position(struct i2c_client *client); +static int dmt_set_position(struct i2c_client *client,int); +static int DMT_GetOpenStatus(struct i2c_client *client){ + struct dmt_data *dmt = i2c_get_clientdata(client); + GSE_LOG("start active=%d\n",dmt->active.counter); + wait_event_interruptible(dmt->open_wq, (atomic_read(&dmt->active) != 0)); + return 0; +} + +static int DMT_GetCloseStatus(struct i2c_client *client){ + struct dmt_data *dmt = i2c_get_clientdata(client); + GSE_LOG("start active=%d\n",dmt->active.counter); + wait_event_interruptible(dmt->open_wq, (atomic_read(&dmt->active) <= 0)); + return 0; +} + +static void DMT_sysfs_update_active_status(struct dmt_data *dmt , int en){ + unsigned long dmt_delay; + if(en){ + dmt_delay=msecs_to_jiffies(atomic_read(&dmt->delay)); + if(dmt_delay<1) + dmt_delay=1; + + GSE_LOG("schedule_delayed_work start with delay time=%lu\n",dmt_delay); + schedule_delayed_work(&dmt->delaywork,dmt_delay); + } + else + cancel_delayed_work_sync(&dmt->delaywork); +} + +static bool get_value_as_int(char const *buf, size_t size, int *value){ + long tmp; + if (size == 0) + return false; + /* maybe text format value */ + if ((buf[0] == '0') && (size > 1)) { + if ((buf[1] == 'x') || (buf[1] == 'X')) { + /* hexadecimal format */ + if (0 != strict_strtol(buf, 16, &tmp)) + return false; + } else { + /* octal format */ + if (0 != strict_strtol(buf, 8, &tmp)) + return false; + } + } else { + /* decimal format */ + if (0 != strict_strtol(buf, 10, &tmp)) + return false; + } + + if (tmp > INT_MAX) + return false; + + *value = tmp; + return true; +} +static bool get_value_as_int64(char const *buf, size_t size, long long *value) +{ + long long tmp; + if (size == 0) + return false; + /* maybe text format value */ + if ((buf[0] == '0') && (size > 1)) { + if ((buf[1] == 'x') || (buf[1] == 'X')) { + /* hexadecimal format */ + if (0 != strict_strtoll(buf, 16, &tmp)) + return false; + } else { + /* octal format */ + if (0 != strict_strtoll(buf, 8, &tmp)) + return false; + } + } else { + /* decimal format */ + if (0 != strict_strtoll(buf, 10, &tmp)) + return false; + } + + if (tmp > LLONG_MAX) + return false; + + *value = tmp; + return true; +} +/* sysfs enable show & store */ +static ssize_t dmt_sysfs_enable_show( + struct dmt_data *dmt, char *buf, int pos) +{ + char str[2][16]={"ACC enable OFF","ACC enable ON"}; + int flag; + flag=atomic_read(&dmt->enable); + return sprintf(buf, "%s\n", str[flag]); +} + +static ssize_t dmt_sysfs_enable_store( + struct dmt_data *dmt, char const *buf, size_t count, int pos) +{ + int en = 0; + if (NULL == buf) + return -EINVAL; + //GSE_LOG("buf=%x %x\n", buf[0], buf[1]); + if (0 == count) + return 0; + + if (false == get_value_as_int(buf, count, &en)) + return -EINVAL; + + en = en ? 1 : 0; + + atomic_set(&dmt->enable,en); + DMT_sysfs_update_active_status(dmt , en); + return count; +} + +static ssize_t dmt_enable_show(struct device *dev, struct device_attribute *attr, char *buf){ + return dmt_sysfs_enable_show( dev_get_drvdata(dev), buf, ACC_DATA_FLAG); +} + +static ssize_t dmt_enable_store( struct device *dev, struct device_attribute *attr, char const *buf, size_t count){ + return dmt_sysfs_enable_store( dev_get_drvdata(dev), buf, count, ACC_DATA_FLAG); +} + +/* sysfs delay show & store*/ +static ssize_t dmt_sysfs_delay_show( struct dmt_data *dmt, char *buf, int pos){ + return sprintf(buf, "%d\n", atomic_read(&dmt->delay)); +} + +static ssize_t dmt_sysfs_delay_store( struct dmt_data *dmt, char const *buf, size_t count, int pos){ + long long val = 0; + + if (NULL == buf) + return -EINVAL; + + if (0 == count) + return 0; + + if (false == get_value_as_int64(buf, count, &val)) + return -EINVAL; + + atomic_set(&dmt->delay, (unsigned int) val); + GSE_LOG("Driver attribute set delay =%lld\n", val); + + return count; +} + +static ssize_t dmt_delay_show( struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return dmt_sysfs_delay_show( dev_get_drvdata(dev), buf, ACC_DATA_FLAG); +} + +static ssize_t dmt_delay_store( struct device *dev, + struct device_attribute *attr, + char const *buf, + size_t count) +{ + return dmt_sysfs_delay_store( dev_get_drvdata(dev), buf, count, ACC_DATA_FLAG); +} +/* sysfs position show & store */ +static ssize_t dmt_position_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct dmt_data *dmt = input_get_drvdata(input); + + return sprintf(buf, "%d\n", dmt_get_position(dmt->client)); +} + +static ssize_t dmt_position_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct input_dev *input = to_input_dev(dev); + struct dmt_data *dmt = input_get_drvdata(input); + unsigned long position; + int ret; + + ret = strict_strtoul(buf, 10, &position); + if (ret < 0) + return count; + + dmt_set_position(dmt->client, position); + return count; +} +/* sysfs offset show & store */ +static ssize_t dmt_offset_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct dmt_data *dmt = input_get_drvdata(input); + return sprintf(buf, "( %d %d %d )\n", dmt->offset.u.x, dmt->offset.u.y, dmt->offset.u.z); +} + +static ssize_t dmt_offset_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct input_dev *input = to_input_dev(dev); + struct dmt_data *dmt = input_get_drvdata(input); + sscanf(buf, "%d %d %d", (int *)&dmt->offset.v[0], (int *)&dmt->offset.v[1], (int *)&dmt->offset.v[2]); + D10_write_offset_to_file(dmt->client); + update_var(); + return count; +} +/* sysfs filter show & store */ +static ssize_t dmt_filter_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct dmt_data *dmt = input_get_drvdata(input); + + return sprintf(buf, "%d\n", dmt_get_filter(dmt->client)); +} + +static ssize_t dmt_filter_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct input_dev *input = to_input_dev(dev); + struct dmt_data *dmt = input_get_drvdata(input); + unsigned long filter; + int ret; + + ret = strict_strtoul(buf, 10, &filter); + if (ret < 0) + return count; + + dmt_set_filter(dmt->client, filter); + return count; +} + +/* sysfs data show */ +static ssize_t dmt_acc_private_data_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct dmt_data *dmt = input_get_drvdata(input); + raw_data accel; + + mutex_lock(&dmt->data_mutex); + accel = dmt->last; + mutex_unlock(&dmt->data_mutex); + + return sprintf(buf, "( %d %d %d )\n", dmt->last.v[0], dmt->last.v[1], dmt->last.v[2]); +} +/* sysfs id show */ +static ssize_t dmt_id_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + char str[8]={GSENSOR_ID}; + return sprintf(buf, "%s\n", str); +} +/* sysfs debug_suspend show & store */ +#ifdef DMT_DEBUG_DATA +static ssize_t dmt_debug_suspend_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct dmt_data *dmt = input_get_drvdata(input); + int suspend = dmt->suspend; + + mutex_lock(&dmt->suspend_mutex); + suspend = sprintf(buf, "%d\n", dmt->suspend); + mutex_unlock(&dmt->suspend_mutex); + return suspend; +} + +static ssize_t dmt_debug_suspend_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct input_dev *input = to_input_dev(dev); + struct dmt_data *dmt = input_get_drvdata(input); + unsigned long suspend; + pm_message_t msg; + int ret; + + ret = strict_strtoul(buf, 10, &suspend); + if (ret < 0) + return count; + + memset(&msg, 0, sizeof(pm_message_t)); + + mutex_lock(&dmt->suspend_mutex); + + if (suspend) { + dmard10_suspend(dmt->pdevice, msg); + dmt->suspend = 1; + } else { + dmard10_resume(dmt->pdevice); + dmt->suspend = 0; + } + + mutex_unlock(&dmt->suspend_mutex); + + return count; +} +/* sysfs reg_read show & store */ +static ssize_t dmt_reg_read_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct dmt_data *dmt = dev_get_drvdata(dev); + int err; + unsigned char i2c[1]; + + i2c[0] = (unsigned char)atomic_read(&dmt->addr); + err = device_i2c_rxdata(dmt->client, i2c, 1); + if (err < 0) + return err; + + return sprintf(buf, "0x%02X\n", i2c[0]); +} + +static ssize_t dmt_reg_read_store(struct device *dev, + struct device_attribute *attr, + char const *buf, + size_t count) +{ + struct dmt_data *dmt = dev_get_drvdata(dev); + int addr = 0; + + if (NULL == buf) + return -EINVAL; + + if (0 == count) + return 0; + + if (false == get_value_as_int(buf, count, &addr)) + return -EINVAL; + + if (addr < 0 || 128 < addr) + return -EINVAL; + + atomic_set(&dmt->addr, addr); + + return 1; +} +#endif /* DEBUG */ +/********************************************************************* + * + * SysFS attribute functions + * + * directory : /sys/class/accelemeter/dmardXX/ + * files : + * - enable_acc [rw] [t] : enable flag for accelerometer + * - delay_acc [rw] [t] : delay in nanosecond for accelerometer + * - position [rw] [t] : chip mounting position + * - offset [rw] [t] : offset + * - data [r] [t] : raw data + * - id [r] [t] : chip id + * + * debug : + * - debug_suspend [w] [t] : suspend test + * - reg_read [rw] [t] : Read register + * - reg_write [rw] [t] : Weite register + * + * [rw]= read/write + * [r] = read only + * [w] = write only + * [b] = binary format + * [t] = text format + */ + +static struct device_attribute DMT_attributes[] = { + __ATTR(enable_acc, 0660, dmt_enable_show, dmt_enable_store), + __ATTR(delay_acc, 0660, dmt_delay_show, dmt_delay_store), + __ATTR(position, 0660, dmt_position_show, dmt_position_store), + __ATTR(offset, 0660, dmt_offset_show, dmt_offset_store), + __ATTR(filter, 0660, dmt_filter_show, dmt_filter_store), + __ATTR(data, 0660, dmt_acc_private_data_show, NULL), + __ATTR(id, 0660, dmt_id_show, NULL), +#ifdef DMT_DEBUG_DATA + __ATTR(debug_suspend, 0660, dmt_debug_suspend_show,dmt_debug_suspend_store), + __ATTR(reg_read, 0660, dmt_reg_read_show, dmt_reg_read_store), + __ATTR(reg_write, 0660, NULL, NULL), +#endif // DEBUG + __ATTR_NULL, +}; + +static char const *const ACCELEMETER_CLASS_NAME = "accelemeter"; +static char const *const GSENSOR_DEVICE_NAME = SENSOR_I2C_NAME; +static char const *const device_link_name = "i2c"; +static dev_t const dmt_device_dev_t = MKDEV(MISC_MAJOR, MISC_DYNAMIC_MINOR); + +// dmt sysfs functions +static int create_device_attributes(struct device *dev, struct device_attribute *attrs){ + int i; + int err = 0; + for (i = 0 ; NULL != attrs[i].attr.name ; ++i) { + err = device_create_file(dev, &attrs[i]); + if (0 != err) + break; + } + + if (0 != err) { + for (; i >= 0 ; --i) + device_remove_file(dev, &attrs[i]); + } + return err; +} + +static void remove_device_attributes( + struct device *dev, + struct device_attribute *attrs) +{ + int i; + + for (i = 0 ; NULL != attrs[i].attr.name ; ++i) + device_remove_file(dev, &attrs[i]); +} + +static int create_sysfs_interfaces(struct dmt_data *dmt) +{ + int err; + + if (NULL == dmt) + return -EINVAL; + + err = 0; + dmt->class = class_create(THIS_MODULE, ACCELEMETER_CLASS_NAME); + if (IS_ERR(dmt->class)) { + err = PTR_ERR(dmt->class); + goto exit_class_create_failed; + } + + dmt->class_dev = device_create( + dmt->class, + NULL, + dmt_device_dev_t, + dmt, + GSENSOR_DEVICE_NAME); + if (IS_ERR(dmt->class_dev)) { + err = PTR_ERR(dmt->class_dev); + goto exit_class_device_create_failed; + } + + err = sysfs_create_link( + &dmt->class_dev->kobj, + &dmt->client->dev.kobj, + device_link_name); + if (0 > err) + goto exit_sysfs_create_link_failed; + + err = create_device_attributes( + dmt->class_dev, + DMT_attributes); + if (0 > err) + goto exit_device_attributes_create_failed; +#if 0 + err = create_device_binary_attributes( + &dmt->class_dev->kobj, + dmt_bin_attributes); + if (0 > err) + goto exit_device_binary_attributes_create_failed; +#endif + + return err; + +#if 0 +exit_device_binary_attributes_create_failed: + remove_device_attributes(dmt->class_dev, dmt_attributes); +#endif +exit_device_attributes_create_failed: + sysfs_remove_link(&dmt->class_dev->kobj, device_link_name); +exit_sysfs_create_link_failed: + device_destroy(dmt->class, dmt_device_dev_t); +exit_class_device_create_failed: + dmt->class_dev = NULL; + class_destroy(dmt->class); +exit_class_create_failed: + dmt->class = NULL; + return err; +} + +static void remove_sysfs_interfaces(struct dmt_data *dmt){ + if (NULL == dmt) + return; + + if (NULL != dmt->class_dev) { + + remove_device_attributes( + dmt->class_dev, + DMT_attributes); + sysfs_remove_link( + &dmt->class_dev->kobj, + device_link_name); + dmt->class_dev = NULL; + } + if (NULL != dmt->class) { + device_destroy( + dmt->class, + dmt_device_dev_t); + class_destroy(dmt->class); + dmt->class = NULL; + } +} + +int D10_input_init(struct i2c_client *client){ + struct dmt_data *dmt = i2c_get_clientdata(client); + int err = 0; + dmt->input = input_allocate_device(); + if (!dmt->input){ + GSE_ERR("input device allocate ERROR !!\n"); + return -ENOMEM; + } + else + GSE_LOG("input device allocate Success !!\n"); + /* Setup input device */ + //dmt->input->name = SENSOR_I2C_NAME; + set_bit(EV_ABS, dmt->input->evbit); + /* Accelerometer [-78.5, 78.5]m/s2 in Q16 */ + input_set_abs_params(dmt->input, ABS_X, ABSMIN, ABSMAX, 0, 0); + input_set_abs_params(dmt->input, ABS_Y, ABSMIN, ABSMAX, 0, 0); + input_set_abs_params(dmt->input, ABS_Z, ABSMIN, ABSMAX, 0, 0); + /* Set InputDevice Name */ + dmt->input->name = INPUT_NAME_ACC; + /* Register */ + err = input_register_device(dmt->input); + if (err) { + GSE_ERR("input_register_device ERROR !!\n"); + input_free_device(dmt->input); + return err; + } + GSE_LOG("input_register_device SUCCESS %d !! \n",err); + + return err; +} + +int D10_calibrate(struct i2c_client *client) +{ + struct dmt_data *dmt = i2c_get_clientdata(client); + raw_data avg; + int i, j; + long xyz_acc[SENSOR_DATA_SIZE]; + int xyz[SENSOR_DATA_SIZE]; + /* initialize the offset value */ + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + dmt->offset.v[i] = 0; + /* initialize the accumulation buffer */ + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + xyz_acc[i] = 0; + + for(i = 0; i < AVG_NUM; i++) { + D10_i2c_read_xyz(client, (int *)&xyz); + for(j = 0; j < SENSOR_DATA_SIZE; ++j) + xyz_acc[j] += xyz[j]; + } + /* calculate averages */ + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + avg.v[i] = xyz_acc[i] / AVG_NUM; + + if(avg.v[2] < 0){ + dmt->offset.u.x = avg.v[0] ; + dmt->offset.u.y = avg.v[1] ; + dmt->offset.u.z = avg.v[2] + DEFAULT_SENSITIVITY; + return CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Z_POSITIVE; + } + else{ + dmt->offset.u.x = avg.v[0] ; + dmt->offset.u.y = avg.v[1] ; + dmt->offset.u.z = avg.v[2] - DEFAULT_SENSITIVITY; + return CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Z_NEGATIVE; + } + return 0; +} + +int dmard10_init(struct i2c_client *client){ + unsigned char buffer[7], buffer2[2]; + /* 1. check D10 , VALUE_STADR = 0x55 , VALUE_STAINT = 0xAA */ + buffer[0] = REG_STADR; + buffer2[0] = REG_STAINT; + + device_i2c_rxdata(client, buffer, 2); + device_i2c_rxdata(client, buffer2, 2); + + if( buffer[0] == VALUE_STADR || buffer2[0] == VALUE_STAINT){ + GSE_LOG(" REG_STADR_VALUE = %d , REG_STAINT_VALUE = %d\n", buffer[0], buffer2[0]); + } + else{ + GSE_LOG(" REG_STADR_VALUE = %d , REG_STAINT_VALUE = %d \n", buffer[0], buffer2[0]); + return -1; + } + /* 2. Powerdown reset */ + buffer[0] = REG_PD; + buffer[1] = VALUE_PD_RST; + device_i2c_txdata(client, buffer, 2); + /* 3. ACTR => Standby mode => Download OTP to parameter reg => Standby mode => Reset data path => Standby mode */ + buffer[0] = REG_ACTR; + buffer[1] = MODE_Standby; + buffer[2] = MODE_ReadOTP; + buffer[3] = MODE_Standby; + buffer[4] = MODE_ResetDataPath; + buffer[5] = MODE_Standby; + device_i2c_txdata(client, buffer, 6); + /* 4. OSCA_EN = 1 ,TSTO = b'000(INT1 = normal, TEST0 = normal) */ + buffer[0] = REG_MISC2; + buffer[1] = VALUE_MISC2_OSCA_EN; + device_i2c_txdata(client, buffer, 2); + /* 5. AFEN = 1(AFE will powerdown after ADC) */ + buffer[0] = REG_AFEM; + buffer[1] = VALUE_AFEM_AFEN_Normal; + buffer[2] = VALUE_CKSEL_ODR_100_204; + buffer[3] = VALUE_INTC; + buffer[4] = VALUE_TAPNS_Ave_4; + buffer[5] = 0x00; // DLYC, no delay timing + buffer[6] = 0x07; // INTD=1 (push-pull), INTA=1 (active high), AUTOT=1 (enable T) + device_i2c_txdata(client, buffer, 7); + /* 6. write TCGYZ & TCGX */ + buffer[0] = REG_WDAL; // REG:0x01 + buffer[1] = 0x00; // set TC of Y,Z gain value + buffer[2] = 0x00; // set TC of X gain value + buffer[3] = 0x03; // Temperature coefficient of X,Y,Z gain + device_i2c_txdata(client, buffer, 4); + + buffer[0] = REG_ACTR; // REG:0x00 + buffer[1] = MODE_Standby; // Standby + buffer[2] = MODE_WriteOTPBuf; // WriteOTPBuf + buffer[3] = MODE_Standby; // Standby + device_i2c_txdata(client, buffer, 4); + //buffer[0] = REG_TCGYZ; + //device_i2c_rxdata(client, buffer, 2); + //GSE_LOG(" TCGYZ = %d, TCGX = %d \n", buffer[0], buffer[1]); + + /* 7. Activation mode */ + buffer[0] = REG_ACTR; + buffer[1] = MODE_Active; + device_i2c_txdata(client, buffer, 2); + return 0; +} + +void D10_set_offset(struct i2c_client *client, int val[3]){ + struct dmt_data *dmt = i2c_get_clientdata(client); + int i; + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + dmt->offset.v[i] = val[i]; +} + +struct file_operations sensor_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = device_ioctl, + .open = device_open, + .release = device_close, +}; + +static struct miscdevice dmt_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = SENSOR_I2C_NAME, + .fops = &sensor_fops, +}; + +static int sensor_close_dev(struct i2c_client *client){ + char buffer[3]; + GSE_FUN(); + buffer[0] = REG_AFEM; + buffer[1] = 0x0f; + device_i2c_txdata(client,buffer, 2); + buffer[0] = REG_ACTR; + buffer[1] = MODE_Standby; + buffer[2] = MODE_Off; + device_i2c_txdata(client,buffer, 3); + return 0; +} + +static void dmard10_shutdown(struct platform_device *pdev) +{ + flush_delayed_work_sync(&s_dmt->delaywork); + DMT_sysfs_update_active_status(s_dmt , 0); +} + + +//static int device_i2c_suspend(struct i2c_client *client, pm_message_t mesg){ +static int dmard10_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct dmt_data *dmt = i2c_get_clientdata(s_dmt->client); + flush_delayed_work_sync(&dmt->delaywork); + DMT_sysfs_update_active_status(dmt , 0); + return sensor_close_dev(dmt->client); +} + +//static int device_i2c_resume(struct i2c_client *client){ +static int dmard10_resume(struct platform_device *pdev) +{ + struct dmt_data *dmt = i2c_get_clientdata(s_dmt->client); + int en = 1; + GSE_FUN(); + printk("dmt->enable=%d",dmt->enable); + dmard10_init(dmt->client); + atomic_set(&dmt->enable,en); + DMT_sysfs_update_active_status(dmt , en); + return 0; +} +/* +static int __devexit device_i2c_remove(struct i2c_client *client){ + return 0; +} + +static const struct i2c_device_id device_i2c_ids[] = { + { SENSOR_I2C_NAME, 0}, + { } +}; + +static struct i2c_driver device_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = SENSOR_I2C_NAME, + }, + .class = I2C_CLASS_HWMON, + .id_table = device_i2c_ids, + .probe = device_i2c_probe, + .remove = __devexit_p(device_i2c_remove), +#ifdef CONFIG_HAS_EARLYSUSPEND + .suspend = device_i2c_suspend, + .resume = device_i2c_resume, +#endif +}; +*/ +static int device_open(struct inode *inode, struct file *filp){ + return 0; +} + +static long device_ioctl(struct file *file, unsigned int cmd, unsigned long arg){ + //struct i2c_client *client = (struct i2c_client *)file->private_data; + //struct dmt_data *dmt = (struct dmt_data*)i2c_get_clientdata(client); + + int err = 0, ret = 0, i; + int intBuf[SENSOR_DATA_SIZE], xyz[SENSOR_DATA_SIZE]; + /* check type */ + if (_IOC_TYPE(cmd) != IOCTL_MAGIC) return -ENOTTY; + + /* check user space pointer is valid */ + if (_IOC_DIR(cmd) & _IOC_READ) + err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd)); + else if (_IOC_DIR(cmd) & _IOC_WRITE) + err = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd)); + if (err) return -EFAULT; + + switch(cmd) { + case SENSOR_RESET: + ret = dmard10_init(s_dmt->client); + return ret; + + case SENSOR_CALIBRATION: + /* get orientation info */ + //if(copy_from_user(&intBuf, (int*)arg, sizeof(intBuf))) return -EFAULT; + D10_calibrate(s_dmt->client); + GSE_LOG("Sensor_calibration:%d %d %d\n", s_dmt->offset.u.x, s_dmt->offset.u.y, s_dmt->offset.u.z); + /* save file */ + D10_write_offset_to_file(s_dmt->client); + update_var(); + + /* return the offset */ + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + intBuf[i] = s_dmt->offset.v[i]; + + ret = copy_to_user((int *)arg, &intBuf, sizeof(intBuf)); + return ret; + + case SENSOR_GET_OFFSET: + /* get data from file */ + D10_read_offset_from_file(s_dmt->client); + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + intBuf[i] = s_dmt->offset.v[i]; + + ret = copy_to_user((int *)arg, &intBuf, sizeof(intBuf)); + return ret; + + case SENSOR_SET_OFFSET: + ret = copy_from_user(&intBuf, (int *)arg, sizeof(intBuf)); + D10_set_offset(s_dmt->client , intBuf); + /* write into file */ + D10_write_offset_to_file(s_dmt->client); + update_var(); + return ret; + + case SENSOR_READ_ACCEL_XYZ: + D10_i2c_read_xyz(s_dmt->client, (int *)&xyz); + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + intBuf[i] = xyz[i] - s_dmt->offset.v[i]; + + ret = copy_to_user((int*)arg, &intBuf, sizeof(intBuf)); + return ret; + + case SENSOR_SETYPR: + if(copy_from_user(&intBuf, (int*)arg, sizeof(intBuf))) { + GSE_LOG("%s: -EFAULT\n",__func__); + return -EFAULT; + } + input_report_abs(s_dmt->input, ABS_X, intBuf[0]); + input_report_abs(s_dmt->input, ABS_Y, intBuf[1]); + input_report_abs(s_dmt->input, ABS_Z, intBuf[2]); + input_sync(s_dmt->input); + GSE_LOG("SENSOR_SETYPR OK! x=%d,y=%d,z=%d\n",intBuf[0],intBuf[1],intBuf[2]); + return ret; + + case SENSOR_GET_OPEN_STATUS: + GSE_LOG("Going into DMT_GetOpenStatus()\n"); + ret = DMT_GetOpenStatus(s_dmt->client); + return ret; + + case SENSOR_GET_CLOSE_STATUS: + GSE_LOG("Going into DMT_GetCloseStatus()\n"); + ret = DMT_GetCloseStatus(s_dmt->client); + return ret; + + case SENSOR_GET_DELAY: + ret = copy_to_user((int*)arg, &interval, sizeof(interval)); + return ret; + + default: /* redundant, as cmd was checked against MAXNR */ + return -ENOTTY; + } + + return 0; +} + +static int device_close(struct inode *inode, struct file *filp){ + return 0; +} + +/***** I2C I/O function ***********************************************/ +static int device_i2c_rxdata( struct i2c_client *client, unsigned char *rxData, int length){ + struct i2c_msg msgs[] = { + {.addr = client->addr, .flags = 0, .len = 1, .buf = rxData,}, + {.addr = client->addr, .flags = I2C_M_RD, .len = length, .buf = rxData,}, + }; + //unsigned char addr = rxData[0]; + if (i2c_transfer(client->adapter, msgs, 2) < 0) { + dev_err(&client->dev, "%s: transfer failed.", __func__); + return -EIO; + } + //DMT_DATA(&client->dev, "RxData: len=%02x, addr=%02x, data=%02x\n", + //length, addr, rxData[0]); + + return 0; +} + +static int device_i2c_txdata( struct i2c_client *client, unsigned char *txData, int length){ + struct i2c_msg msg[] = { + {.addr = client->addr, .flags = 0, .len = length, .buf = txData,}, + }; + + if (i2c_transfer(client->adapter, msg, 1) < 0) { + dev_err(&client->dev, "%s: transfer failed.", __func__); + return -EIO; + } + //DMT_DATA(&client->dev, "TxData: len=%02x, addr=%02x data=%02x\n", + //length, txData[0], txData[1]); + return 0; +} + +static int D10_i2c_read_xyz(struct i2c_client *client, int *xyz_p){ + struct dmt_data *dmt = i2c_get_clientdata(client); + u8 buffer[11]; + s16 xyzTmp[SENSOR_DATA_SIZE]; + int pos = dmt->position; + int i, j , k; + /* get xyz high/low bytes, 0x12 */ + buffer[0] = REG_STADR; + /* Read acceleration data */ + if (device_i2c_rxdata(client, buffer, 10)!= 0) + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + xyz_p[i] = 0; + else + for(i = 0; i < SENSOR_DATA_SIZE; ++i){ + xyz_p[i] = 0; + /* merge xyz high/low bytes & 1g = 128 becomes 1g = 1024 */ + mutex_lock(&dmt->data_mutex); + xyzTmp[i] = ((int16_t)((buffer[2*(i+1)+1] << 8)) | buffer[2*(i+1)] ) << 3; + mutex_unlock(&dmt->data_mutex); + } +#ifdef SW_FILTER + if( dmt->aveflag >= dmt->filter){ + for(i = 0; i < SENSOR_DATA_SIZE; ++i){ + dmt->sum[i] = dmt->sum[i] - dmt->bufferave[i][dmt->pointer] + xyzTmp[i]; + } + /* transfer to the default layout */ + for(i = 0; i < SENSOR_DATA_SIZE; ++i){ + for(j = 0; j < SENSOR_DATA_SIZE; j++) + xyz_p[i] += (int)(dmt->sum[j]/dmt->filter * dmt_position_map[pos][i][j]); + } + } + else{ + /* init dmt->sum */ + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + dmt->sum[i] = xyzTmp[i]; +#endif + /* transfer to the default layout */ + for(i = 0; i < SENSOR_DATA_SIZE; ++i){ + for(j = 0; j < SENSOR_DATA_SIZE; j++){ + xyz_p[i] += (int)(xyzTmp[j] * dmt_position_map[pos][i][j]); + //GSE_LOG("%04d, %04d,%d \n", xyz_p[i], xyzTmp[j], dmt_position_map[pos][i][j]); + } + } + //GSE_LOG("xyz_p: %04d , %04d , %04d\n", xyz_p[0], xyz_p[1], xyz_p[2]); +#ifdef SW_FILTER + dmt->aveflag++; + } + /* init dmt->sum */ + for(i = 0; i < SENSOR_DATA_SIZE; ++i){ + dmt->sum[i] = 0; + } + dmt->pointer++; + dmt->pointer %= dmt->filter; + for(i = 0; i < SENSOR_DATA_SIZE; ++i){ + dmt->bufferave[i][dmt->pointer] = xyzTmp[i]; + } + for(i = 0; i < SENSOR_DATA_SIZE; ++i){ + for(k = 0; k < dmt->filter; ++k){ + dmt->sum[i] += dmt->bufferave[i][k]; + } + } +#endif + return 0; +} + +static void DMT_work_func(struct work_struct *delaywork){ + struct dmt_data *dmt = container_of(delaywork, struct dmt_data, delaywork.work); + int i; + //static bool firsttime=true; + raw_data xyz; + unsigned long dmt_delay = msecs_to_jiffies(atomic_read(&dmt->delay)); + + + D10_i2c_read_xyz(dmt->client, (int *)&xyz.v); + /* dmt->last = RawData - Offset */ + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + dmt->last.v[i] = xyz.v[i] - dmt->offset.v[i]; + //GSE_LOG("@DMTRaw @ X/Y/Z axis: %04d , %04d , %04d\n", xyz.v[0], xyz.v[1], xyz.v[2]); + //GSE_LOG("@Offset @ X/Y/Z axis: %04d , %04d , %04d\n", dmt->offset.u.x, dmt->offset.u.y, dmt->offset.u.z); + //GSE_LOG("@Raw-Offset@ X/Y/Z axis: %04d , %04d , %04d ,dmt_delay=%d\n", dmt->last.u.x, dmt->last.u.y, dmt->last.u.z, atomic_read(&dmt->delay)); + + + input_report_abs(dmt->input, ABS_X, dmt->last.v[l_sensorconfig.xyz_axis[0][0]]*l_sensorconfig.xyz_axis[0][1]);//dmt->last.v[0]); + input_report_abs(dmt->input, ABS_Y, dmt->last.v[l_sensorconfig.xyz_axis[1][0]]*l_sensorconfig.xyz_axis[1][1]);//dmt->last.v[1]); + input_report_abs(dmt->input, ABS_Z, dmt->last.v[l_sensorconfig.xyz_axis[2][0]]*l_sensorconfig.xyz_axis[2][1]);//dmt->last.v[2]); + input_sync(dmt->input); + + if(dmt_delay < 1) + dmt_delay = 1; + schedule_delayed_work(&dmt->delaywork, dmt_delay); +} + +static int mma10_open(struct inode *node, struct file *fle) +{ + GSE_LOG("open...\n"); + return 0; +} + +static int mma10_close(struct inode *node, struct file *fle) +{ + GSE_LOG("close...\n"); + return 0; +} + +static long mma10_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + int err = 0; + //unsigned char data[6]; + void __user *argp = (void __user *)arg; + short delay, enable; + unsigned int uval = 0; + + + /* cmd mapping */ + switch(cmd) + { + case ECS_IOCTL_APP_SET_DELAY: + // set the rate of g-sensor + if (copy_from_user(&delay, argp, sizeof(short))) + { + printk(KERN_ALERT "Can't get set delay!!!\n"); + return -EFAULT; + } + klog("Get delay=%d\n", delay); + + if ((delay >=0) && (delay < 20)) + { + delay = 20; + } else if (delay > 200) + { + delay = 200; + } + l_sensorconfig.sensor_samp = 1000/delay; + atomic_set(&s_dmt->delay, 1000/delay); + break; + case ECS_IOCTL_APP_SET_AFLAG: + // enable/disable sensor + if (copy_from_user(&enable, argp, sizeof(short))) + { + printk(KERN_ERR "Can't get enable flag!!!\n"); + return -EFAULT; + } + klog("enable=%d\n",enable); + if ((enable >=0) && (enable <=1)) + { + //KMSGINF("driver: disable/enable(%d) gsensor.\n", enable); + + l_sensorconfig.sensor_enable = enable; + atomic_set(&s_dmt->enable,enable); + DMT_sysfs_update_active_status(s_dmt , enable); + + } else { + printk(KERN_ERR "Wrong enable argument in %s !!!\n", __FUNCTION__); + return -EINVAL; + } + break; + case WMT_IOCTL_SENSOR_GET_DRVID: + uval = DMARD10_DRVID; + if (copy_to_user((unsigned int*)arg, &uval, sizeof(unsigned int))) + { + return -EFAULT; + } + GSE_LOG("dmard10_driver_id:%d\n",uval); + break; + case WMT_IOCTL_SENOR_GET_RESOLUTION: + uval = (10<<8) | 1; + if (copy_to_user((unsigned int *)arg, &uval, sizeof(unsigned int))) + { + return -EFAULT; + } + printk("<<<<<< 0) + { + if (sample != l_sensorconfig.sensor_samp) + { + // should do sth + } + //printk(KERN_ALERT "sensor samp=%d(amsr:%d) has been set.\n", sample, amsr); + } else { + klog("Wrong sample argumnet of sensor.\n"); + } + } else if (sscanf(buffer, "enable=%d\n", &enable)) + { + if ((enable < 0) || (enable > 1)) + { + klog("The argument to enable/disable g-sensor should be 0 or 1 !!!\n"); + } else if (enable != l_sensorconfig.sensor_enable) + { + //mma_enable_disable(enable); + l_sensorconfig.sensor_enable = enable; + } + } else if (sscanf(buffer, "sensor_test=%d\n", &test)) + { // for test begin + l_sensorconfig.test_pass = 0; + atomic_set(&s_dmt->enable,1); + DMT_sysfs_update_active_status(s_dmt , 1); + } else if (sscanf(buffer, "sensor_testend=%d\n", &test)) + { // Don nothing only to be compatible the before testing program + atomic_set(&s_dmt->enable,0); + DMT_sysfs_update_active_status(s_dmt , 0); + } + //mutex_unlock(&sense_data_mutex); + return count; +} + +static int sensor_readproc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = 0; + + len = sprintf(page, + "test_pass=%d\nisdbg=%d\nrate=%d\nenable=%d\n", + l_sensorconfig.test_pass, + l_sensorconfig.isdbg, + l_sensorconfig.sensor_samp, + l_sensorconfig.sensor_enable + ); + return len; +} + + +//static int __devinit device_i2c_probe(struct i2c_client *client,const struct i2c_device_id *id){ +static int __devinit dmard10_probe(struct platform_device *pdev) +{ + int i, k, ret = 0; + //struct dmt_data *s_dmt = i2c_get_clientdata(client); + //struct dmt_data *s_dmt; + GSE_FUN(); +/* + if(!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)){ + GSE_ERR("check_functionality failed.\n"); + ret = -ENODEV; + goto exit0; + } + + // Allocate memory for driver data + s_dmt = kzalloc(sizeof(struct dmt_data), GFP_KERNEL); + memset(s_dmt, 0, sizeof(struct dmt_data)); + if (s_dmt == NULL) { + GSE_ERR("alloc data failed.\n"); + ret = -ENOMEM; + goto exit1; + } +*/ + /*for(i = 0; i < SENSOR_DATA_SIZE; ++i) + s_dmt->offset.v[i] = 0;*/ +#ifdef SW_FILTER + s_dmt->pointer = 0; + s_dmt->aveflag = 0; + for(i = 0; i < SENSOR_DATA_SIZE; ++i){ + s_dmt->sum[i] = 0; + for(k = 0; k < SENSOR_DATA_AVG; ++k){ + s_dmt->bufferave[i][k] = 0; + } + } + s_dmt->filter = SENSOR_DATA_AVG; + GSE_LOG("D10_DEFAULT_FILTER: %d\n", s_dmt->filter); +#endif + /* I2C initialization */ + //s_dmt->client = client; + + /* set client data */ + i2c_set_clientdata(s_dmt->client, s_dmt); + /*ret = dmard10_init(client); + if (ret < 0) + goto exit2; + */ + /* input */ + ret = D10_input_init(s_dmt->client); + if (ret){ + GSE_ERR("D10_input_init fail, error code= %d\n",ret); + goto exit3; + } + + /* initialize variables in dmt_data */ + mutex_init(&s_dmt->data_mutex); + mutex_init(&s_dmt->enable_mutex); +#ifdef DMT_DEBUG_DATA + mutex_init(&s_dmt->suspend_mutex); +#endif + init_waitqueue_head(&s_dmt->open_wq); + atomic_set(&s_dmt->active, 0); + atomic_set(&s_dmt->enable, 0); + atomic_set(&s_dmt->delay, 0); + atomic_set(&s_dmt->addr, 0); + /* DMT Acceleration Sensor Mounting Position on Board */ + s_dmt->position = D10_DEFAULT_POSITION; + GSE_LOG("D10_DEFAULT_POSITION: %d\n", s_dmt->position); + //s_dmt->position = (CONFIG_INPUT_DMT_ACCELEROMETER_POSITION); + //GSE_LOG("CONFIG_INPUT_DMT_ACCELEROMETER_POSITION: %d\n", s_dmt->position); + /* Misc device */ + if (misc_register(&dmt_device) < 0){ + GSE_ERR("dmt_dev register failed"); + goto exit4; + } + + /* Setup sysfs */ + if (create_sysfs_interfaces(s_dmt) < 0){ + GSE_ERR("create sysfs failed."); + goto exit5; + } +#ifdef CONFIG_HAS_EARLYSUSPEND + s_dmt->early_suspend.suspend = device_i2c_suspend; + s_dmt->early_suspend.resume = device_i2c_resume; + register_early_suspend(&s_dmt->early_suspend); +#endif + /* Setup driver interface */ + INIT_DELAYED_WORK(&s_dmt->delaywork, DMT_work_func); + GSE_LOG("DMT: INIT_DELAYED_WORK\n"); + + //register ctrl dev + ret = misc_register(&d10_device); + if (ret !=0) { + errlog("Can't register d10_device!\n"); + return -1; + } + // register rd/wr proc + l_sensorconfig.sensor_proc = create_proc_entry(GSENSOR_PROC_NAME, 0666, NULL/*&proc_root*/); + if (l_sensorconfig.sensor_proc != NULL) + { + l_sensorconfig.sensor_proc->write_proc = sensor_writeproc; + l_sensorconfig.sensor_proc->read_proc = sensor_readproc; + } + + //create offset file after factory reset + D10_read_offset_from_file(s_dmt->client); + + return 0; + +exit5: + misc_deregister(&dmt_device); +exit4: + input_unregister_device(s_dmt->input); +exit3: + kfree(s_dmt); +/*exit2: +exit1: +exit0:*/ + return ret; +} +/* +static struct i2c_board_info dmard10_board_info={ + .type = SENSOR_I2C_NAME, + .addr = SENSOR_I2C_ADDR, +}; +*/ +//static struct i2c_client *client; + +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); +static int get_axisset(void) +{ + char varbuf[64]; + int n; + int varlen; + + memset(varbuf, 0, sizeof(varbuf)); + varlen = sizeof(varbuf); + if (wmt_getsyspara("wmt.io.dm10sensor", varbuf, &varlen)) { + errlog("Can't get gsensor config in u-boot!!!!\n"); + return -1; //open it for no env just,not insmod such module 2014-6-30 + } else { + n = sscanf(varbuf, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", + &l_sensorconfig.op, + &l_sensorconfig.int_gpio, + &l_sensorconfig.samp, + &(l_sensorconfig.xyz_axis[0][0]), + &(l_sensorconfig.xyz_axis[0][1]), + &(l_sensorconfig.xyz_axis[1][0]), + &(l_sensorconfig.xyz_axis[1][1]), + &(l_sensorconfig.xyz_axis[2][0]), + &(l_sensorconfig.xyz_axis[2][1]), + &(l_sensorconfig.offset[0]), + &(l_sensorconfig.offset[1]), + &(l_sensorconfig.offset[2]) + ); + if (n != 12) { + errlog("gsensor format is error in u-boot!!!\n"); + return -1; + } + l_sensorconfig.sensor_samp = l_sensorconfig.samp; + + dbg("get the sensor config: %d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d\n", + l_sensorconfig.op, + l_sensorconfig.int_gpio, + l_sensorconfig.samp, + l_sensorconfig.xyz_axis[0][0], + l_sensorconfig.xyz_axis[0][1], + l_sensorconfig.xyz_axis[1][0], + l_sensorconfig.xyz_axis[1][1], + l_sensorconfig.xyz_axis[2][0], + l_sensorconfig.xyz_axis[2][1], + l_sensorconfig.offset[0], + l_sensorconfig.offset[1], + l_sensorconfig.offset[2] + ); + } + return 0; +} + +static void dmard10_platform_release(struct device *device) +{ + GSE_LOG("...\n"); + return; +} + +static int __devexit dmard10_remove(struct platform_device *pdev) +{ + if (l_sensorconfig.sensor_proc != NULL) + { + remove_proc_entry(GSENSOR_PROC_NAME, NULL); + l_sensorconfig.sensor_proc = NULL; + } + //misc_deregister(&d10_device); + return 0; +} + + +static struct platform_device dmard10_device = { + .name = SENSOR_I2C_NAME, + .id = 0, + .dev = { + .release = dmard10_platform_release, + }, +}; + +static struct platform_driver dmard10_driver = { + .probe = dmard10_probe, + .remove = dmard10_remove, + .shutdown = dmard10_shutdown, + .suspend = dmard10_suspend, + .resume = dmard10_resume, + .driver = { + .name = SENSOR_I2C_NAME, + }, +}; + + +static int __init device_init(void){ + //struct device *device; + struct i2c_client *this_client; + int ret = 0; + + // parse g-sensor u-boot arg + ret = get_axisset(); + if (ret < 0) + { + printk("<<<<<%s user choose to no sensor chip!\n", __func__); + return ret; + } + GSE_LOG("D10 gsensor driver: initialize.\n"); + + if (!(this_client = sensor_i2c_register_device(0, SENSOR_I2C_ADDR, SENSOR_I2C_NAME))) + { + printk(KERN_ERR"Can't register gsensor i2c device!\n"); + return -1; + } + + if (dmard10_init(this_client)) + { + GSE_ERR("Failed to init dmard10!\n"); + sensor_i2c_unregister_device(this_client); + return -1; + } + + /* Allocate memory for driver data */ + s_dmt = kzalloc(sizeof(struct dmt_data), GFP_KERNEL); + //memset(s_dmt, 0, sizeof(struct dmt_data)); + if (s_dmt == NULL) { + GSE_ERR("alloc data failed.\n"); + return -ENOMEM; + } + + s_dmt->client = this_client; + s_dmt->pdevice = &dmard10_device; + s_dmt->offset.u.x = l_sensorconfig.offset[0]; + s_dmt->offset.u.y = l_sensorconfig.offset[1]; + s_dmt->offset.u.z = l_sensorconfig.offset[2]; + + + // create the platform device + l_dev_class = class_create(THIS_MODULE, SENSOR_I2C_NAME); + if (IS_ERR(l_dev_class)){ + ret = PTR_ERR(l_dev_class); + printk(KERN_ERR "Can't class_create gsensor device !!\n"); + return ret; + } + if((ret = platform_device_register(&dmard10_device))) + { + GSE_ERR("Can't register dmard10 platform devcie!!!\n"); + return ret; + } + if ((ret = platform_driver_register(&dmard10_driver)) != 0) + { + GSE_ERR("Can't register dmard10 platform driver!!!\n"); + return ret; + } + + return 0; +} + +static void __exit device_exit(void){ + //i2c_unregister_device(client); + //i2c_del_driver(&device_i2c_driver); + GSE_LOG("D10 gsensor driver: release.\n"); + + flush_delayed_work_sync(&s_dmt->delaywork); + cancel_delayed_work_sync(&s_dmt->delaywork); + + input_unregister_device(s_dmt->input); + input_free_device(s_dmt->input); + misc_deregister(&dmt_device); + misc_deregister(&d10_device); + platform_driver_unregister(&dmard10_driver); + platform_device_unregister(&dmard10_device); + sensor_i2c_unregister_device(s_dmt->client); + class_destroy(l_dev_class); + + remove_sysfs_interfaces(s_dmt); + kfree(s_dmt); +} + +static int dmt_get_filter(struct i2c_client *client){ + struct dmt_data *dmt = i2c_get_clientdata(client); + return dmt->filter; +} + +static int dmt_set_filter(struct i2c_client *client, int filter){ + struct dmt_data *dmt = i2c_get_clientdata(client); + if (!((filter >= 1) && (filter <= 32))) + return -1; + dmt->filter = filter; + return 0; +} + +static int dmt_get_position(struct i2c_client *client){ + struct dmt_data *dmt = i2c_get_clientdata(client); + return dmt->position; +} + +static int dmt_set_position(struct i2c_client *client, int position){ + struct dmt_data *dmt = i2c_get_clientdata(client); + if (!((position >= 0) && (position <= 7))) + return -1; + dmt->position = position; + return 0; +} + +extern int wmt_setsyspara(char *varname, char *varval); +static void update_var(void) +{ + char varbuf[64]; + int varlen; + + memset(varbuf, 0, sizeof(varbuf)); + varlen = sizeof(varbuf); + + sprintf(varbuf, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", + l_sensorconfig.op, + l_sensorconfig.int_gpio, + l_sensorconfig.samp, + l_sensorconfig.xyz_axis[0][0], + l_sensorconfig.xyz_axis[0][1], + l_sensorconfig.xyz_axis[1][0], + l_sensorconfig.xyz_axis[1][1], + l_sensorconfig.xyz_axis[2][0], + l_sensorconfig.xyz_axis[2][1], + s_dmt->offset.u.x, + s_dmt->offset.u.y, + s_dmt->offset.u.z + ); + + wmt_setsyspara("wmt.io.dm10sensor",varbuf); +} + +static int D10_write_offset_to_file(struct i2c_client *client){ + struct dmt_data *dmt = i2c_get_clientdata(client); + char r_buf[18] = {0}; + char w_buf[18] = {0}; + //unsigned int orgfs; + struct file *fp; + mm_segment_t fs; + ssize_t ret; + //int8_t i; + + sprintf(w_buf,"%5d %5d %5d", dmt->offset.u.x, dmt->offset.u.y, dmt->offset.u.z); + /* Set segment descriptor associated to kernel space */ + fp = filp_open(D10_OffsetFileName, O_RDWR | O_CREAT, 0777); + if(IS_ERR(fp)){ + GSE_ERR("filp_open %s error!!.\n",D10_OffsetFileName); + return -1; + } + else{ + fs = get_fs(); + //set_fs(KERNEL_DS); + set_fs(get_ds()); + GSE_LOG("filp_open %s SUCCESS!!.\n",D10_OffsetFileName); + //fp->f_op->write(fp,data,18, &fp->f_pos); + //filp_close(fp,NULL); + ret = fp->f_op->write(fp,w_buf,18,&fp->f_pos); + if(ret != 18) + { + printk(KERN_ERR "%s: write error!\n", __func__); + filp_close(fp,NULL); + return -EIO; + } + //fp->f_pos=0x00; + ret = fp->f_op->read(fp,r_buf, 18,&fp->f_pos); + if(ret < 0) + { + printk(KERN_ERR "%s: read error!\n", __func__); + filp_close(fp,NULL); + return -EIO; + } + set_fs(fs); + + // + //printk(KERN_INFO "%s: read ret=%d!", __func__, ret); + /* for(i=0; i<18 ;i++) + { + if(r_buf[i] != w_buf[i]) + { + printk(KERN_ERR "%s: read back error, r_buf[%x](0x%x) != w_buf[%x](0x%x)\n", + __func__, i, r_buf[i], i, w_buf[i]); + filp_close(fp,NULL); + return -EIO; + } + } + */ + + } + filp_close(fp,NULL); + return 0; +} + +void D10_read_offset_from_file(struct i2c_client *client){ + struct dmt_data *dmt = i2c_get_clientdata(client); + unsigned int orgfs; + char data[18]; + struct file *fp; + int ux,uy,uz; + orgfs = get_fs(); + /* Set segment descriptor associated to kernel space */ + set_fs(KERNEL_DS); + + fp = filp_open(D10_OffsetFileName, O_RDWR , 0); + GSE_FUN(); + if(IS_ERR(fp)){ + GSE_ERR("Sorry,file open ERROR !\n"); + if(l_sensorconfig.op){ //first time + l_sensorconfig.op=0; +#if AUTO_CALIBRATION + /* get acceleration average reading */ + D10_calibrate(client); + update_var(); + D10_write_offset_to_file(client); +#endif +#ifdef DMT_BROADCAST_APK_ENABLE + create_devidfile(); + return; +#endif + } + D10_write_offset_to_file(client); + } + else{ + GSE_LOG("filp_open %s SUCCESS!!.\n",D10_OffsetFileName); + fp->f_op->read(fp,data,18, &fp->f_pos); + GSE_LOG("filp_read result %s\n",data); + sscanf(data,"%d %d %d",&ux,&uy,&uz); + dmt->offset.u.x=ux; + dmt->offset.u.y=uy; + dmt->offset.u.z=uz; + } + set_fs(orgfs); +} +static int create_devidfile(void) +{ + char data[18]; + unsigned int orgfs; + struct file *fp; + + sprintf(data,"%5d %5d %5d",0,0,0); + orgfs = get_fs(); + /* Set segment descriptor associated to kernel space */ + set_fs(KERNEL_DS); + GSE_FUN(); + fp = filp_open(DmtXXFileName, O_RDWR | O_CREAT, 0777); + if(IS_ERR(fp)){ + GSE_ERR("Sorry,file open ERROR !\n"); + return -1; + } + fp->f_op->write(fp,data,18, &fp->f_pos); + set_fs(orgfs); + filp_close(fp,NULL); + return 0; +} +//********************************************************************************************************* +MODULE_AUTHOR("DMT_RD"); +MODULE_DESCRIPTION("DMT Gsensor Driver"); +MODULE_LICENSE("GPL"); + +module_init(device_init); +module_exit(device_exit); diff --git a/ANDROID_3.4.5/drivers/input/sensor/dmard10_gsensor/dmt10.h b/ANDROID_3.4.5/drivers/input/sensor/dmard10_gsensor/dmt10.h new file mode 100755 index 00000000..f77b07e3 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/dmard10_gsensor/dmt10.h @@ -0,0 +1,192 @@ +/* @version 1.03 + * Copyright 2011 Domintech Technology Co., Ltd + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#ifndef DMT10_H +#define DMT10_H +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#define AUTO_CALIBRATION 0 +#define SW_FILTER /* Enable or Disable Software filter */ +#define SENSOR_DATA_AVG 8 /* AVG sensor data */ + +//#define DMT_DEBUG_DATA +#define GSE_TAG "[DMT_Gsensor]" +#ifdef DMT_DEBUG_DATA +#define GSE_ERR(fmt, args...) printk(KERN_ERR GSE_TAG"%s %d : "fmt, __FUNCTION__, __LINE__, ##args) +#define GSE_LOG(fmt, args...) printk(KERN_INFO GSE_TAG fmt, ##args) +#define GSE_FUN(f) printk(KERN_INFO GSE_TAG" %s: %s: %i\n", __FILE__, __func__, __LINE__) +#define DMT_DATA(dev, ...) dev_dbg((dev), ##__VA_ARGS__) +#else +#define GSE_ERR(fmt, args...) +#define GSE_LOG(fmt, args...) +#define GSE_FUN(f) +#define DMT_DATA(dev, format, ...) +#endif + +#define GSENSOR_ID "DMARD10" +#define INPUT_NAME_ACC "g-sensor"//"DMT_accel"//"g-sensor"// /* Input Device Name */ +#define SENSOR_I2C_NAME "dmard10"//"dmt"// /* Device name for DMARD10 misc. device */ +#define SENSOR_I2C_ADDR 0x18 +#define REG_ACTR 0x00 +#define REG_WDAL 0x01 +#define REG_TAPNS 0x0f +#define REG_MISC2 0x1f +#define REG_AFEM 0x0c +#define REG_CKSEL 0x0d +#define REG_INTC 0x0e +#define REG_STADR 0x12 +#define REG_STAINT 0x1C +#define REG_PD 0x21 +#define REG_TCGYZ 0x26 +#define REG_X_OUT 0x41 + +#define MODE_Off 0x00 +#define MODE_ResetAtOff 0x01 +#define MODE_Standby 0x02 +#define MODE_ResetAtStandby 0x03 +#define MODE_Active 0x06 +#define MODE_Trigger 0x0a +#define MODE_ReadOTP 0x12 +#define MODE_WriteOTP 0x22 +#define MODE_WriteOTPBuf 0x42 +#define MODE_ResetDataPath 0x82 + +#define VALUE_STADR 0x55 +#define VALUE_STAINT 0xAA +#define VALUE_AFEM_AFEN_Normal 0x8f// AFEN set 1 , ATM[2:0]=b'000(normal),EN_Z/Y/X/T=1 +#define VALUE_AFEM_Normal 0x0f// AFEN set 0 , ATM[2:0]=b'000(normal),EN_Z/Y/X/T=1 +#define VALUE_INTC 0x00// INTC[6:5]=b'00 +#define VALUE_INTC_Interrupt_En 0x20// INTC[6:5]=b'01 (Data ready interrupt enable, active high at INT0) +#define VALUE_CKSEL_ODR_0_204 0x04// ODR[3:0]=b'0000 (0.78125Hz), CCK[3:0]=b'0100 (204.8kHZ) +#define VALUE_CKSEL_ODR_1_204 0x14// ODR[3:0]=b'0001 (1.5625Hz), CCK[3:0]=b'0100 (204.8kHZ) +#define VALUE_CKSEL_ODR_3_204 0x24// ODR[3:0]=b'0010 (3.125Hz), CCK[3:0]=b'0100 (204.8kHZ) +#define VALUE_CKSEL_ODR_6_204 0x34// ODR[3:0]=b'0011 (6.25Hz), CCK[3:0]=b'0100 (204.8kHZ) +#define VALUE_CKSEL_ODR_12_204 0x44// ODR[3:0]=b'0100 (12.5Hz), CCK[3:0]=b'0100 (204.8kHZ) +#define VALUE_CKSEL_ODR_25_204 0x54// ODR[3:0]=b'0101 (25Hz), CCK[3:0]=b'0100 (204.8kHZ) +#define VALUE_CKSEL_ODR_50_204 0x64// ODR[3:0]=b'0110 (50Hz), CCK[3:0]=b'0100 (204.8kHZ) +#define VALUE_CKSEL_ODR_100_204 0x74// ODR[3:0]=b'0111 (100Hz), CCK[3:0]=b'0100 (204.8kHZ) + +#define VALUE_TAPNS_NoFilter 0x00 // TAP1/TAP2 NO FILTER +#define VALUE_TAPNS_Ave_2 0x11 // TAP1/TAP2 Average 2 +#define VALUE_TAPNS_Ave_4 0x22 // TAP1/TAP2 Average 4 +#define VALUE_TAPNS_Ave_8 0x33 // TAP1/TAP2 Average 8 +#define VALUE_TAPNS_Ave_16 0x44 // TAP1/TAP2 Average 16 +#define VALUE_TAPNS_Ave_32 0x55 // TAP1/TAP2 Average 32 +#define VALUE_MISC2_OSCA_EN 0x08 +#define VALUE_PD_RST 0x52 + +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Z_NEGATIVE 1 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Z_POSITIVE 2 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Y_NEGATIVE 3 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Y_POSITIVE 4 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_X_NEGATIVE 5 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_X_POSITIVE 6 + +#define AVG_NUM 16 +#define SENSOR_DATA_SIZE 3 +#define DEFAULT_SENSITIVITY 1024 + +#define IOCTL_MAGIC 0x09 +#define SENSOR_RESET _IO(IOCTL_MAGIC, 0) +#define SENSOR_CALIBRATION _IOWR(IOCTL_MAGIC, 1, int[SENSOR_DATA_SIZE]) +#define SENSOR_GET_OFFSET _IOR(IOCTL_MAGIC, 2, int[SENSOR_DATA_SIZE]) +#define SENSOR_SET_OFFSET _IOWR(IOCTL_MAGIC, 3, int[SENSOR_DATA_SIZE]) +#define SENSOR_READ_ACCEL_XYZ _IOR(IOCTL_MAGIC, 4, int[SENSOR_DATA_SIZE]) +#define SENSOR_SETYPR _IOW(IOCTL_MAGIC, 5, int[SENSOR_DATA_SIZE]) +#define SENSOR_GET_OPEN_STATUS _IO(IOCTL_MAGIC, 6) +#define SENSOR_GET_CLOSE_STATUS _IO(IOCTL_MAGIC, 7) +#define SENSOR_GET_DELAY _IOR(IOCTL_MAGIC, 8, unsigned int*) +#define SENSOR_MAXNR 8 +/* Default sensorlayout parameters */ +#define D10_DEFAULT_POSITION 6 + +/* Transformation matrix for chip mounting position */ +static const int dmt_position_map[][3][3] = { + { { 1, 0, 0}, { 0,-1, 0}, { 0, 0,-1}, }, /* top/upper-left */ + { { 0, 1, 0}, { 1, 0, 0}, { 0, 0,-1}, }, /* top/lower-left */ + { {-1, 0, 0}, { 0, 1, 0}, { 0, 0,-1}, }, /* top/lower-right */ + { { 0,-1, 0}, {-1, 0, 0}, { 0, 0,-1}, }, /* top/upper-right */ + { {-1, 0, 0}, { 0,-1, 0}, { 0, 0, 1}, }, /* bottom/upper-right*/ + { { 0,-1, 0}, {-1, 0, 0}, { 0, 0, 1}, }, /* bottom/upper-left */ + { { 1, 0, 0}, { 0, 1, 0}, { 0, 0, 1}, }, /* bottom/lower-right*/ + { { 0, 1,0}, { 1, 0, 0}, { 0, 0, 1}, }, /* bottom/lower-left */ +}; + +typedef union { + struct { + int x; + int y; + int z; + } u; + int v[SENSOR_DATA_SIZE]; +} raw_data; + +struct dmt_data { + struct platform_device *pdevice; + struct device *class_dev; + struct class *class; + struct input_dev *input; + struct i2c_client *client; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif + struct delayed_work delaywork; + struct work_struct work; + struct mutex data_mutex; + struct mutex enable_mutex; /* for suspend */ + raw_data last; /* RawData */ + raw_data offset; /* Offset */ +#ifdef SW_FILTER + int sum[SENSOR_DATA_SIZE]; /* SW_FILTER sum */ + int bufferave[3][32]; + s8 aveflag; /* FULL bufferave[][] */ + s8 pointer; /* last update data */ +#endif + wait_queue_head_t open_wq; + atomic_t active; + atomic_t delay; + atomic_t enable; + int filter; + int position; /* must int type ,for Kconfig setup */ + atomic_t addr; +#ifdef DMT_DEBUG_DATA + struct mutex suspend_mutex; + int suspend; +#endif +}; + +#define ACC_DATA_FLAG 0 +#define MAG_DATA_FLAG 1 +#define ORI_DATA_FLAG 2 +#define DMT_NUM_SENSORS 3 + +/* ABS axes parameter range [um/s^2] (for input event) */ +#define GRAVITY_EARTH 9806550 +#define ABSMAX (GRAVITY_EARTH * 2) +#define ABSMIN (-GRAVITY_EARTH * 2) + +#endif diff --git a/ANDROID_3.4.5/drivers/input/sensor/isl29023_lsensor/Makefile b/ANDROID_3.4.5/drivers/input/sensor/isl29023_lsensor/Makefile new file mode 100755 index 00000000..ac959091 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/isl29023_lsensor/Makefile @@ -0,0 +1,34 @@ +KERNELDIR=../../../../ +#KERNELDIR=/home/hangyan/android8850/kernel/ANDROID_3.0.8 +CROSS = arm_1103_le- +CC= $(CROSS)gcc +LD= $(CROSS)ld +STRIP = $(CROSS)strip + +DEBUG = n + +# Add your debugging flag (or not) to EXTRA_CFLAGS +ifeq ($(DEBUG),y) +# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines +DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines + +else + DEBFLAGS = -O2 -Wall +endif + +EXTRA_CFLAGS += $(DEBFLAGS) + + +MY_MODULE_NAME=s_wmt_lsensor_isl29023 + +obj-m := $(MY_MODULE_NAME).o +$(MY_MODULE_NAME)-objs := isl29023.o + +default: + $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules + $(STRIP) --strip-debug $(MY_MODULE_NAME).ko + rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions + +clean: + rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers + diff --git a/ANDROID_3.4.5/drivers/input/sensor/isl29023_lsensor/isl29023.c b/ANDROID_3.4.5/drivers/input/sensor/isl29023_lsensor/isl29023.c new file mode 100755 index 00000000..3366e92a --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/isl29023_lsensor/isl29023.c @@ -0,0 +1,1164 @@ +/* + * isl29023.c - Intersil ISL29023 ALS & Proximity Driver + * + * By Intersil Corp + * Michael DiGioia + * + * Based on isl29011.c + * by Mike DiGioia + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include "../sensor.h" + +/* Insmod parameters */ +//I2C_CLIENT_INSMOD_1(isl29023); + +#define MODULE_NAME "isl29023" + +#define SENSOR_I2C_NAME "isl29023" +#define SENSOR_I2C_ADDR 0x44 + +#undef dbg +#define dbg(fmt, args...) + +#undef errlog +#undef klog +#define errlog(fmt, args...) printk(KERN_ERR "[%s]: " fmt, __FUNCTION__, ## args) +#define klog(fmt, args...) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__, ## args) + +/* ICS932S401 registers */ +#define ISL29023_REG_VENDOR_REV 0x06 +#define ISL29023_VENDOR 1 +#define ISL29023_VENDOR_MASK 0x0F +#define ISL29023_REV 4 +#define ISL29023_REV_SHIFT 4 +#define ISL29023_REG_DEVICE 0x44 +#define ISL29023_DEVICE 44 + + +#define REG_CMD_1 0x00 +#define REG_CMD_2 0x01 +#define REG_DATA_LSB 0x02 +#define REG_DATA_MSB 0x03 +#define ISL_MOD_MASK 0xE0 +#define ISL_MOD_POWERDOWN 0 +#define ISL_MOD_ALS_ONCE 1 +#define ISL_MOD_IR_ONCE 2 +#define ISL_MOD_RESERVED 4 +#define ISL_MOD_ALS_CONT 5 +#define ISL_MOD_IR_CONT 6 +#define IR_CURRENT_MASK 0xC0 +#define IR_FREQ_MASK 0x30 +#define SENSOR_RANGE_MASK 0x03 +#define ISL_RES_MASK 0x0C + +static int last_mod; + +static struct i2c_client *this_client = NULL; +struct isl_device { + struct input_polled_dev* input_poll_dev; + struct i2c_client* client; + int resolution; + int range; + int isdbg; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend earlysuspend; +#endif + +}; + +static struct isl_device* l_sensorconfig = NULL; +static struct kobject *android_lsensor_kobj = NULL; +static int l_enable = 1; // 0:don't report data + +static DEFINE_MUTEX(mutex); + +static int isl_set_range(struct i2c_client *client, int range) +{ + int ret_val; + + ret_val = i2c_smbus_read_byte_data(client, REG_CMD_2); + if (ret_val < 0) + return -EINVAL; + ret_val &= ~SENSOR_RANGE_MASK; /*reset the bit */ + ret_val |= range; + ret_val = i2c_smbus_write_byte_data(client, REG_CMD_2, ret_val); + + printk(KERN_INFO MODULE_NAME ": %s isl29023 set_range call, \n", __func__); + if (ret_val < 0) + return ret_val; + return range; +} + +static int isl_set_mod(struct i2c_client *client, int mod) +{ + int ret, val, freq; + + switch (mod) { + case ISL_MOD_POWERDOWN: + case ISL_MOD_RESERVED: + goto setmod; + case ISL_MOD_ALS_ONCE: + case ISL_MOD_ALS_CONT: + freq = 0; + break; + case ISL_MOD_IR_ONCE: + case ISL_MOD_IR_CONT: + freq = 1; + break; + default: + return -EINVAL; + } + /* set IR frequency */ + val = i2c_smbus_read_byte_data(client, REG_CMD_2); + if (val < 0) + return -EINVAL; + val &= ~IR_FREQ_MASK; + if (freq) + val |= IR_FREQ_MASK; + ret = i2c_smbus_write_byte_data(client, REG_CMD_2, val); + if (ret < 0) + return -EINVAL; + +setmod: + /* set operation mod */ + val = i2c_smbus_read_byte_data(client, REG_CMD_1); + if (val < 0) + return -EINVAL; + val &= ~ISL_MOD_MASK; + val |= (mod << 5); + ret = i2c_smbus_write_byte_data(client, REG_CMD_1, val); + if (ret < 0) + return -EINVAL; + + if (mod != ISL_MOD_POWERDOWN) + last_mod = mod; + + return mod; +} + +static int isl_get_res(struct i2c_client *client) +{ + int val; + + printk(KERN_INFO MODULE_NAME ": %s isl29023 get_res call, \n", __func__); + val = i2c_smbus_read_word_data(client, 0)>>8 & 0xff; + + if (val < 0) + return -EINVAL; + + val &= ISL_RES_MASK; + val >>= 2; + + switch (val) { + case 0: + return 65536; + case 1: + return 4096; + case 2: + return 256; + case 3: + return 16; + default: + return -EINVAL; + } +} + +static int isl_get_mod(struct i2c_client *client) +{ + int val; + + val = i2c_smbus_read_byte_data(client, REG_CMD_1); + if (val < 0) + return -EINVAL; + return val >> 5; +} + +static int isl_get_range(struct i2c_client* client) +{ + switch (i2c_smbus_read_word_data(client, 0)>>8 & 0xff & 0x3) { + case 0: return 1000; + case 1: return 4000; + case 2: return 16000; + case 3: return 64000; + default: return -EINVAL; + } +} + +static ssize_t +isl_sensing_range_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + int val; + + mutex_lock(&mutex); + pm_runtime_get_sync(dev); + val = i2c_smbus_read_byte_data(client, REG_CMD_2); + pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + + dev_dbg(dev, "%s: range: 0x%.2x\n", __func__, val); + + if (val < 0) + return val; + return sprintf(buf, "%d000\n", 1 << (2 * (val & 3))); +} + +static ssize_t +ir_current_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + int val; + + mutex_lock(&mutex); + pm_runtime_get_sync(dev); + val = i2c_smbus_read_byte_data(client, REG_CMD_2); + pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + + dev_dbg(dev, "%s: IR current: 0x%.2x\n", __func__, val); + + if (val < 0) + return -EINVAL; + val >>= 6; + + switch (val) { + case 0: + val = 100; + break; + case 1: + val = 50; + break; + case 2: + val = 25; + break; + case 3: + val = 0; + break; + default: + return -EINVAL; + } + + if (val) + val = sprintf(buf, "%d\n", val); + else + val = sprintf(buf, "%s\n", "12.5"); + return val; +} + +static ssize_t +isl_sensing_mod_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +// struct i2c_client *client = to_i2c_client(dev); + + dev_dbg(dev, "%s: mod: 0x%.2x\n", __func__, last_mod); + + switch (last_mod) { + case ISL_MOD_POWERDOWN: + return sprintf(buf, "%s\n", "0-Power-down"); + case ISL_MOD_ALS_ONCE: + return sprintf(buf, "%s\n", "1-ALS once"); + case ISL_MOD_IR_ONCE: + return sprintf(buf, "%s\n", "2-IR once"); + case ISL_MOD_RESERVED: + return sprintf(buf, "%s\n", "4-Reserved"); + case ISL_MOD_ALS_CONT: + return sprintf(buf, "%s\n", "5-ALS continuous"); + case ISL_MOD_IR_CONT: + return sprintf(buf, "%s\n", "6-IR continuous"); + default: + return -EINVAL; + } +} + +static ssize_t +isl_output_data_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + int ret_val, mod; + unsigned long int output = 0; + int temp; + + mutex_lock(&mutex); + pm_runtime_get_sync(dev); + + temp = i2c_smbus_read_byte_data(client, REG_DATA_MSB); + if (temp < 0) + goto err_exit; + ret_val = i2c_smbus_read_byte_data(client, REG_DATA_LSB); + if (ret_val < 0) + goto err_exit; + ret_val |= temp << 8; + + dev_dbg(dev, "%s: Data: %04x\n", __func__, ret_val); + + mod = isl_get_mod(client); + switch (last_mod) { + case ISL_MOD_ALS_CONT: + case ISL_MOD_ALS_ONCE: + case ISL_MOD_IR_ONCE: + case ISL_MOD_IR_CONT: + output = ret_val; + break; + default: + goto err_exit; + } + pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + return sprintf(buf, "%ld\n", output); + +err_exit: + pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + return -EINVAL; +} + +static int isl_get_lux_data(struct i2c_client* client) +{ + struct isl_device* idev = i2c_get_clientdata(client); + + __u16 resH, resL; + //int range; + resL = i2c_smbus_read_word_data(client, 1)>>8; + resH = i2c_smbus_read_word_data(client, 2)&0xff00; + if ((resL < 0) || (resH < 0)) + { + errlog("Error to read lux_data!\n"); + return -1; + } + return (resH | resL) * idev->range / idev->resolution; +} +static ssize_t +isl_lux_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + __u16 resH, resL;// L1, L2, H1, H2, thresL, thresH; + char cmd2; + int res, data, tmp, range, resolution; + + mutex_lock(&mutex); + pm_runtime_get_sync(dev); + +// cmd2 = i2c_smbus_read_word_data(client, 0)>>8 & 0xff; // 01h + resL = i2c_smbus_read_word_data(client, 1)>>8; // 02h + resH = i2c_smbus_read_word_data(client, 2)&0xff00; // 03h +// L1 = i2c_smbus_read_word_data(client, 3)>>8; // 04h +// L2 = i2c_smbus_read_word_data(client, 4)&0xff00; // 05h +// H1 = i2c_smbus_read_word_data(client, 5)>>8; // 06h +// H2 = i2c_smbus_read_word_data(client, 6)&0xff00; // 07h + + res = resH | resL; +// thresL = L2 | L1; +// thresH = H2 | H1; + + cmd2 = i2c_smbus_read_word_data(client, 0)>>8 & 0xff; + resolution = isl_get_res(client); //resolution + pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + tmp = cmd2 & 0x3; //range + switch (tmp) { + case 0: + range = 1000; + break; + case 1: + range = 4000; + break; + case 2: + range = 16000; + break; + case 3: + range = 64000; + break; + default: + return -EINVAL; + } + data = res * range / resolution; + +// printk("Data = 0x%04x [%d]\n", data, data); +// printk("CMD2 = 0x%x\n", cmd2); +// printk("Threshold Low = 0x%04x\n", thresL); +// printk("Threshold High = 0x%04x\n", thresH); + + return sprintf(buf, "%u\n", data); +} + +static ssize_t +isl_cmd2_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + unsigned long cmd2; + mutex_lock(&mutex); + pm_runtime_get_sync(dev); + cmd2 = i2c_smbus_read_word_data(client, 0)>>8 & 0xff; + pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + dbg(" cmd2: 0x%02x\n", cmd2); + switch (cmd2) { + case 0: + return sprintf(buf, "%s\n", "[cmd2 = 0] n = 16, range = 1000"); + case 1: + return sprintf(buf, "%s\n", "[cmd2 = 1] n = 16, range = 4000"); + case 2: + return sprintf(buf, "%s\n", "[cmd2 = 2] n = 16, range = 16000"); + case 3: + return sprintf(buf, "%s\n", "[cmd2 = 3] n = 16, range = 64000"); + + case 4: + return sprintf(buf, "%s\n", "[cmd2 = 4] n = 12, range = 1000"); + case 5: + return sprintf(buf, "%s\n", "[cmd2 = 5] n = 12, range = 4000"); + case 6: + return sprintf(buf, "%s\n", "[cmd2 = 6] n = 12, range = 16000"); + case 7: + return sprintf(buf, "%s\n", "[cmd2 = 7] n = 12, range = 64000"); + + case 8: + return sprintf(buf, "%s\n", "[cmd2 = 8] n = 8, range = 1000"); + case 9: + return sprintf(buf, "%s\n", "[cmd2 = 9] n = 8, range = 4000"); + case 10: + return sprintf(buf, "%s\n", "[cmd2 = 10] n = 8, range = 16000"); + case 11: + return sprintf(buf, "%s\n", "[cmd2 = 11] n = 8, range = 64000"); + + case 12: + return sprintf(buf, "%s\n", "[cmd2 = 12] n = 4, range = 1000"); + case 13: + return sprintf(buf, "%s\n", "[cmd2 = 13] n = 4, range = 4000"); + case 14: + return sprintf(buf, "%s\n", "[cmd2 = 14] n = 4, range = 16000"); + case 15: + return sprintf(buf, "%s\n", "[cmd2 = 15] n = 4, range = 64000"); + + default: + return -EINVAL; + } +} + + +static ssize_t +isl_sensing_range_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + unsigned int ret_val; + unsigned long val; + + if (strict_strtoul(buf, 10, &val)) + return -EINVAL; + + switch (val) { + case 1000: + val = 0; + break; + case 4000: + val = 1; + break; + case 16000: + val = 2; + break; + case 64000: + val = 3; + break; + default: + return -EINVAL; + } + + mutex_lock(&mutex); + pm_runtime_get_sync(dev); + ret_val = isl_set_range(client, val); + pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + + if (ret_val < 0) + return ret_val; + return count; +} + +static ssize_t +ir_current_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + unsigned int ret_val; + unsigned long val; + + if (!strncmp(buf, "12.5", 4)) + val = 3; + else { + if (strict_strtoul(buf, 10, &val)) + return -EINVAL; + switch (val) { + case 100: + val = 0; + break; + case 50: + val = 1; + break; + case 25: + val = 2; + break; + default: + return -EINVAL; + } + } + + mutex_lock(&mutex); + pm_runtime_get_sync(dev); + + ret_val = i2c_smbus_read_byte_data(client, REG_CMD_2); + if (ret_val < 0) + goto err_exit; + + ret_val &= ~IR_CURRENT_MASK; /*reset the bit before setting them */ + ret_val |= (val << 6); + + ret_val = i2c_smbus_write_byte_data(client, REG_CMD_2, ret_val); + if (ret_val < 0) + goto err_exit; + + pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + + return count; + +err_exit: + pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + return -EINVAL; +} + +static ssize_t +isl_sensing_mod_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + int ret_val; + unsigned long val; + + if (strict_strtoul(buf, 10, &val)) + return -EINVAL; + if (val > 7) + return -EINVAL; + + mutex_lock(&mutex); + pm_runtime_get_sync(dev); + ret_val = isl_set_mod(client, val); + pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + + if (ret_val < 0) + return ret_val; + return count; +} + +static ssize_t +isl_cmd2_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct isl_device* idev = i2c_get_clientdata(client); + int res; + unsigned long val; + if (strict_strtoul(buf, 10, &val)) + return -EINVAL; + if (val > 15 || val < 0) + return -EINVAL; + + mutex_lock(&mutex); + pm_runtime_get_sync(dev); + res = i2c_smbus_write_byte_data(client, REG_CMD_2, val); + if (res < 0) + printk("Warning - write failed\n"); + + idev->resolution = isl_get_res(client); + idev->range = isl_get_range(client); + pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + + return count; +} + +static DEVICE_ATTR(range, S_IRUGO | S_IWUSR, + isl_sensing_range_show, isl_sensing_range_store); +static DEVICE_ATTR(mod, S_IRUGO | S_IWUSR, + isl_sensing_mod_show, isl_sensing_mod_store); +static DEVICE_ATTR(ir_current, S_IRUGO | S_IWUSR, + ir_current_show, ir_current_store); +static DEVICE_ATTR(output, S_IRUGO, isl_output_data_show, NULL); +static DEVICE_ATTR(cmd2, S_IRUGO | S_IWUSR, + isl_cmd2_show, isl_cmd2_store); +static DEVICE_ATTR(lux, S_IRUGO, + isl_lux_show, NULL); + +static struct attribute *mid_att_isl[] = { + &dev_attr_range.attr, + &dev_attr_mod.attr, + &dev_attr_ir_current.attr, + &dev_attr_output.attr, + &dev_attr_lux.attr, + &dev_attr_cmd2.attr, + NULL +}; + +static struct attribute_group m_isl_gr = { + .name = "isl29023", + .attrs = mid_att_isl +}; + +static int isl_set_default_config(struct i2c_client *client) +{ + struct isl_device* idev = i2c_get_clientdata(client); + + int ret=0; +/* We don't know what it does ... */ +// ret = i2c_smbus_write_byte_data(client, REG_CMD_1, 0xE0); +// ret = i2c_smbus_write_byte_data(client, REG_CMD_2, 0xC3); +/* Set default to ALS continuous */ + ret = i2c_smbus_write_byte_data(client, REG_CMD_1, 0xA0); + if (ret < 0) + return -EINVAL; +/* Range: 0~16000, number of clock cycles: 65536 */ + ret = i2c_smbus_write_byte_data(client, REG_CMD_2, 0x02); // vivienne + if (ret < 0) + return -EINVAL; + idev->resolution = isl_get_res(client); + idev->range = isl_get_range(client);; + dbg("isl29023 set_default_config call, \n"); + + return 0; +} + +/* Return 0 if detection is successful, -ENODEV otherwise */ +static int isl29023_detect(struct i2c_client *client/*, int kind, + struct i2c_board_info *info*/) +{ + struct i2c_adapter *adapter = client->adapter; + int vendor, device, revision; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -ENODEV; + //printk(KERN_INFO MODULE_NAME ": %s isl29023 detact call, kind:%d type:%s addr:%x \n", __func__, kind, info->type, info->addr); + + /* if (kind <= 0)*/ { + + + vendor = i2c_smbus_read_word_data(client, + ISL29023_REG_VENDOR_REV); + dbg("read vendor=%d(0x%x)\n", vendor,vendor); + if (0x0FFFF == vendor) + { + dbg("find isl29023!\n"); + return 0; + } else { + return -ENODEV; + } + vendor >>= 8; + revision = vendor >> ISL29023_REV_SHIFT; + vendor &= ISL29023_VENDOR_MASK; + if (vendor != ISL29023_VENDOR) + { + dbg("real_vendor=0x%x,tvendor=0x%x\n",vendor,ISL29023_VENDOR); + return -ENODEV; + } + + device = i2c_smbus_read_word_data(client, + ISL29023_REG_DEVICE); + dbg("device=%x\n", device); + device >>= 8; + if (device != ISL29023_DEVICE) + { + dbg("real_device=0x%x, tdevice=0x%x\n", device, ISL29023_DEVICE); + return -ENODEV; + } + + if (revision != ISL29023_REV) + { + dbg("Unknown revision %d\n", + revision); + } + } /*else + dev_dbg(&adapter->dev, "detection forced\n");*/ + + // strlcpy(info->type, "isl29023", I2C_NAME_SIZE); + + return 0; +} + +int isl_input_open(struct input_dev* input) +{ + return 0; +} + +void isl_input_close(struct input_dev* input) +{ +} + +static void isl_input_lux_poll(struct input_polled_dev *dev) +{ + struct isl_device* idev = dev->private; + struct input_dev* input = idev->input_poll_dev->input; + struct i2c_client* client = idev->client; + + if (l_enable != 0) + { + mutex_lock(&mutex); + //pm_runtime_get_sync(dev); + input_report_abs(input, ABS_MISC, isl_get_lux_data(client)); + input_sync(input); + //pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + } +} + +static struct i2c_device_id isl29023_id[] = { + {"isl29023", 0}, + {} +}; + +static int isl29023_runtime_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + dev_dbg(dev, "suspend\n"); + + mutex_lock(&mutex); + pm_runtime_get_sync(dev); + isl_set_mod(client, ISL_MOD_POWERDOWN); + pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + + printk(KERN_INFO MODULE_NAME ": %s isl29023 suspend call, \n", __func__); + return 0; +} + +static int isl29023_runtime_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + dev_dbg(dev, "resume\n"); + + mutex_lock(&mutex); + pm_runtime_get_sync(dev); + isl_set_mod(client, last_mod); + pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + + printk(KERN_INFO MODULE_NAME ": %s isl29023 resume call, \n", __func__); + return 0; +} + +MODULE_DEVICE_TABLE(i2c, isl29023_id); + +/*static const struct dev_pm_ops isl29023_pm_ops = { + .runtime_suspend = isl29023_runtime_suspend, + .runtime_resume = isl29023_runtime_resume, +}; + +static struct i2c_board_info isl_info = { + I2C_BOARD_INFO("isl29023", 0x44), +}; + +static struct i2c_driver isl29023_driver = { + .driver = { + .name = "isl29023", + .pm = &isl29023_pm_ops, + }, + .probe = isl29023_probe, + .remove = isl29023_remove, + .id_table = isl29023_id, + .detect = isl29023_detect, + //.address_data = &addr_data, +};*/ + +static int mmad_open(struct inode *inode, struct file *file) +{ + dbg("Open the l-sensor node...\n"); + return 0; +} + +static int mmad_release(struct inode *inode, struct file *file) +{ + dbg("Close the l-sensor node...\n"); + return 0; +} + +static ssize_t mmad_read(struct file *fl, char __user *buf, size_t cnt, loff_t *lf) +{ + int lux_data = 0; + + mutex_lock(&mutex); + lux_data = isl_get_lux_data(l_sensorconfig->client); + mutex_unlock(&mutex); + if (lux_data < 0) + { + errlog("Failed to read lux data!\n"); + return -1; + } + copy_to_user(buf, &lux_data, sizeof(lux_data)); + return sizeof(lux_data); +} + +static long +mmad_ioctl(/*struct inode *inode,*/ struct file *file, unsigned int cmd, + unsigned long arg) +{ + void __user *argp = (void __user *)arg; + //char rwbuf[5]; + short enable; //amsr = -1; + unsigned int uval; + + dbg("l-sensor ioctr...\n"); + //memset(rwbuf, 0, sizeof(rwbuf)); + switch (cmd) { + case LIGHT_IOCTL_SET_ENABLE: + // enable/disable sensor + if (copy_from_user(&enable, argp, sizeof(short))) + { + printk(KERN_ERR "Can't get enable flag!!!\n"); + return -EFAULT; + } + dbg("enable=%d\n",enable); + if ((enable >=0) && (enable <=1)) + { + dbg("driver: disable/enable(%d) gsensor.\n", enable); + + //l_sensorconfig.sensor_enable = enable; + dbg("Should to implement d/e the light sensor!\n"); + l_enable = enable; + + } else { + printk(KERN_ERR "Wrong enable argument in %s !!!\n", __FUNCTION__); + return -EINVAL; + } + break; + case WMT_IOCTL_SENSOR_GET_DRVID: + uval = ISL29023_DRVID; + if (copy_to_user((unsigned int*)arg, &uval, sizeof(unsigned int))) + { + return -EFAULT; + } + dbg("Isl29023_driver_id:%d\n",uval); + default: + break; + } + + return 0; +} + + +static struct file_operations mmad_fops = { + .owner = THIS_MODULE, + .open = mmad_open, + .release = mmad_release, + .read = mmad_read, + .unlocked_ioctl = mmad_ioctl, +}; + + +static struct miscdevice mmad_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "lsensor_ctrl", + .fops = &mmad_fops, +}; + +static void isl29023_early_suspend(struct early_suspend *h) +{ + struct i2c_client *client = l_sensorconfig->client; + + dbg("start\n"); + mutex_lock(&mutex); + //pm_runtime_get_sync(dev); + isl_set_mod(client, ISL_MOD_POWERDOWN); + //pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + dbg("exit\n"); +} + +static void isl29023_late_resume(struct early_suspend *h) +{ + struct i2c_client *client = l_sensorconfig->client; + + dbg("start\n"); + mutex_lock(&mutex); + //pm_runtime_get_sync(dev); + isl_set_mod(client, last_mod); + isl_set_default_config(client); + //pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + dbg("exit\n"); +} + + +static int +isl29023_probe(struct i2c_client *client/*, const struct i2c_device_id *id*/) +{ + int res=0; + + struct isl_device* idev = kzalloc(sizeof(struct isl_device), GFP_KERNEL); + if(!idev) + return -ENOMEM; + + l_sensorconfig = idev; + android_lsensor_kobj = kobject_create_and_add("android_lsensor", NULL); + if (android_lsensor_kobj == NULL) { + errlog( + "lsensor_sysfs_init:"\ + "subsystem_register failed\n"); + res = -ENOMEM; + goto err_kobjetc_create; + } + res = sysfs_create_group(android_lsensor_kobj, &m_isl_gr); + if (res) { + //pr_warn("isl29023: device create file failed!!\n"); + printk(KERN_INFO MODULE_NAME ": %s isl29023 device create file failed\n", __func__); + res = -EINVAL; + goto err_sysfs_create; + } + +/* last mod is ALS continuous */ + last_mod = 5; + //pm_runtime_enable(&client->dev); + idev->input_poll_dev = input_allocate_polled_device(); + if(!idev->input_poll_dev) + { + res = -ENOMEM; + goto err_input_allocate_device; + } + idev->client = client; + idev->input_poll_dev->private = idev; + idev->input_poll_dev->poll = isl_input_lux_poll; + idev->input_poll_dev->poll_interval = 100;//50; + idev->input_poll_dev->input->open = isl_input_open; + idev->input_poll_dev->input->close = isl_input_close; + idev->input_poll_dev->input->name = "lsensor_lux"; + idev->input_poll_dev->input->id.bustype = BUS_I2C; + idev->input_poll_dev->input->dev.parent = &client->dev; + input_set_drvdata(idev->input_poll_dev->input, idev); + input_set_capability(idev->input_poll_dev->input, EV_ABS, ABS_MISC); + input_set_abs_params(idev->input_poll_dev->input, ABS_MISC, 0, 16000, 0, 0); + i2c_set_clientdata(client, idev); + /* set default config after set_clientdata */ + res = isl_set_default_config(client); + res = misc_register(&mmad_device); + if (res) { + errlog("mmad_device register failed\n"); + goto err_misc_register; + } + res = input_register_polled_device(idev->input_poll_dev); + if(res < 0) + goto err_input_register_device; + // suspend/resume register +#ifdef CONFIG_HAS_EARLYSUSPEND + idev->earlysuspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + idev->earlysuspend.suspend = isl29023_early_suspend; + idev->earlysuspend.resume = isl29023_late_resume; + register_early_suspend(&(idev->earlysuspend)); +#endif + + dbg("isl29023 probe succeed!\n"); + return 0; +err_input_register_device: + misc_deregister(&mmad_device); + input_free_polled_device(idev->input_poll_dev); +err_misc_register: +err_input_allocate_device: + //__pm_runtime_disable(&client->dev, false); +err_sysfs_create: + kobject_del(android_lsensor_kobj); +err_kobjetc_create: + kfree(idev); + return res; +} + +static int isl29023_remove(struct i2c_client *client) +{ + struct isl_device* idev = i2c_get_clientdata(client); + + //unregister_early_suspend(&(idev->earlysuspend)); + misc_deregister(&mmad_device); + input_unregister_polled_device(idev->input_poll_dev); + input_free_polled_device(idev->input_poll_dev); + sysfs_remove_group(android_lsensor_kobj, &m_isl_gr); + kobject_del(android_lsensor_kobj); + //__pm_runtime_disable(&client->dev, false); + kfree(idev); + printk(KERN_INFO MODULE_NAME ": %s isl29023 remove call, \n", __func__); + return 0; +} + +//****************add platform_device & platform_driver for suspend &resume 2013-7-2 +static int ls_probe(struct platform_device *pdev){ + //printk("<<<%s\n", __FUNCTION__); + return 0; +} +static int ls_remove(struct platform_device *pdev){ + //printk("<<<%s\n", __FUNCTION__); + return 0; +} +static int ls_suspend(struct platform_device *pdev, pm_message_t state){ + printk("<<<%s\n", __FUNCTION__); + struct i2c_client *client = l_sensorconfig->client; + + mutex_lock(&mutex); + + isl_set_mod(client, ISL_MOD_POWERDOWN); + + mutex_unlock(&mutex); + + + return 0; +} + +static int ls_resume(struct platform_device *pdev){ + //return 0; + int ret = 0; + int count = 0; + printk("<<<%s\n", __FUNCTION__); + struct i2c_client *client = l_sensorconfig->client; + + + + +RETRY: + mutex_lock(&mutex); + //pm_runtime_get_sync(dev); + isl_set_mod(client, last_mod); + ret = isl_set_default_config(client); + //pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + if (ret < 0){ + printk("%s isl_set_default_config fail!\n", __FUNCTION__); + count++; + if (count < 5){ + mdelay(2); + goto RETRY; + } + else + return ret; + } + return 0; + +} +static void lsdev_release(struct device *dev) +{ + return; +} +static struct platform_device lsdev = { + .name = "lsdevice", + .id = -1, + .dev = { + .release = lsdev_release, + }, +}; +static struct platform_driver lsdrv = { + .probe = ls_probe, + .remove = ls_remove, + .suspend = ls_suspend, + .resume = ls_resume, + .driver = { + .name = "lsdevice", + }, +}; +//******************************************************************** + +static int __init sensor_isl29023_init(void) +{ + printk(KERN_INFO MODULE_NAME ": %s isl29023 init call, \n", __func__); + /* + * Force device to initialize: i2c-15 0x44 + * If i2c_new_device is not called, even isl29023_detect will not run + * TODO: rework to automatically initialize the device + */ + //i2c_new_device(i2c_get_adapter(15), &isl_info); + //return i2c_add_driver(&isl29023_driver); + if (!(this_client = sensor_i2c_register_device(2, SENSOR_I2C_ADDR, SENSOR_I2C_NAME))) + { + printk(KERN_EMERG"Can't register gsensor i2c device!\n"); + return -1; + } + if (isl29023_detect(this_client)) + { + errlog("Can't find light sensor isl29023!\n"); + goto detect_fail; + } + if(isl29023_probe(this_client)) + { + errlog("Erro for probe!\n"); + goto detect_fail; + } + int ret = 0; + ret = platform_device_register(&lsdev); + if (ret){ + printk("<< + * + * 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 . + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif /* CONFIG_HAS_EARLYSUSPEND */ +#include +#include +#include +#include "kionix_accel.h" +#include "../sensor.h" + + + +/* Debug Message Flags */ +#define KIONIX_KMSG_ERR 1 /* Print kernel debug message for error */ +#define KIONIX_KMSG_INF 1 /* Print kernel debug message for info */ + +#if KIONIX_KMSG_ERR +#define KMSGERR(format, ...) \ + dev_err(format, ## __VA_ARGS__) + //printk(format, ## __VA_ARGS__) +#else +#define KMSGERR(format, ...) +#endif + +#if KIONIX_KMSG_INF +#define KMSGINF(format, ...) \ + dev_info(format, ## __VA_ARGS__) + //printk(format, ## __VA_ARGS__) +#else +#define KMSGINF(format, ...) +#endif + + +/****************************************************************************** + * Accelerometer WHO_AM_I return value + *****************************************************************************/ +#define KIONIX_ACCEL_WHO_AM_I_KXTE9 0x00 +#define KIONIX_ACCEL_WHO_AM_I_KXTF9 0x01 +#define KIONIX_ACCEL_WHO_AM_I_KXTI9_1001 0x04 +#define KIONIX_ACCEL_WHO_AM_I_KXTIK_1004 0x05 +#define KIONIX_ACCEL_WHO_AM_I_KXTJ9_1005 0x07 +#define KIONIX_ACCEL_WHO_AM_I_KXTJ9_1007 0x08 +#define KIONIX_ACCEL_WHO_AM_I_KXCJ9_1008 0x0A +#define KIONIX_ACCEL_WHO_AM_I_KXTJ2_1009 0x09 +#define KIONIX_ACCEL_WHO_AM_I_KXCJK_1013 0x11 + +/****************************************************************************** + * Accelerometer Grouping + *****************************************************************************/ +#define KIONIX_ACCEL_GRP1 1 /* KXTE9 */ +#define KIONIX_ACCEL_GRP2 2 /* KXTF9/I9-1001/J9-1005 */ +#define KIONIX_ACCEL_GRP3 3 /* KXTIK-1004 */ +#define KIONIX_ACCEL_GRP4 4 /* KXTJ9-1007/KXCJ9-1008 */ +#define KIONIX_ACCEL_GRP5 5 /* KXTJ2-1009 */ +#define KIONIX_ACCEL_GRP6 6 /* KXCJK-1013 */ + +/****************************************************************************** + * Registers for Accelerometer Group 1 & 2 & 3 + *****************************************************************************/ +#define ACCEL_WHO_AM_I 0x0F + +/*****************************************************************************/ +/* Registers for Accelerometer Group 1 */ +/*****************************************************************************/ +/* Output Registers */ +#define ACCEL_GRP1_XOUT 0x12 +/* Control Registers */ +#define ACCEL_GRP1_CTRL_REG1 0x1B +/* CTRL_REG1 */ +#define ACCEL_GRP1_PC1_OFF 0x7F +#define ACCEL_GRP1_PC1_ON (1 << 7) +#define ACCEL_GRP1_ODR40 (3 << 3) +#define ACCEL_GRP1_ODR10 (2 << 3) +#define ACCEL_GRP1_ODR3 (1 << 3) +#define ACCEL_GRP1_ODR1 (0 << 3) +#define ACCEL_GRP1_ODR_MASK (3 << 3) + +/*****************************************************************************/ +/* Registers for Accelerometer Group 2 & 3 */ +/*****************************************************************************/ +/* Output Registers */ +#define ACCEL_GRP2_XOUT_L 0x06 +/* Control Registers */ +#define ACCEL_GRP2_INT_REL 0x1A +#define ACCEL_GRP2_CTRL_REG1 0x1B +#define ACCEL_GRP2_INT_CTRL1 0x1E +#define ACCEL_GRP2_DATA_CTRL 0x21 +/* CTRL_REG1 */ +#define ACCEL_GRP2_PC1_OFF 0x7F +#define ACCEL_GRP2_PC1_ON (1 << 7) +#define ACCEL_GRP2_DRDYE (1 << 5) +#define ACCEL_GRP2_G_8G (2 << 3) +#define ACCEL_GRP2_G_4G (1 << 3) +#define ACCEL_GRP2_G_2G (0 << 3) +#define ACCEL_GRP2_G_MASK (3 << 3) +#define ACCEL_GRP2_RES_8BIT (0 << 6) +#define ACCEL_GRP2_RES_12BIT (1 << 6) +#define ACCEL_GRP2_RES_MASK (1 << 6) +/* INT_CTRL1 */ +#define ACCEL_GRP2_IEA (1 << 4) +#define ACCEL_GRP2_IEN (1 << 5) +/* DATA_CTRL_REG */ +#define ACCEL_GRP2_ODR12_5 0x00 +#define ACCEL_GRP2_ODR25 0x01 +#define ACCEL_GRP2_ODR50 0x02 +#define ACCEL_GRP2_ODR100 0x03 +#define ACCEL_GRP2_ODR200 0x04 +#define ACCEL_GRP2_ODR400 0x05 +#define ACCEL_GRP2_ODR800 0x06 +/*****************************************************************************/ + + +/*****************************************************************************/ +/* Registers for Accelerometer Group 4 & 5 & 6 */ +/*****************************************************************************/ +/* Output Registers */ +#define ACCEL_GRP4_XOUT_L 0x06 +/* Control Registers */ +#define ACCEL_GRP4_INT_REL 0x1A +#define ACCEL_GRP4_CTRL_REG1 0x1B +#define ACCEL_GRP4_INT_CTRL1 0x1E +#define ACCEL_GRP4_DATA_CTRL 0x21 +/* CTRL_REG1 */ +#define ACCEL_GRP4_PC1_OFF 0x7F +#define ACCEL_GRP4_PC1_ON (1 << 7) +#define ACCEL_GRP4_DRDYE (1 << 5) +#define ACCEL_GRP4_G_8G (2 << 3) +#define ACCEL_GRP4_G_4G (1 << 3) +#define ACCEL_GRP4_G_2G (0 << 3) +#define ACCEL_GRP4_G_MASK (3 << 3) +#define ACCEL_GRP4_RES_8BIT (0 << 6) +#define ACCEL_GRP4_RES_12BIT (1 << 6) +#define ACCEL_GRP4_RES_MASK (1 << 6) +/* INT_CTRL1 */ +#define ACCEL_GRP4_IEA (1 << 4) +#define ACCEL_GRP4_IEN (1 << 5) +/* DATA_CTRL_REG */ +#define ACCEL_GRP4_ODR0_781 0x08 +#define ACCEL_GRP4_ODR1_563 0x09 +#define ACCEL_GRP4_ODR3_125 0x0A +#define ACCEL_GRP4_ODR6_25 0x0B +#define ACCEL_GRP4_ODR12_5 0x00 +#define ACCEL_GRP4_ODR25 0x01 +#define ACCEL_GRP4_ODR50 0x02 +#define ACCEL_GRP4_ODR100 0x03 +#define ACCEL_GRP4_ODR200 0x04 +#define ACCEL_GRP4_ODR400 0x05 +#define ACCEL_GRP4_ODR800 0x06 +#define ACCEL_GRP4_ODR1600 0x07 +/*****************************************************************************/ + +/* Input Event Constants */ +#define ACCEL_G_MAX 8096 +#define ACCEL_FUZZ 3 +#define ACCEL_FLAT 3 +/* I2C Retry Constants */ +#define KIONIX_I2C_RETRY_COUNT 10 /* Number of times to retry i2c */ +#define KIONIX_I2C_RETRY_TIMEOUT 1 /* Timeout between retry (miliseconds) */ + +/* Earlysuspend Contants */ +#define KIONIX_ACCEL_EARLYSUSPEND_TIMEOUT 5000 /* Timeout (miliseconds) */ + +/* + * The following table lists the maximum appropriate poll interval for each + * available output data rate (ODR). + */ +static const struct { + unsigned int cutoff; + u8 mask; +} kionix_accel_grp1_odr_table[] = { + { 100, ACCEL_GRP1_ODR40 }, + { 334, ACCEL_GRP1_ODR10 }, + { 1000, ACCEL_GRP1_ODR3 }, + { 0, ACCEL_GRP1_ODR1 }, +}; + +static const struct { + unsigned int cutoff; + u8 mask; +} kionix_accel_grp2_odr_table[] = { + { 3, ACCEL_GRP2_ODR800 }, + { 5, ACCEL_GRP2_ODR400 }, + { 10, ACCEL_GRP2_ODR200 }, + { 20, ACCEL_GRP2_ODR100 }, + { 40, ACCEL_GRP2_ODR50 }, + { 80, ACCEL_GRP2_ODR25 }, + { 0, ACCEL_GRP2_ODR12_5}, +}; + +static const struct { + unsigned int cutoff; + u8 mask; +} kionix_accel_grp4_odr_table[] = { + { 2, ACCEL_GRP4_ODR1600 }, + { 3, ACCEL_GRP4_ODR800 }, + { 5, ACCEL_GRP4_ODR400 }, + { 10, ACCEL_GRP4_ODR200 }, + { 20, ACCEL_GRP4_ODR100 }, + { 40, ACCEL_GRP4_ODR50 }, + { 80, ACCEL_GRP4_ODR25 }, + { 160, ACCEL_GRP4_ODR12_5}, + { 320, ACCEL_GRP4_ODR6_25}, + { 640, ACCEL_GRP4_ODR3_125}, + { 1280, ACCEL_GRP4_ODR1_563}, + { 0, ACCEL_GRP4_ODR0_781}, +}; + +enum { + accel_grp1_ctrl_reg1 = 0, + accel_grp1_regs_count, +}; + +enum { + accel_grp2_ctrl_reg1 = 0, + accel_grp2_data_ctrl, + accel_grp2_int_ctrl, + accel_grp2_regs_count, +}; + +enum { + accel_grp4_ctrl_reg1 = 0, + accel_grp4_data_ctrl, + accel_grp4_int_ctrl, + accel_grp4_regs_count, +}; + +#define GSENSOR_PROC_NAME "gsensor_config" +#define GSENSOR_MAJOR 161 +static struct i2c_client *this_client = NULL; +static struct platform_device *this_pdev; +static struct kionix_accel_platform_data kionix_accel_pdata = { + .min_interval = 5, + .poll_interval = 200, + .accel_direction = 7, + .accel_irq_use_drdy = 0, + .accel_res = KIONIX_ACCEL_RES_12BIT, + .accel_g_range = KIONIX_ACCEL_G_4G, +}; +/* +struct kionix_config +{ + int op; + int int_gpio; //0-3 + int xyz_axis[3][2]; // (axis,direction) + int rxyz_axis[3][2]; + int irq; + struct proc_dir_entry* sensor_proc; + int sensorlevel; + int shake_enable; // 1--enable shake, 0--disable shake + int manual_rotation; // 0--landance, 90--vertical + struct input_dev *input_dev; + //struct work_struct work; + struct delayed_work work; // for polling + struct workqueue_struct *queue; + int isdbg; // 0-- no debug log, 1--show debug log + int sensor_samp; // 1,2,4,8,16,32,64,120 + int sensor_enable; // 0 --> disable sensor, 1 --> enable sensor + int test_pass; + spinlock_t spinlock; + int pollcnt; // the counts of polling + int offset[3]; +}; + +static struct kionix_config l_sensorconfig = { + .op = 0, + .int_gpio = 3, + .xyz_axis = { + {ABS_X, -1}, + {ABS_Y, 1}, + {ABS_Z, -1}, + }, + .irq = 6, + .int_gpio = 3, + .sensor_proc = NULL, + //.sensorlevel = SENSOR_GRAVITYGAME_MODE, + .shake_enable = 0, // default enable shake + .isdbg = 0, + .sensor_samp = 10, // 4sample/second + .sensor_enable = 1, // enable sensor + .test_pass = 0, // for test program + .pollcnt = 0, // Don't report the x,y,z when the driver is loaded until 2~3 seconds + .offset = {0,0,0}, +}; +*/ + +struct kionix_accel_driver { + struct i2c_client *client; + struct kionix_accel_platform_data accel_pdata; + struct input_dev *input_dev; + struct delayed_work accel_work; + struct workqueue_struct *accel_workqueue; + wait_queue_head_t wqh_suspend; + + int accel_data[3]; + int accel_cali[3]; + u8 axis_map_x; + u8 axis_map_y; + u8 axis_map_z; + bool negate_x; + bool negate_y; + bool negate_z; + u8 shift; + + unsigned int poll_interval; + unsigned int poll_delay; + unsigned int accel_group; + u8 *accel_registers; + + atomic_t accel_suspended; + atomic_t accel_suspend_continue; + atomic_t accel_enabled; + atomic_t accel_input_event; + atomic_t accel_enable_resume; + struct mutex mutex_earlysuspend; + struct mutex mutex_resume; + struct mutex mutex_subinput; + rwlock_t rwlock_accel_data; + + bool accel_drdy; + + /* Function callback */ + void (*kionix_accel_report_accel_data)(struct kionix_accel_driver *acceld); + int (*kionix_accel_update_odr)(struct kionix_accel_driver *acceld, unsigned int poll_interval); + int (*kionix_accel_power_on_init)(struct kionix_accel_driver *acceld); + int (*kionix_accel_operate)(struct kionix_accel_driver *acceld); + int (*kionix_accel_standby)(struct kionix_accel_driver *acceld); + +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif /* CONFIG_HAS_EARLYSUSPEND */ +}; + +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); +static void kionix_accel_update_direction(struct kionix_accel_driver *acceld); +static int get_axisset(struct kionix_accel_driver *acceld) +{ + char varbuf[64]; + int n; + int ubootvar[3][3]; + int varlen; + int err; + + memset(varbuf, 0, sizeof(varbuf)); + varlen = sizeof(varbuf); + if (wmt_getsyspara("wmt.io.kionixgsensor", varbuf, &varlen)) { + printk(KERN_DEBUG "Can't get gsensor config in u-boot!!!!\n"); + return -1; + kionix_accel_update_direction(acceld);//return -1; + } else { + sscanf(varbuf, "%d:%d:%d:%d:%d:%d", + &ubootvar[0][0], + &ubootvar[0][1], + &ubootvar[1][0], + &ubootvar[1][1], + &ubootvar[2][0], + &ubootvar[2][1]); + + acceld->axis_map_x = ubootvar[0][0]; + acceld->negate_x = ubootvar[0][1]<0?1:0; + acceld->axis_map_y = ubootvar[1][0]; + acceld->negate_y = ubootvar[1][1]<0?1:0; + acceld->axis_map_z = ubootvar[2][0]; + acceld->negate_z = ubootvar[2][1]<0?1:0; + /*kionix_accel_pdata.accel_direction = direction; + printk(KERN_ERR"accel_direction is %d,g_range is %d,res is %d\n",kionix_accel_pdata.accel_direction,kionix_accel_pdata.accel_g_range,kionix_accel_pdata.accel_res);*/ + + } + return 0; +} + +static int kionix_i2c_read(struct i2c_client *client, u8 addr, u8 *data, int len) +{ + struct i2c_msg msgs[] = { + { + .addr = client->addr, + .flags = client->flags, + .len = 1, + .buf = &addr, + }, + { + .addr = client->addr, + .flags = client->flags | I2C_M_RD, + .len = len, + .buf = data, + }, + }; + + return i2c_transfer(client->adapter, msgs, 2); +} + +static int kionix_i2c_write(struct i2c_client *client, u8 addr, u8 *data, int len) +{ + char wrData[12] = {0}; + /* + struct i2c_msg msgs = + {.addr = client->addr, .flags = 0, .len = len+1, .buf = wrData,}; +*/ + struct i2c_msg msgs[] = { + { + .addr = client->addr, + .flags = client->flags, + .len = len+1, + .buf = wrData, + }, + }; + + if (!client || (!data)) + { + printk("%s NULL client!\n", __FUNCTION__); + return -EIO; + } + + wrData[0] = addr; + strncpy(&wrData[1], data, len); + + if (i2c_transfer(client->adapter, &msgs, 1) < 0) { + printk( "%s: transfer failed.", __func__); + return -EIO; + } + + return 0; +} + +static int kionix_i2c_writebyte(struct i2c_client *client, u8 addr, u8 data) +{ + char wrData[2] = {0}; + /* + struct i2c_msg msgs = + {.addr = client->addr, .flags = 0, .len = len+1, .buf = wrData,}; +*/ + struct i2c_msg msgs[] = { + { + .addr = client->addr, + .flags = client->flags, + .len = 2, + .buf = &wrData[0], + }, + }; + + if (!client) + { + printk("%s NULL client!\n", __FUNCTION__); + return -EIO; + } + + wrData[0] = addr; + //strncpy(&wrData[1], data, len); + wrData[1] = data; + + if (i2c_transfer(client->adapter, &msgs, 1) < 0) { + printk( "%s: transfer failed.", __func__); + return -EIO; + } + + return 0; +} + +static int kionix_strtok(const char *buf, size_t count, char **token, const int token_nr) +{ + char *buf2 = (char *)kzalloc((count + 1) * sizeof(char), GFP_KERNEL); + char **token2 = token; + unsigned int num_ptr = 0, num_nr = 0, num_neg = 0; + int i = 0, start = 0, end = (int)count; + + strcpy(buf2, buf); + + /* We need to breakup the string into separate chunks in order for kstrtoint + * or strict_strtol to parse them without returning an error. Stop when the end of + * the string is reached or when enough value is read from the string */ + while((start < end) && (i < token_nr)) { + /* We found a negative sign */ + if(*(buf2 + start) == '-') { + /* Previous char(s) are numeric, so we store their value first before proceed */ + if(num_nr > 0) { + /* If there is a pending negative sign, we adjust the variables to account for it */ + if(num_neg) { + num_ptr--; + num_nr++; + } + *token2 = (char *)kzalloc((num_nr + 2) * sizeof(char), GFP_KERNEL); + strncpy(*token2, (const char *)(buf2 + num_ptr), (size_t) num_nr); + *(*token2+num_nr) = '\n'; + i++; + token2++; + /* Reset */ + num_ptr = num_nr = 0; + } + /* This indicates that there is a pending negative sign in the string */ + num_neg = 1; + } + /* We found a numeric */ + else if((*(buf2 + start) >= '0') && (*(buf2 + start) <= '9')) { + /* If the previous char(s) are not numeric, set num_ptr to current char */ + if(num_nr < 1) + num_ptr = start; + num_nr++; + } + /* We found an unwanted character */ + else { + /* Previous char(s) are numeric, so we store their value first before proceed */ + if(num_nr > 0) { + if(num_neg) { + num_ptr--; + num_nr++; + } + *token2 = (char *)kzalloc((num_nr + 2) * sizeof(char), GFP_KERNEL); + strncpy(*token2, (const char *)(buf2 + num_ptr), (size_t) num_nr); + *(*token2+num_nr) = '\n'; + i++; + token2++; + } + /* Reset all the variables to start afresh */ + num_ptr = num_nr = num_neg = 0; + } + start++; + } + + kfree(buf2); + + return (i == token_nr) ? token_nr : -1; +} + +static int kionix_accel_grp1_power_on_init(struct kionix_accel_driver *acceld) +{ + int err; + + if(atomic_read(&acceld->accel_enabled) > 0) { + err = i2c_smbus_write_byte_data(acceld->client, + ACCEL_GRP1_CTRL_REG1, acceld->accel_registers[accel_grp1_ctrl_reg1] | ACCEL_GRP1_PC1_ON); + if (err < 0) + return err; + } + else { + err = i2c_smbus_write_byte_data(acceld->client, + ACCEL_GRP1_CTRL_REG1, acceld->accel_registers[accel_grp1_ctrl_reg1]); + if (err < 0) + return err; + } + + return 0; +} + +static int kionix_accel_grp1_operate(struct kionix_accel_driver *acceld) +{ + int err; + + err = i2c_smbus_write_byte_data(acceld->client, ACCEL_GRP1_CTRL_REG1, \ + acceld->accel_registers[accel_grp2_ctrl_reg1] | ACCEL_GRP1_PC1_ON); + if (err < 0) + return err; + + queue_delayed_work(acceld->accel_workqueue, &acceld->accel_work, 0); + + return 0; +} + +static int kionix_accel_grp1_standby(struct kionix_accel_driver *acceld) +{ + int err; + + cancel_delayed_work_sync(&acceld->accel_work); + + err = i2c_smbus_write_byte_data(acceld->client, ACCEL_GRP1_CTRL_REG1, 0); + if (err < 0) + return err; + + return 0; +} + +static void kionix_accel_grp1_report_accel_data(struct kionix_accel_driver *acceld) +{ + u8 accel_data[3]; + s16 x, y, z; + int err; + struct input_dev *input_dev = acceld->input_dev; + int loop = KIONIX_I2C_RETRY_COUNT; + + if(atomic_read(&acceld->accel_enabled) > 0) { + if(atomic_read(&acceld->accel_enable_resume) > 0) + { + while(loop) { + //mutex_lock(&input_dev->mutex); + mutex_lock(&acceld->mutex_subinput); + err = kionix_i2c_read(acceld->client, ACCEL_GRP1_XOUT, accel_data, 6); + //mutex_unlock(&input_dev->mutex); + mutex_unlock(&acceld->mutex_subinput); + if(err < 0){ + loop--; + mdelay(KIONIX_I2C_RETRY_TIMEOUT); + } + else + loop = 0; + } + if (err < 0) { + KMSGERR(&acceld->client->dev, "%s: read data output error = %d\n", __func__, err); + } + else { + write_lock(&acceld->rwlock_accel_data); + + x = ((s16) le16_to_cpu(((s16)(accel_data[acceld->axis_map_x] >> 2)) - 32)) << 6; + y = ((s16) le16_to_cpu(((s16)(accel_data[acceld->axis_map_y] >> 2)) - 32)) << 6; + z = ((s16) le16_to_cpu(((s16)(accel_data[acceld->axis_map_z] >> 2)) - 32)) << 6; + + acceld->accel_data[acceld->axis_map_x] = (acceld->negate_x ? -x : x) + acceld->accel_cali[acceld->axis_map_x]; + acceld->accel_data[acceld->axis_map_y] = (acceld->negate_y ? -y : y) + acceld->accel_cali[acceld->axis_map_y]; + acceld->accel_data[acceld->axis_map_z] = (acceld->negate_z ? -z : z) + acceld->accel_cali[acceld->axis_map_z]; + + if(atomic_read(&acceld->accel_input_event) > 0) { + input_report_abs(acceld->input_dev, ABS_X, acceld->accel_data[acceld->axis_map_x]); + input_report_abs(acceld->input_dev, ABS_Y, acceld->accel_data[acceld->axis_map_y]); + input_report_abs(acceld->input_dev, ABS_Z, acceld->accel_data[acceld->axis_map_z]); + input_sync(acceld->input_dev); + } + + write_unlock(&acceld->rwlock_accel_data); + } + } + else + { + atomic_inc(&acceld->accel_enable_resume); + } + } +} + +static int kionix_accel_grp1_update_odr(struct kionix_accel_driver *acceld, unsigned int poll_interval) +{ + int err; + int i; + u8 odr; + + /* Use the lowest ODR that can support the requested poll interval */ + for (i = 0; i < ARRAY_SIZE(kionix_accel_grp1_odr_table); i++) { + odr = kionix_accel_grp1_odr_table[i].mask; + if (poll_interval < kionix_accel_grp1_odr_table[i].cutoff) + break; + } + + /* Do not need to update CTRL_REG1 register if the ODR is not changed */ + if((acceld->accel_registers[accel_grp1_ctrl_reg1] & ACCEL_GRP1_ODR_MASK) == odr) + return 0; + else { + acceld->accel_registers[accel_grp1_ctrl_reg1] &= ~ACCEL_GRP1_ODR_MASK; + acceld->accel_registers[accel_grp1_ctrl_reg1] |= odr; + } + + /* Do not need to update CTRL_REG1 register if the sensor is not currently turn on */ + if(atomic_read(&acceld->accel_enabled) > 0) { + err = i2c_smbus_write_byte_data(acceld->client, ACCEL_GRP1_CTRL_REG1, \ + acceld->accel_registers[accel_grp1_ctrl_reg1] | ACCEL_GRP1_PC1_ON); + if (err < 0) + return err; + } + + return 0; +} + +static int kionix_accel_grp2_power_on_init(struct kionix_accel_driver *acceld) +{ + int err; + + /* ensure that PC1 is cleared before updating control registers */ + err = i2c_smbus_write_byte_data(acceld->client, + ACCEL_GRP2_CTRL_REG1, 0); + if (err < 0) + return err; + + err = i2c_smbus_write_byte_data(acceld->client, + ACCEL_GRP2_DATA_CTRL, acceld->accel_registers[accel_grp2_data_ctrl]); + if (err < 0) + return err; + + /* only write INT_CTRL_REG1 if in irq mode */ + if (acceld->client->irq) { + err = i2c_smbus_write_byte_data(acceld->client, + ACCEL_GRP2_INT_CTRL1, acceld->accel_registers[accel_grp2_int_ctrl]); + if (err < 0) + return err; + } + + if(atomic_read(&acceld->accel_enabled) > 0) { + err = i2c_smbus_write_byte_data(acceld->client, + ACCEL_GRP2_CTRL_REG1, acceld->accel_registers[accel_grp2_ctrl_reg1] | ACCEL_GRP2_PC1_ON); + if (err < 0) + return err; + } + else { + err = i2c_smbus_write_byte_data(acceld->client, + ACCEL_GRP2_CTRL_REG1, acceld->accel_registers[accel_grp2_ctrl_reg1]); + if (err < 0) + return err; + } + + return 0; +} + +static int kionix_accel_grp2_operate(struct kionix_accel_driver *acceld) +{ + int err; + + err = i2c_smbus_write_byte_data(acceld->client, ACCEL_GRP2_CTRL_REG1, \ + acceld->accel_registers[accel_grp2_ctrl_reg1] | ACCEL_GRP2_PC1_ON); + if (err < 0) + return err; + + if(acceld->accel_drdy == 0) + queue_delayed_work(acceld->accel_workqueue, &acceld->accel_work, 0); + + return 0; +} + +static int kionix_accel_grp2_standby(struct kionix_accel_driver *acceld) +{ + int err; + + if(acceld->accel_drdy == 0) + cancel_delayed_work_sync(&acceld->accel_work); + + err = i2c_smbus_write_byte_data(acceld->client, ACCEL_GRP2_CTRL_REG1, 0); + if (err < 0) + return err; + + return 0; +} + +static void kionix_accel_grp2_report_accel_data(struct kionix_accel_driver *acceld) +{ + struct { union { + s16 accel_data_s16[3]; + s8 accel_data_s8[6]; + }; } accel_data; + s16 x, y, z; + int err; + struct input_dev *input_dev = acceld->input_dev; + int loop; + + /* Only read the output registers if enabled */ + if(atomic_read(&acceld->accel_enabled) > 0) { + if(atomic_read(&acceld->accel_enable_resume) > 0) + { + loop = KIONIX_I2C_RETRY_COUNT; + while(loop) { + //mutex_lock(&input_dev->mutex); + mutex_lock(&acceld->mutex_subinput); + err = kionix_i2c_read(acceld->client, ACCEL_GRP2_XOUT_L, (u8 *)accel_data.accel_data_s16, 6); + //mutex_unlock(&input_dev->mutex); + mutex_unlock(&acceld->mutex_subinput); + if(err < 0){ + loop--; + mdelay(KIONIX_I2C_RETRY_TIMEOUT); + } + else + loop = 0; + } + if (err < 0) { + KMSGERR(&acceld->client->dev, "%s: read data output error = %d\n", __func__, err); + } + else { + write_lock(&acceld->rwlock_accel_data); + + x = ((s16) le16_to_cpu(accel_data.accel_data_s16[acceld->axis_map_x])) >> acceld->shift; + y = ((s16) le16_to_cpu(accel_data.accel_data_s16[acceld->axis_map_y])) >> acceld->shift; + z = ((s16) le16_to_cpu(accel_data.accel_data_s16[acceld->axis_map_z])) >> acceld->shift; + + acceld->accel_data[acceld->axis_map_x] = (acceld->negate_x ? -x : x) + acceld->accel_cali[acceld->axis_map_x]; + acceld->accel_data[acceld->axis_map_y] = (acceld->negate_y ? -y : y) + acceld->accel_cali[acceld->axis_map_y]; + acceld->accel_data[acceld->axis_map_z] = (acceld->negate_z ? -z : z) + acceld->accel_cali[acceld->axis_map_z]; + + if(atomic_read(&acceld->accel_input_event) > 0) { + input_report_abs(acceld->input_dev, ABS_X, acceld->accel_data[acceld->axis_map_x]); + input_report_abs(acceld->input_dev, ABS_Y, acceld->accel_data[acceld->axis_map_y]); + input_report_abs(acceld->input_dev, ABS_Z, acceld->accel_data[acceld->axis_map_z]); + input_sync(acceld->input_dev); + } + + write_unlock(&acceld->rwlock_accel_data); + } + } + else + { + atomic_inc(&acceld->accel_enable_resume); + } + } + + /* Clear the interrupt if using drdy */ + if(acceld->accel_drdy == 1) { + loop = KIONIX_I2C_RETRY_COUNT; + while(loop) { + err = i2c_smbus_read_byte_data(acceld->client, ACCEL_GRP2_INT_REL); + if(err < 0){ + loop--; + mdelay(KIONIX_I2C_RETRY_TIMEOUT); + } + else + loop = 0; + } + if (err < 0) + KMSGERR(&acceld->client->dev, "%s: clear interrupt error = %d\n", __func__, err); + } +} + +static void kionix_accel_grp2_update_g_range(struct kionix_accel_driver *acceld) +{ + acceld->accel_registers[accel_grp2_ctrl_reg1] &= ~ACCEL_GRP2_G_MASK; + + switch (acceld->accel_pdata.accel_g_range) { + case KIONIX_ACCEL_G_8G: + case KIONIX_ACCEL_G_6G: + acceld->shift = 2; + acceld->accel_registers[accel_grp2_ctrl_reg1] |= ACCEL_GRP2_G_8G; + break; + case KIONIX_ACCEL_G_4G: + acceld->shift = 3; + acceld->accel_registers[accel_grp2_ctrl_reg1] |= ACCEL_GRP2_G_4G; + break; + case KIONIX_ACCEL_G_2G: + default: + acceld->shift = 4; + acceld->accel_registers[accel_grp2_ctrl_reg1] |= ACCEL_GRP2_G_2G; + break; + } + + return; +} + +static int kionix_accel_grp2_update_odr(struct kionix_accel_driver *acceld, unsigned int poll_interval) +{ + int err; + int i; + u8 odr; + + /* Use the lowest ODR that can support the requested poll interval */ + for (i = 0; i < ARRAY_SIZE(kionix_accel_grp2_odr_table); i++) { + odr = kionix_accel_grp2_odr_table[i].mask; + if (poll_interval < kionix_accel_grp2_odr_table[i].cutoff) + break; + } + + /* Do not need to update DATA_CTRL_REG register if the ODR is not changed */ + if(acceld->accel_registers[accel_grp2_data_ctrl] == odr) + return 0; + else + acceld->accel_registers[accel_grp2_data_ctrl] = odr; + + /* Do not need to update DATA_CTRL_REG register if the sensor is not currently turn on */ + if(atomic_read(&acceld->accel_enabled) > 0) { + err = i2c_smbus_write_byte_data(acceld->client, ACCEL_GRP2_CTRL_REG1, 0); + if (err < 0) + return err; + + err = i2c_smbus_write_byte_data(acceld->client, ACCEL_GRP2_DATA_CTRL, acceld->accel_registers[accel_grp2_data_ctrl]); + if (err < 0) + return err; + + err = i2c_smbus_write_byte_data(acceld->client, ACCEL_GRP2_CTRL_REG1, acceld->accel_registers[accel_grp2_ctrl_reg1] | ACCEL_GRP2_PC1_ON); + if (err < 0) + return err; + } + + return 0; +} + +static int kionix_accel_grp4_power_on_init(struct kionix_accel_driver *acceld) +{ + int err; + char rxData[2] = {0}; + /* ensure that PC1 is cleared before updating control registers */ + /*err = i2c_smbus_write_byte_data(acceld->client, + ACCEL_GRP4_CTRL_REG1, 0);*/ + + err = kionix_i2c_writebyte(acceld->client, + ACCEL_GRP4_CTRL_REG1, 0); + /*kionix_i2c_read(acceld->client,ACCEL_GRP4_CTRL_REG1,rxData,1); + printk(KERN_ERR"%d ,%s: ACCEL_GRP4_CTRL_REG1 is %d",__LINE__,__FUNCTION__,rxData[0]);*/ + + if (err < 0) + return err; + + /*err = i2c_smbus_write_byte_data(acceld->client, + ACCEL_GRP4_DATA_CTRL, acceld->accel_registers[accel_grp4_data_ctrl]);*/ + + err = kionix_i2c_writebyte(acceld->client, + ACCEL_GRP4_DATA_CTRL, acceld->accel_registers[accel_grp4_data_ctrl]); + /*kionix_i2c_read(acceld->client,ACCEL_GRP4_CTRL_REG1,rxData,1); + printk(KERN_ERR"%d,%s: ACCEL_GRP4_CTRL_REG1 now is %d,wanted value is %d",__LINE__,__FUNCTION__,rxData[0],rxData[1]);*/ + + if (err < 0) + return err; + + /* only write INT_CTRL_REG1 if in irq mode */ + if (acceld->client->irq) { + err = i2c_smbus_write_byte_data(acceld->client, + ACCEL_GRP4_INT_CTRL1, acceld->accel_registers[accel_grp4_int_ctrl]); + if (err < 0) + return err; + } + + if(atomic_read(&acceld->accel_enabled) > 0) { + /*err = i2c_smbus_write_byte_data(acceld->client, + ACCEL_GRP4_CTRL_REG1, acceld->accel_registers[accel_grp4_ctrl_reg1] | ACCEL_GRP4_PC1_ON);*/ + + err = kionix_i2c_writebyte(acceld->client, + ACCEL_GRP4_CTRL_REG1, acceld->accel_registers[accel_grp4_ctrl_reg1] | ACCEL_GRP4_PC1_ON); + /*kionix_i2c_read(acceld->client,ACCEL_GRP4_CTRL_REG1,rxData,1); + printk(KERN_ERR"%d,%s: ACCEL_GRP4_CTRL_REG1 now is %d,wanted value is %d",rxData[0],rxData[1]);*/ + + if (err < 0) + return err; + } + else { + /*err = i2c_smbus_write_byte_data(acceld->client, + ACCEL_GRP4_CTRL_REG1, acceld->accel_registers[accel_grp4_ctrl_reg1]);*/ + + err = kionix_i2c_writebyte(acceld->client, + ACCEL_GRP4_CTRL_REG1, acceld->accel_registers[accel_grp4_ctrl_reg1]); + /*kionix_i2c_read(acceld->client,ACCEL_GRP4_CTRL_REG1,rxData,1); + printk(KERN_ERR"%d,%s: ACCEL_GRP4_CTRL_REG1 now is %d,wanted value is %d",__LINE__,__FUNCTION__,rxData[0],acceld->accel_registers[accel_grp4_ctrl_reg1]);*/ + + if (err < 0) + return err; + } + + return 0; +} + +static int kionix_accel_grp4_operate(struct kionix_accel_driver *acceld) +{ + int err; + + /*err = i2c_smbus_write_byte_data(acceld->client, ACCEL_GRP4_CTRL_REG1, \ + acceld->accel_registers[accel_grp4_ctrl_reg1] | ACCEL_GRP4_PC1_ON);*/ + + err = kionix_i2c_writebyte(acceld->client, ACCEL_GRP4_CTRL_REG1, \ + acceld->accel_registers[accel_grp4_ctrl_reg1] | ACCEL_GRP4_PC1_ON); + if (err < 0) + return err; + + if(acceld->accel_drdy == 0) + queue_delayed_work(acceld->accel_workqueue, &acceld->accel_work, 0); + + return 0; +} + +static int kionix_accel_grp4_standby(struct kionix_accel_driver *acceld) +{ + int err; + + if(acceld->accel_drdy == 0) + cancel_delayed_work_sync(&acceld->accel_work); + + //err = i2c_smbus_write_byte_data(acceld->client, ACCEL_GRP4_CTRL_REG1, 0); + err = kionix_i2c_writebyte(acceld->client, ACCEL_GRP4_CTRL_REG1, 0); + if (err < 0) + return err; + + return 0; +} + +static void kionix_accel_grp4_report_accel_data(struct kionix_accel_driver *acceld) +{ + struct { union { + s16 accel_data_s16[3]; + s8 accel_data_s8[6]; + }; } accel_data; + s16 x, y, z; + int err; + struct input_dev *input_dev = acceld->input_dev; + int loop; + + /* Only read the output registers if enabled */ + if(atomic_read(&acceld->accel_enabled) > 0) { + if(atomic_read(&acceld->accel_enable_resume) > 0) + { + loop = KIONIX_I2C_RETRY_COUNT; + while(loop) { + //mutex_lock(&input_dev->mutex); + mutex_lock(&acceld->mutex_subinput); + err = kionix_i2c_read(acceld->client, ACCEL_GRP4_XOUT_L, (u8 *)accel_data.accel_data_s16, 6); + //mutex_unlock(&input_dev->mutex); + mutex_unlock(&acceld->mutex_subinput); + if(err < 0){ + loop--; + mdelay(KIONIX_I2C_RETRY_TIMEOUT); + } + else + loop = 0; + } + if (err < 0) { + KMSGERR(&acceld->client->dev, "%s: read data output error = %d\n", __func__, err); + } + else { + write_lock(&acceld->rwlock_accel_data); + + x = ((s16) le16_to_cpu(accel_data.accel_data_s16[acceld->axis_map_x])) >> acceld->shift; + y = ((s16) le16_to_cpu(accel_data.accel_data_s16[acceld->axis_map_y])) >> acceld->shift; + z = ((s16) le16_to_cpu(accel_data.accel_data_s16[acceld->axis_map_z])) >> acceld->shift; + + acceld->accel_data[acceld->axis_map_x] = (acceld->negate_x ? -x : x) + acceld->accel_cali[acceld->axis_map_x]; + acceld->accel_data[acceld->axis_map_y] = (acceld->negate_y ? -y : y) + acceld->accel_cali[acceld->axis_map_y]; + acceld->accel_data[acceld->axis_map_z] = (acceld->negate_z ? -z : z) + acceld->accel_cali[acceld->axis_map_z]; + + //printk(KERN_ERR"x:%d,y:%d,z:%d",x,y,z); + + if(atomic_read(&acceld->accel_input_event) > 0) { + input_report_abs(acceld->input_dev, ABS_X, acceld->accel_data[acceld->axis_map_x]); + input_report_abs(acceld->input_dev, ABS_Y, acceld->accel_data[acceld->axis_map_y]); + input_report_abs(acceld->input_dev, ABS_Z, acceld->accel_data[acceld->axis_map_z]); + input_sync(acceld->input_dev); + } + + write_unlock(&acceld->rwlock_accel_data); + } + } + else + { + atomic_inc(&acceld->accel_enable_resume); + } + } + + /* Clear the interrupt if using drdy */ + if(acceld->accel_drdy == 1) { + loop = KIONIX_I2C_RETRY_COUNT; + while(loop) { + err = i2c_smbus_read_byte_data(acceld->client, ACCEL_GRP4_INT_REL); + if(err < 0){ + loop--; + mdelay(KIONIX_I2C_RETRY_TIMEOUT); + } + else + loop = 0; + } + if (err < 0) + KMSGERR(&acceld->client->dev, "%s: clear interrupt error = %d\n", __func__, err); + } +} + +static void kionix_accel_grp4_update_g_range(struct kionix_accel_driver *acceld) +{ + acceld->accel_registers[accel_grp4_ctrl_reg1] &= ~ACCEL_GRP4_G_MASK; + //printk(KERN_ERR"kionix_accel_grp4_update_g_range is %d",acceld->accel_pdata.accel_g_range); + switch (acceld->accel_pdata.accel_g_range) { + case KIONIX_ACCEL_G_8G: + case KIONIX_ACCEL_G_6G: + //acceld->shift = 2; + acceld->accel_registers[accel_grp4_ctrl_reg1] |= ACCEL_GRP4_G_8G; + break; + case KIONIX_ACCEL_G_4G: + //acceld->shift = 4;//3; + acceld->accel_registers[accel_grp4_ctrl_reg1] |= ACCEL_GRP4_G_4G; + break; + case KIONIX_ACCEL_G_2G: + default: + //acceld->shift = 4; + acceld->accel_registers[accel_grp4_ctrl_reg1] |= ACCEL_GRP4_G_2G; + break; + } + + return; +} + +static int kionix_accel_grp4_update_odr(struct kionix_accel_driver *acceld, unsigned int poll_interval) +{ + int err; + int i; + u8 odr; + + /* Use the lowest ODR that can support the requested poll interval */ + for (i = 0; i < ARRAY_SIZE(kionix_accel_grp4_odr_table); i++) { + odr = kionix_accel_grp4_odr_table[i].mask; + if (poll_interval < kionix_accel_grp4_odr_table[i].cutoff) + break; + } + + /* Do not need to update DATA_CTRL_REG register if the ODR is not changed */ + if(acceld->accel_registers[accel_grp4_data_ctrl] == odr) + return 0; + else + acceld->accel_registers[accel_grp4_data_ctrl] = odr; + + /* Do not need to update DATA_CTRL_REG register if the sensor is not currently turn on */ + if(atomic_read(&acceld->accel_enabled) > 0) { + //err = i2c_smbus_write_byte_data(acceld->client, ACCEL_GRP4_CTRL_REG1, 0); + err = kionix_i2c_writebyte(acceld->client, ACCEL_GRP4_CTRL_REG1, 0); + + + if (err < 0) + return err; + + //err = i2c_smbus_write_byte_data(acceld->client, ACCEL_GRP4_DATA_CTRL, acceld->accel_registers[accel_grp4_data_ctrl]); + err = kionix_i2c_writebyte(acceld->client, ACCEL_GRP4_DATA_CTRL, acceld->accel_registers[accel_grp4_data_ctrl]); + if (err < 0) + return err; + + //err = i2c_smbus_write_byte_data(acceld->client, ACCEL_GRP4_CTRL_REG1, acceld->accel_registers[accel_grp4_ctrl_reg1] | ACCEL_GRP4_PC1_ON); + err = kionix_i2c_writebyte(acceld->client, ACCEL_GRP4_CTRL_REG1, acceld->accel_registers[accel_grp4_ctrl_reg1] | ACCEL_GRP4_PC1_ON); + if (err < 0) + return err; + //############# + err = i2c_smbus_read_byte_data(acceld->client, ACCEL_GRP4_DATA_CTRL); + if (err < 0) + return err; + switch(err) { + case ACCEL_GRP4_ODR0_781: + dev_info(&acceld->client->dev, "ODR = 0.781 Hz\n"); + break; + case ACCEL_GRP4_ODR1_563: + dev_info(&acceld->client->dev, "ODR = 1.563 Hz\n"); + break; + case ACCEL_GRP4_ODR3_125: + dev_info(&acceld->client->dev, "ODR = 3.125 Hz\n"); + break; + case ACCEL_GRP4_ODR6_25: + dev_info(&acceld->client->dev, "ODR = 6.25 Hz\n"); + break; + case ACCEL_GRP4_ODR12_5: + dev_info(&acceld->client->dev, "ODR = 12.5 Hz\n"); + break; + case ACCEL_GRP4_ODR25: + dev_info(&acceld->client->dev, "ODR = 25 Hz\n"); + break; + case ACCEL_GRP4_ODR50: + dev_info(&acceld->client->dev, "ODR = 50 Hz\n"); + break; + case ACCEL_GRP4_ODR100: + dev_info(&acceld->client->dev, "ODR = 100 Hz\n"); + break; + case ACCEL_GRP4_ODR200: + dev_info(&acceld->client->dev, "ODR = 200 Hz\n"); + break; + case ACCEL_GRP4_ODR400: + dev_info(&acceld->client->dev, "ODR = 400 Hz\n"); + break; + case ACCEL_GRP4_ODR800: + dev_info(&acceld->client->dev, "ODR = 800 Hz\n"); + break; + case ACCEL_GRP4_ODR1600: + dev_info(&acceld->client->dev, "ODR = 1600 Hz\n"); + break; + default: + dev_info(&acceld->client->dev, "Unknown ODR\n"); + break; + } + //############# + } + + return 0; +} + +static int kionix_accel_power_on(struct kionix_accel_driver *acceld) +{ + if (acceld->accel_pdata.power_on) + return acceld->accel_pdata.power_on(); + + return 0; +} + +static void kionix_accel_power_off(struct kionix_accel_driver *acceld) +{ + if (acceld->accel_pdata.power_off) + acceld->accel_pdata.power_off(); +} + +static irqreturn_t kionix_accel_isr(int irq, void *dev) +{ + struct kionix_accel_driver *acceld = dev; + + queue_delayed_work(acceld->accel_workqueue, &acceld->accel_work, 0); + + return IRQ_HANDLED; +} + +static void kionix_accel_work(struct work_struct *work) +{ + struct kionix_accel_driver *acceld = container_of((struct delayed_work *)work, struct kionix_accel_driver, accel_work); + + if(acceld->accel_drdy == 0) + queue_delayed_work(acceld->accel_workqueue, &acceld->accel_work, acceld->poll_delay); + + acceld->kionix_accel_report_accel_data(acceld); +} + +static void kionix_accel_update_direction(struct kionix_accel_driver *acceld) +{ + unsigned int direction = acceld->accel_pdata.accel_direction; + unsigned int accel_group = acceld->accel_group; + + write_lock(&acceld->rwlock_accel_data); + acceld->axis_map_x = ((direction-1)%2); + acceld->axis_map_y = (direction%2); + acceld->axis_map_z = 2; + acceld->negate_z = ((direction-1)/4); + switch(accel_group) { + case KIONIX_ACCEL_GRP3: + case KIONIX_ACCEL_GRP6: + acceld->negate_x = (((direction+2)/2)%2); + acceld->negate_y = (((direction+5)/4)%2); + break; + case KIONIX_ACCEL_GRP5: + acceld->axis_map_x = (direction%2); + acceld->axis_map_y = ((direction-1)%2); + acceld->negate_x = (((direction+1)/2)%2); + acceld->negate_y = (((direction/2)+((direction-1)/4))%2); + break; + default: + acceld->negate_x = ((direction/2)%2); + acceld->negate_y = (((direction+1)/4)%2); + break; + } + write_unlock(&acceld->rwlock_accel_data); + return; +} + +static int kionix_accel_enable(struct kionix_accel_driver *acceld) +{ + int err = 0; + long remaining; + + mutex_lock(&acceld->mutex_earlysuspend); + + atomic_set(&acceld->accel_suspend_continue, 0); + + /* Make sure that the sensor had successfully resumed before enabling it */ + if(atomic_read(&acceld->accel_suspended) == 1) { + KMSGINF(&acceld->client->dev, "%s: waiting for resume\n", __func__); + remaining = wait_event_interruptible_timeout(acceld->wqh_suspend, \ + atomic_read(&acceld->accel_suspended) == 0, \ + msecs_to_jiffies(KIONIX_ACCEL_EARLYSUSPEND_TIMEOUT)); + + if(atomic_read(&acceld->accel_suspended) == 1) { + KMSGERR(&acceld->client->dev, "%s: timeout waiting for resume\n", __func__); + err = -ETIME; + goto exit; + } + } + + err = acceld->kionix_accel_operate(acceld); + + if (err < 0) { + KMSGERR(&acceld->client->dev, \ + "%s: kionix_accel_operate returned err = %d\n", __func__, err); + goto exit; + } + + atomic_inc(&acceld->accel_enabled); + +exit: + mutex_unlock(&acceld->mutex_earlysuspend); + + return err; +} + +static int kionix_accel_disable(struct kionix_accel_driver *acceld) +{ + int err = 0; + + mutex_lock(&acceld->mutex_resume); + + atomic_set(&acceld->accel_suspend_continue, 1); + + if(atomic_read(&acceld->accel_enabled) > 0){ + if(atomic_dec_and_test(&acceld->accel_enabled)) { + if(atomic_read(&acceld->accel_enable_resume) > 0) + atomic_set(&acceld->accel_enable_resume, 0); + err = acceld->kionix_accel_standby(acceld); + if (err < 0) { + KMSGERR(&acceld->client->dev, \ + "%s: kionix_accel_standby returned err = %d\n", __func__, err); + goto exit; + } + wake_up_interruptible(&acceld->wqh_suspend); + } + } + +exit: + mutex_unlock(&acceld->mutex_resume); + + return err; +} + +static int kionix_accel_input_open(struct input_dev *input) +{ + struct kionix_accel_driver *acceld = input_get_drvdata(input); + + atomic_inc(&acceld->accel_input_event); + + return 0; +} + +static void kionix_accel_input_close(struct input_dev *dev) +{ + struct kionix_accel_driver *acceld = input_get_drvdata(dev); + + atomic_dec(&acceld->accel_input_event); +} + +static void __devinit kionix_accel_init_input_device(struct kionix_accel_driver *acceld, + struct input_dev *input_dev) +{ + __set_bit(EV_ABS, input_dev->evbit); + input_set_abs_params(input_dev, ABS_X, -ACCEL_G_MAX, ACCEL_G_MAX, ACCEL_FUZZ, ACCEL_FLAT); + input_set_abs_params(input_dev, ABS_Y, -ACCEL_G_MAX, ACCEL_G_MAX, ACCEL_FUZZ, ACCEL_FLAT); + input_set_abs_params(input_dev, ABS_Z, -ACCEL_G_MAX, ACCEL_G_MAX, ACCEL_FUZZ, ACCEL_FLAT); + + input_dev->name = "g-sensor";//KIONIX_ACCEL_NAME; + input_dev->id.bustype = BUS_I2C; + input_dev->dev.parent = &acceld->client->dev; +} + +static int __devinit kionix_accel_setup_input_device(struct kionix_accel_driver *acceld) +{ + struct input_dev *input_dev; + int err; + + input_dev = input_allocate_device(); + if (!input_dev) { + KMSGERR(&acceld->client->dev, "input_allocate_device failed\n"); + printk("kionix_accel_probe: Failed to allocate input device\n"); + return -ENOMEM; + } + + acceld->input_dev = input_dev; + + input_dev->open = kionix_accel_input_open; + input_dev->close = kionix_accel_input_close; + input_set_drvdata(input_dev, acceld); + + kionix_accel_init_input_device(acceld, input_dev); + + err = input_register_device(acceld->input_dev); + if (err) { + KMSGERR(&acceld->client->dev, \ + "%s: input_register_device returned err = %d\n", __func__, err); + printk("kionix_accel_probe: Failed to register input device\n"); + input_free_device(acceld->input_dev); + return err; + } + + return 0; +} + +/* Returns the enable state of device */ +static ssize_t kionix_accel_get_enable(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct kionix_accel_driver *acceld = i2c_get_clientdata(client); + + return sprintf(buf, "%d\n", atomic_read(&acceld->accel_enabled) > 0 ? 1 : 0); +} + +/* Allow users to enable/disable the device */ +static ssize_t kionix_accel_set_enable(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct kionix_accel_driver *acceld = i2c_get_clientdata(client); + struct input_dev *input_dev = acceld->input_dev; + char *buf2; + const int enable_count = 1; + unsigned long enable; + int err = 0; + + /* Lock the device to prevent races with open/close (and itself) */ + //mutex_lock(&input_dev->mutex); + mutex_lock(&acceld->mutex_subinput); + if(kionix_strtok(buf, count, &buf2, enable_count) < 0) { + KMSGERR(&acceld->client->dev, \ + "%s: No enable data being read. " \ + "No enable data will be updated.\n", __func__); + } + + else { + /* Removes any leading negative sign */ + while(*buf2 == '-') + buf2++; + #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35)) + err = kstrtouint((const char *)buf2, 10, (unsigned int *)&enable); + if (err < 0) { + KMSGERR(&acceld->client->dev, \ + "%s: kstrtouint returned err = %d\n", __func__, err); + goto exit; + } + #else + err = strict_strtoul((const char *)buf2, 10, &enable); + if (err < 0) { + KMSGERR(&acceld->client->dev, \ + "%s: strict_strtoul returned err = %d\n", __func__, err); + goto exit; + } + #endif + + if(enable) + err = kionix_accel_enable(acceld); + else + err = kionix_accel_disable(acceld); + } + +exit: + //mutex_unlock(&input_dev->mutex); + mutex_unlock(&acceld->mutex_subinput); + return (err < 0) ? err : count; +} + +/* Returns currently selected poll interval (in ms) */ +static ssize_t kionix_accel_get_delay(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct kionix_accel_driver *acceld = i2c_get_clientdata(client); + + return sprintf(buf, "%d\n", acceld->poll_interval); +} + +/* Allow users to select a new poll interval (in ms) */ +static ssize_t kionix_accel_set_delay(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct kionix_accel_driver *acceld = i2c_get_clientdata(client); + struct input_dev *input_dev = acceld->input_dev; + char *buf2; + const int delay_count = 1; + unsigned long interval; + int err = 0; + + /* Lock the device to prevent races with open/close (and itself) */ + //mutex_lock(&input_dev->mutex); + mutex_lock(&acceld->mutex_subinput); + if(kionix_strtok(buf, count, &buf2, delay_count) < 0) { + KMSGERR(&acceld->client->dev, \ + "%s: No delay data being read. " \ + "No delay data will be updated.\n", __func__); + } + + else { + /* Removes any leading negative sign */ + while(*buf2 == '-') + buf2++; + #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35)) + err = kstrtouint((const char *)buf2, 10, (unsigned int *)&interval); + if (err < 0) { + KMSGERR(&acceld->client->dev, \ + "%s: kstrtouint returned err = %d\n", __func__, err); + goto exit; + } + #else + err = strict_strtoul((const char *)buf2, 10, &interval); + if (err < 0) { + KMSGERR(&acceld->client->dev, \ + "%s: strict_strtoul returned err = %d\n", __func__, err); + goto exit; + } + #endif + + if(acceld->accel_drdy == 1) + disable_irq(client->irq); + + /* + * Set current interval to the greater of the minimum interval or + * the requested interval + */ + acceld->poll_interval = max((unsigned int)interval, acceld->accel_pdata.min_interval); + acceld->poll_delay = msecs_to_jiffies(acceld->poll_interval); + + err = acceld->kionix_accel_update_odr(acceld, acceld->poll_interval); + + if(acceld->accel_drdy == 1) + enable_irq(client->irq); + } + +exit: + //mutex_unlock(&input_dev->mutex); + mutex_unlock(&acceld->mutex_subinput); + + return (err < 0) ? err : count; +} + +/* Returns the direction of device */ +static ssize_t kionix_accel_get_direct(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct kionix_accel_driver *acceld = i2c_get_clientdata(client); + + return sprintf(buf, "%d\n", acceld->accel_pdata.accel_direction); +} + +/* Allow users to change the direction the device */ +static ssize_t kionix_accel_set_direct(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct kionix_accel_driver *acceld = i2c_get_clientdata(client); + struct input_dev *input_dev = acceld->input_dev; + char *buf2; + const int direct_count = 1; + unsigned long direction; + int err = 0; + + /* Lock the device to prevent races with open/close (and itself) */ + //mutex_lock(&input_dev->mutex); + mutex_lock(&acceld->mutex_subinput); + if(kionix_strtok(buf, count, &buf2, direct_count) < 0) { + KMSGERR(&acceld->client->dev, \ + "%s: No direction data being read. " \ + "No direction data will be updated.\n", __func__); + } + + else { + /* Removes any leading negative sign */ + while(*buf2 == '-') + buf2++; + #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35)) + err = kstrtouint((const char *)buf2, 10, (unsigned int *)&direction); + if (err < 0) { + KMSGERR(&acceld->client->dev, \ + "%s: kstrtouint returned err = %d\n", __func__, err); + goto exit; + } + #else + err = strict_strtoul((const char *)buf2, 10, &direction); + if (err < 0) { + KMSGERR(&acceld->client->dev, \ + "%s: strict_strtoul returned err = %d\n", __func__, err); + goto exit; + } + #endif + + if(direction < 1 || direction > 8) + KMSGERR(&acceld->client->dev, "%s: invalid direction = %d\n", __func__, (unsigned int) direction); + + else { + acceld->accel_pdata.accel_direction = (u8) direction; + kionix_accel_update_direction(acceld); + } + } + +exit: + //mutex_unlock(&input_dev->mutex); + mutex_unlock(&acceld->mutex_subinput); + return (err < 0) ? err : count; +} + +/* Returns the data output of device */ +static ssize_t kionix_accel_get_data(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct kionix_accel_driver *acceld = i2c_get_clientdata(client); + int x, y, z; + + read_lock(&acceld->rwlock_accel_data); + + x = acceld->accel_data[acceld->axis_map_x]; + y = acceld->accel_data[acceld->axis_map_y]; + z = acceld->accel_data[acceld->axis_map_z]; + + read_unlock(&acceld->rwlock_accel_data); + + return sprintf(buf, "%d %d %d\n", x, y, z); +} + +/* Returns the calibration value of the device */ +static ssize_t kionix_accel_get_cali(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct kionix_accel_driver *acceld = i2c_get_clientdata(client); + int calibration[3]; + + read_lock(&acceld->rwlock_accel_data); + + calibration[0] = acceld->accel_cali[acceld->axis_map_x]; + calibration[1] = acceld->accel_cali[acceld->axis_map_y]; + calibration[2] = acceld->accel_cali[acceld->axis_map_z]; + + read_unlock(&acceld->rwlock_accel_data); + + return sprintf(buf, "%d %d %d\n", calibration[0], calibration[1], calibration[2]); +} + +/* Allow users to change the calibration value of the device */ +static ssize_t kionix_accel_set_cali(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct kionix_accel_driver *acceld = i2c_get_clientdata(client); + struct input_dev *input_dev = acceld->input_dev; + const int cali_count = 3; /* How many calibration that we expect to get from the string */ + char **buf2; + long calibration[cali_count]; + int err = 0, i = 0; + + /* Lock the device to prevent races with open/close (and itself) */ + //mutex_lock(&input_dev->mutex); + mutex_lock(&acceld->mutex_subinput); + buf2 = (char **)kzalloc(cali_count * sizeof(char *), GFP_KERNEL); + + if(kionix_strtok(buf, count, buf2, cali_count) < 0) { + KMSGERR(&acceld->client->dev, \ + "%s: Not enough calibration data being read. " \ + "No calibration data will be updated.\n", __func__); + } + else { + /* Convert string to integers */ + for(i = 0 ; i < cali_count ; i++) { + #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35)) + err = kstrtoint((const char *)*(buf2+i), 10, (int *)&calibration[i]); + if(err < 0) { + KMSGERR(&acceld->client->dev, \ + "%s: kstrtoint returned err = %d." \ + "No calibration data will be updated.\n", __func__ , err); + goto exit; + } + #else + err = strict_strtol((const char *)*(buf2+i), 10, &calibration[i]); + if(err < 0) { + KMSGERR(&acceld->client->dev, \ + "%s: strict_strtol returned err = %d." \ + "No calibration data will be updated.\n", __func__ , err); + goto exit; + } + #endif + } + + write_lock(&acceld->rwlock_accel_data); + + acceld->accel_cali[acceld->axis_map_x] = (int)calibration[0]; + acceld->accel_cali[acceld->axis_map_y] = (int)calibration[1]; + acceld->accel_cali[acceld->axis_map_z] = (int)calibration[2]; + + write_unlock(&acceld->rwlock_accel_data); + } + +exit: + for(i = 0 ; i < cali_count ; i++) + kfree(*(buf2+i)); + + kfree(buf2); + + //mutex_unlock(&input_dev->mutex); + mutex_unlock(&acceld->mutex_subinput); + + return (err < 0) ? err : count; +} + +static DEVICE_ATTR(enable, S_IRUGO|S_IWUSR, kionix_accel_get_enable, kionix_accel_set_enable); +static DEVICE_ATTR(delay, S_IRUGO|S_IWUSR, kionix_accel_get_delay, kionix_accel_set_delay); +static DEVICE_ATTR(direct, S_IRUGO|S_IWUSR, kionix_accel_get_direct, kionix_accel_set_direct); +static DEVICE_ATTR(data, S_IRUGO, kionix_accel_get_data, NULL); +static DEVICE_ATTR(cali, S_IRUGO|S_IWUSR, kionix_accel_get_cali, kionix_accel_set_cali); + +static struct attribute *kionix_accel_attributes[] = { + &dev_attr_enable.attr, + &dev_attr_delay.attr, + &dev_attr_direct.attr, + &dev_attr_data.attr, + &dev_attr_cali.attr, + NULL +}; + +static struct attribute_group kionix_accel_attribute_group = { + .attrs = kionix_accel_attributes +}; + +static int kionix_chip_id[] ={ + KIONIX_ACCEL_WHO_AM_I_KXTE9, + KIONIX_ACCEL_WHO_AM_I_KXTF9, + KIONIX_ACCEL_WHO_AM_I_KXTI9_1001, + KIONIX_ACCEL_WHO_AM_I_KXTIK_1004, + KIONIX_ACCEL_WHO_AM_I_KXTJ9_1005, + KIONIX_ACCEL_WHO_AM_I_KXTJ9_1007, + KIONIX_ACCEL_WHO_AM_I_KXCJ9_1008, + KIONIX_ACCEL_WHO_AM_I_KXTJ2_1009, + KIONIX_ACCEL_WHO_AM_I_KXCJK_1013 +}; + +static int iskionix() +{ + char rxData[2] = {0}; + int ret = 0; + int i = 0; + + ret = kionix_i2c_read(this_client,ACCEL_WHO_AM_I,rxData,1); //maybe should 2 success // -5 ioerror!! + printk(KERN_ERR"<<<<%s ret:%d val 0x%x\n", __FUNCTION__, ret, rxData[0]); + if (ret <= 0) // 2 ? + { + return -1; + } + for(i = 0 ; i < sizeof(kionix_chip_id)/sizeof(kionix_chip_id[0]);i++) + if(rxData[0] == kionix_chip_id[i]) + return 0; + + return -1; +} + +static int __devinit kionix_verify(struct kionix_accel_driver *acceld) +{ + int retval = i2c_smbus_read_byte_data(acceld->client, ACCEL_WHO_AM_I); + +#if KIONIX_KMSG_INF + switch (retval) { + case KIONIX_ACCEL_WHO_AM_I_KXTE9: + KMSGINF(&acceld->client->dev, "this accelerometer is a KXTE9.\n"); + break; + case KIONIX_ACCEL_WHO_AM_I_KXTF9: + KMSGINF(&acceld->client->dev, "this accelerometer is a KXTF9.\n"); + break; + case KIONIX_ACCEL_WHO_AM_I_KXTI9_1001: + KMSGINF(&acceld->client->dev, "this accelerometer is a KXTI9-1001.\n"); + break; + case KIONIX_ACCEL_WHO_AM_I_KXTIK_1004: + KMSGINF(&acceld->client->dev, "this accelerometer is a KXTIK-1004.\n"); + break; + case KIONIX_ACCEL_WHO_AM_I_KXTJ9_1005: + KMSGINF(&acceld->client->dev, "this accelerometer is a KXTJ9-1005.\n"); + break; + case KIONIX_ACCEL_WHO_AM_I_KXTJ9_1007: + KMSGINF(&acceld->client->dev, "this accelerometer is a KXTJ9-1007.\n"); + break; + case KIONIX_ACCEL_WHO_AM_I_KXCJ9_1008: + KMSGINF(&acceld->client->dev, "this accelerometer is a KXCJ9-1008.\n"); + break; + case KIONIX_ACCEL_WHO_AM_I_KXTJ2_1009: + KMSGINF(&acceld->client->dev, "this accelerometer is a KXTJ2-1009.\n"); + break; + case KIONIX_ACCEL_WHO_AM_I_KXCJK_1013: + KMSGINF(&acceld->client->dev, "this accelerometer is a KXCJK-1013.\n"); + break; + default: + break; + } +#endif + + return retval; +} + +#ifdef CONFIG_HAS_EARLYSUSPEND +void kionix_accel_earlysuspend_suspend(struct early_suspend *h) +{ + struct kionix_accel_driver *acceld = container_of(h, struct kionix_accel_driver, early_suspend); + long remaining; + + mutex_lock(&acceld->mutex_earlysuspend); + + /* Only continue to suspend if enable did not intervene */ + if(atomic_read(&acceld->accel_suspend_continue) > 0) { + /* Make sure that the sensor had successfully disabled before suspending it */ + if(atomic_read(&acceld->accel_enabled) > 0) { + KMSGINF(&acceld->client->dev, "%s: waiting for disable\n", __func__); + remaining = wait_event_interruptible_timeout(acceld->wqh_suspend, \ + atomic_read(&acceld->accel_enabled) < 1, \ + msecs_to_jiffies(KIONIX_ACCEL_EARLYSUSPEND_TIMEOUT)); + + if(atomic_read(&acceld->accel_enabled) > 0) { + KMSGERR(&acceld->client->dev, "%s: timeout waiting for disable\n", __func__); + } + } + + kionix_accel_power_off(acceld); + + atomic_set(&acceld->accel_suspended, 1); + } + + mutex_unlock(&acceld->mutex_earlysuspend); + + return; +} + +void kionix_accel_earlysuspend_resume(struct early_suspend *h) +{ + struct kionix_accel_driver *acceld = container_of(h, struct kionix_accel_driver, early_suspend); + int err; + + mutex_lock(&acceld->mutex_resume); + + if(atomic_read(&acceld->accel_suspended) == 1) { + err = kionix_accel_power_on(acceld); + if (err < 0) { + KMSGERR(&acceld->client->dev, "%s: kionix_accel_power_on returned err = %d\n", __func__, err); + goto exit; + } + + /* Only needs to reinitialized the registers if Vdd is pulled low during suspend */ + if(err > 0) { + err = acceld->kionix_accel_power_on_init(acceld); + if (err) { + KMSGERR(&acceld->client->dev, "%s: kionix_accel_power_on_init returned err = %d\n", __func__, err); + goto exit; + } + } + + atomic_set(&acceld->accel_suspended, 0); + } + + wake_up_interruptible(&acceld->wqh_suspend); + +exit: + mutex_unlock(&acceld->mutex_resume); + + return; +} +#endif /* CONFIG_HAS_EARLYSUSPEND */ + +static int kionix_open(struct inode *inode, struct file *file) +{ + struct kionix_accel_driver *acceld = i2c_get_clientdata(this_client); + //KMSGINF("Open the g-sensor node...\n"); + kionix_accel_input_open(acceld->input_dev); + return 0; +} + +static int kionix_release(struct inode *inode, struct file *file) +{ + struct kionix_accel_driver *acceld = i2c_get_clientdata(this_client); + //KMSGINF("Close the g-sensor node...\n"); + kionix_accel_input_close(acceld->input_dev); + return 0; +} + +static long +kionix_ioctl(/*struct inode *inode,*/ struct file *file, unsigned int cmd, + unsigned long arg) +{ + void __user *argp = (void __user *)arg; + char rwbuf[5]; + short delay, enable; //amsr = -1; + unsigned int uval = 0; + + struct kionix_accel_driver *acceld = i2c_get_clientdata(this_client); + + //KMSGINF("g-sensor ioctr...\n"); + memset(rwbuf, 0, sizeof(rwbuf)); + switch (cmd) { + case ECS_IOCTL_APP_SET_DELAY: + // set the rate of g-sensor + if (copy_from_user(&delay, argp, sizeof(short))) + { + printk(KERN_ALERT "Can't get set delay!!!\n"); + return -EFAULT; + } + klog("Get delay=%d\n", delay); + + if ((delay >=0) && (delay < 20)) + { + delay = 20; + } else if (delay > 200) + { + delay = 200; + } + //l_sensorconfig.sensor_samp = 1000/delay; + acceld->poll_interval = 1000/delay; + acceld->poll_delay = msecs_to_jiffies(acceld->poll_interval); + acceld->kionix_accel_update_odr(acceld, acceld->poll_interval); + break; + case ECS_IOCTL_APP_SET_AFLAG: + // enable/disable sensor + if (copy_from_user(&enable, argp, sizeof(short))) + { + printk(KERN_ERR "Can't get enable flag!!!\n"); + return -EFAULT; + } + klog("enable=%d\n",enable); + if ((enable >=0) && (enable <=1)) + { + //KMSGINF("driver: disable/enable(%d) gsensor.\n", enable); + + //l_sensorconfig.sensor_enable = enable; + if(enable) + kionix_accel_enable(acceld); + else + kionix_accel_disable(acceld); + + } else { + printk(KERN_ERR "Wrong enable argument in %s !!!\n", __FUNCTION__); + return -EINVAL; + } + break; + case WMT_IOCTL_SENSOR_GET_DRVID: + uval = KIONIX_DRVID; + if (copy_to_user((unsigned int*)arg, &uval, sizeof(unsigned int))) + { + return -EFAULT; + } + //KMSGINF("kionix_driver_id:%d\n",uval); + break; + case WMT_IOCTL_SENOR_GET_RESOLUTION: + + uval = (12<<8) | 8; // 8bit:4g 0xxx xx //mma8452Q + if (copy_to_user((unsigned int *)arg, &uval, sizeof(unsigned int))) + { + return -EFAULT; + } + printk("<<<<<<dev.platform_data; + struct kionix_accel_driver *acceld; + int err; + struct proc_dir_entry *proc_dir, *proc_entry; +/* + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_I2C | I2C_FUNC_SMBUS_BYTE_DATA)) { + KMSGERR(&client->dev, "client is not i2c capable. Abort.\n"); + return -ENXIO; + } +*/ + if (!accel_pdata) { + KMSGERR(&this_client->dev, "platform data is NULL. Abort.\n"); + return -EINVAL; + } + + acceld = kzalloc(sizeof(*acceld), GFP_KERNEL); + if (acceld == NULL) { + KMSGERR(&this_client->dev, \ + "failed to allocate memory for module data. Abort.\n"); + return -ENOMEM; + } + + acceld->client = this_client; + acceld->accel_pdata = *accel_pdata; + + i2c_set_clientdata(this_client, acceld); + + err = kionix_accel_power_on(acceld); + if (err < 0) + goto err_free_mem; + + if (accel_pdata->init) { + err = accel_pdata->init(); + if (err < 0) + goto err_accel_pdata_power_off; + } + + err = kionix_verify(acceld); + if (err < 0) { + KMSGERR(&acceld->client->dev, "%s: kionix_verify returned err = %d. Abort.\n", __func__, err); + goto err_accel_pdata_exit; + } + + /* Setup group specific configuration and function callback */ + switch (err) { + case KIONIX_ACCEL_WHO_AM_I_KXTE9: + acceld->accel_group = KIONIX_ACCEL_GRP1; + acceld->accel_registers = kzalloc(sizeof(u8)*accel_grp1_regs_count, GFP_KERNEL); + if (acceld->accel_registers == NULL) { + KMSGERR(&this_client->dev, \ + "failed to allocate memory for accel_registers. Abort.\n"); + goto err_accel_pdata_exit; + } + acceld->accel_drdy = 0; + acceld->kionix_accel_report_accel_data = kionix_accel_grp1_report_accel_data; + acceld->kionix_accel_update_odr = kionix_accel_grp1_update_odr; + acceld->kionix_accel_power_on_init = kionix_accel_grp1_power_on_init; + acceld->kionix_accel_operate = kionix_accel_grp1_operate; + acceld->kionix_accel_standby = kionix_accel_grp1_standby; + break; + case KIONIX_ACCEL_WHO_AM_I_KXTF9: + case KIONIX_ACCEL_WHO_AM_I_KXTI9_1001: + case KIONIX_ACCEL_WHO_AM_I_KXTIK_1004: + case KIONIX_ACCEL_WHO_AM_I_KXTJ9_1005: + if(err == KIONIX_ACCEL_WHO_AM_I_KXTIK_1004) + acceld->accel_group = KIONIX_ACCEL_GRP3; + else + acceld->accel_group = KIONIX_ACCEL_GRP2; + acceld->accel_registers = kzalloc(sizeof(u8)*accel_grp2_regs_count, GFP_KERNEL); + if (acceld->accel_registers == NULL) { + KMSGERR(&this_client->dev, \ + "failed to allocate memory for accel_registers. Abort.\n"); + goto err_accel_pdata_exit; + } + switch(acceld->accel_pdata.accel_res) { + case KIONIX_ACCEL_RES_6BIT: + case KIONIX_ACCEL_RES_8BIT: + acceld->accel_registers[accel_grp2_ctrl_reg1] |= ACCEL_GRP2_RES_8BIT; + break; + case KIONIX_ACCEL_RES_12BIT: + default: + acceld->accel_registers[accel_grp2_ctrl_reg1] |= ACCEL_GRP2_RES_12BIT; + break; + } + if(acceld->accel_pdata.accel_irq_use_drdy && this_client->irq) { + acceld->accel_registers[accel_grp2_int_ctrl] |= ACCEL_GRP2_IEN | ACCEL_GRP2_IEA; + acceld->accel_registers[accel_grp2_ctrl_reg1] |= ACCEL_GRP2_DRDYE; + acceld->accel_drdy = 1; + } + else + acceld->accel_drdy = 0; + kionix_accel_grp2_update_g_range(acceld); + acceld->kionix_accel_report_accel_data = kionix_accel_grp2_report_accel_data; + acceld->kionix_accel_update_odr = kionix_accel_grp2_update_odr; + acceld->kionix_accel_power_on_init = kionix_accel_grp2_power_on_init; + acceld->kionix_accel_operate = kionix_accel_grp2_operate; + acceld->kionix_accel_standby = kionix_accel_grp2_standby; + break; + case KIONIX_ACCEL_WHO_AM_I_KXTJ9_1007: + case KIONIX_ACCEL_WHO_AM_I_KXCJ9_1008: + case KIONIX_ACCEL_WHO_AM_I_KXTJ2_1009: + case KIONIX_ACCEL_WHO_AM_I_KXCJK_1013: + if(err == KIONIX_ACCEL_WHO_AM_I_KXTJ2_1009) + acceld->accel_group = KIONIX_ACCEL_GRP5; + else if(err == KIONIX_ACCEL_WHO_AM_I_KXCJK_1013) + acceld->accel_group = KIONIX_ACCEL_GRP6; + else + acceld->accel_group = KIONIX_ACCEL_GRP4; + acceld->accel_registers = kzalloc(sizeof(u8)*accel_grp4_regs_count, GFP_KERNEL); + if (acceld->accel_registers == NULL) { + KMSGERR(&this_client->dev, \ + "failed to allocate memory for accel_registers. Abort.\n"); + goto err_accel_pdata_exit; + } + switch(acceld->accel_pdata.accel_res) { + case KIONIX_ACCEL_RES_6BIT: + case KIONIX_ACCEL_RES_8BIT: + acceld->shift = 0; + acceld->accel_registers[accel_grp4_ctrl_reg1] |= ACCEL_GRP4_RES_8BIT; + break; + case KIONIX_ACCEL_RES_12BIT: + acceld->shift = 4; + default: + acceld->accel_registers[accel_grp4_ctrl_reg1] |= ACCEL_GRP4_RES_12BIT; + break; + } + if(acceld->accel_pdata.accel_irq_use_drdy && this_client->irq) { + acceld->accel_registers[accel_grp4_int_ctrl] |= ACCEL_GRP4_IEN | ACCEL_GRP4_IEA; + acceld->accel_registers[accel_grp4_ctrl_reg1] |= ACCEL_GRP4_DRDYE; + acceld->accel_drdy = 1; + } + else + acceld->accel_drdy = 0; + kionix_accel_grp4_update_g_range(acceld); + acceld->kionix_accel_report_accel_data = kionix_accel_grp4_report_accel_data; + acceld->kionix_accel_update_odr = kionix_accel_grp4_update_odr; + acceld->kionix_accel_power_on_init = kionix_accel_grp4_power_on_init; + acceld->kionix_accel_operate = kionix_accel_grp4_operate; + acceld->kionix_accel_standby = kionix_accel_grp4_standby; + break; + default: + KMSGERR(&acceld->client->dev, \ + "%s: unsupported device, who am i = %d. Abort.\n", __func__, err); + goto err_accel_pdata_exit; + } + + err = kionix_accel_setup_input_device(acceld); + if (err) + goto err_free_accel_registers; + +//add + /*this_pdev = pdev; + l_sensorconfig.input_dev = acceld->input_dev;*/ + + err = misc_register(&kionix_device); + if (err) { + printk(KERN_ERR + "kionix_accel_probe: kionix_device register failed\n"); + goto exit_misc_device_register_failed; + } + + //dev_set_drvdata(&pdev->dev, &l_sensorconfig); +//end add + + + atomic_set(&acceld->accel_suspended, 0); + atomic_set(&acceld->accel_suspend_continue, 1); + atomic_set(&acceld->accel_enabled, 0); + atomic_set(&acceld->accel_input_event, 0); + atomic_set(&acceld->accel_enable_resume, 0); + + mutex_init(&acceld->mutex_earlysuspend); + mutex_init(&acceld->mutex_resume); + + mutex_init(&acceld->mutex_subinput);//add 2014-6-12 + + rwlock_init(&acceld->rwlock_accel_data); + + acceld->poll_interval = acceld->accel_pdata.poll_interval; + acceld->poll_delay = msecs_to_jiffies(acceld->poll_interval); + acceld->kionix_accel_update_odr(acceld, acceld->poll_interval); + get_axisset(acceld);//kionix_accel_update_direction(acceld); + + proc_dir = proc_mkdir("sensors", NULL); + if (proc_dir == NULL) + KMSGERR(&this_client->dev, "failed to create /proc/sensors\n"); + else { + proc_entry = create_proc_entry( "accelinfo", 0644, proc_dir); + if (proc_entry == NULL) + KMSGERR(&this_client->dev, "failed to create /proc/cpu/accelinfo\n"); + } + +/* + proc_dir = create_proc_entry(GSENSOR_PROC_NAME, 0666, NULL);//&proc_root + if (proc_dir != NULL) + { + proc_dir->write_proc = sensor_writeproc; + proc_dir->read_proc = sensor_readproc; + } +*/ + acceld->accel_workqueue = create_singlethread_workqueue("Kionix Accel Workqueue"); + INIT_DELAYED_WORK(&acceld->accel_work, kionix_accel_work); + init_waitqueue_head(&acceld->wqh_suspend); + + if (acceld->accel_drdy) { + err = request_threaded_irq(this_client->irq, NULL, kionix_accel_isr, \ + IRQF_TRIGGER_RISING | IRQF_ONESHOT, \ + KIONIX_ACCEL_IRQ, acceld); + if (err) { + KMSGERR(&acceld->client->dev, "%s: request_threaded_irq returned err = %d\n", __func__, err); + KMSGERR(&acceld->client->dev, "%s: running in software polling mode instead\n", __func__); + acceld->accel_drdy = 0; + } + KMSGINF(&acceld->client->dev, "running in hardware interrupt mode\n"); + } else { + KMSGINF(&acceld->client->dev, "running in software polling mode\n"); + } + + err = acceld->kionix_accel_power_on_init(acceld); + if (err) { + KMSGERR(&acceld->client->dev, "%s: kionix_accel_power_on_init returned err = %d. Abort.\n", __func__, err); + goto err_free_irq; + } + + err = sysfs_create_group(&this_client->dev.kobj, &kionix_accel_attribute_group); + if (err) { + KMSGERR(&acceld->client->dev, "%s: sysfs_create_group returned err = %d. Abort.\n", __func__, err); + goto err_free_irq; + } + +#ifdef CONFIG_HAS_EARLYSUSPEND + /* The higher the level, the earlier it resume, and the later it suspend */ + acceld->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 50; + acceld->early_suspend.suspend = kionix_accel_earlysuspend_suspend; + acceld->early_suspend.resume = kionix_accel_earlysuspend_resume; + register_early_suspend(&acceld->early_suspend); +#endif /* CONFIG_HAS_EARLYSUSPEND */ + + + // satrt the polling work + if(acceld->accel_drdy == 0) + queue_delayed_work(acceld->accel_workqueue, &acceld->accel_work, acceld->poll_delay); + return 0; + +exit_misc_device_register_failed: +err_free_irq: + if (acceld->accel_drdy) + free_irq(this_client->irq, acceld); + destroy_workqueue(acceld->accel_workqueue); + input_unregister_device(acceld->input_dev); +err_free_accel_registers: + kfree(acceld->accel_registers); +err_accel_pdata_exit: + if (accel_pdata->exit) + accel_pdata->exit(); +err_accel_pdata_power_off: + kionix_accel_power_off(acceld); +err_free_mem: + kfree(acceld); +exit_input_dev_alloc_failed: + return err; +} + +static int kionix_accel_remove(struct platform_device *pdev) +{ + struct kionix_accel_driver *acceld = i2c_get_clientdata(this_client); + +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&acceld->early_suspend); +#endif /* CONFIG_HAS_EARLYSUSPEND */ + if (NULL != acceld->accel_workqueue) + { + cancel_delayed_work_sync(&acceld->accel_work); + flush_workqueue(acceld->accel_workqueue); + destroy_workqueue(acceld->accel_workqueue); + acceld->accel_workqueue = NULL; + } + sysfs_remove_group(&this_client->dev.kobj, &kionix_accel_attribute_group); + if (acceld->accel_drdy) + free_irq(this_client->irq, acceld); + //destroy_workqueue(acceld->accel_workqueue); + misc_deregister(&kionix_device); + input_unregister_device(acceld->input_dev); + kfree(acceld->accel_registers); + if (acceld->accel_pdata.exit) + acceld->accel_pdata.exit(); + kionix_accel_power_off(acceld); + kfree(acceld); + + return 0; +} + +static int __devexit kionix_accel_i2cremove(struct i2c_client *client) +{ + return 0; +} + +static const struct i2c_device_id kionix_accel_id[] = { + { KIONIX_ACCEL_NAME, 0 }, + { }, +}; + +MODULE_DEVICE_TABLE(i2c, kionix_accel_id); + +static struct i2c_driver kionix_accel_driver = { + .driver = { + .name = KIONIX_ACCEL_NAME, + .owner = THIS_MODULE, + }, + .probe = kionix_accel_probe, + .remove = __devexit_p(kionix_accel_i2cremove), + .id_table = kionix_accel_id, +}; + + +static struct platform_device kionix_pdevice = { + .name = "kionix", + .id = 0, + /*.dev = { + //.release = mma8452q_platform_release, + },*/ +}; + +//************ +static void kionix_accel_shutdown(struct platform_device *pdev) +{ + struct kionix_accel_driver *acceld = NULL; + acceld = i2c_get_clientdata(this_client); + if (acceld) { + printk("<<<<<%s\n", __func__); + flush_delayed_work_sync(&acceld->accel_work); + cancel_delayed_work_sync(&acceld->accel_work); + } + +} +//****add for resume dpm timeout 2014-6-12 +static int kionix_accel_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct kionix_accel_driver *acceld = NULL; + acceld = i2c_get_clientdata(this_client); + if (acceld) { + printk("<<<<<%s\n", __func__); + flush_delayed_work_sync(&acceld->accel_work); + cancel_delayed_work_sync(&acceld->accel_work); + } +} + +int kionix_accel_resume(struct platform_device *pdev) +{ + struct kionix_accel_driver *acceld = NULL; + acceld = i2c_get_clientdata(this_client); + if (acceld) { + printk("<<<<<%s\n", __func__); + queue_delayed_work(acceld->accel_workqueue, &acceld->accel_work, acceld->poll_delay); + } +} +//*********************** +static struct platform_driver kionix_driver = { + .probe = kionix_accel_probe, + .remove = kionix_accel_remove, + .shutdown = kionix_accel_shutdown, + .suspend = kionix_accel_suspend, + .resume = kionix_accel_resume, + .driver = { + .name = "kionix", + }, +}; + + +static struct class* l_dev_class = NULL; +static struct device *l_clsdevice = NULL; +static int __init kionix_accel_init(void) +{ + //return i2c_add_driver(&kionix_accel_driver); + + int ret = 0; + struct kionix_accel_driver *acceld; + + acceld = kzalloc(sizeof(*acceld), GFP_KERNEL); + if (acceld == NULL) { + printk("%s kzalloc fail!\n", __func__); + return -ENOMEM; + } + + ret = get_axisset(acceld);// + if (ret < 0) + { + printk("%s user choose to no sensor chip!\n", __func__); + kfree(acceld); + return ret; + } + kfree(acceld); + + if (!(this_client = sensor_i2c_register_device2(0, KIONIX_ACCEL_I2C_ADDR, KIONIX_ACCEL_NAME,(void*)(&kionix_accel_pdata)))) + { + printk(KERN_EMERG"Can't register gsensor i2c device!\n"); + return -1; + } + + + if(iskionix()) + { + printk(KERN_ERR "Can't find kionix!!\n"); + sensor_i2c_unregister_device(this_client); + return -1; + } + + //ret = get_axisset(NULL); + + printk("kionix g-sensor driver init\n"); + + //spin_lock_init(&l_sensorconfig.spinlock); + l_dev_class = class_create(THIS_MODULE, KIONIX_ACCEL_NAME); + //for S40 module to judge whether insmod is ok + if (IS_ERR(l_dev_class)){ + ret = PTR_ERR(l_dev_class); + printk(KERN_ERR "Can't class_create gsensor device !!\n"); + return ret; + } + l_clsdevice = device_create(l_dev_class, NULL, MKDEV(GSENSOR_MAJOR, 0), NULL, KIONIX_ACCEL_NAME); + if (IS_ERR(l_clsdevice)){ + ret = PTR_ERR(l_clsdevice); + printk(KERN_ERR "Failed to create device %s !!!",KIONIX_ACCEL_NAME); + return ret; + } + + if((ret = platform_device_register(&kionix_pdevice))) + { + printk(KERN_ERR "%s Can't register kionix platform devcie!!!\n", __FUNCTION__); + return ret; + } + if ((ret = platform_driver_register(&kionix_driver)) != 0) + { + printk(KERN_ERR "%s Can't register kionix platform driver!!!\n", __FUNCTION__); + return ret; + } + + return 0; + +} +module_init(kionix_accel_init); + +static void __exit kionix_accel_exit(void) +{ + //i2c_del_driver(&kionix_accel_driver); + platform_driver_unregister(&kionix_driver); + platform_device_unregister(&kionix_pdevice); + + device_destroy(l_dev_class, MKDEV(GSENSOR_MAJOR, 0)); + + class_destroy(l_dev_class); + sensor_i2c_unregister_device(this_client); +} +module_exit(kionix_accel_exit); + +MODULE_DESCRIPTION("Kionix accelerometer driver"); +MODULE_AUTHOR("Kuching Tan "); +MODULE_LICENSE("GPL"); +MODULE_VERSION("3.3.0"); diff --git a/ANDROID_3.4.5/drivers/input/sensor/kionix_gsensor/kionix_accel.h b/ANDROID_3.4.5/drivers/input/sensor/kionix_gsensor/kionix_accel.h new file mode 100755 index 00000000..b7be9b8f --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/kionix_gsensor/kionix_accel.h @@ -0,0 +1,85 @@ +/* include/linux/input/kionix_accel.h - Kionix accelerometer driver + * + * Copyright (C) 2012 Kionix, Inc. + * Written by Kuching Tan + * + * 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 . + * + */ + +#ifndef __KIONIX_ACCEL_H__ +#define __KIONIX_ACCEL_H__ + +#define KIONIX_ACCEL_I2C_ADDR 0x0E +#define KIONIX_ACCEL_NAME "kionix_accel" +#define KIONIX_ACCEL_IRQ "kionix-irq" + +struct kionix_accel_platform_data { + /* Although the accelerometer can perform at high ODR, + * there is a need to keep the maximum ODR to a lower + * value due to power consumption or other concern. + * Use this variable to set the minimum allowable + * interval for data to be reported from the + * accelerometer. Unit is measured in milli- + * seconds. Recommended value is 5ms. */ + unsigned int min_interval; + /* Use this variable to set the default interval for + * data to be reported from the accelerometer. This + * value will be used during driver setup process, + * but can be changed by the system during runtime via + * sysfs control. Recommended value is 200ms.*/ + unsigned int poll_interval; + + /* This variable controls the corresponding direction + * of the accelerometer that is mounted on the board + * of the device. Refer to the porting guide for + * details. Valid value is 1 to 8. */ + u8 accel_direction; + + /* Use this variable to choose whether or not to use + * DRDY hardware interrupt mode to trigger a data + * report event instead of using software polling. + * Note that for those accelerometer model that does + * not support DRDY hardware interrupt, the driver + * will revert to software polling mode automatically. + * Valid value is 0 or 1.*/ + bool accel_irq_use_drdy; + + /* Use this variable to control the number of + * effective bits of the accelerometer output. + * Use the macro definition to select the desired + * number of effective bits. */ + #define KIONIX_ACCEL_RES_12BIT 0 + #define KIONIX_ACCEL_RES_8BIT 1 + #define KIONIX_ACCEL_RES_6BIT 2 + u8 accel_res; + + /* Use this variable to control the G range of + * the accelerometer output. Use the macro definition + * to select the desired G range.*/ + #define KIONIX_ACCEL_G_2G 0 + #define KIONIX_ACCEL_G_4G 1 + #define KIONIX_ACCEL_G_6G 2 + #define KIONIX_ACCEL_G_8G 3 + u8 accel_g_range; + + /* Optional callback functions that can be implemented + * on per product basis. If these callbacks are defined, + * they will be called by the driver. */ + int (*init)(void); + void (*exit)(void); + int (*power_on)(void); + int (*power_off)(void); +}; +#endif /* __KIONIX_ACCEL_H__ */ diff --git a/ANDROID_3.4.5/drivers/input/sensor/kxte9_gsensor/Makefile b/ANDROID_3.4.5/drivers/input/sensor/kxte9_gsensor/Makefile new file mode 100755 index 00000000..23eca917 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/kxte9_gsensor/Makefile @@ -0,0 +1,34 @@ +KERNELDIR=../../../../ +#KERNELDIR=/home/hangyan/android8850/kernel/ANDROID_3.0.8 +CROSS = arm_1103_le- +CC= $(CROSS)gcc +LD= $(CROSS)ld +STRIP = $(CROSS)strip + +DEBUG = n + +# Add your debugging flag (or not) to EXTRA_CFLAGS +ifeq ($(DEBUG),y) +# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines +DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines + +else + DEBFLAGS = -O2 -Wall +endif + +EXTRA_CFLAGS += $(DEBFLAGS) + + +MY_MODULE_NAME=s_wmt_gsensor_kxte9 + +obj-m := $(MY_MODULE_NAME).o +$(MY_MODULE_NAME)-objs := kxte9.o + +default: + $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules + $(STRIP) --strip-debug $(MY_MODULE_NAME).ko + rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions + +clean: + rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers + diff --git a/ANDROID_3.4.5/drivers/input/sensor/kxte9_gsensor/kxte9.c b/ANDROID_3.4.5/drivers/input/sensor/kxte9_gsensor/kxte9.c new file mode 100755 index 00000000..2f25a4f8 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/kxte9_gsensor/kxte9.c @@ -0,0 +1,1798 @@ +/* drivers/i2c/chips/kxte9.c - KXTE9 accelerometer driver + * + * Copyright (C) 2010 Kionix, Inc. + * Written by Kuching Tan + * + * 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 3 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 . + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include "kxte9.h" +//#include +#include + +#define NAME "kxte9" +#define G_MAX 2000 +/* OUTPUT REGISTERS */ +#define CT_RESP 0x0C +#define WHO_AM_I 0x0F +#define TILT_POS_CUR 0x10 +#define TILT_POS_PRE 0x11 +#define XOUT 0x12 +#define INT_STATUS_REG 0x16 +#define INT_SRC_REG2 0x17 +#define INT_REL 0x1A +/* CONTROL REGISTERS */ +#define CTRL_REG1 0x1B +#define CTRL_REG2 0x1C +#define CTRL_REG3 0x1D +#define INT_CTRL1 0x1E +#define INT_CTRL2 0x1F +#define TILT_TIMER 0x28 +#define WUF_TIMER 0x29 +#define B2S_TIMER 0x2A +#define WUF_THRESH 0x5A +#define B2S_THRESH 0x5B +/* CTRL_REG1 BITS */ +#define PC1_OFF 0x00 +#define PC1_ON 0x80 +/* INT_SRC_REG2 BITS */ +#define TPS 0x01 +#define WUFS 0x02 +#define B2SS 0x04 +/* Direction Mask */ +/* Used for TILT_POS_CUR, TILT_POS_PRE */ +/* INT_SRC_REG1, CTRL_REG2 */ +#define DIR_LE 0x20 +#define DIR_RI 0x10 +#define DIR_DO 0x08 +#define DIR_UP 0x04 +#define DIR_FD 0x02 +#define DIR_FU 0x01 +/* ODR MASKS */ +#define ODRM 0x18 // CTRL_REG1 +#define OWUFM 0x03 // CTRL_REG3 +#define OB2SM 0x0C // CTRL_REG3 +/* INPUT_ABS CONSTANTS */ +#define FUZZ 32 +#define FLAT 32 +/* RESUME STATE INDICES */ +#define RES_CTRL_REG1 0 +#define RES_CTRL_REG3 1 +#define RES_INT_CTRL1 2 +#define RES_TILT_TIMER 3 +#define RES_WUF_TIMER 4 +#define RES_B2S_TIMER 5 +#define RES_WUF_THRESH 6 +#define RES_B2S_THRESH 7 +#define RES_CURRENT_ODR 8 +#define RESUME_ENTRIES 9 +/* OFFSET and SENSITIVITY */ +//#define OFFSET 32 //6-bit +#define OFFSET 128 //8-bit +#define SENS 16 + +#define IOCTL_BUFFER_SIZE 64 + +//#define WM3445_A0 +//#define INT_MODE + +////////////////////////////////////////////////////////////////////////// +//#define DEBUG_WMT_GSENSOR +#ifdef DEBUG_WMT_GSENSOR +#define kxte9_dbg(fmt, args...) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__ , ## args) +//#define kxte9_dbg(fmt, args...) if (kpadall_isrundbg()) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__, ## args) +#else +#define kxte9_dbg(fmt, args...) +#endif + +#undef errlog +#undef klog +#define errlog(fmt, args...) printk(KERN_ERR "[%s]: " fmt, __FUNCTION__, ## args) +#define klog(fmt, args...) printk(KERN_DEBUG "[%s]: " fmt, __FUNCTION__, ## args) +////////////////////////////////////////////////////////////////////////// + +/* + * The following table lists the maximum appropriate poll interval for each + * available output data rate. + */ +struct { + unsigned int interval; + u8 mask; +} kxte9_odr_table[] = { + {1000, ODR1E}, + {334, ODR3E}, + {100, ODR10E}, + {25, ODR40E}, + {8, ODR125E}, +}; + +struct kxte9_data { + //struct i2c_client *client; + struct kxte9_platform_data *pdata; + struct mutex lock; + struct delayed_work input_work; + struct input_dev *input_dev; +#ifdef INT_MODE + struct work_struct irq_work; +#endif +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend earlysuspend; +#endif + int hw_initialized; + atomic_t enabled; + u8 resume[RESUME_ENTRIES]; + int i2c_xfer_complete; + int suspend; +}; + +struct gsensor_config +{ + int op; + int samp; + int xyz_axis[3][3]; // (axis,direction) + struct proc_dir_entry* sensor_proc; + int sensorlevel; + unsigned int avg_count; + unsigned int kxte9_8bit; + int name; + int bmp; + unsigned int ctraddr; + unsigned int ocaddr; + unsigned int idaddr; + unsigned int peaddr; + unsigned int pcaddr; + unsigned int itbmp; + unsigned int itaddr; + unsigned int isbmp; + unsigned int isaddr; + int irq; +}; + +static struct gsensor_config gconf = { + .op = 0, + .samp = 40, + .xyz_axis = { + {ABS_X, -1}, + {ABS_Y, 1}, + {ABS_Z, -1}, + }, + .sensor_proc = NULL, + .avg_count = 4, + .kxte9_8bit = 1, + .name = 3, +#ifdef WM3445_A0 + .bmp = 0x100, /* GPIO 8 */ + .ctraddr = GPIO_BASE_ADDR + 0x40, + .ocaddr = GPIO_BASE_ADDR + 0x80, + .idaddr = GPIO_BASE_ADDR + 0x00, + .peaddr = GPIO_BASE_ADDR + 0x480, + .pcaddr = GPIO_BASE_ADDR + 0x4c0, + .itbmp = 0x30000, /* Rising Edge */ + .itaddr = GPIO_BASE_ADDR + 0x300, + .isbmp = 0x100, + .isaddr = GPIO_BASE_ADDR + 0x304, + .irq = IRQ_GPIO8, +#else + .bmp = 0x8, /* GPIO 3 */ + .ctraddr = GPIO_BASE_ADDR + 0x40, + .ocaddr = GPIO_BASE_ADDR + 0x80, + .idaddr = GPIO_BASE_ADDR + 0x00, + .peaddr = GPIO_BASE_ADDR + 0x480, + .pcaddr = GPIO_BASE_ADDR + 0x4c0, + .itbmp = 0x83000000, /* Rising Edge */ + .itaddr = GPIO_BASE_ADDR + 0x300, + .isbmp = 0x8, + .isaddr = GPIO_BASE_ADDR + 0x320, + .irq = 5, +#endif +}; + +static struct kxte9_platform_data kxte9_pdata = { + .min_interval = 1, + .poll_interval = 100, + .ctrl_reg1_init = ODR10E & ~B2SE & ~WUFE & ~TPE, + .engine_odr_init = OB2S1 | OWUF1, + .int_ctrl_init = KXTE9_IEA, + .tilt_timer_init = 0x00, + .wuf_timer_init = 0x00, + .wuf_thresh_init = 0x20, + .b2s_timer_init = 0x00, + .b2s_thresh_init = 0x60, +}; + +#ifdef WM3445_A0 +#define SET_GPIO_GSENSOR_INT() {\ + REG32_VAL(gconf.ctraddr) &= ~gconf.bmp; \ + REG32_VAL(gconf.ocaddr) &= ~gconf.bmp; \ + REG32_VAL(gconf.peaddr) |= gconf.bmp; \ + REG32_VAL(gconf.pcaddr) &= ~gconf.bmp; \ + REG32_VAL(gconf.itaddr) |= gconf.itbmp; \ + REG32_VAL(GPIO_BASE_ADDR + 0x308) |= gconf.bmp; \ + REG32_VAL(gconf.isaddr) |= gconf.isbmp; \ +} +#define ENABLE_SENSOR_INT(enable) { \ + if (enable) \ + {\ + REG32_VAL(GPIO_BASE_ADDR + 0x308) &= ~gconf.bmp; \ + } else {\ + REG32_VAL(GPIO_BASE_ADDR + 0x308) |= gconf.bmp; \ + }\ +} + +#else +#define SET_GPIO_GSENSOR_INT() {\ + REG32_VAL(gconf.ctraddr) |= gconf.bmp; \ + REG32_VAL(gconf.ocaddr) &= ~gconf.bmp; \ + REG32_VAL(gconf.pcaddr) &= ~gconf.bmp; \ + REG32_VAL(gconf.itaddr) |= gconf.itbmp; \ + REG32_VAL(gconf.isaddr) |= gconf.isbmp; \ +} +#endif + +#define X_CONVERT(x) x*gconf.xyz_axis[ABS_X][1] +#define Y_CONVERT(y) y*gconf.xyz_axis[ABS_Y][1] +#define Z_CONVERT(z) z*gconf.xyz_axis[ABS_Z][1] + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void kxte9_early_suspend(struct early_suspend *h); +static void kxte9_late_resume(struct early_suspend *h); +#endif + +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); +//extern int wmt_i2c_xfer_continue_if_4(struct i2c_msg *msg, unsigned int num, int bus_id); +extern int i2c_api_do_send(int bus_id, char chip_addr, char sub_addr, char *buf, unsigned int size); +extern int i2c_api_do_recv(int bus_id, char chip_addr, char sub_addr, char *buf, unsigned int size); +extern unsigned int wmt_read_oscr(void); + +static struct kxte9_data *te9 = NULL; +static atomic_t kxte9_dev_open_count; +static struct kobject *android_gsensor_kobj = NULL; +static void kxte9_read_callback(void *data); +struct i2c_msg *kxte9_msg; +unsigned char *i2c_read_buf; +unsigned char *i2c_write_buf; +static struct timer_list kxte9_timer; +static unsigned char *x_count; +static unsigned char *y_count; +static unsigned char *z_count; +static unsigned int x_total = 0, y_total = 0, z_total = 0; +static unsigned int xyz_index = 0; + +static int wait_i2c_xfer_complete(void) +{ + unsigned int now_time = 0; + unsigned int delay_time = 0; + + now_time = wmt_read_oscr(); + while (!te9->i2c_xfer_complete) { + delay_time = wmt_read_oscr() - now_time; + if (delay_time > 60000) {//20ms + printk(KERN_WARNING "[kxte9] transfer timeout!\n"); + return 0; + } + } + return 1; +} + +static void kxte9_read_callback(void *data) +{ + int xyz[3]; + + if (te9->suspend) { + te9->i2c_xfer_complete = 1; + return; + } + if (xyz_index >= gconf.avg_count) + xyz_index = 0; + x_total -= x_count[xyz_index]; + y_total -= y_count[xyz_index]; + z_total -= z_count[xyz_index]; + if (gconf.kxte9_8bit) { + x_count[xyz_index] = i2c_read_buf[0]; + y_count[xyz_index] = i2c_read_buf[1]; + z_count[xyz_index] = i2c_read_buf[2]; + } else { + x_count[xyz_index] = i2c_read_buf[0] & ~0x03; + y_count[xyz_index] = i2c_read_buf[1] & ~0x03; + z_count[xyz_index] = i2c_read_buf[2] & ~0x03; + } + x_total += x_count[xyz_index]; + y_total += y_count[xyz_index]; + z_total += z_count[xyz_index]; + xyz[ABS_X] = (x_total/gconf.avg_count - OFFSET) << 4; + xyz[ABS_Y] = (y_total/gconf.avg_count - OFFSET) << 4; + xyz[ABS_Z] = (z_total/gconf.avg_count - OFFSET) << 4; + //printk(KERN_DEBUG " [%d] x:%d y:%d z:%d\n", xyz_index, x_count[xyz_index], y_count[xyz_index], z_count[xyz_index]); + //printk(KERN_DEBUG " total x:%d y:%d z:%d\n", x_total, y_total, z_total); + //printk(KERN_DEBUG " avg x:%d y:%d z:%d\n", x_total/gconf.avg_count, y_total/gconf.avg_count, z_total/gconf.avg_count); + //printk(KERN_DEBUG "report x:%d y:%d z:%d\n", xyz[ABS_X], xyz[ABS_Y], xyz[ABS_Z]); + xyz_index++; + input_report_abs(te9->input_dev, ABS_X, X_CONVERT(xyz[gconf.xyz_axis[ABS_X][0]])); + input_report_abs(te9->input_dev, ABS_Y, Y_CONVERT(xyz[gconf.xyz_axis[ABS_Y][0]])); + input_report_abs(te9->input_dev, ABS_Z, Z_CONVERT(xyz[gconf.xyz_axis[ABS_Z][0]])); + input_sync(te9->input_dev); + te9->i2c_xfer_complete = 1; + mod_timer(&kxte9_timer, jiffies + msecs_to_jiffies(te9->pdata->poll_interval)); +} + +static void kxte9_read_data(u8 addr, int len) +{ + i2c_write_buf[0] = addr; + kxte9_msg[0].addr = KXTE9_I2C_ADDR; + kxte9_msg[0].flags = 0 ; + kxte9_msg[0].len = 1; + kxte9_msg[0].buf = i2c_write_buf; + kxte9_msg[1].addr = KXTE9_I2C_ADDR; + kxte9_msg[1].flags = I2C_M_RD; + kxte9_msg[1].len = len; + kxte9_msg[1].buf = i2c_read_buf; + wmt_i2c_transfer(kxte9_msg, 2, 0, kxte9_read_callback, 0); +} + +static int kxte9_i2c_read(u8 addr, u8 *data, int len) +{ +/* + int err; + + struct i2c_msg msgs[] = { + { + .addr = KXTE9_I2C_ADDR, + .flags = 0 & ~(I2C_M_RD), //te9->client->flags & I2C_M_TEN, + .len = 1, + .buf = &addr, + }, + { + .addr = KXTE9_I2C_ADDR, //te9->client->addr, + .flags = (I2C_M_RD), //(te9->client->flags & I2C_M_TEN) | I2C_M_RD, + .len = len, + .buf = data, + }, + }; + err = wmt_i2c_xfer_continue_if_4(msgs, 2, 0); + + if(err != 2) + errlog("read transfer error\n"); + else + err = 0; + + return err; +*/ + int ret; + ret = i2c_api_do_recv(0, KXTE9_I2C_ADDR, addr, data, len); + if (ret <= 0) { + errlog("i2c_api_do_recv error!\n"); + return -1; + } + return 0; +} + +static int kxte9_i2c_write(u8 addr, u8 *data, int len) +{ +/* + int err; + int i; + u8 buf[len + 1]; + + struct i2c_msg msgs[] = { + { + .addr = KXTE9_I2C_ADDR, //te9->client->addr, + .flags = 0 & ~(I2C_M_RD), //te9->client->flags & I2C_M_TEN, + .len = len + 1, + .buf = buf, + }, + }; + + buf[0] = addr; + for (i = 0; i < len; i++) + buf[i + 1] = data[i]; + + err = wmt_i2c_xfer_continue_if_4(msgs, 1, 0); + if(err != 1) + errlog("write transfer error\n"); + else + err = 0; + return err; +*/ + int ret; + ret = i2c_api_do_send(0, KXTE9_I2C_ADDR, addr, data, len); + if (ret <= 0) { + errlog("i2c_api_do_send error!\n"); + return -1; + } + return 0; + +} + +int kxte9_get_bits(u8 reg_addr, u8* bits_value, u8 bits_mask) +{ + int err; + u8 reg_data; + + err = kxte9_i2c_read(reg_addr, ®_data, 1); + kxte9_dbg("kxte9_i2c_read(%x, 1)=%x, err=%d\n", reg_addr, reg_data, err); + if(err < 0) + return err; + + *bits_value = reg_data & bits_mask; + + return 1; +} + +int kxte9_get_byte(u8 reg_addr, u8* reg_value) +{ + int err; + u8 reg_data; + + err = kxte9_i2c_read(reg_addr, ®_data, 1); + kxte9_dbg("kxte9_i2c_read(%x, 1)=%x, err=%d\n", reg_addr, reg_data, err); + if(err < 0) + return err; + + *reg_value = reg_data; + + return 1; +} + +int kxte9_set_bits(int res_index, u8 reg_addr, u8 bits_value, u8 bits_mask) +{ + int err=0, err1=0, retval=0; + u8 reg_data = 0x00, reg_bits = 0x00, bits_set = 0x00; + + // Turn off PC1 + reg_data = te9->resume[RES_CTRL_REG1] & ~PC1_ON; + + err = kxte9_i2c_write(CTRL_REG1, ®_data, 1); + kxte9_dbg("kxte9_i2c_write(%x, %x, 1), err=%d\n", CTRL_REG1, reg_data, err); + if(err < 0) + goto exit0; + + // Read from device register + err = kxte9_i2c_read(reg_addr, ®_data, 1); + kxte9_dbg("kxte9_i2c_read(%x, 1)=%x, err=%d\n", reg_addr, reg_data, err); + if(err < 0) + goto exit0; + + // Apply mask to device register; + reg_bits = reg_data & bits_mask; + + // Update resume state data + bits_set = bits_mask & bits_value; + te9->resume[res_index] &= ~bits_mask; + te9->resume[res_index] |= bits_set; + + // Return 0 if value in device register and value to be written is the same + if(reg_bits == bits_set) + retval = 0; + // Else, return 1 + else + retval = 1; + + // Write to device register + err = kxte9_i2c_write(reg_addr, &te9->resume[res_index], 1); + kxte9_dbg("kxte9_i2c_write(%x, %x, 1), err=%d\n", reg_addr, te9->resume[res_index], err); + if(err < 0) + goto exit0; + +exit0: + // Turn on PC1 + reg_data = te9->resume[RES_CTRL_REG1] | PC1_ON; + + err1 = kxte9_i2c_write(CTRL_REG1, ®_data, 1); + kxte9_dbg("kxte9_i2c_write(%x, %x, 1), err=%d\n", CTRL_REG1, reg_data, err); + if(err1 < 0) + return err1; + + if(err < 0) + return err; + + return retval; +} + +int kxte9_set_byte(int res_index, u8 reg_addr, u8 reg_value) +{ + int err, err1, retval=0; + u8 reg_data; + + // Turn off PC1 + reg_data = te9->resume[RES_CTRL_REG1] & ~PC1_ON; + + err = kxte9_i2c_write(CTRL_REG1, ®_data, 1); + kxte9_dbg("kxte9_i2c_write(%x, %x, 1), err=%d\n", CTRL_REG1, reg_data, err); + if(err < 0) + goto exit0; + + // Read from device register + err = kxte9_i2c_read(reg_addr, ®_data, 1); + kxte9_dbg("kxte9_i2c_read(%x, 1)=%x, err=%d\n", reg_addr, reg_data, err); + if(err < 0) + goto exit0; + + // Update resume state data + te9->resume[res_index] = reg_value; + + // Return 0 if value in device register and value to be written is the same + if(reg_data == reg_value) + retval = 0; + // Else, return 1 + else + retval = 1; + + // Write to device register + err = kxte9_i2c_write(reg_addr, &te9->resume[res_index], 1); + kxte9_dbg("kxte9_i2c_write(%x, %x, 1), err=%d\n", reg_addr, te9->resume[res_index], err); + if(err < 0) + goto exit0; + +exit0: + // Turn on PC1 + reg_data = te9->resume[RES_CTRL_REG1] | PC1_ON; + err1 = kxte9_i2c_write(CTRL_REG1, ®_data, 1); + kxte9_dbg("kxte9_i2c_write(%x, %x, 1), err=%d\n", CTRL_REG1, reg_data, err); + if(err1 < 0) + return err1; + + if(err < 0) + return err; + + return retval; +} + +int kxte9_set_pc1_off(void) +{ + u8 reg_data; + + reg_data = te9->resume[RES_CTRL_REG1] & ~PC1_ON; + + kxte9_dbg("kxte9_i2c_write(%x, %x, 1)\n", CTRL_REG1, reg_data); + return kxte9_i2c_write(CTRL_REG1, ®_data, 1); +} + +int kxte9_set_pc1_on(void) +{ + u8 reg_data; + + reg_data = te9->resume[RES_CTRL_REG1] | PC1_ON; + + kxte9_dbg("kxte9_i2c_write(%x, %x, 1)\n", CTRL_REG1, reg_data); + return kxte9_i2c_write(CTRL_REG1, ®_data, 1); +} + +static int kxte9_verify(void) +{ + int err; + u8 buf; + + err = kxte9_i2c_read(WHO_AM_I, &buf, 1); + kxte9_dbg("kxte9_i2c_read(%x, 1)=%x, err=%d\n", WHO_AM_I, buf, err); + if(err < 0) + errlog( "read err int source\n"); + if(buf != 0) + err = -1; + return err; +} + +static int kxte9_hw_init(void) +{ + int err; + u8 buf = PC1_OFF; + + err = kxte9_i2c_write(CTRL_REG1, &buf, 1); + kxte9_dbg("kxte9_i2c_write(%x, %x, 1), err=%d\n", CTRL_REG1, buf, err); + if(err < 0) + return err; + err = kxte9_i2c_write(CTRL_REG3, &te9->resume[RES_CTRL_REG3], 1); + kxte9_dbg("kxte9_i2c_write(%x, %x, 1), err=%d\n", CTRL_REG3, te9->resume[RES_CTRL_REG3], err); + if(err < 0) + return err; + err = kxte9_i2c_write(INT_CTRL1, &te9->resume[RES_INT_CTRL1], 1); + kxte9_dbg("kxte9_i2c_write(%x, %x, 1), err=%d\n", INT_CTRL1, te9->resume[RES_INT_CTRL1], err); + if(err < 0) + return err; + err = kxte9_i2c_write(TILT_TIMER, &te9->resume[RES_TILT_TIMER], 1); + kxte9_dbg("kxte9_i2c_write(%x, %x, 1), err=%d\n", TILT_TIMER, te9->resume[RES_TILT_TIMER], err); + if(err < 0) + return err; + err = kxte9_i2c_write(WUF_TIMER, &te9->resume[RES_WUF_TIMER], 1); + kxte9_dbg("kxte9_i2c_write(%x, %x, 1), err=%d\n", WUF_TIMER, te9->resume[RES_WUF_TIMER], err); + if(err < 0) + return err; + err = kxte9_i2c_write(B2S_TIMER, &te9->resume[RES_B2S_TIMER], 1); + kxte9_dbg("kxte9_i2c_write(%x, %x, 1), err=%d\n", B2S_TIMER, te9->resume[RES_B2S_TIMER], err); + if(err < 0) + return err; + err = kxte9_i2c_write(WUF_THRESH, &te9->resume[RES_WUF_THRESH], 1); + kxte9_dbg("kxte9_i2c_write(%x, %x, 1), err=%d\n", WUF_THRESH, te9->resume[RES_WUF_THRESH], err); + if(err < 0) + return err; + err = kxte9_i2c_write(B2S_THRESH, &te9->resume[RES_B2S_THRESH], 1); + kxte9_dbg("kxte9_i2c_write(%x, %x, 1), err=%d\n", B2S_THRESH, te9->resume[RES_B2S_THRESH], err); + if(err < 0) + return err; + buf = te9->resume[RES_CTRL_REG1] | PC1_ON; + err = kxte9_i2c_write(CTRL_REG1, &buf, 1); + kxte9_dbg("kxte9_i2c_write(%x, %x, 1), err=%d\n", CTRL_REG1, buf, err); + if(err < 0) + return err; + + te9->resume[RES_CTRL_REG1] = buf; + te9->hw_initialized = 1; + + return 0; +} + +static void kxte9_device_power_off(void) +{ + int err; + u8 buf = PC1_OFF; + + err = kxte9_i2c_write(CTRL_REG1, &buf, 1); + kxte9_dbg("kxte9_i2c_write(%x, %x, 1), err=%d\n", CTRL_REG1, buf, err); + if(err < 0) + errlog("soft power off failed\n"); +#ifdef INT_MODE + ENABLE_SENSOR_INT(0); +// disable_irq(gconf.irq); +#endif + te9->hw_initialized = 0; +} + +static int kxte9_device_power_on(void) +{ + int err; + + if(!te9->hw_initialized) { + //mdelay(110); + err = kxte9_hw_init(); + if(err < 0) { + kxte9_device_power_off(); + return err; + } + } +#ifdef INT_MODE + ENABLE_SENSOR_INT(1); +// enable_irq(gconf.irq); +#endif + return 0; +} + +static u8 kxte9_resolve_dir(u8 dir) +{ + switch (dir) { + case 0x20: /* -X */ + if (gconf.xyz_axis[ABS_X][1] < 0) + dir = 0x10; + if (gconf.xyz_axis[ABS_Y][0] == 0) + dir >>= 2; + if (gconf.xyz_axis[ABS_Z][0] == 0) + dir >>= 4; + break; + case 0x10: /* +X */ + if (gconf.xyz_axis[ABS_X][1] < 0) + dir = 0x20; + if (gconf.xyz_axis[ABS_Y][0] == 0) + dir >>= 2; + if (gconf.xyz_axis[ABS_Z][0] == 0) + dir >>= 4; + break; + case 0x08: /* -Y */ + if (gconf.xyz_axis[ABS_Y][1] < 0) + dir = 0x04; + if (gconf.xyz_axis[ABS_X][0] == 1) + dir <<= 2; + if (gconf.xyz_axis[ABS_Z][0] == 1) + dir >>= 2; + break; + case 0x04: /* +Y */ + if (gconf.xyz_axis[ABS_Y][1] < 0) + dir = 0x08; + if (gconf.xyz_axis[ABS_X][0] == 1) + dir <<= 2; + if (gconf.xyz_axis[ABS_Z][0] == 1) + dir >>= 2; + break; + case 0x02: /* -Z */ + if (gconf.xyz_axis[ABS_Z][1] < 0) + dir = 0x01; + if (gconf.xyz_axis[ABS_X][0] == 2) + dir <<= 4; + if (gconf.xyz_axis[ABS_Y][0] == 2) + dir <<= 2; + break; + case 0x01: /* +Z */ + if (gconf.xyz_axis[ABS_Z][1] < 0) + dir = 0x02; + if (gconf.xyz_axis[ABS_X][0] == 2) + dir <<= 4; + if (gconf.xyz_axis[ABS_Y][0] == 2) + dir <<= 2; + break; + default: + return -EINVAL; + } + + return dir; +} + +#ifdef INT_MODE +static void kxte9_irq_work_func(struct work_struct *work) +{ +/* + * int_status output: + * [INT_SRC_REG1][INT_SRC_REG2][TILT_POS_PRE][TILT_POS_CUR] + * INT_SRC_REG2, TILT_POS_PRE, and TILT_POS_CUR directions are translated + * based on platform data variables. + */ + + int err; + int i; + int int_status = 0; + u8 status; + u8 b2s_comp; + u8 wuf_comp; + u8 buf[2]; + + err = kxte9_i2c_read(INT_STATUS_REG, &status, 1); + kxte9_dbg("kxte9_i2c_read(%x, 1)=%x, err=%d\n", INT_STATUS_REG, status, err); + if(err < 0) + errlog("read err int source\n"); + int_status = status << 24; + if((status & TPS) > 0) { + err = kxte9_i2c_read(TILT_POS_CUR, buf, 2); + kxte9_dbg("kxte9_i2c_read(%x, 2)=%x,%x, err=%d\n", TILT_POS_CUR, buf[0], buf[1], err); + if(err < 0) + errlog("read err tilt dir\n"); + int_status |= kxte9_resolve_dir(buf[0]); + int_status |= (kxte9_resolve_dir(buf[1])) << 8; + kxte9_dbg("IRQ TILT [%x]\n", kxte9_resolve_dir(buf[0])); + } + if((status & WUFS) > 0) { + kxte9_dbg("for WUFS\n"); + err = kxte9_i2c_read(INT_SRC_REG2, buf, 1); + kxte9_dbg("kxte9_i2c_read(%x, 1)=%x, err=%d\n", INT_SRC_REG2, buf[0], err); + if(err < 0) + kxte9_dbg("reading err wuf dir\n"); + int_status |= (kxte9_resolve_dir(buf[0])) << 16; + b2s_comp = (te9->resume[RES_CTRL_REG3] & 0x0C) >> 2; + wuf_comp = te9->resume[RES_CTRL_REG3] & 0x03; + if(!te9->resume[RES_CURRENT_ODR] && + !(te9->resume[RES_CTRL_REG1] & ODR125E) && + !(b2s_comp & wuf_comp)) { + /* set the new poll interval based on wuf odr */ + for (i = 0; i < ARRAY_SIZE(kxte9_odr_table); i++) { + if(kxte9_odr_table[i].mask == wuf_comp << 3) { + te9->pdata->poll_interval = kxte9_odr_table[i].interval; + break; + } + } + if(te9->input_dev) { + cancel_delayed_work_sync(&te9->input_work); + schedule_delayed_work(&te9->input_work, + msecs_to_jiffies(te9->pdata->poll_interval)); + } + } + } + if((status & B2SS) > 0) { + kxte9_dbg("fro B2SS\n"); + b2s_comp = (te9->resume[RES_CTRL_REG3] & 0x0C) >> 2; + wuf_comp = te9->resume[RES_CTRL_REG3] & 0x03; + if(!te9->resume[RES_CURRENT_ODR] && + !(te9->resume[RES_CTRL_REG1] & ODR125E) && + !(b2s_comp & wuf_comp)) { + /* set the new poll interval based on b2s odr */ + for (i = 1; i < ARRAY_SIZE(kxte9_odr_table); i++) { + if(kxte9_odr_table[i].mask == b2s_comp << 3) { + te9->pdata->poll_interval = kxte9_odr_table[i].interval; + break; + } + } + if(te9->input_dev) { + cancel_delayed_work_sync(&te9->input_work); + schedule_delayed_work(&te9->input_work, + msecs_to_jiffies(te9->pdata->poll_interval)); + } + } + } + input_report_abs(te9->input_dev, ABS_MISC, int_status); + input_sync(te9->input_dev); + err = kxte9_i2c_read(INT_REL, buf, 1); + kxte9_dbg("kxte9_i2c_read(%x, 1)=%x, err=%d\n", INT_REL, buf[0], err); + if(err < 0) + errlog("error clearing interrupt\n"); + //enable_irq(gconf.irq); +} + +static irqreturn_t kxte9_isr(int irq, void *dev) +{ + unsigned int status = REG32_VAL(gconf.isaddr); + + // clr int status ...?? + if ((status & gconf.isbmp) != 0) + { + kxte9_dbg("\n"); + REG32_VAL(gconf.isaddr) |= gconf.isbmp; + udelay(5); + // disable int and satrt irq work + disable_irq_nosync(irq); + schedule_work(&te9->irq_work); + return IRQ_HANDLED; + } + return IRQ_NONE; +} +#endif + +static int kxte9_update_odr(int poll_interval) +{ + int err = -1; + int i; + u8 config; + + /* Convert the poll interval into an output data rate configuration + * that is as low as possible. The ordering of these checks must be + * maintained due to the cascading cut off values - poll intervals are + * checked from shortest to longest. At each check, if the next lower + * ODR cannot support the current poll interval, we stop searching */ + for (i = 0; i < ARRAY_SIZE(kxte9_odr_table); i++) { + config = kxte9_odr_table[i].mask; + if(poll_interval >= kxte9_odr_table[i].interval) + break; + } + + config |= (te9->resume[RES_CTRL_REG1] & ~(ODR40E | ODR125E)); + te9->resume[RES_CTRL_REG1] = config; + if(atomic_read(&te9->enabled)) { + err = kxte9_set_byte(RES_CTRL_REG1, CTRL_REG1, config); + if(err < 0) + return err; + } + klog("Set new ODR to 0x%02X\n", config); + return 0; +} + +static void kxte9_input_work_func(unsigned long unused) +{ + //mutex_lock(&te9->lock); + if (te9->suspend) + return; + if (te9->i2c_xfer_complete) { + te9->i2c_xfer_complete = 0; + kxte9_read_data(XOUT, 3); + } + //mutex_unlock(&te9->lock); +} + +static int kxte9_enable(void) +{ + int err; + int int_status = 0; + u8 buf; + + if(!atomic_cmpxchg(&te9->enabled, 0, 1)) { + err = kxte9_device_power_on(); + err = kxte9_i2c_read(INT_REL, &buf, 1); + kxte9_dbg("kxte9_i2c_read(%x, 1)=%x, err=%d\n", INT_REL, buf, err); + if(err < 0) { + errlog("error clearing interrupt: %d\n", err); + atomic_set(&te9->enabled, 0); + return err; + } + if((te9->resume[RES_CTRL_REG1] & TPS) > 0) { + err = kxte9_i2c_read(TILT_POS_CUR, &buf, 1); + kxte9_dbg("kxte9_i2c_read(%x, 1)=%x, err=%d\n", TILT_POS_CUR, buf, err); + if(err < 0) + errlog("kxte9 error reading current tilt\n"); + int_status |= kxte9_resolve_dir(buf); + input_report_abs(te9->input_dev, ABS_MISC, int_status); + input_sync(te9->input_dev); + } + kxte9_msg = kzalloc(2*sizeof(struct i2c_msg), GFP_ATOMIC); + i2c_read_buf = kzalloc(3*sizeof(unsigned char), GFP_ATOMIC); + i2c_write_buf = kzalloc(sizeof(char), GFP_ATOMIC); + setup_timer(&kxte9_timer, kxte9_input_work_func, 0); + mod_timer(&kxte9_timer, jiffies + msecs_to_jiffies(te9->pdata->poll_interval)); + kxte9_dbg("Enabled\n"); + } + return 0; +} + +static int kxte9_disable(void) +{ + if(atomic_cmpxchg(&te9->enabled, 1, 0)) { + del_timer_sync(&kxte9_timer); + wait_i2c_xfer_complete(); + kfree(kxte9_msg); + kfree(i2c_read_buf); + kfree(i2c_write_buf); +#ifdef WM3445_A0 + ENABLE_SENSOR_INT(1); +#endif + kxte9_device_power_off(); + kxte9_dbg(" Disabled\n"); + //#endif + } + return 0; +} + +int kxte9_input_open(struct input_dev *input) +{ + kxte9_dbg("\n"); + return kxte9_enable(); +} + +void kxte9_input_close(struct input_dev *dev) +{ + kxte9_dbg("\n"); + kxte9_disable(); +} + +static int kxte9_input_init(void) +{ + int err; + + te9->input_dev = input_allocate_device(); + if(!te9->input_dev) { + err = -ENOMEM; + errlog("input device allocate failed\n"); + goto err0; + } + te9->input_dev->open = kxte9_input_open; + te9->input_dev->close = kxte9_input_close; + + input_set_drvdata(te9->input_dev, te9); + + set_bit(EV_ABS, te9->input_dev->evbit); + set_bit(ABS_MISC, te9->input_dev->absbit); + + input_set_abs_params(te9->input_dev, ABS_X, -G_MAX, G_MAX, FUZZ, FLAT); + input_set_abs_params(te9->input_dev, ABS_Y, -G_MAX, G_MAX, FUZZ, FLAT); + input_set_abs_params(te9->input_dev, ABS_Z, -G_MAX, G_MAX, FUZZ, FLAT); + + te9->input_dev->name = INPUT_NAME_ACC; + + err = input_register_device(te9->input_dev); + if(err) { + errlog("unable to register input polled device %s: %d\n", + te9->input_dev->name, err); + goto err1; + } + + return 0; +err1: + input_free_device(te9->input_dev); +err0: + return err; +} + +static void kxte9_input_cleanup(void) +{ + input_unregister_device(te9->input_dev); +} + +/* sysfs */ +static ssize_t kxte9_delay_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", te9->pdata->poll_interval); +} + +static ssize_t kxte9_delay_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int val = simple_strtoul(buf, NULL, 10); + u8 ctrl; + + te9->pdata->poll_interval = max(val, te9->pdata->min_interval); + kxte9_update_odr(te9->pdata->poll_interval); + ctrl = te9->resume[RES_CTRL_REG1] & 0x18; + te9->resume[RES_CURRENT_ODR] = ctrl; + /* All ODRs are changed when this method is used. */ + ctrl = (ctrl >> 1) | (ctrl >> 3); + kxte9_i2c_write(CTRL_REG3, &ctrl, 1); + kxte9_dbg("kxte9_i2c_write(%x, %x, 1)\n", CTRL_REG3, ctrl); + te9->resume[RES_CTRL_REG3] = ctrl; + return count; +} + +static ssize_t kxte9_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", atomic_read(&te9->enabled)); +} + +static ssize_t kxte9_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int val = simple_strtoul(buf, NULL, 10); + if(val) + kxte9_enable(); + else + kxte9_disable(); + return count; +} + +static ssize_t kxte9_tilt_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 tilt; + + if(te9->resume[RES_CTRL_REG1] & TPE) { + kxte9_i2c_read(TILT_POS_CUR, &tilt, 1); + kxte9_dbg("kxte9_i2c_read(%x, 1)=%x\n", TILT_POS_CUR, tilt); + return sprintf(buf, "%d\n", kxte9_resolve_dir(tilt)); + } else { + return sprintf(buf, "%d\n", 0); + } +} + +static ssize_t kxte9_tilt_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int val = simple_strtoul(buf, NULL, 10); + u8 ctrl; + if(val) + te9->resume[RES_CTRL_REG1] |= TPE; + else + te9->resume[RES_CTRL_REG1] &= (~TPE); + ctrl = te9->resume[RES_CTRL_REG1]; + kxte9_i2c_write(CTRL_REG1, &ctrl, 1); + kxte9_dbg("kxte9_i2c_write(%x, %x, 1)\n", CTRL_REG1, ctrl); + return count; +} + +static ssize_t kxte9_wake_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 val = te9->resume[RES_CTRL_REG1] & WUFE; + if(val) + return sprintf(buf, "%d\n", 1); + else + return sprintf(buf, "%d\n", 0); +} + +static ssize_t kxte9_wake_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int val = simple_strtoul(buf, NULL, 10); + u8 ctrl; + if(val) + te9->resume[RES_CTRL_REG1] |= (WUFE | B2SE); + else + te9->resume[RES_CTRL_REG1] &= (~WUFE & ~B2SE); + ctrl = te9->resume[RES_CTRL_REG1]; + kxte9_i2c_write(CTRL_REG1, &ctrl, 1); + kxte9_dbg("kxte9_i2c_write(%x, %x, 1)\n", CTRL_REG1, ctrl); + return count; +} + +static ssize_t kxte9_selftest_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int val = simple_strtoul(buf, NULL, 10); + u8 ctrl = 0x00; + if(val) + ctrl = 0xCA; + kxte9_i2c_write(0x3A, &ctrl, 1); + kxte9_dbg("kxte9_i2c_write(0x3A, %x, 1)\n", ctrl); + return count; +} + +static DEVICE_ATTR(delay, S_IRUGO|S_IWUSR, kxte9_delay_show, kxte9_delay_store); +static DEVICE_ATTR(enable, S_IRUGO|S_IWUSR, kxte9_enable_show, + kxte9_enable_store); +static DEVICE_ATTR(tilt, S_IRUGO|S_IWUSR, kxte9_tilt_show, kxte9_tilt_store); +static DEVICE_ATTR(wake, S_IRUGO|S_IWUSR, kxte9_wake_show, kxte9_wake_store); +static DEVICE_ATTR(selftest, S_IWUSR, NULL, kxte9_selftest_store); + +static struct attribute *kxte9_attributes[] = { + &dev_attr_delay.attr, + &dev_attr_enable.attr, + &dev_attr_tilt.attr, + &dev_attr_wake.attr, + &dev_attr_selftest.attr, + NULL +}; + +static struct attribute_group kxte9_attribute_group = { + .attrs = kxte9_attributes +}; +/* /sysfs */ + +static int kxte9_get_count(char *buf, int bufsize) +{ + const char ACC_REG_SIZE = 3; + int err; + /* Data bytes from hardware xL, xH, yL, yH, zL, zH */ + u8 acc_data[ACC_REG_SIZE]; + /* x,y,z hardware values */ + int xyz[3]; + + if((!buf)||(bufsize<=(sizeof(xyz)*3))) + return -1; + + err = kxte9_i2c_read(XOUT, acc_data, ACC_REG_SIZE); + kxte9_dbg("kxte9_i2c_read(%x, %x)=%x,%x,%x, err=%d\n", XOUT, ACC_REG_SIZE, + acc_data[0], acc_data[1], acc_data[2], err); + if(err < 0) + return err; + + sprintf(buf, "%d %d %d", acc_data[0], acc_data[1], acc_data[2]); + + return err; +} + +static int kxte9_get_mg(char *buf, int bufsize) +{ + const char ACC_REG_SIZE = 3; + int err; + /* Data bytes from hardware xL, xH, yL, yH, zL, zH */ + u8 acc_data[ACC_REG_SIZE]; + /* x,y,z hardware values */ + int xyz[3], mg[3]; + + if((!buf)||(bufsize<=(sizeof(mg)))) + return -1; + + err = kxte9_i2c_read(XOUT, acc_data, ACC_REG_SIZE); + kxte9_dbg("kxte9_i2c_read(%x, %x)=%x,%x,%x, err=%x\n", XOUT, ACC_REG_SIZE, + acc_data[0], acc_data[1], acc_data[2], err); + if(err < 0) + return err; + + xyz[0] = ((int)(acc_data[0]) - OFFSET) << 4; + xyz[1] = ((int)(acc_data[1]) - OFFSET) << 4; + xyz[2] = ((int)(acc_data[2]) - OFFSET) << 4; + + mg[0] = X_CONVERT(xyz[gconf.xyz_axis[ABS_X][0]]); + mg[1] = Y_CONVERT(xyz[gconf.xyz_axis[ABS_Y][0]]); + mg[2] = Z_CONVERT(xyz[gconf.xyz_axis[ABS_Z][0]]); + + sprintf(buf, "%d %d %d",mg[0], mg[1], mg[2]); + + kxte9_dbg(" [%5d] [%5d] [%5d]\n", mg[0], mg[1], mg[2]); + + return err; +} + +static void kxte9_dump_reg(void) +{ + u8 regval = 0; + + klog("**********************kxte9 reg val***************\n"); + // ct_resp + kxte9_i2c_read(CT_RESP, ®val, 1); + klog("ct_resp:0x%x\n", regval); + // who_am_i + kxte9_i2c_read(WHO_AM_I, ®val, 1); + klog("who_am_i:0x%x\n", regval); + // tilt_pos_cur + kxte9_i2c_read(TILT_POS_CUR, ®val, 1); + klog("tilt_pos_cur:0x%x\n", regval); + // int_src_reg1 + kxte9_i2c_read(INT_STATUS_REG, ®val, 1); + klog("int_src_reg1:0x%x\n", regval); + // int_src_reg2 + kxte9_i2c_read(INT_SRC_REG2, ®val, 1); + klog("int_src_reg2:0x%x\n", regval); + // status_reg + kxte9_i2c_read(0x18, ®val, 1); + klog("status_reg:0x%x\n", regval); + // int_rel + kxte9_i2c_read(INT_REL, ®val, 1); + klog("int_rel:0x%x\n", regval); + // ctrl_reg1 + kxte9_i2c_read(CTRL_REG1, ®val, 1); + klog("ctrl_reg1:0x%x\n", regval); + // ctrl_reg2 + kxte9_i2c_read(CTRL_REG2, ®val, 1); + klog("ctrl_reg2:0x%x\n", regval); + // ctrl_reg3 + kxte9_i2c_read(CTRL_REG3, ®val, 1); + klog("ctrl_reg3:0x%x\n", regval); + // int_ctrl_reg1 + kxte9_i2c_read(INT_CTRL1, ®val, 1); + klog("int_ctrl_reg1:0x%x\n", regval); + // int_ctrl_reg2 + kxte9_i2c_read(0x1F, ®val, 1); + klog("int_ctrl_reg2:0x%x\n", regval); + // tilt_timer + kxte9_i2c_read(TILT_TIMER, ®val, 1); + klog("tilt_timer:0x%x\n", regval); + // wuf_timer + kxte9_i2c_read(WUF_TIMER, ®val, 1); + klog("wuf_timer:0x%x\n", regval); + // b2s_timer + kxte9_i2c_read(B2S_TIMER, ®val, 1); + klog("b2s_timer:0x%x\n", regval); + // wuf_thresh + kxte9_i2c_read(WUF_THRESH, ®val, 1); + klog("wuf_thresh:0x%x\n", regval); + // b2s_thresh + kxte9_i2c_read(B2S_THRESH, ®val, 1); + klog("b2s_thresh:0x%x\n", regval); + // tilt_angle + kxte9_i2c_read(0x5c, ®val, 1); + klog("tilt_angle:0x%x\n", regval); + // hyst_set + kxte9_i2c_read(0x5f, ®val, 1); + klog("hyst_set:0x%x\n", regval); + klog("**********************************************************"); +} + +static int kxte9_open(struct inode *inode, struct file *file) +{ + int ret = -1; + + if(kxte9_enable() < 0) + return ret; + + atomic_inc(&kxte9_dev_open_count); + kxte9_dbg("opened %d times\n",\ + atomic_read(&kxte9_dev_open_count)); + kxte9_dump_reg(); + return 0; +} + +static int kxte9_release(struct inode *inode, struct file *file) +{ + int open_count; + + atomic_dec(&kxte9_dev_open_count); + open_count = (int)atomic_read(&kxte9_dev_open_count); + + if(open_count == 0) + kxte9_disable(); + + kxte9_dbg("opened %d times\n",\ + atomic_read(&kxte9_dev_open_count)); + return 0; +} + +static int kxte9_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + char buffer[IOCTL_BUFFER_SIZE]; + void __user *data; + u8 reg_buffer = 0x00; + const u8 set = 0xFF, unset = 0x00; + int retval=0, val_int=0; + short val_short=0; + + switch (cmd) { + case KXTE9_IOCTL_GET_COUNT: + data = (void __user *) arg; + if(data == NULL){ + retval = -EFAULT; + goto err_out; + } + retval = kxte9_get_count(buffer, sizeof(buffer)); + if(retval < 0) + goto err_out; + + if(copy_to_user(data, buffer, sizeof(buffer))) { + retval = -EFAULT; + goto err_out; + } + break; + + case KXTE9_IOCTL_GET_MG: + data = (void __user *) arg; + if(data == NULL){ + retval = -EFAULT; + goto err_out; + } + retval = kxte9_get_mg(buffer, sizeof(buffer)); + if(retval < 0) + goto err_out; + + if(copy_to_user(data, buffer, sizeof(buffer))) { + retval = -EFAULT; + goto err_out; + } + break; + + case KXTE9_IOCTL_ENABLE_OUTPUT: + retval = kxte9_set_pc1_on(); + if(retval < 0) + goto err_out; + break; + + case KXTE9_IOCTL_DISABLE_OUTPUT: + retval = kxte9_set_pc1_off(); + if(retval < 0) + goto err_out; + break; + + case KXTE9_IOCTL_GET_ENABLE: + data = (void __user *) arg; + if(data == NULL){ + retval = -EFAULT; + goto err_out; + } + retval = kxte9_get_bits(CTRL_REG1, ®_buffer, PC1_ON); + if(retval < 0) + goto err_out; + + val_short = (short)reg_buffer; + + if(copy_to_user(data, &val_short, sizeof(val_short))) { + retval = -EFAULT; + goto err_out; + } + break; + + case KXTE9_IOCTL_RESET: + retval = kxte9_set_bits(RES_CTRL_REG3, CTRL_REG3, set, SRST); + if(retval < 0) + goto err_out; + break; + + case KXTE9_IOCTL_UPDATE_ODR: + data = (void __user *) arg; + if(data == NULL){ + retval = -EFAULT; + goto err_out; + } + if(copy_from_user(&val_int, data, sizeof(val_int))) { + retval = -EFAULT; + goto err_out; + } + + mutex_lock(&te9->lock); + te9->pdata->poll_interval = max(val_int, te9->pdata->min_interval); + mutex_unlock(&te9->lock); + + retval = kxte9_update_odr(te9->pdata->poll_interval); + if(retval < 0) + goto err_out; + break; + + case KXTE9_IOCTL_ENABLE_CTC: + retval = kxte9_set_bits(RES_CTRL_REG3, CTRL_REG3, set, CTC); + if(retval < 0) + goto err_out; + break; + + case KXTE9_IOCTL_DISABLE_CTC: + retval = kxte9_set_bits(RES_CTRL_REG3, CTRL_REG3, unset, CTC); + if(retval < 0) + goto err_out; + break; + + case KXTE9_IOCTL_GET_CT_RESP: + data = (void __user *) arg; + if(data == NULL){ + retval = -EFAULT; + goto err_out; + } + retval = kxte9_get_byte(CT_RESP, ®_buffer); + if(retval < 0) + goto err_out; + + buffer[0] = (char)reg_buffer; + if(copy_to_user(data, buffer, sizeof(buffer))) { + retval = -EFAULT; + goto err_out; + } + break; + + default: + retval = -ENOIOCTLCMD; + break; + } + +err_out: + return retval; +} + +static struct file_operations kxte9_fops = { + .owner = THIS_MODULE, + .open = kxte9_open, + .release = kxte9_release, + //.ioctl = kxte9_ioctl, +}; + +static struct miscdevice kxte9_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = NAME_DEV, + .fops = &kxte9_fops, +}; + +static int kxte9_probe(void) +{ + int err = -1; + + te9 = kzalloc(sizeof(*te9), GFP_KERNEL); + if(te9 == NULL) { + errlog("failed to allocate memory for module data\n"); + err = -ENOMEM; + goto err0; + } + te9->pdata = &kxte9_pdata; + mutex_init(&te9->lock); + mutex_lock(&te9->lock); + + x_count = kzalloc(gconf.avg_count, GFP_KERNEL); + y_count = kzalloc(gconf.avg_count, GFP_KERNEL); + z_count = kzalloc(gconf.avg_count, GFP_KERNEL); + + if ((1000000/gconf.samp)%1000) + te9->pdata->poll_interval = 1000/gconf.samp + 1; + else + te9->pdata->poll_interval = 1000/gconf.samp; + printk(KERN_INFO "G-Sensor Time Interval: %d ms\n", te9->pdata->poll_interval); + + android_gsensor_kobj = kobject_create_and_add("kxte9_gsensor", NULL); + if (android_gsensor_kobj == NULL) { + errlog("gsensor_sysfs_init:subsystem_register failed\n"); + err = -ENOMEM; + goto err0; + } + + err = sysfs_create_group(android_gsensor_kobj, &kxte9_attribute_group); + if(err) + goto err1; + + if(te9->pdata->init) { + err = te9->pdata->init(); + if(err < 0) + goto err2; + } + + memset(te9->resume, 0, ARRAY_SIZE(te9->resume)); + te9->resume[RES_CTRL_REG1] = te9->pdata->ctrl_reg1_init; + te9->resume[RES_CTRL_REG3] = te9->pdata->engine_odr_init; + te9->resume[RES_INT_CTRL1] = te9->pdata->int_ctrl_init; + te9->resume[RES_TILT_TIMER] = te9->pdata->tilt_timer_init; + te9->resume[RES_WUF_TIMER] = te9->pdata->wuf_timer_init; + te9->resume[RES_B2S_TIMER] = te9->pdata->b2s_timer_init; + te9->resume[RES_WUF_THRESH] = te9->pdata->wuf_thresh_init; + te9->resume[RES_B2S_THRESH] = te9->pdata->b2s_thresh_init; + te9->hw_initialized = 0; + te9->i2c_xfer_complete = 1; + +#ifdef INT_MODE + // init gpio + SET_GPIO_GSENSOR_INT(); + INIT_WORK(&te9->irq_work, kxte9_irq_work_func); +#endif + + err = kxte9_device_power_on(); + if(err < 0) + goto err3; + atomic_set(&te9->enabled, 1); + + err = kxte9_verify(); + if(err < 0) { + errlog("kxte9_verify failed\n"); + goto err4; + } + + err = kxte9_update_odr(te9->pdata->poll_interval); + if(err < 0) { + errlog("update_odr failed\n"); + goto err4; + } + + err = kxte9_input_init(); + if(err < 0) + goto err4; + + err = misc_register(&kxte9_device); + if(err) { + errlog("misc. device failed to register.\n"); + goto err5; + } + +#ifdef CONFIG_HAS_EARLYSUSPEND + te9->earlysuspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + te9->earlysuspend.suspend = kxte9_early_suspend; + te9->earlysuspend.resume = kxte9_late_resume; + register_early_suspend(&te9->earlysuspend); +#endif + + atomic_set(&te9->enabled, 0); + +#ifdef INT_MODE + err = request_irq(gconf.irq, kxte9_isr, + IRQF_TRIGGER_RISING | IRQF_DISABLED, "kxte9_irq", te9); + if(err < 0) { + pr_err("%s: request irq failed: %d\n", __func__, err); + goto err6; + } + +#ifdef WM3445_A0 + // enable int + ENABLE_SENSOR_INT(1); +#endif + + // enable kxte9 + /*err = kxte9_enable(); + if (err < 0) { + errlog("kxte9_enable failed.\n"); + goto err6; + }*/ +#endif + + mutex_unlock(&te9->lock); + //kxte9_dump_reg(); + + return 0; + +#ifdef INT_MODE +err6: + misc_deregister(&kxte9_device); +#endif +err5: + kxte9_input_cleanup(); +err4: + kxte9_device_power_off(); +err3: + if(te9->pdata->exit) + te9->pdata->exit(); +err2: + //kfree(te9->pdata); + sysfs_remove_group(android_gsensor_kobj, &kxte9_attribute_group); +err1: + kobject_del(android_gsensor_kobj); + mutex_unlock(&te9->lock); + kfree(te9); +err0: + return err; +} + +static int kxte9_remove(void) +{ + cancel_delayed_work_sync(&te9->input_work); +#ifdef INT_MODE + free_irq(gconf.irq, te9); +#endif + kxte9_input_cleanup(); + misc_deregister(&kxte9_device); + kxte9_device_power_off(); + if(te9->pdata->exit) + te9->pdata->exit(); + kobject_del(android_gsensor_kobj); + sysfs_remove_group(android_gsensor_kobj, &kxte9_attribute_group); + kfree(te9); + + return 0; +} + +#ifdef CONFIG_PM +#if 0 +#ifdef CONFIG_HAS_EARLYSUSPEND +static void kxte9_early_suspend(struct early_suspend *h) +{ + kxte9_dbg("start\n"); + te9->suspend = 1; + kxte9_disable(); + kxte9_dbg("exit\n"); +} + +static void kxte9_late_resume(struct early_suspend *h) +{ + kxte9_dbg("start\n"); + te9->suspend = 0; + kxte9_enable(); + kxte9_dbg("exit\n"); +} +#endif +#endif +static int kxte9_resume(struct platform_device *pdev) +{ + te9->suspend = 0; + kxte9_enable(); + return 0; +} + +static int kxte9_suspend(struct platform_device *pdev, pm_message_t state) +{ + te9->suspend = 1; + kxte9_disable(); + return 0; +} +#endif + +static void kxte9_platform_release(struct device *device) +{ + kxte9_dbg("Do nothing!!!\n"); + return; +} + +static struct platform_device kxte9_plt_device = { + .name = "kxte9", + .id = 0, + .dev = { + .release = kxte9_platform_release, + }, +}; + +static struct platform_driver kxte9_plt_driver = { + .probe = NULL, //kxte9_probe, + .remove = NULL, //kxte9_remove, + .suspend = kxte9_suspend, + .resume = kxte9_resume, + .driver = { + .name = "kxte9", + }, +}; + +/* + * Get the configure of sensor from u-boot. + * Return: 1--success, 0--error. + */ +static int get_axisset(void) +{ + char varbuf[64]; + int n; + int varlen; + + memset(varbuf, 0, sizeof(varbuf)); + varlen = sizeof(varbuf); + if (wmt_getsyspara("wmt.io.gsensor", varbuf, &varlen)) { + printk(KERN_DEBUG "KXTE9: wmt.io.gsensor not defined!\n"); + return 0; + } else { + n = sscanf(varbuf, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", + &gconf.op, + &gconf.samp, + &(gconf.xyz_axis[0][0]), + &(gconf.xyz_axis[0][1]), + &(gconf.xyz_axis[1][0]), + &(gconf.xyz_axis[1][1]), + &(gconf.xyz_axis[2][0]), + &(gconf.xyz_axis[2][1]), + &gconf.avg_count, + &gconf.kxte9_8bit); + + if (n != 10) { + kxte9_dbg(KERN_ERR "KXTE9: wmt.io.gsensor format is incorrect!\n"); + return 0; + } + } + if (gconf.op != 1) + return 0; + printk(KERN_INFO "KXTE9 G-Sensor driver init\n"); + kxte9_dbg("AVG Count: %d, KXTE9 8bit: %d\n", + gconf.avg_count, + gconf.kxte9_8bit); + if (gconf.samp > 100) { + printk(KERN_ERR "Sample Rate can't be greater than 100 !\n"); + gconf.samp = 100; + } + if (gconf.avg_count == 0) + gconf.avg_count = 1; + if (gconf.kxte9_8bit > 1) + gconf.kxte9_8bit = 1; + kxte9_dbg("wmt.io.gsensor = %d:%d:%d:%d:%d:%d:%d:%d:%d:%d\n", + gconf.op, + gconf.samp, + gconf.xyz_axis[0][0], + gconf.xyz_axis[0][1], + gconf.xyz_axis[1][0], + gconf.xyz_axis[1][1], + gconf.xyz_axis[2][0], + gconf.xyz_axis[2][1], + gconf.avg_count, + gconf.kxte9_8bit); + return 1; +} + +static int get_gpioset(void) +{ + char varbuf[96]; + int n; + int varlen; + + memset(varbuf, 0, sizeof(varbuf)); + varlen = sizeof(varbuf); + if (wmt_getsyspara("wmt.gpt.gsensor", varbuf, &varlen)) { + printk(KERN_DEBUG "Can't get gsensor's gpio config from u-boot! -> Use default config\n"); + return 0; + } else { + n = sscanf(varbuf, "%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x", + &gconf.name, + &gconf.bmp, + &(gconf.ctraddr), + &(gconf.ocaddr), + &(gconf.idaddr), + &(gconf.peaddr), + &(gconf.pcaddr), + &(gconf.itbmp), + &(gconf.itaddr), + &(gconf.isbmp), + &(gconf.isaddr), + &(gconf.irq)); + if (n != 12) { + printk(KERN_ERR "wmt.gpt.gsensor format is incorrect in u-boot!!!\n"); + return 0; + } + + gconf.ctraddr += WMT_MMAP_OFFSET; + gconf.ocaddr += WMT_MMAP_OFFSET; + gconf.idaddr += WMT_MMAP_OFFSET; + gconf.peaddr += WMT_MMAP_OFFSET; + gconf.pcaddr += WMT_MMAP_OFFSET; + gconf.itaddr += WMT_MMAP_OFFSET; + gconf.isaddr += WMT_MMAP_OFFSET; + } + return 1; +} + +static int __init kxte9_init(void) +{ + int ret = 0; + + // parsing u-boot arg + ret = get_axisset(); // get gsensor config from u-boot + if (!ret) + return -EINVAL; + + get_gpioset(); + + // initail + if ((ret = kxte9_probe()) != 0) { + errlog(" Error for kxte9_probe !!!\n"); + return ret; + } + atomic_set(&kxte9_dev_open_count, 0); + + if ((ret = platform_device_register(&kxte9_plt_device)) != 0) { + errlog("Can't register kxte9_plt_device platform devcie!!!\n"); + return ret; + } + if ((ret = platform_driver_register(&kxte9_plt_driver)) != 0) { + errlog("Can't register kxte9_plt_driver platform driver!!!\n"); + return ret; + } + klog("gsensor_kxte9 driver is loaded successfully!\n"); + return ret; +} + +static void __exit kxte9_exit(void) +{ + platform_driver_unregister(&kxte9_plt_driver); + platform_device_unregister(&kxte9_plt_device); + atomic_set(&kxte9_dev_open_count, 0); + kxte9_remove(); +} + +module_init(kxte9_init); +module_exit(kxte9_exit); + +MODULE_DESCRIPTION("KXTE9 accelerometer driver"); +MODULE_AUTHOR("Kuching Tan "); +MODULE_LICENSE("GPL"); +MODULE_VERSION(VERSION_DEV); diff --git a/ANDROID_3.4.5/drivers/input/sensor/kxte9_gsensor/kxte9.h b/ANDROID_3.4.5/drivers/input/sensor/kxte9_gsensor/kxte9.h new file mode 100755 index 00000000..6b5141e5 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/kxte9_gsensor/kxte9.h @@ -0,0 +1,116 @@ +/* include/linux/kxte9.h - KXTE9 accelerometer driver + * + * Copyright (C) 2010 Kionix, Inc. + * Written by Kuching Tan + * + * 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 3 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 . + * + */ + +#ifndef __KXTE9_H__ +#define __KXTE9_H__ + +#define KXTE9_I2C_ADDR 0x0F +/* CONTROL REGISTER 1 BITS */ +#define TPE 0x01 /* tilt position function enable bit */ +#define WUFE 0x02 /* wake-up function enable bit */ +#define B2SE 0x04 /* back-to-sleep function enable bit */ +#define ODR125E 0x20 /* 125Hz ODR mode */ +#define ODR40E 0x18 /* initial ODR masks */ +#define ODR10E 0x10 +#define ODR3E 0x08 +#define ODR1E 0x00 +/* CONTROL REGISTER 3 BITS */ +#define SRST 0x80 /* software reset */ +#define CTC 0x10 /* communication-test function */ +#define OB2S40 0x0C /* back-to-sleep ODR masks */ +#define OB2S10 0x08 +#define OB2S3 0x04 +#define OB2S1 0x00 +#define OWUF40 0x03 /* wake-up ODR masks */ +#define OWUF10 0x02 +#define OWUF3 0x01 +#define OWUF1 0x00 +/* INTERRUPT CONTROL REGISTER 1 BITS */ +#define KXTE9_IEN 0x10 /* interrupt enable */ +#define KXTE9_IEA 0x08 /* interrupt polarity */ +#define KXTE9_IEL 0x04 /* interrupt response */ + +/* Device Meta Data */ +#define DESC_DEV "KXTE9 3-axis Accelerometer" // Device Description +#define VERSION_DEV "1.1.7" +#define VER_MAJOR_DEV 1 +#define VER_MINOR_DEV 1 +#define VER_MAINT_DEV 7 +#define MAX_G_DEV (2.0f) // Maximum G Level +#define MAX_SENS_DEV (1024.0f) // Maximum Sensitivity +#define PWR_DEV (0.03f) // Typical Current + +/* Input Device Name */ +//#define INPUT_NAME_ACC "kxte9_accel" +#define INPUT_NAME_ACC "g-sensor" + +/* Device name for kxte9 misc. device */ +#define NAME_DEV "kxte9" +#define DIR_DEV "/dev/kxte9" + +/* IOCTLs for kxte9 misc. device library */ +#define KXTE9IO 0x92 +#define KXTE9_IOCTL_GET_COUNT _IOR(KXTE9IO, 0x01, int) +#define KXTE9_IOCTL_GET_MG _IOR(KXTE9IO, 0x02, int) +#define KXTE9_IOCTL_ENABLE_OUTPUT _IO(KXTE9IO, 0x03) +#define KXTE9_IOCTL_DISABLE_OUTPUT _IO(KXTE9IO, 0x04) +#define KXTE9_IOCTL_GET_ENABLE _IOR(KXTE9IO, 0x05, int) +#define KXTE9_IOCTL_RESET _IO(KXTE9IO, 0x06) +#define KXTE9_IOCTL_UPDATE_ODR _IOW(KXTE9IO, 0x07, int) +#define KXTE9_IOCTL_ENABLE_CTC _IO(KXTE9IO, 0x08) +#define KXTE9_IOCTL_DISABLE_CTC _IO(KXTE9IO, 0x09) +#define KXTE9_IOCTL_GET_CT_RESP _IOR(KXTE9IO, 0x0A, int) + + +#ifdef __KERNEL__ +struct kxte9_platform_data { + int poll_interval; + int min_interval; + /* the desired g-range, in milli-g (always 2000 for kxte9) */ + u8 g_range; + /* used to compensate for alternate device placement within the host */ +/* + u8 axis_map_x; + u8 axis_map_y; + u8 axis_map_z; + u8 negate_x; + u8 negate_y; + u8 negate_z; +*/ + /* initial configuration values, set during board configuration */ + u8 ctrl_reg1_init; + u8 engine_odr_init; + u8 int_ctrl_init; + u8 tilt_timer_init; + u8 wuf_timer_init; + u8 b2s_timer_init; + u8 wuf_thresh_init; + u8 b2s_thresh_init; + + int (*init)(void); + void (*exit)(void); +//NelsonTmp{ +// int gpio; +//} +}; +#endif /* __KERNEL__ */ + +#endif /* __KXTE9_H__ */ + diff --git a/ANDROID_3.4.5/drivers/input/sensor/kxte9_gsensor/readme.txt b/ANDROID_3.4.5/drivers/input/sensor/kxte9_gsensor/readme.txt new file mode 100755 index 00000000..e4653a08 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/kxte9_gsensor/readme.txt @@ -0,0 +1,47 @@ +The back of WM3445 MID + ______________ +| +z | +| \ @ | +| \ | +| ---- +y | +| | | +| | | +| +x | +|______________| +(KXTE9-2050 Accelerometer) + +wmt.io.gsensor +Configure G-Sensor for Enable/Disable,X,Y,Z axis mapping and sampling rate. If driver not detect this variable, then G-sensor driver won¡¦t be loaded. +:::::::::<8bit> +:= Operation mode for the g-sensor +0 : KXTE9-2050 G-Sensor is disabled. +1 : KXTE9-2050 G-Sensor is enabled. +:= G-Sensor sampling rate. The valid values are 1,3,10,and 40. +:= G-Sensor axis-x will map to which axis of device. +0 : X +1 : Y +2 : Z +:= If G-Sensor axis-x direction is the same as device. +1 : Positive direction +-1 : Negative direction +:= G-Sensor axis-y will map to which axis of device. +0 : X +1 : Y +2 : Z +:= If G-Sensor axis-y direction is the same as device. +1 : Positive direction +-1 : Negative direction +:= G-Sensor axis-z will map to which axis of device. +0 : X +1 : Y +2 : Z +:= If G-Sensor axis-z direction is the same as device. +1 : Positive direction +-1 : Negative direction +:= For every new/current axes values stored, add the newly stored axes with previously (avg-count-1) stored axes values and do an average +<8bit>:= Using acceleration data as 8bit +0 : 6bit +1 : 8bit +Ex: +#KXTE9-2050 G-sensor enabled, using 40 sampling rate, X->-Y, Y->X, Z->-Z, 4 average count, using 8bit +setenv wmt.io.gsensor 1:40:1:-1:0:-1:2:-1:4:1 diff --git a/ANDROID_3.4.5/drivers/input/sensor/l3g4200d_gyro/Makefile b/ANDROID_3.4.5/drivers/input/sensor/l3g4200d_gyro/Makefile new file mode 100755 index 00000000..2818c82f --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/l3g4200d_gyro/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the kernel device drivers. +# +obj-$(CONFIG_WMT_GYRO_L3G4200D) += s_wmt_gyro_l3g4200d.o +s_wmt_gyro_l3g4200d-objs := l3g4200d_gyr.o \ No newline at end of file diff --git a/ANDROID_3.4.5/drivers/input/sensor/l3g4200d_gyro/l3g4200d.h b/ANDROID_3.4.5/drivers/input/sensor/l3g4200d_gyro/l3g4200d.h new file mode 100755 index 00000000..4cae2bc5 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/l3g4200d_gyro/l3g4200d.h @@ -0,0 +1,108 @@ +/******************** (C) COPYRIGHT 2010 STMicroelectronics ******************** +* +* File Name : l3g4200d.h +* Authors : MH - C&I BU - Application Team +* : Carmine Iascone (carmine.iascone@st.com) +* : Matteo Dameno (matteo.dameno@st.com) +* Version : V 1.1 sysfs +* Date : 2010/Aug/19 +* Description : L3G4200D digital output gyroscope sensor API +* +******************************************************************************** +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* THE PRESENT SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES +* OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, FOR THE SOLE +* PURPOSE TO SUPPORT YOUR APPLICATION DEVELOPMENT. +* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, +* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE +* CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING +* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. +* +******************************************************************************** +* REVISON HISTORY +* +* VERSION | DATE | AUTHORS | DESCRIPTION +* 1.0 | 2010/Aug/19 | Carmine Iascone | First Release +* 1.1 | 2011/02/28 | Matteo Dameno | Self Test Added +* 1.2 | 2013/04/29 | Howay Huo | Android Interface Added +*******************************************************************************/ + +#ifndef __L3G4200D_H__ +#define __L3G4200D_H__ + +#define L3G4200D_GYR_DEV_NAME "l3g4200d_gyr" +#define GYRO_INPUT_NAME "gyroscope" +#define GYRO_MISCDEV_NAME "gyro_ctrl" + +#define L3G4200D_DRVID 0 + +#define L3G4200D_GYR_FS_250DPS 0x00 +#define L3G4200D_GYR_FS_500DPS 0x10 +#define L3G4200D_GYR_FS_2000DPS 0x30 + +#define L3G4200D_GYR_ENABLED 1 +#define L3G4200D_GYR_DISABLED 0 + +#define WMTGSENSOR_IOCTL_MAGIC 0x09 +#define WMT_GYRO_IOCTL_MAGIC 0x11 +#define GYRO_IOCTL_SET_ENABLE _IOW(WMT_GYRO_IOCTL_MAGIC, 0, int) +#define GYRO_IOCTL_GET_ENABLE _IOW(WMT_GYRO_IOCTL_MAGIC, 1, int) +#define GYRO_IOCTL_SET_DELAY _IOW(WMT_GYRO_IOCTL_MAGIC, 2, int) +#define GYRO_IOCTL_GET_DELAY _IOW(WMT_GYRO_IOCTL_MAGIC, 3, int) +#define WMT_IOCTL_SENSOR_GET_DRVID _IOW(WMTGSENSOR_IOCTL_MAGIC, 4, unsigned int) + +#ifdef __KERNEL__ + +struct l3g4200d_triple { + short x, /* x-axis angular rate data. */ + y, /* y-axis angluar rate data. */ + z; /* z-axis angular rate data. */ +}; + + +struct reg_value_t { + u8 ctrl_reg1; + u8 ctrl_reg2; + u8 ctrl_reg3; + u8 ctrl_reg4; + u8 ctrl_reg5; + u8 ref_datacap; + u8 fifo_ctrl_reg; + u8 int1_cfg; + u8 int1_ths_xh; + u8 int1_ths_xl; + u8 int1_ths_yh; + u8 int1_ths_yl; + u8 int1_ths_zh; + u8 int1_ths_zl; + u8 int1_duration; +}; + +struct l3g4200d_gyr_platform_data { + int (*init)(void); + void (*exit)(void); + int (*power_on)(void); + int (*power_off)(void); + int poll_interval; + int min_interval; + + u8 fs_range; + + int axis_map_x; + int axis_map_y; + int axis_map_z; + + int direction_x; + int direction_y; + int direction_z; + + struct reg_value_t init_state; + +}; +#endif /* __KERNEL__ */ + +#endif /* __L3G4200D_H__ */ diff --git a/ANDROID_3.4.5/drivers/input/sensor/l3g4200d_gyro/l3g4200d_gyr.c b/ANDROID_3.4.5/drivers/input/sensor/l3g4200d_gyro/l3g4200d_gyr.c new file mode 100755 index 00000000..a30c00a6 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/l3g4200d_gyro/l3g4200d_gyr.c @@ -0,0 +1,1681 @@ +/******************** (C) COPYRIGHT 2010 STMicroelectronics ******************** +* +* File Name : l3g4200d_gyr_sysfs.c +* Authors : MH - C&I BU - Application Team +* : Carmine Iascone (carmine.iascone@st.com) +* : Matteo Dameno (matteo.dameno@st.com) +* : Both authors are willing to be considered the contact +* : and update points for the driver. +* Version : V 1.1 sysfs +* Date : 2011/02/28 +* Description : L3G4200D digital output gyroscope sensor API +* +******************************************************************************** +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* THE PRESENT SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES +* OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, FOR THE SOLE +* PURPOSE TO SUPPORT YOUR APPLICATION DEVELOPMENT. +* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, +* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE +* CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING +* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. +* +******************************************************************************** +* REVISON HISTORY +* +* VERSION | DATE | AUTHORS | DESCRIPTION +* 1.0 | 2010/11/19 | Carmine Iascone | First Release +* 1.1 | 2011/02/28 | Matteo Dameno | Self Test Added +* 1.2 | 2013/04/29 | Howay Huo | Android Interface Added +*******************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "l3g4200d.h" + +#undef DEBUG +#define DEBUG 1 + +#define L3G4200D_I2C_ADDR 0x69 + +/* WM8880 interrupt pin connect to the DRDY Pin of LL3G4200D */ +#define L3G4200D_IRQ_PIN WMT_PIN_GP2_GPIO17 + +/** Maximum polled-device-reported rot speed value value in dps*/ +#define FS_MAX 32768 + +/* l3g4200d gyroscope registers */ +#define WHO_AM_I 0x0F + +#define CTRL_REG1 0x20 +#define CTRL_REG2 0x21 +#define CTRL_REG3 0x22 +#define CTRL_REG4 0x23 +#define CTRL_REG5 0x24 +#define REF_DATACAP 0x25 +#define OUT_TEMP 0x26 +#define STATUS_REG 0x27 +#define OUT_X_L 0x28 +#define OUT_X_H 0x29 +#define OUT_Y_L 0x2A +#define OUT_Y_H 0x2B +#define OUT_Z_L 0x2C +#define OUT_Z_H 0x2D +#define FIFO_CTRL_REG 0x2E +#define FIFO_SRC_REG 0x2F +#define INT1_CFG 0x30 +#define INT1_SRC 0x31 +#define INT1_THS_XH 0x32 +#define INT1_THS_XL 0x33 +#define INT1_THS_YH 0x34 +#define INT1_THS_YL 0x35 +#define INT1_THS_ZH 0x36 +#define INT1_THS_ZL 0x37 +#define INT1_DURATION 0x38 + +/* CTRL_REG1 */ +#define PM_MASK 0x08 +#define PM_NORMAL 0x08 +#define ENABLE_ALL_AXES 0x07 + +/* CTRL_REG3 */ +#define I2_DRDY 0x08 + +/* CTRL_REG4 bits */ +#define FS_MASK 0x30 + +#define SELFTEST_MASK 0x06 +#define L3G4200D_SELFTEST_DIS 0x00 +#define L3G4200D_SELFTEST_EN_POS 0x02 +#define L3G4200D_SELFTEST_EN_NEG 0x04 + +#define FUZZ 0 +#define FLAT 0 +#define AUTO_INCREMENT 0x80 + +/* STATUS_REG */ +#define ZYXDA 0x08 +#define ZDA 0x04 +#define YDA 0x02 +#define XDA 0x01 + +/** Registers Contents */ +#define WHOAMI_L3G4200D 0x00D3 /* Expected content for WAI register*/ + +#define ODR_MASK 0xF0 +#define ODR100_BW25 0x10 +#define ODR200_BW70 0x70 +#define ODR400_BW110 0xB0 +#define ODR800_BW110 0xF0 + +#define L3G4200D_PU_DELAY 320 //ms + +static struct i2c_client *l3g4200d_i2c_client = NULL; +static int enable_print_log; +static int interrupt_mode = 0; +static int flush_polling_data; + +/* + * L3G4200D gyroscope data + * brief structure containing gyroscope values for yaw, pitch and roll in + * signed short + */ + +struct output_rate{ + u8 odr_mask; + u32 delay_us; +}; + +static const struct output_rate gyro_odr_table[] = { + { ODR800_BW110, 1250 }, + { ODR400_BW110, 2500 }, + { ODR200_BW70, 5000 }, + { ODR100_BW25, 10000}, +}; + +struct l3g4200d_data { + struct i2c_client *client; + struct l3g4200d_gyr_platform_data *pdata; + + struct mutex lock; + + struct delayed_work enable_work; + struct delayed_work input_work; + struct input_dev *input_dev; + int hw_initialized; + int selftest_enabled; + atomic_t enabled; + + u8 reg_addr; + struct reg_value_t resume_state; +}; + +extern int wmt_getsyspara(char *varname, char *varval, int *varlen); + +static int l3g4200d_i2c_read(struct l3g4200d_data *gyro, + u8 *buf, int len) +{ + int err; + + struct i2c_msg msgs[] = { + { + .addr = gyro->client->addr, + .flags = gyro->client->flags & I2C_M_TEN, + .len = 1, + .buf = buf, + }, + { + .addr = gyro->client->addr, + .flags = (gyro->client->flags & I2C_M_TEN) | I2C_M_RD, + .len = len, + .buf = buf, + }, + }; + + err = i2c_transfer(gyro->client->adapter, msgs, 2); + + if (err != 2) { + dev_err(&gyro->client->dev, "read transfer error: %d\n",err); + return -EIO; + } + + return 0; +} + +static int l3g4200d_i2c_write(struct l3g4200d_data *gyro, + u8 *buf, + int len) +{ + int err; + + struct i2c_msg msgs[] = { + { + .addr = gyro->client->addr, + .flags = gyro->client->flags & I2C_M_TEN, + .len = len + 1, + .buf = buf, + }, + }; + + err = i2c_transfer(gyro->client->adapter, msgs, 1); + + if (err != 1) { + dev_err(&gyro->client->dev, "write transfer error\n"); + return -EIO; + } + + return 0; +} + +static int l3g4200d_register_write(struct l3g4200d_data *gyro, u8 *buf, + u8 reg_address, u8 new_value) +{ + int err = -1; + + /* Sets configuration register at reg_address + * NOTE: this is a straight overwrite */ + buf[0] = reg_address; + buf[1] = new_value; + err = l3g4200d_i2c_write(gyro, buf, 1); + if (err < 0) + return err; + + return err; +} + +static int l3g4200d_register_read(struct l3g4200d_data *gyro, u8 *buf, + u8 reg_address) +{ + + int err = -1; + buf[0] = (reg_address); + err = l3g4200d_i2c_read(gyro, buf, 1); + return err; +} + +static int l3g4200d_register_update(struct l3g4200d_data *gyro, u8 *buf, + u8 reg_address, u8 mask, u8 new_bit_values) +{ + int err = -1; + u8 init_val; + u8 updated_val; + err = l3g4200d_register_read(gyro, buf, reg_address); + if (!(err < 0)) { + init_val = buf[0]; + if((new_bit_values & mask) != (init_val & mask)) { + updated_val = ((mask & new_bit_values) | ((~mask) & init_val)); + err = l3g4200d_register_write(gyro, buf, reg_address, + updated_val); + } + else + return 0; + } + return err; +} + +static int l3g4200d_register_store(struct l3g4200d_data *gyro, u8 reg) +{ + int err = -1; + u8 buf[2]; + + err = l3g4200d_register_read(gyro, buf, reg); + if (err) + return err; + + switch (reg) { + case CTRL_REG1: + gyro->resume_state.ctrl_reg1 = buf[0]; + break; + case CTRL_REG2: + gyro->resume_state.ctrl_reg2 = buf[0]; + break; + case CTRL_REG3: + gyro->resume_state.ctrl_reg3 = buf[0]; + break; + case CTRL_REG4: + gyro->resume_state.ctrl_reg4 = buf[0]; + break; + case CTRL_REG5: + gyro->resume_state.ctrl_reg5 = buf[0]; + break; + case REF_DATACAP: + gyro->resume_state.ref_datacap = buf[0]; + break; + case FIFO_CTRL_REG: + gyro->resume_state.fifo_ctrl_reg = buf[0]; + break; + case INT1_CFG: + gyro->resume_state.int1_cfg = buf[0]; + break; + case INT1_THS_XH: + gyro->resume_state.int1_ths_xh = buf[0]; + break; + case INT1_THS_XL: + gyro->resume_state.int1_ths_xl = buf[0]; + break; + case INT1_THS_YH: + gyro->resume_state.int1_ths_yh = buf[0]; + break; + case INT1_THS_YL: + gyro->resume_state.int1_ths_yl = buf[0]; + break; + case INT1_THS_ZH: + gyro->resume_state.int1_ths_zh = buf[0]; + break; + case INT1_THS_ZL: + gyro->resume_state.int1_ths_zl = buf[0]; + break; + case INT1_DURATION: + gyro->resume_state.int1_duration = buf[0]; + break; + default: + pr_err("%s: can't support reg (0x%02X) store\n", L3G4200D_GYR_DEV_NAME, reg); + return -1; + } + + return 0; +} + +static int l3g4200d_update_fs_range(struct l3g4200d_data *gyro, + u8 new_fs) +{ + int res ; + u8 buf[2]; + + buf[0] = CTRL_REG4; + + res = l3g4200d_register_update(gyro, buf, CTRL_REG4, + FS_MASK, new_fs); + + if (res < 0) { + pr_err("%s : failed to update fs:0x%02x\n", + __func__, new_fs); + return res; + } + + l3g4200d_register_store(gyro, CTRL_REG4); + + return 0; +} + + +static int l3g4200d_selftest(struct l3g4200d_data *gyro, u8 enable) +{ + int err = -1; + u8 buf[2] = {0x00,0x00}; + char reg_address, mask, bit_values; + + reg_address = CTRL_REG4; + mask = SELFTEST_MASK; + if (enable > 0) + bit_values = L3G4200D_SELFTEST_EN_POS; + else + bit_values = L3G4200D_SELFTEST_DIS; + if (atomic_read(&gyro->enabled)) { + mutex_lock(&gyro->lock); + err = l3g4200d_register_update(gyro, buf, reg_address, + mask, bit_values); + gyro->selftest_enabled = enable; + mutex_unlock(&gyro->lock); + if (err < 0) + return err; + + l3g4200d_register_store(gyro, CTRL_REG4); + } + return err; +} + + +static int l3g4200d_update_odr(struct l3g4200d_data *gyro, + int poll_interval) +{ + int err = -1; + int i; + u8 config[2]; + + for (i = ARRAY_SIZE(gyro_odr_table) - 1; i >= 0; i--) { + if (gyro_odr_table[i].delay_us <= poll_interval){ + break; + } + } + + gyro->pdata->poll_interval = gyro_odr_table[i].delay_us; + + config[1] = gyro_odr_table[i].odr_mask; + config[1] |= (ENABLE_ALL_AXES + PM_NORMAL); + + /* If device is currently enabled, we need to write new + * configuration out to it */ + if (atomic_read(&gyro->enabled)) { + config[0] = CTRL_REG1; + err = l3g4200d_i2c_write(gyro, config, 1); + if (err < 0) + return err; + + l3g4200d_register_store(gyro, CTRL_REG1); + } + + return err; +} + +/* gyroscope data readout */ +static int l3g4200d_get_data(struct l3g4200d_data *gyro, + struct l3g4200d_triple *data) +{ + int err; + unsigned char gyro_out[6]; + /* y,p,r hardware data */ + s16 hw_d[3] = { 0 }; + + gyro_out[0] = (AUTO_INCREMENT | OUT_X_L); + + err = l3g4200d_i2c_read(gyro, gyro_out, 6); + + if (err < 0) + return err; + + hw_d[0] = (s16) (((gyro_out[1]) << 8) | gyro_out[0]); + hw_d[1] = (s16) (((gyro_out[3]) << 8) | gyro_out[2]); + hw_d[2] = (s16) (((gyro_out[5]) << 8) | gyro_out[4]); + + data->x = ((gyro->pdata->direction_x < 0) ? (-hw_d[gyro->pdata->axis_map_x]) + : (hw_d[gyro->pdata->axis_map_x])); + data->y = ((gyro->pdata->direction_y < 0) ? (-hw_d[gyro->pdata->axis_map_y]) + : (hw_d[gyro->pdata->axis_map_y])); + data->z = ((gyro->pdata->direction_z < 0) ? (-hw_d[gyro->pdata->axis_map_z]) + : (hw_d[gyro->pdata->axis_map_z])); + + if(enable_print_log) + printk("x = %d, y = %d, z = %d\n", data->x, data->y, data->z); + + return err; +} + +static void l3g4200d_report_values(struct l3g4200d_data *l3g, + struct l3g4200d_triple *data) +{ + struct input_dev *input = l3g->input_dev; + + input_report_abs(input, ABS_X, data->x); + input_report_abs(input, ABS_Y, data->y); + input_report_abs(input, ABS_Z, data->z); + input_sync(input); +} + +static int l3g4200d_hw_init(struct l3g4200d_data *gyro) +{ + int err = -1; + u8 buf[8]; + + printk(KERN_INFO "%s hw init\n", L3G4200D_GYR_DEV_NAME); + + buf[0] = (AUTO_INCREMENT | CTRL_REG1); + buf[1] = gyro->resume_state.ctrl_reg1; + buf[2] = gyro->resume_state.ctrl_reg2; + buf[3] = gyro->resume_state.ctrl_reg3; + buf[4] = gyro->resume_state.ctrl_reg4; + buf[5] = gyro->resume_state.ctrl_reg5; + buf[6] = gyro->resume_state.ref_datacap; + err = l3g4200d_i2c_write(gyro, buf, 6); + if(err) + return err; + + buf[0] = FIFO_CTRL_REG; + buf[1] = gyro->resume_state.fifo_ctrl_reg; + err = l3g4200d_i2c_write(gyro, buf, 1); + if(err) + return err; + + buf[0] = INT1_CFG; + buf[1] = gyro->resume_state.int1_cfg; + err = l3g4200d_i2c_write(gyro, buf, 1); + if(err) + return err; + + buf[0] = (AUTO_INCREMENT | INT1_THS_XH); + buf[1] = gyro->resume_state.int1_ths_xh; + buf[2] = gyro->resume_state.int1_ths_xl; + buf[3] = gyro->resume_state.int1_ths_yh; + buf[4] = gyro->resume_state.int1_ths_yl; + buf[5] = gyro->resume_state.int1_ths_zh; + buf[6] = gyro->resume_state.int1_ths_zl; + buf[7] = gyro->resume_state.int1_duration; + err = l3g4200d_i2c_write(gyro, buf, 7); + if(err) + return err; + + gyro->hw_initialized = 1; + + return 0; +} + +static void l3g4200d_gpio_irq_enable(void) +{ + wmt_gpio_unmask_irq(L3G4200D_IRQ_PIN); +} + +static void l3g4200d_gpio_irq_disable(void) +{ + wmt_gpio_mask_irq(L3G4200D_IRQ_PIN); +} + +static int l3g4200d_irq_hw_init(int resume) +{ + int ret; + + if(!resume) { + ret = gpio_request(L3G4200D_IRQ_PIN, "l3g4200d-gyro irq"); //enable gpio + if(ret < 0) { + pr_err("gpio(%d) request fail for l3g4200d-gyro irq\n", L3G4200D_IRQ_PIN); + return ret; + } + }else + gpio_re_enabled(L3G4200D_IRQ_PIN); //re-enable gpio + + gpio_direction_input(L3G4200D_IRQ_PIN); //gpio input + + wmt_gpio_setpull(L3G4200D_IRQ_PIN, WMT_GPIO_PULL_DOWN); //enable pull and pull-down + + wmt_gpio_mask_irq(L3G4200D_IRQ_PIN); //disable interrupt + + wmt_gpio_set_irq_type(L3G4200D_IRQ_PIN, IRQ_TYPE_EDGE_RISING); //rise edge and clear interrupt + + return 0; +} + +static void l3g4200d_irq_hw_free(void) +{ + l3g4200d_gpio_irq_disable(); + gpio_free(L3G4200D_IRQ_PIN); + +} + +static int l3g4200d_gpio_get_value(void) +{ + return (REG8_VAL(__GPIO_BASE + 0x0002) & BIT1); +} + +static int l3g4200d_flush_gyro_data(struct l3g4200d_data *gyro) +{ + struct l3g4200d_triple data; + int i; + + for (i = 0; i < 5; i++) { + if (l3g4200d_gpio_get_value()) { + l3g4200d_get_data(gyro, &data); + pr_info("%s: flush_gyro_data: %d\n", L3G4200D_GYR_DEV_NAME, i); + } + else { + return 0; + } + } + + return -EIO; +} + +static void l3g4200d_device_power_off(struct l3g4200d_data *gyro) +{ + int err; + u8 buf[2]; + + pr_info("%s power off\n", L3G4200D_GYR_DEV_NAME); + + buf[0] = CTRL_REG1; + err = l3g4200d_i2c_read(gyro, buf, 1); + if(err < 0) { + dev_err(&gyro->client->dev, "read ctrl_reg1 failed\n"); + buf[0] = (gyro->resume_state.ctrl_reg1 | PM_MASK); + } + + if(buf[0] & PM_MASK) { + buf[1] = buf[0] & ~PM_MASK; + buf[0] = CTRL_REG1; + + err = l3g4200d_i2c_write(gyro, buf, 1); + if (err) + dev_err(&gyro->client->dev, "soft power off failed\n"); + + l3g4200d_register_store(gyro, CTRL_REG1); + } + + if (gyro->pdata->power_off) { + gyro->pdata->power_off(); +// gyro->hw_initialized = 0; + } + +// if (gyro->hw_initialized) +// gyro->hw_initialized = 0; + +} + +static int l3g4200d_device_power_on(struct l3g4200d_data *gyro) +{ + int err; + u8 buf[2]; + + pr_info("%s power on\n", L3G4200D_GYR_DEV_NAME); + + if (gyro->pdata->power_on) { + err = gyro->pdata->power_on(); + if (err < 0) + return err; + } + + if (!gyro->hw_initialized) { + err = l3g4200d_hw_init(gyro); + if (err) { + l3g4200d_device_power_off(gyro); + return err; + } + } + + buf[0] = CTRL_REG1; + err = l3g4200d_i2c_read(gyro, buf, 1); + if(err) { + dev_err(&gyro->client->dev, "read ctrl_reg1 failed\n"); + buf[0] = (gyro->resume_state.ctrl_reg1 & ~PM_MASK); + } + + if(!(buf[0] & PM_MASK)) { + buf[1] = buf[0] | PM_MASK; + buf[0] = CTRL_REG1; + err = l3g4200d_i2c_write(gyro, buf, 1); + if(err) { + dev_err(&gyro->client->dev, "soft power on failed\n"); + return err; + } + l3g4200d_register_store(gyro, CTRL_REG1); + } + + return 0; +} + +static int l3g4200d_enable(struct l3g4200d_data *gyro) +{ + int err; + + pr_info("%s enable\n", L3G4200D_GYR_DEV_NAME); + + if (!atomic_cmpxchg(&gyro->enabled, 0, 1)) { + err = l3g4200d_device_power_on(gyro); + if (err) { + atomic_set(&gyro->enabled, 0); + return err; + } + + //Android will call l3g4200d_set_delay() after l3g4200d_enable; + } + + return 0; +} + +static int l3g4200d_disable(struct l3g4200d_data *gyro) +{ + pr_info("%s disable\n", L3G4200D_GYR_DEV_NAME); + + if (atomic_cmpxchg(&gyro->enabled, 1, 0)){ + if(interrupt_mode) { + cancel_delayed_work_sync(&gyro->enable_work); + l3g4200d_gpio_irq_disable(); + }else + cancel_delayed_work_sync(&gyro->input_work); + + l3g4200d_device_power_off(gyro); + } + return 0; +} + +static int l3g4200d_set_delay(struct l3g4200d_data *gyro, u32 delay_us) +{ + int odr_value = ODR100_BW25; + int err = -1; + int i; + u8 buf[2] = {CTRL_REG1, 0}; + + pr_info("l3g4200d_set_delay: %d us\n", delay_us); + + /* do not report noise during ODR update */ + if(interrupt_mode) { + cancel_delayed_work_sync(&gyro->enable_work); + l3g4200d_gpio_irq_disable(); + }else + cancel_delayed_work_sync(&gyro->input_work); + + for(i=0; i < ARRAY_SIZE(gyro_odr_table); i++) + if(delay_us <= gyro_odr_table[i].delay_us) { + odr_value = gyro_odr_table[i].odr_mask; + delay_us = gyro_odr_table[i].delay_us; + break; + } + + if(delay_us >= gyro_odr_table[3].delay_us) { + odr_value = gyro_odr_table[3].odr_mask; + delay_us = gyro_odr_table[3].delay_us; + } + + err = l3g4200d_register_update(gyro, buf, CTRL_REG1, ODR_MASK, odr_value); + if(err) { + dev_err(&gyro->client->dev, "update odr failed 0x%x,0x%x: %d\n", + buf[0], odr_value, err); + return err; + } + + l3g4200d_register_store(gyro, CTRL_REG1); + + gyro->pdata->poll_interval = max((int)delay_us, gyro->pdata->min_interval); + + //do not report noise at IC power-up + // flush data before really read + if(interrupt_mode) + schedule_delayed_work(&gyro->enable_work, msecs_to_jiffies( + L3G4200D_PU_DELAY)); + else { + flush_polling_data = 1; + schedule_delayed_work(&gyro->input_work, msecs_to_jiffies( + L3G4200D_PU_DELAY)); + } + + return 0; +} + +static ssize_t attr_polling_rate_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int val; + struct l3g4200d_data *gyro = dev_get_drvdata(dev); + mutex_lock(&gyro->lock); + val = gyro->pdata->poll_interval; + mutex_unlock(&gyro->lock); + return sprintf(buf, "%d\n", val); +} + +static ssize_t attr_polling_rate_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct l3g4200d_data *gyro = dev_get_drvdata(dev); + unsigned long interval_us; + + if (strict_strtoul(buf, 10, &interval_us)) + return -EINVAL; + if (!interval_us) + return -EINVAL; + mutex_lock(&gyro->lock); + gyro->pdata->poll_interval = interval_us; + l3g4200d_update_odr(gyro, interval_us); + mutex_unlock(&gyro->lock); + return size; +} + +static ssize_t attr_range_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct l3g4200d_data *gyro = dev_get_drvdata(dev); + int range = 0; + char val; + mutex_lock(&gyro->lock); + val = gyro->pdata->fs_range; + switch (val) { + case L3G4200D_GYR_FS_250DPS: + range = 250; + break; + case L3G4200D_GYR_FS_500DPS: + range = 500; + break; + case L3G4200D_GYR_FS_2000DPS: + range = 2000; + break; + } + mutex_unlock(&gyro->lock); + return sprintf(buf, "%d\n", range); +} + +static ssize_t attr_range_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct l3g4200d_data *gyro = dev_get_drvdata(dev); + unsigned long val; + if (strict_strtoul(buf, 10, &val)) + return -EINVAL; + mutex_lock(&gyro->lock); + gyro->pdata->fs_range = val; + l3g4200d_update_fs_range(gyro, val); + mutex_unlock(&gyro->lock); + return size; +} + +static ssize_t attr_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct l3g4200d_data *gyro = dev_get_drvdata(dev); + int val = atomic_read(&gyro->enabled); + return sprintf(buf, "%d\n", val); +} + +static ssize_t attr_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct l3g4200d_data *gyro = dev_get_drvdata(dev); + unsigned long val; + + if (strict_strtoul(buf, 10, &val)) + return -EINVAL; + + if (val) { + l3g4200d_enable(gyro); + l3g4200d_set_delay(gyro, gyro->pdata->poll_interval); + } + else + l3g4200d_disable(gyro); + + return size; +} + +static ssize_t attr_get_selftest(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int val; + struct l3g4200d_data *gyro = dev_get_drvdata(dev); + mutex_lock(&gyro->lock); + val = gyro->selftest_enabled; + mutex_unlock(&gyro->lock); + return sprintf(buf, "%d\n", val); +} + +static ssize_t attr_set_selftest(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct l3g4200d_data *gyro = dev_get_drvdata(dev); + unsigned long val; + + if (strict_strtoul(buf, 10, &val)) + return -EINVAL; + + l3g4200d_selftest(gyro, val); + + return size; +} + +#ifdef DEBUG +static ssize_t attr_reg_set(struct device *dev, struct device_attribute *attr, + const char *buf, size_t size) +{ + int rc; + struct l3g4200d_data *gyro = dev_get_drvdata(dev); + u8 x[2]; + unsigned long val; + + if (strict_strtoul(buf, 16, &val)) + return -EINVAL; + mutex_lock(&gyro->lock); + x[0] = gyro->reg_addr; + mutex_unlock(&gyro->lock); + x[1] = val; + rc = l3g4200d_i2c_write(gyro, x, 1); + return size; +} + +static ssize_t attr_reg_get(struct device *dev, struct device_attribute *attr, + char *buf) +{ + ssize_t ret; + struct l3g4200d_data *gyro = dev_get_drvdata(dev); + int rc; + u8 data; + + mutex_lock(&gyro->lock); + data = gyro->reg_addr; + mutex_unlock(&gyro->lock); + rc = l3g4200d_i2c_read(gyro, &data, 1); + ret = sprintf(buf, "0x%02x\n", data); + return ret; +} + +static ssize_t attr_addr_set(struct device *dev, struct device_attribute *attr, + const char *buf, size_t size) +{ + struct l3g4200d_data *gyro = dev_get_drvdata(dev); + unsigned long val; + + if (strict_strtoul(buf, 16, &val)) + return -EINVAL; + + mutex_lock(&gyro->lock); + + gyro->reg_addr = val; + + mutex_unlock(&gyro->lock); + + return size; +} + +static ssize_t attr_get_printlog(struct device * dev,struct device_attribute * attr, + char * buf) +{ + ssize_t ret; + + ret = sprintf(buf, "%d\n", enable_print_log); + + return ret; +} + +static ssize_t attr_set_printlog(struct device *dev, struct device_attribute *attr, + const char *buf, size_t size) +{ + unsigned long val; + + if (strict_strtoul(buf, 10, &val)) + return -EINVAL; + + enable_print_log = val; + + return size; +} + +#endif /* DEBUG */ + +static struct device_attribute attributes[] = { + __ATTR(pollrate_ms, 0666, attr_polling_rate_show, + attr_polling_rate_store), + __ATTR(range, 0666, attr_range_show, attr_range_store), + __ATTR(enable_device, 0666, attr_enable_show, attr_enable_store), + __ATTR(enable_selftest, 0666, attr_get_selftest, attr_set_selftest), +#ifdef DEBUG + __ATTR(reg_value, 0600, attr_reg_get, attr_reg_set), + __ATTR(reg_addr, 0200, NULL, attr_addr_set), + __ATTR(printlog, 0600, attr_get_printlog, attr_set_printlog), +#endif +}; + +static int create_sysfs_interfaces(struct device *dev) +{ + int i; + for (i = 0; i < ARRAY_SIZE(attributes); i++) + if (device_create_file(dev, attributes + i)) + goto error; + return 0; + +error: + for ( ; i >= 0; i--) + device_remove_file(dev, attributes + i); + dev_err(dev, "%s:Unable to create interface\n", __func__); + return -1; +} + +static int remove_sysfs_interfaces(struct device *dev) +{ + int i; + for (i = 0; i < ARRAY_SIZE(attributes); i++) + device_remove_file(dev, attributes + i); + return 0; +} + +static void l3g4200d_data_report(struct l3g4200d_data *gyro) +{ + struct l3g4200d_triple data_out; + int err; + + err = l3g4200d_get_data(gyro, &data_out); + if (err) + dev_err(&gyro->client->dev, "get_gyroscope_data failed\n"); + else + l3g4200d_report_values(gyro, &data_out); + +} + +static int l3g4200d_validate_pdata(struct l3g4200d_data *gyro) +{ + gyro->pdata->poll_interval = max(gyro->pdata->poll_interval, + gyro->pdata->min_interval); + + if (gyro->pdata->axis_map_x > 2 || + gyro->pdata->axis_map_y > 2 || + gyro->pdata->axis_map_z > 2) { + dev_err(&gyro->client->dev, + "invalid axis_map value x:%u y:%u z%u\n", + gyro->pdata->axis_map_x, + gyro->pdata->axis_map_y, + gyro->pdata->axis_map_z); + return -EINVAL; + } + + /* Only allow 1 and -1 for direction flag */ + if (abs(gyro->pdata->direction_x) != 1 || + abs(gyro->pdata->direction_y) != 1 || + abs(gyro->pdata->direction_z) != 1) { + dev_err(&gyro->client->dev, + "invalid direction value x:%d y:%d z:%d\n", + gyro->pdata->direction_x, + gyro->pdata->direction_y, + gyro->pdata->direction_z); + return -EINVAL; + } + + /* Enforce minimum polling interval */ + if (gyro->pdata->poll_interval < gyro->pdata->min_interval) { + dev_err(&gyro->client->dev, + "minimum poll interval violated\n"); + return -EINVAL; + } + return 0; +} + +static int l3g4200d_misc_open(struct inode *inode, struct file *file) +{ + int err; + + err = nonseekable_open(inode, file); + if(err < 0) + return err; + + file->private_data = i2c_get_clientdata(l3g4200d_i2c_client); + + return 0; +} + +static int l3g4200d_misc_close(struct inode *inode, struct file *filp) +{ + return 0; +} + + +static long l3g4200d_misc_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + void __user *argp = (void __user *)arg; + int interval, val; + int err = -1; + struct l3g4200d_data *gyro = file->private_data; + + switch(cmd){ + case GYRO_IOCTL_GET_DELAY: + interval = gyro->pdata->poll_interval; + if(copy_to_user(argp, &interval, sizeof(interval))) + return -EFAULT; + break; + + case GYRO_IOCTL_SET_DELAY: + if(copy_from_user(&interval, argp, sizeof(interval))) + return -EFAULT; + err = l3g4200d_set_delay(gyro, interval); + if(err < 0) + return err; + break; + + case GYRO_IOCTL_SET_ENABLE: + if(copy_from_user(&val, argp, sizeof(val))) + return -EFAULT; + if(val > 1) + return -EINVAL; + + if(val) + l3g4200d_enable(gyro); + else + l3g4200d_disable(gyro); + break; + + case GYRO_IOCTL_GET_ENABLE: + val = atomic_read(&gyro->enabled); + if(copy_to_user(argp, &val, sizeof(val))) + return -EINVAL; + break; + + case WMT_IOCTL_SENSOR_GET_DRVID: + val = L3G4200D_DRVID; + if (copy_to_user(argp, &val, sizeof(val))) + return -EFAULT; + break; + + default: + return -EINVAL; + } + + return 0; +} + +static const struct file_operations l3g4200d_misc_fops = { + .owner = THIS_MODULE, + .open = l3g4200d_misc_open, + .unlocked_ioctl = l3g4200d_misc_ioctl, + .release = l3g4200d_misc_close, +}; + +static struct miscdevice l3g4200d_misc_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = GYRO_MISCDEV_NAME, + .fops = &l3g4200d_misc_fops, +}; + +static int l3g4200d_input_init(struct l3g4200d_data *gyro) +{ + int err = -1; + struct input_dev *input; + + gyro->input_dev = input_allocate_device(); + if (!gyro->input_dev) { + err = -ENOMEM; + dev_err(&gyro->client->dev, + "input device allocate failed\n"); + goto err0; + } + + input = gyro->input_dev; + + input_set_drvdata(input, gyro); + + set_bit(EV_ABS, input->evbit); + + input_set_abs_params(input, ABS_X, -FS_MAX, FS_MAX, FUZZ, FLAT); + input_set_abs_params(input, ABS_Y, -FS_MAX, FS_MAX, FUZZ, FLAT); + input_set_abs_params(input, ABS_Z, -FS_MAX, FS_MAX, FUZZ, FLAT); + + input->name = GYRO_INPUT_NAME; + + err = input_register_device(input); + if (err) { + dev_err(&gyro->client->dev, + "unable to register input polled device %s\n", + input->name); + goto err1; + } + + return 0; + +err1: + input_free_device(input); +err0: + return err; +} + +static void l3g4200d_input_cleanup(struct l3g4200d_data *gyro) +{ + input_unregister_device(gyro->input_dev); + input_free_device(gyro->input_dev); +} + +static int l3g4300d_detect(struct i2c_client *client) +{ + int ret; + u8 buf[1]; + struct l3g4200d_data gyro; + + gyro.client = client; + + ret = l3g4200d_register_read(&gyro, buf, WHO_AM_I); + if(ret) + return 0; + + if(buf[0] != WHOAMI_L3G4200D){ + dev_err(&client->dev, "chipId = 0x%02X, error", buf[0]); + return 0; + } + + return 1; +} + +static irqreturn_t gyro_irq_handler(int irq, void *dev_id) +{ + if(!gpio_irqstatus(L3G4200D_IRQ_PIN)) + return IRQ_NONE; + + wmt_gpio_ack_irq(L3G4200D_IRQ_PIN); //clear interrupt + + //printk("got gyro interrupt\n"); + if(!is_gpio_irqenable(L3G4200D_IRQ_PIN)) { + //pr_err("l3g4200d irq is disabled\n"); + return IRQ_HANDLED; + }else + return IRQ_WAKE_THREAD; +} + +static irqreturn_t gyro_irq_thread(int irq, void *dev) +{ + struct l3g4200d_data *gyro = dev; + + l3g4200d_data_report(gyro); + + return IRQ_HANDLED; +} + +static void l3g4200d_enable_work_func(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct l3g4200d_data *gyro = + container_of(dwork, struct l3g4200d_data, enable_work); + + l3g4200d_flush_gyro_data(gyro); + l3g4200d_gpio_irq_enable(); +} + +static void l3g4200d_input_poll_func(struct work_struct *work) +{ + struct l3g4200d_triple data; + struct delayed_work *dwork = to_delayed_work(work); + struct l3g4200d_data *gyro = + container_of(dwork, struct l3g4200d_data, input_work); + + if(flush_polling_data == 0) + l3g4200d_data_report(gyro); + else { + l3g4200d_get_data(gyro, &data); //flush the first data + flush_polling_data = 0; + } + + schedule_delayed_work(&gyro->input_work, + usecs_to_jiffies(gyro->pdata->poll_interval)); +} + +static int l3g4200d_param_parse(int *p_int_mode, struct l3g4200d_gyr_platform_data *pdata) +{ + char varbuf[64] = {0}; + int n, ret, varlen; + int tmp[7]; + + varlen = sizeof(varbuf); + + ret = wmt_getsyspara("wmt.io.gyro.l3g4200d", varbuf, &varlen); + if(ret) + return 0; + + n = sscanf(varbuf, "%d:%d:%d:%d:%d:%d:%d", + &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5], &tmp[6]); + + if(n != 7) { + pr_err("l3g4200d-gyro param format error\n"); + return -1; + } + + pdata->axis_map_x = tmp[0]; + pdata->direction_x = tmp[1]; + pdata->axis_map_y = tmp[2]; + pdata->direction_y = tmp[3]; + pdata->axis_map_z = tmp[4]; + pdata->direction_z = tmp[5]; + *p_int_mode = tmp[6]; + + return 0; +} + +static int l3g4200d_probe(struct i2c_client *client, + const struct i2c_device_id *devid) +{ + struct l3g4200d_data *gyro; + int err = -1; + u8 buf[2]; + + pr_info("%s: probe start.\n", L3G4200D_GYR_DEV_NAME); + + if (client->dev.platform_data == NULL) { + dev_err(&client->dev, "platform data is NULL. exiting.\n"); + err = -ENODEV; + goto err0; + } + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, "client not i2c capable:1\n"); + err = -ENODEV; + goto err0; + } + + if(l3g4300d_detect(client) == 0){ + dev_err(&client->dev, "not found the gyro\n"); + err = -ENODEV; + goto err0; + } + + gyro = kzalloc(sizeof(*gyro), GFP_KERNEL); + if (gyro == NULL) { + dev_err(&client->dev, + "failed to allocate memory for module data\n"); + err = -ENOMEM; + goto err0; + } + + l3g4200d_param_parse(&interrupt_mode, client->dev.platform_data); + if(interrupt_mode) { + pr_info("l3g4200d-gyro in interrupt mode\n"); + err = l3g4200d_irq_hw_init(0); + if(err) + goto err0; + } + else + pr_info("l3g4200d-gyro in polling mode\n"); + + mutex_init(&gyro->lock); + mutex_lock(&gyro->lock); + gyro->client = client; + + gyro->pdata = kmalloc(sizeof(*gyro->pdata), GFP_KERNEL); + if (gyro->pdata == NULL) { + dev_err(&client->dev, + "failed to allocate memory for pdata: %d\n", err); + goto err1; + } + memcpy(gyro->pdata, client->dev.platform_data, + sizeof(*gyro->pdata)); + + err = l3g4200d_validate_pdata(gyro); + if (err < 0) { + dev_err(&client->dev, "failed to validate platform data\n"); + goto err1_1; + } + + i2c_set_clientdata(client, gyro); + + if (gyro->pdata->init) { + err = gyro->pdata->init(); + if (err < 0) { + dev_err(&client->dev, "init failed: %d\n", err); + goto err1_1; + } + } + + if(interrupt_mode) + gyro->pdata->init_state.ctrl_reg3 |= I2_DRDY; + + //According to the introduction of L3G4200D's datasheet page 32, + //the bit7 and bit6 of CTRL_REG2's value is loaded at boot. This value must not be changed + buf[0] = CTRL_REG2; + err = l3g4200d_i2c_read(gyro, buf, 1); + if(err) + goto err1_1; + + gyro->pdata->init_state.ctrl_reg2 = (gyro->pdata->init_state.ctrl_reg2 & 0x1F) + | (buf[0] & 0xC0); + + gyro->pdata->init_state.ctrl_reg1 &= ~PM_MASK; + + memcpy(&gyro->resume_state, &gyro->pdata->init_state, + sizeof(struct reg_value_t)); + + err = l3g4200d_hw_init(gyro); + if (err) { + dev_err(&client->dev, "hardware init failed: %d\n", err); + goto err2; + } + + err = l3g4200d_input_init(gyro); + if (err < 0) + goto err3; + + err = create_sysfs_interfaces(&client->dev); + if (err < 0) { + dev_err(&client->dev, + "%s device register failed\n", L3G4200D_GYR_DEV_NAME); + goto err4; + } + + /* As default, do not report information */ + atomic_set(&gyro->enabled, 0); + + if(interrupt_mode) + INIT_DELAYED_WORK(&gyro->enable_work, l3g4200d_enable_work_func); + else + INIT_DELAYED_WORK(&gyro->input_work, l3g4200d_input_poll_func); + + err = misc_register(&l3g4200d_misc_device); + if(err){ + dev_err(&client->dev, "l3g4200d_device register failed\n"); + goto err5; + } + + if(interrupt_mode) { + err = request_threaded_irq(gyro->client->irq, gyro_irq_handler, + gyro_irq_thread, IRQF_SHARED, L3G4200D_GYR_DEV_NAME, gyro); + + if(err) { + pr_err("%s: irq request failed: %d\n", __func__, err); + err = -ENODEV; + goto err6; + } + } + + mutex_unlock(&gyro->lock); + +#ifdef DEBUG + pr_info("%s probed: device created successfully\n", + L3G4200D_GYR_DEV_NAME); +#endif + + return 0; + +err6: + misc_deregister(&l3g4200d_misc_device); +err5: + remove_sysfs_interfaces(&client->dev); +err4: + l3g4200d_input_cleanup(gyro); +err3: + l3g4200d_device_power_off(gyro); +err2: + if (gyro->pdata->exit) + gyro->pdata->exit(); +err1_1: + mutex_unlock(&gyro->lock); + kfree(gyro->pdata); +err1: + kfree(gyro); + if(interrupt_mode) + l3g4200d_irq_hw_free(); +err0: + pr_err("%s: Driver Initialization failed\n", + L3G4200D_GYR_DEV_NAME); + return err; +} + +static int l3g4200d_remove(struct i2c_client *client) +{ + struct l3g4200d_data *gyro = i2c_get_clientdata(client); +#ifdef DEBUG + pr_info(KERN_INFO "L3G4200D driver removing\n"); +#endif + + l3g4200d_disable(gyro); + if(interrupt_mode) { + free_irq(gyro->client->irq, gyro); + l3g4200d_irq_hw_free(); + } + misc_deregister(&l3g4200d_misc_device); + l3g4200d_input_cleanup(gyro); + remove_sysfs_interfaces(&client->dev); + kfree(gyro->pdata); + kfree(gyro); + return 0; +} + +static void l3g4200d_shutdown(struct i2c_client *client) +{ + struct l3g4200d_data *gyro = i2c_get_clientdata(client); + + pr_info("l3g4200d_shutdown\n"); + + l3g4200d_disable(gyro); +} + + +static int l3g4200d_suspend(struct device *dev) +{ + struct l3g4200d_data *gyro = i2c_get_clientdata(l3g4200d_i2c_client); + int err; + u8 buf[8]; + + pr_info(KERN_INFO "l3g4200d_suspend\n"); + + if(atomic_read(&gyro->enabled)) { + if(interrupt_mode) { + cancel_delayed_work_sync(&gyro->enable_work); + l3g4200d_gpio_irq_disable(); + } + else + cancel_delayed_work_sync(&gyro->input_work); + + //store register value + buf[0] = (AUTO_INCREMENT | CTRL_REG1); + err = l3g4200d_i2c_read(gyro, buf, 6); + if(err) + goto err1; + gyro->resume_state.ctrl_reg1 = buf[0]; + gyro->resume_state.ctrl_reg2 = buf[1]; + gyro->resume_state.ctrl_reg3 = buf[2]; + gyro->resume_state.ctrl_reg4 = buf[3]; + gyro->resume_state.ctrl_reg5 = buf[4]; + gyro->resume_state.ref_datacap = buf[5]; + + buf[0] = FIFO_CTRL_REG; + err = l3g4200d_i2c_read(gyro, buf, 1); + if(err) + goto err1; + gyro->resume_state.fifo_ctrl_reg = buf[0]; + + buf[0] = INT1_CFG; + err = l3g4200d_i2c_read(gyro, buf, 1); + if(err) + goto err1; + gyro->resume_state.int1_cfg = buf[0]; + + buf[0] = (AUTO_INCREMENT | INT1_THS_XH); + err = l3g4200d_i2c_read(gyro, buf, 7); + if(err) + goto err1; + + gyro->resume_state.int1_ths_xh = buf[0]; + gyro->resume_state.int1_ths_xl = buf[1]; + gyro->resume_state.int1_ths_yh = buf[2]; + gyro->resume_state.int1_ths_yl = buf[3]; + gyro->resume_state.int1_ths_zh = buf[4]; + gyro->resume_state.int1_ths_zl = buf[5]; + gyro->resume_state.int1_duration = buf[6]; + } + + goto exit1; + +err1: + dev_err(&gyro->client->dev, "save register value fail at suspend\n"); + memcpy(&gyro->resume_state, &gyro->pdata->init_state, + sizeof(struct reg_value_t)); +exit1: + l3g4200d_device_power_off(gyro); + + if (gyro->hw_initialized) + gyro->hw_initialized = 0; + + return 0; +} + +static int l3g4200d_resume(struct device *dev) +{ + struct l3g4200d_data *gyro = i2c_get_clientdata(l3g4200d_i2c_client); + int err; + + pr_info(KERN_INFO "l3g4200d_resume\n"); + + if(interrupt_mode) + l3g4200d_irq_hw_init(1); + + if(atomic_read(&gyro->enabled)) { + + err = l3g4200d_device_power_on(gyro); + if(err) + { + dev_err(&gyro->client->dev, "power_on failed at resume\n"); + atomic_set(&gyro->enabled, 0); + + return 0; + } + + //do not report noise at IC power-up + // flush data before really read + if(interrupt_mode) + schedule_delayed_work(&gyro->enable_work, msecs_to_jiffies( + L3G4200D_PU_DELAY)); + else { + flush_polling_data = 1; + schedule_delayed_work(&gyro->input_work, msecs_to_jiffies( + L3G4200D_PU_DELAY)); + } + }else { + memcpy(&gyro->resume_state, &gyro->pdata->init_state, + sizeof(struct reg_value_t)); + + err = l3g4200d_hw_init(gyro); + if (err) + dev_err(&gyro->client->dev, "hardware init failed at resume\n"); + } + + return 0; +} + +static const struct i2c_device_id l3g4200d_id[] = { + { L3G4200D_GYR_DEV_NAME , 0 }, + {}, +}; + +MODULE_DEVICE_TABLE(i2c, l3g4200d_id); + +static struct dev_pm_ops l3g4200d_pm = { + .suspend = l3g4200d_suspend, + .resume = l3g4200d_resume, +}; + +static struct i2c_driver l3g4200d_driver = { + .driver = { + .owner = THIS_MODULE, + .name = L3G4200D_GYR_DEV_NAME, + .pm = &l3g4200d_pm, + }, + .probe = l3g4200d_probe, + .remove = __devexit_p(l3g4200d_remove), + .shutdown = l3g4200d_shutdown, + .id_table = l3g4200d_id, +}; + +static struct l3g4200d_gyr_platform_data gyr_drvr_platform_data={ + .poll_interval = 10000, // us + .min_interval = 1250, // us + + .fs_range = L3G4200D_GYR_FS_2000DPS, + + .axis_map_x = 0, + .axis_map_y = 1, + .axis_map_z = 2, + + .direction_x = 1, + .direction_y = -1, + .direction_z = -1, + + .init_state.ctrl_reg1 = 0x17, //ODR100 + .init_state.ctrl_reg2 = 0x00, + .init_state.ctrl_reg3 = 0x00, //DRDY interrupt + .init_state.ctrl_reg4 = 0xA0, //BDU enable, 2000 dps + .init_state.ctrl_reg5 = 0x00, + .init_state.ref_datacap = 0x00, + .init_state.fifo_ctrl_reg = 0x00, + .init_state.int1_cfg = 0x00, + .init_state.int1_ths_xh = 0x00, + .init_state.int1_ths_xl = 0x00, + .init_state.int1_ths_yh = 0x00, + .init_state.int1_ths_yl = 0x00, + .init_state.int1_ths_zh = 0x00, + .init_state.int1_ths_zl = 0x00, + .init_state.int1_duration = 0x00 +}; + +static struct i2c_board_info __initdata l3g4200d_i2c_board[] = { + { + I2C_BOARD_INFO(L3G4200D_GYR_DEV_NAME, L3G4200D_I2C_ADDR), + .irq = IRQ_GPIO, + .platform_data = &gyr_drvr_platform_data, + }, +}; + +static int __init l3g4200d_init(void) +{ + int ret; + struct i2c_adapter *adapter; + +#ifdef DEBUG + pr_info("%s: gyroscope sysfs driver init\n", L3G4200D_GYR_DEV_NAME); +#endif + + adapter = i2c_get_adapter(0); + if (adapter == NULL) { + pr_err("%s: i2c_get_adapter() error\n", L3G4200D_GYR_DEV_NAME); + return -ENODEV; + } + + l3g4200d_i2c_client = i2c_new_device(adapter, l3g4200d_i2c_board); + if (l3g4200d_i2c_client == NULL) { + pr_err("%s: i2c_new_device() error\n", L3G4200D_GYR_DEV_NAME); + return -ENOMEM; + } + + i2c_put_adapter(adapter); + + ret = i2c_add_driver(&l3g4200d_driver); + if(ret){ + pr_err("%s: i2c_add_driver() failed\n", L3G4200D_GYR_DEV_NAME); + i2c_unregister_device(l3g4200d_i2c_client); + return ret; + } + + return ret; +} + +static void __exit l3g4200d_exit(void) +{ +#ifdef DEBUG + pr_info("L3G4200D exit\n"); +#endif + + i2c_del_driver(&l3g4200d_driver); + i2c_unregister_device(l3g4200d_i2c_client); + + return; +} + +module_init(l3g4200d_init); +module_exit(l3g4200d_exit); + +MODULE_DESCRIPTION("l3g4200d digital gyroscope sysfs driver"); +MODULE_AUTHOR("Matteo Dameno, Carmine Iascone, STMicroelectronics"); +MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/input/sensor/mc3230_gsensor/Makefile b/ANDROID_3.4.5/drivers/input/sensor/mc3230_gsensor/Makefile new file mode 100755 index 00000000..8a419fc7 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/mc3230_gsensor/Makefile @@ -0,0 +1,34 @@ +KERNELDIR=../../../../ +#KERNELDIR=/home/hangyan/android8850/kernel/ANDROID_3.0.8 +CROSS = arm_1103_le- +CC= $(CROSS)gcc +LD= $(CROSS)ld +STRIP = $(CROSS)strip + +DEBUG = n + +# Add your debugging flag (or not) to EXTRA_CFLAGS +ifeq ($(DEBUG),y) +# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines +DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines + +else + DEBFLAGS = -O2 -Wall +endif + +EXTRA_CFLAGS += $(DEBFLAGS) + + +MY_MODULE_NAME=s_wmt_gsensor_mc3230 + +obj-m := $(MY_MODULE_NAME).o +$(MY_MODULE_NAME)-objs := mc32x0.o + +default: + $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules + $(STRIP) --strip-debug $(MY_MODULE_NAME).ko + rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions + +clean: + rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers + diff --git a/ANDROID_3.4.5/drivers/input/sensor/mc3230_gsensor/mc32x0.c b/ANDROID_3.4.5/drivers/input/sensor/mc3230_gsensor/mc32x0.c new file mode 100755 index 00000000..4330dbb6 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/mc3230_gsensor/mc32x0.c @@ -0,0 +1,2580 @@ +/* Date: 2011/4/8 11:00:00 + * Revision: 2.5 + */ + +/* + * This software program is licensed subject to the GNU General Public License + * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html + + * (C) Copyright 2011 Bosch Sensortec GmbH + * All Rights Reserved + */ + + +/* file mc32x0.c + brief This file contains all function implementations for the mc32x0 in linux + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include + +//#include +#include +#include + +#include "../sensor.h" +#include "mc32x0_driver.h" + + +#if 0 +#define mcprintkreg(x...) printk(x) +#else +#define mcprintkreg(x...) +#endif + +#if 0 +#define mcprintkfunc(x...) printk(x) +#else +#define mcprintkfunc(x...) +#endif + +#if 0 +#define GSE_ERR(x...) printk(x) +#define GSE_LOG(x...) printk(x) +#else +#define GSE_ERR(x...) +#define GSE_LOG(x...) +#endif + +static int g_virtual_z = 0; +#define G_2_REVERSE_VIRTUAL_Z 0 //!!!!! 1 +#define SUPPORT_VIRTUAL_Z_SENSOR //add 2013-10-23 +#define LOW_RESOLUTION 1 +#define HIGH_RESOLUTION 2 +#define RBM_RESOLUTION 3 +#ifdef SUPPORT_VIRTUAL_Z_SENSOR +#define Low_Pos_Max 127 +#define Low_Neg_Max -128 +#define High_Pos_Max 8191 +#define High_Neg_Max -8192 +#define VIRTUAL_Z 1 +static int Railed = 0; +#else +#define VIRTUAL_Z 0 +#endif + + +static struct class* l_dev_class = NULL; + + + + +#define GSENSOR_NAME "mc3230" +#define SENSOR_DATA_SIZE 3 +#define AVG_NUM 16 +/* Addresses to scan */ +//static const unsigned short normal_i2c[2] = {0x00,I2C_CLIENT_END}; + + +//volatile unsigned char mc32x0_on_off=0; +//static int mc32x0_pin_hd; +static char mc32x0_on_off_str[32]; +#define G_0 ABS_X +#define G_1 ABS_Y +#define G_2 ABS_Z +#define G_0_REVERSE 1 +#define G_1_REVERSE 1 +#define G_2_REVERSE -1 + +#define GRAVITY_1G_VALUE 1000 + +#define SENSOR_DMARD_IOCTL_BASE 234 + +#define IOCTL_SENSOR_SET_DELAY_ACCEL _IO(SENSOR_DMARD_IOCTL_BASE, 100) +#define IOCTL_SENSOR_GET_DELAY_ACCEL _IO(SENSOR_DMARD_IOCTL_BASE, 101) +#define IOCTL_SENSOR_GET_STATE_ACCEL _IO(SENSOR_DMARD_IOCTL_BASE, 102) +#define IOCTL_SENSOR_SET_STATE_ACCEL _IO(SENSOR_DMARD_IOCTL_BASE, 103) +#define IOCTL_SENSOR_GET_DATA_ACCEL _IO(SENSOR_DMARD_IOCTL_BASE, 104) + +#define IOCTL_MSENSOR_SET_DELAY_MAGNE _IO(SENSOR_DMARD_IOCTL_BASE, 200) +#define IOCTL_MSENSOR_GET_DATA_MAGNE _IO(SENSOR_DMARD_IOCTL_BASE, 201) +#define IOCTL_MSENSOR_GET_STATE_MAGNE _IO(SENSOR_DMARD_IOCTL_BASE, 202) +#define IOCTL_MSENSOR_SET_STATE_MAGNE _IO(SENSOR_DMARD_IOCTL_BASE, 203) + +#define IOCTL_SENSOR_GET_NAME _IO(SENSOR_DMARD_IOCTL_BASE, 301) +#define IOCTL_SENSOR_GET_VENDOR _IO(SENSOR_DMARD_IOCTL_BASE, 302) + +#define IOCTL_SENSOR_GET_CONVERT_PARA _IO(SENSOR_DMARD_IOCTL_BASE, 401) + +#define SENSOR_CALIBRATION _IOWR(SENSOR_DMARD_IOCTL_BASE, 402, int[SENSOR_DATA_SIZE]) + + +#define mc32x0_CONVERT_PARAMETER (1.5f * (9.80665f) / 256.0f) +//#define mc32x0_DISPLAY_NAME "mc32x0" +//#define mc32x0_DIPLAY_VENDOR "domintech" + +#define X_OUT 0x41 +#define CONTROL_REGISTER 0x44 +#define SW_RESET 0x53 +#define WHO_AM_I 0x0f +#define WHO_AM_I_VALUE 0x06 + +#define MC32X0_AXIS_X 0 +#define MC32X0_AXIS_Y 1 +#define MC32X0_AXIS_Z 2 +#define MC32X0_AXES_NUM 3 +#define MC32X0_DATA_LEN 6 + +#define MC32X0_XOUT_REG 0x00 +#define MC32X0_YOUT_REG 0x01 +#define MC32X0_ZOUT_REG 0x02 +#define MC32X0_Tilt_Status_REG 0x03 +#define MC32X0_Sampling_Rate_Status_REG 0x04 +#define MC32X0_Sleep_Count_REG 0x05 +#define MC32X0_Interrupt_Enable_REG 0x06 +#define MC32X0_Mode_Feature_REG 0x07 +#define MC32X0_Sample_Rate_REG 0x08 +#define MC32X0_Tap_Detection_Enable_REG 0x09 +#define MC32X0_TAP_Dwell_Reject_REG 0x0a +#define MC32X0_DROP_Control_Register_REG 0x0b +#define MC32X0_SHAKE_Debounce_REG 0x0c +#define MC32X0_XOUT_EX_L_REG 0x0d +#define MC32X0_XOUT_EX_H_REG 0x0e +#define MC32X0_YOUT_EX_L_REG 0x0f +#define MC32X0_YOUT_EX_H_REG 0x10 +#define MC32X0_ZOUT_EX_L_REG 0x11 +#define MC32X0_ZOUT_EX_H_REG 0x12 +#define MC32X0_CHIP_ID_REG 0x18 +#define MC32X0_RANGE_Control_REG 0x20 +#define MC32X0_SHAKE_Threshold_REG 0x2B +#define MC32X0_UD_Z_TH_REG 0x2C +#define MC32X0_UD_X_TH_REG 0x2D +#define MC32X0_RL_Z_TH_REG 0x2E +#define MC32X0_RL_Y_TH_REG 0x2F +#define MC32X0_FB_Z_TH_REG 0x30 +#define MC32X0_DROP_Threshold_REG 0x31 +#define MC32X0_TAP_Threshold_REG 0x32 +#define MC32X0_HIGH_END 0x01 +/*******MC3210/20 define this**********/ + + +#define MCUBE_8G_14BIT 0x10 + +#define DOT_CALI + +#define MC32X0_LOW_END 0x02 +/*******mc32x0 define this**********/ + +#define MCUBE_1_5G_8BIT 0x20 +//#define MCUBE_1_5G_8BIT_TAP +//#define MCUBE_1_5G_6BIT +#define MC32X0_MODE_DEF 0x43 + +#define MC32X0ADDRESS 0x4c + +#define mc32x0_I2C_NAME "mc32x0" +#define GSENSOR_DEV_COUNT 1 +#define GSENSOR_DURATION_MAX 200 +#define GSENSOR_DURATION_MIN 10 +#define GSENSOR_DURATION_DEFAULT 20 + +#define MAX_RETRY 20 +#define INPUT_FUZZ 0 +#define INPUT_FLAT 0 + +#define AUTO_CALIBRATION 0 + +static unsigned char is_new_mc34x0 = 0; +static unsigned char is_mc3250 = 0; + +static unsigned char McubeID=0; +#ifdef DOT_CALI +#define CALIB_PATH "/data/data/com.mcube.acc/files/mcube-calib.txt" +//MCUBE_BACKUP_FILE +#define BACKUP_CALIB_PATH "/data/misc/sensors/mcube-calib.txt" +//static char backup_buf[64]; +//MCUBE_BACKUP_FILE +#define DATA_PATH "/sdcard/mcube-register-map.txt" + +typedef struct { + unsigned short x; /**< X axis */ + unsigned short y; /**< Y axis */ + unsigned short z; /**< Z axis */ +} GSENSOR_VECTOR3D; + +static GSENSOR_VECTOR3D gsensor_gain; +static struct miscdevice mc32x0_device; + +//static struct file * fd_file = NULL; + +static mm_segment_t oldfs; +//add by Liang for storage offset data +static unsigned char offset_buf[9]; +static signed int offset_data[3]; +s16 G_RAW_DATA[3]; +static signed int gain_data[3]; +static signed int enable_RBM_calibration = 0; +#endif + +#ifdef DOT_CALI + +#if 1 +#define GSENSOR 0xA1//0x95 + +#define GSENSOR_IOCTL_INIT _IO(GSENSOR, 0x01) +#define GSENSOR_IOCTL_READ_CHIPINFO _IOR(GSENSOR, 0x02, int) +#define GSENSOR_IOCTL_READ_SENSORDATA _IOR(GSENSOR, 0x17, int) +#define GSENSOR_IOCTL_READ_OFFSET _IOR(GSENSOR, 0x04, GSENSOR_VECTOR3D) +#define GSENSOR_IOCTL_READ_GAIN _IOR(GSENSOR, 0x05, GSENSOR_VECTOR3D) +#define GSENSOR_IOCTL_READ_RAW_DATA _IOR(GSENSOR, 0x30, int) +//#define GSENSOR_IOCTL_SET_CALI _IOW(GSENSOR, 0x06, SENSOR_DATA) +#define GSENSOR_IOCTL_GET_CALI _IOW(GSENSOR, 0x22, SENSOR_DATA) +#define GSENSOR_IOCTL_CLR_CALI _IO(GSENSOR, 0x23) +#define GSENSOR_MCUBE_IOCTL_READ_RBM_DATA _IOR(GSENSOR, 0x24, SENSOR_DATA) +#define GSENSOR_MCUBE_IOCTL_SET_RBM_MODE _IO(GSENSOR, 0x25) +#define GSENSOR_MCUBE_IOCTL_CLEAR_RBM_MODE _IO(GSENSOR, 0x26) +#define GSENSOR_MCUBE_IOCTL_SET_CALI _IOW(GSENSOR, 0x27, SENSOR_DATA) +#define GSENSOR_MCUBE_IOCTL_REGISTER_MAP _IO(GSENSOR, 0x28) +#define GSENSOR_IOCTL_SET_CALI_MODE _IOW(GSENSOR, 0x29,int) +#else + +#define GSENSOR_IOCTL_INIT 0xa1 +#define GSENSOR_IOCTL_READ_CHIPINFO 0xa2 +#define GSENSOR_IOCTL_READ_SENSORDATA 0xa3 +#define GSENSOR_IOCTL_READ_OFFSET 0xa4 +#define GSENSOR_IOCTL_READ_GAIN 0xa5 +#define GSENSOR_IOCTL_READ_RAW_DATA 0xa6 +#define GSENSOR_IOCTL_SET_CALI 0xa7 +#define GSENSOR_IOCTL_GET_CALI 0xa8 +#define GSENSOR_IOCTL_CLR_CALI 0xa9 + +#define GSENSOR_MCUBE_IOCTL_READ_RBM_DATA 0xaa +#define GSENSOR_MCUBE_IOCTL_SET_RBM_MODE 0xab +#define GSENSOR_MCUBE_IOCTL_CLEAR_RBM_MODE 0xac +#define GSENSOR_MCUBE_IOCTL_SET_CALI 0xad +#define GSENSOR_MCUBE_IOCTL_REGISTER_MAP 0xae +#define GSENSOR_IOCTL_SET_CALI_MODE 0xaf +#endif + +typedef struct{ + int x; + int y; + int z; +}SENSOR_DATA; + +static int load_cali_flg = 0; +//MCUBE_BACKUP_FILE +//static bool READ_FROM_BACKUP = false; +//MCUBE_BACKUP_FILE + +#endif + +#define MC32X0_WAKE 1 +#define MC32X0_SNIFF 2 +#define MC32X0_STANDBY 3 + +struct dev_data { + struct i2c_client *client; +}; +static struct dev_data dev; + +/* Addresses to scan */ +static const unsigned short normal_i2c[2] = {MC32X0ADDRESS, I2C_CLIENT_END}; + +/* +typedef union { + struct { + s16 x; + s16 y; + s16 z; + } u; + s16 v[SENSOR_DATA_SIZE]; +} raw_data; +static raw_data offset; +*/ + +struct acceleration { + int x; + int y; + int z; +}; + +//void gsensor_write_offset_to_file(void); +//void gsensor_read_offset_from_file(void); +//char OffsetFileName[] = "/data/misc/dmt/offset.txt"; +/*static struct sensor_config_info gsensor_info = { + .input_type = GSENSOR_TYPE, +};*/ + +static u32 debug_mask = 0; +#define dprintk(level_mask, fmt, arg...) if (unlikely(debug_mask & level_mask)) \ + printk(KERN_DEBUG fmt , ## arg) + +module_param_named(debug_mask, debug_mask, int, 0644); + + +enum { + DEBUG_INIT = 1U << 0, + DEBUG_CONTROL_INFO = 1U << 1, + DEBUG_DATA_INFO = 1U << 2, + DEBUG_SUSPEND = 1U << 3, +}; + +struct mc32x0_data { + struct mutex lock; + struct i2c_client *client; + struct delayed_work work; + struct workqueue_struct *mc32x0_wq; + struct hrtimer timer; + struct device *device; + struct input_dev *input_dev; + int use_count; + int enabled; + volatile unsigned int duration; + int use_irq; + int irq; + unsigned long irqflags; + int gpio; + unsigned int map[3]; + int inv[3]; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif + // for control + int int_gpio; //0-3 + int op; + int samp; + //int xyz_axis[3][3]; // (axis,direction) + struct proc_dir_entry* sensor_proc; + int isdbg; + int sensor_samp; // + int sensor_enable; // 0 --> disable sensor, 1 --> enable sensor + int test_pass; + int offset[MC32X0_AXES_NUM+1]; /*+1: for 4-byte alignment*/ + s16 data[MC32X0_AXES_NUM+1]; +}; + +static struct mc32x0_data l_sensorconfig = { + .op = 0, + .int_gpio = 3, + .samp = 16, + /*.xyz_axis = { + {ABS_X, -1}, + {ABS_Y, 1}, + {ABS_Z, -1}, + },*/ + .sensor_proc = NULL, + .isdbg = 1, + .sensor_samp = 1, // 1 sample/second + .sensor_enable = 1, // enable sensor + .test_pass = 0, // for test program + //.offset={0,0,0}, +}; + + +//============================================================================= +enum mc3xx0_orientation +{ + MC3XX0_TOP_LEFT_DOWN = 0, + MC3XX0_TOP_RIGHT_DOWN, + MC3XX0_TOP_RIGHT_UP, + MC3XX0_TOP_LEFT_UP, + MC3XX0_BOTTOM_LEFT_DOWN, + MC3XX0_BOTTOM_RIGHT_DOWN, + MC3XX0_BOTTOM_RIGHT_UP, + MC3XX0_BOTTOM_LEFT_UP +}; + +enum mc3xx0_axis +{ + MC3XX0_AXIS_X = 0, + MC3XX0_AXIS_Y, + MC3XX0_AXIS_Z, + MC3XX0_AXIS_NUM +}; + +struct mc3xx0_hwmsen_convert +{ + signed int sign[3]; + unsigned int map[3]; +}; + +// Transformation matrix for chip mounting position +static const struct mc3xx0_hwmsen_convert mc3xx0_cvt[] = +{ + {{ 1, 1, 1}, {MC3XX0_AXIS_X, MC3XX0_AXIS_Y, MC3XX0_AXIS_Z}}, // 0: top , left-down + {{-1, 1, 1}, {MC3XX0_AXIS_Y, MC3XX0_AXIS_X, MC3XX0_AXIS_Z}}, // 1: top , right-down + {{-1, -1, 1}, {MC3XX0_AXIS_X, MC3XX0_AXIS_Y, MC3XX0_AXIS_Z}}, // 2: top , right-up + {{ 1, -1, 1}, {MC3XX0_AXIS_Y, MC3XX0_AXIS_X, MC3XX0_AXIS_Z}}, // 3: top , left-up + {{-1, 1, -1}, {MC3XX0_AXIS_X, MC3XX0_AXIS_Y, MC3XX0_AXIS_Z}}, // 4: bottom, left-down + {{ 1, 1, -1}, {MC3XX0_AXIS_Y, MC3XX0_AXIS_X, MC3XX0_AXIS_Z}}, // 5: bottom, right-down + {{ 1, -1, -1}, {MC3XX0_AXIS_X, MC3XX0_AXIS_Y, MC3XX0_AXIS_Z}}, // 6: bottom, right-up + {{-1, -1, -1}, {MC3XX0_AXIS_Y, MC3XX0_AXIS_X, MC3XX0_AXIS_Z}}, // 7: bottom, left-up +}; + +//static unsigned char mc3xx0_current_placement = MC3XX0_BOTTOM_LEFT_DOWN; // current soldered placement +static struct mc3xx0_hwmsen_convert *pCvt; + +//volatile static short sensor_duration = SENSOR_DURATION_DEFAULT;//delay +//volatile static short sensor_state_flag = 1; + +#ifdef SUPPORT_VIRTUAL_Z_SENSOR //add 2013-10-23 +int Verify_Z_Railed(int AccData, int resolution) +{ + int status = 0; + GSE_LOG("%s: AccData = %d",__func__, AccData); + if(resolution == 1) // Low resolution + { + if((AccData >= Low_Pos_Max && AccData >=0)|| (AccData <= Low_Neg_Max && AccData < 0)) + { + status = 1; + GSE_LOG("%s: Railed at Low Resolution",__func__); + } + } + else if (resolution == 2) //High resolution + { + if((AccData >= High_Pos_Max && AccData >=0) || (AccData <= High_Neg_Max && AccData < 0)) + { + status = 1; + GSE_LOG("%s: Railed at High Resolution",__func__); + } + } + else if (resolution == 3) //High resolution + { + if((AccData >= Low_Pos_Max*3 && AccData >=0) || (AccData <= Low_Neg_Max*3 && AccData < 0)) + { + status = 1; + GSE_LOG("%s: Railed at High Resolution",__func__); + } + } + else + GSE_LOG("%s, Wrong resolution",__func__); + + return status; +} + +int SquareRoot(int x) +{ + int lowerbound; + int upperbound; + int root; + + if(x < 0) return -1; + if(x == 0 || x == 1) return x; + lowerbound = 1; + upperbound = x; + root = lowerbound + (upperbound - lowerbound)/2; + + while(root > x/root || root+1 <= x/(root+1)) + { + if(root > x/root) + { + upperbound = root; + } + else + { + lowerbound = root; + } + root = lowerbound + (upperbound - lowerbound)/2; + } + GSE_LOG("%s: Sqrt root is %d",__func__, root); + return root; +} +#endif + + +unsigned int sample_rate_2_memsec(unsigned int rate) +{ + return (1000/rate); +} + +static ssize_t mc32x0_map_show(struct device *dev, struct device_attribute *attr,char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct mc32x0_data *data; + int i; + data = i2c_get_clientdata(client); + for (i = 0; i< 3; i++) + { + if(data->inv[i] == 1) + { + switch(data->map[i]) + { + case ABS_X: + buf[i] = 'x'; + break; + case ABS_Y: + buf[i] = 'y'; + break; + case ABS_Z: + buf[i] = 'z'; + break; + default: + buf[i] = '_'; + break; + } + } + else + { + switch(data->map[i]) + { + case ABS_X: + buf[i] = 'X'; + break; + case ABS_Y: + buf[i] = 'Y'; + break; + case ABS_Z: + buf[i] = 'Z'; + break; + default: + buf[i] = '-'; + break; + } + } + } + sprintf(buf+3,"\r\n"); + return 5; +} +/* +//Function as i2c_master_send, and return 1 if operation is successful. +static int i2c_write_bytes(struct i2c_client *client, uint8_t *data, uint16_t len) +{ + struct i2c_msg msg; + int ret=-1; + + msg.flags = !I2C_M_RD; + msg.addr = client->addr; + msg.len = len; + msg.buf = data; + + ret=i2c_transfer(client->adapter, &msg,1); + return ret; +} + +static bool gsensor_i2c_test(struct i2c_client * client) +{ + int ret, retry; + uint8_t test_data[1] = { 0 }; //only write a data address. + + for(retry=0; retry < 2; retry++) + { + ret =i2c_write_bytes(client, test_data, 1); //Test i2c. + if (ret == 1) + break; + msleep(5); + } + + return ret==1 ? true : false; +} +*/ +/** + * gsensor_detect - Device detection callback for automatic device creation + * return value: + * = 0; success; + * < 0; err + */ + /* +static int gsensor_detect(struct i2c_client *client, struct i2c_board_info *info) +{ + struct i2c_adapter *adapter = client->adapter; + int ret; + + dprintk(DEBUG_INIT, "%s enter \n", __func__); + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -ENODEV; + + if(twi_id == adapter->nr){ + pr_info("%s: addr= %x\n",__func__,client->addr); + + ret = gsensor_i2c_test(client); + if(!ret){ + pr_info("%s:I2C connection might be something wrong or maybe the other gsensor equipment! \n",__func__); + return -ENODEV; + }else{ + pr_info("I2C connection sucess!\n"); + strlcpy(info->type, SENSOR_NAME, I2C_NAME_SIZE); + return 0; + } + + }else{ + return -ENODEV; + } +} +*/ +int mc32x0_set_image (struct i2c_client *client) +{ + int comres = 0; + unsigned char data; + + + data = i2c_smbus_read_byte_data(client, 0x3B); + //comres = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, 0x3B, &data, 1 ); + if((data == 0x19)||(data == 0x29)) + { + McubeID = 0x22; + } + else if((data == 0x90)||(data == 0xA8)) + { + McubeID = 0x11; + } + else + { + McubeID = 0; + } + + if (0x88 == data) + { + McubeID = 0x11; + is_mc3250 = 1; + } + + if (0x39 == data) + { + McubeID = 0x22; + is_new_mc34x0 = 1; + } + else if (0xB8 == data) + { + McubeID = 0x11; + is_new_mc34x0 = 1; + } + + + if(McubeID &MCUBE_8G_14BIT) + { + //#ifdef MCUBE_8G_14BIT + data = MC32X0_MODE_DEF; + //comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Mode_Feature_REG, &data, 1 ); + i2c_smbus_write_byte_data(client, MC32X0_Mode_Feature_REG,data); + data = 0x00; + //comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Sleep_Count_REG, &data, 1 ); + i2c_smbus_write_byte_data(client, MC32X0_Sleep_Count_REG,data); + data = 0x00; + //comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Sample_Rate_REG, &data, 1 ); + i2c_smbus_write_byte_data(client, MC32X0_Sample_Rate_REG,data); + data = 0x00; + //comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Tap_Detection_Enable_REG, &data, 1 ); + i2c_smbus_write_byte_data(client, MC32X0_Tap_Detection_Enable_REG,data); + data = 0x3F; + //comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_RANGE_Control_REG, &data, 1 ); + i2c_smbus_write_byte_data(client, MC32X0_RANGE_Control_REG,data); + data = 0x00; + //comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Interrupt_Enable_REG, &data, 1 ); + i2c_smbus_write_byte_data(client, MC32X0_Interrupt_Enable_REG,data); +#ifdef DOT_CALI + gsensor_gain.x = gsensor_gain.y = gsensor_gain.z = 1024; +#endif + //#endif + } + else if(McubeID &MCUBE_1_5G_8BIT) + { + #ifdef MCUBE_1_5G_8BIT + data = MC32X0_MODE_DEF; + //comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Mode_Feature_REG, &data, 1 ); + i2c_smbus_write_byte_data(client, MC32X0_Mode_Feature_REG,data); + data = 0x00; + //comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Sleep_Count_REG, &data, 1 ); + i2c_smbus_write_byte_data(client, MC32X0_Sleep_Count_REG,data); + data = 0x00; + //comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Sample_Rate_REG, &data, 1 ); + i2c_smbus_write_byte_data(client, MC32X0_Sample_Rate_REG,data); + data = 0x02; + //comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_RANGE_Control_REG, &data, 1 ); + i2c_smbus_write_byte_data(client, MC32X0_RANGE_Control_REG,data); + data = 0x00; + //comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Tap_Detection_Enable_REG, &data, 1 ); + i2c_smbus_write_byte_data(client, MC32X0_Tap_Detection_Enable_REG,data); + data = 0x00; + //comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Interrupt_Enable_REG, &data, 1 ); + i2c_smbus_write_byte_data(client, MC32X0_Interrupt_Enable_REG,data); +#ifdef DOT_CALI + gsensor_gain.x = gsensor_gain.y = gsensor_gain.z = 86; +#endif + #endif + } + + data = 0x41; + //comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Mode_Feature_REG, &data, 1 ); + i2c_smbus_write_byte_data(client, MC32X0_Mode_Feature_REG,data); + //MC32X0_rbm(0,0); + return comres; +} + +static ssize_t mc32x0_map_store(struct device *dev, struct device_attribute *attr,const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct mc32x0_data *data; + int i; + data = i2c_get_clientdata(client); + + if(count < 3) return -EINVAL; + + for(i = 0; i< 3; i++) + { + switch(buf[i]) + { + case 'x': + data->map[i] = ABS_X; + data->inv[i] = 1; + break; + case 'y': + data->map[i] = ABS_Y; + data->inv[i] = 1; + break; + case 'z': + data->map[i] = ABS_Z; + data->inv[i] = 1; + break; + case 'X': + data->map[i] = ABS_X; + data->inv[i] = -1; + break; + case 'Y': + data->map[i] = ABS_Y; + data->inv[i] = -1; + break; + case 'Z': + data->map[i] = ABS_Z; + data->inv[i] = -1; + break; + default: + return -EINVAL; + } + } + + return count; +} + +static int mc32x0_enable(struct mc32x0_data *data, int enable); + +static ssize_t mc32x0_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = container_of(mc32x0_device.parent, struct i2c_client, dev); + + struct mc32x0_data *mc32x0 = i2c_get_clientdata(client); + + return sprintf(buf, "%d\n", mc32x0->enabled); +} + +static ssize_t mc32x0_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + bool new_enable; + + struct i2c_client *client = container_of(mc32x0_device.parent, struct i2c_client, dev); + + struct mc32x0_data *mc32x0 = i2c_get_clientdata(client); + + if (sysfs_streq(buf, "1")) + new_enable = true; + else if (sysfs_streq(buf, "0")) + new_enable = false; + else { + pr_debug("%s: invalid value %d\n", __func__, *buf); + return -EINVAL; + } + + mc32x0_enable(mc32x0, new_enable); + + return count; +} + +static ssize_t mc32x0_delay_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", 1000/l_sensorconfig.sensor_samp); +} + +static ssize_t mc32x0_delay_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + + error = strict_strtoul(buf, 10, &data); + if (error) + return error; + if (data > GSENSOR_DURATION_MAX) + data = GSENSOR_DURATION_MAX; + if (data < GSENSOR_DURATION_MIN) + data = GSENSOR_DURATION_MIN; + l_sensorconfig.sensor_samp = 1000/data; + + return count; +} + +static DEVICE_ATTR(map, 0660, mc32x0_map_show, mc32x0_map_store); +static DEVICE_ATTR(enable, 0660, mc32x0_enable_show, mc32x0_enable_store); +static DEVICE_ATTR(delay, 0660, mc32x0_delay_show, mc32x0_delay_store); + +static struct attribute* mc32x0_attrs[] = +{ + &dev_attr_map.attr, + &dev_attr_enable.attr, + &dev_attr_delay.attr, + NULL +}; + +static const struct attribute_group mc32x0_group = +{ + .attrs = mc32x0_attrs, +}; + +static int mc32x0_chip_init(struct i2c_client *client) +{ + + mc32x0_set_image(client); + + return McubeID?0:-1; +} + +int mc32x0_set_mode(struct i2c_client *client, unsigned char mode) +{ + + int comres=0; + unsigned char data; + + + if (mode<4) { + data = 0x40|mode; + i2c_smbus_write_byte_data(client, MC32X0_Mode_Feature_REG,data); + } + return comres; + +} + + + +#ifdef DOT_CALI +struct file *openFile(const char *path,int flag,int mode) +{ + struct file *fp; + + fp=filp_open(path, flag, mode); + if (IS_ERR(fp) || !fp->f_op) + { + GSE_LOG("Calibration File filp_open return NULL\n"); + return NULL; + } + else + { + + return fp; + } +} + +int readFile(struct file *fp,char *buf,int readlen) +{ + if (fp->f_op && fp->f_op->read) + return fp->f_op->read(fp,buf,readlen, &fp->f_pos); + else + return -1; +} + +int writeFile(struct file *fp,char *buf,int writelen) +{ + if (fp->f_op && fp->f_op->write) + return fp->f_op->write(fp,buf,writelen, &fp->f_pos); + else + return -1; +} + +int closeFile(struct file *fp) +{ + filp_close(fp,NULL); + return 0; +} + +void initKernelEnv(void) +{ + oldfs = get_fs(); + set_fs(KERNEL_DS); + printk(KERN_INFO "initKernelEnv\n"); +} + + int MC32X0_WriteCalibration(struct i2c_client *client, int dat[MC32X0_AXES_NUM]) +{ + int err; + u8 buf[9]; + s16 tmp, x_gain, y_gain, z_gain ; + s32 x_off, y_off, z_off; + int temp_cali_dat[MC32X0_AXES_NUM] = { 0 }; + //const struct mc3xx0_hwmsen_convert *pCvt = NULL; + + //pCvt = &mc3xx0_cvt[mc3xx0_current_placement]; + + temp_cali_dat[pCvt->map[MC3XX0_AXIS_X]] = pCvt->sign[MC3XX0_AXIS_X] * dat[MC3XX0_AXIS_X]; + temp_cali_dat[pCvt->map[MC3XX0_AXIS_Y]] = pCvt->sign[MC3XX0_AXIS_Y] * dat[MC3XX0_AXIS_Y]; + temp_cali_dat[pCvt->map[MC3XX0_AXIS_Z]] = pCvt->sign[MC3XX0_AXIS_Z] * dat[MC3XX0_AXIS_Z]; +/* + temp_cali_dat[MC3XX0_AXIS_X] = ((temp_cali_dat[MC3XX0_AXIS_X] * gsensor_gain.x) / GRAVITY_1G_VALUE); + temp_cali_dat[MC3XX0_AXIS_Y] = ((temp_cali_dat[MC3XX0_AXIS_Y] * gsensor_gain.y) / GRAVITY_1G_VALUE); + temp_cali_dat[MC3XX0_AXIS_Z] = ((temp_cali_dat[MC3XX0_AXIS_Z] * gsensor_gain.z) / GRAVITY_1G_VALUE); +*/ + if (is_new_mc34x0) + { + temp_cali_dat[MC3XX0_AXIS_X] = -temp_cali_dat[MC3XX0_AXIS_X]; + temp_cali_dat[MC3XX0_AXIS_Y] = -temp_cali_dat[MC3XX0_AXIS_Y]; + } + else if (is_mc3250) + { + s16 temp = 0; + + temp = temp_cali_dat[MC3XX0_AXIS_X]; + + temp_cali_dat[MC3XX0_AXIS_X] = -temp_cali_dat[MC3XX0_AXIS_Y]; + temp_cali_dat[MC3XX0_AXIS_Y] = temp; + } + + dat[MC3XX0_AXIS_X] = temp_cali_dat[MC3XX0_AXIS_X]; + dat[MC3XX0_AXIS_Y] = temp_cali_dat[MC3XX0_AXIS_Y]; + dat[MC3XX0_AXIS_Z] = temp_cali_dat[MC3XX0_AXIS_Z]; + +#if 0 //modify by zwx + + GSE_LOG("UPDATE dat: (%+3d %+3d %+3d)\n", + dat[MC32X0_AXIS_X], dat[MC32X0_AXIS_Y], dat[MC32X0_AXIS_Z]); + + /*calculate the real offset expected by caller*/ + //cali_temp[MC32X0_AXIS_X] = dat[MC32X0_AXIS_X]; + //cali_temp[MC32X0_AXIS_Y] = dat[MC32X0_AXIS_Y]; + //cali_temp[MC32X0_AXIS_Z] = dat[MC32X0_AXIS_Z]; + //cali[MC32X0_AXIS_Z]= cali[MC32X0_AXIS_Z]-gsensor_gain.z; + + +#endif +// read register 0x21~0x28 +#if 1 //zwx + //if ((err = mc32x0_read_block(client, 0x21, buf, 3))) + //if ((err = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, 0x21, &buf[0],3))) + err = i2c_smbus_read_i2c_block_data(client , 0x21 , 3 , &buf[0]); + + //if ((err = mc32x0_read_block(client, 0x24, &buf[3], 3))) + //if ((err = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, 0x24, &buf[3],3))) + err = i2c_smbus_read_i2c_block_data(client , 0x24 , 3 , &buf[3]); + + //if ((err = mc32x0_read_block(client, 0x27, &buf[6], 3))) + //if ((err = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, 0x27, &buf[6],3))) + err = i2c_smbus_read_i2c_block_data(client , 0x27 , 3 , &buf[6]); + +#else + buf[0] = 0x21; + err = mc32x0_rx_data(client, &buf[0], 3); + buf[3] = 0x24; + err = mc32x0_rx_data(client, &buf[3], 3); + buf[6] = 0x27; + err = mc32x0_rx_data(client, &buf[6], 3); +#endif +#if 1 + // get x,y,z offset + tmp = ((buf[1] & 0x3f) << 8) + buf[0]; + if (tmp & 0x2000) + tmp |= 0xc000; + x_off = tmp; + + tmp = ((buf[3] & 0x3f) << 8) + buf[2]; + if (tmp & 0x2000) + tmp |= 0xc000; + y_off = tmp; + + tmp = ((buf[5] & 0x3f) << 8) + buf[4]; + if (tmp & 0x2000) + tmp |= 0xc000; + z_off = tmp; + + // get x,y,z gain + x_gain = ((buf[1] >> 7) << 8) + buf[6]; + y_gain = ((buf[3] >> 7) << 8) + buf[7]; + z_gain = ((buf[5] >> 7) << 8) + buf[8]; + + // prepare new offset + x_off = x_off + 16 * dat[MC32X0_AXIS_X] * 256 * 128 / 3 / gsensor_gain.x / (40 + x_gain); + y_off = y_off + 16 * dat[MC32X0_AXIS_Y] * 256 * 128 / 3 / gsensor_gain.y / (40 + y_gain); + z_off = z_off + 16 * dat[MC32X0_AXIS_Z] * 256 * 128 / 3 / gsensor_gain.z / (40 + z_gain); + + //storege the cerrunt offset data with DOT format + offset_data[0] = x_off; + offset_data[1] = y_off; + offset_data[2] = z_off; + + //storege the cerrunt Gain data with GOT format + gain_data[0] = 256*8*128/3/(40+x_gain); + gain_data[1] = 256*8*128/3/(40+y_gain); + gain_data[2] = 256*8*128/3/(40+z_gain); + printk("%d %d ======================\n\n ",gain_data[0],x_gain); +#endif + buf[0]=0x43; + //mc32x0_write_block(client, 0x07, buf, 1); + //mc32x0_write_reg(client,0x07,0x43); + //p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x07, &buf[0], 1 ); + i2c_smbus_write_byte_data(client, 0x07,buf[0]); + buf[0] = x_off & 0xff; + buf[1] = ((x_off >> 8) & 0x3f) | (x_gain & 0x0100 ? 0x80 : 0); + buf[2] = y_off & 0xff; + buf[3] = ((y_off >> 8) & 0x3f) | (y_gain & 0x0100 ? 0x80 : 0); + buf[4] = z_off & 0xff; + buf[5] = ((z_off >> 8) & 0x3f) | (z_gain & 0x0100 ? 0x80 : 0); + + + //mc32x0_write_block(client, 0x21, buf, 6); + //p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x21, &buf[0], 6 ); + i2c_smbus_write_i2c_block_data(client, 0x21, 2,&buf[0]); + i2c_smbus_write_i2c_block_data(client, 0x21+2, 2,&buf[2]); + i2c_smbus_write_i2c_block_data(client, 0x21+4, 2,&buf[4]); + + + buf[0]=0x41; + //mc32x0_write_block(client, 0x07, buf, 1); + //p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x07, &buf[0], 1 ); + i2c_smbus_write_byte_data(client, 0x07,buf[0]); + //mc32x0_write_reg(client,0x07,0x41); + + return err; + +} +/* +int mcube_read_cali_file(struct i2c_client *client) +{ + int cali_data[3]; + int err =0; + + printk("%s %d\n",__func__,__LINE__); + //MCUBE_BACKUP_FILE + READ_FROM_BACKUP = false; + //MCUBE_BACKUP_FILE + initKernelEnv(); + fd_file = openFile(CALIB_PATH,O_RDONLY,0); + //MCUBE_BACKUP_FILE + if (fd_file == NULL) + { + fd_file = openFile(BACKUP_CALIB_PATH, O_RDONLY, 0); + if(fd_file != NULL) + { + READ_FROM_BACKUP = true; + } + } + //MCUBE_BACKUP_FILE + if (fd_file == NULL) + { + GSE_LOG("fail to open\n"); + cali_data[0] = 0; + cali_data[1] = 0; + cali_data[2] = 0; + return 1; + } + else + { + printk("%s %d\n",__func__,__LINE__); + memset(backup_buf,0,64); + if ((err = readFile(fd_file,backup_buf,128))>0) + GSE_LOG("buf:%s\n",backup_buf); + else + GSE_LOG("read file error %d\n",err); + printk("%s %d\n",__func__,__LINE__); + + set_fs(oldfs); + closeFile(fd_file); + + sscanf(backup_buf, "%d %d %d",&cali_data[MC32X0_AXIS_X], &cali_data[MC32X0_AXIS_Y], &cali_data[MC32X0_AXIS_Z]); + GSE_LOG("cali_data: %d %d %d\n", cali_data[MC32X0_AXIS_X], cali_data[MC32X0_AXIS_Y], cali_data[MC32X0_AXIS_Z]); + + //cali_data1[MC32X0_AXIS_X] = cali_data[MC32X0_AXIS_X] * gsensor_gain.x / GRAVITY_EARTH_1000; + //cali_data1[MC32X0_AXIS_Y] = cali_data[MC32X0_AXIS_Y] * gsensor_gain.y / GRAVITY_EARTH_1000; + //cali_data1[MC32X0_AXIS_Z] = cali_data[MC32X0_AXIS_Z] * gsensor_gain.z / GRAVITY_EARTH_1000; + //cali_data[MC32X0_AXIS_X]=-cali_data[MC32X0_AXIS_X]; + //cali_data[MC32X0_AXIS_Y]=-cali_data[MC32X0_AXIS_Y]; + //cali_data[MC32X0_AXIS_Z]=-cali_data[MC32X0_AXIS_Z]; + + //GSE_LOG("cali_data1: %d %d %d\n", cali_data1[MC32X0_AXIS_X], cali_data1[MC32X0_AXIS_Y], cali_data1[MC32X0_AXIS_Z]); + printk("%s %d\n",__func__,__LINE__); + MC32X0_WriteCalibration(client,cali_data); + } + + return 0; +} +*/ + +void MC32X0_rbm(struct i2c_client *client, int enable) +{ + //int err; + char buf1[3]; + if(enable == 1 ) + { +#if 1 + buf1[0] = 0x43; + //err = mc32x0_write_block(client, 0x07, buf1, 0x01); + //err = p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x07, &buf1[0], 1 ); + i2c_smbus_write_byte_data(client, 0x07,buf1[0]); + buf1[0] = 0x02; + //err = mc32x0_write_block(client, 0x14, buf1, 0x01); + //err = p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x14, &buf1[0], 1 ); + i2c_smbus_write_byte_data(client, 0x14,buf1[0]); + buf1[0] = 0x41; + //err = mc32x0_write_block(client, 0x07, buf1, 0x01); + //err = p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x07, &buf1[0], 1 ); + i2c_smbus_write_byte_data(client, 0x07,buf1[0]); +#else + err = mc32x0_write_reg(client,0x07,0x43); + err = mc32x0_write_reg(client,0x14,0x02); + err = mc32x0_write_reg(client,0x07,0x41); +#endif + enable_RBM_calibration =1; + + GSE_LOG("set rbm!!\n"); + + msleep(10); + } + else if(enable == 0 ) + { +#if 1 + buf1[0] = 0x43; + //err = mc32x0_write_block(client, 0x07, buf1, 0x01); + //err = p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x07, &buf1[0], 1 ); + i2c_smbus_write_byte_data(client, 0x07,buf1[0]); + + buf1[0] = 0x00; + //err = mc32x0_write_block(client, 0x14, buf1, 0x01); + //err = p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x14, &buf1[0], 1 ); + i2c_smbus_write_byte_data(client, 0x14,buf1[0]); + buf1[0] = 0x41; + //err = mc32x0_write_block(client, 0x07, buf1, 0x01); + //err = p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x07, &buf1[0], 1 ); + i2c_smbus_write_byte_data(client, 0x07,buf1[0]); +#else + err = mc32x0_write_reg(client,0x07,0x43); + err = mc32x0_write_reg(client,0x14,0x00); + err = mc32x0_write_reg(client,0x07,0x41); +#endif + enable_RBM_calibration =0; + + GSE_LOG("clear rbm!!\n"); + + msleep(10); + } +} + +/*----------------------------------------------------------------------------*/ + int MC32X0_ReadData_RBM(struct i2c_client *client,int data[MC32X0_AXES_NUM]) +{ + //u8 uData; + u8 addr = 0x0d; + u8 rbm_buf[MC32X0_DATA_LEN] = {0}; + int err = 0; + + + //err = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, addr, &rbm_buf[0],6); + err = i2c_smbus_read_i2c_block_data(client , addr , 6 , rbm_buf); + //err = mc32x0_read_block(client, addr, rbm_buf, 0x06); + + data[MC32X0_AXIS_X] = (s16)((rbm_buf[0]) | (rbm_buf[1] << 8)); + data[MC32X0_AXIS_Y] = (s16)((rbm_buf[2]) | (rbm_buf[3] << 8)); + data[MC32X0_AXIS_Z] = (s16)((rbm_buf[4]) | (rbm_buf[5] << 8)); + + GSE_LOG("rbm_buf<<<<<[%02x %02x %02x %02x %02x %02x]\n",rbm_buf[0], rbm_buf[2], rbm_buf[2], rbm_buf[3], rbm_buf[4], rbm_buf[5]); + GSE_LOG("RBM<<<<<[%04x %04x %04x]\n", data[MC32X0_AXIS_X], data[MC32X0_AXIS_Y], data[MC32X0_AXIS_Z]); + GSE_LOG("RBM<<<<<[%04d %04d %04d]\n", data[MC32X0_AXIS_X], data[MC32X0_AXIS_Y], data[MC32X0_AXIS_Z]); + return err; +} + + + int MC32X0_ReadRBMData(struct i2c_client *client, char *buf) +{ + //struct mc32x0_data *mc32x0 = i2c_get_clientdata(client); + int res = 0; + int data[3]; + + if (!buf) + { + return EINVAL; + } + + mc32x0_set_mode(client,MC32X0_WAKE); +/* + if(mc32x0->status == mc32x0_CLOSE) + { + res = mc32x0_start(client, 0); + if(res) + { + GSE_ERR("Power on mc32x0 error %d!\n", res); + } + } +*/ + if((res = MC32X0_ReadData_RBM(client,data))) + { + GSE_ERR("%s I2C error: ret value=%d",__func__, res); + return EIO; + } + else + { + sprintf(buf, "%04x %04x %04x", data[MC32X0_AXIS_X], + data[MC32X0_AXIS_Y], data[MC32X0_AXIS_Z]); + + } + + return 0; +} + int MC32X0_ReadOffset(struct i2c_client *client,s16 ofs[MC32X0_AXES_NUM]) +{ + int err; + u8 off_data[6]; + + + if(McubeID &MCUBE_8G_14BIT) + { + + //if ((err = mc32x0_read_block(client, MC32X0_XOUT_EX_L_REG, off_data, MC32X0_DATA_LEN))) + //if ((err = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, MC32X0_XOUT_EX_L_REG, &off_data[0],MC32X0_DATA_LEN))) + err = i2c_smbus_read_i2c_block_data(client , MC32X0_XOUT_EX_L_REG , MC32X0_DATA_LEN , off_data); + + ofs[MC32X0_AXIS_X] = ((s16)(off_data[0]))|((s16)(off_data[1])<<8); + ofs[MC32X0_AXIS_Y] = ((s16)(off_data[2]))|((s16)(off_data[3])<<8); + ofs[MC32X0_AXIS_Z] = ((s16)(off_data[4]))|((s16)(off_data[5])<<8); + } + else if(McubeID &MCUBE_1_5G_8BIT) + { + //if ((err = mc32x0_read_block(client, 0, off_data, 3))) + //if ((err = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, 0, &off_data[0],3))) + err = i2c_smbus_read_i2c_block_data(client , 0 , 3 , off_data); + + ofs[MC32X0_AXIS_X] = (s8)off_data[0]; + ofs[MC32X0_AXIS_Y] = (s8)off_data[1]; + ofs[MC32X0_AXIS_Z] = (s8)off_data[2]; + } + + GSE_LOG("MC32X0_ReadOffset %d %d %d \n",ofs[MC32X0_AXIS_X] ,ofs[MC32X0_AXIS_Y],ofs[MC32X0_AXIS_Z]); + + return 0; +} +/*----------------------------------------------------------------------------*/ + int MC32X0_ResetCalibration(struct i2c_client *client) +{ + + u8 buf[6]; + s16 tmp; + int err; +#if 1 //zwx + buf[0] = 0x43; + //if(err = mc32x0_write_block(client, 0x07, buf, 1)) + //if(err = p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x07, &buf[0], 1 )) + if((err = i2c_smbus_write_byte_data(client, 0x07,buf[0]))) + { + GSE_ERR("error 0x07: %d\n", err); + } + + + //if(err = mc32x0_write_block(client, 0x21, offset_buf, 6)) // add by liang for writing offset register as OTP value + //if(err = p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x21, &offset_buf[0], 6 )) + if((err = i2c_smbus_write_i2c_block_data(client, 0x21, 6,offset_buf))) + { + GSE_ERR("error: %d\n", err); + } + + buf[0] = 0x41; + //if(err = mc32x0_write_block(client, 0x07, buf, 1)) + //if(err = p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x07, &buf[0], 1 )) + if((err = i2c_smbus_write_byte_data(client, 0x07,buf[0]))) + { + GSE_ERR("error: %d\n", err); + } +#else + mc32x0_write_reg(client,0x07,0x43); + + mc32x0_write_block(client, 0x21, offset_buf, 6); + + mc32x0_write_reg(client,0x07,0x41); +#endif + msleep(20); + + tmp = ((offset_buf[1] & 0x3f) << 8) + offset_buf[0]; // add by Liang for set offset_buf as OTP value + if (tmp & 0x2000) + tmp |= 0xc000; + offset_data[0] = tmp; + + tmp = ((offset_buf[3] & 0x3f) << 8) + offset_buf[2]; // add by Liang for set offset_buf as OTP value + if (tmp & 0x2000) + tmp |= 0xc000; + offset_data[1] = tmp; + + tmp = ((offset_buf[5] & 0x3f) << 8) + offset_buf[4]; // add by Liang for set offset_buf as OTP value + if (tmp & 0x2000) + tmp |= 0xc000; + offset_data[2] = tmp; + + //memset(mc32x0->cali_sw, 0x00, sizeof(mc32x0->cali_sw)); + return 0; + +} +/*----------------------------------------------------------------------------*/ + int MC32X0_ReadCalibration(struct i2c_client *client,int dat[MC32X0_AXES_NUM]) +{ + + signed short MC_offset[MC32X0_AXES_NUM+1]; /*+1: for 4-byte alignment*/ + int err; + memset(MC_offset, 0, sizeof(MC_offset)); + if ((err = MC32X0_ReadOffset(client, MC_offset))) { + GSE_ERR("read offset fail, %d\n", err); + return err; + } + + dat[MC32X0_AXIS_X] = MC_offset[MC32X0_AXIS_X]; + dat[MC32X0_AXIS_Y] = MC_offset[MC32X0_AXIS_Y]; + dat[MC32X0_AXIS_Z] = MC_offset[MC32X0_AXIS_Z]; + //modify by zwx + //GSE_LOG("MC32X0_ReadCalibration %d %d %d \n",dat[mc32x0->cvt.map[MC32X0_AXIS_X]] ,dat[mc32x0->cvt.map[MC32X0_AXIS_Y]],dat[mc32x0->cvt.map[MC32X0_AXIS_Z]]); + + return 0; +} + +/*----------------------------------------------------------------------------*/ + + int MC32X0_ReadData(struct i2c_client *client, s16 buffer[MC32X0_AXES_NUM]) +{ + unsigned char buf[6]; + signed char buf1[6]; + char rbm_buf[6]; + int ret; + //int err = 0; + + #ifdef SUPPORT_VIRTUAL_Z_SENSOR + int tempX=0; + int tempY=0; + int tempZ=0; + #endif + + if ( enable_RBM_calibration == 0) + { + //err = hwmsen_read_block(client, addr, buf, 0x06); + } + else if (enable_RBM_calibration == 1) + { + memset(rbm_buf, 0, 6); + //rbm_buf[0] = mc32x0_REG_RBM_DATA; + //ret = mc32x0_rx_data(client, &rbm_buf[0], 6); + //ret = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, 0x0d, &rbm_buf[0],6); + i2c_smbus_read_i2c_block_data(client , 0x0d , 2 , &rbm_buf[0]); + i2c_smbus_read_i2c_block_data(client , 0x0d+2 , 2 , &rbm_buf[2]); + i2c_smbus_read_i2c_block_data(client , 0x0d+4 , 2 , &rbm_buf[4]); + } + + if ( enable_RBM_calibration == 0) + { + + if(McubeID &MC32X0_HIGH_END) + { + #ifdef MC32X0_HIGH_END + ret = i2c_smbus_read_i2c_block_data(client , MC32X0_XOUT_EX_L_REG , 6 , buf); + //ret = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, MC32X0_XOUT_EX_L_REG, &buf[0],6); + + buffer[0] = (signed short)((buf[0])|(buf[1]<<8)); + buffer[1] = (signed short)((buf[2])|(buf[3]<<8)); + buffer[2] = (signed short)((buf[4])|(buf[5]<<8)); + #endif + } + else if(McubeID &MC32X0_LOW_END) + { + #ifdef MC32X0_LOW_END + ret = i2c_smbus_read_i2c_block_data(client , MC32X0_XOUT_REG , 3 , buf1); + //ret = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, MC32X0_XOUT_REG, &buf[0],3); + + buffer[0] = (signed short)buf1[0]; + buffer[1] = (signed short)buf1[1]; + buffer[2] = (signed short)buf1[2]; + #endif + } + #ifdef SUPPORT_VIRTUAL_Z_SENSOR //add 2013-10-23 + if (g_virtual_z) + { + //printk("%s 1\n", __FUNCTION__); + + tempX = buffer[MC32X0_AXIS_X]; + tempY = buffer[MC32X0_AXIS_Y]; + tempZ = buffer[MC32X0_AXIS_Z]; + //printk(" %d:Verify_Z_Railed() %d\n", (int)buffer[MC32X0_AXIS_Z], Verify_Z_Railed((int)buffer[MC32X0_AXIS_Z], LOW_RESOLUTION)); + if(1 == Verify_Z_Railed((int)buffer[MC32X0_AXIS_Z], LOW_RESOLUTION)) // z-railed + { + Railed = 1; + + GSE_LOG("%s: Z railed", __func__); + //printk("%s: Z railed \n", __func__); + if (G_2_REVERSE_VIRTUAL_Z == 1) + buffer[MC32X0_AXIS_Z] = (s8) ( gsensor_gain.z - (abs(tempX) + abs(tempY))); + else + buffer[MC32X0_AXIS_Z] = (s8) -( gsensor_gain.z - (abs(tempX) + abs(tempY))); + } + else + { + Railed = 0; + } + } + #endif + mcprintkreg("MC32X0_ReadData : %d %d %d \n",buffer[0],buffer[1],buffer[2]); + } + else if (enable_RBM_calibration == 1) + { + buffer[MC32X0_AXIS_X] = (s16)((rbm_buf[0]) | (rbm_buf[1] << 8)); + buffer[MC32X0_AXIS_Y] = (s16)((rbm_buf[2]) | (rbm_buf[3] << 8)); + buffer[MC32X0_AXIS_Z] = (s16)((rbm_buf[4]) | (rbm_buf[5] << 8)); + + GSE_LOG("%s RBM<<<<<[%08d %08d %08d]\n", __func__,buffer[MC32X0_AXIS_X], buffer[MC32X0_AXIS_Y], buffer[MC32X0_AXIS_Z]); + if(gain_data[0] == 0) + { + buffer[MC32X0_AXIS_X] = 0; + buffer[MC32X0_AXIS_Y] = 0; + buffer[MC32X0_AXIS_Z] = 0; + return 0; + } + buffer[MC32X0_AXIS_X] = (buffer[MC32X0_AXIS_X] + offset_data[0]/2)*gsensor_gain.x/gain_data[0]; + buffer[MC32X0_AXIS_Y] = (buffer[MC32X0_AXIS_Y] + offset_data[1]/2)*gsensor_gain.y/gain_data[1]; + buffer[MC32X0_AXIS_Z] = (buffer[MC32X0_AXIS_Z] + offset_data[2]/2)*gsensor_gain.z/gain_data[2]; + + #ifdef SUPPORT_VIRTUAL_Z_SENSOR // add 2013-10-23 + if (g_virtual_z) + { + tempX = buffer[MC32X0_AXIS_X]; + tempY = buffer[MC32X0_AXIS_Y]; + tempZ = buffer[MC32X0_AXIS_Z]; + //printk("%s 2\n", __FUNCTION__); + GSE_LOG("Original RBM<<<<<[%08d %08d %08d]\n", buffer[MC32X0_AXIS_X], buffer[MC32X0_AXIS_Y], buffer[MC32X0_AXIS_Z]); + printk("Verify_Z_Railed() %d\n", Verify_Z_Railed((int)buffer[MC32X0_AXIS_Z], RBM_RESOLUTION)); + if(1 == Verify_Z_Railed(buffer[MC32X0_AXIS_Z], RBM_RESOLUTION)) // z-railed + { + GSE_LOG("%s: Z Railed in RBM mode",__FUNCTION__); + //printk("%s: Z Railed in RBM mode\n",__FUNCTION__); + if (G_2_REVERSE_VIRTUAL_Z == 1) + buffer[MC32X0_AXIS_Z] = (s16) ( gsensor_gain.z - (abs(tempX) + abs(tempY))); + else + buffer[MC32X0_AXIS_Z] = (s16) -( gsensor_gain.z - (abs(tempX) + abs(tempY))); + } + GSE_LOG("RBM<<<<<[%08d %08d %08d]\n", buffer[MC32X0_AXIS_X], buffer[MC32X0_AXIS_Y], buffer[MC32X0_AXIS_Z]); + } + #endif + + GSE_LOG("%s offset_data <<<<<[%d %d %d]\n", __func__,offset_data[0], offset_data[1], offset_data[2]); + + GSE_LOG("%s gsensor_gain <<<<<[%d %d %d]\n", __func__,gsensor_gain.x, gsensor_gain.y, gsensor_gain.z); + + GSE_LOG("%s gain_data <<<<<[%d %d %d]\n", __func__,gain_data[0], gain_data[1], gain_data[2]); + + GSE_LOG("%s RBM->RAW <<<<<[%d %d %d]\n", __func__,buffer[MC32X0_AXIS_X], buffer[MC32X0_AXIS_Y], buffer[MC32X0_AXIS_Z]); + } + + return 0; +} + +int MC32X0_ReadRawData(struct i2c_client *client, char * buf) +{ + + + int res = 0; + s16 raw_buf[3]; + + if (!buf) + { + return EINVAL; + } + + //mc32x0_power_up(mc32x0); + mc32x0_set_mode(client, MC32X0_WAKE); + if((res = MC32X0_ReadData(client,&raw_buf[0]))) + { + printk("%s %d\n",__FUNCTION__, __LINE__); + GSE_ERR("I2C error: ret value=%d", res); + return EIO; + } + else + { + //const struct mc3xx0_hwmsen_convert *pCvt = &mc3xx0_cvt[mc3xx0_current_placement]; + GSE_LOG("UPDATE dat: (%+3d %+3d %+3d)\n", + raw_buf[MC32X0_AXIS_X], raw_buf[MC32X0_AXIS_Y], raw_buf[MC32X0_AXIS_Z]); + + //G_RAW_DATA[MC32X0_AXIS_X] = raw_buf[0]; + //G_RAW_DATA[MC32X0_AXIS_Y] = raw_buf[1]; + //G_RAW_DATA[MC32X0_AXIS_Z] = raw_buf[2]; + //G_RAW_DATA[MC32X0_AXIS_Z] = G_RAW_DATA[MC32X0_AXIS_Z] + gsensor_gain.z; +/* + raw_buf[MC3XX0_AXIS_X] = ((raw_buf[MC3XX0_AXIS_X] * GRAVITY_1G_VALUE) / gsensor_gain.x); + raw_buf[MC3XX0_AXIS_Y] = ((raw_buf[MC3XX0_AXIS_Y] * GRAVITY_1G_VALUE) / gsensor_gain.y); + raw_buf[MC3XX0_AXIS_Z] = ((raw_buf[MC3XX0_AXIS_Z] * GRAVITY_1G_VALUE) / gsensor_gain.z); +*/ + if (is_new_mc34x0) + { + raw_buf[MC3XX0_AXIS_X] = -raw_buf[MC3XX0_AXIS_X]; + raw_buf[MC3XX0_AXIS_Y] = -raw_buf[MC3XX0_AXIS_Y]; + } + else if (is_mc3250) + { + s16 temp = 0; + + temp = raw_buf[MC3XX0_AXIS_X]; + + raw_buf[MC3XX0_AXIS_X] = raw_buf[MC3XX0_AXIS_Y]; + raw_buf[MC3XX0_AXIS_Y] = -temp; + } + + G_RAW_DATA[MC3XX0_AXIS_X] = pCvt->sign[MC3XX0_AXIS_X] * raw_buf[pCvt->map[MC3XX0_AXIS_X]]; + G_RAW_DATA[MC3XX0_AXIS_Y] = pCvt->sign[MC3XX0_AXIS_Y] * raw_buf[pCvt->map[MC3XX0_AXIS_Y]]; + G_RAW_DATA[MC3XX0_AXIS_Z] = pCvt->sign[MC3XX0_AXIS_Z] * raw_buf[pCvt->map[MC3XX0_AXIS_Z]]; + + G_RAW_DATA[MC32X0_AXIS_Z] += gsensor_gain.z*(pCvt->sign[MC3XX0_AXIS_Z])*(1);//-=GRAVITY_1G_VALUE; + + //printk("%s %d\n",__FUNCTION__, __LINE__); + sprintf(buf, "%04x %04x %04x", G_RAW_DATA[MC32X0_AXIS_X], + G_RAW_DATA[MC32X0_AXIS_Y], G_RAW_DATA[MC32X0_AXIS_Z]); + GSE_LOG("G_RAW_DATA: (%+3d %+3d %+3d)\n", + G_RAW_DATA[MC32X0_AXIS_X], G_RAW_DATA[MC32X0_AXIS_Y], G_RAW_DATA[MC32X0_AXIS_Z]); + } + return 0; +} + +int mc32x0_reset (struct i2c_client *client) +{ + + s16 tmp, x_gain, y_gain, z_gain ; + s32 x_off, y_off, z_off; + u8 buf[3]; + int err; + //mc32x0_write_reg(client,0x1b,0x6d); + buf[0]=0x6d; + //p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x1b, &buf[0], 1 ); + i2c_smbus_write_byte_data(client, 0x1b,buf[0]); + + //mc32x0_write_reg(client,0x1b,0x43); + buf[0]=0x43; + //p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x1b, &buf[0], 1 ); + i2c_smbus_write_byte_data(client, 0x1b,buf[0]); + msleep(5); + + //mc32x0_write_reg(client,0x07,0x43); + buf[0]=0x43; + //p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x07, &buf[0], 1 ); + i2c_smbus_write_byte_data(client, 0x07,buf[0]); + //mc32x0_write_reg(client,0x1C,0x80); + buf[0]=0x80; + //p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x1C, &buf[0], 1 ); + i2c_smbus_write_byte_data(client, 0x1c,buf[0]); + //mc32x0_write_reg(client,0x17,0x80); + buf[0]=0x80; + //p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x17, &buf[0], 1 ); + i2c_smbus_write_byte_data(client, 0x17,buf[0]); + msleep(5); + //mc32x0_write_reg(client,0x1C,0x00); + buf[0]=0x00; + //p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x1C, &buf[0], 1 ); + i2c_smbus_write_byte_data(client, 0x1c,buf[0]); + //mc32x0_write_reg(client,0x17,0x00); + buf[0]=0x00; + //p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x17, &buf[0], 1 ); + i2c_smbus_write_byte_data(client, 0x17,buf[0]); + msleep(5); + + +/* + if ((err = mc32x0_read_block(new_client, 0x21, offset_buf, 6))) //add by Liang for storeage OTP offsef register value + { + GSE_ERR("error: %d\n", err); + return err; + } +*/ + memset(offset_buf, 0, 9); + //offset_buf[0] = 0x21; + //err = mc32x0_rx_data(client, offset_buf, 9); + //err = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, 0x21, &offset_buf[0],9); + err = i2c_smbus_read_i2c_block_data(client , 0x21 , 9 , offset_buf); + + + tmp = ((offset_buf[1] & 0x3f) << 8) + offset_buf[0]; + if (tmp & 0x2000) + tmp |= 0xc000; + x_off = tmp; + + tmp = ((offset_buf[3] & 0x3f) << 8) + offset_buf[2]; + if (tmp & 0x2000) + tmp |= 0xc000; + y_off = tmp; + + tmp = ((offset_buf[5] & 0x3f) << 8) + offset_buf[4]; + if (tmp & 0x2000) + tmp |= 0xc000; + z_off = tmp; + + // get x,y,z gain + x_gain = ((offset_buf[1] >> 7) << 8) + offset_buf[6]; + y_gain = ((offset_buf[3] >> 7) << 8) + offset_buf[7]; + z_gain = ((offset_buf[5] >> 7) << 8) + offset_buf[8]; + + + //storege the cerrunt offset data with DOT format + offset_data[0] = x_off; + offset_data[1] = y_off; + offset_data[2] = z_off; + + //storege the cerrunt Gain data with GOT format + gain_data[0] = 256*8*128/3/(40+x_gain); + gain_data[1] = 256*8*128/3/(40+y_gain); + gain_data[2] = 256*8*128/3/(40+z_gain); + printk("offser gain = %d %d %d %d %d %d======================\n\n ", + gain_data[0],gain_data[1],gain_data[2],offset_data[0],offset_data[1],offset_data[2]); + + return 0; +} +#endif + +int mc32x0_read_accel_xyz(struct i2c_client *client, s16 * acc) +{ + int comres; + s16 raw_data[MC3XX0_AXIS_NUM] = { 0 }; + //const struct mc3xx0_hwmsen_convert *pCvt = &mc3xx0_cvt[mc3xx0_current_placement]; +#ifdef DOT_CALI + s16 raw_buf[6]; + + + comres = MC32X0_ReadData(client,&raw_buf[0]); + + acc[0] = raw_buf[0]; + acc[1] = raw_buf[1]; + acc[2] = raw_buf[2]; +#else + unsigned char raw_buf[6]; + signed char raw_buf1[3]; + if(McubeID &MC32X0_HIGH_END) + { + #ifdef MC32X0_HIGH_END + comres = i2c_smbus_read_i2c_block_data(client , MC32X0_XOUT_EX_L_REG , 6 , raw_buf); + //comres = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, MC32X0_XOUT_EX_L_REG, &data[0],6); + + acc[0] = (signed short)((raw_buf[0])|(raw_buf[1]<<8)); + acc[1] = (signed short)((raw_buf[2])|(raw_buf[3]<<8)); + acc[2] = (signed short)((raw_buf[4])|(raw_buf[5]<<8)); + #endif + } + else if(McubeID &MC32X0_LOW_END) + { + #ifdef MC32X0_LOW_END + comres = i2c_smbus_read_i2c_block_data(client , MC32X0_XOUT_REG , 3 , raw_buf1); + //comres = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, MC32X0_XOUT_REG, &data[0],3); + + acc[0] = (signed short)raw_buf1[0]; + acc[1] = (signed short)raw_buf1[1]; + acc[2] = (signed short)raw_buf1[2]; + #endif + } +#endif + + raw_data[MC3XX0_AXIS_X] = acc[MC3XX0_AXIS_X]; + raw_data[MC3XX0_AXIS_Y] = acc[MC3XX0_AXIS_Y]; + raw_data[MC3XX0_AXIS_Z] = acc[MC3XX0_AXIS_Z]; +/* + raw_data[MC3XX0_AXIS_X] = ((raw_data[MC3XX0_AXIS_X] * GRAVITY_1G_VALUE) / gsensor_gain.x); + raw_data[MC3XX0_AXIS_Y] = ((raw_data[MC3XX0_AXIS_Y] * GRAVITY_1G_VALUE) / gsensor_gain.y); + raw_data[MC3XX0_AXIS_Z] = ((raw_data[MC3XX0_AXIS_Z] * GRAVITY_1G_VALUE) / gsensor_gain.z); +*/ + if (is_new_mc34x0) + { + raw_data[MC3XX0_AXIS_X] = -raw_data[MC3XX0_AXIS_X]; + raw_data[MC3XX0_AXIS_Y] = -raw_data[MC3XX0_AXIS_Y]; + } + else if (is_mc3250) + { + s16 temp = 0; + + temp = raw_data[MC3XX0_AXIS_X]; + + raw_data[MC3XX0_AXIS_X] = raw_data[MC3XX0_AXIS_Y]; + raw_data[MC3XX0_AXIS_Y] = -temp; + } + + acc[MC3XX0_AXIS_X] = pCvt->sign[MC3XX0_AXIS_X] * raw_data[pCvt->map[MC3XX0_AXIS_X]]; + acc[MC3XX0_AXIS_Y] = pCvt->sign[MC3XX0_AXIS_Y] * raw_data[pCvt->map[MC3XX0_AXIS_Y]]; + acc[MC3XX0_AXIS_Z] = pCvt->sign[MC3XX0_AXIS_Z] * raw_data[pCvt->map[MC3XX0_AXIS_Z]]; + + return comres; + +} + +static int mc32x0_measure(struct i2c_client *client, struct acceleration *accel) +{ + + s16 raw[3]; + +#ifdef DOT_CALI + //int ret; +#endif + + +#ifdef DOT_CALI + if( load_cali_flg > 0) + { + /*ret =mcube_read_cali_file(client); + if(ret == 0) + load_cali_flg = ret; + else + load_cali_flg --; + GSE_LOG("load_cali %d\n",ret); */ + MC32X0_WriteCalibration(client,l_sensorconfig.offset); + load_cali_flg = 0; + } +#endif + /* read acceleration data */ + mc32x0_read_accel_xyz(client,&raw[0]); + + accel->x = raw[0] ; + accel->y = raw[1] ; + accel->z = raw[2] ; + return 0; +} + +static void mc32x0_work_func(struct work_struct *work) +{ + struct mc32x0_data *data = container_of(work, struct mc32x0_data, work); + struct acceleration accel = {0}; + + mc32x0_measure(data->client, &accel); + + //printk(KERN_ERR"mc32x0_measure: acc.x=%d, acc.y=%d, acc.z=%d\n", data->inv[0]*accel.x,data->inv[1]*accel.y, data->inv[2]*accel.z); + + //input_report_abs(data->input_dev, data->map[0], data->inv[0]*accel.x); + //input_report_abs(data->input_dev, data->map[1], data->inv[1]*accel.y); + //input_report_abs(data->input_dev, data->map[2], data->inv[2]*accel.z); + + //accel.x = (accel.x&0x00FF) | ((accel.y&0xFF)<<8) | ((accel.z&0xFF)<<16); + + input_report_abs(data->input_dev, ABS_X, accel.x); + input_report_abs(data->input_dev, ABS_Y, accel.y); + input_report_abs(data->input_dev, ABS_Z, accel.z); + input_sync(data->input_dev); + + queue_delayed_work(data->mc32x0_wq, &data->work, msecs_to_jiffies(sample_rate_2_memsec(data->sensor_samp))); +} +/* +static enum hrtimer_restart mc32x0_timer_func(struct hrtimer *timer) +{ + struct mc32x0_data *data = container_of(timer, struct mc32x0_data, timer); + + queue_work(data->mc32x0_wq, &data->work); + hrtimer_start(&data->timer, ktime_set(0, sensor_duration*1000000), HRTIMER_MODE_REL); + + return HRTIMER_NORESTART; +} +*/ +static int mc32x0_enable(struct mc32x0_data *data, int enable) +{ + if(enable){ + msleep(10); + mc32x0_chip_init(data->client); + queue_delayed_work(data->mc32x0_wq, &data->work, msecs_to_jiffies(sample_rate_2_memsec(data->sensor_samp)));//hrtimer_start(&data->timer, ktime_set(0, asensor_duration*1000000), HRTIMER_MODE_REL); + data->enabled = true; + }else{ + cancel_delayed_work_sync(&l_sensorconfig.work);//hrtimer_cancel(&data->timer); + data->enabled = false; + } + return 0; +} +/* +//MCUBE_BACKUP_FILE +static void mcube_copy_file(const char *dstFilePath) +{ + + int err =0; + initKernelEnv(); + + fd_file = openFile(dstFilePath,O_RDWR,0); + if (fd_file == NULL) + { + GSE_LOG("open %s fail\n",dstFilePath); + return; + } + + if ((err = writeFile(fd_file,backup_buf,64))>0) + GSE_LOG("buf:%s\n",backup_buf); + else + GSE_LOG("write file error %d\n",err); + + set_fs(oldfs); ; + closeFile(fd_file); + +} +//MCUBE_BACKUP_FILE +*/ + +extern int wmt_setsyspara(char *varname, char *varval); +static void update_var(void) +{ + char varbuf[64]; + int varlen; + + memset(varbuf, 0, sizeof(varbuf)); + varlen = sizeof(varbuf); + + sprintf(varbuf, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", + l_sensorconfig.op, + l_sensorconfig.int_gpio, + l_sensorconfig.samp, + (pCvt->map[MC3XX0_AXIS_X]), + (pCvt->sign[MC3XX0_AXIS_X]), + (pCvt->map[MC3XX0_AXIS_Y]), + (pCvt->sign[MC3XX0_AXIS_Y]), + (pCvt->map[MC3XX0_AXIS_Z]), + (pCvt->sign[MC3XX0_AXIS_Z]), + l_sensorconfig.offset[0], + l_sensorconfig.offset[1], + l_sensorconfig.offset[2] + ); + + wmt_setsyspara("wmt.io.mc3230sensor",varbuf); +} + +static long mc32x0_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + //int intBuf[SENSOR_DATA_SIZE]; + int ret = 0; + //float convert_para=0.0f; + short enable = 0; + short delay = 0; + //short val=1000/l_sensorconfig.sensor_samp; + unsigned int uval ; +#ifdef DOT_CALI + void __user *data1; + char strbuf[256]; + //int cali[3]; + SENSOR_DATA sensor_data; + struct i2c_client *client = container_of(mc32x0_device.parent, struct i2c_client, dev); + //struct mc32x0_data* this = (struct mc32x0_data *)i2c_get_clientdata(client); /* ?õô????????????. */ +#endif + + switch (cmd) { + case ECS_IOCTL_APP_SET_AFLAG: + // enable/disable sensor + + if (copy_from_user(&enable, (short*)arg, sizeof(short))) + { + errlog("Can't get enable flag!!!\n"); + ret = -EFAULT; + goto errioctl; + } + if ((enable >=0) && (enable <=1)) + { + dbg("driver: disable/enable(%d) gsensor. l_sensorconfig.sensor_samp=%d\n", enable, l_sensorconfig.sensor_samp); + + if (enable != l_sensorconfig.sensor_enable) + { + + l_sensorconfig.sensor_enable = enable; + + } + } else { + errlog("Wrong enable argument!!!\n"); + ret = -EFAULT; + goto errioctl; + } + break; + case ECS_IOCTL_APP_SET_DELAY://IOCTL_SENSOR_SET_DELAY_ACCEL: + /*if(copy_from_user((void *)&sensor_duration, (void __user *) arg, sizeof(short))!=0){ + printk("copy from error in %s.\n",__func__); + }*/ + + // set the rate of g-sensor + if (copy_from_user(&delay,(short*)arg, sizeof(short))) + { + errlog("Can't get set delay!!!\n"); + ret = -EFAULT; + goto errioctl; + } + dbg("Get delay=%d \n", delay); + + if ((delay >=0) && (delay < 20)) + { + delay = 20; + } else if (delay > 200) + { + delay = 200; + } + if (delay > 0) + { + l_sensorconfig.sensor_samp = 1000/delay; + } else { + errlog("error delay argument(delay=%d)!!!\n",delay); + ret = -EFAULT; + goto errioctl; + } + + break; +/* + case IOCTL_SENSOR_GET_DELAY_ACCEL: + + if(copy_to_user((void __user *) arg, (const void *)&val, sizeof(short))!=0){ + printk("copy to error in %s.\n",__func__); + } + + break;*/ + case WMT_IOCTL_SENSOR_GET_DRVID: + uval = MC3230_DRVID; + if (copy_to_user((unsigned int*)arg, &uval, sizeof(unsigned int))) + { + return -EFAULT; + } + dbg("mc32x0_driver_id:%d\n",uval); + break; + case WMT_IOCTL_SENOR_GET_RESOLUTION: + if(McubeID &MCUBE_1_5G_8BIT) + uval = (8<<8) | 3; //mc3230:8 bit ,+/-1.5g + if (copy_to_user((unsigned int *)arg, &uval, sizeof(unsigned int))) + { + return -EFAULT; + } + printk("<<<<<<suspend)) + //{ + // GSE_ERR("Perform calibration in suspend state!!\n"); + // err = -EINVAL; + //} + else + { + //this->cali_sw[MC32X0_AXIS_X] += sensor_data.x; + //this->cali_sw[MC32X0_AXIS_Y] += sensor_data.y; + //this->cali_sw[MC32X0_AXIS_Z] += sensor_data.z; + + l_sensorconfig.offset[MC32X0_AXIS_X] = sensor_data.x; + l_sensorconfig.offset[MC32X0_AXIS_Y] = sensor_data.y; + l_sensorconfig.offset[MC32X0_AXIS_Z] = sensor_data.z; + + GSE_LOG("GSENSOR_MCUBE_IOCTL_SET_CALI %d %d %d %d %d %d!!\n", l_sensorconfig.offset[MC32X0_AXIS_X], l_sensorconfig.offset[MC32X0_AXIS_Y],l_sensorconfig.offset[MC32X0_AXIS_Z] ,sensor_data.x, sensor_data.y ,sensor_data.z); + + update_var(); + ret = MC32X0_WriteCalibration(client, l_sensorconfig.offset); + } + + break; + + case GSENSOR_IOCTL_CLR_CALI: + GSE_LOG("fwq GSENSOR_IOCTL_CLR_CALI!!\n"); + l_sensorconfig.offset[0] = 0; + l_sensorconfig.offset[1] = 0; + l_sensorconfig.offset[2] = 0; + + update_var(); + ret = MC32X0_ResetCalibration(client); + break; + + case GSENSOR_IOCTL_GET_CALI: + GSE_LOG("fwq mc32x0 GSENSOR_IOCTL_GET_CALI\n"); + + data1 = (unsigned char*)arg; + + if(data1 == NULL) + { + ret = -EINVAL; + break; + } + + if((ret = MC32X0_ReadCalibration(client,l_sensorconfig.offset))) + { + GSE_LOG("fwq mc32x0 MC32X0_ReadCalibration error!!!!\n"); + break; + } + + sensor_data.x = l_sensorconfig.offset[0];//this->cali_sw[MC32X0_AXIS_X]; + sensor_data.y = l_sensorconfig.offset[1];//this->cali_sw[MC32X0_AXIS_Y]; + sensor_data.z = l_sensorconfig.offset[2];//this->cali_sw[MC32X0_AXIS_Z]; + // if(copy_to_user(data, &sensor_data, sizeof(sensor_data))) + + if(copy_to_user(data1, &sensor_data, sizeof(sensor_data))) + { + ret = -EFAULT; + break; + } + break; + // add by liang **** + //add in Sensors_io.h + //#define GSENSOR_IOCTL_SET_CALI_MODE _IOW(GSENSOR, 0x0e, int) + case GSENSOR_IOCTL_SET_CALI_MODE: + GSE_LOG("fwq mc32x0 GSENSOR_IOCTL_SET_CALI_MODE\n"); + break; + + case GSENSOR_MCUBE_IOCTL_READ_RBM_DATA: + GSE_LOG("fwq GSENSOR_MCUBE_IOCTL_READ_RBM_DATA\n"); + data1 = (void __user *) arg; + if(data1 == NULL) + { + ret = -EINVAL; + break; + } + MC32X0_ReadRBMData(client,(char *)&strbuf); + if(copy_to_user(data1, &strbuf, strlen(strbuf)+1)) + { + ret = -EFAULT; + break; + } + break; + + case GSENSOR_MCUBE_IOCTL_SET_RBM_MODE: + GSE_LOG("fwq GSENSOR_MCUBE_IOCTL_SET_RBM_MODE\n"); + //MCUBE_BACKUP_FILE + /*if(READ_FROM_BACKUP==true) + { + + mcube_copy_file(CALIB_PATH); + + READ_FROM_BACKUP = false; + }*/ + //MCUBE_BACKUP_FILE + MC32X0_rbm(client, 1); + + break; + + case GSENSOR_MCUBE_IOCTL_CLEAR_RBM_MODE: + GSE_LOG("fwq GSENSOR_MCUBE_IOCTL_CLEAR_RBM_MODE\n"); + + MC32X0_rbm(client, 0); + + break; + + case GSENSOR_MCUBE_IOCTL_REGISTER_MAP: + GSE_LOG("fwq GSENSOR_MCUBE_IOCTL_REGISTER_MAP\n"); + + //MC32X0_Read_Reg_Map(client); + + break; +#endif + + + + default: + ret = -EINVAL; + break; + } + +errioctl: + + return ret; +} + + +static int mc32x0_open(struct inode *inode, struct file *filp) +{ + /*int ret; + ret = nonseekable_open(inode, filp);*/ + return 0; +} + +static int mc32x0_release(struct inode *inode, struct file *filp) +{ + return 0; +} + +static struct file_operations sensor_fops = +{ + .owner = THIS_MODULE, + .open = mc32x0_open, + .release = mc32x0_release, + .unlocked_ioctl = mc32x0_ioctl, +}; + +//#ifdef CONFIG_HAS_EARLYSUSPEND +static int mc32x0_i2c_suspend(struct platform_device *pdev, pm_message_t state) +{ + /*struct mc32x0_data *data; + char mc32x0_address; + char mc32x0_data; + + //printk("mc32x0_early_suspend 2 \n"); + + data = container_of(handler, struct mc32x0_data, early_suspend); + + hrtimer_cancel(&data->timer); + */ + cancel_delayed_work_sync(&l_sensorconfig.work); + mc32x0_set_mode(l_sensorconfig.client,MC32X0_STANDBY); + return 0; +} + +static int mc32x0_i2c_resume(struct platform_device *pdev) +{ + struct mc32x0_data *data = &l_sensorconfig; + //char mc32x0_address; + //char mc32x0_data; + + //printk("mc32x0_early_resume 2\n"); + + //data = container_of(handler, struct mc32x0_data, early_suspend); + + //Add 20130722 + mc32x0_chip_init(data->client); + MC32X0_ResetCalibration(data->client); + MC32X0_WriteCalibration(data->client,l_sensorconfig.offset);//mcube_read_cali_file(data->client); + //before + + mc32x0_set_mode(data->client,MC32X0_WAKE); + + queue_delayed_work(data->mc32x0_wq, &data->work, msecs_to_jiffies(sample_rate_2_memsec(data->sensor_samp))); + //hrtimer_start(&data->timer, ktime_set(1, 0), HRTIMER_MODE_REL); + return 0; +} +//#endif + +static struct miscdevice mc32x0_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "sensor_ctrl", + .fops = &sensor_fops, +}; + +static int sensor_writeproc( struct file *file, + const char *buffer, + unsigned long count, + void *data ) +{ + + //int inputval = -1; + int enable, sample = -1; + char tembuf[8]; + //unsigned int amsr = 0; + int test = 0; + + mutex_lock(&l_sensorconfig.lock); + memset(tembuf, 0, sizeof(tembuf)); + // get sensor level and set sensor level + if (sscanf(buffer, "isdbg=%d\n", &l_sensorconfig.isdbg)) + { + // only set the dbg flag + } else if (sscanf(buffer, "samp=%d\n", &sample)) + { + if (sample > 0) + { + if (sample != l_sensorconfig.sensor_samp) + { + // should do sth + } + //printk(KERN_ALERT "sensor samp=%d(amsr:%d) has been set.\n", sample, amsr); + } else { + klog("Wrong sample argumnet of sensor.\n"); + } + } else if (sscanf(buffer, "enable=%d\n", &enable)) + { + if ((enable < 0) || (enable > 1)) + { + dbg("The argument to enable/disable g-sensor should be 0 or 1 !!!\n"); + } else if (enable != l_sensorconfig.sensor_enable) + { + //mma_enable_disable(enable); + l_sensorconfig.sensor_enable = enable; + } + } else if (sscanf(buffer, "sensor_test=%d\n", &test)) + { // for test begin + l_sensorconfig.test_pass = 0; + } else if (sscanf(buffer, "sensor_testend=%d\n", &test)) + { // Don nothing only to be compatible the before testing program + } + mutex_unlock(&l_sensorconfig.lock); + return count; +} + +static int sensor_readproc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = 0; + + len = sprintf(page, + "test_pass=%d\nisdbg=%d\nrate=%d\nenable=%d\n", + l_sensorconfig.test_pass, + l_sensorconfig.isdbg, + l_sensorconfig.sensor_samp, + l_sensorconfig.sensor_enable + ); + return len; +} + +static int mc32x0_probe(struct platform_device *pdev) +{ + int ret = 0; + struct mc32x0_data *data = &l_sensorconfig; + struct i2c_client *client = data->client; + +#ifdef DOT_CALI + load_cali_flg = 30; +#endif + data->sensor_proc = create_proc_entry(GSENSOR_PROC_NAME, 0666, NULL/*&proc_root*/); + if (data->sensor_proc != NULL) + { + data->sensor_proc->write_proc = sensor_writeproc; + data->sensor_proc->read_proc = sensor_readproc; + } + + data->mc32x0_wq = create_singlethread_workqueue("mc32x0_wq"); + if (!data->mc32x0_wq ) + { + ret = -ENOMEM; + goto err_create_workqueue_failed; + } + + INIT_DELAYED_WORK(&data->work, mc32x0_work_func); + //INIT_WORK(&data->work, mc32x0_work_func); + mutex_init(&data->lock); + + + data->input_dev = input_allocate_device(); + if (!data->input_dev) { + ret = -ENOMEM; + goto exit_input_dev_alloc_failed; + } + + + dev.client=client; + + i2c_set_clientdata(client, data); + #ifdef DOT_CALI + mc32x0_reset(client); + #endif + + set_bit(EV_ABS, data->input_dev->evbit); + data->map[0] = G_0; + data->map[1] = G_1; + data->map[2] = G_2; + data->inv[0] = G_0_REVERSE; + data->inv[1] = G_1_REVERSE; + data->inv[2] = G_2_REVERSE; + + input_set_abs_params(data->input_dev, ABS_X, -32*8, 32*8, INPUT_FUZZ, INPUT_FLAT); + input_set_abs_params(data->input_dev, ABS_Y, -32*8, 32*8, INPUT_FUZZ, INPUT_FLAT); + input_set_abs_params(data->input_dev, ABS_Z, -32*8, 32*8, INPUT_FUZZ, INPUT_FLAT); + + data->input_dev->name = "g-sensor"; + + + ret = input_register_device(data->input_dev); + if (ret) { + goto exit_input_register_device_failed; + } + mc32x0_device.parent = &client->dev; + ret = misc_register(&mc32x0_device); + if (ret) { + goto exit_misc_device_register_failed; + } + + ret = sysfs_create_group(&client->dev.kobj, &mc32x0_group); +/* + if (!data->use_irq){ + hrtimer_init(&data->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + data->timer.function = mc32x0_timer_func; + hrtimer_start(&data->timer, ktime_set(1, 0), HRTIMER_MODE_REL); + } +*/ + +#ifdef CONFIG_HAS_EARLYSUSPEND + data->early_suspend.suspend = mc32x0_early_suspend; + data->early_suspend.resume = mc32x0_early_resume; + register_early_suspend(&data->early_suspend); +#endif + data->enabled = true; + queue_delayed_work(data->mc32x0_wq, &data->work, msecs_to_jiffies(sample_rate_2_memsec(data->sensor_samp))); + strcpy(mc32x0_on_off_str,"gsensor_int2"); + dprintk(DEBUG_INIT,"mc32x0 probe ok \n"); + + return 0; +exit_misc_device_register_failed: +exit_input_register_device_failed: + input_free_device(data->input_dev); +exit_input_dev_alloc_failed: + destroy_workqueue(data->mc32x0_wq); +err_create_workqueue_failed: + kfree(data); + printk("mc32x0 probe failed \n"); + return ret; + +} + +static int mc32x0_remove(struct platform_device *pdev) +{ + /*struct mc32x0_data *data = i2c_get_clientdata(client); + + hrtimer_cancel(&data->timer); + input_unregister_device(data->input_dev); + //gpio_release(mc32x0_pin_hd, 2); + misc_deregister(&mc32x0_device); + sysfs_remove_group(&client->dev.kobj, &mc32x0_group); + kfree(data);*/ + + if (NULL != l_sensorconfig.mc32x0_wq) + { + cancel_delayed_work_sync(&l_sensorconfig.work); + flush_workqueue(l_sensorconfig.mc32x0_wq); + destroy_workqueue(l_sensorconfig.mc32x0_wq); + l_sensorconfig.mc32x0_wq = NULL; + } + if (l_sensorconfig.sensor_proc != NULL) + { + remove_proc_entry(GSENSOR_PROC_NAME, NULL); + l_sensorconfig.sensor_proc = NULL; + } + misc_deregister(&mc32x0_device); + input_unregister_device(l_sensorconfig.input_dev); + sysfs_remove_group(&l_sensorconfig.client->dev.kobj, &mc32x0_group); + return 0; +} + +static void mc32x0_shutdown(struct platform_device *pdev) +{ + struct mc32x0_data *data = &l_sensorconfig;//i2c_get_clientdata(client); + if(data->enabled) + mc32x0_enable(data,0); +} +/* +static const struct i2c_device_id mc32x0_id[] = { + { SENSOR_NAME, 0 }, + { } +}; + +MODULE_DEVICE_TABLE(i2c, mc32x0_id); + +static struct i2c_driver mc32x0_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .owner = THIS_MODULE, + .name = SENSOR_NAME, + }, + .id_table = mc32x0_id, + .probe = mc32x0_probe, + .remove = mc32x0_remove, + .shutdown = mc32x0_shutdown, + .detect = gsensor_detect, + .address_list = normal_i2c, +}; +*/ +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); +static int get_axisset(void) +{ + char varbuf[64]; + int n; + int varlen; + //int tmpoff[3] = {0}; + memset(varbuf, 0, sizeof(varbuf)); + varlen = sizeof(varbuf); + + pCvt = (struct mc3xx0_hwmsen_convert *)kzalloc(sizeof(struct mc3xx0_hwmsen_convert), GFP_KERNEL); + + if (wmt_getsyspara("wmt.io.mc3230.virtualz", varbuf, &varlen)) { + errlog("Can't get gsensor config in u-boot!!!!\n"); + //return -1; + } else { + sscanf(varbuf, "%d", &g_virtual_z); + + } + printk("%s g_virtual_z %d\n", __FUNCTION__, g_virtual_z); + memset(varbuf, 0, sizeof(varbuf)); + if (wmt_getsyspara("wmt.io.mc3230sensor", varbuf, &varlen)) { + errlog("Can't get gsensor config in u-boot!!!!\n"); + return -1; //open it for no env just,not insmod such module 2014-6-30 + } else { + n = sscanf(varbuf, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", + &l_sensorconfig.op, + &l_sensorconfig.int_gpio, + &l_sensorconfig.samp, + &(pCvt->map[MC3XX0_AXIS_X]), + &(pCvt->sign[MC3XX0_AXIS_X]), + &(pCvt->map[MC3XX0_AXIS_Y]), + &(pCvt->sign[MC3XX0_AXIS_Y]), + &(pCvt->map[MC3XX0_AXIS_Z]), + &(pCvt->sign[MC3XX0_AXIS_Z]), + &(l_sensorconfig.offset[0]), + &(l_sensorconfig.offset[1]), + &(l_sensorconfig.offset[2]) + ); + if (n != 12) { + printk(KERN_ERR "gsensor format is error in u-boot!!!\n"); + return -1; + } + l_sensorconfig.sensor_samp = l_sensorconfig.samp; + + + dbg("get the sensor config: %d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d\n", + l_sensorconfig.op, + l_sensorconfig.int_gpio, + l_sensorconfig.samp, + pCvt->map[MC3XX0_AXIS_X], + pCvt->sign[MC3XX0_AXIS_X], + pCvt->map[MC3XX0_AXIS_Y], + pCvt->sign[MC3XX0_AXIS_Y], + pCvt->map[MC3XX0_AXIS_Z], + pCvt->sign[MC3XX0_AXIS_Z], + l_sensorconfig.offset[0], + l_sensorconfig.offset[1], + l_sensorconfig.offset[2] + ); + } + return 0; +} + +static void mc32x0_platform_release(struct device *device) +{ + return; +} + +static struct platform_device mc32x0_pdevice = { + .name = GSENSOR_NAME, + .id = 0, + .dev = { + .release = mc32x0_platform_release, + }, +}; + +static struct platform_driver mc32x0_pdriver = { + .probe = mc32x0_probe, + .remove = mc32x0_remove, + .suspend = mc32x0_i2c_suspend, + .resume = mc32x0_i2c_resume, + .shutdown = mc32x0_shutdown, + .driver = { + .name = GSENSOR_NAME, + }, +}; + + +static int __init mc32x0_init(void) +{ + struct i2c_client *this_client; + int ret = 0; + + dprintk(DEBUG_INIT, "======%s=========. \n", __func__); + // parse g-sensor u-boot arg + ret = get_axisset(); + if (ret < 0) + { + printk("<<<<<%s user choose to no sensor chip!\n", __func__); + return ret; + } + if (!(this_client = sensor_i2c_register_device(0, MC32X0_I2C_ADDR, GSENSOR_NAME))) + { + printk(KERN_ERR"Can't register gsensor i2c device!\n"); + return -1; + } + + if (mc32x0_chip_init(this_client)) + { + printk(KERN_ERR"Failed to init MC32X0!\n"); + sensor_i2c_unregister_device(this_client); + return -1; + } + + //printk(KERN_ERR"McubeID:%d\n",McubeID); + l_sensorconfig.client = this_client; + + l_dev_class = class_create(THIS_MODULE, GSENSOR_NAME); + if (IS_ERR(l_dev_class)){ + ret = PTR_ERR(l_dev_class); + printk(KERN_ERR "Can't class_create gsensor device !!\n"); + return ret; + } + if((ret = platform_device_register(&mc32x0_pdevice))) + { + klog("Can't register mc3230 platform devcie!!!\n"); + return ret; + } + if ((ret = platform_driver_register(&mc32x0_pdriver)) != 0) + { + errlog("Can't register mc3230 platform driver!!!\n"); + return ret; + } + return ret; +} + +static void __exit mc32x0_exit(void) +{ +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&l_sensorconfig.earlysuspend); +#endif + platform_driver_unregister(&mc32x0_pdriver); + platform_device_unregister(&mc32x0_pdevice); + sensor_i2c_unregister_device(l_sensorconfig.client); + class_destroy(l_dev_class); +} + +//********************************************************************************************************* +MODULE_AUTHOR("Long Chen "); +MODULE_DESCRIPTION("mc32x0 driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("1.1"); + +module_init(mc32x0_init); +module_exit(mc32x0_exit); + diff --git a/ANDROID_3.4.5/drivers/input/sensor/mc3230_gsensor/mc32x0_driver.c b/ANDROID_3.4.5/drivers/input/sensor/mc3230_gsensor/mc32x0_driver.c new file mode 100755 index 00000000..19c81b97 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/mc3230_gsensor/mc32x0_driver.c @@ -0,0 +1,505 @@ +/* + * Copyright (C) 2011 MCUBE, Inc. + * + * Initial Code: + * Tan Liang + */ + + + + + +#include + +#include "mc32x0_driver.h" + + +mc32x0_t *p_mc32x0; /**< pointer to MC32X0 device structure */ + + +/** API Initialization routine + \param *mc32x0 pointer to MC32X0 structured type + \return result of communication routines + */ + +int mcube_mc32x0_init(mc32x0_t *mc32x0) +{ + int comres=0; + unsigned char data; + + p_mc32x0 = mc32x0; /* assign mc32x0 ptr */ + p_mc32x0->dev_addr = MC32X0_I2C_ADDR; /* preset I2C_addr */ + comres += p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, MC32X0_CHIP_ID, &data, 1); /* read Chip Id */ + + p_mc32x0->chip_id = data; + + // init other reg + data = 0x63; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x1b, &data, 1); + data = 0x43; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x1b, &data, 1); + msleep(5); + + data = 0x43; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x07, &data, 1); + data = 0x80; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x1c, &data, 1); + data = 0x80; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x17, &data, 1); + msleep(5); + data = 0x00; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x1c, &data, 1); + data = 0x00; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x17, &data, 1); + + return comres; +} + +int mc32x0_set_image (void) +{ + int comres; + unsigned char data; + if (p_mc32x0==0) + return E_NULL_PTR; + +#ifdef MCUBE_2G_10BIT_TAP + data = MC32X0_MODE_DEF; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Mode_Feature_REG, &data, 1 ); + + data = 0x00; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Sleep_Count_REG, &data, 1 ); + + data = 0x00; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Sample_Rate_REG, &data, 1 ); + + data = 0x80; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Tap_Detection_Enable_REG, &data, 1 ); + + data = 0x05; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_TAP_Dwell_Reject_REG, &data, 1 ); + + data = 0x33; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_RANGE_Control_REG, &data, 1 ); + + data = 0x07; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_TAP_Threshold_REG, &data, 1 ); + + data = 0x04; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Interrupt_Enable_REG, &data, 1 ); + +#endif + +#ifdef MCUBE_2G_10BIT + data = MC32X0_MODE_DEF; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Mode_Feature_REG, &data, 1 ); + + data = 0x00; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Sleep_Count_REG, &data, 1 ); + + data = 0x00; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Sample_Rate_REG, &data, 1 ); + + data = 0x00; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Tap_Detection_Enable_REG, &data, 1 ); + + data = 0x33; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_RANGE_Control_REG, &data, 1 ); + + data = 0x00; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Interrupt_Enable_REG, &data, 1 ); + +#endif + +#ifdef MCUBE_8G_14BIT_TAP + data = MC32X0_MODE_DEF; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Mode_Feature_REG, &data, 1 ); + + data = 0x00; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Sleep_Count_REG, &data, 1 ); + + data = 0x00; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Sample_Rate_REG, &data, 1 ); + + data = 0x80; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Tap_Detection_Enable_REG, &data, 1 ); + + data = 0x05; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_TAP_Dwell_Reject_REG, &data, 1 ); + + data = 0x3F; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_RANGE_Control_REG, &data, 1 ); + + data = 0x07; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_TAP_Threshold_REG, &data, 1 ); + + data = 0x04; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Interrupt_Enable_REG, &data, 1 ); + +#endif + +#ifdef MCUBE_8G_14BIT + data = MC32X0_MODE_DEF; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Mode_Feature_REG, &data, 1 ); + + data = 0x00; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Sleep_Count_REG, &data, 1 ); + + data = 0x00; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Sample_Rate_REG, &data, 1 ); + + data = 0x00; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Tap_Detection_Enable_REG, &data, 1 ); + + data = 0x3F; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_RANGE_Control_REG, &data, 1 ); + + data = 0x00; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Interrupt_Enable_REG, &data, 1 ); + +#endif + + + +#ifdef MCUBE_1_5G_8BIT + data = MC32X0_MODE_DEF; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Mode_Feature_REG, &data, 1 ); + + data = 0x00; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Sleep_Count_REG, &data, 1 ); + + data = 0x00; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Sample_Rate_REG, &data, 1 ); + + data = 0x02; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_RANGE_Control_REG, &data, 1 ); + + data = 0x00; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Tap_Detection_Enable_REG, &data, 1 ); + + data = 0x00; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Interrupt_Enable_REG, &data, 1 ); + +#endif + + +#ifdef MCUBE_1_5G_8BIT_TAP + data = MC32X0_MODE_DEF; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Mode_Feature_REG, &data, 1 ); + + data = 0x00; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Sleep_Count_REG, &data, 1 ); + + data = 0x00; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Sample_Rate_REG, &data, 1 ); + + data = 0x80; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Tap_Detection_Enable_REG, &data, 1 ); + + data = 0x02; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_RANGE_Control_REG, &data, 1 ); + + data = 0x03; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_TAP_Dwell_Reject_REG, &data, 1 ); + + data = 0x07; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_TAP_Threshold_REG, &data, 1 ); + + data = 0x04; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Interrupt_Enable_REG, &data, 1 ); + +#endif + + +#ifdef MCUBE_1_5G_6BIT + + data = MC32X0_MODE_DEF; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Mode_Feature_REG, &data, 1 ); + + data = 0x00; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Sleep_Count_REG, &data, 1 ); + + data = 0x00; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Sample_Rate_REG, &data, 1 ); + + data = 0x00; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_RANGE_Control_REG, &data, 1 ); + + data = 0x00; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Tap_Detection_Enable_REG, &data, 1 ); + + data = 0x00; + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Interrupt_Enable_REG, &data, 1 ); + + +#endif + + + + return comres; +} + + +int mc32x0_get_offset(unsigned char *offset) +{ + return 0; +} + + +int mc32x0_set_offset(unsigned char offset) +{ + return 0; +} + + + + +/** set mc32x0s range + \param range + + \see MC32X0_RANGE_2G + \see MC32X0_RANGE_4G + \see MC32X0_RANGE_8G +*/ +int mc32x0_set_range(char range) +{ + int comres = 0; + unsigned char data; + + if (p_mc32x0==0) + return E_NULL_PTR; + + if (range<3) { + comres = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, MC32X0_RANGE__REG, &data, 1); + data = MC32X0_SET_BITSLICE(data, MC32X0_RANGE, range); + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_RANGE__REG, &data, 1); + + } + return comres; + +} + + +/* readout select range from MC32X0 + \param *range pointer to range setting + \return result of bus communication function + \see MC32X0_RANGE_2G, MC32X0_RANGE_4G, MC32X0_RANGE_8G + \see mc32x0_set_range() +*/ +int mc32x0_get_range(unsigned char *range) +{ + + int comres = 0; + unsigned char data; + + if (p_mc32x0==0) + return E_NULL_PTR; + comres = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, MC32X0_RANGE__REG, &data, 1); + data = MC32X0_GET_BITSLICE(data, MC32X0_RANGE); + + *range = data; + + + return comres; + +} + + + +int mc32x0_set_mode(unsigned char mode) { + + int comres=0; + unsigned char data; + + if (p_mc32x0==0) + return E_NULL_PTR; + + if (mode<4) { + data = MC32X0_MODE_DEF; + data = MC32X0_SET_BITSLICE(data, MC32X0_MODE, mode); + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_MODE__REG, &data, 1 ); + + p_mc32x0->mode = mode; + } + return comres; + +} + + + +int mc32x0_get_mode(unsigned char *mode) +{ + if (p_mc32x0==0) + return E_NULL_PTR; + *mode = p_mc32x0->mode; + return 0; +} + + +int mc32x0_set_bandwidth(char bw) +{ + int comres = 0; + unsigned char data; + + + if (p_mc32x0==0) + return E_NULL_PTR; + + if (bw<7) { + + comres = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, MC32X0_BANDWIDTH__REG, &data, 1 ); + data = MC32X0_SET_BITSLICE(data, MC32X0_BANDWIDTH, bw); + comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_BANDWIDTH__REG, &data, 1 ); + + } + + return comres; + + +} + +int mc32x0_get_bandwidth(unsigned char *bw) { + int comres = 1; + if (p_mc32x0==0) + return E_NULL_PTR; + + comres = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, MC32X0_BANDWIDTH__REG, bw, 1 ); + + *bw = MC32X0_GET_BITSLICE(*bw, MC32X0_BANDWIDTH); + + return comres; + +} + + +int mc32x0_read_accel_x(short *a_x) +{ + int comres; + unsigned char data[2]; + + + if (p_mc32x0==0) + return E_NULL_PTR; + + comres = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, MC32X0_XOUT_EX_L_REG, &data[0],2); + + *a_x = ((short)data[0])|(((short)data[1])<<8); + + return comres; + +} + + + +int mc32x0_read_accel_y(short *a_y) +{ + int comres; + unsigned char data[2]; + + + if (p_mc32x0==0) + return E_NULL_PTR; + + comres = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, MC32X0_YOUT_EX_L_REG, &data[0],2); + + *a_y = ((short)data[0])|(((short)data[1])<<8); + + return comres; +} + + +int mc32x0_read_accel_z(short *a_z) +{ + int comres; + unsigned char data[2]; + + if (p_mc32x0==0) + return E_NULL_PTR; + + comres = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, MC32X0_ZOUT_EX_L_REG, &data[0],2); + + *a_z = ((short)data[0])|(((short)data[1])<<8); + + return comres; +} + + +int mc32x0_read_accel_xyz(mc32x0acc_t * acc) +{ + int comres; + unsigned char data[6]; + + + if (p_mc32x0==0) + return E_NULL_PTR; + +#ifdef MC32X0_HIGH_END + comres = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, MC32X0_XOUT_EX_L_REG, &data[0],6); + + acc->x = ((signed short)data[0])|(((signed short)data[1])<<8); + acc->y = ((signed short)data[2])|(((signed short)data[3])<<8); + acc->z = ((signed short)data[4])|(((signed short)data[5])<<8); +#endif + +#ifdef MC32X0_LOW_END + comres = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, MC32X0_XOUT_REG, &data[0],3); + +#ifndef MCUBE_1_5G_6BIT + acc->x = (signed char)data[0]; + acc->y = (signed char)data[1]; + acc->z = (signed char)data[2]; +#else + acc->x = (signed short)GET_REAL_VALUE(data[0],6); + acc->y = (signed short)GET_REAL_VALUE(data[1],6); + acc->z = (signed short)GET_REAL_VALUE(data[2],6); +#endif + +#endif + + + + + return comres; + +} + + + +int mc32x0_get_interrupt_status(unsigned char * ist) +{ + + int comres=0; + if (p_mc32x0==0) + return E_NULL_PTR; + comres = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, MC32X0_Tilt_Status_REG, ist, 1); + return comres; +} + + + +int mc32x0_read_reg(unsigned char addr, unsigned char *data, unsigned char len) +{ + + int comres; + if (p_mc32x0==0) + return E_NULL_PTR; + + comres = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, addr, data, len); + return comres; + +} + + +int mc32x0_write_reg(unsigned char addr, unsigned char *data, unsigned char len) +{ + + int comres; + + if (p_mc32x0==0) + return E_NULL_PTR; + + comres = p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, addr, data, len); + + return comres; + +} + diff --git a/ANDROID_3.4.5/drivers/input/sensor/mc3230_gsensor/mc32x0_driver.h b/ANDROID_3.4.5/drivers/input/sensor/mc3230_gsensor/mc32x0_driver.h new file mode 100755 index 00000000..0aca80e8 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/mc3230_gsensor/mc32x0_driver.h @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2011 MCUBE, Inc. + * + * Initial Code: + * Tan Liang + */ + + + +#ifndef __MC32X0_H__ +#define __MC32X0_H__ + + + +#define MC32X0_WR_FUNC_PTR char (* bus_write)(unsigned char, unsigned char *, unsigned char) + +#define MC32X0_BUS_WRITE_FUNC(dev_addr, reg_addr, reg_data, wr_len)\ + bus_write(reg_addr, reg_data, wr_len) + +#define MC32X0_RD_FUNC_PTR char (* bus_read)( unsigned char, unsigned char *, unsigned char) + +#define MC32X0_BUS_READ_FUNC(dev_addr, reg_addr, reg_data, r_len)\ + bus_read(reg_addr, reg_data, r_len) + +#define GET_REAL_VALUE(rv, bn) \ + ((rv & (0x01 << (bn - 1))) ? (- (rv & ~(0xffff << (bn - 1)))) : (rv & ~(0xffff << (bn - 1)))) + + + +//#define MC32X0_HIGH_END +/*******MC3210/20 define this**********/ + +//#define MCUBE_2G_10BIT_TAP +//#define MCUBE_2G_10BIT +//#define MCUBE_8G_14BIT_TAP +//#define MCUBE_8G_14BIT + + + +//#define MC32X0_LOW_END +/*******MC3230 define this**********/ + +//#define MCUBE_1_5G_8BIT +//#define MCUBE_1_5G_8BIT_TAP + + + + + +/** MC32X0 I2C Address +*/ + +#define MC32X0_I2C_ADDR 0x4c // 0x98 >> 1 + + + +/* + MC32X0 API error codes +*/ + +#define E_NULL_PTR (char)-127 + +/* + * + * register definitions + * + */ + +#define MC32X0_XOUT_REG 0x00 +#define MC32X0_YOUT_REG 0x01 +#define MC32X0_ZOUT_REG 0x02 +#define MC32X0_Tilt_Status_REG 0x03 +#define MC32X0_Sampling_Rate_Status_REG 0x04 +#define MC32X0_Sleep_Count_REG 0x05 +#define MC32X0_Interrupt_Enable_REG 0x06 +#define MC32X0_Mode_Feature_REG 0x07 +#define MC32X0_Sample_Rate_REG 0x08 +#define MC32X0_Tap_Detection_Enable_REG 0x09 +#define MC32X0_TAP_Dwell_Reject_REG 0x0a +#define MC32X0_DROP_Control_Register_REG 0x0b +#define MC32X0_SHAKE_Debounce_REG 0x0c +#define MC32X0_XOUT_EX_L_REG 0x0d +#define MC32X0_XOUT_EX_H_REG 0x0e +#define MC32X0_YOUT_EX_L_REG 0x0f +#define MC32X0_YOUT_EX_H_REG 0x10 +#define MC32X0_ZOUT_EX_L_REG 0x11 +#define MC32X0_ZOUT_EX_H_REG 0x12 +#define MC32X0_CHIP_ID 0x18 +#define MC32X0_RANGE_Control_REG 0x20 +#define MC32X0_SHAKE_Threshold_REG 0x2B +#define MC32X0_UD_Z_TH_REG 0x2C +#define MC32X0_UD_X_TH_REG 0x2D +#define MC32X0_RL_Z_TH_REG 0x2E +#define MC32X0_RL_Y_TH_REG 0x2F +#define MC32X0_FB_Z_TH_REG 0x30 +#define MC32X0_DROP_Threshold_REG 0x31 +#define MC32X0_TAP_Threshold_REG 0x32 + + + + +/** MC32X0 acceleration data + \brief Structure containing acceleration values for x,y and z-axis in signed short + +*/ + +typedef struct { + short x, /**< holds x-axis acceleration data sign extended. Range -512 to 511. */ + y, /**< holds y-axis acceleration data sign extended. Range -512 to 511. */ + z; /**< holds z-axis acceleration data sign extended. Range -512 to 511. */ +} mc32x0acc_t; + +/* RANGE */ + +#define MC32X0_RANGE__POS 2 +#define MC32X0_RANGE__LEN 2 +#define MC32X0_RANGE__MSK 0x0c +#define MC32X0_RANGE__REG MC32X0_RANGE_Control_REG + +/* MODE */ + +#define MC32X0_MODE__POS 0 +#define MC32X0_MODE__LEN 2 +#define MC32X0_MODE__MSK 0x03 +#define MC32X0_MODE__REG MC32X0_Mode_Feature_REG + +#define MC32X0_MODE_DEF 0x43 + + +/* BANDWIDTH */ + +#define MC32X0_BANDWIDTH__POS 4 +#define MC32X0_BANDWIDTH__LEN 3 +#define MC32X0_BANDWIDTH__MSK 0x70 +#define MC32X0_BANDWIDTH__REG MC32X0_RANGE_Control_REG + + +#define MC32X0_GET_BITSLICE(regvar, bitname)\ + (regvar & bitname##__MSK) >> bitname##__POS + + +#define MC32X0_SET_BITSLICE(regvar, bitname, val)\ + (regvar & ~bitname##__MSK) | ((val< +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include + + +#include +#include + +#include "../sensor.h" + + +//#include + +//=== CONFIGURATIONS ========================================================== +//#define _MC3XXX_DEBUG_ON_ + +//============================================================================= +#ifdef _MC3XXX_DEBUG_ON_ + #define mcprintkreg(x...) printk(x) + #define mcprintkfunc(x...) printk(x) + #define GSE_ERR(x...) printk(x) + #define GSE_LOG(x...) printk(x) +#else + #define mcprintkreg(x...) + #define mcprintkfunc(x...) + #define GSE_ERR(x...) + #define GSE_LOG(x...) +#endif + +static int g_virtual_z = 0; +#define G_2_REVERSE_VIRTUAL_Z 0 //!!!!! 1 +#define SUPPORT_VIRTUAL_Z_SENSOR //add 2013-10-23 +#define LOW_RESOLUTION 1 +#define HIGH_RESOLUTION 2 +#define RBM_RESOLUTION 3 +#ifdef SUPPORT_VIRTUAL_Z_SENSOR +#define Low_Pos_Max 127 +#define Low_Neg_Max -128 +#define High_Pos_Max 8191 +#define High_Neg_Max -8192 +#define VIRTUAL_Z 1 +static int Railed = 0; +#else +#define VIRTUAL_Z 0 +#endif + + +static struct class* l_dev_class = NULL; + + +#define SENSOR_NAME "mc3xxx" +#define SENSOR_DRIVER_VERSION "1.0.0" +#define SENSOR_DATA_SIZE 3 + +//static int mc3xxx_pin_hd; +//static char mc3xxx_on_off_str[32]; +#define G_0 ABS_Y +#define G_1 ABS_X +#define G_2 ABS_Z +#define G_0_REVERSE 1 +#define G_1_REVERSE 1 +#define G_2_REVERSE 1 + +//static unsigned char s_bResolution = 0x00; +static unsigned char s_bPCODE = 0x00; +static unsigned short mc3xxx_i2c_auto_probe_addr[] = { 0x4C, 0x6C, 0x4E, 0x6D, 0x6E, 0x6F }; + +//============================================================================= +#define SENSOR_DMARD_IOCTL_BASE 234 +#define IOCTL_SENSOR_SET_DELAY_ACCEL _IO(SENSOR_DMARD_IOCTL_BASE, 100) +#define IOCTL_SENSOR_GET_DELAY_ACCEL _IO(SENSOR_DMARD_IOCTL_BASE, 101) +#define IOCTL_SENSOR_GET_STATE_ACCEL _IO(SENSOR_DMARD_IOCTL_BASE, 102) +#define IOCTL_SENSOR_SET_STATE_ACCEL _IO(SENSOR_DMARD_IOCTL_BASE, 103) +#define IOCTL_SENSOR_GET_DATA_ACCEL _IO(SENSOR_DMARD_IOCTL_BASE, 104) + +#define IOCTL_MSENSOR_SET_DELAY_MAGNE _IO(SENSOR_DMARD_IOCTL_BASE, 200) +#define IOCTL_MSENSOR_GET_DATA_MAGNE _IO(SENSOR_DMARD_IOCTL_BASE, 201) +#define IOCTL_MSENSOR_GET_STATE_MAGNE _IO(SENSOR_DMARD_IOCTL_BASE, 202) +#define IOCTL_MSENSOR_SET_STATE_MAGNE _IO(SENSOR_DMARD_IOCTL_BASE, 203) + +#define IOCTL_SENSOR_GET_NAME _IO(SENSOR_DMARD_IOCTL_BASE, 301) +#define IOCTL_SENSOR_GET_VENDOR _IO(SENSOR_DMARD_IOCTL_BASE, 302) +#define IOCTL_SENSOR_GET_CONVERT_PARA _IO(SENSOR_DMARD_IOCTL_BASE, 401) +//#define SENSOR_CALIBRATION _IOWR(SENSOR_DMARD_IOCTL_BASE, 402, int[SENSOR_DATA_SIZE]) + +//============================================================================= +#define MC3XXX_CONVERT_PARAMETER (1.5f * (9.80665f) / 256.0f) +#define MC3XXX_DISPLAY_NAME SENSOR_NAME +#define MC3XXX_DIPLAY_VENDOR "mCube" + +//============================================================================= +#define MC3XXX_AXIS_X 0 +#define MC3XXX_AXIS_Y 1 +#define MC3XXX_AXIS_Z 2 +#define MC3XXX_AXIS_NUM 3 +#define MC3XXX_DATA_LEN 6 + + +/*********************************************** + *** REGISTER MAP + ***********************************************/ +#define MC3XXX_REG_XOUT 0x00 +#define MC3XXX_REG_YOUT 0x01 +#define MC3XXX_REG_ZOUT 0x02 +#define MC3XXX_REG_TILT_STATUS 0x03 +#define MC3XXX_REG_SAMPLE_RATE_STATUS 0x04 +#define MC3XXX_REG_SLEEP_COUNT 0x05 +#define MC3XXX_REG_INTERRUPT_ENABLE 0x06 +#define MC3XXX_REG_MODE_FEATURE 0x07 +#define MC3XXX_REG_SAMPLE_RATE 0x08 +#define MC3XXX_REG_TAP_DETECTION_ENABLE 0x09 +#define MC3XXX_REG_TAP_DWELL_REJECT 0x0A +#define MC3XXX_REG_DROP_CONTROL 0x0B +#define MC3XXX_REG_SHAKE_DEBOUNCE 0x0C +#define MC3XXX_REG_XOUT_EX_L 0x0D +#define MC3XXX_REG_XOUT_EX_H 0x0E +#define MC3XXX_REG_YOUT_EX_L 0x0F +#define MC3XXX_REG_YOUT_EX_H 0x10 +#define MC3XXX_REG_ZOUT_EX_L 0x11 +#define MC3XXX_REG_ZOUT_EX_H 0x12 +#define MC3XXX_REG_RANGE_CONTROL 0x20 +#define MC3XXX_REG_SHAKE_THRESHOLD 0x2B +#define MC3XXX_REG_UD_Z_TH 0x2C +#define MC3XXX_REG_UD_X_TH 0x2D +#define MC3XXX_REG_RL_Z_TH 0x2E +#define MC3XXX_REG_RL_Y_TH 0x2F +#define MC3XXX_REG_FB_Z_TH 0x30 +#define MC3XXX_REG_DROP_THRESHOLD 0x31 +#define MC3XXX_REG_TAP_THRESHOLD 0x32 +#define MC3XXX_REG_PRODUCT_CODE 0x3B + +/*********************************************** + *** RETURN CODE + ***********************************************/ +#define MC3XXX_RETCODE_SUCCESS (0) +#define MC3XXX_RETCODE_ERROR_I2C (-1) +#define MC3XXX_RETCODE_ERROR_NULL_POINTER (-2) +#define MC3XXX_RETCODE_ERROR_STATUS (-3) +#define MC3XXX_RETCODE_ERROR_SETUP (-4) +#define MC3XXX_RETCODE_ERROR_GET_DATA (-5) +#define MC3XXX_RETCODE_ERROR_IDENTIFICATION (-6) + + +/*********************************************** + *** CONFIGURATION + ***********************************************/ +#define MC3XXX_BUF_SIZE 256 + +#define MCUBE_1_5G_8BIT 0x01 //MC3XXX_LOW_END +#define MCUBE_8G_14BIT 0x02 //MC3XXX_HIGH_END + +#define DOT_CALI + + +#define SENSOR_DURATION_DEFAULT 20 + +#define INPUT_FUZZ 0 +#define INPUT_FLAT 0 + +/*********************************************** + *** PRODUCT ID + ***********************************************/ +#define MC3XXX_PCODE_3210 0x90 +#define MC3XXX_PCODE_3230 0x19 +#define MC3XXX_PCODE_3250 0x88 +#define MC3XXX_PCODE_3410 0xA8 +#define MC3XXX_PCODE_3410N 0xB8 +#define MC3XXX_PCODE_3430 0x29 +#define MC3XXX_PCODE_3430N 0x39 +#define MC3XXX_PCODE_3510B 0x40 +#define MC3XXX_PCODE_3530B 0x30 +#define MC3XXX_PCODE_3510C 0x10 +#define MC3XXX_PCODE_3530C 0x6E + +//============================================================================= +static unsigned char is_new_mc34x0 = 0; +static unsigned char is_mc3250 = 0; +static unsigned char is_mc35xx = 0; +static unsigned char Sensor_Accuracy = 0; + + +//============================================================================= +#ifdef DOT_CALI +#define CALIB_PATH "/data/data/com.mcube.acc/files/mcube-calib.txt" +//MCUBE_BACKUP_FILE +#define BACKUP_CALIB_PATH "/data/misc/mcube-calib.txt" +static char backup_buf[64]; +//MCUBE_BACKUP_FILE +#define DATA_PATH "/sdcard/mcube-register-map.txt" + +typedef struct { + unsigned short x; /**< X axis */ + unsigned short y; /**< Y axis */ + unsigned short z; /**< Z axis */ +} GSENSOR_VECTOR3D; + +static GSENSOR_VECTOR3D gsensor_gain = { 0 }; +static struct miscdevice mc3xxx_device; + +static struct file * fd_file = NULL; + +static mm_segment_t oldfs = { 0 }; +static unsigned char offset_buf[6] = { 0 }; +static signed int offset_data[3] = { 0 }; +s16 G_RAW_DATA[3] = { 0 }; +static signed int gain_data[3] = { 0 }; +static signed int enable_RBM_calibration = 0; + +#define GSENSOR 0x95 +#define GSENSOR_IOCTL_INIT _IO(GSENSOR, 0x01) +#define GSENSOR_IOCTL_READ_CHIPINFO _IOR(GSENSOR, 0x02, int) +#define GSENSOR_IOCTL_READ_SENSORDATA _IOR(GSENSOR, 0x03, int) +#define GSENSOR_IOCTL_READ_OFFSET _IOR(GSENSOR, 0x04, GSENSOR_VECTOR3D) +#define GSENSOR_IOCTL_READ_GAIN _IOR(GSENSOR, 0x05, GSENSOR_VECTOR3D) +#define GSENSOR_IOCTL_READ_RAW_DATA _IOR(GSENSOR, 0x06, int) +//#define GSENSOR_IOCTL_SET_CALI _IOW(GSENSOR, 0x06, SENSOR_DATA) +#define GSENSOR_IOCTL_GET_CALI _IOW(GSENSOR, 0x07, SENSOR_DATA) +#define GSENSOR_IOCTL_CLR_CALI _IO(GSENSOR, 0x08) +#define GSENSOR_MCUBE_IOCTL_READ_RBM_DATA _IOR(GSENSOR, 0x09, SENSOR_DATA) +#define GSENSOR_MCUBE_IOCTL_SET_RBM_MODE _IO(GSENSOR, 0x0a) +#define GSENSOR_MCUBE_IOCTL_CLEAR_RBM_MODE _IO(GSENSOR, 0x0b) +#define GSENSOR_MCUBE_IOCTL_SET_CALI _IOW(GSENSOR, 0x0c, SENSOR_DATA) +#define GSENSOR_MCUBE_IOCTL_REGISTER_MAP _IO(GSENSOR, 0x0d) +#define GSENSOR_IOCTL_SET_CALI_MODE _IOW(GSENSOR, 0x0e,int) +#define GSENSOR_MCUBE_IOCTL_READ_PRODUCT_ID _IOR(GSENSOR, 0x0f, int) +#define GSENSOR_MCUBE_IOCTL_READ_FILEPATH _IOR(GSENSOR, 0x10, char[256]) + + +static int MC3XXX_ReadRegMap(struct i2c_client *client, u8 *pbUserBuf); +static int mc3xxx_chip_init(struct i2c_client *client); +static int MC3XXX_ResetCalibration(struct i2c_client *client); +static int MC3XX0_ValidateSensorIC(unsigned char bPCode); + + +typedef struct{ + int x; + int y; + int z; +}SENSOR_DATA; + +static int load_cali_flg = 0; +static int wake_mc3xxx_flg = 0; + +//MCUBE_BACKUP_FILE +static bool READ_FROM_BACKUP = false; +//MCUBE_BACKUP_FILE + +#endif + +#define MC3XXX_WAKE 1 +#define MC3XXX_SNIFF 2 +#define MC3XXX_STANDBY 3 + +struct dev_data { + struct i2c_client *client; +}; + +static struct dev_data dev = { 0 }; + +struct acceleration { + int x; + int y; + int z; +}; + +struct mc3xxx_data { + struct mutex lock; + struct i2c_client *client; + struct delayed_work work; + struct workqueue_struct *mc3xxx_wq; + struct hrtimer timer; + struct device *device; + struct input_dev *input_dev; + int use_count; + int enabled; + volatile unsigned int duration; + int use_irq; + int irq; + unsigned long irqflags; + int gpio; + unsigned int map[3]; + int inv[3]; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif + // for control + int int_gpio; //0-3 + int op; + int samp; + //int xyz_axis[3][3]; // (axis,direction) + struct proc_dir_entry* sensor_proc; + int isdbg; + int sensor_samp; // + int sensor_enable; // 0 --> disable sensor, 1 --> enable sensor + int test_pass; + int offset[MC3XXX_AXIS_NUM+1]; /*+1: for 4-byte alignment*/ + s16 data[MC3XXX_AXIS_NUM+1]; +}; + +static struct mc3xxx_data l_sensorconfig = { + .op = 0, + .int_gpio = 3, + .samp = 16, + /*.xyz_axis = { + {ABS_X, -1}, + {ABS_Y, 1}, + {ABS_Z, -1}, + },*/ + .sensor_proc = NULL, + .isdbg = 1, + .sensor_samp = 1, // 1 sample/second + .sensor_enable = 1, // enable sensor + .test_pass = 0, // for test program + //.offset={0,0,0}, +}; + + +//============================================================================= +enum mc3xx0_orientation +{ + MC3XX0_TOP_LEFT_DOWN = 0, + MC3XX0_TOP_RIGHT_DOWN, + MC3XX0_TOP_RIGHT_UP, + MC3XX0_TOP_LEFT_UP, + MC3XX0_BOTTOM_LEFT_DOWN, + MC3XX0_BOTTOM_RIGHT_DOWN, + MC3XX0_BOTTOM_RIGHT_UP, + MC3XX0_BOTTOM_LEFT_UP +}; + + +struct mc3xx0_hwmsen_convert +{ + signed int sign[3]; + unsigned int map[3]; +}; + +// Transformation matrix for chip mounting position +static const struct mc3xx0_hwmsen_convert mc3xx0_cvt[] = +{ + {{ 1, 1, 1}, {MC3XXX_AXIS_X, MC3XXX_AXIS_Y, MC3XXX_AXIS_Z}}, // 0: top , left-down + {{-1, 1, 1}, {MC3XXX_AXIS_Y, MC3XXX_AXIS_X, MC3XXX_AXIS_Z}}, // 1: top , right-down + {{-1, -1, 1}, {MC3XXX_AXIS_X, MC3XXX_AXIS_Y, MC3XXX_AXIS_Z}}, // 2: top , right-up + {{ 1, -1, 1}, {MC3XXX_AXIS_Y, MC3XXX_AXIS_X, MC3XXX_AXIS_Z}}, // 3: top , left-up + {{-1, 1, -1}, {MC3XXX_AXIS_X, MC3XXX_AXIS_Y, MC3XXX_AXIS_Z}}, // 4: bottom, left-down + {{ 1, 1, -1}, {MC3XXX_AXIS_Y, MC3XXX_AXIS_X, MC3XXX_AXIS_Z}}, // 5: bottom, right-down + {{ 1, -1, -1}, {MC3XXX_AXIS_X, MC3XXX_AXIS_Y, MC3XXX_AXIS_Z}}, // 6: bottom, right-up + {{-1, -1, -1}, {MC3XXX_AXIS_Y, MC3XXX_AXIS_X, MC3XXX_AXIS_Z}}, // 7: bottom, left-up +}; + +//static unsigned char mc3xx0_current_placement = MC3XX0_TOP_RIGHT_UP; // current soldered placement +static struct mc3xx0_hwmsen_convert *pCvt; + +#ifdef SUPPORT_VIRTUAL_Z_SENSOR //add 2013-10-23 +int Verify_Z_Railed(int AccData, int resolution) +{ + int status = 0; + GSE_LOG("%s: AccData = %d",__func__, AccData); + if(resolution == 1) // Low resolution + { + if((AccData >= Low_Pos_Max && AccData >=0)|| (AccData <= Low_Neg_Max && AccData < 0)) + { + status = 1; + GSE_LOG("%s: Railed at Low Resolution",__func__); + } + } + else if (resolution == 2) //High resolution + { + if((AccData >= High_Pos_Max && AccData >=0) || (AccData <= High_Neg_Max && AccData < 0)) + { + status = 1; + GSE_LOG("%s: Railed at High Resolution",__func__); + } + } + else if (resolution == 3) //High resolution + { + if((AccData >= Low_Pos_Max*3 && AccData >=0) || (AccData <= Low_Neg_Max*3 && AccData < 0)) + { + status = 1; + GSE_LOG("%s: Railed at High Resolution",__func__); + } + } + else + GSE_LOG("%s, Wrong resolution",__func__); + + return status; +} + +int SquareRoot(int x) +{ + int lowerbound; + int upperbound; + int root; + + if(x < 0) return -1; + if(x == 0 || x == 1) return x; + lowerbound = 1; + upperbound = x; + root = lowerbound + (upperbound - lowerbound)/2; + + while(root > x/root || root+1 <= x/(root+1)) + { + if(root > x/root) + { + upperbound = root; + } + else + { + lowerbound = root; + } + root = lowerbound + (upperbound - lowerbound)/2; + } + GSE_LOG("%s: Sqrt root is %d",__func__, root); + return root; +} +#endif + + +unsigned int sample_rate_2_memsec(unsigned int rate) +{ + return (1000/rate); +} + + +//============================================================================= +//volatile static short sensor_duration = SENSOR_DURATION_DEFAULT; +//volatile static short sensor_state_flag = 1; + +//============================================================================= +static ssize_t mc3xxx_map_show(struct device *dev, struct device_attribute *attr,char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct mc3xxx_data *data = NULL; + int i = 0; + data = i2c_get_clientdata(client); + for (i = 0; i< 3; i++) + { + if(data->inv[i] == 1) + { + switch(data->map[i]) + { + case ABS_X: + buf[i] = 'x'; + break; + case ABS_Y: + buf[i] = 'y'; + break; + case ABS_Z: + buf[i] = 'z'; + break; + default: + buf[i] = '_'; + break; + } + } + else + { + switch(data->map[i]) + { + case ABS_X: + buf[i] = 'X'; + break; + case ABS_Y: + buf[i] = 'Y'; + break; + case ABS_Z: + buf[i] = 'Z'; + break; + default: + buf[i] = '-'; + break; + } + } + } + sprintf(buf+3,"\r\n"); + return 5; +} + +/***************************************** + *** show_regiter_map + *****************************************/ +static ssize_t show_regiter_map(struct device *dev, struct device_attribute *attr, char *buf) +{ + u8 _bIndex = 0; + u8 _baRegMap[64] = { 0 }; + ssize_t _tLength = 0; + + struct i2c_client *client = to_i2c_client(dev); + + MC3XXX_ReadRegMap(client, _baRegMap); + + for (_bIndex = 0; _bIndex < 64; _bIndex++) + _tLength += snprintf((buf + _tLength), (PAGE_SIZE - _tLength), "Reg[0x%02X]: 0x%02X\n", _bIndex, _baRegMap[_bIndex]); + + return (_tLength); +} + +static ssize_t mc3xxx_map_store(struct device *dev, struct device_attribute *attr,const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct mc3xxx_data *data = NULL; + int i = 0; + data = i2c_get_clientdata(client); + + if(count < 3) return -EINVAL; + + for(i = 0; i< 3; i++) + { + switch(buf[i]) + { + case 'x': + data->map[i] = ABS_X; + data->inv[i] = 1; + break; + case 'y': + data->map[i] = ABS_Y; + data->inv[i] = 1; + break; + case 'z': + data->map[i] = ABS_Z; + data->inv[i] = 1; + break; + case 'X': + data->map[i] = ABS_X; + data->inv[i] = -1; + break; + case 'Y': + data->map[i] = ABS_Y; + data->inv[i] = -1; + break; + case 'Z': + data->map[i] = ABS_Z; + data->inv[i] = -1; + break; + default: + return -EINVAL; + } + } + + return count; +} + +//============================================================================= +static ssize_t mc3xxx_version_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", SENSOR_DRIVER_VERSION); +} + +//============================================================================= +static ssize_t mc3xxx_chip_id_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + unsigned char bChipID[4] = { 0 }; + struct i2c_client *client = to_i2c_client(dev); + + i2c_smbus_read_i2c_block_data(client, 0x3C, 4, bChipID); + + return sprintf(buf, "%02X-%02X-%02X-%02X\n", bChipID[0], bChipID[1], bChipID[2], bChipID[3]); +} +/* +//============================================================================= +static ssize_t mc3xxx_position_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + printk("%s called\n", __func__); + return sprintf(buf, "%d\n", mc3xx0_current_placement); +} + +//============================================================================= +static ssize_t mc3xxx_position_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned long position = 0; + + printk("%s called\n", __func__); + + position = simple_strtoul(buf, NULL,10); + + if (position < 8) + mc3xx0_current_placement = position; + + return count; +} +*/ + +static int mc3xxx_enable(struct mc3xxx_data *data, int enable) +{ + if(enable) + { + msleep(10); + //mutex_lock(&data->lock); + mc3xxx_chip_init(data->client); + //mutex_unlock(&data->lock); + queue_delayed_work(data->mc3xxx_wq, &data->work, msecs_to_jiffies(sample_rate_2_memsec(data->sensor_samp)));//hrtimer_start(&data->timer, ktime_set(0, sensor_duration*1000000), HRTIMER_MODE_REL); + data->enabled = true; + } + else + { + cancel_delayed_work_sync(&l_sensorconfig.work);//hrtimer_cancel(&data->timer); + data->enabled = false; + } + return 0; +} + +static ssize_t mc3xxx_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = container_of(mc3xxx_device.parent, struct i2c_client, dev); + + struct mc3xxx_data *mc3xxx = i2c_get_clientdata(client); + + + return sprintf(buf, "%d\n", mc3xxx->enabled); +} + +static ssize_t mc3xxx_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + + bool new_enable; + + struct i2c_client *client = container_of(mc3xxx_device.parent, struct i2c_client, dev); + + struct mc3xxx_data *mc3xxx = i2c_get_clientdata(client); + + if (sysfs_streq(buf, "1")) + new_enable = true; + else if (sysfs_streq(buf, "0")) + new_enable = false; + else + { + pr_debug("%s: invalid value %d\n", __func__, *buf); + return -EINVAL; + } + + mc3xxx_enable(mc3xxx, new_enable); + + return count; +} + + +static DRIVER_ATTR(regmap , S_IRUGO, show_regiter_map, NULL ); +static DEVICE_ATTR(map, S_IWUSR | S_IRUGO, mc3xxx_map_show, mc3xxx_map_store); +static DEVICE_ATTR(version , S_IRUGO , mc3xxx_version_show , NULL ); +static DEVICE_ATTR(chipid , S_IRUGO , mc3xxx_chip_id_show , NULL ); +//static DEVICE_ATTR(position, S_IRUGO | S_IWUSR | S_IWGRP, mc3xxx_position_show, mc3xxx_position_store); +static DEVICE_ATTR(enable, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH, mc3xxx_enable_show, mc3xxx_enable_store); +static struct attribute* mc3xxx_attrs[] = +{ + &driver_attr_regmap, + &dev_attr_map.attr, + &dev_attr_version.attr, + &dev_attr_chipid.attr, + //&dev_attr_position.attr, + &dev_attr_enable.attr, + NULL +}; + +static const struct attribute_group mc3xxx_group = +{ + .attrs = mc3xxx_attrs, +}; + +//============================================================================= +static int mc3xxx_chip_init(struct i2c_client *client) +{ + unsigned char data = 0; + + data = i2c_smbus_read_byte_data(client, MC3XXX_REG_PRODUCT_CODE); + s_bPCODE =data; + if((data == MC3XXX_PCODE_3230)||(data == MC3XXX_PCODE_3430) + ||(data == MC3XXX_PCODE_3430N)||(data == MC3XXX_PCODE_3530B) + ||((data|0x0E) == MC3XXX_PCODE_3530C)) + Sensor_Accuracy = MCUBE_1_5G_8BIT; //8bit + else if((data == MC3XXX_PCODE_3210)||(data == MC3XXX_PCODE_3410) + ||(data == MC3XXX_PCODE_3250)||(data == MC3XXX_PCODE_3410N) + ||(data == MC3XXX_PCODE_3510B)||(data == MC3XXX_PCODE_3510C)) + Sensor_Accuracy = MCUBE_8G_14BIT; //14bit + else + Sensor_Accuracy = 0; + + if (data == MC3XXX_PCODE_3250) + is_mc3250 = 1; + + if ((data == MC3XXX_PCODE_3430N)||(data == MC3XXX_PCODE_3410N)) + is_new_mc34x0 = 1; + + if((MC3XXX_PCODE_3510B == data) || (MC3XXX_PCODE_3510C == data) + ||(data == MC3XXX_PCODE_3530B)||((data|0x0E) == MC3XXX_PCODE_3530C)) + is_mc35xx = 1; + + + if(MCUBE_8G_14BIT == Sensor_Accuracy) + { + data = 0x43; + i2c_smbus_write_byte_data(client, MC3XXX_REG_MODE_FEATURE, data); + data = 0x00; + i2c_smbus_write_byte_data(client, MC3XXX_REG_SLEEP_COUNT, data); + + data = 0x00; + if (is_mc35xx) + { + data = 0x0A; + } + + i2c_smbus_write_byte_data(client, MC3XXX_REG_SAMPLE_RATE, data); + + data = 0x3F; + if ((MC3XXX_PCODE_3510B == s_bPCODE) || (MC3XXX_PCODE_3510C == s_bPCODE)) + data = 0x25; + else if ((MC3XXX_PCODE_3530B == s_bPCODE) || (MC3XXX_PCODE_3530C == (s_bPCODE|0x0E))) + data = 0x02; + + i2c_smbus_write_byte_data(client, MC3XXX_REG_RANGE_CONTROL, data); + data = 0x00; + i2c_smbus_write_byte_data(client, MC3XXX_REG_TAP_DETECTION_ENABLE, data); + data = 0x00; + i2c_smbus_write_byte_data(client, MC3XXX_REG_INTERRUPT_ENABLE, data); + + #ifdef DOT_CALI + gsensor_gain.x = gsensor_gain.y = gsensor_gain.z = 1024; + #endif + } + else if(MCUBE_1_5G_8BIT == Sensor_Accuracy) + { + data = 0x43; + i2c_smbus_write_byte_data(client, MC3XXX_REG_MODE_FEATURE, data); + data = 0x00; + i2c_smbus_write_byte_data(client, MC3XXX_REG_SLEEP_COUNT, data); + + data = 0x00; + if (is_mc35xx) + { + data = 0x0A; + } + + i2c_smbus_write_byte_data(client, MC3XXX_REG_SAMPLE_RATE, data); + + data = 0x32; + if ((MC3XXX_PCODE_3510B == s_bPCODE) || (MC3XXX_PCODE_3510C == s_bPCODE)) + data = 0x25; + else if ((MC3XXX_PCODE_3530B == s_bPCODE) || (MC3XXX_PCODE_3530C == (s_bPCODE|0x0E))) + data = 0x02; + + i2c_smbus_write_byte_data(client, MC3XXX_REG_RANGE_CONTROL,data); + data = 0x00; + i2c_smbus_write_byte_data(client, MC3XXX_REG_TAP_DETECTION_ENABLE, data); + data = 0x00; + i2c_smbus_write_byte_data(client, MC3XXX_REG_INTERRUPT_ENABLE, data); + + #ifdef DOT_CALI + gsensor_gain.x = gsensor_gain.y = gsensor_gain.z = 86; + if (is_mc35xx) + { + gsensor_gain.x = gsensor_gain.y = gsensor_gain.z = 64; + } + #endif + } + + data = 0x41; + i2c_smbus_write_byte_data(client, MC3XXX_REG_MODE_FEATURE, data); + + return 0; +} + +//============================================================================= +int mc3xxx_set_mode(struct i2c_client *client, unsigned char mode) +{ + int comres = 0; + unsigned char data = 0; + + if (mode < 4) + { + data = (0x40 | mode); + comres = i2c_smbus_write_byte_data(client, MC3XXX_REG_MODE_FEATURE, data); + } + + return comres; +} + + + +#ifdef DOT_CALI +//============================================================================= +struct file *openFile(char *path,int flag,int mode) +{ + struct file *fp = NULL; + + fp = filp_open(path, flag, mode); + + if (IS_ERR(fp) || !fp->f_op) + { + GSE_LOG("Calibration File filp_open return NULL\n"); + return NULL; + } + + return fp; +} + +//============================================================================= +int readFile(struct file *fp,char *buf,int readlen) +{ + if (fp->f_op && fp->f_op->read) + return fp->f_op->read(fp,buf,readlen, &fp->f_pos); + else + return -1; +} + +//============================================================================= +int writeFile(struct file *fp,char *buf,int writelen) +{ + if (fp->f_op && fp->f_op->write) + return fp->f_op->write(fp,buf,writelen, &fp->f_pos); + else + return -1; +} + +//============================================================================= +int closeFile(struct file *fp) +{ + filp_close(fp,NULL); + + return 0; +} + +//============================================================================= +void initKernelEnv(void) +{ + oldfs = get_fs(); + set_fs(KERNEL_DS); + printk(KERN_INFO "initKernelEnv\n"); +} + +//============================================================================= + int MC3XXX_WriteCalibration(struct i2c_client *client, int dat[MC3XXX_AXIS_NUM]) +{ + int err = 0; + u8 buf[9] = { 0 }; + s16 tmp = 0, x_gain = 0, y_gain = 0, z_gain = 0; + s32 x_off = 0, y_off = 0, z_off = 0; + int temp_cali_dat[MC3XXX_AXIS_NUM] = { 0 }; + //const struct mc3xx0_hwmsen_convert *pCvt = NULL; + + u8 bMsbFilter = 0x3F; + s16 wSignBitMask = 0x2000; + s16 wSignPaddingBits = 0xC000; + s32 dwRangePosLimit = 0x1FFF; + s32 dwRangeNegLimit = -0x2000; + + if (is_mc35xx) + { + bMsbFilter = 0x7F; + wSignBitMask = 0x4000; + wSignPaddingBits = 0x8000; + dwRangePosLimit = 0x3FFF; + dwRangeNegLimit = -0x4000; + } + + //pCvt = &mc3xx0_cvt[mc3xx0_current_placement]; + + temp_cali_dat[pCvt->map[MC3XXX_AXIS_X]] = pCvt->sign[MC3XXX_AXIS_X] * dat[MC3XXX_AXIS_X]; + temp_cali_dat[pCvt->map[MC3XXX_AXIS_Y]] = pCvt->sign[MC3XXX_AXIS_Y] * dat[MC3XXX_AXIS_Y]; + temp_cali_dat[pCvt->map[MC3XXX_AXIS_Z]] = pCvt->sign[MC3XXX_AXIS_Z] * dat[MC3XXX_AXIS_Z]; + + if ((is_new_mc34x0)||(is_mc35xx)) + { + temp_cali_dat[MC3XXX_AXIS_X] = -temp_cali_dat[MC3XXX_AXIS_X]; + temp_cali_dat[MC3XXX_AXIS_Y] = -temp_cali_dat[MC3XXX_AXIS_Y]; + } + else if (is_mc3250) + { + s16 temp = 0; + + temp = temp_cali_dat[MC3XXX_AXIS_X]; + + temp_cali_dat[MC3XXX_AXIS_X] = -temp_cali_dat[MC3XXX_AXIS_Y]; + temp_cali_dat[MC3XXX_AXIS_Y] = temp; + } + + dat[MC3XXX_AXIS_X] = temp_cali_dat[MC3XXX_AXIS_X]; + dat[MC3XXX_AXIS_Y] = temp_cali_dat[MC3XXX_AXIS_Y]; + dat[MC3XXX_AXIS_Z] = temp_cali_dat[MC3XXX_AXIS_Z]; + + GSE_LOG("UPDATE dat: (%+3d %+3d %+3d)\n", + dat[MC3XXX_AXIS_X], dat[MC3XXX_AXIS_Y], dat[MC3XXX_AXIS_Z]); + + // read register 0x21~0x29 + err = i2c_smbus_read_i2c_block_data(client , 0x21 , 3 , &buf[0]); + err |= i2c_smbus_read_i2c_block_data(client , 0x24 , 3 , &buf[3]); + err |= i2c_smbus_read_i2c_block_data(client , 0x27 , 3 , &buf[6]); + + + // get x,y,z offset + tmp = ((buf[1] & bMsbFilter) << 8) + buf[0]; + if (tmp & wSignBitMask) + tmp |= wSignPaddingBits; + x_off = tmp; + + tmp = ((buf[3] & bMsbFilter) << 8) + buf[2]; + if (tmp & wSignBitMask) + tmp |= wSignPaddingBits; + y_off = tmp; + + tmp = ((buf[5] & bMsbFilter) << 8) + buf[4]; + if (tmp & wSignBitMask) + tmp |= wSignPaddingBits; + z_off = tmp; + + // get x,y,z gain + x_gain = ((buf[1] >> 7) << 8) + buf[6]; + y_gain = ((buf[3] >> 7) << 8) + buf[7]; + z_gain = ((buf[5] >> 7) << 8) + buf[8]; + + // prepare new offset + x_off = x_off + 16 * dat[MC3XXX_AXIS_X] * 256 * 128 / 3 / gsensor_gain.x / (40 + x_gain); + y_off = y_off + 16 * dat[MC3XXX_AXIS_Y] * 256 * 128 / 3 / gsensor_gain.y / (40 + y_gain); + z_off = z_off + 16 * dat[MC3XXX_AXIS_Z] * 256 * 128 / 3 / gsensor_gain.z / (40 + z_gain); + + //add for over range + if( x_off > dwRangePosLimit) + { + x_off = dwRangePosLimit; + } + else if( x_off < dwRangeNegLimit) + { + x_off = dwRangeNegLimit; + } + + if( y_off > dwRangePosLimit) + { + y_off = dwRangePosLimit; + } + else if( y_off < dwRangeNegLimit) + { + y_off = dwRangeNegLimit; + } + + if( z_off > dwRangePosLimit) + { + z_off = dwRangePosLimit; + } + else if( z_off < dwRangeNegLimit) + { + z_off = dwRangeNegLimit; + } + + //storege the cerrunt offset data with DOT format + offset_data[0] = x_off; + offset_data[1] = y_off; + offset_data[2] = z_off; + + //storege the cerrunt Gain data with GOT format + gain_data[0] = 256*8*128/3/(40+x_gain); + gain_data[1] = 256*8*128/3/(40+y_gain); + gain_data[2] = 256*8*128/3/(40+z_gain); + printk("%d %d ======================\n\n ",gain_data[0],x_gain); + + buf[0] = 0x43; + i2c_smbus_write_byte_data(client, 0x07, buf[0]); + + buf[0] = x_off & 0xff; + buf[1] = ((x_off >> 8) & bMsbFilter) | (x_gain & 0x0100 ? 0x80 : 0); + buf[2] = y_off & 0xff; + buf[3] = ((y_off >> 8) & bMsbFilter) | (y_gain & 0x0100 ? 0x80 : 0); + buf[4] = z_off & 0xff; + buf[5] = ((z_off >> 8) & bMsbFilter) | (z_gain & 0x0100 ? 0x80 : 0); + + i2c_smbus_write_i2c_block_data(client, 0x21, 2, &buf[0]); + i2c_smbus_write_i2c_block_data(client, 0x21+2, 2, &buf[2]); + i2c_smbus_write_i2c_block_data(client, 0x21+4, 2, &buf[4]); + + buf[0] = 0x41; + i2c_smbus_write_byte_data(client, 0x07,buf[0]); + + msleep(50); + + return err; + +} + +int mcube_read_cali_file(struct i2c_client *client) +{ + int cali_data[3] = { 0 }; + int err =0; + //char buf[64]; + printk("%s %d\n",__func__,__LINE__); + //MCUBE_BACKUP_FILE + READ_FROM_BACKUP = false; + //MCUBE_BACKUP_FILE + initKernelEnv(); + fd_file = openFile(CALIB_PATH,O_RDONLY,0); + //MCUBE_BACKUP_FILE + if (fd_file == NULL) + { + fd_file = openFile(BACKUP_CALIB_PATH, O_RDONLY, 0); + if(fd_file != NULL) + { + READ_FROM_BACKUP = true; + } + } + //MCUBE_BACKUP_FILE + if (fd_file == NULL) + { + GSE_LOG("fail to open\n"); + cali_data[0] = 0; + cali_data[1] = 0; + cali_data[2] = 0; + + return -1; + } + else + { + printk("%s %d\n",__func__,__LINE__); + memset(backup_buf,0,64); + if ((err = readFile(fd_file,backup_buf,128))>0) + GSE_LOG("buf:%s\n",backup_buf); + else + GSE_LOG("read file error %d\n",err); + printk("%s %d\n",__func__,__LINE__); + + set_fs(oldfs); + closeFile(fd_file); + + sscanf(backup_buf, "%d %d %d",&cali_data[MC3XXX_AXIS_X], &cali_data[MC3XXX_AXIS_Y], &cali_data[MC3XXX_AXIS_Z]); + GSE_LOG("cali_data: %d %d %d\n", cali_data[MC3XXX_AXIS_X], cali_data[MC3XXX_AXIS_Y], cali_data[MC3XXX_AXIS_Z]); + + MC3XXX_WriteCalibration(client, cali_data); + } + return 0; +} + +//============================================================================= +static int mcube_write_log_data(struct i2c_client *client, u8 data[0x3f]) +{ + #define _WRT_LOG_DATA_BUFFER_SIZE (66 * 50) + + s16 rbm_data[3]={0}, raw_data[3]={0}; + int err =0; + char *_pszBuffer = NULL; + int n=0,i=0; + + initKernelEnv(); + fd_file = openFile(DATA_PATH ,O_RDWR | O_CREAT,0); + if (fd_file == NULL) + { + GSE_LOG("mcube_write_log_data fail to open\n"); + } + else + { + rbm_data[MC3XXX_AXIS_X] = (s16)((data[0x0d]) | (data[0x0e] << 8)); + rbm_data[MC3XXX_AXIS_Y] = (s16)((data[0x0f]) | (data[0x10] << 8)); + rbm_data[MC3XXX_AXIS_Z] = (s16)((data[0x11]) | (data[0x12] << 8)); + + raw_data[MC3XXX_AXIS_X] = (rbm_data[MC3XXX_AXIS_X] + offset_data[0]/2)*gsensor_gain.x/gain_data[0]; + raw_data[MC3XXX_AXIS_Y] = (rbm_data[MC3XXX_AXIS_Y] + offset_data[1]/2)*gsensor_gain.y/gain_data[1]; + raw_data[MC3XXX_AXIS_Z] = (rbm_data[MC3XXX_AXIS_Z] + offset_data[2]/2)*gsensor_gain.z/gain_data[2]; + + _pszBuffer = kzalloc(_WRT_LOG_DATA_BUFFER_SIZE, GFP_KERNEL); + if (NULL == _pszBuffer) + { + GSE_ERR("fail to allocate memory for buffer\n"); + closeFile(fd_file); + return -1; + } + memset(_pszBuffer, 0, _WRT_LOG_DATA_BUFFER_SIZE); + + n += sprintf(_pszBuffer+n, "G-sensor RAW X = %d Y = %d Z = %d\n", raw_data[0] ,raw_data[1] ,raw_data[2]); + n += sprintf(_pszBuffer+n, "G-sensor RBM X = %d Y = %d Z = %d\n", rbm_data[0] ,rbm_data[1] ,rbm_data[2]); + for(i=0; i<64; i++) + { + n += sprintf(_pszBuffer+n, "mCube register map Register[%x] = 0x%x\n",i,data[i]); + } + msleep(50); + if ((err = writeFile(fd_file,_pszBuffer,n))>0) + GSE_LOG("buf:%s\n",_pszBuffer); + else + GSE_LOG("write file error %d\n",err); + + kfree(_pszBuffer); + + set_fs(oldfs); + closeFile(fd_file); + } + return 0; +} + +//============================================================================= +void MC3XXX_rbm(struct i2c_client *client, int enable) +{ + char buf1[3] = { 0 }; + if(enable == 1 ) + { + buf1[0] = 0x43; + i2c_smbus_write_byte_data(client, 0x07, buf1[0]); + + buf1[0] = 0x6D; + i2c_smbus_write_byte_data(client, 0x1B, buf1[0]); + + buf1[0] = 0x43; + i2c_smbus_write_byte_data(client, 0x1B, buf1[0]); + + buf1[0] = 0x00; + i2c_smbus_write_byte_data(client, 0x3B, buf1[0]); + + buf1[0] = 0x02; + i2c_smbus_write_byte_data(client, 0x14, buf1[0]); + + buf1[0] = 0x41; + i2c_smbus_write_byte_data(client, 0x07, buf1[0]); + + enable_RBM_calibration = 1; + + GSE_LOG("set rbm!!\n"); + + msleep(10); + } + else if(enable == 0 ) + { + buf1[0] = 0x43; + i2c_smbus_write_byte_data(client, 0x07, buf1[0]); + + buf1[0] = 0x00; + i2c_smbus_write_byte_data(client, 0x14, buf1[0]); + GSE_LOG("set rbm!! %x @@@@\n",s_bPCODE); + + buf1[0] = s_bPCODE; + i2c_smbus_write_byte_data(client, 0x3B, buf1[0]); + + buf1[0] = 0x6D; + i2c_smbus_write_byte_data(client, 0x1B, buf1[0]); + + buf1[0] = 0x43; + i2c_smbus_write_byte_data(client, 0x1B, buf1[0]); + + buf1[0] = 0x41; + i2c_smbus_write_byte_data(client, 0x07, buf1[0]); + + enable_RBM_calibration = 0; + + GSE_LOG("clear rbm!!\n"); + + msleep(10); + } +} + +/*----------------------------------------------------------------------------*/ + int MC3XXX_ReadData_RBM(struct i2c_client *client,int data[MC3XXX_AXIS_NUM]) +{ + u8 addr = 0x0d; + u8 rbm_buf[MC3XXX_DATA_LEN] = {0}; + int err = 0; + + //err = p_mc3xxx->MC3XXX_BUS_READ_FUNC(p_mc3xxx->dev_addr, addr, &rbm_buf[0],6); + err = i2c_smbus_read_i2c_block_data(client , addr , 6 , rbm_buf); + //err = mc3xxx_read_block(client, addr, rbm_buf, 0x06); + + data[MC3XXX_AXIS_X] = (s16)((rbm_buf[0]) | (rbm_buf[1] << 8)); + data[MC3XXX_AXIS_Y] = (s16)((rbm_buf[2]) | (rbm_buf[3] << 8)); + data[MC3XXX_AXIS_Z] = (s16)((rbm_buf[4]) | (rbm_buf[5] << 8)); + + GSE_LOG("rbm_buf<<<<<[%02x %02x %02x %02x %02x %02x]\n",rbm_buf[0], rbm_buf[2], rbm_buf[2], rbm_buf[3], rbm_buf[4], rbm_buf[5]); + GSE_LOG("RBM<<<<<[%04x %04x %04x]\n", data[MC3XXX_AXIS_X], data[MC3XXX_AXIS_Y], data[MC3XXX_AXIS_Z]); + GSE_LOG("RBM<<<<<[%04d %04d %04d]\n", data[MC3XXX_AXIS_X], data[MC3XXX_AXIS_Y], data[MC3XXX_AXIS_Z]); + return err; +} + + + int MC3XXX_ReadRBMData(struct i2c_client *client, char *buf) +{ + int res = 0; + int data[3]; + + if (!buf) + { + return EINVAL; + } + + mc3xxx_set_mode(client,MC3XXX_WAKE); + + res = MC3XXX_ReadData_RBM(client,data); + + if(res) + { + GSE_ERR("%s I2C error: ret value=%d",__func__, res); + return EIO; + } + else + { + sprintf(buf, "%04x %04x %04x", data[MC3XXX_AXIS_X], + data[MC3XXX_AXIS_Y], data[MC3XXX_AXIS_Z]); + + } + + return 0; +} + int MC3XXX_ReadOffset(struct i2c_client *client,s16 ofs[MC3XXX_AXIS_NUM]) +{ + int err = 0; + u8 off_data[6] = { 0 }; + + if(Sensor_Accuracy == MCUBE_8G_14BIT) + { + err = i2c_smbus_read_i2c_block_data(client, MC3XXX_REG_XOUT_EX_L, MC3XXX_DATA_LEN, off_data); + + ofs[MC3XXX_AXIS_X] = ((s16)(off_data[0]))|((s16)(off_data[1])<<8); + ofs[MC3XXX_AXIS_Y] = ((s16)(off_data[2]))|((s16)(off_data[3])<<8); + ofs[MC3XXX_AXIS_Z] = ((s16)(off_data[4]))|((s16)(off_data[5])<<8); + } + else if(Sensor_Accuracy == MCUBE_1_5G_8BIT) + { + err = i2c_smbus_read_i2c_block_data(client, 0, 3, off_data); + + ofs[MC3XXX_AXIS_X] = (s8)off_data[0]; + ofs[MC3XXX_AXIS_Y] = (s8)off_data[1]; + ofs[MC3XXX_AXIS_Z] = (s8)off_data[2]; + } + + GSE_LOG("MC3XXX_ReadOffset %d %d %d\n", ofs[MC3XXX_AXIS_X], ofs[MC3XXX_AXIS_Y], ofs[MC3XXX_AXIS_Z]); + + return err; +} +/*----------------------------------------------------------------------------*/ + static int MC3XXX_ResetCalibration(struct i2c_client *client) +{ + u8 buf[6] = { 0 }; + s16 tmp = 0; + int err = 0; + + u8 bMsbFilter = 0x3F; + s16 wSignBitMask = 0x2000; + s16 wSignPaddingBits = 0xC000; + + buf[0] = 0x43; + err = i2c_smbus_write_byte_data(client, 0x07, buf[0]); + if(err) + { + GSE_ERR("error 0x07: %d\n", err); + } + + err = i2c_smbus_write_i2c_block_data(client, 0x21, 6, offset_buf); + if(err) + { + GSE_ERR("error: %d\n", err); + } + + buf[0] = 0x41; + err = i2c_smbus_write_byte_data(client, 0x07, buf[0]); + if(err) + { + GSE_ERR("error: %d\n", err); + } + + msleep(20); + + + if (is_mc35xx) + { + bMsbFilter = 0x7F; + wSignBitMask = 0x4000; + wSignPaddingBits = 0x8000; + } + + tmp = ((offset_buf[1] & bMsbFilter) << 8) + offset_buf[0]; + if (tmp & wSignBitMask) + tmp |= wSignPaddingBits; + offset_data[0] = tmp; + + tmp = ((offset_buf[3] & bMsbFilter) << 8) + offset_buf[2]; + if (tmp & wSignBitMask) + tmp |= wSignPaddingBits; + offset_data[1] = tmp; + + tmp = ((offset_buf[5] & bMsbFilter) << 8) + offset_buf[4]; + if (tmp & wSignBitMask) + tmp |= wSignPaddingBits; + offset_data[2] = tmp; + + return 0; +} + +//============================================================================= + int MC3XXX_ReadCalibration(struct i2c_client *client,int dat[MC3XXX_AXIS_NUM]) +{ + signed short MC_offset[MC3XXX_AXIS_NUM + 1] = { 0 }; // +1: for 4-byte alignment + int err = 0; + + memset(MC_offset, 0, sizeof(MC_offset)); + + err = MC3XXX_ReadOffset(client, MC_offset); + + if (err) + { + GSE_ERR("read offset fail, %d\n", err); + return err; + } + + dat[MC3XXX_AXIS_X] = MC_offset[MC3XXX_AXIS_X]; + dat[MC3XXX_AXIS_Y] = MC_offset[MC3XXX_AXIS_Y]; + dat[MC3XXX_AXIS_Z] = MC_offset[MC3XXX_AXIS_Z]; + + return 0; +} + +//============================================================================= +int MC3XXX_ReadData(struct i2c_client *client, s16 buffer[MC3XXX_AXIS_NUM]) +{ + unsigned char buf[6] = { 0 }; + signed char buf1[6] = { 0 }; + char rbm_buf[6] = { 0 }; + int ret = 0; + + #ifdef SUPPORT_VIRTUAL_Z_SENSOR + int tempX=0; + int tempY=0; + int tempZ=0; + #endif + + if (enable_RBM_calibration == 0) + { + //err = hwmsen_read_block(client, addr, buf, 0x06); + } + else if (enable_RBM_calibration == 1) + { + memset(rbm_buf, 0, 6); + i2c_smbus_read_i2c_block_data(client, 0x0d , 2, &rbm_buf[0]); + i2c_smbus_read_i2c_block_data(client, 0x0d+2, 2, &rbm_buf[2]); + i2c_smbus_read_i2c_block_data(client, 0x0d+4, 2, &rbm_buf[4]); + } + + if (enable_RBM_calibration == 0) + { + if(Sensor_Accuracy == MCUBE_8G_14BIT) + { + ret = i2c_smbus_read_i2c_block_data(client, MC3XXX_REG_XOUT_EX_L, 6, buf); + + buffer[0] = (signed short)((buf[0])|(buf[1]<<8)); + buffer[1] = (signed short)((buf[2])|(buf[3]<<8)); + buffer[2] = (signed short)((buf[4])|(buf[5]<<8)); + } + else if(Sensor_Accuracy == MCUBE_1_5G_8BIT) + { + ret = i2c_smbus_read_i2c_block_data(client, MC3XXX_REG_XOUT, 3, buf1); + + buffer[0] = (signed short)buf1[0]; + buffer[1] = (signed short)buf1[1]; + buffer[2] = (signed short)buf1[2]; + } + + #ifdef SUPPORT_VIRTUAL_Z_SENSOR //add 2013-10-23 + if (g_virtual_z) + { + //printk("%s 1\n", __FUNCTION__); + + tempX = buffer[MC3XXX_AXIS_X]; + tempY = buffer[MC3XXX_AXIS_Y]; + tempZ = buffer[MC3XXX_AXIS_Z]; + //printk(" %d:Verify_Z_Railed() %d\n", (int)buffer[MC32X0_AXIS_Z], Verify_Z_Railed((int)buffer[MC32X0_AXIS_Z], LOW_RESOLUTION)); + if(1 == Verify_Z_Railed((int)buffer[MC3XXX_AXIS_Z], LOW_RESOLUTION)) // z-railed + { + Railed = 1; + + GSE_LOG("%s: Z railed", __func__); + //printk("%s: Z railed \n", __func__); + if (G_2_REVERSE_VIRTUAL_Z == 1) + buffer[MC3XXX_AXIS_Z] = (s8) ( gsensor_gain.z - (abs(tempX) + abs(tempY))); + else + buffer[MC3XXX_AXIS_Z] = (s8) -( gsensor_gain.z - (abs(tempX) + abs(tempY))); + } + else + { + Railed = 0; + } + } + #endif + mcprintkreg("MC3XXX_ReadData: %d %d %d\n", buffer[0], buffer[1], buffer[2]); + } + else if (enable_RBM_calibration == 1) + { + buffer[MC3XXX_AXIS_X] = (s16)((rbm_buf[0]) | (rbm_buf[1] << 8)); + buffer[MC3XXX_AXIS_Y] = (s16)((rbm_buf[2]) | (rbm_buf[3] << 8)); + buffer[MC3XXX_AXIS_Z] = (s16)((rbm_buf[4]) | (rbm_buf[5] << 8)); + + GSE_LOG("%s RBM<<<<<[%08d %08d %08d]\n", __func__, buffer[MC3XXX_AXIS_X], buffer[MC3XXX_AXIS_Y], buffer[MC3XXX_AXIS_Z]); + + if(gain_data[0] == 0) + { + buffer[MC3XXX_AXIS_X] = 0; + buffer[MC3XXX_AXIS_Y] = 0; + buffer[MC3XXX_AXIS_Z] = 0; + + return 0; + } + + buffer[MC3XXX_AXIS_X] = (buffer[MC3XXX_AXIS_X] + offset_data[0]/2)*gsensor_gain.x/gain_data[0]; + buffer[MC3XXX_AXIS_Y] = (buffer[MC3XXX_AXIS_Y] + offset_data[1]/2)*gsensor_gain.y/gain_data[1]; + buffer[MC3XXX_AXIS_Z] = (buffer[MC3XXX_AXIS_Z] + offset_data[2]/2)*gsensor_gain.z/gain_data[2]; + + #ifdef SUPPORT_VIRTUAL_Z_SENSOR // add 2013-10-23 + if (g_virtual_z) + { + tempX = buffer[MC3XXX_AXIS_X]; + tempY = buffer[MC3XXX_AXIS_Y]; + tempZ = buffer[MC3XXX_AXIS_Z]; + //printk("%s 2\n", __FUNCTION__); + GSE_LOG("Original RBM<<<<<[%08d %08d %08d]\n", buffer[MC3XXX_AXIS_X], buffer[MC3XXX_AXIS_Y], buffer[MC3XXX_AXIS_Z]); + printk("Verify_Z_Railed() %d\n", Verify_Z_Railed((int)buffer[MC3XXX_AXIS_Z], RBM_RESOLUTION)); + if(1 == Verify_Z_Railed(buffer[MC3XXX_AXIS_Z], RBM_RESOLUTION)) // z-railed + { + GSE_LOG("%s: Z Railed in RBM mode",__FUNCTION__); + //printk("%s: Z Railed in RBM mode\n",__FUNCTION__); + if (G_2_REVERSE_VIRTUAL_Z == 1) + buffer[MC3XXX_AXIS_Z] = (s16) ( gsensor_gain.z - (abs(tempX) + abs(tempY))); + else + buffer[MC3XXX_AXIS_Z] = (s16) -( gsensor_gain.z - (abs(tempX) + abs(tempY))); + } + GSE_LOG("RBM<<<<<[%08d %08d %08d]\n", buffer[MC3XXX_AXIS_X], buffer[MC3XXX_AXIS_Y], buffer[MC3XXX_AXIS_Z]); + } + #endif + + GSE_LOG("%s offset_data <<<<<[%d %d %d]\n", __func__, offset_data[0], offset_data[1], offset_data[2]); + GSE_LOG("%s gsensor_gain <<<<<[%d %d %d]\n", __func__, gsensor_gain.x, gsensor_gain.y, gsensor_gain.z); + GSE_LOG("%s gain_data <<<<<[%d %d %d]\n", __func__, gain_data[0], gain_data[1], gain_data[2]); + GSE_LOG("%s RBM->RAW <<<<<[%d %d %d]\n", __func__, buffer[MC3XXX_AXIS_X], buffer[MC3XXX_AXIS_Y], buffer[MC3XXX_AXIS_Z]); + } + + return 0; +} + +//============================================================================= +int MC3XXX_ReadRawData(struct i2c_client *client, char * buf) +{ + int res = 0; + s16 raw_buf[3] = { 0 }; + + if (!buf || !client) + { + return -EINVAL; + } + + mc3xxx_set_mode(client, MC3XXX_WAKE); + res = MC3XXX_ReadData(client,&raw_buf[0]); + if(res) + { + printk("%s %d\n",__FUNCTION__, __LINE__); + GSE_ERR("I2C error: ret value=%d", res); + return -EIO; + } + else + { + //const struct mc3xx0_hwmsen_convert *pCvt = &mc3xx0_cvt[mc3xx0_current_placement]; + + GSE_LOG("UPDATE dat: (%+3d %+3d %+3d)\n", + raw_buf[MC3XXX_AXIS_X], raw_buf[MC3XXX_AXIS_Y], raw_buf[MC3XXX_AXIS_Z]); + + if ((is_new_mc34x0)||(is_mc35xx)) + { + raw_buf[MC3XXX_AXIS_X] = -raw_buf[MC3XXX_AXIS_X]; + raw_buf[MC3XXX_AXIS_Y] = -raw_buf[MC3XXX_AXIS_Y]; + } + else if (is_mc3250) + { + s16 temp = 0; + + temp = raw_buf[MC3XXX_AXIS_X]; + + raw_buf[MC3XXX_AXIS_X] = raw_buf[MC3XXX_AXIS_Y]; + raw_buf[MC3XXX_AXIS_Y] = -temp; + } + + G_RAW_DATA[MC3XXX_AXIS_X] = pCvt->sign[MC3XXX_AXIS_X] * raw_buf[pCvt->map[MC3XXX_AXIS_X]]; + G_RAW_DATA[MC3XXX_AXIS_Y] = pCvt->sign[MC3XXX_AXIS_Y] * raw_buf[pCvt->map[MC3XXX_AXIS_Y]]; + G_RAW_DATA[MC3XXX_AXIS_Z] = pCvt->sign[MC3XXX_AXIS_Z] * raw_buf[pCvt->map[MC3XXX_AXIS_Z]]; + + G_RAW_DATA[MC3XXX_AXIS_Z] += gsensor_gain.z*(pCvt->sign[MC3XXX_AXIS_Z])*(1);//G_RAW_DATA[MC3XXX_AXIS_Z]+gsensor_gain.z; + + sprintf(buf, "%04x %04x %04x", G_RAW_DATA[MC3XXX_AXIS_X], + G_RAW_DATA[MC3XXX_AXIS_Y], G_RAW_DATA[MC3XXX_AXIS_Z]); + + GSE_LOG("G_RAW_DATA: (%+3d %+3d %+3d)\n", + G_RAW_DATA[MC3XXX_AXIS_X], G_RAW_DATA[MC3XXX_AXIS_Y], G_RAW_DATA[MC3XXX_AXIS_Z]); + } + + return 0; +} + +//============================================================================= +static int MC3XXX_ReadRegMap(struct i2c_client *client, u8 *pbUserBuf) +{ + u8 data[128] = {0}; + //u8 addr = 0x00; + int err = 0; + int i = 0; + + if(NULL == client) + { + err = -EINVAL; + return err; + } + + + for(i = 0; i < 64; i++) + { + data[i] = i2c_smbus_read_byte_data(client, i); + printk(KERN_INFO "mcube register map Register[%x] = 0x%x\n", i ,data[i]); + } + + msleep(50); + + mcube_write_log_data(client, data); + + msleep(50); + + if (NULL != pbUserBuf) + { + printk(KERN_INFO "copy to user buffer\n"); + memcpy(pbUserBuf, data, 64); + } + + return err; +} + +//============================================================================= +void MC3XXX_Reset(struct i2c_client *client) +{ + //s16 tmp = 0, x_gain = 0, y_gain = 0, z_gain = 0; + u8 buf[3] = { 0 }; + int err = 0; + + buf[0] = 0x43; + i2c_smbus_write_byte_data(client, 0x07, buf[0]); + + i2c_smbus_read_i2c_block_data(client, 0x04, 1, buf); + + if (0x00 == (buf[0] & 0x40)) + { + buf[0] = 0x6d; + i2c_smbus_write_byte_data(client, 0x1b, buf[0]); + + buf[0] = 0x43; + i2c_smbus_write_byte_data(client, 0x1b, buf[0]); + } + + msleep(5); + + buf[0] = 0x43; + i2c_smbus_write_byte_data(client, 0x07, buf[0]); + + buf[0] = 0x80; + i2c_smbus_write_byte_data(client, 0x1c, buf[0]); + + buf[0] = 0x80; + i2c_smbus_write_byte_data(client, 0x17, buf[0]); + + msleep(5); + + buf[0] = 0x00; + i2c_smbus_write_byte_data(client, 0x1c, buf[0]); + + buf[0] = 0x00; + i2c_smbus_write_byte_data(client, 0x17, buf[0]); + + msleep(5); + + memset(offset_buf, 0, sizeof(offset_buf)); + + err = i2c_smbus_read_i2c_block_data(client, 0x21, 6, offset_buf); + + i2c_smbus_read_i2c_block_data(client, 0x04, 1, buf); + + if (0x00 == (buf[0] & 0x40)) + { + buf[0] = 0x6d; + i2c_smbus_write_byte_data(client, 0x1b, buf[0]); + + buf[0] = 0x43; + i2c_smbus_write_byte_data(client, 0x1b, buf[0]); + } + + buf[0] = 0x41; + i2c_smbus_write_byte_data(client, 0x07, buf[0]); + +} +#endif + +int mc3xxx_read_accel_xyz(struct i2c_client *client, s16 * acc) +{ + int comres = 0; + s16 raw_data[MC3XXX_AXIS_NUM] = { 0 }; + //const struct mc3xx0_hwmsen_convert *pCvt = &mc3xx0_cvt[mc3xx0_current_placement]; + +#ifdef DOT_CALI + s16 raw_buf[6] = { 0 }; + + comres = MC3XXX_ReadData(client, &raw_buf[0]); + + raw_data[MC3XXX_AXIS_X] = raw_buf[0]; + raw_data[MC3XXX_AXIS_Y] = raw_buf[1]; + raw_data[MC3XXX_AXIS_Z] = raw_buf[2]; +#else + unsigned char raw_buf[6] = { 0 }; + signed char raw_buf1[3] = { 0 }; + + if(Sensor_Accuracy == MCUBE_8G_14BIT) + { + comres = i2c_smbus_read_i2c_block_data(client, MC3XXX_REG_XOUT_EX_L, 6, raw_buf); + + raw_data[MC3XXX_AXIS_X] = (signed short)((raw_buf[0])|(raw_buf[1]<<8)); + raw_data[MC3XXX_AXIS_Y] = (signed short)((raw_buf[2])|(raw_buf[3]<<8)); + raw_data[MC3XXX_AXIS_Z] = (signed short)((raw_buf[4])|(raw_buf[5]<<8)); + } + else if(Sensor_Accuracy == MCUBE_1_5G_8BIT) + { + comres = i2c_smbus_read_i2c_block_data(client, MC3XXX_REG_XOUT, 3, raw_buf1); + + raw_data[MC3XXX_AXIS_X] = (signed short)raw_buf1[0]; + raw_data[MC3XXX_AXIS_Y] = (signed short)raw_buf1[1]; + raw_data[MC3XXX_AXIS_Z] = (signed short)raw_buf1[2]; + } +#endif + + if((is_new_mc34x0)||(is_mc35xx)) + { + raw_data[MC3XXX_AXIS_X] = -raw_data[MC3XXX_AXIS_X]; + raw_data[MC3XXX_AXIS_Y] = -raw_data[MC3XXX_AXIS_Y]; + } + else if (is_mc3250) + { + s16 temp = 0; + + temp = raw_data[MC3XXX_AXIS_X]; + + raw_data[MC3XXX_AXIS_X] = raw_data[MC3XXX_AXIS_Y]; + raw_data[MC3XXX_AXIS_Y] = -temp; + } + //printk("%s:%d %d %d\n",__FUNCTION__,raw_data[0],raw_data[1],raw_data[2]); + acc[MC3XXX_AXIS_X] = pCvt->sign[MC3XXX_AXIS_X] * raw_data[pCvt->map[MC3XXX_AXIS_X]]; + acc[MC3XXX_AXIS_Y] = pCvt->sign[MC3XXX_AXIS_Y] * raw_data[pCvt->map[MC3XXX_AXIS_Y]]; + acc[MC3XXX_AXIS_Z] = pCvt->sign[MC3XXX_AXIS_Z] * raw_data[pCvt->map[MC3XXX_AXIS_Z]]; + + return comres; +} + +//============================================================================= +static void mc3xxx_work_func(struct work_struct *work) +{ + struct mc3xxx_data *data = &l_sensorconfig;//container_of(work, struct mc3xxx_data, work); + //int ret = 0; + s16 raw[3] = { 0 }; + +#ifdef DOT_CALI + if( load_cali_flg > 0) + { + /* ret = mcube_read_cali_file(data->client); + + if(ret == 0) + load_cali_flg = ret; + else + load_cali_flg--; + + GSE_LOG("load_cali %d\n",ret); */ + MC3XXX_WriteCalibration(data->client,l_sensorconfig.offset); + load_cali_flg = 0; + } +#endif +#if 1 +//gsensor not use when resume + if(wake_mc3xxx_flg==1){ + wake_mc3xxx_flg=0; + + + mc3xxx_chip_init(data->client); + MC3XXX_ResetCalibration(data->client); + + MC3XXX_WriteCalibration(data->client,l_sensorconfig.offset); + /*ret =mcube_read_cali_file(data->client); + if(ret !=0) + printk("*load_cali %d\n",ret); */ + } +#endif + + mc3xxx_read_accel_xyz(data->client, &raw[0]); + //printk("%s:%d %d %d\n",__FUNCTION__,raw[0],raw[1],raw[2]); + input_report_abs(data->input_dev, ABS_X, raw[0]); + input_report_abs(data->input_dev, ABS_Y, raw[1]); + input_report_abs(data->input_dev, ABS_Z, raw[2]); + input_sync(data->input_dev); + + queue_delayed_work(data->mc3xxx_wq, &data->work, msecs_to_jiffies(sample_rate_2_memsec(data->sensor_samp))); +} +/* +//============================================================================= +static enum hrtimer_restart mc3xxx_timer_func(struct hrtimer *timer) +{ + struct mc3xxx_data *data = container_of(timer, struct mc3xxx_data, timer); + + queue_work(data->mc3xxx_wq, &data->work); + + hrtimer_start(&data->timer, ktime_set(0, sensor_duration*1000000), HRTIMER_MODE_REL); + + return HRTIMER_NORESTART; +} +*/ +//MCUBE_BACKUP_FILE +static void mcube_copy_file(const char *dstFilePath) +{ + int err =0; + initKernelEnv(); + + fd_file = openFile(dstFilePath,O_RDWR,0); + if (fd_file == NULL) + { + GSE_LOG("open %s fail\n",dstFilePath); + return; + } + + if ((err = writeFile(fd_file,backup_buf,64))>0) + GSE_LOG("buf:%s\n",backup_buf); + else + GSE_LOG("write file error %d\n",err); + + set_fs(oldfs); ; + closeFile(fd_file); + +} +//MCUBE_BACKUP_FILE + +extern int wmt_setsyspara(char *varname, char *varval); +static void update_var(void) +{ + char varbuf[64]; + int varlen; + + memset(varbuf, 0, sizeof(varbuf)); + varlen = sizeof(varbuf); + + sprintf(varbuf, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", + l_sensorconfig.op, + l_sensorconfig.int_gpio, + l_sensorconfig.samp, + (pCvt->map[MC3XXX_AXIS_X]), + (pCvt->sign[MC3XXX_AXIS_X]), + (pCvt->map[MC3XXX_AXIS_Y]), + (pCvt->sign[MC3XXX_AXIS_Y]), + (pCvt->map[MC3XXX_AXIS_Z]), + (pCvt->sign[MC3XXX_AXIS_Z]), + l_sensorconfig.offset[0], + l_sensorconfig.offset[1], + l_sensorconfig.offset[2] + ); + + wmt_setsyspara("wmt.io.mc3230sensor",varbuf); +} + +static long wmt_mc3xxx_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + short enable = 0; + short delay = 0; + unsigned int temp; + + switch (cmd){ + + case ECS_IOCTL_APP_SET_AFLAG: + // enable/disable sensor + if (copy_from_user(&enable, (short*)arg, sizeof(short))) + { + errlog("Can't get enable flag!!!\n"); + return -EFAULT; + } + if ((enable >=0) && (enable <=1)) + { + dbg("driver: disable/enable(%d) gsensor. l_sensorconfig.sensor_samp=%d\n", enable, l_sensorconfig.sensor_samp); + + if (enable != l_sensorconfig.sensor_enable) + { + + l_sensorconfig.sensor_enable = enable; + + } + } else { + errlog("Wrong enable argument!!!\n"); + return -EFAULT; + } + break; + case ECS_IOCTL_APP_SET_DELAY://IOCTL_SENSOR_SET_DELAY_ACCEL: + // set the rate of g-sensor + if (copy_from_user(&delay,(short*)arg, sizeof(short))) + { + errlog("Can't get set delay!!!\n"); + return -EFAULT; + } + dbg("Get delay=%d \n", delay); + + if ((delay >=0) && (delay < 20)) + { + delay = 20; + } else if (delay > 200) + { + delay = 200; + } + if (delay > 0) + { + l_sensorconfig.sensor_samp = 1000/delay; + } else { + errlog("error delay argument(delay=%d)!!!\n",delay); + return -EFAULT; + } + + break; + case WMT_IOCTL_SENSOR_GET_DRVID: + temp = MC3230_DRVID; + if (copy_to_user((unsigned int*)arg, &temp, sizeof(unsigned int))) + { + return -EFAULT; + } + dbg("mc32x0_driver_id:%d\n",temp); + break; + case WMT_IOCTL_SENOR_GET_RESOLUTION: + if(Sensor_Accuracy &MCUBE_1_5G_8BIT){ + if(is_mc35xx) //mc3236:8 bit ,+/-2g + temp = (8<<8) | 4; + else + temp = (8<<8) | 3; //mc3230:8 bit ,+/-1.5g + + } + if (copy_to_user((unsigned int *)arg, &temp, sizeof(unsigned int))) + { + return -EFAULT; + } + printk("<<<<<<lock); + MC3XXX_ReadRawData(client, strbuf); + //mutex_unlock(&data->lock); + + if (copy_to_user((void __user *) arg, &strbuf, strlen(strbuf)+1)) + { + printk("failed to copy sense data to user space."); + return -EFAULT; + } + break; + + case GSENSOR_MCUBE_IOCTL_SET_CALI: + GSE_LOG("fwq GSENSOR_MCUBE_IOCTL_SET_CALI!!\n"); + data1 = (void __user *)arg; + + if(data1 == NULL) + { + ret = -EINVAL; + break; + } + if(copy_from_user(&sensor_data, data1, sizeof(sensor_data))) + { + ret = -EFAULT; + break; + } + else + { + l_sensorconfig.offset[MC3XXX_AXIS_X] = sensor_data.x; + l_sensorconfig.offset[MC3XXX_AXIS_Y] = sensor_data.y; + l_sensorconfig.offset[MC3XXX_AXIS_Z] = sensor_data.z; + update_var(); + GSE_LOG("GSENSOR_MCUBE_IOCTL_SET_CALI %d %d %d %d %d %d!!\n", l_sensorconfig.offset[MC3XXX_AXIS_X], l_sensorconfig.offset[MC3XXX_AXIS_Y],l_sensorconfig.offset[MC3XXX_AXIS_Z] ,sensor_data.x, sensor_data.y ,sensor_data.z); + + //mutex_lock(&data->lock); + ret = MC3XXX_WriteCalibration(client, l_sensorconfig.offset); + //mutex_unlock(&data->lock); + } + break; + + case GSENSOR_IOCTL_CLR_CALI: + GSE_LOG("fwq GSENSOR_IOCTL_CLR_CALI!!\n"); + //mutex_lock(&data->lock); + l_sensorconfig.offset[0] = 0; + l_sensorconfig.offset[1] = 0; + l_sensorconfig.offset[2] = 0; + + update_var(); + ret = MC3XXX_ResetCalibration(client); + //mutex_unlock(&data->lock); + break; + + case GSENSOR_IOCTL_GET_CALI: + GSE_LOG("fwq mc3xxx GSENSOR_IOCTL_GET_CALI\n"); + + data1 = (unsigned char*)arg; + + if(data1 == NULL) + { + ret = -EINVAL; + break; + } + + if((ret = MC3XXX_ReadCalibration(client,l_sensorconfig.offset))) + { + GSE_LOG("fwq mc3xxx MC3XXX_ReadCalibration error!!!!\n"); + break; + } + + sensor_data.x = l_sensorconfig.offset[MC3XXX_AXIS_X]; + sensor_data.y = l_sensorconfig.offset[MC3XXX_AXIS_Y]; + sensor_data.z = l_sensorconfig.offset[MC3XXX_AXIS_Z]; + + if(copy_to_user(data1, &sensor_data, sizeof(sensor_data))) + { + ret = -EFAULT; + break; + } + break; + + case GSENSOR_IOCTL_SET_CALI_MODE: + GSE_LOG("fwq mc3xxx GSENSOR_IOCTL_SET_CALI_MODE\n"); + break; + + case GSENSOR_MCUBE_IOCTL_READ_RBM_DATA: + GSE_LOG("fwq GSENSOR_MCUBE_IOCTL_READ_RBM_DATA\n"); + data1 = (void __user *) arg; + if(data1 == NULL) + { + ret = -EINVAL; + break; + } + MC3XXX_ReadRBMData(client,(char *)&strbuf); + if(copy_to_user(data1, &strbuf, strlen(strbuf)+1)) + { + ret = -EFAULT; + break; + } + break; + case GSENSOR_MCUBE_IOCTL_SET_RBM_MODE: + GSE_LOG("fwq GSENSOR_MCUBE_IOCTL_SET_RBM_MODE\n"); + //MCUBE_BACKUP_FILE + if(READ_FROM_BACKUP==true) + { + + //mcube_copy_file(CALIB_PATH); + + READ_FROM_BACKUP = false; + } + //MCUBE_BACKUP_FILE + //mutex_lock(&data->lock); + MC3XXX_rbm(client, 1); + //mutex_unlock(&data->lock); + break; + + case GSENSOR_MCUBE_IOCTL_CLEAR_RBM_MODE: + GSE_LOG("fwq GSENSOR_MCUBE_IOCTL_CLEAR_RBM_MODE\n"); + //mutex_lock(&data->lock); + MC3XXX_rbm(client, 0); + //mutex_unlock(&data->lock); + break; + + case GSENSOR_MCUBE_IOCTL_REGISTER_MAP: + GSE_LOG("fwq GSENSOR_MCUBE_IOCTL_REGISTER_MAP\n"); + MC3XXX_ReadRegMap(client, NULL); + break; + + case GSENSOR_MCUBE_IOCTL_READ_PRODUCT_ID: + GSE_LOG("fwq GSENSOR_MCUBE_IOCTL_READ_PRODUCT_ID\n"); + data1 = (void __user *) arg; + if(data1 == NULL) + { + ret = -EINVAL; + break; + } + + if (MC3XXX_RETCODE_SUCCESS != (prod = MC3XX0_ValidateSensorIC(s_bPCODE))) + GSE_LOG("Not mCube accelerometers!\n"); + + if(copy_to_user(data1, &prod, sizeof(prod))) + { + GSE_LOG("%s: read pcode fail to copy!\n", __func__); + return -EFAULT; + } + break; +#endif + + default: + ret = -EINVAL; + break; + } + + return ret; +} + + +static int mc3xxx_open(struct inode *inode, struct file *filp) +{ + return nonseekable_open(inode, filp); +} + +static int mc3xxx_release(struct inode *inode, struct file *filp) +{ + return 0; +} + +static int wmt_mc3xxx_open(struct inode *inode, struct file *filp) +{ + return 0; +} + +static int wmt_mc3xxx_release(struct inode *inode, struct file *filp) +{ + return 0; +} + + +//============================================================================= +static struct file_operations sensor_fops = +{ + .owner = THIS_MODULE, + .open = mc3xxx_open, + .release = mc3xxx_release, + .unlocked_ioctl = mc3xxx_ioctl, +}; + +static struct file_operations wmt_sensor_fops = +{ + .owner = THIS_MODULE, + .open = wmt_mc3xxx_open, + .release = wmt_mc3xxx_release, + .unlocked_ioctl = wmt_mc3xxx_ioctl, +}; + + + +static int sensor_writeproc( struct file *file, + const char *buffer, + unsigned long count, + void *data ) +{ + + //int inputval = -1; + int enable, sample = -1; + char tembuf[8]; + //unsigned int amsr = 0; + int test = 0; + + mutex_lock(&l_sensorconfig.lock); + memset(tembuf, 0, sizeof(tembuf)); + // get sensor level and set sensor level + if (sscanf(buffer, "isdbg=%d\n", &l_sensorconfig.isdbg)) + { + // only set the dbg flag + } else if (sscanf(buffer, "samp=%d\n", &sample)) + { + if (sample > 0) + { + if (sample != l_sensorconfig.sensor_samp) + { + // should do sth + } + //printk(KERN_ALERT "sensor samp=%d(amsr:%d) has been set.\n", sample, amsr); + } else { + klog("Wrong sample argumnet of sensor.\n"); + } + } else if (sscanf(buffer, "enable=%d\n", &enable)) + { + if ((enable < 0) || (enable > 1)) + { + dbg("The argument to enable/disable g-sensor should be 0 or 1 !!!\n"); + } else if (enable != l_sensorconfig.sensor_enable) + { + //mma_enable_disable(enable); + l_sensorconfig.sensor_enable = enable; + } + } else if (sscanf(buffer, "sensor_test=%d\n", &test)) + { // for test begin + l_sensorconfig.test_pass = 0; + } else if (sscanf(buffer, "sensor_testend=%d\n", &test)) + { // Don nothing only to be compatible the before testing program + } + mutex_unlock(&l_sensorconfig.lock); + return count; +} + +static int sensor_readproc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = 0; + + len = sprintf(page, + "test_pass=%d\nisdbg=%d\nrate=%d\nenable=%d\n", + l_sensorconfig.test_pass, + l_sensorconfig.isdbg, + l_sensorconfig.sensor_samp, + l_sensorconfig.sensor_enable + ); + return len; +} + + +//#ifdef CONFIG_HAS_EARLYSUSPEND +static void mc3xxx_early_suspend(struct platform_device *pdev, pm_message_t state) +{ + /*struct mc3xxx_data *data = NULL; + + data = container_of(handler, struct mc3xxx_data, early_suspend); + + hrtimer_cancel(&data->timer);*/ + + cancel_delayed_work_sync(&l_sensorconfig.work); + mc3xxx_set_mode(l_sensorconfig.client,MC3XXX_STANDBY); +} + +//============================================================================= +static void mc3xxx_early_resume(struct platform_device *pdev) +{ + struct mc3xxx_data *data = &l_sensorconfig; + + wake_mc3xxx_flg =1; + //data = container_of(handler, struct mc3xxx_data, early_suspend); + + mc3xxx_set_mode(data->client,MC3XXX_WAKE); + + queue_delayed_work(data->mc3xxx_wq, &data->work, msecs_to_jiffies(sample_rate_2_memsec(data->sensor_samp))); + //hrtimer_start(&data->timer, ktime_set(1, 0), HRTIMER_MODE_REL); +} +//#endif + +//============================================================================= +static struct miscdevice mc3xxx_device = +{ + .minor = MISC_DYNAMIC_MINOR, + .name = SENSOR_NAME, + .fops = &sensor_fops, +}; + +static struct miscdevice mc3xxx_wmt_device = +{ + .minor = MISC_DYNAMIC_MINOR, + .name = "sensor_ctrl", + .fops = &wmt_sensor_fops, +}; + + + +/***************************************** + *** MC3XX0_ValidateSensorIC + *****************************************/ +static int MC3XX0_ValidateSensorIC(unsigned char bPCode) +{ + unsigned char _baOurSensorList[] = { MC3XXX_PCODE_3210 , MC3XXX_PCODE_3230 , + MC3XXX_PCODE_3250 , + MC3XXX_PCODE_3410 , MC3XXX_PCODE_3430 , + MC3XXX_PCODE_3410N, MC3XXX_PCODE_3430N, + MC3XXX_PCODE_3510B, MC3XXX_PCODE_3530B, + MC3XXX_PCODE_3510C, MC3XXX_PCODE_3530C + }; + + int _nSensorCount = (sizeof(_baOurSensorList) / sizeof(_baOurSensorList[0])); + int _nCheckIndex = 0; + + GSE_LOG("[%s] code to be verified: 0x%X, _nSensorCount: %d\n", __FUNCTION__, bPCode, _nSensorCount); + + for (_nCheckIndex = 0; _nCheckIndex < _nSensorCount; _nCheckIndex++) + { + if (_baOurSensorList[_nCheckIndex] == bPCode) + return (MC3XXX_RETCODE_SUCCESS); + } + + if (MC3XXX_PCODE_3530C == (bPCode | 0x0E)) + return (MC3XXX_RETCODE_SUCCESS); + + return (MC3XXX_RETCODE_ERROR_IDENTIFICATION); +} + +/***************************************** + *** _mc3xxx_i2c_auto_probe + *****************************************/ +static int _mc3xxx_i2c_auto_probe(struct i2c_client *client) +{ + unsigned char _baDataBuf[2] = {0}; + int _nProbeAddrCount = (sizeof(mc3xxx_i2c_auto_probe_addr) / sizeof(mc3xxx_i2c_auto_probe_addr[0])); + int _nCount = 0; + int _nCheckCount = 0; + + //GSE_FUN(); + + s_bPCODE = 0x00; + + for (_nCount = 0; _nCount < _nProbeAddrCount; _nCount++) + { + _nCheckCount = 0; + client->addr = mc3xxx_i2c_auto_probe_addr[_nCount]; + + //GSE_LOG("[%s] probing addr: 0x%X\n", __FUNCTION__, client->addr); + +_I2C_AUTO_PROBE_RECHECK_: + _baDataBuf[0] = MC3XXX_REG_PRODUCT_CODE; + if (0 > i2c_master_send(client, &(_baDataBuf[0]), 1)) + { + //GSE_ERR("ERR: addr: 0x%X fail to communicate-2!\n", client->addr); + continue; + } + + if (0 > i2c_master_recv(client, &(_baDataBuf[0]), 1)) + { + //GSE_ERR("ERR: addr: 0x%X fail to communicate-3!\n", client->addr); + continue; + } + + _nCheckCount++; + + //GSE_LOG("[%s][%d] addr: 0x%X ok to read REG(0x3B): 0x%X\n", __FUNCTION__, _nCheckCount, client->addr, _baDataBuf[0]); + + if (0x00 == _baDataBuf[0]) + { + if (1 == _nCheckCount) + { + MC3XXX_Reset(client); + goto _I2C_AUTO_PROBE_RECHECK_; + } + } + + if (MC3XXX_RETCODE_SUCCESS == MC3XX0_ValidateSensorIC(_baDataBuf[0])) + { + //GSE_LOG("[%s] addr: 0x%X confirmed ok to use.\n", __FUNCTION__, client->addr); + + s_bPCODE = _baDataBuf[0]; + + return (MC3XXX_RETCODE_SUCCESS); + } + } + + return (MC3XXX_RETCODE_ERROR_I2C); +} + + +//============================================================================= +//static int mc3xxx_probe(struct i2c_client *client, +// const struct i2c_device_id *id) +static int mc3xxx_probe(struct platform_device *pdev) +{ + int ret = 0; + //int product_code = 0; + struct mc3xxx_data *data = &l_sensorconfig; + struct i2c_client *client = l_sensorconfig.client; + + #ifdef DOT_CALI + load_cali_flg = 30; + #endif +/* + if (MC3XXX_RETCODE_SUCCESS != _mc3xxx_i2c_auto_probe(client)) + { + GSE_ERR("ERR: fail to probe mCube sensor!\n"); + goto err_check_functionality_failed; + } + + data = kzalloc(sizeof(struct mc3xxx_data), GFP_KERNEL); + if(data == NULL) + { + ret = -ENOMEM; + goto err_alloc_data_failed; + } +*/ + data->sensor_proc = create_proc_entry(GSENSOR_PROC_NAME, 0666, NULL/*&proc_root*/); + if (data->sensor_proc != NULL) + { + data->sensor_proc->write_proc = sensor_writeproc; + data->sensor_proc->read_proc = sensor_readproc; + } + + data->mc3xxx_wq = create_singlethread_workqueue("mc3xxx_wq"); + if (!data->mc3xxx_wq ) + { + ret = -ENOMEM; + goto err_create_workqueue_failed; + } + INIT_DELAYED_WORK(&data->work, mc3xxx_work_func); + mutex_init(&data->lock); + + //sensor_duration = SENSOR_DURATION_DEFAULT; + //sensor_state_flag = 1; + + + data->client = client; + dev.client=client; + + i2c_set_clientdata(client, data); + + data->input_dev = input_allocate_device(); + if (!data->input_dev) { + ret = -ENOMEM; + goto exit_input_dev_alloc_failed; + } + + #ifdef DOT_CALI + MC3XXX_Reset(client); + #endif + + ret = mc3xxx_chip_init(client); + if (ret < 0) { + goto err_chip_init_failed; + } + + set_bit(EV_ABS, data->input_dev->evbit); + data->map[0] = G_0; + data->map[1] = G_1; + data->map[2] = G_2; + data->inv[0] = G_0_REVERSE; + data->inv[1] = G_1_REVERSE; + data->inv[2] = G_2_REVERSE; + + input_set_abs_params(data->input_dev, ABS_X, -32*8, 32*8, INPUT_FUZZ, INPUT_FLAT); + input_set_abs_params(data->input_dev, ABS_Y, -32*8, 32*8, INPUT_FUZZ, INPUT_FLAT); + input_set_abs_params(data->input_dev, ABS_Z, -32*8, 32*8, INPUT_FUZZ, INPUT_FLAT); + + data->input_dev->name = "g-sensor"; + + ret = input_register_device(data->input_dev); + if (ret) { + goto exit_input_register_device_failed; + } + + mc3xxx_device.parent = &client->dev; + + ret = misc_register(&mc3xxx_device); + if (ret) { + goto exit_misc_device_register_failed; + } + + ret = misc_register(&mc3xxx_wmt_device); + if (ret) { + goto exit_misc_device_register_failed; + } + + ret = sysfs_create_group(&data->input_dev->dev.kobj, &mc3xxx_group); +/* + if (!data->use_irq){ + hrtimer_init(&data->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + data->timer.function = mc3xxx_timer_func; + //hrtimer_start(&data->timer, ktime_set(1, 0), HRTIMER_MODE_REL); + } +*/ + +#ifdef CONFIG_HAS_EARLYSUSPEND + data->early_suspend.suspend = mc3xxx_early_suspend; + data->early_suspend.resume = mc3xxx_early_resume; + register_early_suspend(&data->early_suspend); +#endif + data->enabled = 1; + queue_delayed_work(data->mc3xxx_wq, &data->work, msecs_to_jiffies(sample_rate_2_memsec(data->sensor_samp))); + //strcpy(mc3xxx_on_off_str,"gsensor_int2"); + //gpio_set_one_pin_io_status(mc3xxx_pin_hd,0,mc3xxx_on_off_str); + + printk("mc3xxx probe ok \n"); + + return 0; +exit_misc_device_register_failed: +exit_input_register_device_failed: + input_free_device(data->input_dev); +err_chip_init_failed: +exit_input_dev_alloc_failed: + destroy_workqueue(data->mc3xxx_wq); +err_create_workqueue_failed: + kfree(data); +//err_alloc_data_failed: +//err_check_functionality_failed: + printk("mc3xxx probe failed \n"); + return ret; + +} + +//static int mc3xxx_remove(struct i2c_client *client) +static int mc3xxx_remove(struct platform_device *pdev) +{ + /*struct mc3xxx_data *data = i2c_get_clientdata(client); + + hrtimer_cancel(&data->timer); + input_unregister_device(data->input_dev); +// gpio_release(mc3xxx_pin_hd, 2); + misc_deregister(&mc3xxx_device); + sysfs_remove_group(&data->input_dev->dev.kobj, &mc3xxx_group); + kfree(data); + return 0;*/ + + if (NULL != l_sensorconfig.mc3xxx_wq) + { + cancel_delayed_work_sync(&l_sensorconfig.work); + flush_workqueue(l_sensorconfig.mc3xxx_wq); + destroy_workqueue(l_sensorconfig.mc3xxx_wq); + l_sensorconfig.mc3xxx_wq = NULL; + } + if (l_sensorconfig.sensor_proc != NULL) + { + remove_proc_entry(GSENSOR_PROC_NAME, NULL); + l_sensorconfig.sensor_proc = NULL; + } + misc_deregister(&mc3xxx_device); + misc_deregister(&mc3xxx_wmt_device); + sysfs_remove_group(&l_sensorconfig.input_dev->dev.kobj, &mc3xxx_group); + input_unregister_device(l_sensorconfig.input_dev); + return 0; +} + +//============================================================================= +/* +static void mc3xxx_shutdown(struct i2c_client *client) +{ + struct mc3xxx_data *data = i2c_get_clientdata(client); + + if(data->enabled) + mc3xxx_enable(data, 0); +} +*/ + +//============================================================================= + +static const struct i2c_device_id mc3xxx_id[] = +{ + { SENSOR_NAME, 0 }, + { } +}; + +MODULE_DEVICE_TABLE(i2c, mc3xxx_id); +/* +static struct i2c_driver mc3xxx_driver = +{ + .class = I2C_CLASS_HWMON, + + .driver = { + .owner = THIS_MODULE, + .name = SENSOR_NAME, + }, + .id_table = mc3xxx_id, + .probe = mc3xxx_probe, + .remove = mc3xxx_remove, + //.shutdown = mc3xxx_shutdown, +}; +*/ +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); +static int get_axisset(void) +{ + char varbuf[64]; + int n; + int varlen; + //int tmpoff[3] = {0}; + memset(varbuf, 0, sizeof(varbuf)); + varlen = sizeof(varbuf); + + pCvt = (struct mc3xx0_hwmsen_convert *)kzalloc(sizeof(struct mc3xx0_hwmsen_convert), GFP_KERNEL); + + if (wmt_getsyspara("wmt.io.mc3230.virtualz", varbuf, &varlen)) { + errlog("Can't get gsensor config in u-boot!!!!\n"); + //return -1; + } else { + sscanf(varbuf, "%d", &g_virtual_z); + + } + printk("%s g_virtual_z %d\n", __FUNCTION__, g_virtual_z); + memset(varbuf, 0, sizeof(varbuf)); + if (wmt_getsyspara("wmt.io.mc3230sensor", varbuf, &varlen)) { + errlog("Can't get gsensor config in u-boot!!!!\n"); + return -1; //open it for no env just,not insmod such module 2014-6-30 + } else { + n = sscanf(varbuf, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", + &l_sensorconfig.op, + &l_sensorconfig.int_gpio, + &l_sensorconfig.samp, + &(pCvt->map[MC3XXX_AXIS_X]), + &(pCvt->sign[MC3XXX_AXIS_X]), + &(pCvt->map[MC3XXX_AXIS_Y]), + &(pCvt->sign[MC3XXX_AXIS_Y]), + &(pCvt->map[MC3XXX_AXIS_Z]), + &(pCvt->sign[MC3XXX_AXIS_Z]), + &(l_sensorconfig.offset[0]), + &(l_sensorconfig.offset[1]), + &(l_sensorconfig.offset[2]) + ); + if (n != 12) { + printk(KERN_ERR "gsensor format is error in u-boot!!!\n"); + return -1; + } + l_sensorconfig.sensor_samp = l_sensorconfig.samp; + + + dbg("get the sensor config: %d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d\n", + l_sensorconfig.op, + l_sensorconfig.int_gpio, + l_sensorconfig.samp, + pCvt->map[MC3XXX_AXIS_X], + pCvt->sign[MC3XXX_AXIS_X], + pCvt->map[MC3XXX_AXIS_Y], + pCvt->sign[MC3XXX_AXIS_Y], + pCvt->map[MC3XXX_AXIS_Z], + pCvt->sign[MC3XXX_AXIS_Z], + l_sensorconfig.offset[0], + l_sensorconfig.offset[1], + l_sensorconfig.offset[2] + ); + } + return 0; +} + +static void mc3xxx_platform_release(struct device *device) +{ + return; +} + + +static struct platform_device mc3xxx_pdevice = { + .name = SENSOR_NAME, + .id = 0, + .dev = { + .release = mc3xxx_platform_release, + }, +}; + +static struct platform_driver mc3xxx_pdriver = { + .probe = mc3xxx_probe, + .remove = mc3xxx_remove, + .suspend = mc3xxx_early_suspend, + .resume = mc3xxx_early_resume, + //.shutdown = mc3xxx_shutdown, + .driver = { + .name = SENSOR_NAME, + }, +}; + + +static int __init mc3xxx_init(void) +{ + int ret = -1; + struct i2c_client *this_client; + printk("mc3xxx: init\n"); + + //ret = i2c_add_driver(&mc3xxx_driver); + + // parse g-sensor u-boot arg + ret = get_axisset(); + if (ret < 0) + { + printk("<<<<<%s user choose to no sensor chip!\n", __func__); + return ret; + } + + if (!(this_client = sensor_i2c_register_device(0, mc3xxx_i2c_auto_probe_addr[0], SENSOR_NAME))) + { + printk(KERN_ERR"Can't register gsensor i2c device!\n"); + return -1; + } + + if (MC3XXX_RETCODE_SUCCESS != _mc3xxx_i2c_auto_probe(this_client)) + { + GSE_ERR("ERR: fail to auto_probe mCube sensor!\n"); + sensor_i2c_unregister_device(this_client); + return -1; + } + + + l_sensorconfig.client = this_client; + + l_dev_class = class_create(THIS_MODULE, SENSOR_NAME); + if (IS_ERR(l_dev_class)){ + ret = PTR_ERR(l_dev_class); + printk(KERN_ERR "Can't class_create gsensor device !!\n"); + return ret; + } + if((ret = platform_device_register(&mc3xxx_pdevice))) + { + klog("Can't register mc3xxx platform devcie!!!\n"); + return ret; + } + if ((ret = platform_driver_register(&mc3xxx_pdriver)) != 0) + { + errlog("Can't register mc3xxx platform driver!!!\n"); + return ret; + } + + + return ret; +} + +static void __exit mc3xxx_exit(void) +{ + //i2c_del_driver(&mc3xxx_driver); +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&l_sensorconfig.earlysuspend); +#endif + platform_driver_unregister(&mc3xxx_pdriver); + platform_device_unregister(&mc3xxx_pdevice); + sensor_i2c_unregister_device(l_sensorconfig.client); + class_destroy(l_dev_class); +} + +//============================================================================= +module_init(mc3xxx_init); +module_exit(mc3xxx_exit); + +MODULE_DESCRIPTION("mc3xxx accelerometer driver"); +MODULE_AUTHOR("mCube-inc"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(SENSOR_DRIVER_VERSION); + diff --git a/ANDROID_3.4.5/drivers/input/sensor/mma7660_gsensor/Makefile b/ANDROID_3.4.5/drivers/input/sensor/mma7660_gsensor/Makefile new file mode 100755 index 00000000..99ecc6a1 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/mma7660_gsensor/Makefile @@ -0,0 +1,34 @@ +KERNELDIR=../../../../ +#KERNELDIR=/home/hangyan/android8850/kernel/ANDROID_3.0.8 +CROSS = arm_1103_le- +CC= $(CROSS)gcc +LD= $(CROSS)ld +STRIP = $(CROSS)strip + +DEBUG = n + +# Add your debugging flag (or not) to EXTRA_CFLAGS +ifeq ($(DEBUG),y) +# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines +DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines + +else + DEBFLAGS = -O2 -Wall +endif + +EXTRA_CFLAGS += $(DEBFLAGS) + + +MY_MODULE_NAME=s_wmt_gsensor_mma7660 + +obj-m := $(MY_MODULE_NAME).o +$(MY_MODULE_NAME)-objs := mma7660.o + +default: + $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules + $(STRIP) --strip-debug $(MY_MODULE_NAME).ko + rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions + +clean: + rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers + diff --git a/ANDROID_3.4.5/drivers/input/sensor/mma7660_gsensor/mma7660.c b/ANDROID_3.4.5/drivers/input/sensor/mma7660_gsensor/mma7660.c new file mode 100755 index 00000000..f0a0b1ee --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/mma7660_gsensor/mma7660.c @@ -0,0 +1,1052 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mma7660.h" + + +//#define DEBUG 1 + +#undef dbg + +//#if 0 + #define dbg(fmt, args...) if (l_sensorconfig.isdbg) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__, ## args) + //#define dbg(fmt, args...) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__, ## args) + +#define klog(fmt, args...) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__, ## args) + + //#define dbg(format, arg...) printk(KERN_ALERT format, ## arg) + + +//#else +// #define dbg(format, arg...) +//#endif + +/////////////////////Macro constant +#define SENSOR_POLL_WAIT_TIME 1837 +#define MAX_FAILURE_COUNT 10 +#define MMA7660_ADDR 0x4C +#define LAND_PORT_MASK 0x1C +#define LAND_LEFT 0x1 +#define LAND_RIGHT 0x2 +#define PORT_INVERT 0x5 +#define PORT_NORMAL 0x6 + +#define LANDSCAPE_LOCATION 0 +#define PORTRAIT_LOCATION 1 + +#define SENSOR_UI_MODE 0 +#define SENSOR_GRAVITYGAME_MODE 1 + +#define UI_SAMPLE_RATE 0xFC + +#define GSENSOR_PROC_NAME "gsensor_config" +#define GSENSOR_MAJOR 161 +#define GSENSOR_NAME "mma7660" +#define GSENSOR_DRIVER_NAME "mma7660_drv" + + +#define sin30_1000 500 +#define cos30_1000 866 + +#define DISABLE 0 +#define ENABLE 1 + +////////////////////////the rate of g-sensor///////////////////////////////////////////// +#define SENSOR_DELAY_FASTEST 0 +#define SENSOR_DELAY_GAME 20 +#define SENSOR_DELAY_UI 60 +#define SENSOR_DELAY_NORMAL 200 + +#define FASTEST_MMA_AMSR 0 // 120 samples/sec +#define GAME_MMA_AMSR 1 // 1, (64, samples/sec) +#define UI_MMA_AMSR 3 // 2, 3,4, (16, 8,32 samples/sec) +#define NORMAL_MMA_AMSR 5 // 5, 6, 7 (4, 2, 1 samples/sec) + +///////////////////////////////////////////////////////////////////////// +static int xyz_g_table[64] = { +0,47,94,141,188,234,281,328, +375,422,469,516,563,609,656,703, +750,797,844,891,938,984,1031,1078, +1125,1172,1219,1266,1313,1359,1406,1453, +-1500,-1453,-1406,-1359,-1313,-1266,-1219,-1172, +-1125,-1078,-1031,-984,-938,-891,-844,-797, +-750,-703,-656,-609,-563,-516,-469,-422, +-375,-328,-281,-234,-188,-141,-94,-47 +}; + +static struct platform_device *this_pdev; + +static struct class* l_dev_class = NULL; +static struct device *l_clsdevice = NULL; + + + +struct mma7660_config +{ + int op; + int int_gpio; //0-3 + int xyz_axis[3][2]; // (axis,direction) + int rxyz_axis[3][2]; + int irq; + struct proc_dir_entry* sensor_proc; + int sensorlevel; + int shake_enable; // 1--enable shake, 0--disable shake + int manual_rotation; // 0--landance, 90--vertical + struct input_dev *input_dev; + //struct work_struct work; + struct delayed_work work; // for polling + struct workqueue_struct *queue; + int isdbg; // 0-- no debug log, 1--show debug log + int sensor_samp; // 1,2,4,8,16,32,64,120 + int sensor_enable; // 0 --> disable sensor, 1 --> enable sensor + int test_pass; + spinlock_t spinlock; + int pollcnt; // the counts of polling + int offset[3]; +}; + +static struct mma7660_config l_sensorconfig = { + .op = 0, + .int_gpio = 3, + .xyz_axis = { + {ABS_X, -1}, + {ABS_Y, 1}, + {ABS_Z, -1}, + }, + .irq = 6, + .int_gpio = 3, + .sensor_proc = NULL, + .sensorlevel = SENSOR_GRAVITYGAME_MODE, + .shake_enable = 0, // default enable shake + .isdbg = 0, + .sensor_samp = 10, // 4sample/second + .sensor_enable = 1, // enable sensor + .test_pass = 0, // for test program + .pollcnt = 0, // Don't report the x,y,z when the driver is loaded until 2~3 seconds + .offset = {0,0,0}, +}; + + +static struct timer_list l_polltimer; // for shaking +static int is_sensor_good = 0; // 1-- work well, 0 -- exception +struct work_struct poll_work; +static struct mutex sense_data_mutex; +static int revision = -1; +static int l_resumed = 0; // 1: suspend --> resume;2: suspend but not resumed; other values have no meaning + +//////////////////Macro function////////////////////////////////////////////////////// + +#define SET_MMA_SAMPLE(buf,samp) { \ + buf[0] = 0; \ + sensor_i2c_write(MMA7660_ADDR,7,buf,1); \ + buf[0] = samp; \ + sensor_i2c_write(MMA7660_ADDR,8,buf,1); \ + buf[0] = 0x01; \ + sensor_i2c_write(MMA7660_ADDR,7,buf,1); \ +} + +////////////////////////Function define///////////////////////////////////////////////////////// + +static unsigned int mma_sample2AMSR(unsigned int samp); + +////////////////////////Function implement///////////////////////////////////////////////// +// rate: 1,2,4,8,16,32,64,120 +static unsigned int sample_rate_2_memsec(unsigned int rate) +{ + return (1000/rate); +} + + + +static ssize_t gsensor_vendor_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = 0; + + sprintf(buf, "MMA7660_%#x\n", revision); + ret = strlen(buf) + 1; + + return ret; +} + +static DEVICE_ATTR(vendor, 0444, gsensor_vendor_show, NULL); + +static struct kobject *android_gsensor_kobj; +static int gsensor_sysfs_init(void) +{ + int ret ; + + android_gsensor_kobj = kobject_create_and_add("android_gsensor", NULL); + if (android_gsensor_kobj == NULL) { + printk(KERN_ERR + "mma7660 gsensor_sysfs_init:"\ + "subsystem_register failed\n"); + ret = -ENOMEM; + goto err; + } + + ret = sysfs_create_file(android_gsensor_kobj, &dev_attr_vendor.attr); + if (ret) { + printk(KERN_ERR + "mma7660 gsensor_sysfs_init:"\ + "sysfs_create_group failed\n"); + goto err4; + } + + return 0 ; +err4: + kobject_del(android_gsensor_kobj); +err: + return ret ; +} + +static int gsensor_sysfs_exit(void) +{ + sysfs_remove_file(android_gsensor_kobj, &dev_attr_vendor.attr); + kobject_del(android_gsensor_kobj); + return 0; +} + +//extern int wmt_i2c_xfer_continue_if_4(struct i2c_msg *msg, unsigned int num, int bus_id); +extern int i2c_api_do_send(int bus_id, char chip_addr, char sub_addr, char *buf, unsigned int size); +extern int i2c_api_do_recv(int bus_id, char chip_addr, char sub_addr, char *buf, unsigned int size); + +int sensor_i2c_write(unsigned int addr,unsigned int index,char *pdata,int len) +{ + /*struct i2c_msg msg[1]; + unsigned char buf[len+1]; + + //addr = (addr >> 1); + buf[0] = index; + memcpy(&buf[1],pdata,len); + msg[0].addr = addr; + msg[0].flags = 0 ; + msg[0].flags &= ~(I2C_M_RD); + msg[0].len = len+1; + msg[0].buf = buf; +//tmp sensor_i2c_do_xfer(msg,1); + if (wmt_i2c_xfer_continue_if_4(msg,1,0) <= 0) + { + klog("write error!\n"); + return -1; + }*/ + int ret; + ret = i2c_api_do_send(0, addr, index, pdata, len); + if (ret <= 0) { + klog("i2c_api_do_send error!\n"); + return -1; + } + +#ifdef DEBUG +{ + int i; + + printk("sensor_i2c_write(addr 0x%x,index 0x%x,len %d\n",addr,index,len); + for(i=0;i> 1); + memset(buf,0x55,len+1); + buf[0] = index; + buf[1] = 0x0; + + msg[0].addr = addr; + msg[0].flags = 0 ; + msg[0].flags &= ~(I2C_M_RD); + msg[0].len = 1; + msg[0].buf = buf; + + msg[1].addr = addr; + msg[1].flags = 0 ; + msg[1].flags |= (I2C_M_RD); + msg[1].len = len; + msg[1].buf = buf; + + //tmp sensor_i2c_do_xfer(msg, 2); + ret = wmt_i2c_xfer_continue_if_4(msg, 2,0); + if (ret < 0) + { + klog("read error!\n"); + return ret; + } + + memcpy(pdata,buf,len);*/ + int ret; + ret = i2c_api_do_recv(0, addr, index, pdata, len); + if (ret <= 0) { + klog("i2c_api_do_recv error!\n"); + return -1; + } +#ifdef DEBUG +{ + int i; + + printk("sensor_i2c_read(addr 0x%x,index 0x%x,len %d\n",addr,index,len); + for(i=0;i= 120) + { + return 0; + } + while (samp) + { + samp = samp >> 1; + i++; + } + amsr = 8 - i; + return amsr; +} + +static int mma_enable_disable(int enable) +{ + char buf[1]; + + // disable all interrupt of g-sensor + memset(buf, 0, sizeof(buf)); + if ((enable < 0) || (enable > 1)) + { + return -1; + } + buf[0] = 0; + sensor_i2c_write(MMA7660_ADDR,7,buf,1); + if (enable != 0) + { + buf[0] = (1 == l_sensorconfig.shake_enable) ? 0xF0:0x10; + } else { + buf[0] = 0; + } + sensor_i2c_write(MMA7660_ADDR,6,buf,1); + buf[0] = 0xf9; + sensor_i2c_write(MMA7660_ADDR,7,buf,1); + return 0; +} + +// To contol the g-sensor for UI +static int mmad_open(struct inode *inode, struct file *file) +{ + dbg("Open the g-sensor node...\n"); + return 0; +} + +static int mmad_release(struct inode *inode, struct file *file) +{ + dbg("Close the g-sensor node...\n"); + return 0; +} + +static /*int*/ long +mmad_ioctl(/*struct inode *inode,*/ struct file *file, unsigned int cmd, + unsigned long arg) +{ + void __user *argp = (void __user *)arg; + char rwbuf[5]; + short delay, enable; //amsr = -1; + unsigned int uval = 0; + int i = 0; + unsigned char rxData[3] = {0}; + int intBuf[3] = {0}; + dbg("g-sensor ioctr...\n"); + memset(rwbuf, 0, sizeof(rwbuf)); + switch (cmd) { + case ECS_IOCTL_APP_SET_DELAY: + // set the rate of g-sensor + if (copy_from_user(&delay, argp, sizeof(short))) + { + printk(KERN_ALERT "Can't get set delay!!!\n"); + return -EFAULT; + } + klog("Get delay=%d\n", delay); + //klog("before change sensor sample:%d...\n", l_sensorconfig.sensor_samp); + if ((delay >=0) && (delay < 20)) + { + delay = 20; + } else if (delay > 200) + { + delay = 200; + } + l_sensorconfig.sensor_samp = 1000/delay; + + break; + case ECS_IOCTL_APP_SET_AFLAG: + // enable/disable sensor + if (copy_from_user(&enable, argp, sizeof(short))) + { + printk(KERN_ERR "Can't get enable flag!!!\n"); + return -EFAULT; + } + klog("enable=%d\n",enable); + if ((enable >=0) && (enable <=1)) + { + dbg("driver: disable/enable(%d) gsensor.\n", enable); + + l_sensorconfig.sensor_enable = enable; + + } else { + printk(KERN_ERR "Wrong enable argument in %s !!!\n", __FUNCTION__); + return -EINVAL; + } + break; + case WMT_IOCTL_SENSOR_GET_DRVID: + uval = MMA7660_DRVID; + if (copy_to_user((unsigned int*)arg, &uval, sizeof(unsigned int))) + { + return -EFAULT; + } + dbg("mma7660_driver_id:%d\n",uval); + break; + case ECS_IOCTL_APP_READ_XYZ: + sensor_i2c_read(MMA7660_ADDR,0,rxData,3); + + for (i=0; i < 3; i++) + { + if (rxData[i]&0x40) break; + } + //if (l_sensorconfig.pollcnt >= 20) + if (3 == i) + { + intBuf[0] = xyz_g_table[rxData[l_sensorconfig.xyz_axis[0][0]]]*l_sensorconfig.xyz_axis[0][1]; + intBuf[1] = xyz_g_table[rxData[l_sensorconfig.xyz_axis[1][0]]]*l_sensorconfig.xyz_axis[1][1]; + intBuf[2] = xyz_g_table[rxData[l_sensorconfig.xyz_axis[2][0]]]*l_sensorconfig.xyz_axis[2][1]; + + if (copy_to_user((unsigned int*)arg, intBuf, sizeof(intBuf))) + { + return -EFAULT; + } + } + break; + } + + + + return 0; +} + + +static void mma_work_func(struct work_struct *work) +{ + struct mma7660_config *data; + unsigned char rxData[3]; + //unsigned char tiltval = 0; + int i = 0; + int x,y,z; + + dbg("enter...\n"); + data = dev_get_drvdata(&this_pdev->dev); + if (!l_sensorconfig.sensor_enable) + { + queue_delayed_work(l_sensorconfig.queue, &l_sensorconfig.work, msecs_to_jiffies(sample_rate_2_memsec(l_sensorconfig.sensor_samp))); + return; + } + mutex_lock(&sense_data_mutex); + is_sensor_good = 1; // for watchdog + l_sensorconfig.test_pass = 1; // for testing + + /*sensor_i2c_read(MMA7660_ADDR,3,rxData,1); + tiltval = rxData[0]; + if (tiltval & 0x80) { + if (1 == l_sensorconfig.shake_enable) { + printk(KERN_NOTICE "shake!!!\n"); + input_report_key(data->input_dev, KEY_NEXTSONG, 1); + input_report_key(data->input_dev, KEY_NEXTSONG, 0); + input_sync(data->input_dev); + + } + } else*/ { + sensor_i2c_read(MMA7660_ADDR,0,rxData,3); + /* dbg(KERN_DEBUG "Angle: x=%d, y=%d, z=%d\n", + xy_degree_table[rxData[0]], + xy_degree_table[rxData[1]], + z_degree_table[rxData[2]]); + dbg(KERN_DEBUG "G value: x=%d, y=%d, z=%d\n", + xyz_g_table[rxData[0]], + xyz_g_table[rxData[1]], + xyz_g_table[rxData[2]]); + */ + for (i=0; i < 3; i++) + { + if (rxData[i]&0x40) break; + } + //if (l_sensorconfig.pollcnt >= 20) + if (3 == i) + { + x = xyz_g_table[rxData[l_sensorconfig.xyz_axis[0][0]]]*l_sensorconfig.xyz_axis[0][1]; + y = xyz_g_table[rxData[l_sensorconfig.xyz_axis[1][0]]]*l_sensorconfig.xyz_axis[1][1]; + z = xyz_g_table[rxData[l_sensorconfig.xyz_axis[2][0]]]*l_sensorconfig.xyz_axis[2][1]; + input_report_abs(data->input_dev, ABS_X, x); + input_report_abs(data->input_dev, ABS_Y, y); + input_report_abs(data->input_dev, ABS_Z, z); + input_sync(data->input_dev); + dbg("gx=%x,gy=%x,gz=%x\n",x,y,z); + } + } + //gsensor_int_ctrl(ENABLE); + mutex_unlock(&sense_data_mutex); + queue_delayed_work(l_sensorconfig.queue, &l_sensorconfig.work, msecs_to_jiffies(sample_rate_2_memsec(l_sensorconfig.sensor_samp))); +} + +static int sensor_writeproc( struct file *file, + const char *buffer, + unsigned long count, + void *data ) +{ + + int inputval = -1; + int enable, sample = -1; + char tembuf[8]; + unsigned int amsr = 0; + int test = 0; + + mutex_lock(&sense_data_mutex); + // disable int + //gsensor_int_ctrl(DISABLE); + memset(tembuf, 0, sizeof(tembuf)); + // get sensor level and set sensor level + if (sscanf(buffer, "level=%d\n", &l_sensorconfig.sensorlevel)) + { + } else if (sscanf(buffer, "shakenable=%d\n", &l_sensorconfig.shake_enable)) + { + /* + regval[0] = 0; + sensor_i2c_write(MMA7660_ADDR,7,regval,1); // standard mode + sensor_i2c_read(MMA7660_ADDR,6,regval,1); + switch (l_sensorconfig.shake_enable) + { + case 0: // disable shake + regval[0] &= 0x1F; + sensor_i2c_write(MMA7660_ADDR,6, regval,1); + dbg("Shake disable!!\n"); + break; + case 1: // enable shake + regval[0] |= 0xE0; + sensor_i2c_write(MMA7660_ADDR,6, regval,1); + dbg("Shake enable!!\n"); + break; + }; + sensor_i2c_write(MMA7660_ADDR,7,&oldval,1); + */ + } /*else if (sscanf(buffer, "rotation=%d\n", &l_sensorconfig.manual_rotation)) + { + switch (l_sensorconfig.manual_rotation) + { + case 90: + // portrait + input_report_abs(mma7660data->input_dev, ABS_X, cos30_1000); + input_report_abs(mma7660data->input_dev, ABS_Y, 0); + input_report_abs(mma7660data->input_dev, ABS_Z, sin30_1000); + input_sync(mma7660data->input_dev); + break; + case 0: + // landscape + input_report_abs(mma7660data->input_dev, ABS_X, 0); + input_report_abs(mma7660data->input_dev, ABS_Y, cos30_1000); + input_report_abs(mma7660data->input_dev, ABS_Z, sin30_1000); + input_sync(mma7660data->input_dev); + break; + }; + }*/ else if (sscanf(buffer, "isdbg=%d\n", &l_sensorconfig.isdbg)) + { + // only set the dbg flag + } else if (sscanf(buffer, "init=%d\n", &inputval)) + { + mma7660_chip_init(); + dbg("Has reinit sensor !!!\n"); + } else if (sscanf(buffer, "samp=%d\n", &sample)) + { + if (sample > 0) + { + if (sample != l_sensorconfig.sensor_samp) + { + amsr = mma_sample2AMSR(sample); + SET_MMA_SAMPLE(tembuf, amsr); + klog("sample:%d ,amsr:%d \n", sample, amsr); + l_sensorconfig.sensor_samp = sample; + } + printk(KERN_ALERT "sensor samp=%d(amsr:%d) has been set.\n", sample, amsr); + } else { + printk(KERN_ALERT "Wrong sample argumnet of sensor.\n"); + } + } else if (sscanf(buffer, "enable=%d\n", &enable)) + { + if ((enable < 0) || (enable > 1)) + { + printk(KERN_ERR "The argument to enable/disable g-sensor should be 0 or 1 !!!\n"); + } else if (enable != l_sensorconfig.sensor_enable) + { + mma_enable_disable(enable); + l_sensorconfig.sensor_enable = enable; + } + } else if (sscanf(buffer, "sensor_test=%d\n", &test)) + { // for test begin + l_sensorconfig.test_pass = 0; + } else if (sscanf(buffer, "sensor_testend=%d\n", &test)) + { // Don nothing only to be compatible the before testing program + } + mutex_unlock(&sense_data_mutex); + return count; +} + +static int sensor_readproc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = 0; + + len = sprintf(page, + "test_pass=%d\nisdbg=%d\nrate=%d\nenable=%d\n", + l_sensorconfig.test_pass, + l_sensorconfig.isdbg, + l_sensorconfig.sensor_samp, + l_sensorconfig.sensor_enable + ); + return len; +} + + + +static int mma7660_init_client(struct platform_device *pdev) +{ + struct mma7660_config *data; +// int ret; + + data = dev_get_drvdata(&pdev->dev); + mutex_init(&sense_data_mutex); + /*Only for polling, not interrupt*/ + l_sensorconfig.sensor_proc = create_proc_entry(GSENSOR_PROC_NAME, 0666, NULL/*&proc_root*/); + if (l_sensorconfig.sensor_proc != NULL) + { + l_sensorconfig.sensor_proc->write_proc = sensor_writeproc; + l_sensorconfig.sensor_proc->read_proc = sensor_readproc; + } + + + return 0; + +//err: +// return ret; +} + +static struct file_operations mmad_fops = { + .owner = THIS_MODULE, + .open = mmad_open, + .release = mmad_release, + .unlocked_ioctl = mmad_ioctl, +}; + + +static struct miscdevice mmad_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "sensor_ctrl", + .fops = &mmad_fops, +}; + +static int mma7660_probe( + struct platform_device *pdev) +{ + int err; + + this_pdev = pdev; + l_sensorconfig.queue = create_singlethread_workqueue("sensor-intterupt-handle"); + INIT_DELAYED_WORK(&l_sensorconfig.work, mma_work_func); + + l_sensorconfig.input_dev = input_allocate_device(); + if (!l_sensorconfig.input_dev) { + err = -ENOMEM; + printk(KERN_ERR + "mma7660_probe: Failed to allocate input device\n"); + goto exit_input_dev_alloc_failed; + } + l_sensorconfig.input_dev->evbit[0] = BIT(EV_ABS) | BIT_MASK(EV_KEY); + set_bit(KEY_NEXTSONG, l_sensorconfig.input_dev->keybit); + + /* x-axis acceleration */ + input_set_abs_params(l_sensorconfig.input_dev, ABS_X, -65532, 65532, 0, 0); + /* y-axis acceleration */ + input_set_abs_params(l_sensorconfig.input_dev, ABS_Y, -65532, 65532, 0, 0); + /* z-axis acceleration */ + input_set_abs_params(l_sensorconfig.input_dev, ABS_Z, -65532, 65532, 0, 0); + + l_sensorconfig.input_dev->name = "g-sensor"; + + err = input_register_device(l_sensorconfig.input_dev); + + if (err) { + printk(KERN_ERR + "mma7660_probe: Unable to register input device: %s\n", + l_sensorconfig.input_dev->name); + goto exit_input_register_device_failed; + } + + err = misc_register(&mmad_device); + if (err) { + printk(KERN_ERR + "mma7660_probe: mmad_device register failed\n"); + goto exit_misc_device_register_failed; + } + + dev_set_drvdata(&pdev->dev, &l_sensorconfig); + mma7660_chip_init(); + mma7660_init_client(pdev); + gsensor_sysfs_init(); + + // satrt the polling work + l_sensorconfig.sensor_samp = 10; + queue_delayed_work(l_sensorconfig.queue, &l_sensorconfig.work, msecs_to_jiffies(sample_rate_2_memsec(l_sensorconfig.sensor_samp))); + return 0; + +exit_misc_device_register_failed: +exit_input_register_device_failed: + input_free_device(l_sensorconfig.input_dev); +//exit_alloc_data_failed: +exit_input_dev_alloc_failed: +//exit_check_functionality_failed: + return err; +} + +static int mma7660_remove(struct platform_device *pdev) +{ + if (NULL != l_sensorconfig.queue) + { + cancel_delayed_work_sync(&l_sensorconfig.work); + flush_workqueue(l_sensorconfig.queue); + destroy_workqueue(l_sensorconfig.queue); + l_sensorconfig.queue = NULL; + } + gsensor_sysfs_exit(); + misc_deregister(&mmad_device); + input_unregister_device(l_sensorconfig.input_dev); + if (l_sensorconfig.sensor_proc != NULL) + { + remove_proc_entry(GSENSOR_PROC_NAME, NULL); + l_sensorconfig.sensor_proc = NULL; + } + //free_irq(l_sensorconfig.irq, &l_sensorconfig); + return 0; +} + +static int mma7660_suspend(struct platform_device *pdev, pm_message_t state) +{ + //gsensor_int_ctrl(DISABLE); + cancel_delayed_work_sync(&l_sensorconfig.work); + del_timer(&l_polltimer); + dbg("...ok\n"); + //l_resumed = 2; + + return 0; +} + +static int mma7660_resume(struct platform_device *pdev) +{ + + //mma7660_chip_init(); + //gsensor_int_ctrl(ENABLE); + //mma_enable_disable(1); + l_resumed = 1; + mod_timer(&l_polltimer, jiffies + msecs_to_jiffies(SENSOR_POLL_WAIT_TIME)); + dbg("...ok\n"); + + return 0; +} + +static void mma7660_platform_release(struct device *device) +{ + return; +} + +static void mma7660_shutdown(struct platform_device *pdev) +{ + + flush_delayed_work_sync(&l_sensorconfig.work); + cancel_delayed_work_sync(&l_sensorconfig.work); + +} + +static struct platform_device mma7660_device = { + .name = "mma7660", + .id = 0, + .dev = { + .release = mma7660_platform_release, + }, +}; + +static struct platform_driver mma7660_driver = { + .probe = mma7660_probe, + .remove = mma7660_remove, + .suspend = mma7660_suspend, + .resume = mma7660_resume, + .shutdown = mma7660_shutdown, + .driver = { + .name = "mma7660", + }, +}; + +/* + * Brief: + * Get the configure of sensor from u-boot. + * Input: + * no use. + * Output: + * no use. + * Return: + * 0--success, -1--error. + * History: + * Created by HangYan on 2010-4-19 + * Author: + * Hang Yan in ShenZhen. + */ +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); +static int get_axisset(void* param) +{ + char varbuf[64]; + int n; + int varlen; + + memset(varbuf, 0, sizeof(varbuf)); + varlen = sizeof(varbuf); + if (wmt_getsyspara("wmt.io.mma7660gsensor", varbuf, &varlen)) { + printk(KERN_DEBUG "Can't get gsensor config in u-boot!!!!\n"); + return -1; + } else { + n = sscanf(varbuf, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", + &l_sensorconfig.op, + &(l_sensorconfig.xyz_axis[0][0]), + &(l_sensorconfig.xyz_axis[0][1]), + &(l_sensorconfig.xyz_axis[1][0]), + &(l_sensorconfig.xyz_axis[1][1]), + &(l_sensorconfig.xyz_axis[2][0]), + &(l_sensorconfig.xyz_axis[2][1]), + &(l_sensorconfig.offset[0]), + &(l_sensorconfig.offset[1]), + &(l_sensorconfig.offset[2])); + if (n != 10) { + printk(KERN_ERR "gsensor format is error in u-boot!!!\n"); + return -1; + } + + dbg("get the sensor config: %d:%d:%d:%d:%d:%d:%d:%d:%d:%d\n", + l_sensorconfig.op, + l_sensorconfig.xyz_axis[0][0], + l_sensorconfig.xyz_axis[0][1], + l_sensorconfig.xyz_axis[1][0], + l_sensorconfig.xyz_axis[1][1], + l_sensorconfig.xyz_axis[2][0], + l_sensorconfig.xyz_axis[2][1], + l_sensorconfig.offset[0], + l_sensorconfig.offset[1], + l_sensorconfig.offset[2] + ); + } + return 0; +} + + +// Add one timer to reinit sensor every 5s +static void sensor_polltimer_timeout(unsigned long timeout) +{ + schedule_work(&poll_work); +} + +static void poll_work_func(struct work_struct *work) +{ + char rxData[1]; + + //mutex_lock(&sense_data_mutex); + if (l_sensorconfig.pollcnt != 20) + { + l_sensorconfig.pollcnt++; + } + dbg("read to work!\n"); + //spin_lock(&l_sensorconfig.spinlock); + mutex_lock(&sense_data_mutex); + if (1 == l_resumed) + { + mma7660_chip_init(); + //gsensor_int_ctrl(ENABLE); + //mma_enable_disable(1); + dbg("reinit for resume...\n"); + l_resumed = 0; + //spin_unlock(&l_sensorconfig.spinlock); + mutex_unlock(&sense_data_mutex); + queue_delayed_work(l_sensorconfig.queue, &l_sensorconfig.work, msecs_to_jiffies(sample_rate_2_memsec(l_sensorconfig.sensor_samp))); + + return; + } + //spin_unlock(&l_sensorconfig.spinlock); + mutex_unlock(&sense_data_mutex); + if (!is_sensor_good) + { + //mma7660_chip_init(); + // if ic is blocked then wake g-sensor + sensor_i2c_read(MMA7660_ADDR,3,rxData,1); + } else { + is_sensor_good = 0; + } + + //mutex_unlock(&sense_data_mutex); + mod_timer(&l_polltimer, jiffies + msecs_to_jiffies(SENSOR_POLL_WAIT_TIME)); + +} + +static int mma7660_open(struct inode *inode, struct file *file) +{ + return 0; +} + +static int mma7660_release(struct inode *inode, struct file *file) +{ + return 0; +} + + +static struct file_operations mma7660_fops = { + .owner = THIS_MODULE, + .open = mma7660_open, + .release = mma7660_release, +}; + +static int is_mma7660(void) +{ + char txData[2]; + int i = 0; + + txData[1] = 0; + for (i = 0; i < 3; i++) + { + if(sensor_i2c_write(MMA7660_ADDR,7,txData,1) == 0) + { + return 0; + } + } + return -1; +} + +static int __init mma7660_init(void) +{ + int ret = 0; + + if (is_mma7660()) + { + printk(KERN_ERR "Can't find mma7660!!\n"); + return -1; + } + ret = get_axisset(NULL); // get gsensor config from u-boot + if (ret < 0) + { + printk("<<<<<%s user choose to no sensor chip!\n", __func__); + return ret; + } + /*if ((ret != 0) || !l_sensorconfig.op) + return -EINVAL;*/ + + + printk(KERN_INFO "mma7660fc g-sensor driver init\n"); + + spin_lock_init(&l_sensorconfig.spinlock); + INIT_WORK(&poll_work, poll_work_func); + // Create device node + if (register_chrdev (GSENSOR_MAJOR, GSENSOR_NAME, &mma7660_fops)) { + printk (KERN_ERR "unable to get major %d\n", GSENSOR_MAJOR); + return -EIO; + } + + l_dev_class = class_create(THIS_MODULE, GSENSOR_NAME); + if (IS_ERR(l_dev_class)){ + ret = PTR_ERR(l_dev_class); + printk(KERN_ERR "Can't class_create gsensor device !!\n"); + return ret; + } + l_clsdevice = device_create(l_dev_class, NULL, MKDEV(GSENSOR_MAJOR, 0), NULL, GSENSOR_NAME); + if (IS_ERR(l_clsdevice)){ + ret = PTR_ERR(l_clsdevice); + printk(KERN_ERR "Failed to create device %s !!!",GSENSOR_NAME); + return ret; + } + + if((ret = platform_device_register(&mma7660_device))) + { + printk(KERN_ERR "%s Can't register mma7660 platform devcie!!!\n", __FUNCTION__); + return ret; + } + if ((ret = platform_driver_register(&mma7660_driver)) != 0) + { + printk(KERN_ERR "%s Can't register mma7660 platform driver!!!\n", __FUNCTION__); + return ret; + } + + setup_timer(&l_polltimer, sensor_polltimer_timeout, 0); + mod_timer(&l_polltimer, jiffies + msecs_to_jiffies(SENSOR_POLL_WAIT_TIME)); + is_sensor_good = 1; + + return 0; +} + +static void __exit mma7660_exit(void) +{ + del_timer(&l_polltimer); + platform_driver_unregister(&mma7660_driver); + platform_device_unregister(&mma7660_device); + device_destroy(l_dev_class, MKDEV(GSENSOR_MAJOR, 0)); + unregister_chrdev(GSENSOR_MAJOR, GSENSOR_NAME); + class_destroy(l_dev_class); + +} + +module_init(mma7660_init); +module_exit(mma7660_exit); +MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/input/sensor/mma7660_gsensor/mma7660.h b/ANDROID_3.4.5/drivers/input/sensor/mma7660_gsensor/mma7660.h new file mode 100755 index 00000000..db6c06c0 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/mma7660_gsensor/mma7660.h @@ -0,0 +1,106 @@ +/* + * Definitions for akm8976 compass chip. + */ +#ifndef AKM8976_H +#define AKM8976_H + +#include + +/* Compass device dependent definition */ +#define AKECS_MODE_MEASURE 0x00 /* Starts measurement. Please use AKECS_MODE_MEASURE_SNG */ + /* or AKECS_MODE_MEASURE_SEQ instead of this. */ +#define AKECS_MODE_PFFD 0x01 /* Start pedometer and free fall detect. */ +#define AKECS_MODE_E2P_READ 0x02 /* E2P access mode (read). */ +#define AKECS_MODE_POWERDOWN 0x03 /* Power down mode */ + +#define AKECS_MODE_MEASURE_SNG 0x10 /* Starts single measurement */ +#define AKECS_MODE_MEASURE_SEQ 0x11 /* Starts sequential measurement */ + +/* Default register settings */ +#define CSPEC_AINT 0x01 /* Amplification for acceleration sensor */ +#define CSPEC_SNG_NUM 0x01 /* Single measurement mode */ +#define CSPEC_SEQ_NUM 0x02 /* Sequential measurement mode */ +#define CSPEC_SFRQ_32 0x00 /* Measurement frequency: 32Hz */ +#define CSPEC_SFRQ_64 0x01 /* Measurement frequency: 64Hz */ +#define CSPEC_MCS 0x07 /* Clock frequency */ +#define CSPEC_MKS 0x01 /* Clock type: CMOS level */ +#define CSPEC_INTEN 0x01 /* Interruption pin enable: Enable */ + +#define RBUFF_SIZE 31 /* Rx buffer size */ +#define MAX_CALI_SIZE 0x1000U /* calibration buffer size */ + +/* AK8976A register address */ +#define AKECS_REG_ST 0xC0 +#define AKECS_REG_TMPS 0xC1 +#define AKECS_REG_MS1 0xE0 +#define AKECS_REG_MS2 0xE1 +#define AKECS_REG_MS3 0xE2 + +#define AKMIO 0xA1 + +/* IOCTLs for AKM library */ +#define ECS_IOCTL_RESET _IO(AKMIO, 0x04) +#define ECS_IOCTL_INT_STATUS _IO(AKMIO, 0x05) +#define ECS_IOCTL_FFD_STATUS _IO(AKMIO, 0x06) +#define ECS_IOCTL_SET_MODE _IOW(AKMIO, 0x07, short) +#define ECS_IOCTL_GETDATA _IOR(AKMIO, 0x08, char[RBUFF_SIZE+1]) +#define ECS_IOCTL_GET_NUMFRQ _IOR(AKMIO, 0x09, char[2]) +#define ECS_IOCTL_SET_PERST _IO(AKMIO, 0x0A) +#define ECS_IOCTL_SET_G0RST _IO(AKMIO, 0x0B) +#define ECS_IOCTL_SET_YPR _IOW(AKMIO, 0x0C, short[12]) +#define ECS_IOCTL_GET_OPEN_STATUS _IOR(AKMIO, 0x0D, int) +#define ECS_IOCTL_GET_CLOSE_STATUS _IOR(AKMIO, 0x0E, int) +#define ECS_IOCTL_GET_CALI_DATA _IOR(AKMIO, 0x0F, char[MAX_CALI_SIZE]) +#define ECS_IOCTL_GET_DELAY _IOR(AKMIO, 0x30, short) + +/* IOCTLs for APPs */ +#define ECS_IOCTL_APP_SET_MODE _IOW(AKMIO, 0x10, short) +#define ECS_IOCTL_APP_SET_MFLAG _IOW(AKMIO, 0x11, short) +#define ECS_IOCTL_APP_GET_MFLAG _IOW(AKMIO, 0x12, short) +#define ECS_IOCTL_APP_GET_AFLAG _IOR(AKMIO, 0x14, short) +#define ECS_IOCTL_APP_SET_TFLAG _IOR(AKMIO, 0x15, short) +#define ECS_IOCTL_APP_GET_TFLAG _IOR(AKMIO, 0x16, short) +#define ECS_IOCTL_APP_RESET_PEDOMETER _IO(AKMIO, 0x17) +#define ECS_IOCTL_APP_GET_DELAY ECS_IOCTL_GET_DELAY +#define ECS_IOCTL_APP_SET_MVFLAG _IOW(AKMIO, 0x19, short) /* Set raw magnetic vector flag */ +#define ECS_IOCTL_APP_GET_MVFLAG _IOR(AKMIO, 0x1A, short) /* Get raw magnetic vector flag */ + +/* IOCTLs for pedometer */ +#define ECS_IOCTL_SET_STEP_CNT _IOW(AKMIO, 0x20, short) +#define SENSOR_DATA_SIZE 3 +#define WMTGSENSOR_IOCTL_MAGIC 0x09 +#define ECS_IOCTL_APP_SET_AFLAG _IOW(WMTGSENSOR_IOCTL_MAGIC, 0x02, short) +#define ECS_IOCTL_APP_SET_DELAY _IOW(WMTGSENSOR_IOCTL_MAGIC, 0x03, short) +#define WMT_IOCTL_SENSOR_GET_DRVID _IOW(WMTGSENSOR_IOCTL_MAGIC, 0x04, unsigned int) +#define ECS_IOCTL_APP_READ_XYZ _IOW(WMTGSENSOR_IOCTL_MAGIC, 0x05, int[SENSOR_DATA_SIZE]) + +#define MMA7660_DRVID 0 + + + +/* Default GPIO setting */ +#define ECS_RST 146 /*MISC4, bit2 */ +#define ECS_CLK_ON 155 /*MISC5, bit3 */ +#define ECS_INTR 161 /*INT2, bit1 */ + +/* MISC */ +#define MMA7660_ADDR 0x4C +#define SENSOR_UI_MODE 0 +#define SENSOR_GRAVITYGAME_MODE 1 +#define UI_SAMPLE_RATE 0xFC +#define GSENSOR_PROC_NAME "gsensor_config" +#define sin30_1000 500 +#define cos30_1000 866 +#define DISABLE 0 +#define ENABLE 1 + +struct mma7660_platform_data { + int reset; + int clk_on; + int intr; +}; + +extern char *get_mma_cal_ram(void); + +#endif + diff --git a/ANDROID_3.4.5/drivers/input/sensor/mma8452q_gsensor/Makefile b/ANDROID_3.4.5/drivers/input/sensor/mma8452q_gsensor/Makefile new file mode 100755 index 00000000..4dcceb42 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/mma8452q_gsensor/Makefile @@ -0,0 +1,34 @@ +KERNELDIR=../../../../ +#KERNELDIR=/home/hangyan/android8850/kernel/ANDROID_3.0.8 +CROSS = arm_1103_le- +CC= $(CROSS)gcc +LD= $(CROSS)ld +STRIP = $(CROSS)strip + +DEBUG = n + +# Add your debugging flag (or not) to EXTRA_CFLAGS +ifeq ($(DEBUG),y) +# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines +DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines + +else + DEBFLAGS = -O2 -Wall +endif + +EXTRA_CFLAGS += $(DEBFLAGS) + + +MY_MODULE_NAME=s_wmt_gsensor_mma8452q + +obj-m := $(MY_MODULE_NAME).o +$(MY_MODULE_NAME)-objs := mma8x5x.o + +default: + $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules + $(STRIP) --strip-debug $(MY_MODULE_NAME).ko + rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions + +clean: + rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers + diff --git a/ANDROID_3.4.5/drivers/input/sensor/mma8452q_gsensor/mma8x5x.c b/ANDROID_3.4.5/drivers/input/sensor/mma8452q_gsensor/mma8x5x.c new file mode 100755 index 00000000..443d3b18 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/mma8452q_gsensor/mma8x5x.c @@ -0,0 +1,982 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mma8x5x.h" //"mma8452q.h" +#include "../sensor.h" + +//#define DEBUG 1 + +#undef dbg + +//#if 0 + #define dbg(fmt, args...) if (l_sensorconfig.isdbg) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__, ## args) + //#define dbg(fmt, args...) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__, ## args) + +#define klog(fmt, args...) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__, ## args) + + //#define dbg(format, arg...) printk(KERN_ALERT format, ## arg) + + +//#else +// #define dbg(format, arg...) +//#endif + +/////////////////////Macro constant +#define SENSOR_POLL_WAIT_TIME 1837 +#define MAX_FAILURE_COUNT 10 +#define MMA8452_ADDR 0x1C //slave 0x1D??high +#define LAND_PORT_MASK 0x1C +#define LAND_LEFT 0x1 +#define LAND_RIGHT 0x2 +#define PORT_INVERT 0x5 +#define PORT_NORMAL 0x6 + +#define LANDSCAPE_LOCATION 0 +#define PORTRAIT_LOCATION 1 + +#define SENSOR_UI_MODE 0 +#define SENSOR_GRAVITYGAME_MODE 1 + +#define UI_SAMPLE_RATE 0xFC + +#define GSENSOR_PROC_NAME "gsensor_config" +#define GSENSOR_MAJOR 161 +#define GSENSOR_NAME "mma8452q" +#define GSENSOR_DRIVER_NAME "mma8452q_drv" + + +#define sin30_1000 500 +#define cos30_1000 866 + +#define DISABLE 0 +#define ENABLE 1 + +////////////////////////the rate of g-sensor///////////////////////////////////////////// +#define SENSOR_DELAY_FASTEST 0 +#define SENSOR_DELAY_GAME 20 +#define SENSOR_DELAY_UI 60 +#define SENSOR_DELAY_NORMAL 200 + +#define FASTEST_MMA_AMSR 0 // 120 samples/sec +#define GAME_MMA_AMSR 1 // 1, (64, samples/sec) +#define UI_MMA_AMSR 3 // 2, 3,4, (16, 8,32 samples/sec) +#define NORMAL_MMA_AMSR 5 // 5, 6, 7 (4, 2, 1 samples/sec) + +#define MMA8451_ID 0x1A +#define MMA8452_ID 0x2A +#define MMA8453_ID 0x3A +#define MMA8652_ID 0x4A +#define MMA8653_ID 0x5A +#define MODE_CHANGE_DELAY_MS 100 +/* register enum for mma8x5x registers */ +enum { + MMA8X5X_STATUS = 0x00, + MMA8X5X_OUT_X_MSB, + MMA8X5X_OUT_X_LSB, + MMA8X5X_OUT_Y_MSB, + MMA8X5X_OUT_Y_LSB, + MMA8X5X_OUT_Z_MSB, + MMA8X5X_OUT_Z_LSB, + + MMA8X5X_F_SETUP = 0x09, + MMA8X5X_TRIG_CFG, + MMA8X5X_SYSMOD, + MMA8X5X_INT_SOURCE, + MMA8X5X_WHO_AM_I, + MMA8X5X_XYZ_DATA_CFG, + MMA8X5X_HP_FILTER_CUTOFF, + + MMA8X5X_PL_STATUS, + MMA8X5X_PL_CFG, + MMA8X5X_PL_COUNT, + MMA8X5X_PL_BF_ZCOMP, + MMA8X5X_P_L_THS_REG, + + MMA8X5X_FF_MT_CFG, + MMA8X5X_FF_MT_SRC, + MMA8X5X_FF_MT_THS, + MMA8X5X_FF_MT_COUNT, + + MMA8X5X_TRANSIENT_CFG = 0x1D, + MMA8X5X_TRANSIENT_SRC, + MMA8X5X_TRANSIENT_THS, + MMA8X5X_TRANSIENT_COUNT, + + MMA8X5X_PULSE_CFG, + MMA8X5X_PULSE_SRC, + MMA8X5X_PULSE_THSX, + MMA8X5X_PULSE_THSY, + MMA8X5X_PULSE_THSZ, + MMA8X5X_PULSE_TMLT, + MMA8X5X_PULSE_LTCY, + MMA8X5X_PULSE_WIND, + + MMA8X5X_ASLP_COUNT, + MMA8X5X_CTRL_REG1, + MMA8X5X_CTRL_REG2, + MMA8X5X_CTRL_REG3, + MMA8X5X_CTRL_REG4, + MMA8X5X_CTRL_REG5, + + MMA8X5X_OFF_X, + MMA8X5X_OFF_Y, + MMA8X5X_OFF_Z, + + MMA8X5X_REG_END, +}; + +enum { + MODE_2G = 0, + MODE_4G, + MODE_8G, +}; + +static int mma8x5x_chip_id[] ={ + MMA8451_ID, + MMA8452_ID, + MMA8453_ID, + MMA8652_ID, + MMA8653_ID, +}; + +static struct i2c_client *this_client = NULL; +///////////////////////////////////////////////////////////////////////// + +static struct platform_device *this_pdev; + +static struct class* l_dev_class = NULL; +static struct device *l_clsdevice = NULL; + + + +struct mma8452q_config +{ + int op; + int int_gpio; //0-3 + int xyz_axis[3][2]; // (axis,direction) + int rxyz_axis[3][2]; + int irq; + struct proc_dir_entry* sensor_proc; + int sensorlevel; + int shake_enable; // 1--enable shake, 0--disable shake + int manual_rotation; // 0--landance, 90--vertical + struct input_dev *input_dev; + //struct work_struct work; + struct delayed_work work; // for polling + struct workqueue_struct *queue; + int isdbg; // 0-- no debug log, 1--show debug log + int sensor_samp; // 1,2,4,8,16,32,64,120 + int sensor_enable; // 0 --> disable sensor, 1 --> enable sensor + int test_pass; + spinlock_t spinlock; + int pollcnt; // the counts of polling + int offset[3]; +}; + +static struct mma8452q_config l_sensorconfig = { + .op = 0, + .int_gpio = 3, + .xyz_axis = { + {ABS_X, -1}, + {ABS_Y, 1}, + {ABS_Z, -1}, + }, + .irq = 6, + .int_gpio = 3, + .sensor_proc = NULL, + .sensorlevel = SENSOR_GRAVITYGAME_MODE, + .shake_enable = 0, // default enable shake + .isdbg = 0, + .sensor_samp = 10, // 4sample/second + .sensor_enable = 1, // enable sensor + .test_pass = 0, // for test program + .pollcnt = 0, // Don't report the x,y,z when the driver is loaded until 2~3 seconds + .offset = {0,0,0}, +}; + + + +struct work_struct poll_work; +static struct mutex sense_data_mutex; +static int revision = -1; +static int l_resumed = 0; // 1: suspend --> resume;2: suspend but not resumed; other values have no meaning + +//////////////////Macro function////////////////////////////////////////////////////// + +#define SET_MMA_SAMPLE(buf,samp) { \ + buf[0] = 0; \ + sensor_i2c_write(/*MMA8452_ADDR,*/7,buf,1); \ + buf[0] = samp; \ + sensor_i2c_write(/*MMA8452_ADDR,*/8,buf,1); \ + buf[0] = 0x01; \ + sensor_i2c_write(/*MMA8452_ADDR,*/7,buf,1); \ +} + +////////////////////////Function define///////////////////////////////////////////////////////// + +static unsigned int mma_sample2AMSR(unsigned int samp); + +////////////////////////Function implement///////////////////////////////////////////////// +// rate: 1,2,4,8,16,32,64,120 +static unsigned int sample_rate_2_memsec(unsigned int rate) +{ + return (1000/rate); +} + + + +static ssize_t gsensor_vendor_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = 0; + + sprintf(buf, "MMA8452_%#x\n", revision); + ret = strlen(buf) + 1; + + return ret; +} + +static DEVICE_ATTR(vendor, 0444, gsensor_vendor_show, NULL); + +static struct kobject *android_gsensor_kobj; +static int gsensor_sysfs_init(void) +{ + int ret ; + + android_gsensor_kobj = kobject_create_and_add("android_gsensor", NULL); + if (android_gsensor_kobj == NULL) { + printk(KERN_ERR + "mma8452q gsensor_sysfs_init:"\ + "subsystem_register failed\n"); + ret = -ENOMEM; + goto err; + } + + ret = sysfs_create_file(android_gsensor_kobj, &dev_attr_vendor.attr); + if (ret) { + printk(KERN_ERR + "mma8452q gsensor_sysfs_init:"\ + "sysfs_create_group failed\n"); + goto err4; + } + + return 0 ; +err4: + kobject_del(android_gsensor_kobj); +err: + return ret ; +} + +static int gsensor_sysfs_exit(void) +{ + sysfs_remove_file(android_gsensor_kobj, &dev_attr_vendor.attr); + kobject_del(android_gsensor_kobj); + return 0; +} + +//extern int wmt_i2c_xfer_continue_if_4(struct i2c_msg *msg, unsigned int num, int bus_id); +extern int i2c_api_do_send(int bus_id, char chip_addr, char sub_addr, char *buf, unsigned int size); +extern int i2c_api_do_recv(int bus_id, char chip_addr, char sub_addr, char *buf, unsigned int size); + +int sensor_i2c_write(/*unsigned int addr,*/unsigned int index,char *pdata,int len) +{ + + char wrData[12] = {0}; + struct i2c_client *client = this_client; + + struct i2c_msg msgs = + {.addr = client->addr, .flags = 0, .len = len+1, .buf = wrData,}; + + + if (!client || (!pdata)) + { + printk("%s NULL client!\n", __FUNCTION__); + return -EIO; + } + + wrData[0] = index; + strncpy(&wrData[1], pdata, len); + + if (i2c_transfer(client->adapter, &msgs, 1) < 0) { + printk( "%s: transfer failed.", __func__); + return -EIO; + } + + return 0; +} /* End of sensor_i2c_write */ + +int sensor_i2c_read(/*unsigned int addr,*/unsigned int index,char *pdata,int len) +{ + char rdData[2] = {0}; + struct i2c_client *client = this_client; + + struct i2c_msg msgs[2] = + { + {.addr = client->addr, .flags = 0|I2C_M_NOSTART, .len = 1, .buf = rdData,}, + {.addr = client->addr, .flags = I2C_M_RD, .len = len, .buf = pdata,}, + }; + rdData[0] = index; + if (!client || (!pdata)) + { + printk("%s NULL client!\n", __FUNCTION__); + return -EIO; + } + if (i2c_transfer(client->adapter, msgs, 2) < 0) { + printk( "%s: transfer failed.", __func__); + return -EIO; + } + + return 0;//rdData[0]; i2c read ok!! + +} /* End of sensor_i2c_read */ + +//****************add for mma8452q****************************** + +static int mma8452q_chip_init(void) +{ + char txData[1] = {0}; + + int result; + + txData[0] = 0x1; //active mode + result = sensor_i2c_write(/*MMA8452_ADDR,*/MMA8X5X_CTRL_REG1,txData,1); + if (result < 0) + goto out; + + txData[0] = MODE_2G; + result = sensor_i2c_write(/*MMA8452_ADDR,*/MMA8X5X_XYZ_DATA_CFG,txData,1); + if (result < 0) + goto out; + + txData[0] = 0x1; //wake mode + result = sensor_i2c_write(/*MMA8452_ADDR,*/MMA8X5X_SYSMOD,txData,1); + if (result < 0) + goto out; + + msleep(MODE_CHANGE_DELAY_MS); + return 0; +out: + + return result; + +} + +static unsigned int mma_sample2AMSR(unsigned int samp) +{ + int i = 0; + unsigned int amsr; + + if (samp >= 120) + { + return 0; + } + while (samp) + { + samp = samp >> 1; + i++; + } + amsr = 8 - i; + return amsr; +} + +static int mma_enable_disable(int enable) +{ + char buf[1]; + + // disable all interrupt of g-sensor + memset(buf, 0, sizeof(buf)); + if ((enable < 0) || (enable > 1)) + { + return -1; + } + buf[0] = 0; + sensor_i2c_write(/*MMA8452_ADDR,*/7,buf,1); + if (enable != 0) + { + buf[0] = (1 == l_sensorconfig.shake_enable) ? 0xF0:0x10; + } else { + buf[0] = 0; + } + sensor_i2c_write(/*MMA8452_ADDR,*/6,buf,1); + buf[0] = 0xf9; + sensor_i2c_write(/*MMA8452_ADDR,*/7,buf,1); + return 0; +} + +// To contol the g-sensor for UI +static int mmad_open(struct inode *inode, struct file *file) +{ + dbg("Open the g-sensor node...\n"); + return 0; +} + +static int mmad_release(struct inode *inode, struct file *file) +{ + dbg("Close the g-sensor node...\n"); + return 0; +} + +static long +mmad_ioctl(/*struct inode *inode,*/ struct file *file, unsigned int cmd, + unsigned long arg) +{ + void __user *argp = (void __user *)arg; + char rwbuf[5]; + short delay, enable; //amsr = -1; + unsigned int uval = 0; + + dbg("g-sensor ioctr...\n"); + memset(rwbuf, 0, sizeof(rwbuf)); + switch (cmd) { + case ECS_IOCTL_APP_SET_DELAY: + // set the rate of g-sensor + if (copy_from_user(&delay, argp, sizeof(short))) + { + printk(KERN_ALERT "Can't get set delay!!!\n"); + return -EFAULT; + } + klog("Get delay=%d\n", delay); + //klog("before change sensor sample:%d...\n", l_sensorconfig.sensor_samp); + if ((delay >=0) && (delay < 20)) + { + delay = 20; + } else if (delay > 200) + { + delay = 200; + } + l_sensorconfig.sensor_samp = 1000/delay; + + break; + case ECS_IOCTL_APP_SET_AFLAG: + // enable/disable sensor + if (copy_from_user(&enable, argp, sizeof(short))) + { + printk(KERN_ERR "Can't get enable flag!!!\n"); + return -EFAULT; + } + klog("enable=%d\n",enable); + if ((enable >=0) && (enable <=1)) + { + dbg("driver: disable/enable(%d) gsensor.\n", enable); + + l_sensorconfig.sensor_enable = enable; + + } else { + printk(KERN_ERR "Wrong enable argument in %s !!!\n", __FUNCTION__); + return -EINVAL; + } + break; + case WMT_IOCTL_SENSOR_GET_DRVID: + uval = MMA8452Q_DRVID; + if (copy_to_user((unsigned int*)arg, &uval, sizeof(unsigned int))) + { + return -EFAULT; + } + dbg("mma8452q_driver_id:%d\n",uval); + break; + case WMT_IOCTL_SENOR_GET_RESOLUTION: + + uval = (16<<8) | 4; // 16bit:4g 0xxx xx //mma8452Q + if (copy_to_user((unsigned int *)arg, &uval, sizeof(unsigned int))) + { + return -EFAULT; + } + printk("<<<<<<dev); + if (!l_sensorconfig.sensor_enable) + { + queue_delayed_work(l_sensorconfig.queue, &l_sensorconfig.work, msecs_to_jiffies(sample_rate_2_memsec(l_sensorconfig.sensor_samp))); + return; + } + mutex_lock(&sense_data_mutex); + + + i = sensor_i2c_read(/*MMA8452_ADDR,*/MMA8X5X_OUT_X_MSB,tmp, sizeof(tmp)); +#if 0 + for (i=0; i<6; i++) + sensor_i2c_read(/*MMA8452_ADDR,*/MMA8X5X_OUT_X_MSB+i,&tmp[i], 1); + i = 0; +#endif + + if (0 == i) + { + rxData[0] = ((tmp[0] << 8 )&0xff00 ) | (tmp[1] ); + rxData[1] = ((tmp[2] << 8) &0xff00 ) | (tmp[3] ); + rxData[2] = ((tmp[4] << 8) &0xff00 ) | (tmp[5] ); + x = rxData[l_sensorconfig.xyz_axis[0][0]]*l_sensorconfig.xyz_axis[0][1]; + y = rxData[l_sensorconfig.xyz_axis[1][0]]*l_sensorconfig.xyz_axis[1][1]; + z = rxData[l_sensorconfig.xyz_axis[2][0]]*l_sensorconfig.xyz_axis[2][1]; + #if 0 + x = (x*9800) >> 14; + y = (y*9800) >> 14; + z = (z*9800) >> 14; + #endif + //printk("x,y,z (%d, %d, %d) \n", rxData[0], rxData[1], rxData[2]); + //printk("x,y,z (%d, %d, %d) \n", x, y, z); + //printk("x 0x%x\n", tmp[0]); + input_report_abs(data->input_dev, ABS_X, x); + input_report_abs(data->input_dev, ABS_Y, y); + input_report_abs(data->input_dev, ABS_Z, z); + input_sync(data->input_dev); + } + + + mutex_unlock(&sense_data_mutex); + queue_delayed_work(l_sensorconfig.queue, &l_sensorconfig.work, msecs_to_jiffies(sample_rate_2_memsec(l_sensorconfig.sensor_samp))); +} + +static int sensor_writeproc( struct file *file, + const char *buffer, + unsigned long count, + void *data ) +{ + + int inputval = -1; + int enable, sample = -1; + char tembuf[8]; + unsigned int amsr = 0; + int test = 0; + + mutex_lock(&sense_data_mutex); + // disable int + //gsensor_int_ctrl(DISABLE); + memset(tembuf, 0, sizeof(tembuf)); + // get sensor level and set sensor level + if (sscanf(buffer, "level=%d\n", &l_sensorconfig.sensorlevel)) + { + } else if (sscanf(buffer, "shakenable=%d\n", &l_sensorconfig.shake_enable)) + { + + } + else if (sscanf(buffer, "isdbg=%d\n", &l_sensorconfig.isdbg)) + { + // only set the dbg flag + } else if (sscanf(buffer, "init=%d\n", &inputval)) + { + mma8452q_chip_init(); + dbg("Has reinit sensor !!!\n"); + } else if (sscanf(buffer, "samp=%d\n", &sample)) + { + if (sample > 0) + { + if (sample != l_sensorconfig.sensor_samp) + { + amsr = mma_sample2AMSR(sample); + SET_MMA_SAMPLE(tembuf, amsr); + klog("sample:%d ,amsr:%d \n", sample, amsr); + l_sensorconfig.sensor_samp = sample; + } + printk(KERN_ALERT "sensor samp=%d(amsr:%d) has been set.\n", sample, amsr); + } else { + printk(KERN_ALERT "Wrong sample argumnet of sensor.\n"); + } + } else if (sscanf(buffer, "enable=%d\n", &enable)) + { + if ((enable < 0) || (enable > 1)) + { + printk(KERN_ERR "The argument to enable/disable g-sensor should be 0 or 1 !!!\n"); + } else if (enable != l_sensorconfig.sensor_enable) + { + mma_enable_disable(enable); + l_sensorconfig.sensor_enable = enable; + } + } else if (sscanf(buffer, "sensor_test=%d\n", &test)) + { // for test begin + l_sensorconfig.test_pass = 0; + } else if (sscanf(buffer, "sensor_testend=%d\n", &test)) + { // Don nothing only to be compatible the before testing program + } + mutex_unlock(&sense_data_mutex); + return count; +} + +static int sensor_readproc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = 0; + + len = sprintf(page, + "test_pass=%d\nisdbg=%d\nrate=%d\nenable=%d\n", + l_sensorconfig.test_pass, + l_sensorconfig.isdbg, + l_sensorconfig.sensor_samp, + l_sensorconfig.sensor_enable + ); + return len; +} + + + +static int mma8452q_init_client(struct platform_device *pdev) +{ + struct mma8452q_config *data; +// int ret; + + data = dev_get_drvdata(&pdev->dev); + mutex_init(&sense_data_mutex); + /*Only for polling, not interrupt*/ + l_sensorconfig.sensor_proc = create_proc_entry(GSENSOR_PROC_NAME, 0666, NULL/*&proc_root*/); + if (l_sensorconfig.sensor_proc != NULL) + { + l_sensorconfig.sensor_proc->write_proc = sensor_writeproc; + l_sensorconfig.sensor_proc->read_proc = sensor_readproc; + } + + + return 0; + +//err: +// return ret; +} + +static struct file_operations mmad_fops = { + .owner = THIS_MODULE, + .open = mmad_open, + .release = mmad_release, + .unlocked_ioctl = mmad_ioctl, +}; + + +static struct miscdevice mmad_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "sensor_ctrl", + .fops = &mmad_fops, +}; + +static int mma8452q_probe(struct platform_device *pdev) +{ + int err; + + this_pdev = pdev; + l_sensorconfig.queue = create_singlethread_workqueue("sensor-intterupt-handle"); + INIT_DELAYED_WORK(&l_sensorconfig.work, mma_work_func); + + l_sensorconfig.input_dev = input_allocate_device(); + if (!l_sensorconfig.input_dev) { + err = -ENOMEM; + printk(KERN_ERR + "mma8452q_probe: Failed to allocate input device\n"); + goto exit_input_dev_alloc_failed; + } + l_sensorconfig.input_dev->evbit[0] = BIT(EV_ABS) | BIT_MASK(EV_KEY); + set_bit(KEY_NEXTSONG, l_sensorconfig.input_dev->keybit); + + /* x-axis acceleration */ + input_set_abs_params(l_sensorconfig.input_dev, ABS_X, -65532, 65532, 0, 0); + /* y-axis acceleration */ + input_set_abs_params(l_sensorconfig.input_dev, ABS_Y, -65532, 65532, 0, 0); + /* z-axis acceleration */ + input_set_abs_params(l_sensorconfig.input_dev, ABS_Z, -65532, 65532, 0, 0); + + l_sensorconfig.input_dev->name = "g-sensor"; + + err = input_register_device(l_sensorconfig.input_dev); + + if (err) { + printk(KERN_ERR + "mma8452q_probe: Unable to register input device: %s\n", + l_sensorconfig.input_dev->name); + goto exit_input_register_device_failed; + } + + err = misc_register(&mmad_device); + if (err) { + printk(KERN_ERR + "mma8452q_probe: mmad_device register failed\n"); + goto exit_misc_device_register_failed; + } + + dev_set_drvdata(&pdev->dev, &l_sensorconfig); + mma8452q_chip_init(); + mma8452q_init_client(pdev); + gsensor_sysfs_init(); + + // satrt the polling work + l_sensorconfig.sensor_samp = 10; + queue_delayed_work(l_sensorconfig.queue, &l_sensorconfig.work, msecs_to_jiffies(sample_rate_2_memsec(l_sensorconfig.sensor_samp))); + return 0; + +exit_misc_device_register_failed: +exit_input_register_device_failed: + input_free_device(l_sensorconfig.input_dev); + +exit_input_dev_alloc_failed: + + return err; +} + +static int mma8452q_remove(struct platform_device *pdev) +{ + if (NULL != l_sensorconfig.queue) + { + cancel_delayed_work_sync(&l_sensorconfig.work); + flush_workqueue(l_sensorconfig.queue); + destroy_workqueue(l_sensorconfig.queue); + l_sensorconfig.queue = NULL; + } + gsensor_sysfs_exit(); + misc_deregister(&mmad_device); + input_unregister_device(l_sensorconfig.input_dev); + if (l_sensorconfig.sensor_proc != NULL) + { + remove_proc_entry(GSENSOR_PROC_NAME, NULL); + l_sensorconfig.sensor_proc = NULL; + } + + return 0; +} + +static int mma8452q_suspend(struct platform_device *pdev, pm_message_t state) +{ + //gsensor_int_ctrl(DISABLE); + cancel_delayed_work_sync(&l_sensorconfig.work); + + dbg("...ok\n"); + //l_resumed = 2; + + return 0; +} + +static int mma8452q_resume(struct platform_device *pdev) +{ + + l_resumed = 1; + + mma8452q_chip_init(); + queue_delayed_work(l_sensorconfig.queue, \ + &l_sensorconfig.work, msecs_to_jiffies(sample_rate_2_memsec(l_sensorconfig.sensor_samp))); + dbg("...ok\n"); + + return 0; +} + +static void mma8452q_platform_release(struct device *device) +{ + return; +} + +static void mma8452q_shutdown(struct platform_device *pdev) +{ + flush_delayed_work_sync(&l_sensorconfig.work); + cancel_delayed_work_sync(&l_sensorconfig.work); + +} + +static struct platform_device mma8452q_device = { + .name = "mma8452q", + .id = 0, + .dev = { + .release = mma8452q_platform_release, + }, +}; + +static struct platform_driver mma8452q_driver = { + .probe = mma8452q_probe, + .remove = mma8452q_remove, + .suspend = mma8452q_suspend, + .resume = mma8452q_resume, + .shutdown = mma8452q_shutdown, + .driver = { + .name = "mma8452q", + }, +}; + +/* + * Brief: + * Get the configure of sensor from u-boot. + * Input: + * no use. + * Output: + * no use. + * Return: + * 0--success, -1--error. + * History: + * Created by HangYan on 2010-4-19 + * Author: + * Hang Yan in ShenZhen. + */ +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); +static int get_axisset(void* param) +{ + char varbuf[64]; + int n; + int varlen; + + memset(varbuf, 0, sizeof(varbuf)); + varlen = sizeof(varbuf); + if (wmt_getsyspara("wmt.io.mma8452qgsensor", varbuf, &varlen)) { + printk(KERN_DEBUG "Can't get gsensor config in u-boot!!!!\n"); + return -1; + } else { + n = sscanf(varbuf, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", + &l_sensorconfig.op, + &(l_sensorconfig.xyz_axis[0][0]), + &(l_sensorconfig.xyz_axis[0][1]), + &(l_sensorconfig.xyz_axis[1][0]), + &(l_sensorconfig.xyz_axis[1][1]), + &(l_sensorconfig.xyz_axis[2][0]), + &(l_sensorconfig.xyz_axis[2][1]), + &(l_sensorconfig.offset[0]), + &(l_sensorconfig.offset[1]), + &(l_sensorconfig.offset[2])); + if (n != 10) { + printk(KERN_ERR "gsensor format is error in u-boot!!!\n"); + return -1; + } + + printk("get the sensor config: %d:%d:%d:%d:%d:%d:%d:%d:%d:%d\n", + l_sensorconfig.op, + l_sensorconfig.xyz_axis[0][0], + l_sensorconfig.xyz_axis[0][1], + l_sensorconfig.xyz_axis[1][0], + l_sensorconfig.xyz_axis[1][1], + l_sensorconfig.xyz_axis[2][0], + l_sensorconfig.xyz_axis[2][1], + l_sensorconfig.offset[0], + l_sensorconfig.offset[1], + l_sensorconfig.offset[2] + ); + } + return 0; +} + +static int is_mma8452q(void) +{ + char rxData[2] = {0}; + int ret = 0; + int i = 0; + //char rdData[10] = {0}; + //char wbuf[6] = {0}; + //char rbuf[0x33] = {0}; + + ret = sensor_i2c_read(MMA8X5X_WHO_AM_I,rxData,1); + //printk("<<<<%s ret %d, val 0x%x\n", __FUNCTION__, ret, rxData[0]); + for(i = 0 ; i < sizeof(mma8x5x_chip_id)/sizeof(mma8x5x_chip_id[0]);i++) + if(rxData[0] == mma8x5x_chip_id[i]) + return 0; +#if 0 + struct i2c_client* client = gsensor_get_i2c_client(); + if (!client){ + printk("client NULL!\n"); + return -1; + } + + for (i=0; i<6; i++) + wbuf[i] = i+2; + //sensor_i2c_write(0x25, wbuf, 6); + //rbuf[0] = 0x11; + //sensor_i2c_read(0xb, rbuf, 0x1); + mma8452q_chip_init(); + for (i=0; i<0x12; i++) { + sensor_i2c_read(0xb+i, rbuf, 0x1); + printk("<<<<%s reg 0x%x val 0x%x\n", __FUNCTION__, 0xb+i, rbuf[0]); + } +#endif + return -1; +} + +static int __init mma8452q_init(void) +{ + int ret = 0; + + ret = get_axisset(NULL); + if (ret < 0) + { + printk("<<<<<%s user choose to no sensor chip!\n", __func__); + return ret; + } + + if (!(this_client = sensor_i2c_register_device(0, GSENSOR_I2C_ADDR, GSENSOR_I2C_NAME))) + { + printk(KERN_EMERG"Can't register gsensor i2c device!\n"); + return -1; + } + + if (is_mma8452q()) + { + printk(KERN_ERR "Can't find mma8452q!!\n"); + sensor_i2c_unregister_device(this_client); + return -1; + } + + + + printk(KERN_INFO "mma8452qfc g-sensor driver init\n"); + + spin_lock_init(&l_sensorconfig.spinlock); + + // Create device node + + l_dev_class = class_create(THIS_MODULE, GSENSOR_NAME); + //for S40 module to judge whether insmod is ok + if (IS_ERR(l_dev_class)){ + ret = PTR_ERR(l_dev_class); + printk(KERN_ERR "Can't class_create gsensor device !!\n"); + return ret; + } + l_clsdevice = device_create(l_dev_class, NULL, MKDEV(GSENSOR_MAJOR, 0), NULL, GSENSOR_NAME); + if (IS_ERR(l_clsdevice)){ + ret = PTR_ERR(l_clsdevice); + printk(KERN_ERR "Failed to create device %s !!!",GSENSOR_NAME); + return ret; + } + + if((ret = platform_device_register(&mma8452q_device))) + { + printk(KERN_ERR "%s Can't register mma8452q platform devcie!!!\n", __FUNCTION__); + return ret; + } + if ((ret = platform_driver_register(&mma8452q_driver)) != 0) + { + printk(KERN_ERR "%s Can't register mma8452q platform driver!!!\n", __FUNCTION__); + return ret; + } + + return 0; +} + +static void __exit mma8452q_exit(void) +{ + platform_driver_unregister(&mma8452q_driver); + platform_device_unregister(&mma8452q_device); + device_destroy(l_dev_class, MKDEV(GSENSOR_MAJOR, 0)); + + class_destroy(l_dev_class); + sensor_i2c_unregister_device(this_client); + +} + +module_init(mma8452q_init); +module_exit(mma8452q_exit); +MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/input/sensor/mma8452q_gsensor/mma8x5x.h b/ANDROID_3.4.5/drivers/input/sensor/mma8452q_gsensor/mma8x5x.h new file mode 100755 index 00000000..d8d386b2 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/mma8452q_gsensor/mma8x5x.h @@ -0,0 +1,107 @@ +/* + * Definitions for akm8976 compass chip. + */ +#ifndef AKM8976_H +#define AKM8976_H + +#include + +#define GSENSOR_I2C_NAME "mma8452q" +#define GSENSOR_I2C_ADDR 0x1c +/* Compass device dependent definition */ +#define AKECS_MODE_MEASURE 0x00 /* Starts measurement. Please use AKECS_MODE_MEASURE_SNG */ + /* or AKECS_MODE_MEASURE_SEQ instead of this. */ +#define AKECS_MODE_PFFD 0x01 /* Start pedometer and free fall detect. */ +#define AKECS_MODE_E2P_READ 0x02 /* E2P access mode (read). */ +#define AKECS_MODE_POWERDOWN 0x03 /* Power down mode */ + +#define AKECS_MODE_MEASURE_SNG 0x10 /* Starts single measurement */ +#define AKECS_MODE_MEASURE_SEQ 0x11 /* Starts sequential measurement */ + +/* Default register settings */ +#define CSPEC_AINT 0x01 /* Amplification for acceleration sensor */ +#define CSPEC_SNG_NUM 0x01 /* Single measurement mode */ +#define CSPEC_SEQ_NUM 0x02 /* Sequential measurement mode */ +#define CSPEC_SFRQ_32 0x00 /* Measurement frequency: 32Hz */ +#define CSPEC_SFRQ_64 0x01 /* Measurement frequency: 64Hz */ +#define CSPEC_MCS 0x07 /* Clock frequency */ +#define CSPEC_MKS 0x01 /* Clock type: CMOS level */ +#define CSPEC_INTEN 0x01 /* Interruption pin enable: Enable */ + +#define RBUFF_SIZE 31 /* Rx buffer size */ +#define MAX_CALI_SIZE 0x1000U /* calibration buffer size */ + +/* AK8976A register address */ +#define AKECS_REG_ST 0xC0 +#define AKECS_REG_TMPS 0xC1 +#define AKECS_REG_MS1 0xE0 +#define AKECS_REG_MS2 0xE1 +#define AKECS_REG_MS3 0xE2 + +#define AKMIO 0xA1 + +/* IOCTLs for AKM library */ +#define ECS_IOCTL_RESET _IO(AKMIO, 0x04) +#define ECS_IOCTL_INT_STATUS _IO(AKMIO, 0x05) +#define ECS_IOCTL_FFD_STATUS _IO(AKMIO, 0x06) +#define ECS_IOCTL_SET_MODE _IOW(AKMIO, 0x07, short) +#define ECS_IOCTL_GETDATA _IOR(AKMIO, 0x08, char[RBUFF_SIZE+1]) +#define ECS_IOCTL_GET_NUMFRQ _IOR(AKMIO, 0x09, char[2]) +#define ECS_IOCTL_SET_PERST _IO(AKMIO, 0x0A) +#define ECS_IOCTL_SET_G0RST _IO(AKMIO, 0x0B) +#define ECS_IOCTL_SET_YPR _IOW(AKMIO, 0x0C, short[12]) +#define ECS_IOCTL_GET_OPEN_STATUS _IOR(AKMIO, 0x0D, int) +#define ECS_IOCTL_GET_CLOSE_STATUS _IOR(AKMIO, 0x0E, int) +#define ECS_IOCTL_GET_CALI_DATA _IOR(AKMIO, 0x0F, char[MAX_CALI_SIZE]) +#define ECS_IOCTL_GET_DELAY _IOR(AKMIO, 0x30, short) + +/* IOCTLs for APPs */ +#define ECS_IOCTL_APP_SET_MODE _IOW(AKMIO, 0x10, short) +#define ECS_IOCTL_APP_SET_MFLAG _IOW(AKMIO, 0x11, short) +#define ECS_IOCTL_APP_GET_MFLAG _IOW(AKMIO, 0x12, short) +#define ECS_IOCTL_APP_GET_AFLAG _IOR(AKMIO, 0x14, short) +#define ECS_IOCTL_APP_SET_TFLAG _IOR(AKMIO, 0x15, short) +#define ECS_IOCTL_APP_GET_TFLAG _IOR(AKMIO, 0x16, short) +#define ECS_IOCTL_APP_RESET_PEDOMETER _IO(AKMIO, 0x17) +#define ECS_IOCTL_APP_GET_DELAY ECS_IOCTL_GET_DELAY +#define ECS_IOCTL_APP_SET_MVFLAG _IOW(AKMIO, 0x19, short) /* Set raw magnetic vector flag */ +#define ECS_IOCTL_APP_GET_MVFLAG _IOR(AKMIO, 0x1A, short) /* Get raw magnetic vector flag */ + +/* IOCTLs for pedometer */ +#define ECS_IOCTL_SET_STEP_CNT _IOW(AKMIO, 0x20, short) + +#define WMTGSENSOR_IOCTL_MAGIC 0x09 +#define ECS_IOCTL_APP_SET_AFLAG _IOW(WMTGSENSOR_IOCTL_MAGIC, 0x02, short) +#define ECS_IOCTL_APP_SET_DELAY _IOW(WMTGSENSOR_IOCTL_MAGIC, 0x03, short) +#define WMT_IOCTL_SENSOR_GET_DRVID _IOW(WMTGSENSOR_IOCTL_MAGIC, 0x04, unsigned int) + +//#define MMA8452_DRVID 6 + + + +/* Default GPIO setting */ +#define ECS_RST 146 /*MISC4, bit2 */ +#define ECS_CLK_ON 155 /*MISC5, bit3 */ +#define ECS_INTR 161 /*INT2, bit1 */ + +/* MISC */ +#define MMA8452_ADDR 0x1C +#define SENSOR_UI_MODE 0 +#define SENSOR_GRAVITYGAME_MODE 1 +#define UI_SAMPLE_RATE 0xFC +#define GSENSOR_PROC_NAME "gsensor_config" +#define sin30_1000 500 +#define cos30_1000 866 +#define DISABLE 0 +#define ENABLE 1 + +struct mma7660_platform_data { + int reset; + int clk_on; + int intr; +}; + +extern char *get_mma_cal_ram(void); + +#endif + diff --git a/ANDROID_3.4.5/drivers/input/sensor/mmc328x_msensor/Makefile b/ANDROID_3.4.5/drivers/input/sensor/mmc328x_msensor/Makefile new file mode 100755 index 00000000..bdf4598d --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/mmc328x_msensor/Makefile @@ -0,0 +1,4 @@ +s_wmt_msensor_mmc328x-objs += mmc328x.o +obj-m += s_wmt_msensor_mmc328x.o +s_wmt_generic_mecs-objs += mecs.o +obj-m += s_wmt_generic_mecs.o \ No newline at end of file diff --git a/ANDROID_3.4.5/drivers/input/sensor/mmc328x_msensor/mecs.c b/ANDROID_3.4.5/drivers/input/sensor/mmc328x_msensor/mecs.c new file mode 100755 index 00000000..335ad266 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/mmc328x_msensor/mecs.c @@ -0,0 +1,433 @@ +/* + * Copyright (C) 2010 MEMSIC, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include "mecs.h" + +#define DEBUG 0 + +#define ECS_DATA_DEV_NAME "ecompass_data" +#define ECS_CTRL_DEV_NAME "ecompass_ctrl" + +static int ecs_ctrl_open(struct inode *inode, struct file *file); +static int ecs_ctrl_release(struct inode *inode, struct file *file); +static int ecs_ctrl_ioctl(struct file *file, unsigned int cmd, unsigned long arg); + +static DECLARE_WAIT_QUEUE_HEAD(open_wq); + +static atomic_t open_count; +static atomic_t open_flag; +static atomic_t reserve_open_flag; + +static atomic_t a_flag; +static atomic_t m_flag; +static atomic_t o_flag; + +static short ecompass_delay = 0; + + +static struct input_dev *ecs_data_device; + +static struct file_operations ecs_ctrl_fops = { + .owner = THIS_MODULE, + .open = ecs_ctrl_open, + .release = ecs_ctrl_release, + .unlocked_ioctl = ecs_ctrl_ioctl, +}; + +static struct miscdevice ecs_ctrl_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = ECS_CTRL_DEV_NAME, + .fops = &ecs_ctrl_fops, +}; + +static int ecs_ctrl_open(struct inode *inode, struct file *file) +{ +#if 1 + atomic_set(&reserve_open_flag, 1); + atomic_set(&open_flag, 1); + atomic_set(&open_count, 1); + wake_up(&open_wq); + + return 0; +#else + int ret = -1; + + if (atomic_cmpxchg(&open_count, 0, 1) == 0) { + if (atomic_cmpxchg(&open_flag, 0, 1) == 0) { + atomic_set(&reserve_open_flag, 1); + wake_up(&open_wq); + ret = 0; + } + } + + return ret; +#endif +} + +static int ecs_ctrl_release(struct inode *inode, struct file *file) +{ + atomic_set(&reserve_open_flag, 0); + atomic_set(&open_flag, 0); + atomic_set(&open_count, 0); + wake_up(&open_wq); + + return 0; +} + +static int ecs_ctrl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + void __user *pa = (void __user *)arg; + short flag; + short delay; + int parms[4]; + int ypr[12]; + unsigned int uval = 0; + + switch (cmd) { + case ECOMPASS_IOC_SET_MODE: + break; + case ECOMPASS_IOC_SET_DELAY: + if (copy_from_user(&delay, pa, sizeof(delay))) + return -EFAULT; + ecompass_delay = delay; + break; + case ECOMPASS_IOC_GET_DELAY: + delay = ecompass_delay; + if (copy_to_user(pa, &delay, sizeof(delay))) + return -EFAULT; + break; + + case ECOMPASS_IOC_SET_AFLAG: + if (copy_from_user(&flag, pa, sizeof(flag))) + return -EFAULT; + if (flag < 0 || flag > 1) + return -EINVAL; + atomic_set(&a_flag, flag); + break; + case ECOMPASS_IOC_GET_AFLAG: + flag = atomic_read(&a_flag); + if (copy_to_user(pa, &flag, sizeof(flag))) + return -EFAULT; + break; + case ECOMPASS_IOC_SET_MFLAG: + if (copy_from_user(&flag, pa, sizeof(flag))) + return -EFAULT; + if (flag < 0 || flag > 1) + return -EINVAL; + atomic_set(&m_flag, flag); + break; + case ECOMPASS_IOC_GET_MFLAG: + flag = atomic_read(&m_flag); + if (copy_to_user(pa, &flag, sizeof(flag))) + return -EFAULT; + break; + case ECOMPASS_IOC_SET_OFLAG: + if (copy_from_user(&flag, pa, sizeof(flag))) + return -EFAULT; + if (flag < 0 || flag > 1) + return -EINVAL; + atomic_set(&o_flag, flag); + break; + case ECOMPASS_IOC_GET_OFLAG: + flag = atomic_read(&o_flag); + if (copy_to_user(pa, &flag, sizeof(flag))) + return -EFAULT; + break; + + case ECOMPASS_IOC_SET_APARMS: + if (copy_from_user(parms, pa, sizeof(parms))) + return -EFAULT; + /* acceleration x-axis */ + input_set_abs_params(ecs_data_device, ABS_X, + parms[0], parms[1], parms[2], parms[3]); + /* acceleration y-axis */ + input_set_abs_params(ecs_data_device, ABS_Y, + parms[0], parms[1], parms[2], parms[3]); + /* acceleration z-axis */ + input_set_abs_params(ecs_data_device, ABS_Z, + parms[0], parms[1], parms[2], parms[3]); + break; + case ECOMPASS_IOC_GET_APARMS: + break; + case ECOMPASS_IOC_SET_MPARMS: + if (copy_from_user(parms, pa, sizeof(parms))) + return -EFAULT; + /* magnetic raw x-axis */ + input_set_abs_params(ecs_data_device, ABS_HAT0X, + parms[0], parms[1], parms[2], parms[3]); + /* magnetic raw y-axis */ + input_set_abs_params(ecs_data_device, ABS_HAT0Y, + parms[0], parms[1], parms[2], parms[3]); + /* magnetic raw z-axis */ + input_set_abs_params(ecs_data_device, ABS_BRAKE, + parms[0], parms[1], parms[2], parms[3]); + break; + case ECOMPASS_IOC_GET_MPARMS: + break; + case ECOMPASS_IOC_SET_OPARMS_YAW: + if (copy_from_user(parms, pa, sizeof(parms))) + return -EFAULT; + /* orientation yaw */ + input_set_abs_params(ecs_data_device, ABS_RX, + parms[0], parms[1], parms[2], parms[3]); + break; + case ECOMPASS_IOC_GET_OPARMS_YAW: + break; + case ECOMPASS_IOC_SET_OPARMS_PITCH: + if (copy_from_user(parms, pa, sizeof(parms))) + return -EFAULT; + /* orientation pitch */ + input_set_abs_params(ecs_data_device, ABS_RY, + parms[0], parms[1], parms[2], parms[3]); + break; + case ECOMPASS_IOC_GET_OPARMS_PITCH: + break; + case ECOMPASS_IOC_SET_OPARMS_ROLL: + if (copy_from_user(parms, pa, sizeof(parms))) + return -EFAULT; + /* orientation roll */ + input_set_abs_params(ecs_data_device, ABS_RZ, + parms[0], parms[1], parms[2], parms[3]); + break; + case ECOMPASS_IOC_GET_OPARMS_ROLL: + break; + + case ECOMPASS_IOC_SET_YPR: + if (copy_from_user(ypr, pa, sizeof(ypr))) + return -EFAULT; + /* Report acceleration sensor information */ + if (atomic_read(&a_flag)) { + input_report_abs(ecs_data_device, ABS_X, ypr[0]); + input_report_abs(ecs_data_device, ABS_Y, ypr[1]); + input_report_abs(ecs_data_device, ABS_Z, ypr[2]); + input_report_abs(ecs_data_device, ABS_WHEEL, ypr[3]); + } + + /* Report magnetic sensor information */ + if (atomic_read(&m_flag)) { + input_report_abs(ecs_data_device, ABS_HAT0X, ypr[4]); + input_report_abs(ecs_data_device, ABS_HAT0Y, ypr[5]); + input_report_abs(ecs_data_device, ABS_BRAKE, ypr[6]); + input_report_abs(ecs_data_device, ABS_GAS, ypr[7]); + } + + /* Report orientation information */ + if (atomic_read(&o_flag)) { + input_report_abs(ecs_data_device, ABS_RX, ypr[8]); + input_report_abs(ecs_data_device, ABS_RY, ypr[9]); + input_report_abs(ecs_data_device, ABS_RZ, ypr[10]); + input_report_abs(ecs_data_device, ABS_RUDDER, ypr[11]); + } + + input_sync(ecs_data_device); + break; + + case WMT_IOCTL_SENSOR_GET_DRVID: + uval = 0; + if (copy_to_user((unsigned int*)arg, &uval, sizeof(unsigned int))) + { + return -EFAULT; + } + + default: + break; + } + + return 0; +} + +static ssize_t ecs_ctrl_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + ssize_t ret = 0; + + sprintf(buf, "ecompass_ctrl");//!!! + ret = strlen(buf) + 1; + + return ret; +} + +static DEVICE_ATTR(ecs_ctrl, S_IRUGO, ecs_ctrl_show, NULL); + +//********************** +static struct input_dev *g_input; +struct timer_list mytimer; +static void rep_pwer(long var) +{ + static int i = 0; + i++; +#if 0 + input_report_abs(g_input, ABS_X,i); + input_report_abs(g_input, ABS_Y, i); + input_report_abs(g_input, ABS_Z, i); + //input_report_abs(ecs_data_device, ABS_GAS, 2); + input_sync(g_input); +#endif + + input_report_abs(ecs_data_device, ABS_HAT0X,i); + input_report_abs(ecs_data_device, ABS_HAT0Y, i); + input_report_abs(ecs_data_device, ABS_BRAKE, i); + input_report_abs(ecs_data_device, ABS_GAS, 2); + input_sync(ecs_data_device); + //printk("<<<evbit); + /* Accelerometer [-78.5, 78.5]m/s2 in Q16 */ + input_set_abs_params(g_input, ABS_HAT0X, -5144576, 5144576, 0, 0); + input_set_abs_params(g_input, ABS_HAT0Y, -5144576, 5144576, 0, 0); + input_set_abs_params(g_input, ABS_BRAKE, -5144576, 5144576, 0, 0); + + /* Set InputDevice Name */ + g_input->name = "ecompass_data"; + + /* Register */ + //err = input_register_device(g_input); + //*****************************************2013-4-13 + + ecs_data_device = input_allocate_device(); + if (!ecs_data_device) { + res = -ENOMEM; + pr_err("%s: failed to allocate input device\n", __FUNCTION__); + goto out; + } + + set_bit(EV_ABS, ecs_data_device->evbit); + + /* 32768 == 1g, range -4g ~ +4g */ + /* acceleration x-axis */ + input_set_abs_params(ecs_data_device, ABS_X, + -32768*4, 32768*4, 0, 0); + /* acceleration y-axis */ + input_set_abs_params(ecs_data_device, ABS_Y, + -32768*4, 32768*4, 0, 0); + /* acceleration z-axis */ + input_set_abs_params(ecs_data_device, ABS_Z, + -32768*4, 32768*4, 0, 0); + /* acceleration status, 0 ~ 3 */ + input_set_abs_params(ecs_data_device, ABS_WHEEL, + 0, 100, 0, 0); + + /* 32768 == 1gauss, range -4gauss ~ +4gauss */ + /* magnetic raw x-axis */ + input_set_abs_params(ecs_data_device, ABS_HAT0X, + -32768*4, 32768*4, 0, 0); + /* magnetic raw y-axis */ + input_set_abs_params(ecs_data_device, ABS_HAT0Y, + -32768*4, 32768*4, 0, 0); + /* magnetic raw z-axis */ + input_set_abs_params(ecs_data_device, ABS_BRAKE, + -32768*4, 32768*4, 0, 0); + /* magnetic raw status, 0 ~ 3 */ + input_set_abs_params(ecs_data_device, ABS_GAS, + 0, 100, 0, 0); + + /* 65536 == 360degree */ + /* orientation yaw, 0 ~ 360 */ + input_set_abs_params(ecs_data_device, ABS_RX, + 0, 65536, 0, 0); + /* orientation pitch, -180 ~ 180 */ + input_set_abs_params(ecs_data_device, ABS_RY, + -65536/2, 65536/2, 0, 0); + /* orientation roll, -90 ~ 90 */ + input_set_abs_params(ecs_data_device, ABS_RZ, + -65536/4, 65536/4, 0, 0); + /* orientation status, 0 ~ 3 */ + input_set_abs_params(ecs_data_device, ABS_RUDDER, + 0, 100, 0, 0); + + ecs_data_device->name = ECS_DATA_DEV_NAME; +#if 1 + res = input_register_device(ecs_data_device); + if (res) { + pr_err("%s: unable to register input device: %s\n", + __FUNCTION__, ecs_data_device->name); + goto out_free_input; + } +#endif + + res = misc_register(&ecs_ctrl_device); + if (res) { + pr_err("%s: ecs_ctrl_device register failed\n", __FUNCTION__); + goto out_free_input; + } + res = device_create_file(ecs_ctrl_device.this_device, &dev_attr_ecs_ctrl); + if (res) { + pr_err("%s: device_create_file failed\n", __FUNCTION__); + goto out_deregister_misc; + } + + return 0; + +out_deregister_misc: + misc_deregister(&ecs_ctrl_device); +out_free_input: + input_free_device(ecs_data_device); +out: + return res; +} + +static void __exit ecompass_exit(void) +{ + pr_info("ecompass driver: exit\n"); + device_remove_file(ecs_ctrl_device.this_device, &dev_attr_ecs_ctrl); + misc_deregister(&ecs_ctrl_device); + input_free_device(ecs_data_device); +} + +module_init(ecompass_init); +module_exit(ecompass_exit); + +MODULE_DESCRIPTION("MEMSIC eCompass Driver"); +MODULE_LICENSE("GPL"); + diff --git a/ANDROID_3.4.5/drivers/input/sensor/mmc328x_msensor/mecs.h b/ANDROID_3.4.5/drivers/input/sensor/mmc328x_msensor/mecs.h new file mode 100755 index 00000000..c328e585 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/mmc328x_msensor/mecs.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2010 MEMSIC, Inc. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* + * Definitions for ECOMPASS magnetic sensor chip. + */ +#ifndef __ECOMPASS_H__ +#define __ECOMPASS_H__ + +#include + +/* Use 'e' as magic number */ +#define ECOMPASS_IOM 'e' + +/* IOCTLs for ECOMPASS device */ +#define ECOMPASS_IOC_SET_MODE _IOW(ECOMPASS_IOM, 0x00, short) +#define ECOMPASS_IOC_SET_DELAY _IOW(ECOMPASS_IOM, 0x01, short) +#define ECOMPASS_IOC_GET_DELAY _IOR(ECOMPASS_IOM, 0x02, short) + +#define ECOMPASS_IOC_SET_AFLAG _IOW(ECOMPASS_IOM, 0x10, short) +#define ECOMPASS_IOC_GET_AFLAG _IOR(ECOMPASS_IOM, 0x11, short) +#define ECOMPASS_IOC_SET_MFLAG _IOW(ECOMPASS_IOM, 0x12, short) +#define ECOMPASS_IOC_GET_MFLAG _IOR(ECOMPASS_IOM, 0x13, short) +#define ECOMPASS_IOC_SET_OFLAG _IOW(ECOMPASS_IOM, 0x14, short) +#define ECOMPASS_IOC_GET_OFLAG _IOR(ECOMPASS_IOM, 0x15, short) + +#define ECOMPASS_IOC_SET_APARMS _IOW(ECOMPASS_IOM, 0x20, int[4]) +#define ECOMPASS_IOC_GET_APARMS _IOR(ECOMPASS_IOM, 0x21, int[4]) +#define ECOMPASS_IOC_SET_MPARMS _IOW(ECOMPASS_IOM, 0x22, int[4]) +#define ECOMPASS_IOC_GET_MPARMS _IOR(ECOMPASS_IOM, 0x23, int[4]) +#define ECOMPASS_IOC_SET_OPARMS_YAW _IOW(ECOMPASS_IOM, 0x24, int[4]) +#define ECOMPASS_IOC_GET_OPARMS_YAW _IOR(ECOMPASS_IOM, 0x25, int[4]) +#define ECOMPASS_IOC_SET_OPARMS_PITCH _IOW(ECOMPASS_IOM, 0x26, int[4]) +#define ECOMPASS_IOC_GET_OPARMS_PITCH _IOR(ECOMPASS_IOM, 0x27, int[4]) +#define ECOMPASS_IOC_SET_OPARMS_ROLL _IOW(ECOMPASS_IOM, 0x28, int[4]) +#define ECOMPASS_IOC_GET_OPARMS_ROLL _IOR(ECOMPASS_IOM, 0x29, int[4]) + +#define ECOMPASS_IOC_SET_YPR _IOW(ECOMPASS_IOM, 0x30, int[12]) + +#define WMTGSENSOR_IOCTL_MAGIC 0x09 +#define WMT_IOCTL_SENSOR_GET_DRVID _IOW(WMTGSENSOR_IOCTL_MAGIC, 0x04, unsigned int) +#endif /* __ECOMPASS_H__ */ + diff --git a/ANDROID_3.4.5/drivers/input/sensor/mmc328x_msensor/mmc328x.c b/ANDROID_3.4.5/drivers/input/sensor/mmc328x_msensor/mmc328x.c new file mode 100755 index 00000000..4148b5f1 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/mmc328x_msensor/mmc328x.c @@ -0,0 +1,505 @@ +/* + * Copyright (C) 2011 MEMSIC, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include "mmc328x.h" +#define DEBUG 0 +#define MAX_FAILURE_COUNT 3 +#define READMD 0 + +#define MMC328X_DELAY_TM 10 /* ms */ +#define MMC328X_DELAY_RM 10 /* ms */ +#define MMC328X_DELAY_STDN 1 /* ms */ +#define MMC328X_DELAY_RRM 1 /* ms */ + +#define MMC328X_RETRY_COUNT 3 +#define MMC328X_RRM_INTV 100 + + +//******************************* move from memsicd 2013-4-26 +#define MMC328X_OFFSET_X 4096 +#define MMC328X_OFFSET_Y 4096 +#define MMC328X_OFFSET_Z 4096 +//****************************************** + +#define MMC328X_DEV_NAME "mmc328x" +#define CONFIG_SENSORS_MMC328xMA_MAG //add rambo 2013-4-20 +struct i2c_client *g_client; + +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); +static u32 read_idx = 0; + +static struct i2c_client *this_client; + +static struct wmt_msensor_data l_sensorconfig = { + .op = 0, + .int_gpio = 3, + .samp = 5, + .xyz_axis = { + {ABS_X, -1}, + {ABS_Y, 1}, + {ABS_Z, -1}, + }, + .sensor_proc = NULL, + .isdbg = 0, + .sensor_samp = 10, // 1 sample/second + .sensor_enable = 1, // enable sensor + .test_pass = 0, // for test program + .offset={0,0,0}, +}; + +static int get_axisset(void) +{ + char varbuf[64]; + int n; + int varlen; + + memset(varbuf, 0, sizeof(varbuf)); + varlen = sizeof(varbuf); + if (wmt_getsyspara("wmt.io.msensor328x", varbuf, &varlen)) { + printk("Can't get gsensor config in u-boot!!!!\n"); + //return -1; + } else { + n = sscanf(varbuf, "%d:%d:%d:%d:%d:%d", + + &(l_sensorconfig.xyz_axis[0][0]), + &(l_sensorconfig.xyz_axis[0][1]), + &(l_sensorconfig.xyz_axis[1][0]), + &(l_sensorconfig.xyz_axis[1][1]), + &(l_sensorconfig.xyz_axis[2][0]), + &(l_sensorconfig.xyz_axis[2][1]) + + ); + if (n != 6) { + printk("gsensor format is error in u-boot!!!\n"); + return -1; + } + l_sensorconfig.sensor_samp = l_sensorconfig.samp; + + printk("get the sensor config: %d:%d:%d:%d:%d:%d\n", + + l_sensorconfig.xyz_axis[0][0], + l_sensorconfig.xyz_axis[0][1], + l_sensorconfig.xyz_axis[1][0], + l_sensorconfig.xyz_axis[1][1], + l_sensorconfig.xyz_axis[2][0], + l_sensorconfig.xyz_axis[2][1] + ); + } + return 0; +} + + +static int mmc328x_i2c_rx_data(char *buf, int len) +{ + uint8_t i; + struct i2c_msg msgs[] = { + { + .addr = this_client->addr, + .flags = 0, + .len = 1, + .buf = buf, + }, + { + .addr = this_client->addr, + .flags = I2C_M_RD, + .len = len, + .buf = buf, + } + }; + + for (i = 0; i < MMC328X_RETRY_COUNT; i++) { + if (i2c_transfer(this_client->adapter, msgs, 2) >= 0) { + break; + } + mdelay(10); + } + + if (i >= MMC328X_RETRY_COUNT) { + pr_err("%s: retry over %d\n", __FUNCTION__, MMC328X_RETRY_COUNT); + return -EIO; + } + + return 0; +} + +static int mmc328x_i2c_tx_data(char *buf, int len) +{ + uint8_t i; + struct i2c_msg msg[] = { + { + .addr = this_client->addr, + .flags = 0, + .len = len, + .buf = buf, + } + }; + + for (i = 0; i < MMC328X_RETRY_COUNT; i++) { + if (i2c_transfer(this_client->adapter, msg, 1) >= 0) { + break; + } + mdelay(10); + } + + if (i >= MMC328X_RETRY_COUNT) { + pr_err("%s: retry over %d\n", __FUNCTION__, MMC328X_RETRY_COUNT); + return -EIO; + } + return 0; +} + +static int mmc328x_open(struct inode *inode, struct file *file) +{ + return nonseekable_open(inode, file); +} + +static int mmc328x_release(struct inode *inode, struct file *file) +{ + return 0; +} + +static int mmc328x_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + void __user *pa = (void __user *)arg; + unsigned char data[16] = {0}; + int vec[3] = {0}; + int tmp[3] = {0}; + + int MD_times = 0; + + switch (cmd) { + case MMC328X_IOC_TM: + data[0] = MMC328X_REG_CTRL; + data[1] = MMC328X_CTRL_TM; + if (mmc328x_i2c_tx_data(data, 2) < 0) { + return -EFAULT; + } + /* wait TM done for coming data read */ + msleep(MMC328X_DELAY_TM); + break; + case MMC328X_IOC_RM: + data[0] = MMC328X_REG_CTRL; + data[1] = MMC328X_CTRL_RM; + if (mmc328x_i2c_tx_data(data, 2) < 0) { + return -EFAULT; + } + /* wait external capacitor charging done for next SET*/ + msleep(MMC328X_DELAY_RM); + break; + case MMC328X_IOC_RRM: + data[0] = MMC328X_REG_CTRL; + data[1] = MMC328X_CTRL_RRM; + if (mmc328x_i2c_tx_data(data, 2) < 0) { + return -EFAULT; + } + /* wait external capacitor charging done for next RRM */ + msleep(MMC328X_DELAY_RM); + break; + case MMC328X_IOC_READ: + data[0] = MMC328X_REG_DATA; + if (mmc328x_i2c_rx_data(data, 6) < 0) { + return -EFAULT; + } + tmp[0] = data[1] << 8 | data[0]; + tmp[1] = data[3] << 8 | data[2]; + tmp[2] = data[5] << 8 | data[4]; + tmp[2] = 8192 - tmp[2] ; + //add 2013-4-26 + tmp[0] -= MMC328X_OFFSET_X; + tmp[1] -= MMC328X_OFFSET_Y; + tmp[2] -= MMC328X_OFFSET_Z; + //add end + vec[0] = tmp[l_sensorconfig.xyz_axis[0][0]]*l_sensorconfig.xyz_axis[0][1]; + + vec[1] = tmp[l_sensorconfig.xyz_axis[1][0]]*l_sensorconfig.xyz_axis[1][1]; + + vec[2] = tmp[l_sensorconfig.xyz_axis[2][0]]*l_sensorconfig.xyz_axis[2][1]; + + #if DEBUG + printk("[X - %04x] [Y - %04x] [Z - %04x]\n", + vec[0], vec[1], vec[2]); + #endif + if (copy_to_user(pa, vec, sizeof(vec))) { + return -EFAULT; + } + break; + case MMC328X_IOC_READXYZ: + /* do RM every MMC328X_RRM_INTV times read */ + if (!(read_idx % MMC328X_RRM_INTV)) { +#ifdef CONFIG_SENSORS_MMC328xMA_MAG + data[0] = MMC328X_REG_CTRL; + data[1] = MMC328X_CTRL_RRM; + mmc328x_i2c_tx_data(data, 2); + msleep(MMC328X_DELAY_RRM); +#endif + /* RM */ + data[0] = MMC328X_REG_CTRL; + data[1] = MMC328X_CTRL_RM; + /* not check return value here, assume it always OK */ + mmc328x_i2c_tx_data(data, 2); + /* wait external capacitor charging done for next RM */ + msleep(MMC328X_DELAY_RM); + } + read_idx++; + + /* send TM cmd before read */ + data[0] = MMC328X_REG_CTRL; + data[1] = MMC328X_CTRL_TM; + /* not check return value here, assume it always OK */ + mmc328x_i2c_tx_data(data, 2); + /* wait TM done for coming data read */ + msleep(MMC328X_DELAY_TM); +#if READMD + /* Read MD */ + data[0] = MMC328X_REG_DS; + if (mmc328x_i2c_rx_data(data, 1) < 0) { + return -EFAULT; + } + while (!(data[0] & 0x01)) { + msleep(1); + /* Read MD again*/ + data[0] = MMC328X_REG_DS; + if (mmc328x_i2c_rx_data(data, 1) < 0) { + return -EFAULT; + } + + if (data[0] & 0x01) break; + MD_times++; + if (MD_times > 2) { + #if DEBUG + printk("TM not work!!"); + #endif + return -EFAULT; + } + } +#endif + /* read xyz raw data */ + data[0] = MMC328X_REG_DATA; + if (mmc328x_i2c_rx_data(data, 6) < 0) { + return -EFAULT; + } + tmp[0] = data[1] << 8 | data[0]; + tmp[1] = data[3] << 8 | data[2]; + tmp[2] = data[5] << 8 | data[4]; + tmp[2] = 8192 - tmp[2]; + //add 2013-4-26 + tmp[0] -= MMC328X_OFFSET_X; + tmp[1] -= MMC328X_OFFSET_Y; + tmp[2] -= MMC328X_OFFSET_Z; + //add + vec[0] = tmp[l_sensorconfig.xyz_axis[0][0]]*l_sensorconfig.xyz_axis[0][1]; + + vec[1] = tmp[l_sensorconfig.xyz_axis[1][0]]*l_sensorconfig.xyz_axis[1][1]; + + vec[2] = tmp[l_sensorconfig.xyz_axis[2][0]]*l_sensorconfig.xyz_axis[2][1]; + + + + #if DEBUG + printk("[X - %04x] [Y - %04x] [Z - %04x]\n", + vec[0], vec[1], vec[2]); + #endif + if (copy_to_user(pa, vec, sizeof(vec))) { + return -EFAULT; + } + + break; + default: + break; + } + + return 0; +} + +static ssize_t mmc328x_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + ssize_t ret = 0; + + sprintf(buf, "MMC328X");//!!! + ret = strlen(buf) + 1; + + return ret; +} + +static DEVICE_ATTR(mmc328x, S_IRUGO, mmc328x_show, NULL); + +static struct file_operations mmc328x_fops = { + .owner = THIS_MODULE, + .open = mmc328x_open, + .release = mmc328x_release, + .unlocked_ioctl = mmc328x_ioctl, +}; + +static struct miscdevice mmc328x_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = MMC328X_DEV_NAME, + .fops = &mmc328x_fops, +}; + +static int mmc328x_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + unsigned char data[16] = {0}; + int res = 0; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + pr_err("%s: functionality check failed\n", __FUNCTION__); + res = -ENODEV; + goto out; + } + this_client = client; + + res = misc_register(&mmc328x_device);// + if (res) { + pr_err("%s: mmc328x_device register failed\n", __FUNCTION__); + goto out; + } + res = device_create_file(&client->dev, &dev_attr_mmc328x);// + if (res) { + pr_err("%s: device_create_file failed\n", __FUNCTION__); + goto out_deregister; + } + + /* send RM/RRM cmd to mag sensor first of all */ +#ifdef CONFIG_SENSORS_MMC328xMA_MAG + data[0] = MMC328X_REG_CTRL; + data[1] = MMC328X_CTRL_RRM; + if (mmc328x_i2c_tx_data(data, 2) < 0) { + } + msleep(MMC328X_DELAY_RRM); + data[0] = MMC328X_REG_CTRL; + data[1] = MMC328X_CTRL_TM; + if (mmc328x_i2c_tx_data(data, 2) < 0) { + } + msleep(5*MMC328X_DELAY_TM); +#endif + + data[0] = MMC328X_REG_CTRL; + data[1] = MMC328X_CTRL_RM; + if (mmc328x_i2c_tx_data(data, 2) < 0) { + /* assume RM always success */ + } +#ifndef CONFIG_SENSORS_MMC328xMA_MAG + /* wait external capacitor charging done for next RM */ + msleep(MMC328X_DELAY_RM); +#else + msleep(10*MMC328X_DELAY_RM); + data[0] = MMC328X_REG_CTRL; + data[1] = MMC328X_CTRL_TM; + if (mmc328x_i2c_tx_data(data, 2) < 0) { + } +#endif + + return 0; + +out_deregister: + misc_deregister(&mmc328x_device); +out: + return res; +} + +static int mmc328x_remove(struct i2c_client *client) +{ + device_remove_file(&client->dev, &dev_attr_mmc328x); + misc_deregister(&mmc328x_device); + + return 0; +} + +static const struct i2c_device_id mmc328x_id[] = { + { MMC328X_I2C_NAME, 0 }, + { } +}; + +static struct i2c_driver mmc328x_driver = { + .probe = mmc328x_probe, + .remove = mmc328x_remove, + .id_table = mmc328x_id, + .driver = { + .owner = THIS_MODULE, + .name = MMC328X_I2C_NAME, + }, +}; + +//****************************add by rambo to create i2c client 2013-4-18 +static struct i2c_board_info mmc328x_board_info = +{ + .type = MMC328X_I2C_NAME, + .addr = MMC328X_I2C_ADDR, +}; + +//****************************************** + +static int __init mmc328x_init(void) +{ + int ret; + pr_info("mmc328x driver: init\n"); + + ret = get_axisset(); + struct i2c_adapter *adapter; + adapter = i2c_get_adapter(0); + if (!adapter) + { + printk("<<<<<%s i2c get adapter fail!\n", __FUNCTION__); + return -1; + } + g_client = i2c_new_device(adapter, &mmc328x_board_info); + if (!g_client) + { + printk("<<<<%s i2c new device fail!\n", __FUNCTION__); + i2c_put_adapter(adapter); + return -1; + } + i2c_put_adapter(adapter); + + return i2c_add_driver(&mmc328x_driver); +} + +static void __exit mmc328x_exit(void) +{ + if (g_client != NULL) + { + i2c_unregister_device(g_client); + } + pr_info("mmc328x driver: exit\n"); + i2c_del_driver(&mmc328x_driver); +} + +module_init(mmc328x_init); +module_exit(mmc328x_exit); + +MODULE_DESCRIPTION("MEMSIC MMC328X Magnetic Sensor Driver"); +MODULE_LICENSE("GPL"); + diff --git a/ANDROID_3.4.5/drivers/input/sensor/mmc328x_msensor/mmc328x.h b/ANDROID_3.4.5/drivers/input/sensor/mmc328x_msensor/mmc328x.h new file mode 100755 index 00000000..f272ea1d --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/mmc328x_msensor/mmc328x.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2010 MEMSIC, Inc. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* + * Definitions for mmc328x magnetic sensor chip. + */ +#ifndef __MMC328X_H__ +#define __MMC328X_H__ + +#include + +#define MMC328X_I2C_NAME "mmc328x" + +/* + * This address comes must match the part# on your target. + * Address to the sensor part# support as following list: + * MMC3280MS - 0110000b + * MMC3281MS - 0110001b + * MMC3282MS - 0110010b + * MMC3283MS - 0110011b + * MMC3284MS - 0110100b + * MMC3285MS - 0110101b + * MMC3286MS - 0110110b + * MMC3287MS - 0110111b + * Please refer to sensor datasheet for detail. + */ + struct wmt_msensor_data{ + // for control + int int_gpio; //0-3 + int op; + int samp; + int xyz_axis[3][2]; // (axis,direction) + struct proc_dir_entry* sensor_proc; + struct input_dev *input_dev; + //struct work_struct work; + struct delayed_work work; // for polling + struct workqueue_struct *queue; + int isdbg; + int sensor_samp; // + int sensor_enable; // 0 --> disable sensor, 1 --> enable sensor + int test_pass; + int offset[3]; + struct i2c_client *client; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend earlysuspend; +#endif + +}; +#define MMC328X_I2C_ADDR 0x30 + +/* MMC328X register address */ +#define MMC328X_REG_CTRL 0x07 +#define MMC328X_REG_DATA 0x00 +#define MMC328X_REG_DS 0x06 + +/* MMC328X control bit */ +#define MMC328X_CTRL_TM 0x01 +#define MMC328X_CTRL_RM 0x20 +#define MMC328X_CTRL_RRM 0x40 +#define MMC328X_CTRL_NOBOOST 0x10 + +/* Use 'm' as magic number */ +#define MMC328X_IOM 'm' + +/* IOCTLs for MMC328X device */ +#define MMC328X_IOC_TM _IO (MMC328X_IOM, 0x00) +#define MMC328X_IOC_RM _IO (MMC328X_IOM, 0x01) +#define MMC328X_IOC_READ _IOR(MMC328X_IOM, 0x02, int[3]) +#define MMC328X_IOC_READXYZ _IOR(MMC328X_IOM, 0x03, int[3]) +#define MMC328X_IOC_RRM _IO (MMC328X_IOM, 0x04) +#define MMC328X_IOC_NOBOOST _IO (MMC328X_IOM, 0x05) + +#endif /* __MMC328X_H__ */ + diff --git a/ANDROID_3.4.5/drivers/input/sensor/mxc622x_gsensor/Makefile b/ANDROID_3.4.5/drivers/input/sensor/mxc622x_gsensor/Makefile new file mode 100755 index 00000000..16baea79 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/mxc622x_gsensor/Makefile @@ -0,0 +1,34 @@ +KERNELDIR=../../../../ +#KERNELDIR=/home/hangyan/android8850/kernel/ANDROID_3.0.8 +CROSS = arm_1103_le- +CC= $(CROSS)gcc +LD= $(CROSS)ld +STRIP = $(CROSS)strip + +DEBUG = n + +# Add your debugging flag (or not) to EXTRA_CFLAGS +ifeq ($(DEBUG),y) +# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines +DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines + +else + DEBFLAGS = -O2 -Wall +endif + +EXTRA_CFLAGS += $(DEBFLAGS) + + +MY_MODULE_NAME=s_wmt_gsensor_mxc622x + +obj-m := $(MY_MODULE_NAME).o +$(MY_MODULE_NAME)-objs := mxc622x.o + +default: + $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules + $(STRIP) --strip-debug $(MY_MODULE_NAME).ko + rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions + +clean: + rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers + diff --git a/ANDROID_3.4.5/drivers/input/sensor/mxc622x_gsensor/mxc622x.c b/ANDROID_3.4.5/drivers/input/sensor/mxc622x_gsensor/mxc622x.c new file mode 100755 index 00000000..9c94b6ed --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/mxc622x_gsensor/mxc622x.c @@ -0,0 +1,1151 @@ +/******************** (C) COPYRIGHT 2010 STMicroelectronics ******************** + * + * File Name : mxc622x_acc.c + * Description : MXC622X accelerometer sensor API + * + ******************************************************************************* + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THE PRESENT SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, FOR THE SOLE + * PURPOSE TO SUPPORT YOUR APPLICATION DEVELOPMENT. + * AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, + * INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE + * CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING + * INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + * THIS SOFTWARE IS SPECIFICALLY DESIGNED FOR EXCLUSIVE USE WITH ST PARTS. + * + + ******************************************************************************/ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include + +#include "mxc622x.h" +#include "../sensor.h" +#ifdef CONFIG_ARCH_SC8810 +#include +#endif + +#define G_MAX 16000 /** Maximum polled-device-reported g value */ +#define WHOAMI_MXC622X_ACC 0x25 /* Expctd content for WAI */ + +/* CONTROL REGISTERS */ +#define WHO_AM_I 0x08 /* WhoAmI register */ + +#define FUZZ 32 +#define FLAT 32 +#define I2C_RETRY_DELAY 5 +#define I2C_RETRIES 5 +#define I2C_AUTO_INCREMENT 0x80 + +/* RESUME STATE INDICES */ + +#define RESUME_ENTRIES 20 +#define DEVICE_INFO "Memsic, MXC622X" +#define DEVICE_INFO_LEN 32 + +/* end RESUME STATE INDICES */ + +#define DEBUG +//#define MXC622X_DEBUG + +#define MAX_INTERVAL 50 + +#ifdef __KERNEL__ +static struct mxc622x_acc_platform_data mxc622x_plat_data = { + .poll_interval = 20, + .min_interval = 10, +}; +#endif + +#ifdef I2C_BUS_NUM_STATIC_ALLOC +static struct i2c_board_info mxc622x_i2c_boardinfo = { + I2C_BOARD_INFO(MXC622X_ACC_I2C_NAME, MXC622X_ACC_I2C_ADDR), +#ifdef __KERNEL__ + .platform_data = &mxc622x_plat_data +#endif +}; +#endif + +struct mxc622x_acc_data { + struct i2c_client *client; + struct mxc622x_acc_platform_data *pdata; + + struct mutex lock; + struct delayed_work input_work; + + struct input_dev *input_dev; + + int hw_initialized; + /* hw_working=-1 means not tested yet */ + int hw_working; + atomic_t enabled; + int on_before_suspend; + + u8 resume_state[RESUME_ENTRIES]; + +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif +}; + +/* + * Because misc devices can not carry a pointer from driver register to + * open, we keep this global. This limits the driver to a single instance. + */ +struct mxc622x_acc_data *mxc622x_acc_misc_data; +struct i2c_client *mxc622x_i2c_client = NULL; +static struct class* l_dev_class = NULL; +struct i2c_client *this_client = NULL; +////////////////////////////////////////////////////// +struct mx622x_sensordata{ + // for control + int int_gpio; //0-3 + int op; + int samp; + int xyz_axis[3][3]; // (axis,direction) + struct proc_dir_entry* sensor_proc; + struct input_dev *input_dev; + //struct work_struct work; + struct delayed_work work; // for polling + struct workqueue_struct *queue; + int isdbg; + int sensor_samp; // + int sensor_enable; // 0 --> disable sensor, 1 --> enable sensor + int test_pass; + //int offset[3]; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend earlysuspend; +#endif + s16 offset[3+1]; /*+1: for 4-byte alignment*/ + + +}; + +static struct mx622x_sensordata l_sensorconfig = { + .op = 0, + .int_gpio = 3, + .samp = 16, + .xyz_axis = { + {ABS_X, -1}, + {ABS_Y, 1}, + {ABS_Z, -1}, + }, + .sensor_proc = NULL, + .isdbg = 0, + .sensor_samp = 1, // 1 sample/second + .sensor_enable = 1, // enable sensor + .test_pass = 0, // for test program + //.offset={0,0,0}, +}; + +////////////////////////////////////////////////////// + + +static int mxc622x_acc_i2c_read(struct mxc622x_acc_data *acc, u8 * buf, int len) +{ + int err; + int tries = 0; + + struct i2c_msg msgs[] = { + { + .addr = acc->client->addr, + .flags = acc->client->flags & I2C_M_TEN, + .len = 1, + .buf = buf, }, + { + .addr = acc->client->addr, + .flags = (acc->client->flags & I2C_M_TEN) | I2C_M_RD, + .len = len, + .buf = buf, }, + }; + + do { + err = i2c_transfer(acc->client->adapter, msgs, 2); + if (err != 2) + msleep_interruptible(I2C_RETRY_DELAY); + } while ((err != 2) && (++tries < I2C_RETRIES)); + + if (err != 2) { + dev_err(&acc->client->dev, "read transfer error\n"); + err = -EIO; + } else { + err = 0; + } + + return err; +} + +static int mxc622x_acc_i2c_write(struct mxc622x_acc_data *acc, u8 * buf, int len) +{ + int err; + int tries = 0; + + struct i2c_msg msgs[] = { { .addr = acc->client->addr, + .flags = acc->client->flags & I2C_M_TEN, + .len = len + 1, .buf = buf, }, }; + do { + err = i2c_transfer(acc->client->adapter, msgs, 1); + if (err != 1) + msleep_interruptible(I2C_RETRY_DELAY); + } while ((err != 1) && (++tries < I2C_RETRIES)); + + if (err != 1) { + dev_err(&acc->client->dev, "write transfer error\n"); + err = -EIO; + } else { + err = 0; + } + + return err; +} + +static int mxc622x_acc_hw_init(struct mxc622x_acc_data *acc) +{ + int err = -1; + u8 buf[7]; + + printk(KERN_INFO "%s: hw init start\n", MXC622X_ACC_DEV_NAME); + + buf[0] = WHO_AM_I; + err = mxc622x_acc_i2c_read(acc, buf, 1); + if (err < 0) + goto error_firstread; + else + acc->hw_working = 1; + if ((buf[0] & 0x3F) != WHOAMI_MXC622X_ACC) { + err = -1; /* choose the right coded error */ + goto error_unknown_device; + } + + acc->hw_initialized = 1; + printk(KERN_INFO "%s: hw init done\n", MXC622X_ACC_DEV_NAME); + return 0; + +error_firstread: + acc->hw_working = 0; + dev_warn(&acc->client->dev, "Error reading WHO_AM_I: is device " + "available/working?\n"); + goto error1; +error_unknown_device: + dev_err(&acc->client->dev, + "device unknown. Expected: 0x%x," + " Replies: 0x%x\n", WHOAMI_MXC622X_ACC, buf[0]); +error1: + acc->hw_initialized = 0; + dev_err(&acc->client->dev, "hw init error 0x%x,0x%x: %d\n", buf[0], + buf[1], err); + return err; +} + +static void mxc622x_acc_device_power_off(struct mxc622x_acc_data *acc) +{ + int err; + u8 buf[2] = { MXC622X_REG_CTRL, MXC622X_CTRL_PWRDN }; + + err = mxc622x_acc_i2c_write(acc, buf, 1); + if (err < 0) + dev_err(&acc->client->dev, "soft power off failed: %d\n", err); +} + +static int mxc622x_acc_device_power_on(struct mxc622x_acc_data *acc) +{ + int err = -1; + u8 buf[2] = { MXC622X_REG_CTRL, MXC622X_CTRL_PWRON }; + + err = mxc622x_acc_i2c_write(acc, buf, 1); + if (err < 0) + dev_err(&acc->client->dev, "soft power on failed: %d\n", err); + + if (!acc->hw_initialized) { + err = mxc622x_acc_hw_init(acc); + if (acc->hw_working == 1 && err < 0) { + mxc622x_acc_device_power_off(acc); + return err; + } + } + + return 0; +} + + +/* */ + +static int mxc622x_acc_register_write(struct mxc622x_acc_data *acc, u8 *buf, + u8 reg_address, u8 new_value) +{ + int err = -1; + + if (atomic_read(&acc->enabled)) { + /* Sets configuration register at reg_address + * NOTE: this is a straight overwrite */ + buf[0] = reg_address; + buf[1] = new_value; + err = mxc622x_acc_i2c_write(acc, buf, 1); + if (err < 0) + return err; + } + return err; +} + +static int mxc622x_acc_register_read(struct mxc622x_acc_data *acc, u8 *buf, + u8 reg_address) +{ + + int err = -1; + buf[0] = (reg_address); + err = mxc622x_acc_i2c_read(acc, buf, 1); + return err; +} + +static int mxc622x_acc_register_update(struct mxc622x_acc_data *acc, u8 *buf, + u8 reg_address, u8 mask, u8 new_bit_values) +{ + int err = -1; + u8 init_val; + u8 updated_val; + err = mxc622x_acc_register_read(acc, buf, reg_address); + if (!(err < 0)) { + init_val = buf[1]; + updated_val = ((mask & new_bit_values) | ((~mask) & init_val)); + err = mxc622x_acc_register_write(acc, buf, reg_address, + updated_val); + } + return err; +} + +/* */ + +static int mxc622x_acc_get_acceleration_data(struct mxc622x_acc_data *acc, + int *xyz) +{ + int err = -1; + /* Data bytes from hardware x, y */ + u8 acc_data[2]; + + acc_data[0] = MXC622X_REG_DATA; + err = mxc622x_acc_i2c_read(acc, acc_data, 2); + + if (err < 0) + { + #ifdef DEBUG + printk(KERN_INFO "%s I2C read error %d\n", MXC622X_ACC_I2C_NAME, err); + #endif + return err; + } + + xyz[0] = (signed char)acc_data[0]; + xyz[1] = (signed char)acc_data[1]; + xyz[2] = 8; //32; + + #ifdef MXC622X_DEBUG + printk("x = %d, y = %d\n", xyz[0], xyz[1]); + #endif + + #ifdef MXC622X_DEBUG + + printk(KERN_INFO "%s read x=%d, y=%d, z=%d\n", + MXC622X_ACC_DEV_NAME, xyz[0], xyz[1], xyz[2]); + printk(KERN_INFO "%s poll interval %d\n", MXC622X_ACC_DEV_NAME, acc->pdata->poll_interval); + + #endif + return err; +} + +static void mxc622x_acc_report_values(struct mxc622x_acc_data *acc, int *xyz) +{ + int txyz,tx,ty,tz = 0; + static int suf=0; // To report every merging value + + tx = xyz[l_sensorconfig.xyz_axis[0][0]]*l_sensorconfig.xyz_axis[0][1]; + ty = xyz[l_sensorconfig.xyz_axis[1][0]]*l_sensorconfig.xyz_axis[1][1]; + tz = xyz[l_sensorconfig.xyz_axis[2][0]]*l_sensorconfig.xyz_axis[2][1]; + suf++; + if (suf > 5) + { + suf = 0; + } + + // packet the x,y,z + txyz = (tx&0x00FF) | ((ty&0xFF)<<8) | ((tz&0xFF)<<16) | ((suf&0xFF)<<24); + input_report_abs(acc->input_dev, ABS_X, txyz); + /*input_report_abs(acc->input_dev, ABS_Y, xyz[1]); + input_report_abs(acc->input_dev, ABS_Z, xyz[2]);*/ + input_sync(acc->input_dev); +} + +static int mxc622x_acc_enable(struct mxc622x_acc_data *acc) +{ + int err; + + if (!atomic_cmpxchg(&acc->enabled, 0, 1)) { + err = mxc622x_acc_device_power_on(acc); + if (err < 0) { + atomic_set(&acc->enabled, 0); + return err; + } + + schedule_delayed_work(&acc->input_work, msecs_to_jiffies( + acc->pdata->poll_interval)); + } + + return 0; +} + +static int mxc622x_acc_disable(struct mxc622x_acc_data *acc) +{ + if (atomic_cmpxchg(&acc->enabled, 1, 0)) { + cancel_delayed_work_sync(&acc->input_work); + mxc622x_acc_device_power_off(acc); + } + + return 0; +} + +static int mxc622x_acc_misc_open(struct inode *inode, struct file *file) +{ + int err; + err = nonseekable_open(inode, file); + if (err < 0) + return err; + + file->private_data = mxc622x_acc_misc_data; + + return 0; +} + +static /*int*/long mxc622x_acc_misc_ioctl(/*struct inode *inode, */struct file *file, + unsigned int cmd, unsigned long arg) +{ + void __user *argp = (void __user *)arg; + //u8 buf[4]; + //u8 mask; + //u8 reg_address; + //u8 bit_values; + int err; + int interval; + int xyz[3] = {0}; + struct mxc622x_acc_data *acc = file->private_data; + unsigned int uval = 0; + +// printk(KERN_INFO "%s: %s call with cmd 0x%x and arg 0x%x\n", +// MXC622X_ACC_DEV_NAME, __func__, cmd, (unsigned int)arg); + + switch (cmd) { + case MXC622X_ACC_IOCTL_GET_DELAY: + interval = acc->pdata->poll_interval; + if (copy_to_user(argp, &interval, sizeof(interval))) + return -EFAULT; + break; + + //case MXC622X_ACC_IOCTL_SET_DELAY: + case ECS_IOCTL_APP_SET_DELAY: + if (copy_from_user(&interval, argp, sizeof(interval))) + return -EFAULT; + if (interval < 0 || interval > 1000) + return -EINVAL; + //if(interval > MAX_INTERVAL) + //interval = MAX_INTERVAL; + acc->pdata->poll_interval = max(interval, + acc->pdata->min_interval); + break; + + //case MXC622X_ACC_IOCTL_SET_ENABLE: + case ECS_IOCTL_APP_SET_AFLAG: + if (copy_from_user(&interval, argp, sizeof(interval))) + return -EFAULT; + if (interval > 1) + return -EINVAL; + if (interval) + err = mxc622x_acc_enable(acc); + else + err = mxc622x_acc_disable(acc); + return err; + break; + + case MXC622X_ACC_IOCTL_GET_ENABLE: + interval = atomic_read(&acc->enabled); + if (copy_to_user(argp, &interval, sizeof(interval))) + return -EINVAL; + break; + case MXC622X_ACC_IOCTL_GET_COOR_XYZ: + err = mxc622x_acc_get_acceleration_data(acc, xyz); + if (err < 0) + return err; + #ifdef DEBUG + // printk(KERN_ALERT "%s Get coordinate xyz:[%d, %d, %d]\n", + // __func__, xyz[0], xyz[1], xyz[2]); + #endif + if (copy_to_user(argp, xyz, sizeof(xyz))) { + printk(KERN_ERR " %s %d error in copy_to_user \n", + __func__, __LINE__); + return -EINVAL; + } + break; + case MXC622X_ACC_IOCTL_GET_CHIP_ID: + { + u8 devid = 0; + u8 devinfo[DEVICE_INFO_LEN] = {0}; + err = mxc622x_acc_register_read(acc, &devid, WHO_AM_I); + if (err < 0) { + printk("%s, error read register WHO_AM_I\n", __func__); + return -EAGAIN; + } + sprintf(devinfo, "%s, %#x", DEVICE_INFO, devid); + + if (copy_to_user(argp, devinfo, sizeof(devinfo))) { + printk("%s error in copy_to_user(IOCTL_GET_CHIP_ID)\n", __func__); + return -EINVAL; + } + } + break; + case WMT_IOCTL_SENSOR_GET_DRVID: + uval = MXC622X_DRVID; + if (copy_to_user((unsigned int*)arg, &uval, sizeof(unsigned int))) + { + return -EFAULT; + } + dbg("mxc622x_driver_id:%d\n",uval); + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int mxc622x_acc_misc_close(struct inode *inode, struct file *filp) +{ + return 0; +} + + +static const struct file_operations mxc622x_acc_misc_fops = { + .owner = THIS_MODULE, + .open = mxc622x_acc_misc_open, + .unlocked_ioctl = mxc622x_acc_misc_ioctl, + .release = mxc622x_acc_misc_close, +}; + +static struct miscdevice mxc622x_acc_misc_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = GSENSOR_DEV_NODE,//MXC622X_ACC_DEV_NAME, + .fops = &mxc622x_acc_misc_fops, +}; + +static void mxc622x_acc_input_work_func(struct work_struct *work) +{ + struct mxc622x_acc_data *acc; + + int xyz[3] = { 0 }; + int err; + + acc = mxc622x_acc_misc_data; /*container_of((struct delayed_work *)work, + struct mxc622x_acc_data, input_work); */ + + mutex_lock(&acc->lock); + err = mxc622x_acc_get_acceleration_data(acc, xyz); + if (err < 0) + dev_err(&acc->client->dev, "get_acceleration_data failed\n"); + else + mxc622x_acc_report_values(acc, xyz); + + schedule_delayed_work(&acc->input_work, msecs_to_jiffies( + acc->pdata->poll_interval)); + mutex_unlock(&acc->lock); +} + +#ifdef MXC622X_OPEN_ENABLE +int mxc622x_acc_input_open(struct input_dev *input) +{ + struct mxc622x_acc_data *acc = input_get_drvdata(input); + + return mxc622x_acc_enable(acc); +} + +void mxc622x_acc_input_close(struct input_dev *dev) +{ + struct mxc622x_acc_data *acc = input_get_drvdata(dev); + + mxc622x_acc_disable(acc); +} +#endif + +static int mxc622x_acc_validate_pdata(struct mxc622x_acc_data *acc) +{ + acc->pdata->poll_interval = max(acc->pdata->poll_interval, + acc->pdata->min_interval); + + /* Enforce minimum polling interval */ + if (acc->pdata->poll_interval < acc->pdata->min_interval) { + dev_err(&acc->client->dev, "minimum poll interval violated\n"); + return -EINVAL; + } + + return 0; +} + +static int mxc622x_acc_input_init(struct mxc622x_acc_data *acc) +{ + int err; + // Polling rx data when the interrupt is not used. + if (1/*acc->irq1 == 0 && acc->irq1 == 0*/) { + INIT_DELAYED_WORK(&acc->input_work, mxc622x_acc_input_work_func); + } + + acc->input_dev = input_allocate_device(); + if (!acc->input_dev) { + err = -ENOMEM; + dev_err(&acc->client->dev, "input device allocate failed\n"); + goto err0; + } + +#ifdef MXC622X_ACC_OPEN_ENABLE + acc->input_dev->open = mxc622x_acc_input_open; + acc->input_dev->close = mxc622x_acc_input_close; +#endif + + input_set_drvdata(acc->input_dev, acc); + + set_bit(EV_ABS, acc->input_dev->evbit); + + input_set_abs_params(acc->input_dev, ABS_X, -G_MAX, G_MAX, FUZZ, FLAT); + input_set_abs_params(acc->input_dev, ABS_Y, -G_MAX, G_MAX, FUZZ, FLAT); + input_set_abs_params(acc->input_dev, ABS_Z, -G_MAX, G_MAX, FUZZ, FLAT); + + acc->input_dev->name = GSENSOR_INPUT_NAME;//MXC622X_ACC_INPUT_NAME; + + err = input_register_device(acc->input_dev); + if (err) { + dev_err(&acc->client->dev, + "unable to register input polled device %s\n", + acc->input_dev->name); + goto err1; + } + + return 0; + +err1: + input_free_device(acc->input_dev); +err0: + return err; +} + +static void mxc622x_acc_input_cleanup(struct mxc622x_acc_data *acc) +{ + input_unregister_device(acc->input_dev); + input_free_device(acc->input_dev); +} + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void mxc622x_early_suspend (struct early_suspend* es); +static void mxc622x_early_resume (struct early_suspend* es); +#endif + +static int is_mxc622x(struct i2c_client *client) +{ + int tempvalue; + + /* read chip id */ + tempvalue = i2c_smbus_read_word_data(client, WHO_AM_I); + if ((tempvalue & 0x003F) == WHOAMI_MXC622X_ACC) { + //printk(KERN_INFO "%s I2C driver registered!\n", + // MXC622X_ACC_DEV_NAME); + return 1; + } + return 0; +} + +static int mxc622x_acc_probe(struct i2c_client *client) +{ + + struct mxc622x_acc_data *acc; + + int err = -1; + int tempvalue; + + pr_info("%s: probe start.\n", MXC622X_ACC_DEV_NAME); + + /*if (client->dev.platform_data == NULL) { + dev_err(&client->dev, "platform data is NULL. exiting.\n"); + err = -ENODEV; + goto exit_check_functionality_failed; + }*/ + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, "client not i2c capable\n"); + err = -ENODEV; + goto exit_check_functionality_failed; + } + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA)) { + dev_err(&client->dev, "client not smb-i2c capable:2\n"); + err = -EIO; + goto exit_check_functionality_failed; + } + + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_I2C_BLOCK)){ + dev_err(&client->dev, "client not smb-i2c capable:3\n"); + err = -EIO; + goto exit_check_functionality_failed; + } + /* + * OK. From now, we presume we have a valid client. We now create the + * client structure, even though we cannot fill it completely yet. + */ + + acc = kzalloc(sizeof(struct mxc622x_acc_data), GFP_KERNEL); + if (acc == NULL) { + err = -ENOMEM; + dev_err(&client->dev, + "failed to allocate memory for module data: " + "%d\n", err); + goto exit_alloc_data_failed; + } + + mutex_init(&acc->lock); + mutex_lock(&acc->lock); + + acc->client = client; + mxc622x_i2c_client = client; + i2c_set_clientdata(client, acc); + + /* read chip id */ + tempvalue = i2c_smbus_read_word_data(client, WHO_AM_I); + + if ((tempvalue & 0x003F) == WHOAMI_MXC622X_ACC) { + printk(KERN_INFO "%s I2C driver registered!\n", + MXC622X_ACC_DEV_NAME); + } else { + acc->client = NULL; + printk(KERN_INFO "I2C driver not registered!" + " Device unknown 0x%x\n", tempvalue); + goto err_mutexunlockfreedata; + } + acc->pdata = kzalloc(sizeof(struct mxc622x_acc_platform_data), GFP_KERNEL); + if (acc->pdata == NULL) { + err = -ENOMEM; + dev_err(&client->dev, + "failed to allocate memory for pdata: %d\n", + err); + goto exit_kfree_pdata; + } + + //memcpy(acc->pdata, client->dev.platform_data, sizeof(*acc->pdata)); + acc->pdata->poll_interval = 20; + acc->pdata->min_interval = 10; + + err = mxc622x_acc_validate_pdata(acc); + if (err < 0) { + dev_err(&client->dev, "failed to validate platform data\n"); + goto exit_kfree_pdata; + } + + i2c_set_clientdata(client, acc); + + + /*if (acc->pdata->init) { + err = acc->pdata->init(); + if (err < 0) { + dev_err(&client->dev, "init failed: %d\n", err); + goto err2; + } + }*/ + + err = mxc622x_acc_device_power_on(acc); + if (err < 0) { + dev_err(&client->dev, "power on failed: %d\n", err); + goto err2; + } + + atomic_set(&acc->enabled, 1); + + err = mxc622x_acc_input_init(acc); + if (err < 0) { + dev_err(&client->dev, "input init failed\n"); + goto err_power_off; + } + mxc622x_acc_misc_data = acc; + + err = misc_register(&mxc622x_acc_misc_device); + if (err < 0) { + dev_err(&client->dev, + "misc MXC622X_ACC_DEV_NAME register failed\n"); + goto err_input_cleanup; + } + + mxc622x_acc_device_power_off(acc); + + /* As default, do not report information */ + atomic_set(&acc->enabled, 0); + + acc->on_before_suspend = 0; + + #ifdef CONFIG_HAS_EARLYSUSPEND + acc->early_suspend.suspend = mxc622x_early_suspend; + acc->early_suspend.resume = mxc622x_early_resume; + acc->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN; + register_early_suspend(&acc->early_suspend); +#endif + + mutex_unlock(&acc->lock); + + dev_info(&client->dev, "%s: probed\n", MXC622X_ACC_DEV_NAME); + + return 0; + +err_input_cleanup: + mxc622x_acc_input_cleanup(acc); +err_power_off: + mxc622x_acc_device_power_off(acc); +err2: + if (acc->pdata->exit) acc->pdata->exit(); +exit_kfree_pdata: + kfree(acc->pdata); +err_mutexunlockfreedata: + kfree(acc); + mutex_unlock(&acc->lock); + i2c_set_clientdata(client, NULL); + mxc622x_acc_misc_data = NULL; +exit_alloc_data_failed: +exit_check_functionality_failed: + printk(KERN_ERR "%s: Driver Init failed\n", MXC622X_ACC_DEV_NAME); + return err; +} + +static int __devexit mxc622x_acc_remove(struct i2c_client *client) +{ + /* TODO: revisit ordering here once _probe order is finalized */ + struct mxc622x_acc_data *acc = mxc622x_acc_misc_data;//i2c_get_clientdata(client); + + misc_deregister(&mxc622x_acc_misc_device); + mxc622x_acc_input_cleanup(acc); + mxc622x_acc_device_power_off(acc); + if (acc->pdata->exit) + acc->pdata->exit(); + kfree(acc->pdata); + kfree(acc); + + return 0; +} + +static int mxc622x_acc_resume(struct platform_device *pdev) +{ + struct mxc622x_acc_data *acc = mxc622x_acc_misc_data; + + if (acc != NULL && acc->on_before_suspend) { + acc->on_before_suspend = 0; + acc->hw_initialized = 0; + return mxc622x_acc_enable(acc); + } + return 0; +} + +static int mxc622x_acc_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct mxc622x_acc_data *acc = mxc622x_acc_misc_data; + if (acc != NULL) { + if (atomic_read(&acc->enabled)) { + acc->on_before_suspend = 1; + return mxc622x_acc_disable(acc); + } + } + return 0; +} + +static int mxc622x_probe(struct platform_device *pdev) +{ + return 0; +} + +static int mxc622x_remove(struct platform_device *pdev) +{ + return 0; +} + +static struct platform_driver mxc622x_driver = { + .probe = mxc622x_probe, + .remove = mxc622x_remove, + .suspend = mxc622x_acc_suspend, + .resume = mxc622x_acc_resume, + .driver = { + .name = GSENSOR_I2C_NAME, + }, +}; + + +#ifdef CONFIG_HAS_EARLYSUSPEND + +static void mxc622x_early_suspend (struct early_suspend* es) +{ + struct mxc622x_acc_data *acc = mxc622x_acc_misc_data; //i2c_get_clientdata(client); +#ifdef MXC622X_DEBUG + printk("%s.\n", __func__); +#endif + if (acc != NULL) { + if (atomic_read(&acc->enabled)) { + acc->on_before_suspend = 1; + return mxc622x_acc_disable(acc); + } + } +} + +static void mxc622x_early_resume (struct early_suspend* es) +{ + struct mxc622x_acc_data *acc = mxc622x_acc_misc_data; //i2c_get_clientdata(client); +#ifdef MXC622X_DEBUG + printk("%s.\n", __func__); +#endif + + if (acc != NULL && acc->on_before_suspend) { + acc->on_before_suspend = 0; + acc->hw_initialized = 0; + return mxc622x_acc_enable(acc); + } + +} + +#endif /* CONFIG_HAS_EARLYSUSPEND */ + +static const struct i2c_device_id mxc622x_acc_id[] + = { { MXC622X_ACC_DEV_NAME, 0 }, { }, }; + +MODULE_DEVICE_TABLE(i2c, mxc622x_acc_id); + +#if 0 +static struct i2c_driver mxc622x_acc_driver = { + .driver = { + .name = MXC622X_ACC_I2C_NAME, + }, + .probe = mxc622x_acc_probe, + .remove = __devexit_p(mxc622x_acc_remove), + .resume = mxc622x_acc_resume, + .suspend = mxc622x_acc_suspend, + .id_table = mxc622x_acc_id, +}; +#endif + +#ifdef I2C_BUS_NUM_STATIC_ALLOC + +int i2c_static_add_device(struct i2c_board_info *info) +{ + struct i2c_adapter *adapter; + struct i2c_client *client; + int err; + + adapter = i2c_get_adapter(I2C_STATIC_BUS_NUM); + if (!adapter) { + pr_err("%s: can't get i2c adapter\n", __FUNCTION__); + err = -ENODEV; + goto i2c_err; + } + + client = i2c_new_device(adapter, info); + if (!client) { + pr_err("%s: can't add i2c device at 0x%x\n", + __FUNCTION__, (unsigned int)info->addr); + err = -ENODEV; + goto i2c_err; + } + + i2c_put_adapter(adapter); + + return 0; + +i2c_err: + return err; +} + +#endif /*I2C_BUS_NUM_STATIC_ALLOC*/ + +static void mxc622x_platform_release(struct device *device) +{ + dbg("...\n"); + return; +} + + +static struct platform_device mxc622x_device = { + .name = GSENSOR_I2C_NAME, + .id = 0, + .dev = { + .release = mxc622x_platform_release, + }, +}; + +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); +static int get_axisset(void* param) +{ + char varbuf[64]; + int n; + int varlen; + + int tmp_offset[3] = {0}; + memset(varbuf, 0, sizeof(varbuf)); + varlen = sizeof(varbuf); + if (wmt_getsyspara("wmt.io.mxc622xsensor", varbuf, &varlen)) { + errlog("Can't get gsensor config in u-boot!!!!\n"); + return -1; + } else { + n = sscanf(varbuf, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", + &l_sensorconfig.op, + &l_sensorconfig.int_gpio, + &l_sensorconfig.samp, + &(l_sensorconfig.xyz_axis[0][0]), + &(l_sensorconfig.xyz_axis[0][1]), + &(l_sensorconfig.xyz_axis[1][0]), + &(l_sensorconfig.xyz_axis[1][1]), + &(l_sensorconfig.xyz_axis[2][0]), + &(l_sensorconfig.xyz_axis[2][1]), + &tmp_offset[0], + &tmp_offset[1], + &tmp_offset[2] + ); + if (n != 12) { + printk(KERN_ERR "gsensor format is error in u-boot!!!\n"); + return -1; + } + l_sensorconfig.offset[0] = tmp_offset[0]; + l_sensorconfig.offset[1] = tmp_offset[1]; + l_sensorconfig.offset[2] = tmp_offset[2]; + l_sensorconfig.sensor_samp = l_sensorconfig.samp; + + dbg("get the sensor config: %d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d\n", + l_sensorconfig.op, + l_sensorconfig.int_gpio, + l_sensorconfig.samp, + l_sensorconfig.xyz_axis[0][0], + l_sensorconfig.xyz_axis[0][1], + l_sensorconfig.xyz_axis[1][0], + l_sensorconfig.xyz_axis[1][1], + l_sensorconfig.xyz_axis[2][0], + l_sensorconfig.xyz_axis[2][1], + l_sensorconfig.offset[0], + l_sensorconfig.offset[1], + l_sensorconfig.offset[2] + ); + } + return 0; +} + + +static int __init mxc622x_acc_init(void) +{ + int ret = 0; + + printk(KERN_INFO "%s accelerometer driver: init\n", + MXC622X_ACC_I2C_NAME); + ret = get_axisset(NULL); + if (ret < 0) + { + printk("<<<<<%s user choose to no sensor chip!\n", __func__); + return ret; + } + + if (!(this_client = sensor_i2c_register_device(0, GSENSOR_I2C_ADDR, GSENSOR_I2C_NAME))) + { + printk(KERN_EMERG"Can't register gsensor i2c device!\n"); + return -1; + } + if(!is_mxc622x(this_client)) + { + dbg("isn't mxc622x gsensor!\n"); + return -1; + } + // parse g-sensor u-boot arg + + /*if (ret) + { + errlog("only for test!\n"); + return -1; + }*/ +#ifdef I2C_BUS_NUM_STATIC_ALLOC + ret = i2c_static_add_device(&mxc622x_i2c_boardinfo); + if (ret < 0) { + pr_err("%s: add i2c device error %d\n", __FUNCTION__, ret); + goto init_err; + } +#endif + ret = mxc622x_acc_probe(this_client); + if (ret) + { + sensor_i2c_unregister_device(this_client); + return -1; + } + // create the platform device + l_dev_class = class_create(THIS_MODULE, GSENSOR_I2C_NAME); + if (IS_ERR(l_dev_class)){ + ret = PTR_ERR(l_dev_class); + printk(KERN_ERR "Can't class_create gsensor device !!\n"); + return ret; + } + if((ret = platform_device_register(&mxc622x_device))) + { + klog("Can't register mc3230 platform devcie!!!\n"); + return ret; + } + if ((ret = platform_driver_register(&mxc622x_driver)) != 0) + { + errlog("Can't register mc3230 platform driver!!!\n"); + return ret; + } + + //return i2c_add_driver(&mxc622x_acc_driver); + +init_err: + return ret; +} + +static void __exit mxc622x_acc_exit(void) +{ + //printk(KERN_INFO "%s accelerometer driver exit\n", MXC622X_ACC_DEV_NAME); + + platform_driver_unregister(&mxc622x_driver); + platform_device_unregister(&mxc622x_device); + class_destroy(l_dev_class); + mxc622x_acc_remove(mxc622x_i2c_client); + sensor_i2c_unregister_device(this_client); + #ifdef I2C_BUS_NUM_STATIC_ALLOC + i2c_unregister_device(mxc622x_i2c_client); + #endif + + //i2c_del_driver(&mxc622x_acc_driver); + return; +} + +module_init(mxc622x_acc_init); +module_exit(mxc622x_acc_exit); + +MODULE_DESCRIPTION("mxc622x accelerometer misc driver"); +MODULE_AUTHOR("Memsic"); +MODULE_LICENSE("GPL"); + diff --git a/ANDROID_3.4.5/drivers/input/sensor/mxc622x_gsensor/mxc622x.h b/ANDROID_3.4.5/drivers/input/sensor/mxc622x_gsensor/mxc622x.h new file mode 100755 index 00000000..2b83bb7b --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/mxc622x_gsensor/mxc622x.h @@ -0,0 +1,83 @@ + +/******************** (C) COPYRIGHT 2010 STMicroelectronics ******************** +* +* File Name : mxc622x.h +* Authors : MH - C&I BU - Application Team +* +******************************************************************************** +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* THE PRESENT SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES +* OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, FOR THE SOLE +* PURPOSE TO SUPPORT YOUR APPLICATION DEVELOPMENT. +* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, +* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE +* CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING +* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. +* +* THIS SOFTWARE IS SPECIFICALLY DESIGNED FOR EXCLUSIVE USE WITH ST PARTS. +* +*******************************************************************************/ + + +#ifndef __MXC622X_H__ +#define __MXC622X_H__ + +#include /* For IOCTL macros */ +#include + +#ifndef DEBUG +#define DEBUG +#endif + +#define GSENSOR_I2C_NAME "mxc622x" +#define GSENSOR_I2C_ADDR 0x15 + +#define MXC622X_ACC_IOCTL_BASE 77 +/** The following define the IOCTL command values via the ioctl macros */ +#define MXC622X_ACC_IOCTL_SET_DELAY _IOW(MXC622X_ACC_IOCTL_BASE, 0, int) +#define MXC622X_ACC_IOCTL_GET_DELAY _IOR(MXC622X_ACC_IOCTL_BASE, 1, int) +#define MXC622X_ACC_IOCTL_SET_ENABLE _IOW(MXC622X_ACC_IOCTL_BASE, 2, int) +#define MXC622X_ACC_IOCTL_GET_ENABLE _IOR(MXC622X_ACC_IOCTL_BASE, 3, int) +#define MXC622X_ACC_IOCTL_GET_COOR_XYZ _IOW(MXC622X_ACC_IOCTL_BASE, 22, int) +#define MXC622X_ACC_IOCTL_GET_CHIP_ID _IOR(MXC622X_ACC_IOCTL_BASE, 255, char[32]) + +/************************************************/ +/* Accelerometer defines section */ +/************************************************/ +#define MXC622X_ACC_DEV_NAME "mxc622x" +#define MXC622X_ACC_INPUT_NAME "accelerometer" +#define MXC622X_ACC_I2C_ADDR 0x15 +#define MXC622X_ACC_I2C_NAME MXC622X_ACC_DEV_NAME + +/* MXC622X register address */ +#define MXC622X_REG_CTRL 0x04 +#define MXC622X_REG_DATA 0x00 + +/* MXC622X control bit */ +#define MXC622X_CTRL_PWRON 0x00 /* power on */ +#define MXC622X_CTRL_PWRDN 0x80 /* power donw */ + +//#if defined(CONFIG_MACH_SP6810A) +//#define I2C_BUS_NUM_STATIC_ALLOC +#define I2C_STATIC_BUS_NUM ( 0) // Need to be modified according to actual setting +//#endif + +struct mxc622x_acc_platform_data { + int poll_interval; + int min_interval; + + int (*init)(void); + void (*exit)(void); + int (*power_on)(void); + int (*power_off)(void); + +}; + +#endif /* __MXC622X_H__ */ + + + diff --git a/ANDROID_3.4.5/drivers/input/sensor/sensor.c b/ANDROID_3.4.5/drivers/input/sensor/sensor.c new file mode 100755 index 00000000..5a82a9fb --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/sensor.c @@ -0,0 +1,114 @@ +#include +#include +//#include +#include "sensor.h" +//DEFINE_MUTEX(mutex_client); +//static struct i2c_client *sensor_client=NULL; +struct i2c_client *sensor_i2c_register_device(int bus_no, int client_addr, const char *client_name) +{ + struct i2c_adapter *adapter = NULL; + struct i2c_client *sensor_client=NULL; + + struct i2c_board_info sensor_i2c_board_info = { + .type = "unused", + .flags = 0x00, + .addr = 0xff, + .platform_data = NULL, + .archdata = NULL, + .irq = -1, + }; + + if ((bus_no<0) || (client_addr>0x7f) || (client_addr<0)|| (!client_name)) + { + printk(KERN_ERR "%s param error! pls check out!\n", __FUNCTION__); + return NULL; + } + printk(KERN_INFO "%s busno %d client_addr 0x%x client_name %s \n", __FUNCTION__, \ + bus_no, client_addr, client_name); + + sensor_i2c_board_info.addr = client_addr; + //sensor_i2c_board_info.type = client_name; + strcpy(sensor_i2c_board_info.type, client_name); + + adapter = i2c_get_adapter(bus_no);/*in bus NR*/ + + if (NULL == adapter) { + printk("can not get i2c adapter, client address error\n"); + return NULL; + } + + //mutex_lock(&mutex_client); + sensor_client = i2c_new_device(adapter, &sensor_i2c_board_info); + + + if (sensor_client == NULL) { + printk("allocate i2c client failed\n"); + //mutex_unlock(&mutex_client); + return NULL; + } + i2c_put_adapter(adapter); + //mutex_unlock(&mutex_client); + + return sensor_client; +} +EXPORT_SYMBOL(sensor_i2c_register_device); + +struct i2c_client *sensor_i2c_register_device2(int bus_no, int client_addr, const char *client_name,void *pdata) +{ + struct i2c_adapter *adapter = NULL; + struct i2c_client *sensor_client=NULL; + + struct i2c_board_info sensor_i2c_board_info = { + .type = "unused", + .flags = 0x00, + .addr = 0xff, + .platform_data = NULL, + .archdata = NULL, + .irq = -1, + }; + + if ((bus_no<0) || (client_addr>0x7f) || (client_addr<0)|| (!client_name)) + { + printk(KERN_ERR "%s param error! pls check out!\n", __FUNCTION__); + return NULL; + } + printk(KERN_INFO "%s busno %d client_addr 0x%x client_name %s \n", __FUNCTION__, \ + bus_no, client_addr, client_name); + + sensor_i2c_board_info.addr = client_addr; + sensor_i2c_board_info.platform_data = pdata; + //sensor_i2c_board_info.type = client_name; + strcpy(sensor_i2c_board_info.type, client_name); + + adapter = i2c_get_adapter(bus_no);/*in bus NR*/ + + if (NULL == adapter) { + printk("can not get i2c adapter, client address error\n"); + return NULL; + } + + //mutex_lock(&mutex_client); + sensor_client = i2c_new_device(adapter, &sensor_i2c_board_info); + + + if (sensor_client == NULL) { + printk("allocate i2c client failed\n"); + //mutex_unlock(&mutex_client); + return NULL; + } + i2c_put_adapter(adapter); + //mutex_unlock(&mutex_client); + + return sensor_client; +} +EXPORT_SYMBOL(sensor_i2c_register_device2); + +void sensor_i2c_unregister_device(struct i2c_client *client) +{ + if (client != NULL) + { + i2c_unregister_device(client); + } +} +EXPORT_SYMBOL(sensor_i2c_unregister_device); + diff --git a/ANDROID_3.4.5/drivers/input/sensor/sensor.h b/ANDROID_3.4.5/drivers/input/sensor/sensor.h new file mode 100755 index 00000000..9a51433d --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/sensor.h @@ -0,0 +1,91 @@ +#ifndef __SENSOR_H__ +#define __SENSOR_H__ +#include +#include +#include +#include +#include + +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif + + +//#define GSENSOR_I2C_NAME "unused" +//#define GSENSOR_I2C_ADDR 0xff + + +#define GSENSOR_PROC_NAME "gsensor_config" +#define GSENSOR_INPUT_NAME "g-sensor" +#define GSENSOR_DEV_NODE "sensor_ctrl" + +#define SENSOR_PROC_NAME "lsensor_config" +#define SENSOR_INPUT_NAME "l-sensor" +#define SENSOR_DEV_NODE "lsensor_ctrl" + +#undef dbg +#define dbg(fmt, args...) if (l_sensorconfig.isdbg) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__, ## args) + +#undef errlog +#undef klog +#define errlog(fmt, args...) printk(KERN_ERR "[%s]: " fmt, __FUNCTION__, ## args) +#define klog(fmt, args...) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__, ## args) + +enum gsensor_id +{ + MMA7660_DRVID = 0, + MC3230_DRVID , + DMARD08_DRVID , + DMARD06_DRVID , + DMARD10_DRVID , + MXC622X_DRVID , + MMA8452Q_DRVID , + STK8312_DRVID , + KIONIX_DRVID, + DMARD09_DRVID , + //add new gsensor id here, must be in order +}; + +#define ISL29023_DRVID 0 + +struct wmt_gsensor_data{ + // for control + int int_gpio; //0-3 + int op; + int samp; + int xyz_axis[3][2]; // (axis,direction) + struct proc_dir_entry* sensor_proc; + struct input_dev *input_dev; + //struct work_struct work; + struct delayed_work work; // for polling + struct workqueue_struct *queue; + int isdbg; + int sensor_samp; // + int sensor_enable; // 0 --> disable sensor, 1 --> enable sensor + int test_pass; + int offset[3]; + struct i2c_client *client; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend earlysuspend; +#endif + +}; + +///////////////////////// ioctrl cmd //////////////////////// +#define WMTGSENSOR_IOCTL_MAGIC 0x09 +#define WMT_IOCTL_SENSOR_CAL_OFFSET _IOW(WMTGSENSOR_IOCTL_MAGIC, 0x01, int) //offset calibration +#define ECS_IOCTL_APP_SET_AFLAG _IOW(WMTGSENSOR_IOCTL_MAGIC, 0x02, short) +#define ECS_IOCTL_APP_SET_DELAY _IOW(WMTGSENSOR_IOCTL_MAGIC, 0x03, short) +#define WMT_IOCTL_SENSOR_GET_DRVID _IOW(WMTGSENSOR_IOCTL_MAGIC, 0x04, unsigned int) +#define WMT_IOCTL_SENOR_GET_RESOLUTION _IOR(WMTGSENSOR_IOCTL_MAGIC, 0x05, short) + +#define WMT_LSENSOR_IOCTL_MAGIC 0x10 +#define LIGHT_IOCTL_SET_ENABLE _IOW(WMT_LSENSOR_IOCTL_MAGIC, 0x01, short) + +/* Function prototypes */ +extern struct i2c_client *sensor_i2c_register_device (int bus_no, int client_addr, const char *client_name); +extern struct i2c_client *sensor_i2c_register_device2(int bus_no, int client_addr, const char *client_name,void *pdata); +extern void sensor_i2c_unregister_device(struct i2c_client *client); + + +#endif diff --git a/ANDROID_3.4.5/drivers/input/sensor/stk3310/Makefile b/ANDROID_3.4.5/drivers/input/sensor/stk3310/Makefile new file mode 100755 index 00000000..19a79f84 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/stk3310/Makefile @@ -0,0 +1,34 @@ +KERNELDIR=../../../../ +#KERNELDIR=/home/hangyan/android8850/kernel/ANDROID_3.0.8 +CROSS = arm_1103_le- +CC= $(CROSS)gcc +LD= $(CROSS)ld +STRIP = $(CROSS)strip + +DEBUG = n + +# Add your debugging flag (or not) to EXTRA_CFLAGS +ifeq ($(DEBUG),y) +# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines +DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines + +else + DEBFLAGS = -O2 -Wall +endif + +EXTRA_CFLAGS += $(DEBFLAGS) + + +MY_MODULE_NAME=s_wmt_lsensor_stk3310 + +obj-m := $(MY_MODULE_NAME).o +$(MY_MODULE_NAME)-objs := stk3310.o + +default: + $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules + $(STRIP) --strip-debug $(MY_MODULE_NAME).ko + rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions + +clean: + rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers + diff --git a/ANDROID_3.4.5/drivers/input/sensor/stk3310/stk3310.c b/ANDROID_3.4.5/drivers/input/sensor/stk3310/stk3310.c new file mode 100755 index 00000000..4e9fde10 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/stk3310/stk3310.c @@ -0,0 +1,644 @@ +/* + * stk3310.c - stk3310 ALS & Proximity Driver + * + * By Intersil Corp + * Michael DiGioia + * + * Based on isl29011.c + * by Mike DiGioia + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include "../sensor.h" +#define SENSOR_I2C_NAME "stk3310" +#define SENSOR_I2C_ADDR 0x48 + +#undef dbg +#define dbg(fmt, args...) +#undef errlog +#undef klog +#define errlog(fmt, args...) printk(KERN_ERR "[%s]: " fmt, __FUNCTION__, ## args) +#define klog(fmt, args...) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__, ## args) +/* Insmod parameters */ +//I2C_CLIENT_INSMOD_1(stk3310); + +#define MODULE_NAME "stk3310" + + +struct stk_device { + struct input_polled_dev* input_poll_devl; + struct input_polled_dev* input_poll_devp; + struct i2c_client* client; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend earlysuspend; +#endif + +}; + +static struct stk_device* l_sensorconfig = NULL; +static int l_enable = 1; // 0:don't report data +static int p_enable = 1; // 0:don't report data + +static struct i2c_client *this_client = NULL; + +static DEFINE_MUTEX(mutex); + +static int isl_get_lux_datal(struct i2c_client* client) +{ + __u16 resH, resL; + resL = i2c_smbus_read_byte_data(client, 0x14); + resH = i2c_smbus_read_byte_data(client, 0x13); + if ((resL < 0) || (resH < 0)) + { + errlog("Error to read lux_data!\n"); + return -1; + } + return (resH <<8 | resL) ;//* idev->range / idev->resolution; +} + + +static int isl_get_lux_datap(struct i2c_client* client) +{ + __u16 resH, resL; + resL = i2c_smbus_read_byte_data(client, 0x12); + resH = i2c_smbus_read_byte_data(client, 0x11); + if ((resL < 0) || (resH < 0)) + { + errlog("Error to read lux_data!\n"); + return -1; + } + //return (resH <<8 | resL) ;//* idev->range / idev->resolution; + if(resH>0) + return 0; + else + return 6; +} + +//#define PXM 0 +static int isl_set_default_config(struct i2c_client *client) +{ + int ret=0; + unsigned char regval; +//#if PXM + ret = i2c_smbus_write_byte_data(client, 0, (1 << 1)); + if(p_enable) + { + regval = i2c_smbus_read_byte_data(l_sensorconfig->client, 0); + regval |= (1 << 0); + i2c_smbus_write_byte_data(l_sensorconfig->client, 0, regval); + } + //ret = i2c_smbus_write_byte_data(client, 0, (1 << 0)); +//#else +//#endif + if (ret < 0) + return -EINVAL; + return 0; +} + +/* Return 0 if detection is successful, -ENODEV otherwise */ +static int stk3310_detect(struct i2c_client *client/*, int kind, + struct i2c_board_info *info*/) +{ + int device; + + device= i2c_smbus_read_byte_data(client, 0x3e); + if(0x13==device) + { + printk(KERN_ALERT "stk3310 detected OK\n"); + return 0; + } + else + return -1; +} + +int isl_input_open(struct input_dev* input) +{ + return 0; +} + +void isl_input_close(struct input_dev* input) +{ +} + +static void isl_input_lux_poll_l(struct input_polled_dev *dev) +{ + struct stk_device* idev = dev->private; + struct input_dev* input = idev->input_poll_devl->input; + struct i2c_client* client = idev->client; + if (l_enable != 0) + { + mutex_lock(&mutex); + //printk(KERN_ALERT "by flashchen val is %x",val); + input_report_abs(input, ABS_MISC, isl_get_lux_datal(client)); + input_sync(input); + mutex_unlock(&mutex); + } +} + +static void isl_input_lux_poll_p(struct input_polled_dev *dev) +{ + struct stk_device* idev = dev->private; + struct input_dev* input = idev->input_poll_devp->input; + struct i2c_client* client = idev->client; + if (p_enable != 0) + { + mutex_lock(&mutex); + //printk(KERN_ALERT "by flashchen val is %x",val); + input_report_abs(input, ABS_MISC, isl_get_lux_datap(client)); + input_sync(input); + mutex_unlock(&mutex); + } +} + +static struct i2c_device_id stk3310_id[] = { + {"stk3310", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, stk3310_id); + + +static int mmad_open(struct inode *inode, struct file *file) +{ + dbg("Open the l-sensor node...\n"); + return 0; +} + +static int mmad_release(struct inode *inode, struct file *file) +{ + dbg("Close the l-sensor node...\n"); + return 0; +} + +static ssize_t mmadl_read(struct file *fl, char __user *buf, size_t cnt, loff_t *lf) +{ + int lux_data = 0; + + mutex_lock(&mutex); + lux_data = isl_get_lux_datal(l_sensorconfig->client); + mutex_unlock(&mutex); + if (lux_data < 0) + { + errlog("Failed to read lux data!\n"); + return -1; + } + printk(KERN_ALERT "lux_data is %x\n",lux_data); + return 0; + copy_to_user(buf, &lux_data, sizeof(lux_data)); + return sizeof(lux_data); +} + + +static ssize_t mmadp_read(struct file *fl, char __user *buf, size_t cnt, loff_t *lf) +{ + int lux_data = 0; + + mutex_lock(&mutex); + lux_data = isl_get_lux_datap(l_sensorconfig->client); + mutex_unlock(&mutex); + if (lux_data < 0) + { + errlog("Failed to read lux data!\n"); + return -1; + } + printk(KERN_ALERT "lux_data is %x\n",lux_data); + return 0; + copy_to_user(buf, &lux_data, sizeof(lux_data)); + return sizeof(lux_data); +} + +static long +mmadl_ioctl(/*struct inode *inode,*/ struct file *file, unsigned int cmd, + unsigned long arg) +{ + void __user *argp = (void __user *)arg; + //char rwbuf[5]; + short enable; //amsr = -1; + unsigned int uval; + + dbg("l-sensor ioctr...\n"); + //memset(rwbuf, 0, sizeof(rwbuf)); + switch (cmd) { + case LIGHT_IOCTL_SET_ENABLE: + // enable/disable sensor + if (copy_from_user(&enable, argp, sizeof(short))) + { + printk(KERN_ERR "Can't get enable flag!!!\n"); + return -EFAULT; + } + dbg("enable=%d\n",enable); + if ((enable >=0) && (enable <=1)) + { + dbg("driver: disable/enable(%d) gsensor.\n", enable); + + //l_sensorconfig.sensor_enable = enable; + dbg("Should to implement d/e the light sensor!\n"); + l_enable = enable; + + } else { + printk(KERN_ERR "Wrong enable argument in %s !!!\n", __FUNCTION__); + return -EINVAL; + } + break; + case WMT_IOCTL_SENSOR_GET_DRVID: +#define DRVID 0 + uval = DRVID ; + if (copy_to_user((unsigned int*)arg, &uval, sizeof(unsigned int))) + { + return -EFAULT; + } + dbg("stk3310_driver_id:%d\n",uval); + default: + break; + } + + return 0; +} + + +static long +mmadp_ioctl(/*struct inode *inode,*/ struct file *file, unsigned int cmd, + unsigned long arg) +{ + void __user *argp = (void __user *)arg; + //char rwbuf[5]; + short enable; //amsr = -1; + unsigned int uval; + unsigned char regval; + + dbg("l-sensor ioctr...\n"); + //memset(rwbuf, 0, sizeof(rwbuf)); + switch (cmd) { + case LIGHT_IOCTL_SET_ENABLE: + // enable/disable sensor + if (copy_from_user(&enable, argp, sizeof(short))) + { + printk(KERN_ERR "Can't get enable flag!!!\n"); + return -EFAULT; + } + dbg("enable=%d\n",enable); + if ((enable >=0) && (enable <=1)) + { + dbg("driver: disable/enable(%d) gsensor.\n", enable); + + //l_sensorconfig.sensor_enable = enable; + dbg("Should to implement d/e the light sensor!\n"); + p_enable = enable; + if(p_enable) + { + regval = i2c_smbus_read_byte_data(l_sensorconfig->client, 0); + regval |= (1 << 0); + i2c_smbus_write_byte_data(l_sensorconfig->client, 0, regval); + } + else + { + regval = i2c_smbus_read_byte_data(l_sensorconfig->client, 0); + regval &= ~(1 << 0); + i2c_smbus_write_byte_data(l_sensorconfig->client, 0, regval); + } + + } else { + printk(KERN_ERR "Wrong enable argument in %s !!!\n", __FUNCTION__); + return -EINVAL; + } + break; + case WMT_IOCTL_SENSOR_GET_DRVID: +#define DRVID 0 + uval = DRVID ; + if (copy_to_user((unsigned int*)arg, &uval, sizeof(unsigned int))) + { + return -EFAULT; + } + dbg("stk3310_driver_id:%d\n",uval); + default: + break; + } + + return 0; +} + + +static struct file_operations mmadl_fops = { + .owner = THIS_MODULE, + .open = mmad_open, + .release = mmad_release, + .read = mmadl_read, + .unlocked_ioctl = mmadl_ioctl, +}; + +static struct miscdevice mmadl_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "lsensor_ctrl", + .fops = &mmadl_fops, +}; + +static struct file_operations mmadp_fops = { + .owner = THIS_MODULE, + .open = mmad_open, + .release = mmad_release, + .read = mmadp_read, + .unlocked_ioctl = mmadp_ioctl, +}; + +static struct miscdevice mmadp_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "psensor_ctrl", + .fops = &mmadp_fops, +}; +#if 0 +static void stk3310_early_suspend(struct early_suspend *h) +{ + dbg("start\n"); + mutex_lock(&mutex); + //pm_runtime_get_sync(dev); + //isl_set_mod(client, ISL_MOD_POWERDOWN); + //pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + dbg("exit\n"); +} + +static void stk3310_late_resume(struct early_suspend *h) +{ + struct i2c_client *client = l_sensorconfig->client; + + dbg("start\n"); + mutex_lock(&mutex); + //pm_runtime_get_sync(dev); + //isl_set_mod(client, last_mod); + isl_set_default_config(client); + //pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + dbg("exit\n"); +} +#endif + +static int +stk3310_probe(struct i2c_client *client/*, const struct i2c_device_id *id*/) +{ + int res=0; + + struct stk_device* idev = kzalloc(sizeof(struct stk_device), GFP_KERNEL); + if(!idev) + return -ENOMEM; + + l_sensorconfig = idev; + +/* last mod is ALS continuous */ + //pm_runtime_enable(&client->dev); + idev->input_poll_devl = input_allocate_polled_device(); + if(!idev->input_poll_devl) + { + res = -ENOMEM; + goto err_input_allocate_device; + } + idev->input_poll_devp = input_allocate_polled_device(); + if(!idev->input_poll_devp) + { + res = -ENOMEM; + goto err_input_allocate_device; + } + idev->client = client; + + idev->input_poll_devl->private = idev; + idev->input_poll_devl->poll = isl_input_lux_poll_l; + idev->input_poll_devl->poll_interval = 100;//50; + idev->input_poll_devl->input->open = isl_input_open; + idev->input_poll_devl->input->close = isl_input_close; + idev->input_poll_devl->input->name = "lsensor_lux"; + idev->input_poll_devl->input->id.bustype = BUS_I2C; + idev->input_poll_devl->input->dev.parent = &client->dev; + + input_set_drvdata(idev->input_poll_devl->input, idev); + input_set_capability(idev->input_poll_devl->input, EV_ABS, ABS_MISC); + input_set_abs_params(idev->input_poll_devl->input, ABS_MISC, 0, 16000, 0, 0); + + idev->input_poll_devp->private = idev; + idev->input_poll_devp->poll = isl_input_lux_poll_p; + idev->input_poll_devp->poll_interval = 100;//50; + idev->input_poll_devp->input->open = isl_input_open; + idev->input_poll_devp->input->close = isl_input_close; + idev->input_poll_devp->input->name = "psensor_lux"; + idev->input_poll_devp->input->id.bustype = BUS_I2C; + idev->input_poll_devp->input->dev.parent = &client->dev; + + input_set_drvdata(idev->input_poll_devp->input, idev); + input_set_capability(idev->input_poll_devp->input, EV_ABS, ABS_MISC); + input_set_abs_params(idev->input_poll_devp->input, ABS_MISC, 0, 16000, 0, 0); + i2c_set_clientdata(client, idev); + /* set default config after set_clientdata */ + res = isl_set_default_config(client); + res = misc_register(&mmadl_device); + if (res) { + errlog("mmad_device register failed\n"); + goto err_misc_registerl; + } + res = misc_register(&mmadp_device); + if (res) { + errlog("mmad_device register failed\n"); + goto err_misc_registerp; + } + res = input_register_polled_device(idev->input_poll_devl); + if(res < 0) + goto err_input_register_devicel; + res = input_register_polled_device(idev->input_poll_devp); + if(res < 0) + goto err_input_register_devicep; + // suspend/resume register +#ifdef CONFIG_HAS_EARLYSUSPEND + idev->earlysuspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + idev->earlysuspend.suspend = stk3310_early_suspend; + idev->earlysuspend.resume = stk3310_late_resume; + register_early_suspend(&(idev->earlysuspend)); +#endif + + dbg("stk3310 probe succeed!\n"); + return 0; +err_input_register_devicep: + input_free_polled_device(idev->input_poll_devp); +err_input_register_devicel: + input_free_polled_device(idev->input_poll_devl); +err_misc_registerp: + misc_deregister(&mmadp_device); +err_misc_registerl: + misc_deregister(&mmadl_device); +err_input_allocate_device: + //__pm_runtime_disable(&client->dev, false); + kfree(idev); + return res; +} + +static int stk3310_remove(struct i2c_client *client) +{ + struct stk_device* idev = i2c_get_clientdata(client); + + //unregister_early_suspend(&(idev->earlysuspend)); + misc_deregister(&mmadl_device); + misc_deregister(&mmadp_device); + input_unregister_polled_device(idev->input_poll_devl); + input_unregister_polled_device(idev->input_poll_devp); + input_free_polled_device(idev->input_poll_devl); + input_free_polled_device(idev->input_poll_devp); + //__pm_runtime_disable(&client->dev, false); + kfree(idev); + printk(KERN_INFO MODULE_NAME ": %s stk3310 remove call, \n", __func__); + return 0; +} + +//****************add platform_device & platform_driver for suspend &resume 2013-7-2 +static int ls_probe(struct platform_device *pdev){ + //printk("<<<%s\n", __FUNCTION__); + return 0; +} +static int ls_remove(struct platform_device *pdev){ + //printk("<<<%s\n", __FUNCTION__); + return 0; +} +static int ls_suspend(struct platform_device *pdev, pm_message_t state){ + printk("<<<%s\n", __FUNCTION__); + + return 0; +} + +static int ls_resume(struct platform_device *pdev){ + //return 0; + int ret = 0; + int count = 0; + + struct i2c_client *client = l_sensorconfig->client; + printk("<<<%s\n", __FUNCTION__); + +RETRY: + mutex_lock(&mutex); + + ret = isl_set_default_config(client); + + mutex_unlock(&mutex); + if (ret < 0){ + printk("%s isl_set_default_config fail!\n", __FUNCTION__); + count++; + if (count < 5){ + mdelay(2); + goto RETRY; + } + else + return ret; + } + return 0; + +} +static void lsdev_release(struct device *dev) +{ + return; +} +static struct platform_device lsdev = { + .name = "lsdevice", + .id = -1, + .dev = { + .release = lsdev_release, + }, +}; +static struct platform_driver lsdrv = { + .probe = ls_probe, + .remove = ls_remove, + .suspend = ls_suspend, + .resume = ls_resume, + .driver = { + .name = "lsdevice", + }, +}; +//******************************************************************** + + +static int __init sensor_stk3310_init(void) +{ + int ret = 0; + printk(KERN_INFO MODULE_NAME ": %s stk3310 init call, \n", __func__); + /* + * Force device to initialize: i2c-15 0x44 + * If i2c_new_device is not called, even stk3310_detect will not run + * TODO: rework to automatically initialize the device + */ + //i2c_new_device(i2c_get_adapter(15), &isl_info); + //return i2c_add_driver(&stk3310_driver); + if (!(this_client = sensor_i2c_register_device(2, SENSOR_I2C_ADDR, SENSOR_I2C_NAME))) + { + printk(KERN_EMERG"Can't register gsensor i2c device!\n"); + return -1; + } + if (stk3310_detect(this_client)) + { + errlog("Can't find light sensor stk3310!\n"); + goto detect_fail; + } + if(stk3310_probe(this_client)) + { + errlog("Erro for probe!\n"); + goto detect_fail; + } + + ret = platform_device_register(&lsdev); + if (ret){ + printk("<< +#define STK831X_I2C_NAME "stk831x" +#define ACC_IDEVICE_NAME "sensor_ctrl" +#define STKDIR 0x3D +#define STK_LSB_1G 21 +/* registers for stk8312 registers */ + +#define STK831X_XOUT 0x00 /* x-axis acceleration*/ +#define STK831X_YOUT 0x01 /* y-axis acceleration*/ +#define STK831X_ZOUT 0x02 /* z-axis acceleration*/ +#define STK831X_TILT 0x03 /* Tilt Status */ +#define STK831X_SRST 0x04 /* Sampling Rate Status */ +#define STK831X_SPCNT 0x05 /* Sleep Count */ +#define STK831X_INTSU 0x06 /* Interrupt setup*/ +#define STK831X_MODE 0x07 +#define STK831X_SR 0x08 /* Sample rate */ +#define STK831X_PDET 0x09 /* Tap Detection */ +#define STK831X_DEVID 0x0B /* Device ID */ +#define STK831X_OFSX 0x0C /* X-Axis offset */ +#define STK831X_OFSY 0x0D /* Y-Axis offset */ +#define STK831X_OFSZ 0x0E /* Z-Axis offset */ +#define STK831X_PLAT 0x0F /* Tap Latency */ +#define STK831X_PWIN 0x10 /* Tap Window */ +#define STK831X_FTH 0x11 /* Free-Fall Threshold */ +#define STK831X_FTM 0x12 /* Free-Fall Time */ +#define STK831X_STH 0x13 /* Shake Threshold */ +#define STK831X_CTRL 0x14 /* Control Register */ +#define STK831X_RESET 0x20 /*software reset*/ + +/* IOCTLs*/ +#define STK_IOCTL_WRITE _IOW(STKDIR, 0x01, char[8]) +#define STK_IOCTL_READ _IOWR(STKDIR, 0x02, char[8]) +#define STK_IOCTL_SET_ENABLE _IOW(STKDIR, 0x03, char) +#define STK_IOCTL_GET_ENABLE _IOR(STKDIR, 0x04, char) +#define STK_IOCTL_SET_DELAY _IOW(STKDIR, 0x05, char) +#define STK_IOCTL_GET_DELAY _IOR(STKDIR, 0x06, char) +#define STK_IOCTL_SET_OFFSET _IOW(STKDIR, 0x07, char[3]) +#define STK_IOCTL_GET_OFFSET _IOR(STKDIR, 0x08, char[3]) +#define STK_IOCTL_GET_ACCELERATION _IOR(STKDIR, 0x09, int[3]) +#define STK_IOCTL_SET_RANGE _IOW(STKDIR, 0x10, char) +#define STK_IOCTL_GET_RANGE _IOR(STKDIR, 0x11, char) +#define STK_IOCTL_SET_CALI _IOW(STKDIR, 0x12, char) + + +#endif diff --git a/ANDROID_3.4.5/drivers/input/sensor/stk8312_gsensor/stk8313.h b/ANDROID_3.4.5/drivers/input/sensor/stk8312_gsensor/stk8313.h new file mode 100755 index 00000000..66536ac7 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/stk8312_gsensor/stk8313.h @@ -0,0 +1,52 @@ +/* + * Definitions for Sensortek stk8313 accelerometer + */ +#ifndef _STK831X_H_ +#define _STK831X_H_ + +#include +#define STK831X_I2C_NAME "stk831x" +#define ACC_IDEVICE_NAME "accelerometer" +#define STKDIR 0x3D +#define STK_LSB_1G 256 +/* register for stk8313 registers */ + +#define STK831X_XOUT 0x00 +#define STK831X_YOUT 0x02 +#define STK831X_ZOUT 0x04 +#define STK831X_TILT 0x06 /* Tilt Status */ +#define STK831X_SRST 0x07 /* Sampling Rate Status */ +#define STK831X_SPCNT 0x08 /* Sleep Count */ +#define STK831X_INTSU 0x09 /* Interrupt setup*/ +#define STK831X_MODE 0x0A +#define STK831X_SR 0x0B /* Sample rate */ +#define STK831X_PDET 0x0C /* Tap Detection */ +#define STK831X_DEVID 0x0E /* Device ID */ +#define STK831X_OFSX 0x0F /* X-Axis offset */ +#define STK831X_OFSY 0x10 /* Y-Axis offset */ +#define STK831X_OFSZ 0x11 /* Z-Axis offset */ +#define STK831X_PLAT 0x12 /* Tap Latency */ +#define STK831X_PWIN 0x13 /* Tap Window */ +#define STK831X_FTH 0x14 /* Fre e-Fall Threshold */ +#define STK831X_FTM 0x15 /* Free-Fall Time */ +#define STK831X_STH 0x16 /* Shake Threshold */ +#define STK831X_ISTMP 0x17 /* Interrupt Setup */ +#define STK831X_INTMAP 0x18 /*Interrupt Map*/ +#define STK831X_RESET 0x20 /*software reset*/ + +/* IOCTLs*/ +#define STK_IOCTL_WRITE _IOW(STKDIR, 0x01, char[8]) +#define STK_IOCTL_READ _IOWR(STKDIR, 0x02, char[8]) +#define STK_IOCTL_SET_ENABLE _IOW(STKDIR, 0x03, char) +#define STK_IOCTL_GET_ENABLE _IOR(STKDIR, 0x04, char) +#define STK_IOCTL_SET_DELAY _IOW(STKDIR, 0x05, char) +#define STK_IOCTL_GET_DELAY _IOR(STKDIR, 0x06, char) +#define STK_IOCTL_SET_OFFSET _IOW(STKDIR, 0x07, char[3]) +#define STK_IOCTL_GET_OFFSET _IOR(STKDIR, 0x08, char[3]) +#define STK_IOCTL_GET_ACCELERATION _IOR(STKDIR, 0x09, int[3]) +#define STK_IOCTL_SET_RANGE _IOW(STKDIR, 0x10, char) +#define STK_IOCTL_GET_RANGE _IOR(STKDIR, 0x11, char) +#define STK_IOCTL_SET_CALI _IOW(STKDIR, 0x12, char) + + +#endif \ No newline at end of file diff --git a/ANDROID_3.4.5/drivers/input/sensor/stk8312_gsensor/stk831x.c b/ANDROID_3.4.5/drivers/input/sensor/stk8312_gsensor/stk831x.c new file mode 100755 index 00000000..68952f9c --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/stk8312_gsensor/stk831x.c @@ -0,0 +1,3590 @@ +/* + * stk831x.c - Linux kernel modules for sensortek stk8311/stk8312/stk8313 accelerometer + * + * Copyright (C) 2011~2013 Lex Hsieh / sensortek + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "../sensor.h" + + +//#define STK_ALLWINNER_PLATFORM +#define STK_ACC_DRIVER_VERSION "1.6.1" +/*choose polling or interrupt mode*/ +#define STK_ACC_POLLING_MODE 1 +#if (!STK_ACC_POLLING_MODE) + #define ADDITIONAL_GPIO_CFG 1 + #define STK_INT_PIN 39 +#endif +//#define STK_PERMISSION_THREAD +#define STK_RESUME_RE_INIT +//#define STK_DEBUG_PRINT +//#define STK_DEBUG_RAWDATA +//#define STK_LOWPASS +#define STK_FIR_LEN 4 + +/////////////////////////////////////// +#define CONFIG_SENSORS_STK8312//////// +///////////////////////////////////// +#define STK_ZG_FILTER +#ifdef CONFIG_SENSORS_STK8312 + #define STK_ZG_COUNT 1 +#elif defined (CONFIG_SENSORS_STK8313) + #define STK_ZG_COUNT 4 +#endif + +#define STK_TUNE +#ifdef CONFIG_SENSORS_STK8312 + #define STK_TUNE_XYOFFSET 3 + #define STK_TUNE_ZOFFSET 6 + #define STK_TUNE_NOISE 5 +#elif defined (CONFIG_SENSORS_STK8313) + #define STK_TUNE_XYOFFSET 35 + #define STK_TUNE_ZOFFSET 75 + #define STK_TUNE_NOISE 20 +#endif +#define STK_TUNE_NUM 125 +#define STK_TUNE_DELAY 125 +//Flourtise - Kevin +#define STK_WMT_PLATFORM +#ifdef STK_WMT_PLATFORM + //#define STK8312_DRVID 7 + ///////////////////////// ioctrl cmd ////////////////////////^M + #define WMTGSENSOR_IOCTL_MAGIC 0x09 + #define WMT_IOCTL_SENSOR_CAL_OFFSET _IOW(WMTGSENSOR_IOCTL_MAGIC, 0x01, int) //offset calibration^M + #define ECS_IOCTL_APP_SET_AFLAG _IOW(WMTGSENSOR_IOCTL_MAGIC, 0x02, short) + #define ECS_IOCTL_APP_SET_DELAY _IOW(WMTGSENSOR_IOCTL_MAGIC, 0x03, short) + #define WMT_IOCTL_SENSOR_GET_DRVID _IOW(WMTGSENSOR_IOCTL_MAGIC, 0x04, unsigned int) + #define WMT_IOCTL_SENOR_GET_RESOLUTION _IOR(WMTGSENSOR_IOCTL_MAGIC, 0x05, short) + +#endif +//Flourise - Kevin +#ifndef STK_WMT_PLATFORM + #ifdef CONFIG_SENSORS_STK8313 + #include + #elif defined CONFIG_SENSORS_STK8312 + #include + #else + #error "What's your stk accelerometer?" + #endif +#else + #ifdef CONFIG_SENSORS_STK8313 + #include "stk8313.h" + #elif defined CONFIG_SENSORS_STK8312 + #include "stk8312.h" + #else + #error "What's your stk accelerometer?" + #endif +#endif /* #ifndef STK_ALLWINNER_PLATFORM */ + +SYSCALL_DEFINE3(fchmodat, int, dfd, const char __user *, filename, mode_t, mode); + +static struct i2c_client *this_client = NULL; + +//add 2013-6-24 +#define GSENSOR_NAME "stk8312" +static struct class* l_dev_class = NULL; +struct stk8312_config +{ + int op; + int int_gpio; //0-3 + int xyz_axis[3][2]; // (axis,direction) + int rxyz_axis[3][2]; + int irq; + struct proc_dir_entry* sensor_proc; + int sensorlevel; + int shake_enable; // 1--enable shake, 0--disable shake + int manual_rotation; // 0--landance, 90--vertical + struct input_dev *input_dev; + //struct work_struct work; + struct delayed_work work; // for polling + struct workqueue_struct *queue; + int isdbg; // 0-- no debug log, 1--show debug log + int sensor_samp; // 1,2,4,8,16,32,64,120 + int sensor_enable; // 0 --> disable sensor, 1 --> enable sensor + int test_pass; + spinlock_t spinlock; + int pollcnt; // the counts of polling + int offset[3]; +}; + +static struct stk8312_config l_sensorconfig = { + .op = 0, + .int_gpio = 3, + .xyz_axis = { + {ABS_X, -1}, + {ABS_Y, 1}, + {ABS_Z, -1}, + }, + .irq = 6, + .int_gpio = 3, + .sensor_proc = NULL, + .sensorlevel = 0, + .shake_enable = 0, // default enable shake + .isdbg = 0, + .sensor_samp = 10, // 4sample/second + .sensor_enable = 1, // enable sensor + .test_pass = 0, // for test program + .pollcnt = 0, // Don't report the x,y,z when the driver is loaded until 2~3 seconds + .offset = {0,0,0}, +}; +//****************************************** + +#if defined(STK_LOWPASS) +#define MAX_FIR_LEN 32 +struct data_filter { + s16 raw[MAX_FIR_LEN][3]; + int sum[3]; + int num; + int idx; +}; +#endif + +struct stk831x_data +{ + struct input_dev *input_dev; + struct work_struct stk_work; + int irq; + int raw_data[3]; + atomic_t enabled; + unsigned char delay; + struct mutex write_lock; + bool first_enable; + bool re_enable; + char recv_reg; +#if STK_ACC_POLLING_MODE + struct hrtimer acc_timer; + struct work_struct stk_acc_work; + struct workqueue_struct *stk_acc_wq; + ktime_t acc_poll_delay; +#endif //#if STK_ACC_POLLING_MODE + atomic_t cali_status; +#if defined(STK_LOWPASS) + atomic_t firlength; + atomic_t fir_en; + struct data_filter fir; +#endif +}; + +#define STK831X_HOLD_ODR +#define STK831X_INIT_ODR 1//2 //2:100Hz, 3:50Hz, 4:25Hz +#define STK831X_SAMPLE_TIME_MIN_NO 2 +#define STK831X_SAMPLE_TIME_NO 5 +const static int STK831X_SAMPLE_TIME[STK831X_SAMPLE_TIME_NO] = {2500, 5000, 10000, 20000, 40000}; +static struct stk831x_data *stk831x_data_ptr; +static int event_since_en = 0; +static int event_since_en_limit = 20; +#if (!STK_ACC_POLLING_MODE) +static struct workqueue_struct *stk_mems_work_queue = NULL; +#endif //#if STK_ACC_POLLING_MODE + +#define STK_DEBUG_CALI +#define STK_SAMPLE_NO 10 +#define STK_ACC_CALI_VER0 0x3D +#define STK_ACC_CALI_VER1 0x01 +#define STK_ACC_CALI_FILE "/data/misc/stkacccali.conf" +#define STK_ACC_CALI_FILE_SIZE 10 + +#define STK_K_SUCCESS_TUNE 0x04 +#define STK_K_SUCCESS_FT2 0x03 +#define STK_K_SUCCESS_FT1 0x02 +#define STK_K_SUCCESS_FILE 0x01 +#define STK_K_NO_CALI 0xFF +#define STK_K_RUNNING 0xFE +#define STK_K_FAIL_LRG_DIFF 0xFD +#define STK_K_FAIL_OPEN_FILE 0xFC +#define STK_K_FAIL_W_FILE 0xFB +#define STK_K_FAIL_R_BACK 0xFA +#define STK_K_FAIL_R_BACK_COMP 0xF9 +#define STK_K_FAIL_I2C 0xF8 +#define STK_K_FAIL_K_PARA 0xF7 +#define STK_K_FAIL_OTP_OUT_RG 0xF6 +#define STK_K_FAIL_ENG_I2C 0xF5 +#define STK_K_FAIL_FT1_USD 0xF4 +#define STK_K_FAIL_FT2_USD 0xF3 +#define STK_K_FAIL_WRITE_NOFST 0xF2 +#define STK_K_FAIL_OTP_5T 0xF1 +#define STK_K_FAIL_PLACEMENT 0xF0 + + +#define POSITIVE_Z_UP 0 +#define NEGATIVE_Z_UP 1 +#define POSITIVE_X_UP 2 +#define NEGATIVE_X_UP 3 +#define POSITIVE_Y_UP 4 +#define NEGATIVE_Y_UP 5 +static unsigned char stk831x_placement = POSITIVE_Z_UP; +#ifdef STK_TUNE +static char stk_tune_offset_record[3] = {0}; +static int stk_tune_offset[3] = {0}; +static int stk_tune_sum[3] = {0}; +static int stk_tune_max[3] = {0}; +static int stk_tune_min[3] = {0}; +static int stk_tune_index = 0; +static int stk_tune_done = 0; +#endif + +static int stk_store_in_ic( struct stk831x_data *stk, char otp_offset[], char FT_index, uint32_t delay_ms); +static int32_t stk_get_file_content(char * r_buf, int8_t buf_size); +static int stk_store_in_file(char offset[], char mode); +static int STK831x_ReadByteOTP(char rReg, char *value); +static int STK831x_SetEnable(struct stk831x_data *stk, char en); +static int STK831x_SetCali(struct stk831x_data *stk, char sstate); +static int32_t stk_get_ic_content(struct stk831x_data *stk); +static int STK831x_SetOffset(char buf[]); +static void stk_handle_first_en(struct stk831x_data *stk); +static int STK831x_GetDelay(struct stk831x_data *stk, uint32_t* gdelay_ns); +static int STK831x_SetDelay(struct stk831x_data *stk, uint32_t sdelay_ns); + +#ifdef STK_ALLWINNER_PLATFORM +static int gsensor_direct_x = 0; +static int gsensor_direct_y = 0; +static int gsensor_direct_z = 0; +static int gsensor_xy_revert = 0; + +enum { + DEBUG_INIT = 1U << 0, + DEBUG_CONTROL_INFO = 1U << 1, + DEBUG_DATA_INFO = 1U << 2, + DEBUG_SUSPEND = 1U << 3, +}; +static u32 debug_mask = 0; +#define dprintk(level_mask, fmt, arg...) if (unlikely(debug_mask & level_mask)) \ + printk(KERN_DEBUG fmt , ## arg) + +module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP); +#endif /* #ifdef STK_ALLWINNER_PLATFORM */ + +#ifdef STK_ALLWINNER_PLATFORM +/* Addresses to scan */ +static union +{ + unsigned short dirty_addr_buf[2]; + const unsigned short normal_i2c[2]; +}u_i2c_addr = {{0x00},}; +static __u32 twi_id = 1; +#endif /* #ifdef STK_ALLWINNER_PLATFORM */ + +/** + * gsensor_fetch_sysconfig_para - get config info from sysconfig.fex file. + * return value: + * = 0; success; + * < 0; err + */ +#ifdef STK_ALLWINNER_A20_A31 +static int gsensor_fetch_sysconfig_para(void) +{ + int ret = -1; + int device_used = -1; + script_item_u val; + script_item_value_type_e type; + + dprintk(DEBUG_INIT, "========%s===================\n", __func__); + + type = script_get_item("gsensor_para", "gsensor_used", &val); + + if (SCIRPT_ITEM_VALUE_TYPE_INT != type) { + pr_err("%s: type err device_used = %d. \n", __func__, val.val); + goto script_get_err; + } + device_used = val.val; + + if (1 == device_used) { + type = script_get_item("gsensor_para", "gsensor_twi_id", &val); + if(SCIRPT_ITEM_VALUE_TYPE_INT != type){ + pr_err("%s: type err twi_id = %d. \n", __func__, val.val); + goto script_get_err; + } + twi_id = val.val; + + dprintk(DEBUG_INIT, "%s: twi_id is %d. \n", __func__, twi_id); + + if(SCIRPT_ITEM_VALUE_TYPE_INT != script_get_item("gsensor_para", "gsensor_direct_x", &val)){ + pr_err("%s: line: %d: script_get_item err. \n", __FILE__, __LINE__); + goto script_get_err; + } + gsensor_direct_x = val.val; + + if(SCIRPT_ITEM_VALUE_TYPE_INT != script_get_item("gsensor_para", "gsensor_direct_y", &val)){ + pr_err("%s: line: %d: script_get_item err. \n", __FILE__, __LINE__); + goto script_get_err; + } + gsensor_direct_y = val.val; + if(SCIRPT_ITEM_VALUE_TYPE_INT != script_get_item("gsensor_para", "gsensor_direct_z", &val)){ + pr_err("%s: line: %d: script_get_item err. \n", __FILE__, __LINE__); + goto script_get_err; + } + gsensor_direct_z = val.val; + + if(SCIRPT_ITEM_VALUE_TYPE_INT != script_get_item("gsensor_para", "gsensor_xy_revert", &val)){ + pr_err("%s: line: %d: script_get_item err. \n", __FILE__, __LINE__); + goto script_get_err; + } + gsensor_xy_revert = val.val; + + ret = 0; + + } else { + pr_err("%s: gsensor_unused. \n", __func__); + ret = -1; + } + + return ret; + +script_get_err: + pr_notice("=========script_get_err============\n"); + return ret; +} +#endif /* #ifdef STK_ALLWINNER_A20_A31 */ + +#ifdef STK_ALLWINNER_A13 +static int gsensor_fetch_sysconfig_para(void) +{ + int ret = -1; + int device_used = -1; + + printk("========%s===================\n", __func__); + + if(SCRIPT_PARSER_OK != (ret = script_parser_fetch("gsensor_para", "gsensor_used", &device_used, 1))){ + pr_err("%s: script_parser_fetch err.ret = %d. \n", __func__, ret); + goto script_parser_fetch_err; + } + if(1 == device_used){ + if(SCRIPT_PARSER_OK != script_parser_fetch("gsensor_para", "gsensor_twi_id", &twi_id, 1)){ + pr_err("%s: script_parser_fetch err. \n",__func__); + goto script_parser_fetch_err; + } + printk("%s: twi_id is %d. \n", __func__, twi_id); + + stk8313_pin_hd = gpio_request_ex("gsensor_para",NULL); + if (stk8313_pin_hd==-1) { + printk("stk8313_pin_hd pin request error!\n"); + } + ret = 0; + + }else{ + pr_err("%s: gsensor_unused. \n", __func__); + ret = -1; + } + + return ret; + + script_parser_fetch_err: + pr_notice("=========script_parser_fetch_err============\n"); + return ret; +} +#endif /* #ifdef STK_ALLWINNER_A13 */ + + + +static int STK_i2c_Rx(char *rxData, int length) +{ + uint8_t retry; + struct i2c_msg msgs[] = + { + { + .addr = this_client->addr, + .flags = 0, + .len = 1, + .buf = rxData, + }, + { + .addr = this_client->addr, + .flags = I2C_M_RD, + .len = length, + .buf = rxData, + }, + }; + + for (retry = 0; retry <= 3; retry++) + { + if (i2c_transfer(this_client->adapter, msgs, 2) > 0) + break; + else + mdelay(10); + } + + if (retry > 3) + { + printk(KERN_ERR "%s: retry over 3\n", __func__); + return -EIO; + } + else + return 0; +} + +static int STK_i2c_Tx(char *txData, int length) +{ + int retry; + struct i2c_msg msg[] = + { + { + .addr = this_client->addr, + .flags = 0, + .len = length, + .buf = txData, + }, + }; + + for (retry = 0; retry <= 3; retry++) + { + if (i2c_transfer(this_client->adapter, msg, 1) > 0) + break; + else + mdelay(10); + } + + if(*txData >= 0x21 && *txData <= 0x3E) + { + for (retry = 0; retry <= 3; retry++) + { + if (i2c_transfer(this_client->adapter, msg, 1) > 0) + break; + else + mdelay(10); + } + } + + if (retry > 3) + { + printk(KERN_ERR "%s: i2c error, retry over 3\n", __func__); + return -EIO; + } + else + return 0; +} + + +static int STK831X_SetVD(struct stk831x_data *stk) +{ + int result; + char buffer[2] = ""; + char reg24; + + msleep(2); + result = STK831x_ReadByteOTP(0x70, ®24); + if(result < 0) + { + printk(KERN_ERR "%s: read back error, result=%d\n", __func__, result); + return result; + } + + if(reg24 != 0) + { + buffer[0] = 0x24; + buffer[1] = reg24; + //printk(KERN_INFO "%s:write 0x%x to 0x24\n", __func__, buffer[1]); + result = STK_i2c_Tx(buffer, 2); + if (result < 0) + { + printk(KERN_ERR "%s:failed\n", __func__); + return result; + } + } + else + { + //printk(KERN_INFO "%s: reg24=0, do nothing\n", __func__); + return 0; + } + + buffer[0] = 0x24; + result = STK_i2c_Rx(buffer, 1); + if (result < 0) + { + printk(KERN_ERR "%s:failed\n", __func__); + return result; + } + if(buffer[0] != reg24) + { + printk(KERN_ERR "%s: error, reg24=0x%x, read=0x%x\n", __func__, reg24, buffer[0]); + return -1; + } + //printk(KERN_INFO "%s: successfully", __func__); + return 0; +} + +#ifdef STK_TUNE +static void STK831x_ResetPara(void) +{ + int ii; + for(ii=0;ii<3;ii++) + { + stk_tune_sum[ii] = 0; + stk_tune_min[ii] = 4096; + stk_tune_max[ii] = -4096; + } + return; +} + +static void STK831x_Tune(struct stk831x_data *stk, int acc[]) +{ + int ii; + char offset[3]; + char mode_reg; + int result; + char buffer[2] = ""; + + if (stk_tune_done==0) + { + if( event_since_en >= STK_TUNE_DELAY) + { + if ((abs(acc[0]) <= STK_TUNE_XYOFFSET) && (abs(acc[1]) <= STK_TUNE_XYOFFSET) + && (abs(abs(acc[2])-STK_LSB_1G) <= STK_TUNE_ZOFFSET)) + stk_tune_index++; + else + stk_tune_index = 0; + + if (stk_tune_index==0) + STK831x_ResetPara(); + else + { + for(ii=0;ii<3;ii++) + { + stk_tune_sum[ii] += acc[ii]; + if(acc[ii] > stk_tune_max[ii]) + stk_tune_max[ii] = acc[ii]; + if(acc[ii] < stk_tune_min[ii]) + stk_tune_min[ii] = acc[ii]; + } + } + + if(stk_tune_index == STK_TUNE_NUM) + { + for(ii=0;ii<3;ii++) + { + if((stk_tune_max[ii] - stk_tune_min[ii]) > STK_TUNE_NOISE) + { + stk_tune_index = 0; + STK831x_ResetPara(); + return; + } + } + buffer[0] = STK831X_MODE; + result = STK_i2c_Rx(buffer, 1); + if (result < 0) + { + printk(KERN_ERR "%s:failed, result=0x%x\n", __func__, result); + return; + } + mode_reg = buffer[0]; + buffer[1] = mode_reg & 0xF8; + buffer[0] = STK831X_MODE; + result = STK_i2c_Tx(buffer, 2); + if (result < 0) + { + printk(KERN_ERR "%s:failed, result=0x%x\n", __func__, result); + return; + } + + stk_tune_offset[0] = stk_tune_sum[0]/STK_TUNE_NUM; + stk_tune_offset[1] = stk_tune_sum[1]/STK_TUNE_NUM; + if (acc[2] > 0) + stk_tune_offset[2] = stk_tune_sum[2]/STK_TUNE_NUM - STK_LSB_1G; + else + stk_tune_offset[2] = stk_tune_sum[2]/STK_TUNE_NUM - (-STK_LSB_1G); + + offset[0] = (char) (-stk_tune_offset[0]); + offset[1] = (char) (-stk_tune_offset[1]); + offset[2] = (char) (-stk_tune_offset[2]); + STK831x_SetOffset(offset); + stk_tune_offset_record[0] = offset[0]; + stk_tune_offset_record[1] = offset[1]; + stk_tune_offset_record[2] = offset[2]; + + buffer[1] = mode_reg | 0x1; + buffer[0] = STK831X_MODE; + result = STK_i2c_Tx(buffer, 2); + if (result < 0) + { + printk(KERN_ERR "%s:failed, result=0x%x\n", __func__, result); + return; + } + + STK831X_SetVD(stk); + stk_store_in_file(offset, STK_K_SUCCESS_TUNE); + stk_tune_done = 1; + atomic_set(&stk->cali_status, STK_K_SUCCESS_TUNE); + event_since_en = 0; + printk(KERN_INFO "%s:TUNE done, %d,%d,%d\n", __func__, offset[0], offset[1],offset[2]); + } + } + } + /* + else + { + if(atomic_read(&stk->enabled)) + { + acc[0] -= stk_tune_offset[0]; + acc[1] -= stk_tune_offset[1]; + acc[2] -= stk_tune_offset[2]; + } + } + */ + // printk(KERN_INFO "%s:TUNE %4d,%4d,%4d [%d,%d,%d] %d\n", __func__, acc[0], acc[1], acc[2], stk_tune_offset[0], stk_tune_offset[1],stk_tune_offset[2],stk_tune_done); + return; +} +#endif + +#ifdef CONFIG_SENSORS_STK8312 +static int STK831x_CheckReading(int acc[], bool clear) +{ + static int check_result = 0; + + if(acc[0] == 127 || acc[0] == -128 || acc[1] == 127 || acc[1] == -128 || + acc[2] == 127 || acc[2] == -128) + { + printk(KERN_INFO "%s: acc:%o,%o,%o\n", __func__, acc[0], acc[1], acc[2]); + check_result++; + } + if(clear) + { + if(check_result == 3) + { + event_since_en_limit = 10000; + printk(KERN_INFO "%s: incorrect reading\n", __func__); + check_result = 0; + return 1; + } + check_result = 0; + } + return 0; +} +static inline int STK831x_ReadSensorData(struct stk831x_data *stk) +{ + int result; + char buffer[3] = {0}; + int acc_xyz[3] = {0}; +#ifdef STK_ZG_FILTER + s16 zero_fir = 0; +#endif +#ifdef STK_LOWPASS + int idx, firlength = atomic_read(&stk->firlength); +#endif + int k_status = atomic_read(&stk->cali_status); + memset(buffer, 0, 3); + + buffer[0] = STK831X_XOUT; + result = STK_i2c_Rx(buffer, 3); + if (result < 0) + { + printk(KERN_ERR "%s:i2c transfer error\n", __func__); + return result; + } + + if (buffer[0] & 0x80) + acc_xyz[0] = buffer[0] - 256; + else + acc_xyz[0] = buffer[0]; + if (buffer[1] & 0x80) + acc_xyz[1] = buffer[1] - 256; + else + acc_xyz[1] = buffer[1]; + if (buffer[2] & 0x80) + acc_xyz[2] = buffer[2] - 256; + else + acc_xyz[2] = buffer[2]; + +#ifdef STK_DEBUG_RAWDATA + printk(KERN_INFO "%s:RAW %4d,%4d,%4d\n", __func__, stk->raw_data[0], stk->raw_data[1], stk->raw_data[2]); +#endif + + if(event_since_en == 16 || event_since_en == 17) + STK831x_CheckReading(acc_xyz, false); + else if(event_since_en == 18) + STK831x_CheckReading(acc_xyz, true); + + if(k_status == STK_K_RUNNING) + { + stk->raw_data[0] = acc_xyz[0]; + stk->raw_data[1] = acc_xyz[1]; + stk->raw_data[2] = acc_xyz[2]; + return 0; + } + +#ifdef STK_LOWPASS //not define 2013-7-12 + if(atomic_read(&stk->fir_en)) + { + if(stk->fir.num < firlength) + { + stk->fir.raw[stk->fir.num][0] = acc_xyz[0]; + stk->fir.raw[stk->fir.num][1] = acc_xyz[1]; + stk->fir.raw[stk->fir.num][2] = acc_xyz[2]; + stk->fir.sum[0] += acc_xyz[0]; + stk->fir.sum[1] += acc_xyz[1]; + stk->fir.sum[2] += acc_xyz[2]; + stk->fir.num++; + stk->fir.idx++; + } + else + { + idx = stk->fir.idx % firlength; + stk->fir.sum[0] -= stk->fir.raw[idx][0]; + stk->fir.sum[1] -= stk->fir.raw[idx][1]; + stk->fir.sum[2] -= stk->fir.raw[idx][2]; + stk->fir.raw[idx][0] = acc_xyz[0]; + stk->fir.raw[idx][1] = acc_xyz[1]; + stk->fir.raw[idx][2] = acc_xyz[2]; + stk->fir.sum[0] += acc_xyz[0]; + stk->fir.sum[1] += acc_xyz[1]; + stk->fir.sum[2] += acc_xyz[2]; + stk->fir.idx++; + acc_xyz[0] = stk->fir.sum[0]/firlength; + acc_xyz[1] = stk->fir.sum[1]/firlength; + acc_xyz[2] = stk->fir.sum[2]/firlength; + } + } +#ifdef STK_DEBUG_RAWDATA + printk(KERN_INFO "%s:After FIR %4d,%4d,%4d\n", __func__, stk->raw_data[0], stk->raw_data[1], stk->raw_data[2]); +#endif + +#endif /* #ifdef STK_LOWPASS */ + + + +#ifdef STK_TUNE //define + if((k_status&0xF0) != 0) + STK831x_Tune(stk, acc_xyz); +#endif + +#ifdef STK_ZG_FILTER //define + if( abs(acc_xyz[0]) <= STK_ZG_COUNT) // 1 + acc_xyz[0] = (acc_xyz[0]*zero_fir); + if( abs(acc_xyz[1]) <= STK_ZG_COUNT) + acc_xyz[1] = (acc_xyz[1]*zero_fir); + if( abs(acc_xyz[2]) <= STK_ZG_COUNT) + acc_xyz[2] = (acc_xyz[2]*zero_fir); +#endif /* #ifdef STK_ZG_FILTER */ + + stk->raw_data[0] = acc_xyz[0]; + stk->raw_data[1] = acc_xyz[1]; + stk->raw_data[2] = acc_xyz[2]; + + return 0; +} + +#elif defined CONFIG_SENSORS_STK8313 +static int STK831x_CheckReading(int acc[], bool clear) +{ + static int check_result = 0; + + if(acc[0] == 2047 || acc[0] == -2048 || acc[1] == 2047 || acc[1] == -2048 || + acc[2] == 2047 || acc[2] == -2048) + { + printk(KERN_INFO "%s: acc:%o,%o,%o\n", __func__, acc[0], acc[1], acc[2]); + check_result++; + } + if(clear) + { + if(check_result == 3) + { + event_since_en_limit = 10000; + printk(KERN_INFO "%s: incorrect reading\n", __func__); + check_result = 0; + return 1; + } + check_result = 0; + } + return 0; +} +static int STK831x_ReadSensorData(struct stk831x_data *stk) +{ + int result; + char buffer[6] = ""; + int acc_xyz[3] = {0}; +#ifdef STK_ZG_FILTER + s16 zero_fir = 0; +#endif +#ifdef STK_LOWPASS + int idx, firlength = atomic_read(&stk->firlength); +#endif + int k_status = atomic_read(&stk->cali_status); + + memset(buffer, 0, 6); + buffer[0] = STK831X_XOUT; + result = STK_i2c_Rx(buffer, 6); + if (result < 0) + { + printk(KERN_ERR "%s:i2c transfer error\n", __func__); + return result; + } + + if (buffer[0] & 0x80) + acc_xyz[0] = ((int)buffer[0]<<4) + (buffer[1]>>4) - 4096; + else + acc_xyz[0] = ((int)buffer[0]<<4) + (buffer[1]>>4); + if (buffer[2] & 0x80) + acc_xyz[1] = ((int)buffer[2]<<4) + (buffer[3]>>4) - 4096; + else + acc_xyz[1] = ((int)buffer[2]<<4) + (buffer[3]>>4); + if (buffer[4] & 0x80) + acc_xyz[2] = ((int)buffer[4]<<4) + (buffer[5]>>4) - 4096; + else + acc_xyz[2] = ((int)buffer[4]<<4) + (buffer[5]>>4); + +#ifdef STK_DEBUG_RAWDATA + printk(KERN_INFO "%s:RAW %4d,%4d,%4d\n", __func__, stk->raw_data[0], stk->raw_data[1], stk->raw_data[2]); +#endif + + if(event_since_en == 16 || event_since_en == 17) + STK831x_CheckReading(acc_xyz, false); + else if(event_since_en == 18) + STK831x_CheckReading(acc_xyz, true); + if(k_status == STK_K_RUNNING) + { + stk->raw_data[0] = acc_xyz[0]; + stk->raw_data[1] = acc_xyz[1]; + stk->raw_data[2] = acc_xyz[2]; + return 0; + } + +#ifdef STK_LOWPASS + if(atomic_read(&stk->fir_en)) + { + if(stk->fir.num < firlength) + { + stk->fir.raw[stk->fir.num][0] = acc_xyz[0]; + stk->fir.raw[stk->fir.num][1] = acc_xyz[1]; + stk->fir.raw[stk->fir.num][2] = acc_xyz[2]; + stk->fir.sum[0] += acc_xyz[0]; + stk->fir.sum[1] += acc_xyz[1]; + stk->fir.sum[2] += acc_xyz[2]; + stk->fir.num++; + stk->fir.idx++; + } + else + { + idx = stk->fir.idx % firlength; + stk->fir.sum[0] -= stk->fir.raw[idx][0]; + stk->fir.sum[1] -= stk->fir.raw[idx][1]; + stk->fir.sum[2] -= stk->fir.raw[idx][2]; + stk->fir.raw[idx][0] = acc_xyz[0]; + stk->fir.raw[idx][1] = acc_xyz[1]; + stk->fir.raw[idx][2] = acc_xyz[2]; + stk->fir.sum[0] += acc_xyz[0]; + stk->fir.sum[1] += acc_xyz[1]; + stk->fir.sum[2] += acc_xyz[2]; + stk->fir.idx++; + acc_xyz[0] = stk->fir.sum[0]/firlength; + acc_xyz[1] = stk->fir.sum[1]/firlength; + acc_xyz[2] = stk->fir.sum[2]/firlength; + } + } +#ifdef STK_DEBUG_RAWDATA + printk(KERN_INFO "%s:After FIR %4d,%4d,%4d\n", __func__, stk->raw_data[0], stk->raw_data[1], stk->raw_data[2]); +#endif + +#endif /* #ifdef STK_LOWPASS */ + + +#ifdef STK_TUNE + if((k_status&0xF0) != 0) + STK831x_Tune(stk, acc_xyz); +#endif + +#ifdef STK_ZG_FILTER + if( abs(acc_xyz[0]) <= STK_ZG_COUNT) + acc_xyz[0] = (acc_xyz[0]*zero_fir); + if( abs(acc_xyz[1]) <= STK_ZG_COUNT) + acc_xyz[1] = (acc_xyz[1]*zero_fir); + if( abs(acc_xyz[2]) <= STK_ZG_COUNT) + acc_xyz[2] = (acc_xyz[2]*zero_fir); +#endif /* #ifdef STK_ZG_FILTER */ + + stk->raw_data[0] = acc_xyz[0]; + stk->raw_data[1] = acc_xyz[1]; + stk->raw_data[2] = acc_xyz[2]; + + return 0; +} +#endif + +static int STK831x_ReportValue(struct stk831x_data *stk) +{ + //int tmp = 0; + int rxyz[3] = {0}; +#if 1//comment 2013-8-15 + if(event_since_en < 1200) + { + event_since_en++; + if(event_since_en < 12) + return 0; + } +#endif +//add by gandy + //gsensor_direct_x = 0; +#if 0 + if (gsensor_direct_x == 1) + stk->raw_data[0] = -stk->raw_data[0]; + + //gsensor_direct_y = 1; + if (gsensor_direct_y == 1) + stk->raw_data[1] = -stk->raw_data[1]; + + gsensor_direct_z = 1; + if (gsensor_direct_z == 1) + stk->raw_data[2] = -stk->raw_data[2]; + + if (gsensor_xy_revert == 1) + { + tmp = stk->raw_data[0]; + stk->raw_data[0] = stk->raw_data[1]; + stk->raw_data[1] = tmp; + } +#endif +//end add + //add coord + //printk("x,y,z(%d,%d,%d)\n", stk->raw_data[0], stk->raw_data[1], stk->raw_data[2]); + rxyz[0] = stk->raw_data[0]; + rxyz[1] = stk->raw_data[1]; + rxyz[2] = stk->raw_data[2]; + stk->raw_data[0] = rxyz[l_sensorconfig.xyz_axis[0][0]]*l_sensorconfig.xyz_axis[0][1]; + stk->raw_data[1] = rxyz[l_sensorconfig.xyz_axis[1][0]]*l_sensorconfig.xyz_axis[1][1]; + stk->raw_data[2] = rxyz[l_sensorconfig.xyz_axis[2][0]]*l_sensorconfig.xyz_axis[2][1]; + + +#if 0 + stk->raw_data[0] = stk->raw_data[0]*9800*100/2133; //add for stk8132 21.34 + stk->raw_data[1] = stk->raw_data[1]*9800*100/2133; + stk->raw_data[2] = stk->raw_data[2]*9800*100/2133; +#endif + + +#ifdef STK_DEBUG_PRINT + printk(KERN_INFO "%s:%4d,%4d,%4d\n", __func__, stk->raw_data[0], stk->raw_data[1], stk->raw_data[2]); +#endif + input_report_abs(stk->input_dev, ABS_X, stk->raw_data[0]); + input_report_abs(stk->input_dev, ABS_Y, stk->raw_data[1]); + input_report_abs(stk->input_dev, ABS_Z, stk->raw_data[2]); + + //printk(" after x,y,z(%d,%d,%d)\n", stk->raw_data[0], stk->raw_data[1], stk->raw_data[2]); + input_sync(stk->input_dev); + return 0; +} + +static int STK831x_SetOffset(char buf[]) +{ + int result; + char buffer[4] = ""; + + buffer[0] = STK831X_OFSX; + buffer[1] = buf[0]; + buffer[2] = buf[1]; + buffer[3] = buf[2]; + result = STK_i2c_Tx(buffer, 4); + if (result < 0) + { + printk(KERN_ERR "%s:failed\n", __func__); + return result; + } + return 0; +} + +static int STK831x_GetOffset(char buf[]) +{ + int result; + char buffer[3] = ""; + + buffer[0] = STK831X_OFSX; + result = STK_i2c_Rx(buffer, 3); + if (result < 0) + { + printk(KERN_ERR "%s:failed\n", __func__); + return result; + } + buf[0] = buffer[0]; + buf[1] = buffer[1]; + buf[2] = buffer[2]; + return 0; +} + +static int STK831x_SetEnable(struct stk831x_data *stk, char en) +{ + int result; + char buffer[2] = ""; + int new_enabled = (en)?1:0; + int k_status = atomic_read(&stk->cali_status); + + if(new_enabled == atomic_read(&stk->enabled)) + return 0; + printk(KERN_INFO "%s:%x\n", __func__, en); + + //mutex_lock(&stk->write_lock); + if(stk->first_enable && k_status != STK_K_RUNNING) + stk_handle_first_en(stk); + + mutex_lock(&stk->write_lock); + buffer[0] = STK831X_MODE; + result = STK_i2c_Rx(buffer, 1); + if (result < 0) + { + printk(KERN_ERR "%s:failed\n", __func__); + goto e_err_i2c; + } + if(en) + { + buffer[1] = (buffer[0] & 0xF8) | 0x01; + event_since_en = 0; +#ifdef STK_TUNE + if((k_status&0xF0) != 0 && stk_tune_done == 0) + { + stk_tune_index = 0; + STK831x_ResetPara(); + } +#endif + } + else + buffer[1] = (buffer[0] & 0xF8); + + buffer[0] = STK831X_MODE; + result = STK_i2c_Tx(buffer, 2); + if (result < 0) + { + printk(KERN_ERR "%s:failed\n", __func__); + goto e_err_i2c; + } + mutex_unlock(&stk->write_lock); + + if(stk->first_enable && k_status != STK_K_RUNNING) + { + stk->first_enable = false; + msleep(2); + result = stk_get_ic_content(stk); + } + if(en) + { + STK831X_SetVD(stk); +#if STK_ACC_POLLING_MODE + hrtimer_start(&stk->acc_timer, stk->acc_poll_delay, HRTIMER_MODE_REL); +#else + enable_irq((unsigned int)stk->irq); +#endif //#if STK_ACC_POLLING_MODE + } + else + { +#if STK_ACC_POLLING_MODE + hrtimer_cancel(&stk->acc_timer); + cancel_work_sync(&stk->stk_acc_work); +#else + disable_irq((unsigned int)stk->irq); +#endif //#if STK_ACC_POLLING_MODE + } + //mutex_unlock(&stk->write_lock); + atomic_set(&stk->enabled, new_enabled); + return 0; + +e_err_i2c: + mutex_unlock(&stk->write_lock); + return result; +} + +static int STK831x_GetEnable(struct stk831x_data *stk, char* gState) +{ + *gState = atomic_read(&stk->enabled); + return 0; +} + +static int STK831x_SetDelay(struct stk831x_data *stk, uint32_t sdelay_ns) +{ + unsigned char sr_no; + int result; + char buffer[2] = ""; + uint32_t sdelay_us = sdelay_ns / 1000; + + for(sr_no=(STK831X_SAMPLE_TIME_NO-1);sr_no>0;sr_no--) + { + if(sdelay_us >= STK831X_SAMPLE_TIME[sr_no]) + break; + } + if(sr_no < STK831X_SAMPLE_TIME_MIN_NO) + sr_no = STK831X_SAMPLE_TIME_MIN_NO; + +#ifdef STK831X_HOLD_ODR + sr_no = STK831X_INIT_ODR; +#endif + +#ifdef STK_DEBUG_PRINT +#ifdef STK831X_HOLD_ODR + printk(KERN_INFO "%s:sdelay_us=%d, Hold delay = %d\n", __func__, sdelay_us, STK831X_SAMPLE_TIME[STK831X_INIT_ODR]); +#else + printk(KERN_INFO "%s:sdelay_us=%d\n", __func__, sdelay_us); +#endif +#endif + mutex_lock(&stk->write_lock); + if(stk->delay == sr_no) + { + mutex_unlock(&stk->write_lock); + return 0; + } + buffer[0] = STK831X_SR; + result = STK_i2c_Rx(buffer, 1); + if (result < 0) + { + printk(KERN_ERR "%s:failed\n", __func__); + goto d_err_i2c; + } + + buffer[1] = (buffer[0] & 0xF8) | ((sr_no & 0x07)); + buffer[0] = STK831X_SR; + result = STK_i2c_Tx(buffer, 2); + if (result < 0) + { + printk(KERN_ERR "%s:failed\n", __func__); + goto d_err_i2c; + } + stk->delay = sr_no; +#if STK_ACC_POLLING_MODE + stk->acc_poll_delay = ns_to_ktime(STK831X_SAMPLE_TIME[sr_no]*USEC_PER_MSEC); +#endif + +#if defined(STK_LOWPASS) + stk->fir.num = 0; + stk->fir.idx = 0; + stk->fir.sum[0] = 0; + stk->fir.sum[1] = 0; + stk->fir.sum[2] = 0; +#endif + mutex_unlock(&stk->write_lock); + + return 0; +d_err_i2c: + mutex_unlock(&stk->write_lock); + return result; +} + +static int STK831x_GetDelay(struct stk831x_data *stk, uint32_t *gdelay_ns) +{ + int result; + char buffer[2] = ""; + + mutex_lock(&stk->write_lock); + buffer[0] = STK831X_SR; + result = STK_i2c_Rx(buffer, 1); + if (result < 0) + { + mutex_unlock(&stk->write_lock); + printk(KERN_ERR "%s:failed\n", __func__); + return result; + } + mutex_unlock(&stk->write_lock); + *gdelay_ns = (uint32_t) STK831X_SAMPLE_TIME[(int)buffer[0]] * 1000; + return 0; +} + + +static int STK831x_SetRange(char srange) +{ + int result; + char buffer[2] = ""; +#ifdef STK_DEBUG_PRINT + printk(KERN_INFO "%s:range=0x%x\n", __func__, srange); +#endif + + if(srange >= 3) + { + printk(KERN_ERR "%s:parameter out of range\n", __func__); + return -1; + } + + buffer[0] = STK831X_STH; + result = STK_i2c_Rx(buffer, 1); + if (result < 0) + { + printk(KERN_ERR "%s:failed\n", __func__); + return result; + } + + buffer[1] = (buffer[0] & 0x3F) | srange<<6; + buffer[0] = STK831X_STH; + result = STK_i2c_Tx(buffer, 2); + if (result < 0) + { + printk(KERN_ERR "%s:failed\n", __func__); + return result; + } + return 0; +} + +static int STK831x_GetRange(char* grange) +{ + int result; + char buffer = 0; + + buffer = STK831X_STH; + result = STK_i2c_Rx(&buffer, 1); + if (result < 0) + { + printk(KERN_ERR "%s:failed\n", __func__); + return result; + } + *grange = buffer >> 6; + return 0; +} + +static int STK831x_ReadByteOTP(char rReg, char *value) +{ + int redo = 0; + int result; + char buffer[2] = ""; + *value = 0; + + buffer[0] = 0x3D; + buffer[1] = rReg; + result = STK_i2c_Tx(buffer, 2); + if (result < 0) + { + printk(KERN_ERR "%s:failed\n", __func__); + goto eng_i2c_r_err; + } + buffer[0] = 0x3F; + buffer[1] = 0x02; + result = STK_i2c_Tx(buffer, 2); + if (result < 0) + { + printk(KERN_ERR "%s:failed\n", __func__); + goto eng_i2c_r_err; + } + + do { + msleep(2); + buffer[0] = 0x3F; + result = STK_i2c_Rx(buffer, 1); + if (result < 0) + { + printk(KERN_ERR "%s:failed\n", __func__); + goto eng_i2c_r_err; + } + if(buffer[0]& 0x80) + { + break; + } + redo++; + }while(redo < 10); + + if(redo == 10) + { + printk(KERN_ERR "%s:OTP read repeat read 10 times! Failed!\n", __func__); + return -STK_K_FAIL_OTP_5T; + } + buffer[0] = 0x3E; + result = STK_i2c_Rx(buffer, 1); + if (result < 0) + { + printk(KERN_ERR "%s:failed\n", __func__); + goto eng_i2c_r_err; + } + *value = buffer[0]; +#ifdef STK_DEBUG_CALI + printk(KERN_INFO "%s: read 0x%x=0x%x\n", __func__, rReg, *value); +#endif + return 0; + +eng_i2c_r_err: + return -STK_K_FAIL_ENG_I2C; +} + +static int STK831x_WriteByteOTP(char wReg, char value) +{ + int finish_w_check = 0; + int result; + char buffer[2] = ""; + char read_back, value_xor = value; + int re_write = 0; + + do + { + finish_w_check = 0; + buffer[0] = 0x3D; + buffer[1] = wReg; + result = STK_i2c_Tx(buffer, 2); + if (result < 0) + { + printk(KERN_ERR "%s:failed, err=0x%x\n", __func__, result); + goto eng_i2c_w_err; + } + buffer[0] = 0x3E; + buffer[1] = value_xor; + result = STK_i2c_Tx(buffer, 2); + if (result < 0) + { + printk(KERN_ERR "%s:failed, err=0x%x\n", __func__, result); + goto eng_i2c_w_err; + } + buffer[0] = 0x3F; + buffer[1] = 0x01; + result = STK_i2c_Tx(buffer, 2); + if (result < 0) + { + printk(KERN_ERR "%s:failed, err=0x%x\n", __func__, result); + goto eng_i2c_w_err; + } + + do + { + msleep(1); + buffer[0] = 0x3F; + result = STK_i2c_Rx(buffer, 1); + if (result < 0) + { + printk(KERN_ERR "%s:failed, err=0x%x\n", __func__, result); + goto eng_i2c_w_err; + } + if(buffer[0]& 0x80) + { + result = STK831x_ReadByteOTP(wReg, &read_back); + if(result < 0) + { + printk(KERN_ERR "%s: read back error, result=%d\n", __func__, result); + goto eng_i2c_w_err; + } + + if(read_back == value) + { +#ifdef STK_DEBUG_CALI + printk(KERN_INFO "%s: write 0x%x=0x%x successfully\n", __func__, wReg, value); +#endif + re_write = 0xFF; + break; + } + else + { + printk(KERN_ERR "%s: write 0x%x=0x%x, read 0x%x=0x%x, try again\n", __func__, wReg, value_xor, wReg, read_back); + value_xor = read_back ^ value; + re_write++; + break; + } + } + finish_w_check++; + } while (finish_w_check < 5); + } while(re_write < 10); + + if(re_write == 10) + { + printk(KERN_ERR "%s: write 0x%x fail, read=0x%x, write=0x%x, target=0x%x\n", __func__, wReg, read_back, value_xor, value); + return -STK_K_FAIL_OTP_5T; + } + + return 0; + +eng_i2c_w_err: + return -STK_K_FAIL_ENG_I2C; +} + +static int STK831x_WriteOffsetOTP(struct stk831x_data *stk, int FT, char offsetData[]) +{ + char regR[6], reg_comp[3]; + char mode; + int result; + char buffer[2] = ""; + int ft_pre_trim = 0; + + if(FT==1) + { + result = STK831x_ReadByteOTP(0x7F, ®R[0]); + if(result < 0) + goto eng_i2c_err; + + if(regR[0]&0x10) + { + printk(KERN_ERR "%s: 0x7F=0x%x\n", __func__, regR[0]); + return -STK_K_FAIL_FT1_USD; + } + } + else if (FT == 2) + { + result = STK831x_ReadByteOTP(0x7F, ®R[0]); + if(result < 0) + goto eng_i2c_err; + + if(regR[0]&0x20) + { + printk(KERN_ERR "%s: 0x7F=0x%x\n", __func__, regR[0]); + return -STK_K_FAIL_FT2_USD; + } + } +//Check End + + buffer[0] = STK831X_MODE; + result = STK_i2c_Rx(buffer, 1); + if (result < 0) + { + goto common_i2c_error; + } + mode = buffer[0]; + buffer[1] = (mode | 0x01); + buffer[0] = STK831X_MODE; + result = STK_i2c_Tx(buffer, 2); + if (result < 0) + { + goto common_i2c_error; + } + msleep(2); + + + if(FT == 1) + { + result = STK831x_ReadByteOTP(0x40, ®_comp[0]); + if(result < 0) + goto eng_i2c_err; + result = STK831x_ReadByteOTP(0x41, ®_comp[1]); + if(result < 0) + goto eng_i2c_err; + result = STK831x_ReadByteOTP(0x42, ®_comp[2]); + if(result < 0) + goto eng_i2c_err; + } + else if (FT == 2) + { + result = STK831x_ReadByteOTP(0x50, ®_comp[0]); + if(result < 0) + goto eng_i2c_err; + result = STK831x_ReadByteOTP(0x51, ®_comp[1]); + if(result < 0) + goto eng_i2c_err; + result = STK831x_ReadByteOTP(0x52, ®_comp[2]); + if(result < 0) + goto eng_i2c_err; + } + + result = STK831x_ReadByteOTP(0x30, ®R[0]); + if(result < 0) + goto eng_i2c_err; + result = STK831x_ReadByteOTP(0x31, ®R[1]); + if(result < 0) + goto eng_i2c_err; + result = STK831x_ReadByteOTP(0x32, ®R[2]); + if(result < 0) + goto eng_i2c_err; + + if(reg_comp[0] == regR[0] && reg_comp[1] == regR[1] && reg_comp[2] == regR[2]) + { + printk(KERN_INFO "%s: ft pre-trimmed\n", __func__); + ft_pre_trim = 1; + } + + if(!ft_pre_trim) + { + if(FT == 1) + { + result = STK831x_WriteByteOTP(0x40, regR[0]); + if(result < 0) + goto eng_i2c_err; + result = STK831x_WriteByteOTP(0x41, regR[1]); + if(result < 0) + goto eng_i2c_err; + result = STK831x_WriteByteOTP(0x42, regR[2]); + if(result < 0) + goto eng_i2c_err; + } + else if (FT == 2) + { + result = STK831x_WriteByteOTP(0x50, regR[0]); + if(result < 0) + goto eng_i2c_err; + result = STK831x_WriteByteOTP(0x51, regR[1]); + if(result < 0) + goto eng_i2c_err; + result = STK831x_WriteByteOTP(0x52, regR[2]); + if(result < 0) + goto eng_i2c_err; + } + } +#ifdef STK_DEBUG_CALI + printk(KERN_INFO "%s:OTP step1 Success!\n", __func__); +#endif + buffer[0] = 0x2A; + result = STK_i2c_Rx(buffer, 1); + if (result < 0) + { + goto common_i2c_error; + } + else + { + regR[0] = buffer[0]; + } + buffer[0] = 0x2B; + result = STK_i2c_Rx(buffer, 1); + if (result < 0) + { + goto common_i2c_error; + } + else + { + regR[1] = buffer[0]; + } + buffer[0] = 0x2E; + result = STK_i2c_Rx(buffer, 1); + if (result < 0) + { + goto common_i2c_error; + } + else + { + regR[2] = buffer[0]; + } + buffer[0] = 0x2F; + result = STK_i2c_Rx(buffer, 1); + if (result < 0) + { + goto common_i2c_error; + } + else + { + regR[3] = buffer[0]; + } + buffer[0] = 0x32; + result = STK_i2c_Rx(buffer, 1); + if (result < 0) + { + goto common_i2c_error; + } + else + { + regR[4] = buffer[0]; + } + buffer[0] = 0x33; + result = STK_i2c_Rx(buffer, 1); + if (result < 0) + { + goto common_i2c_error; + } + else + { + regR[5] = buffer[0]; + } + + regR[1] = offsetData[0]; + regR[3] = offsetData[2]; + regR[5] = offsetData[1]; + if(FT==1) + { + result = STK831x_WriteByteOTP(0x44, regR[1]); + if(result < 0) + goto eng_i2c_err; + result = STK831x_WriteByteOTP(0x46, regR[3]); + if(result < 0) + goto eng_i2c_err; + result = STK831x_WriteByteOTP(0x48, regR[5]); + if(result < 0) + goto eng_i2c_err; + + if(!ft_pre_trim) + { + result = STK831x_WriteByteOTP(0x43, regR[0]); + if(result < 0) + goto eng_i2c_err; + result = STK831x_WriteByteOTP(0x45, regR[2]); + if(result < 0) + goto eng_i2c_err; + result = STK831x_WriteByteOTP(0x47, regR[4]); + if(result < 0) + goto eng_i2c_err; + } + } + else if (FT == 2) + { + result = STK831x_WriteByteOTP(0x54, regR[1]); + if(result < 0) + goto eng_i2c_err; + result = STK831x_WriteByteOTP(0x56, regR[3]); + if(result < 0) + goto eng_i2c_err; + result = STK831x_WriteByteOTP(0x58, regR[5]); + if(result < 0) + goto eng_i2c_err; + + if(!ft_pre_trim) + { + result = STK831x_WriteByteOTP(0x53, regR[0]); + if(result < 0) + goto eng_i2c_err; + result = STK831x_WriteByteOTP(0x55, regR[2]); + if(result < 0) + goto eng_i2c_err; + result = STK831x_WriteByteOTP(0x57, regR[4]); + if(result < 0) + goto eng_i2c_err; + } + } +#ifdef STK_DEBUG_CALI + printk(KERN_INFO "%s:OTP step2 Success!\n", __func__); +#endif + result = STK831x_ReadByteOTP(0x7F, ®R[0]); + if(result < 0) + goto eng_i2c_err; + + if(FT==1) + regR[0] = regR[0]|0x10; + else if(FT==2) + regR[0] = regR[0]|0x20; + + result = STK831x_WriteByteOTP(0x7F, regR[0]); + if(result < 0) + goto eng_i2c_err; +#ifdef STK_DEBUG_CALI + printk(KERN_INFO "%s:OTP step3 Success!\n", __func__); +#endif + return 0; + +eng_i2c_err: + printk(KERN_ERR "%s: read/write eng i2c error, result=0x%x\n", __func__, result); + return result; + +common_i2c_error: + printk(KERN_ERR "%s: read/write common i2c error, result=0x%x\n", __func__, result); + return result; +} + +static int STK831X_VerifyCali(struct stk831x_data *stk, unsigned char en_dis, uint32_t delay_ms) +{ + unsigned char axis, state; + int acc_ave[3] = {0, 0, 0}; + const unsigned char verify_sample_no = 3; +#ifdef CONFIG_SENSORS_STK8313 + const unsigned char verify_diff = 25; +#elif defined CONFIG_SENSORS_STK8312 + const unsigned char verify_diff = 2; +#endif + int result; + char buffer[2] = ""; + int ret = 0; + + if(en_dis) + { + STK831x_SetDelay(stk, 10000000); + buffer[0] = STK831X_MODE; + result = STK_i2c_Rx(buffer, 1); + if (result < 0) + { + printk(KERN_ERR "%s:failed, result=0x%x\n", __func__, result); + return -STK_K_FAIL_I2C; + } + buffer[1] = (buffer[0] & 0xF8) | 0x01; + buffer[0] = STK831X_MODE; + result = STK_i2c_Tx(buffer, 2); + if (result < 0) + { + printk(KERN_ERR "%s:failed, result=0x%x\n", __func__, result); + return -STK_K_FAIL_I2C; + } + STK831X_SetVD(stk); + msleep(delay_ms*15); + } + + for(state=0;stateraw_data[axis]; +#ifdef STK_DEBUG_CALI + printk(KERN_INFO "%s: acc=%d,%d,%d\n", __func__, stk->raw_data[0], stk->raw_data[1], stk->raw_data[2]); +#endif + msleep(delay_ms); + } + + for(axis=0;axis<3;axis++) + acc_ave[axis] /= verify_sample_no; + + switch(stk831x_placement) + { + case POSITIVE_X_UP: + acc_ave[0] -= STK_LSB_1G; + break; + case NEGATIVE_X_UP: + acc_ave[0] += STK_LSB_1G; + break; + case POSITIVE_Y_UP: + acc_ave[1] -= STK_LSB_1G; + break; + case NEGATIVE_Y_UP: + acc_ave[1] += STK_LSB_1G; + break; + case POSITIVE_Z_UP: + acc_ave[2] -= STK_LSB_1G; + break; + case NEGATIVE_Z_UP: + acc_ave[2] += STK_LSB_1G; + break; + default: + printk("%s: invalid stk831x_placement=%d\n", __func__, stk831x_placement); + ret = -STK_K_FAIL_PLACEMENT; + break; + } + if(abs(acc_ave[0]) > verify_diff || abs(acc_ave[1]) > verify_diff || abs(acc_ave[2]) > verify_diff) + { + printk(KERN_INFO "%s:Check data x:%d, y:%d, z:%d\n", __func__,acc_ave[0],acc_ave[1],acc_ave[2]); + printk(KERN_ERR "%s:Check Fail, Calibration Fail\n", __func__); + ret = -STK_K_FAIL_LRG_DIFF; + } +#ifdef STK_DEBUG_CALI + else + printk(KERN_INFO "%s:Check data pass\n", __func__); +#endif + if(en_dis) + { + buffer[0] = STK831X_MODE; + result = STK_i2c_Rx(buffer, 1); + if (result < 0) + { + printk(KERN_ERR "%s:failed, result=0x%x\n", __func__, result); + return -STK_K_FAIL_I2C; + } + buffer[1] = (buffer[0] & 0xF8); + buffer[0] = STK831X_MODE; + result = STK_i2c_Tx(buffer, 2); + if (result < 0) + { + printk(KERN_ERR "%s:failed, result=0x%x\n", __func__, result); + return -STK_K_FAIL_I2C; + } + } + + return ret; +} + + +static int STK831x_SetCali(struct stk831x_data *stk, char sstate) +{ + char org_enable; + int acc_ave[3] = {0, 0, 0}; + int state, axis; + int new_offset[3]; + char char_offset[3] = {0}; + int result; + char buffer[2] = ""; + char reg_offset[3] = {0}; + char store_location = sstate; + uint32_t gdelay_ns, real_delay_ms; + char offset[3]; + + atomic_set(&stk->cali_status, STK_K_RUNNING); + //sstate=1, STORE_OFFSET_IN_FILE + //sstate=2, STORE_OFFSET_IN_IC +#ifdef STK_DEBUG_CALI + printk(KERN_INFO "%s:store_location=%d\n", __func__, store_location); +#endif + if((store_location != 3 && store_location != 2 && store_location != 1) || (stk831x_placement < 0 || stk831x_placement > 5) ) + { + printk(KERN_ERR "%s, invalid parameters\n", __func__); + atomic_set(&stk->cali_status, STK_K_FAIL_K_PARA); + return -STK_K_FAIL_K_PARA; + } + STK831x_GetDelay(stk, &gdelay_ns); + STK831x_GetEnable(stk, &org_enable); + if(org_enable) + STK831x_SetEnable(stk, 0); + STK831x_SetDelay(stk, 10000000); + msleep(1); + STK831x_GetDelay(stk, &real_delay_ms); + real_delay_ms = (real_delay_ms + (NSEC_PER_MSEC / 2)) / NSEC_PER_MSEC; + printk(KERN_INFO "%s: delay =%d ms\n", __func__, real_delay_ms); + + STK831x_SetOffset(reg_offset); + buffer[0] = STK831X_MODE; + result = STK_i2c_Rx(buffer, 1); + if (result < 0) + { + goto err_i2c_rw; + } + buffer[1] = (buffer[0] & 0xF8) | 0x01; + buffer[0] = STK831X_MODE; + result = STK_i2c_Tx(buffer, 2); + if (result < 0) + { + goto err_i2c_rw; + } + + STK831X_SetVD(stk); + if(store_location >= 2) + { + buffer[0] = 0x2B; + buffer[1] = 0x0; + result = STK_i2c_Tx(buffer, 2); + if (result < 0) + { + goto err_i2c_rw; + } + buffer[0] = 0x2F; + buffer[1] = 0x0; + result = STK_i2c_Tx(buffer, 2); + if (result < 0) + { + goto err_i2c_rw; + } + buffer[0] = 0x33; + buffer[1] = 0x0; + result = STK_i2c_Tx(buffer, 2); + if (result < 0) + { + goto err_i2c_rw; + } + } + + msleep(real_delay_ms*20); + for(state=0;stateraw_data[axis]; +#ifdef STK_DEBUG_CALI + printk(KERN_INFO "%s: acc=%d,%d,%d\n", __func__, stk->raw_data[0], stk->raw_data[1], stk->raw_data[2]); +#endif + msleep(real_delay_ms); + } + buffer[0] = STK831X_MODE; + result = STK_i2c_Rx(buffer, 1); + if (result < 0) + { + goto err_i2c_rw; + } + buffer[1] = (buffer[0] & 0xF8); + buffer[0] = STK831X_MODE; + result = STK_i2c_Tx(buffer, 2); + if (result < 0) + { + goto err_i2c_rw; + } + + for(axis=0;axis<3;axis++) + { + if(acc_ave[axis] >= 0) + acc_ave[axis] = (acc_ave[axis] + STK_SAMPLE_NO / 2) / STK_SAMPLE_NO; + else + acc_ave[axis] = (acc_ave[axis] - STK_SAMPLE_NO / 2) / STK_SAMPLE_NO; + + } + if(acc_ave[2] <= -1) + stk831x_placement = NEGATIVE_Z_UP; + else if((acc_ave[2] >= 1)) + stk831x_placement = POSITIVE_Z_UP; +#ifdef STK_DEBUG_CALI + printk(KERN_INFO "%s:stk831x_placement=%d\n", __func__, stk831x_placement); +#endif + + switch(stk831x_placement) + { + case POSITIVE_X_UP: + acc_ave[0] -= STK_LSB_1G; + break; + case NEGATIVE_X_UP: + acc_ave[0] += STK_LSB_1G; + break; + case POSITIVE_Y_UP: + acc_ave[1] -= STK_LSB_1G; + break; + case NEGATIVE_Y_UP: + acc_ave[1] += STK_LSB_1G; + break; + case POSITIVE_Z_UP: + acc_ave[2] -= STK_LSB_1G; + break; + case NEGATIVE_Z_UP: + acc_ave[2] += STK_LSB_1G; + break; + default: + printk("%s: invalid stk831x_placement=%d\n", __func__, stk831x_placement); + atomic_set(&stk->cali_status, STK_K_FAIL_PLACEMENT); + return -STK_K_FAIL_K_PARA; + break; + } + + for(axis=0;axis<3;axis++) + { + acc_ave[axis] = -acc_ave[axis]; + new_offset[axis] = acc_ave[axis]; + char_offset[axis] = new_offset[axis]; + } +#ifdef STK_DEBUG_CALI + printk(KERN_INFO "%s: New offset:%d,%d,%d\n", __func__, new_offset[0], new_offset[1], new_offset[2]); +#endif + if(store_location == 1) + { + STK831x_SetOffset(char_offset); + msleep(1); + STK831x_GetOffset(reg_offset); + for(axis=0;axis<3;axis++) + { + if(char_offset[axis] != reg_offset[axis]) + { + printk(KERN_ERR "%s: set offset to register fail!, char_offset[%d]=%d,reg_offset[%d]=%d\n", + __func__, axis,char_offset[axis], axis, reg_offset[axis]); + atomic_set(&stk->cali_status, STK_K_FAIL_WRITE_NOFST); + return -STK_K_FAIL_WRITE_NOFST; + } + } + + + result = STK831X_VerifyCali(stk, 1, real_delay_ms); + if(result) + { + printk(KERN_ERR "%s: calibration check fail, result=0x%x\n", __func__, result); + atomic_set(&stk->cali_status, -result); + } + else + { + result = stk_store_in_file(char_offset, STK_K_SUCCESS_FILE); + if(result) + { + printk(KERN_INFO "%s:write calibration failed\n", __func__); + atomic_set(&stk->cali_status, -result); + } + else + { + printk(KERN_INFO "%s successfully\n", __func__); + atomic_set(&stk->cali_status, STK_K_SUCCESS_FILE); + } + + } + } + else if(store_location >= 2) + { + for(axis=0; axis<3; axis++) + { +#ifdef CONFIG_SENSORS_STK8313 + new_offset[axis]>>=2; +#endif + char_offset[axis] = (char)new_offset[axis]; + if( (char_offset[axis]>>7)==0) + { + if(char_offset[axis] >= 0x20 ) + { + printk(KERN_ERR "%s: offset[%d]=0x%x is too large, limit to 0x1f\n", + __func__, axis, char_offset[axis] ); + char_offset[axis] = 0x1F; + //atomic_set(&stk->cali_status, STK_K_FAIL_OTP_OUT_RG); + //return -STK_K_FAIL_OTP_OUT_RG; + } + } + else + { + if(char_offset[axis] <= 0xDF) + { + printk(KERN_ERR "%s: offset[%d]=0x%x is too large, limit to 0x20\n", + __func__, axis, char_offset[axis]); + char_offset[axis] = 0x20; + //atomic_set(&stk->cali_status, STK_K_FAIL_OTP_OUT_RG); + //return -STK_K_FAIL_OTP_OUT_RG; + } + else + char_offset[axis] = char_offset[axis] & 0x3f; + } + } + + printk(KERN_INFO "%s: OTP offset:0x%x,0x%x,0x%x\n", __func__, char_offset[0], char_offset[1], char_offset[2]); + if(store_location == 2) + { + result = stk_store_in_ic( stk, char_offset, 1, real_delay_ms); + if(result == 0) + { + printk(KERN_INFO "%s successfully\n", __func__); + atomic_set(&stk->cali_status, STK_K_SUCCESS_FT1); + } + else + { + printk(KERN_ERR "%s fail, result=%d\n", __func__, result); + } + } + else if(store_location == 3) + { + result = stk_store_in_ic( stk, char_offset, 2, real_delay_ms); + if(result == 0) + { + printk(KERN_INFO "%s successfully\n", __func__); + atomic_set(&stk->cali_status, STK_K_SUCCESS_FT2); + } + else + { + printk(KERN_ERR "%s fail, result=%d\n", __func__, result); + } + } + offset[0] = offset[1] = offset[2] = 0; + stk_store_in_file(offset, store_location); + } +#ifdef STK_TUNE + stk_tune_offset_record[0] = 0; + stk_tune_offset_record[1] = 0; + stk_tune_offset_record[2] = 0; + stk_tune_done = 1; +#endif + stk->first_enable = false; + STK831x_SetDelay(stk, gdelay_ns); + + if(org_enable) + STK831x_SetEnable(stk, 1); + return 0; + +err_i2c_rw: + stk->first_enable = false; + if(org_enable) + STK831x_SetEnable(stk, 1); + printk(KERN_ERR "%s: i2c read/write error, err=0x%x\n", __func__, result); + atomic_set(&stk->cali_status, STK_K_FAIL_I2C); + return result; +} + + +static int STK831x_GetCali(struct stk831x_data *stk) +{ + char r_buf[STK_ACC_CALI_FILE_SIZE] = {0}; + char offset[3], mode; + int cnt, result; + char regR[6]; + +#ifdef STK_TUNE + printk(KERN_INFO "%s: stk_tune_done=%d, stk_tune_index=%d, stk_tune_offset=%d,%d,%d\n", __func__, + stk_tune_done, stk_tune_index, stk_tune_offset_record[0], stk_tune_offset_record[1], + stk_tune_offset_record[2]); +#endif + if ((stk_get_file_content(r_buf, STK_ACC_CALI_FILE_SIZE)) == 0) + { + if(r_buf[0] == STK_ACC_CALI_VER0 && r_buf[1] == STK_ACC_CALI_VER1) + { + offset[0] = r_buf[2]; + offset[1] = r_buf[3]; + offset[2] = r_buf[4]; + mode = r_buf[5]; + printk(KERN_INFO "%s:file offset:%#02x,%#02x,%#02x,%#02x\n", + __func__, offset[0], offset[1], offset[2], mode); + } + else + { + printk(KERN_ERR "%s: cali version number error! r_buf=0x%x,0x%x,0x%x,0x%x,0x%x\n", + __func__, r_buf[0], r_buf[1], r_buf[2], r_buf[3], r_buf[4]); + } + } + else + printk(KERN_INFO "%s: No file offset\n", __func__); + + for(cnt=0x43;cnt<0x49;cnt++) + { + result = STK831x_ReadByteOTP(cnt, &(regR[cnt-0x43])); + if(result < 0) + printk(KERN_ERR "%s: STK831x_ReadByteOTP failed, ret=%d\n", __func__, result); + } + printk(KERN_INFO "%s: OTP 0x43-0x49:%#02x,%#02x,%#02x,%#02x,%#02x,%#02x\n", __func__, regR[0], + regR[1], regR[2],regR[3], regR[4], regR[5]); + + for(cnt=0x53;cnt<0x59;cnt++) + { + result = STK831x_ReadByteOTP(cnt, &(regR[cnt-0x53])); + if(result < 0) + printk(KERN_ERR "%s: STK831x_ReadByteOTP failed, ret=%d\n", __func__, result); + } + printk(KERN_INFO "%s: OTP 0x53-0x59:%#02x,%#02x,%#02x,%#02x,%#02x,%#02x\n", __func__, regR[0], + regR[1], regR[2],regR[3], regR[4], regR[5]); + + return 0; +} + +static int STK831x_Init(struct stk831x_data *stk, struct i2c_client *client) +{ + int result; + char buffer[2] = ""; + +#ifdef CONFIG_SENSORS_STK8312 + printk(KERN_INFO "%s: Initialize stk8312\n", __func__); +#elif defined CONFIG_SENSORS_STK8313 + printk(KERN_INFO "%s: Initialize stk8313\n", __func__); +#endif + + buffer[0] = STK831X_RESET; + buffer[1] = 0x00; + result = STK_i2c_Tx(buffer, 2); + if (result < 0) + { + printk(KERN_ERR "%s:failed\n", __func__); + return result; + } + + /* int pin is active high, psuh-pull */ + buffer[0] = STK831X_MODE; + buffer[1] = 0xC0; + result = STK_i2c_Tx(buffer, 2); + if (result < 0) + { + printk(KERN_ERR "%s:failed\n", __func__); + return result; + } + + /* 50 Hz ODR */ + stk->delay = STK831X_INIT_ODR; + buffer[0] = STK831X_SR; + buffer[1] = stk->delay /*+ STK831X_SAMPLE_TIME_BASE*//*2*/; //debug for rotate slowly 2013-8-15 + result = STK_i2c_Tx(buffer, 2); + if (result < 0) + { + printk(KERN_ERR "%s:failed\n", __func__); + return result; + } + +#if (!STK_ACC_POLLING_MODE) + /* enable GINT, int after every measurement */ + buffer[0] = STK831X_INTSU; + buffer[1] = 0x10; + result = STK_i2c_Tx(buffer, 2); + if (result < 0) + { + printk(KERN_ERR "%s:interrupt init failed\n", __func__); + return result; + } +#endif + /* +- 6g mode */ + buffer[0] = STK831X_STH; +#ifdef CONFIG_SENSORS_STK8312 + buffer[1] = 0x42; +#elif defined CONFIG_SENSORS_STK8313 + buffer[1] = 0x82; +#endif + result = STK_i2c_Tx(buffer, 2); + if (result < 0) + { + printk(KERN_ERR "%s:set range failed\n", __func__); + return result; + } + + atomic_set(&stk->enabled, 0); + event_since_en = 0; + +#ifdef STK_LOWPASS + memset(&stk->fir, 0x00, sizeof(stk->fir)); + atomic_set(&stk->firlength, STK_FIR_LEN); + atomic_set(&stk->fir_en, 1); +#endif + +#ifdef STK_TUNE + stk_tune_offset[0] = 0; + stk_tune_offset[1] = 0; + stk_tune_offset[2] = 0; + stk_tune_done = 0; +#endif + return 0; +} + +static void stk_handle_first_en(struct stk831x_data *stk) +{ + char r_buf[STK_ACC_CALI_FILE_SIZE] = {0}; + char offset[3]; + char mode; + + if ((stk_get_file_content(r_buf, STK_ACC_CALI_FILE_SIZE)) == 0) + { + if(r_buf[0] == STK_ACC_CALI_VER0 && r_buf[1] == STK_ACC_CALI_VER1) + { + offset[0] = r_buf[2]; + offset[1] = r_buf[3]; + offset[2] = r_buf[4]; + mode = r_buf[5]; + STK831x_SetOffset(offset); +#ifdef STK_TUNE + stk_tune_offset_record[0] = offset[0]; + stk_tune_offset_record[1] = offset[1]; + stk_tune_offset_record[2] = offset[2]; +#endif + printk(KERN_INFO "%s: set offset:%d,%d,%d, mode=%d\n", __func__, offset[0], offset[1], offset[2], mode); + atomic_set(&stk->cali_status, mode); + } + else + { + printk(KERN_ERR "%s: cali version number error! r_buf=0x%x,0x%x,0x%x,0x%x,0x%x\n", + __func__, r_buf[0], r_buf[1], r_buf[2], r_buf[3], r_buf[4]); + //return -EINVAL; + } + } +#ifdef STK_TUNE + else if(stk_tune_offset_record[0]!=0 || stk_tune_offset_record[1]!=0 || stk_tune_offset_record[2]!=0) + { + STK831x_SetOffset(stk_tune_offset_record); + stk_tune_done = 1; + atomic_set(&stk->cali_status, STK_K_SUCCESS_TUNE); + printk(KERN_INFO "%s: set offset:%d,%d,%d\n", __func__, stk_tune_offset_record[0], + stk_tune_offset_record[1],stk_tune_offset_record[2]); + } +#endif + else + { + offset[0] = offset[1] = offset[2] = 0; + stk_store_in_file(offset, STK_K_NO_CALI); + atomic_set(&stk->cali_status, STK_K_NO_CALI); + } + printk(KERN_INFO "%s: finish, cali_status = 0x%x\n", __func__, atomic_read(&stk->cali_status)); + return; +} + +static int32_t stk_get_ic_content(struct stk831x_data *stk) +{ + int result; + char regR; + + result = STK831x_ReadByteOTP(0x7F, ®R); + if(result < 0) + { + printk(KERN_ERR "%s: read/write eng i2c error, result=0x%x\n", __func__, result); + return result; + } + + if(regR&0x20) + { + atomic_set(&stk->cali_status, STK_K_SUCCESS_FT2); + printk(KERN_INFO "%s: OTP 2 used\n", __func__); + return 2; + } + if(regR&0x10) + { + atomic_set(&stk->cali_status, STK_K_SUCCESS_FT1); + printk(KERN_INFO "%s: OTP 1 used\n", __func__); + return 1; + } + return 0; +} + +static int stk_store_in_ic( struct stk831x_data *stk, char otp_offset[], char FT_index, uint32_t delay_ms) +{ + int result; + char buffer[2] = ""; + + buffer[0] = STK831X_MODE; + result = STK_i2c_Rx(buffer, 1); + if (result < 0) + { + goto ic_err_i2c_rw; + } + buffer[1] = (buffer[0] & 0xF8) | 0x01; + buffer[0] = STK831X_MODE; + result = STK_i2c_Tx(buffer, 2); + if (result < 0) + { + goto ic_err_i2c_rw; + } + STK831X_SetVD(stk); + + buffer[0] = 0x2B; + buffer[1] = otp_offset[0]; + result = STK_i2c_Tx(buffer, 2); + if (result < 0) + { + goto ic_err_i2c_rw; + } + buffer[0] = 0x2F; + buffer[1] = otp_offset[2]; + result = STK_i2c_Tx(buffer, 2); + if (result < 0) + { + goto ic_err_i2c_rw; + } + buffer[0] = 0x33; + buffer[1] = otp_offset[1]; + result = STK_i2c_Tx(buffer, 2); + if (result < 0) + { + goto ic_err_i2c_rw; + } + + +#ifdef STK_DEBUG_CALI + //printk(KERN_INFO "%s:Check All OTP Data after write 0x2B 0x2F 0x33\n", __func__); + //STK831x_ReadAllOTP(); +#endif + + msleep(delay_ms*15); + result = STK831X_VerifyCali(stk, 0, 0); + if(result) + { + printk(KERN_ERR "%s: calibration check1 fail, FT_index=%d\n", __func__, FT_index); + goto ic_err_misc; + } +#ifdef STK_DEBUG_CALI + //printk(KERN_INFO "\n%s:Check All OTP Data before write OTP\n", __func__); + +#endif + //Write OTP + printk(KERN_INFO "\n%s:Write offset data to FT%d OTP\n", __func__, FT_index); + result = STK831x_WriteOffsetOTP(stk, FT_index, otp_offset); + if(result < 0) + { + printk(KERN_INFO "%s: write OTP%d fail\n", __func__, FT_index); + goto ic_err_misc; + } + + buffer[0] = STK831X_MODE; + result = STK_i2c_Rx(buffer, 1); + if (result < 0) + { + goto ic_err_i2c_rw; + } + buffer[1] = (buffer[0] & 0xF8); + buffer[0] = STK831X_MODE; + result = STK_i2c_Tx(buffer, 2); + if (result < 0) + { + goto ic_err_i2c_rw; + } + + msleep(1); + STK831x_Init(stk, this_client); +#ifdef STK_DEBUG_CALI + //printk(KERN_INFO "\n%s:Check All OTP Data after write OTP and reset\n", __func__); +#endif + + result = STK831X_VerifyCali(stk, 1, delay_ms); + if(result) + { + printk(KERN_ERR "%s: calibration check2 fail\n", __func__); + goto ic_err_misc; + } + return 0; + +ic_err_misc: + STK831x_Init(stk, this_client); + msleep(1); + atomic_set(&stk->cali_status, -result); + return result; + +ic_err_i2c_rw: + printk(KERN_ERR "%s: i2c read/write error, err=0x%x\n", __func__, result); + msleep(1); + STK831x_Init(stk, this_client); + atomic_set(&stk->cali_status, STK_K_FAIL_I2C); + return result; +} + +static int32_t stk_get_file_content(char * r_buf, int8_t buf_size) +{ + struct file *cali_file; + mm_segment_t fs; + ssize_t ret; + + cali_file = filp_open(STK_ACC_CALI_FILE, O_RDONLY,0); + if(IS_ERR(cali_file)) + { + printk(KERN_ERR "%s: filp_open error, no offset file!\n", __func__); + return -ENOENT; + } + else + { + fs = get_fs(); + set_fs(get_ds()); + ret = cali_file->f_op->read(cali_file,r_buf, STK_ACC_CALI_FILE_SIZE,&cali_file->f_pos); + if(ret < 0) + { + printk(KERN_ERR "%s: read error, ret=%d\n", __func__, ret); + filp_close(cali_file,NULL); + return -EIO; + } + set_fs(fs); + } + + filp_close(cali_file,NULL); + return 0; +} + +#ifdef STK_PERMISSION_THREAD +static struct task_struct *STKPermissionThread = NULL; + +static int stk_permission_thread(void *data) +{ + int ret = 0; + int retry = 0; + mm_segment_t fs = get_fs(); + set_fs(KERNEL_DS); + msleep(20000); + do{ + msleep(5000); + ret = sys_fchmodat(AT_FDCWD, "/sys/class/input/input0/driver/cali" , 0666); + ret = sys_fchmodat(AT_FDCWD, "/sys/class/input/input1/driver/cali" , 0666); + ret = sys_fchmodat(AT_FDCWD, "/sys/class/input/input2/driver/cali" , 0666); + ret = sys_fchmodat(AT_FDCWD, "/sys/class/input/input3/driver/cali" , 0666); + ret = sys_fchmodat(AT_FDCWD, "/sys/class/input/input4/driver/cali" , 0666); + ret = sys_fchmodat(AT_FDCWD, "/sys/class/input/input0/cali" , 0666); + ret = sys_fchmodat(AT_FDCWD, "/sys/class/input/input1/cali" , 0666); + ret = sys_fchmodat(AT_FDCWD, "/sys/class/input/input2/cali" , 0666); + ret = sys_fchmodat(AT_FDCWD, "/sys/class/input/input3/cali" , 0666); + ret = sys_fchmodat(AT_FDCWD, "/sys/class/input/input4/cali" , 0666); + ret = sys_chmod(STK_ACC_CALI_FILE , 0666); + ret = sys_fchmodat(AT_FDCWD, STK_ACC_CALI_FILE , 0666); + //if(ret < 0) + // printk("fail to execute sys_fchmodat, ret = %d\n", ret); + if(retry++ > 10) + break; + }while(ret == -ENOENT); + set_fs(fs); + printk(KERN_INFO "%s exit, retry=%d\n", __func__, retry); + return 0; +} +#endif /* #ifdef STK_PERMISSION_THREAD */ + +static int stk_store_in_file(char offset[], char mode) +{ + struct file *cali_file; + char r_buf[STK_ACC_CALI_FILE_SIZE] = {0}; + char w_buf[STK_ACC_CALI_FILE_SIZE] = {0}; + mm_segment_t fs; + ssize_t ret; + int8_t i; + + w_buf[0] = STK_ACC_CALI_VER0; + w_buf[1] = STK_ACC_CALI_VER1; + w_buf[2] = offset[0]; + w_buf[3] = offset[1]; + w_buf[4] = offset[2]; + w_buf[5] = mode; + + cali_file = filp_open(STK_ACC_CALI_FILE, O_CREAT | O_RDWR,0666); + + if(IS_ERR(cali_file)) + { + printk(KERN_ERR "%s: filp_open error!\n", __func__); + return -STK_K_FAIL_OPEN_FILE; + } + else + { + fs = get_fs(); + set_fs(get_ds()); + + ret = cali_file->f_op->write(cali_file,w_buf,STK_ACC_CALI_FILE_SIZE,&cali_file->f_pos); + if(ret != STK_ACC_CALI_FILE_SIZE) + { + printk(KERN_ERR "%s: write error!\n", __func__); + filp_close(cali_file,NULL); + return -STK_K_FAIL_W_FILE; + } + cali_file->f_pos=0x00; + ret = cali_file->f_op->read(cali_file,r_buf, STK_ACC_CALI_FILE_SIZE,&cali_file->f_pos); + if(ret < 0) + { + printk(KERN_ERR "%s: read error!\n", __func__); + filp_close(cali_file,NULL); + return -STK_K_FAIL_R_BACK; + } + set_fs(fs); + + //printk(KERN_INFO "%s: read ret=%d!\n", __func__, ret); + for(i=0;iprivate_data = stk831x_data_ptr; + return 0; +} + +static int stk_release(struct inode *inode, struct file *file) +{ + return 0; +} + +#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,36)) +static long stk_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +#else +static int stk_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +#endif +{ + void __user *argp = (void __user *)arg; + int retval = 0; + char state = 0, restore_state = 0; + char rwbuf[8] = ""; + uint32_t delay_ns; + char char3_buffer[3]; + int result; + int int3_buffer[3]; + struct stk831x_data *stk = file->private_data; + unsigned int uval = -1; +/* printk(KERN_INFO "%s: cmd = 0x%x\n", __func__, cmd); */ + + if(cmd == ECS_IOCTL_APP_SET_DELAY || cmd == STK_IOCTL_SET_DELAY || cmd == STK_IOCTL_SET_OFFSET || cmd == STK_IOCTL_SET_RANGE || cmd == STK_IOCTL_WRITE || cmd == STK_IOCTL_SET_CALI) + { + STK831x_GetEnable(stk, &restore_state); + if(restore_state) + STK831x_SetEnable(stk, 0); + } + + switch (cmd) + { + case STK_IOCTL_SET_OFFSET: + if(copy_from_user(&char3_buffer, argp, sizeof(char3_buffer))) + return -EFAULT; + break; + case ECS_IOCTL_APP_SET_DELAY: + case STK_IOCTL_SET_DELAY: + if(copy_from_user(&delay_ns, argp, sizeof(uint32_t))) + return -EFAULT; + break; + case STK_IOCTL_WRITE: + case STK_IOCTL_READ: + if (copy_from_user(&rwbuf, argp, sizeof(rwbuf))) + return -EFAULT; + break; + case ECS_IOCTL_APP_SET_AFLAG: + case STK_IOCTL_SET_ENABLE: + case STK_IOCTL_SET_RANGE: + case STK_IOCTL_SET_CALI: + if(copy_from_user(&state, argp, sizeof(char))) + return -EFAULT; + break; + case WMT_IOCTL_SENSOR_GET_DRVID: + + uval = STK8312_DRVID; + if (copy_to_user((unsigned int*)arg, &uval, sizeof(unsigned int))) + { + return -EFAULT; + } + printk("<<<<<<raw_data[0]; + int3_buffer[1] = stk->raw_data[1]; + int3_buffer[2] = stk->raw_data[2]; + break; + case ECS_IOCTL_APP_SET_AFLAG: + case STK_IOCTL_SET_ENABLE: + STK831x_SetEnable(stk, state); + break; + case STK_IOCTL_GET_ENABLE: + STK831x_GetEnable(stk, &state); + break; + case STK_IOCTL_SET_RANGE: + STK831x_SetRange(state); + break; + case STK_IOCTL_GET_RANGE: + STK831x_GetRange(&state); + break; + case STK_IOCTL_SET_CALI: + STK831x_SetCali(stk, state); + break; + default: + //retval = -ENOTTY; + break; + } + + if(cmd == ECS_IOCTL_APP_SET_DELAY || cmd == STK_IOCTL_SET_DELAY || cmd == STK_IOCTL_SET_OFFSET || cmd == STK_IOCTL_SET_RANGE || cmd == STK_IOCTL_WRITE || cmd == STK_IOCTL_SET_CALI) + { + if(restore_state) + STK831x_SetEnable(stk, restore_state); + } + switch (cmd) + { + case STK_IOCTL_GET_ACCELERATION: + if(copy_to_user(argp, &int3_buffer, sizeof(int3_buffer))) + return -EFAULT; + break; + case STK_IOCTL_READ: + if(copy_to_user(argp, &rwbuf, sizeof(rwbuf))) + return -EFAULT; + break; + case STK_IOCTL_GET_DELAY: + if(copy_to_user(argp, &delay_ns, sizeof(delay_ns))) + return -EFAULT; + break; + case STK_IOCTL_GET_OFFSET: + if(copy_to_user(argp, &char3_buffer, sizeof(char3_buffer))) + return -EFAULT; + break; + case STK_IOCTL_GET_RANGE: + case STK_IOCTL_GET_ENABLE: + if(copy_to_user(argp, &state, sizeof(char))) + return -EFAULT; + break; + default: + break; + } + + return retval; +} + + +static struct file_operations stk_fops = { + .owner = THIS_MODULE, + .open = stk_open, + .release = stk_release, +#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,36)) + .unlocked_ioctl = stk_ioctl, +#else + .ioctl = stk_ioctl, +#endif +}; + +static struct miscdevice stk_device = { + .minor = MISC_DYNAMIC_MINOR, +#ifndef STK_WMT_PLATFORM + .name = "stk831x", +#else + .name = "sensor_ctrl", +#endif + .fops = &stk_fops, +}; + + +#if STK_ACC_POLLING_MODE +static enum hrtimer_restart stk_acc_timer_func(struct hrtimer *timer) +{ + struct stk831x_data *stk = container_of(timer, struct stk831x_data, acc_timer); + queue_work(stk->stk_acc_wq, &stk->stk_acc_work); + hrtimer_forward_now(&stk->acc_timer, stk->acc_poll_delay); + return HRTIMER_RESTART; +} + +static void stk_acc_poll_work_func(struct work_struct *work) +{ + struct stk831x_data *stk = container_of(work, struct stk831x_data, stk_acc_work); + STK831x_ReadSensorData(stk); + STK831x_ReportValue(stk); + return; +} + +#else + +static irqreturn_t stk_mems_irq_handler(int irq, void *data) +{ + struct stk831x_data *pData = data; + disable_irq_nosync(pData->irq); + queue_work(stk_mems_work_queue,&pData->stk_work); + return IRQ_HANDLED; +} + + +static void stk_mems_wq_function(struct work_struct *work) +{ + struct stk831x_data *stk = container_of(work, struct stk831x_data, stk_work); + STK831x_ReadSensorData(stk); + STK831x_ReportValue(stk); + enable_irq(stk->irq); +} + +static int stk831x_irq_setup(struct i2c_client *client, struct stk831x_data *stk_int) +{ + int error; + int irq= -1; +#if ADDITIONAL_GPIO_CFG + if (gpio_request(STK_INT_PIN, "EINT")) + { + printk(KERN_ERR "%s:gpio_request() failed\n",__func__); + return -1; + } + gpio_direction_input(STK_INT_PIN); + + irq = gpio_to_irq(STK_INT_PIN); + if ( irq < 0 ) + { + printk(KERN_ERR "%s:gpio_to_irq() failed\n",__func__); + return -1; + } + client->irq = irq; + stk_int->irq = irq; +#endif //#if ADDITIONAL_GPIO_CFG + printk(KERN_INFO "%s: irq # = %d\n", __func__, irq); + if(irq < 0) + printk(KERN_ERR "%s: irq number was not specified!\n", __func__); + error = request_irq(client->irq, stk_mems_irq_handler, IRQF_TRIGGER_RISING , "stk-mems", stk_int); + if (error < 0) + { + printk(KERN_ERR "%s: request_irq(%d) failed for (%d)\n", __func__, client->irq, error); + return -1; + } + disable_irq(irq); + return irq; +} + +#endif //#if STK_ACC_POLLING_MODE + +static ssize_t stk831x_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct stk831x_data *stk = i2c_get_clientdata(this_client); + return scnprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&stk->enabled)); +} + +static ssize_t stk831x_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + + struct stk831x_data *stk = i2c_get_clientdata(this_client); + + error = strict_strtoul(buf, 10, &data); + if (error) + { + printk(KERN_ERR "%s: strict_strtoul failed, error=0x%x\n", __func__, error); + return error; + } + if ((data == 0)||(data==1)) + STK831x_SetEnable(stk,data); + else + printk(KERN_ERR "%s: invalud argument, data=%ld\n", __func__, data); + return count; +} + +static ssize_t stk831x_value_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct stk831x_data *stk = i2c_get_clientdata(this_client); + int ddata[3]; + + printk(KERN_INFO "driver version:%s\n",STK_ACC_DRIVER_VERSION); + STK831x_ReadSensorData(stk); + ddata[0]= stk->raw_data[0]; + ddata[1]= stk->raw_data[1]; + ddata[2]= stk->raw_data[2]; + return scnprintf(buf, PAGE_SIZE, "%d %d %d\n", ddata[0], ddata[1], ddata[2]); +} + +static ssize_t stk831x_delay_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct stk831x_data *stk = i2c_get_clientdata(this_client); + uint32_t gdelay_ns; + + STK831x_GetDelay(stk, &gdelay_ns); + return scnprintf(buf, PAGE_SIZE, "%d\n", gdelay_ns/1000000); +} + +static ssize_t stk831x_delay_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct stk831x_data *stk = i2c_get_clientdata(this_client); + char restore_state = 0; + + error = strict_strtoul(buf, 10, &data); + if (error) + { + printk(KERN_ERR "%s: strict_strtoul failed, error=0x%x\n", __func__, error); + return error; + } + + STK831x_GetEnable(stk, &restore_state); + if(restore_state) + STK831x_SetEnable(stk, 0); + + STK831x_SetDelay(stk, data*1000000); // ms to ns + + if(restore_state) + STK831x_SetEnable(stk, restore_state); + return count; +} + +static ssize_t stk831x_cali_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct stk831x_data *stk = i2c_get_clientdata(this_client); + int status = atomic_read(&stk->cali_status); + + if(status != STK_K_RUNNING) + STK831x_GetCali(stk); + return scnprintf(buf, PAGE_SIZE, "%02x\n", status); +} + +static ssize_t stk831x_cali_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct stk831x_data *stk = i2c_get_clientdata(this_client); + error = strict_strtoul(buf, 10, &data); + if (error) + { + printk(KERN_ERR "%s: strict_strtoul failed, error=0x%x\n", __func__, error); + return error; + } + STK831x_SetCali(stk, data); + return count; +} + +static ssize_t stk831x_send_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int error, i; + char *token[2]; + int w_reg[2]; + char buffer[2] = ""; + + for (i = 0; i < 2; i++) + token[i] = strsep((char **)&buf, " "); + if((error = strict_strtoul(token[0], 16, (unsigned long *)&(w_reg[0]))) < 0) + { + printk(KERN_ERR "%s:strict_strtoul failed, error=0x%x\n", __func__, error); + return error; + } + if((error = strict_strtoul(token[1], 16, (unsigned long *)&(w_reg[1]))) < 0) + { + printk(KERN_ERR "%s:strict_strtoul failed, error=0x%x\n", __func__, error); + return error; + } + printk(KERN_INFO "%s: reg[0x%x]=0x%x\n", __func__, w_reg[0], w_reg[1]); + buffer[0] = w_reg[0]; + buffer[1] = w_reg[1]; + error = STK_i2c_Tx(buffer, 2); + if (error < 0) + { + printk(KERN_ERR "%s:failed\n", __func__); + return error; + } + return count; +} + +static ssize_t stk831x_recv_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct stk831x_data *stk = i2c_get_clientdata(this_client); + return scnprintf(buf, PAGE_SIZE, "%02x\n", stk->recv_reg); +} + +static ssize_t stk831x_recv_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + char buffer[2] = ""; + unsigned long data; + int error; + struct stk831x_data *stk = i2c_get_clientdata(this_client); + + error = strict_strtoul(buf, 16, &data); + if (error) + { + printk(KERN_ERR "%s: strict_strtoul failed, error=0x%x\n", __func__, error); + return error; + } + + buffer[0] = data; + error = STK_i2c_Rx(buffer, 2); + if (error < 0) + { + printk(KERN_ERR "%s:failed\n", __func__); + return error; + } + stk->recv_reg = buffer[0]; + printk(KERN_INFO "%s: reg[0x%x]=0x%x\n", __func__, (int)data , (int)buffer[0]); + return count; +} + +static ssize_t stk831x_allreg_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int error; + char buffer[16] = ""; + char show_buffer[14] = ""; + int aa,bb, no, show_no = 0; + + for(bb=0;bb<4;bb++) + { + buffer[0] = bb * 0x10; + error = STK_i2c_Rx(buffer, 16); + if (error < 0) + { + printk(KERN_ERR "%s:failed\n", __func__); + return error; + } + for(aa=0;aa<16;aa++) + { + no = bb*0x10+aa; + printk(KERN_INFO "stk reg[0x%x]=0x%x\n", no, buffer[aa]); + switch(no) + { + case 0x0: + case 0x1: + case 0x2: + case 0x3: + case 0x4: + case 0x5: + case STK831X_INTSU: + case STK831X_MODE: + case STK831X_SR: + case STK831X_OFSX: + case STK831X_OFSY: + case STK831X_OFSZ: + case STK831X_STH: + case 0x24: + show_buffer[show_no] = buffer[aa]; + show_no++; + break; + default: + break; + } + } + } + return scnprintf(buf, PAGE_SIZE, "0x0=%02x,0x1=%02x,0x2=%02x,0x3=%02x,0x4=%02x,0x5=%02x,INTSU=%02x,MODE=%02x,SR=%02x,OFSX=%02x,OFSY=%02x,OFSZ=%02x,STH=%02x,0x24=%02x\n", + show_buffer[0], show_buffer[1], show_buffer[2], show_buffer[3], show_buffer[4], + show_buffer[5], show_buffer[6], show_buffer[7], show_buffer[8], show_buffer[9], + show_buffer[10], show_buffer[11], show_buffer[12], show_buffer[13]); +} + +static ssize_t stk831x_sendo_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int error, i; + char *token[2]; + int w_reg[2]; + char buffer[2] = ""; + + for (i = 0; i < 2; i++) + token[i] = strsep((char **)&buf, " "); + if((error = strict_strtoul(token[0], 16, (unsigned long *)&(w_reg[0]))) < 0) + { + printk(KERN_ERR "%s:strict_strtoul failed, error=0x%x\n", __func__, error); + return error; + } + if((error = strict_strtoul(token[1], 16, (unsigned long *)&(w_reg[1]))) < 0) + { + printk(KERN_ERR "%s:strict_strtoul failed, error=0x%x\n", __func__, error); + return error; + } + printk(KERN_INFO "%s: reg[0x%x]=0x%x\n", __func__, w_reg[0], w_reg[1]); + + buffer[0] = w_reg[0]; + buffer[1] = w_reg[1]; + error = STK831x_WriteByteOTP(buffer[0], buffer[1]); + if (error < 0) + { + printk(KERN_ERR "%s:failed\n", __func__); + return error; + } + return count; +} + + +static ssize_t stk831x_recvo_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + char buffer[2] = ""; + unsigned long data; + int error; + + error = strict_strtoul(buf, 16, &data); + if (error) + { + printk(KERN_ERR "%s: strict_strtoul failed, error=0x%x\n", __func__, error); + return error; + } + + buffer[0] = data; + error = STK831x_ReadByteOTP(buffer[0], &buffer[1]); + if (error < 0) + { + printk(KERN_ERR "%s:failed\n", __func__); + return error; + } + printk(KERN_INFO "%s: reg[0x%x]=0x%x\n", __func__, buffer[0] , buffer[1]); + return count; +} + +static ssize_t stk831x_firlen_show(struct device *dev, +struct device_attribute *attr, char *buf) +{ +#ifdef STK_LOWPASS + struct stk831x_data *stk = i2c_get_clientdata(this_client); + int len = atomic_read(&stk->firlength); + + if(atomic_read(&stk->firlength)) + { + printk(KERN_INFO "len = %2d, idx = %2d\n", stk->fir.num, stk->fir.idx); + printk(KERN_INFO "sum = [%5d %5d %5d]\n", stk->fir.sum[0], stk->fir.sum[1], stk->fir.sum[2]); + printk(KERN_INFO "avg = [%5d %5d %5d]\n", stk->fir.sum[0]/len, stk->fir.sum[1]/len, stk->fir.sum[2]/len); + } + return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&stk->firlength)); +#else + return snprintf(buf, PAGE_SIZE, "not support\n"); +#endif +} + +static ssize_t stk831x_firlen_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifdef STK_LOWPASS + struct stk831x_data *stk = i2c_get_clientdata(this_client); + int error; + unsigned long data; + + error = strict_strtoul(buf, 10, &data); + if (error) + { + printk(KERN_ERR "%s: strict_strtoul failed, error=%d\n", __func__, error); + return error; + } + + if(data > MAX_FIR_LEN) + { + printk(KERN_ERR "%s: firlen exceed maximum filter length\n", __func__); + } + else if (data < 1) + { + atomic_set(&stk->firlength, 1); + atomic_set(&stk->fir_en, 0); + memset(&stk->fir, 0x00, sizeof(stk->fir)); + } + else + { + atomic_set(&stk->firlength, data); + memset(&stk->fir, 0x00, sizeof(stk->fir)); + atomic_set(&stk->fir_en, 1); + } +#else + printk(KERN_ERR "%s: firlen is not supported\n", __func__); +#endif + return count; +} + + +static DEVICE_ATTR(enable, 0644, stk831x_enable_show, stk831x_enable_store); +static DEVICE_ATTR(value, 0444, stk831x_value_show, NULL); +static DEVICE_ATTR(delay, 0644, stk831x_delay_show, stk831x_delay_store); +static DEVICE_ATTR(cali, 0644, stk831x_cali_show, stk831x_cali_store); +static DEVICE_ATTR(send, 0200, NULL, stk831x_send_store); +static DEVICE_ATTR(recv, 0644, stk831x_recv_show, stk831x_recv_store); +static DEVICE_ATTR(allreg, 0444, stk831x_allreg_show, NULL); +static DEVICE_ATTR(sendo, 0200, NULL, stk831x_sendo_store); +static DEVICE_ATTR(recvo, 0200, NULL, stk831x_recvo_store); +static DEVICE_ATTR(firlen, 0644, stk831x_firlen_show, stk831x_firlen_store); + +static struct attribute *stk831x_attributes[] = { + &dev_attr_enable.attr, + &dev_attr_value.attr, + &dev_attr_delay.attr, + &dev_attr_cali.attr, + &dev_attr_send.attr, + &dev_attr_recv.attr, + &dev_attr_allreg.attr, + &dev_attr_sendo.attr, + &dev_attr_recvo.attr, + &dev_attr_firlen.attr, + NULL +}; + +static struct attribute_group stk831x_attribute_group = { +#ifndef STK_ALLWINNER_PLATFORM + .name = "driver", +#endif + .attrs = stk831x_attributes, +}; +static int stk831x_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + int error; + struct stk831x_data *stk; + + printk(KERN_INFO "stk831x_probe: driver version:%s\n",STK_ACC_DRIVER_VERSION); + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + { + printk(KERN_ERR "%s:i2c_check_functionality error\n", __func__); + error = -ENODEV; + goto exit_i2c_check_functionality_error; + } + + stk = kzalloc(sizeof(struct stk831x_data),GFP_KERNEL); + if (!stk) + { + printk(KERN_ERR "%s:memory allocation error\n", __func__); + error = -ENOMEM; + goto exit_kzalloc_error; + } + stk831x_data_ptr = stk; + mutex_init(&stk->write_lock); + +#if (STK_ACC_POLLING_MODE) + stk->stk_acc_wq = create_singlethread_workqueue("stk_acc_wq"); + INIT_WORK(&stk->stk_acc_work, stk_acc_poll_work_func); + hrtimer_init(&stk->acc_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); +// stk->acc_poll_delay = ns_to_ktime(40 * NSEC_PER_MSEC); + stk->acc_poll_delay = ns_to_ktime(STK831X_SAMPLE_TIME[STK831X_INIT_ODR]*USEC_PER_MSEC); + stk->acc_timer.function = stk_acc_timer_func; +#else + stk_mems_work_queue = create_workqueue("stk_mems_wq"); + if(stk_mems_work_queue) + INIT_WORK(&stk->stk_work, stk_mems_wq_function); + else + { + printk(KERN_ERR "%s:create_workqueue error\n", __func__); + error = -EPERM; + goto exit_create_workqueue_error; + } + + error = stk831x_irq_setup(client, stk); + if(!error) + { + goto exit_irq_setup_error; + } +#endif //#if STK_ACC_POLLING_MODE + + i2c_set_clientdata(client, stk); + this_client = client; + + error = STK831x_Init(stk, client); + if (error) + { + printk(KERN_ERR "%s:stk831x initialization failed\n", __func__); + goto exit_stk_init_error; + } + atomic_set(&stk->cali_status, STK_K_NO_CALI); + stk->first_enable = true; + stk->re_enable = false; + event_since_en_limit = 20; + + stk->input_dev = input_allocate_device(); + if (!stk->input_dev) + { + error = -ENOMEM; + printk(KERN_ERR "%s:input_allocate_device failed\n", __func__); + goto exit_input_dev_alloc_error; + } +#ifndef STK_WMT_PLATFORM + stk->input_dev->name = ACC_IDEVICE_NAME; +#else + stk->input_dev->name = "g-sensor"; +#endif + set_bit(EV_ABS, stk->input_dev->evbit); + + input_set_abs_params(stk->input_dev, ABS_X, -65532, 65532, 0, 0); + input_set_abs_params(stk->input_dev, ABS_Y, -65532, 65532, 0, 0); + input_set_abs_params(stk->input_dev, ABS_Z, -65532, 65532, 0, 0); + + + error = input_register_device(stk->input_dev); + if (error) + { + printk(KERN_ERR "%s:Unable to register input device: %s\n", __func__, stk->input_dev->name); + goto exit_input_register_device_error; + } + + error = misc_register(&stk_device); + if (error) + { + printk(KERN_ERR "%s: misc_register failed\n", __func__); + goto exit_misc_device_register_error; + } + error = sysfs_create_group(&stk_device.this_device->kobj, &stk831x_attribute_group); + if (error) + { + printk(KERN_ERR "%s: sysfs_create_group failed\n", __func__); + goto exit_sysfs_create_group_error; + } + + printk(KERN_INFO "%s successfully\n", __func__); + return 0; +exit_sysfs_create_group_error: + //sysfs_remove_group(&stk->input_dev->dev.kobj, &stk831x_attribute_group); + sysfs_remove_group(&stk_device.this_device->kobj, &stk831x_attribute_group); +exit_misc_device_register_error: + misc_deregister(&stk_device); +exit_input_register_device_error: + input_unregister_device(stk->input_dev); +exit_input_dev_alloc_error: +exit_stk_init_error: +#if (STK_ACC_POLLING_MODE) + hrtimer_try_to_cancel(&stk->acc_timer); + destroy_workqueue(stk->stk_acc_wq); +#else + free_irq(client->irq, stk); +#if ADDITIONAL_GPIO_CFG +exit_irq_setup_error: + gpio_free( STK_INT_PIN ); +#endif //#if ADDITIONAL_GPIO_CFG + destroy_workqueue(stk_mems_work_queue); +exit_create_workqueue_error: +#endif //#if (!STK_ACC_POLLING_MODE) + mutex_destroy(&stk->write_lock); + kfree(stk); + stk = NULL; +exit_kzalloc_error: +exit_i2c_check_functionality_error: + return error; +} + +static int stk831x_remove(struct i2c_client *client) +{ + struct stk831x_data *stk = i2c_get_clientdata(client); + + //sysfs_remove_group(&stk->input_dev->dev.kobj, &stk831x_attribute_group); + sysfs_remove_group(&stk_device.this_device->kobj, &stk831x_attribute_group); + misc_deregister(&stk_device); + input_unregister_device(stk->input_dev); + cancel_work_sync(&stk->stk_work); +#if (STK_ACC_POLLING_MODE) + hrtimer_try_to_cancel(&stk->acc_timer); + destroy_workqueue(stk->stk_acc_wq); +#else + free_irq(client->irq, stk); +#if ADDITIONAL_GPIO_CFG + gpio_free( STK_INT_PIN ); +#endif //#if ADDITIONAL_GPIO_CFG + if (stk_mems_work_queue) + destroy_workqueue(stk_mems_work_queue); +#endif //#if (!STK_ACC_POLLING_MODE) + mutex_destroy(&stk->write_lock); + kfree(stk); + stk = NULL; + return 0; +} + +static const struct i2c_device_id stk831x[] = { + { STK831X_I2C_NAME, 0 }, + { } +}; + +#ifdef CONFIG_PM_SLEEP +static int stk831x_suspend(struct device *dev) +{ + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + struct stk831x_data *stk = i2c_get_clientdata(client); + printk(KERN_INFO "%s\n", __func__); + if(atomic_read(&stk->enabled)) + { + STK831x_SetEnable(stk, 0); + stk->re_enable = true; + } + return 0; +} + + +static int stk831x_resume(struct device *dev) +{ + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + struct stk831x_data *stk = i2c_get_clientdata(client); +#ifdef STK_RESUME_RE_INIT + int error; +#endif + + printk(KERN_INFO "%s\n", __func__); +#ifdef STK_RESUME_RE_INIT + error = STK831x_Init(stk, this_client); + if (error) + { + printk(KERN_ERR "%s:stk831x initialization failed\n", __func__); + return error; + } + stk->first_enable = true; +#endif + if(stk->re_enable) + { + stk->re_enable = false; + STK831x_SetEnable(stk, 1); + } + return 0; +} +#endif /* CONFIG_PM_SLEEP */ + + +#ifdef CONFIG_PM_RUNTIME +static int stk831x_runtime_suspend(struct device *dev) +{ + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + struct stk831x_data *stk = i2c_get_clientdata(client); + printk(KERN_INFO "%s\n", __func__); + if(atomic_read(&stk->enabled)) + { + STK831x_SetEnable(stk, 0); + stk->re_enable = true; + } + return 0; +} + + +static int stk831x_runtime_resume(struct device *dev) +{ + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + struct stk831x_data *stk = i2c_get_clientdata(client); + printk(KERN_INFO "%s\n", __func__); + stk->first_enable = true; + if(stk->re_enable) + { + stk->re_enable = false; + STK831x_SetEnable(stk, 1); + } + return 0; +} +#endif /* CONFIG_PM_RUNTIME */ + +static const struct dev_pm_ops stk831x_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(stk831x_suspend, stk831x_resume) + SET_RUNTIME_PM_OPS(stk831x_runtime_suspend, stk831x_runtime_resume, NULL) +}; + +static void stk831x_shutdown(struct i2c_client *client) +{ + struct stk831x_data *stk = NULL; + + stk = i2c_get_clientdata(client); + hrtimer_cancel(&stk->acc_timer); + cancel_work_sync(&stk->stk_acc_work); +} + +static struct i2c_driver stk831x_driver = { + .probe = stk831x_probe, + .remove = stk831x_remove, + .id_table = stk831x, + .shutdown = stk831x_shutdown, +// .suspend = stk831x_suspend, +// .resume = stk831x_resume, + .driver = { + .name = STK831X_I2C_NAME, + .pm = &stk831x_pm_ops, + }, +}; + + +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); +static int get_axisset(void* param) +{ + char varbuf[64]; + int n; + int varlen; + //int tmpoff[3] = {0}; + memset(varbuf, 0, sizeof(varbuf)); + varlen = sizeof(varbuf); + if (wmt_getsyspara("wmt.io.stk8312sensor", varbuf, &varlen)) { + errlog("Can't get gsensor config in u-boot!!!!\n"); + return -1; + } else { + n = sscanf(varbuf, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", + &l_sensorconfig.op, + &(l_sensorconfig.xyz_axis[0][0]), + &(l_sensorconfig.xyz_axis[0][1]), + &(l_sensorconfig.xyz_axis[1][0]), + &(l_sensorconfig.xyz_axis[1][1]), + &(l_sensorconfig.xyz_axis[2][0]), + &(l_sensorconfig.xyz_axis[2][1]), + &(l_sensorconfig.offset[0]), + &(l_sensorconfig.offset[1]), + &(l_sensorconfig.offset[2])); + if (n != 10) { + printk(KERN_ERR "gsensor format is error in u-boot!!!\n"); + return -1; + } + + printk("get the sensor config: %d:%d:%d:%d:%d:%d:%d:%d:%d:%d\n", + l_sensorconfig.op, + l_sensorconfig.xyz_axis[0][0], + l_sensorconfig.xyz_axis[0][1], + l_sensorconfig.xyz_axis[1][0], + l_sensorconfig.xyz_axis[1][1], + l_sensorconfig.xyz_axis[2][0], + l_sensorconfig.xyz_axis[2][1], + l_sensorconfig.offset[0], + l_sensorconfig.offset[1], + l_sensorconfig.offset[2] + ); + } + return 0; +} + +static int is_stk8312(void) +{ + struct i2c_client *client = NULL; + int ret = 0; + char wbuf[1] = {0x0b}; + char rbuf[1] = {0x0}; + //int devid = 0; + client = this_client; + if (!client) + { + return 0; + } +#if 0 + + devid = i2c_smbus_read_byte_data(client, 0x0b); //fail!!! +#endif + + ret = i2c_master_send(client, wbuf, 1); + ret = i2c_master_recv(client, rbuf, 1); + printk("<<<%s devid 0x%x\n", __FUNCTION__ ,rbuf[0]); +#if 0 //also ok!! + struct i2c_msg msg[2] = { + {.addr = client->addr, + .flags = 0, + .len = 1, + .buf = wbuf, + }, + { .addr = client->addr, + .flags = I2C_M_RD, + .len = 1, + .buf = rbuf, + }, + }; + + ret = i2c_transfer(client->adapter, msg, 2); + + printk("ret %d, id 0x%x\n", ret, rbuf[0]); +#endif + if (rbuf[0] == 0x58) + return 1; + else + return 0; + + +} + +static int __init stk831x_init(void) +{ + int ret = 0; + printk(KERN_EMERG"%d:%s",__LINE__,__func__); + + ret = get_axisset(NULL); + if (ret < 0) + { + printk("<<<<<%s user choose to no sensor chip!\n", __func__); + return ret; + } + + if (!(this_client = sensor_i2c_register_device(0, STKDIR, STK831X_I2C_NAME))) + { + printk(KERN_EMERG"Can't register gsensor i2c device!\n"); + return -1; + } + ret = is_stk8312(); + if (!ret) + { + printk("%s not find stk8312\n", __FUNCTION__); + sensor_i2c_unregister_device(this_client); + return -1; + + } + + + l_dev_class = class_create(THIS_MODULE, GSENSOR_NAME); + //for S40 module to judge whether insmod is ok + if (IS_ERR(l_dev_class)){ + ret = PTR_ERR(l_dev_class); + printk(KERN_ERR "Can't class_create gsensor device !!\n"); + return ret; + } + + ret = i2c_add_driver(&stk831x_driver); + if (ret!=0) + { + printk(KERN_EMERG"======stk831x init fail, ret=0x%x======\n", ret); + i2c_del_driver(&stk831x_driver); + return ret; + } +#ifdef STK_PERMISSION_THREAD + STKPermissionThread = kthread_run( + ,"stk","Permissionthread"); + if(IS_ERR(STKPermissionThread)) + STKPermissionThread = NULL; +#endif // STK_PERMISSION_THREAD + printk(KERN_EMERG"%d:%s",__LINE__,__func__); + + return ret; +} + +static void __exit stk831x_exit(void) +{ + //sensor_i2c_unregister_device(this_client); + i2c_del_driver(&stk831x_driver); + class_destroy(l_dev_class); +#ifdef STK_PERMISSION_THREAD + if(STKPermissionThread) + STKPermissionThread = NULL; +#endif // STK_PERMISSION_THREAD + sensor_i2c_unregister_device(this_client); +} + +module_init(stk831x_init); +module_exit(stk831x_exit); + +MODULE_AUTHOR("Lex Hsieh / Sensortek"); +MODULE_DESCRIPTION("stk831x 3-Axis accelerometer driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(STK_ACC_DRIVER_VERSION); diff --git a/ANDROID_3.4.5/drivers/input/sensor/us5182_lpsensor/Makefile b/ANDROID_3.4.5/drivers/input/sensor/us5182_lpsensor/Makefile new file mode 100755 index 00000000..1f89e698 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/us5182_lpsensor/Makefile @@ -0,0 +1,34 @@ +KERNELDIR=../../../../ +#KERNELDIR=/home/hangyan/android8850/kernel/ANDROID_3.0.8 +CROSS = arm_1103_le- +CC= $(CROSS)gcc +LD= $(CROSS)ld +STRIP = $(CROSS)strip + +DEBUG = n + +# Add your debugging flag (or not) to EXTRA_CFLAGS +ifeq ($(DEBUG),y) +# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines +DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines + +else + DEBFLAGS = -O2 -Wall +endif + +EXTRA_CFLAGS += $(DEBFLAGS) + + +MY_MODULE_NAME=s_wmt_lsensor_us5182 + +obj-m := $(MY_MODULE_NAME).o +$(MY_MODULE_NAME)-objs := us5182.o + +default: + $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules + $(STRIP) --strip-debug $(MY_MODULE_NAME).ko + rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions + +clean: + rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers + diff --git a/ANDROID_3.4.5/drivers/input/sensor/us5182_lpsensor/us5182.c b/ANDROID_3.4.5/drivers/input/sensor/us5182_lpsensor/us5182.c new file mode 100755 index 00000000..b251fb83 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/us5182_lpsensor/us5182.c @@ -0,0 +1,1098 @@ +/* + * us5182.c - us5182 ALS & Proximity Driver + * + * By Intersil Corp + * Michael DiGioia + * + * Based on isl29011.c + * by Mike DiGioia + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include "../sensor.h" +#include "us5182.h" +/* Insmod parameters */ +//I2C_CLIENT_INSMOD_1(us5182); + +#define MODULE_NAME "us5182" + +#undef dbg +#define dbg(fmt, args...) + +#undef errlog +#undef klog +#define errlog(fmt, args...) printk(KERN_ERR "[%s]: " fmt, __FUNCTION__, ## args) +#define klog(fmt, args...) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__, ## args) + +struct us_device { + struct input_polled_dev* input_poll_devl; + struct input_polled_dev* input_poll_devp; + struct i2c_client* client; + struct class* class; + struct device *lsdev; + dev_t devno; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend earlysuspend; +#endif + u8 enable_id; + +}; +static int psh_l8th = 90; +static int psh_h8th = 0; + +static int psl_l8th = 50; +static int psl_h8th = 0; + +static struct i2c_client *this_client = NULL; +/*=====Global variable===============================*/ +static u8 error_flag, debounces; +static int previous_value, this_value; +static struct i2c_client *gclient = NULL; +/*===================================================*/ +static u8 reg_cache[us5182_NUM_CACHABLE_REGS]; + +static struct us_device* l_sensorconfig = NULL; +static int l_enable = 0; // 0:don't report data +static int p_enable = 0; // 0:don't report data + +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); +static int no_adc_map = 1; + +static DEFINE_MUTEX(mutex); + +static int us5182_i2c_read(struct i2c_client *client,u8 reg) +{ +#if 0 + int val; + val = i2c_smbus_read_byte_data(client, reg); + if (val < 0) + printk("%s %d i2c transfer error\n", __func__, __LINE__); + return val; +#endif +//in default our i2c controller, will not send repeatStart signal in read process.(stop-start) +//well this sensor must have the repeatStart signal to work normally +//so we have to pass I2C_M_NOSTART flag to controller 2013-7-5 + char rdData[2] = {0}; + + struct i2c_msg msgs[2] = + { + {.addr = client->addr, .flags = 0|I2C_M_NOSTART, .len = 1, .buf = rdData,}, + {.addr = client->addr, .flags = I2C_M_RD, .len = 1, .buf = rdData,}, + }; + rdData[0] = reg; + + if (i2c_transfer(client->adapter, msgs, 2) < 0) { + printk( "%s: transfer failed.", __func__); + return -EIO; + } + + return rdData[0]; +} + +static int get_als_resolution(struct i2c_client *client) +{ + return (us5182_i2c_read(client,REGS_CR01) & 0x18) >> 3; +} + + +static int isl_get_lux_datal(struct i2c_client* client) +{ + + int lsb, msb, bitdepth; + + mutex_lock(&mutex); + lsb = us5182_i2c_read(client, REGS_LSB_SENSOR);// + + if (lsb < 0) { + mutex_unlock(&mutex); + return lsb; + } + + msb = us5182_i2c_read(client, REGS_MSB_SENSOR);// + mutex_unlock(&mutex); + + if (msb < 0) + return msb; + + bitdepth = get_als_resolution(client);//????? + switch(bitdepth){ + case 0: + lsb &= 0xF0; // 12bit?? + lsb >>= 4; //add + return ((msb << 4) | lsb); + break; + case 1: + lsb &= 0xFC; //?? 14bit + lsb >>= 2; + return ((msb << 6) | lsb); + break; + } + + return ((msb << 8) | lsb); +} + + +static int get_ps_resolution(struct i2c_client *client) +{ + u8 data; + + data = (us5182_i2c_read(client,REGS_CR02) & 0x18) >> 3; + + return data; +} + +static int isl_get_lux_datap(struct i2c_client* client) +{ + + int lsb, msb, bitdepth; + + mutex_lock(&mutex); + lsb = us5182_i2c_read(client, REGS_LSB_SENSOR_PS); + + if (lsb < 0) { + mutex_unlock(&mutex); + return lsb; + } + + msb = us5182_i2c_read(client, REGS_MSB_SENSOR_PS); + mutex_unlock(&mutex); + + if (msb < 0) + return msb; + + bitdepth = get_ps_resolution(client); + switch(bitdepth){ + case 0: + lsb &= 0xF0; // 12bit ?? + lsb >>= 4; + return ((msb << 4) | lsb); + break; + case 1: + lsb &= 0xFC; // 14bit ?? + lsb >>= 2; + return ((msb << 6) | lsb); + break; + } + + return ((msb << 8) | lsb); //we use 16bit now +} + + + +/* Return 0 if detection is successful, -ENODEV otherwise */ +static int us5182_detect(struct i2c_client *client/*, int kind, + struct i2c_board_info *info*/) +{ + + char rxData[2] = {0xb2, 0}; + int ret = 0; + +#if 1 + //rxData[0] = 0xb2; + + struct i2c_msg msgs[2] = { + + {.addr = client->addr, .flags = 0|I2C_M_NOSTART, .len = 1, .buf = rxData,}, + {.addr = client->addr, .flags = I2C_M_RD, .len = 1, .buf = rxData,} + }; + ret = i2c_transfer(client->adapter, msgs, 2); + if (ret < 0){ + printk(KERN_ERR "%s i2c_transfer error!\n", __FUNCTION__); + return -EIO; + } + +#endif + + if(0x26 == rxData[0]) + { + printk(KERN_ALERT "us5182 detected OK\n"); + return 0; + } + else + return -1; +} + +int isl_input_open(struct input_dev* input) +{ + return 0; +} + +void isl_input_close(struct input_dev* input) +{ +} + +//Fixme plan to transfer the adc value to the config.xml lux 2013-5-10 +static __u16 uadc[8] = {2, 8, 100, 400, 900, 1000, 1500, 1900};//customize +static __u16 ulux[9] = {128, 200, 1300, 2000, 3000, 4000, 5000, 6000, 7000}; +static __u16 adc_to_lux(__u16 adc) +{ + static long long var = 0; + int i = 0; //length of array is 8,9 + for (i=0; i<8; i++) { + if ( adc < uadc[i]){ + break; + } + } + if ( i<9) + { + var++; + if (var%2) + return ulux[i]+0; + else + return ulux[i]-1; + } + return ulux[4]; +} + +static void isl_input_lux_poll_l(struct input_polled_dev *dev) +{ + struct us_device* idev = dev->private; + struct input_dev* input = idev->input_poll_devl->input; + struct i2c_client* client = idev->client; + int ret_val = 0; + + if (client == NULL){ + printk("%s client NULL!\n", __FUNCTION__); + return; + } + + //printk("%s\n", __FUNCTION__); + if (l_enable != 0) + { + //mutex_lock(&mutex); //dead lock!! 2013-7-9!!! + //printk(KERN_ALERT "by flashchen val is %x",val); + ret_val = isl_get_lux_datal(client); //adc + if (ret_val < 0) + return; + if (!no_adc_map) + ret_val = adc_to_lux(ret_val); + + input_report_abs(input, ABS_MISC, ret_val); + //printk("%s %d\n", __FUNCTION__, ret_val); + input_sync(input); + //mutex_unlock(&mutex); + } +} + +static void isl_input_lux_poll_p(struct input_polled_dev *dev) +{ + struct us_device* idev = dev->private; + struct input_dev* input = idev->input_poll_devp->input; + struct i2c_client* client = idev->client; + + int tmp_val = 0, debounce = 0; + int ret_val = 0; + + //printk("%s\n", __FUNCTION__); + if (p_enable != 0) + { + //mutex_lock(&mutex); + //printk(KERN_ALERT "by flashchen val is %x",val); + + #if 0 //just read raw data out 2013-7-18 + for (debounce=0; debounce<10; debounce++){ + ret_val = isl_get_lux_datap(client); + if (ret_val < 0) + return; + + tmp_val += ret_val; + msleep(1); + } + tmp_val /= 10; + //add for near/far detection! + if (tmp_val > 0x00ff) + tmp_val = 6; + else + tmp_val = 0; + input_report_abs(input, ABS_MISC, tmp_val); + input_sync(input); + #endif + + tmp_val = us5182_i2c_read(client, REGS_CR00); + + if (tmp_val & CR0_PROX_MASK) //approach + input_report_abs(input, ABS_MISC, 0); + else + input_report_abs(input, ABS_MISC, 6); + + input_sync(input); + //printk("%s %d\n", __FUNCTION__, tmp_val); + //mutex_unlock(&mutex); + } +} + +#if 0 +static struct i2c_device_id us5182_id[] = { + {"us5182", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, us5182_id); +#endif // 2013-7-9 + +static int mmad_open(struct inode *inode, struct file *file) +{ + dbg("Open the l-sensor node...\n"); + return 0; +} + +static int mmad_release(struct inode *inode, struct file *file) +{ + dbg("Close the l-sensor node...\n"); + return 0; +} + +static ssize_t mmadl_read(struct file *fl, char __user *buf, size_t cnt, loff_t *lf) +{ + int lux_data = 0; + //printk("%s try to mutex_lock \n", __FUNCTION__); + //mutex_lock(&mutex); + //printk("lock ok!\n"); + lux_data = isl_get_lux_datal(l_sensorconfig->client); + //mutex_unlock(&mutex); + if (lux_data < 0) + { + printk("Failed to read lux data!\n"); + return -1; + } + printk(KERN_ALERT "lux_data is %x\n",lux_data); + //return 0; + copy_to_user(buf, &lux_data, sizeof(lux_data)); + return sizeof(lux_data); +} + + +static ssize_t mmadp_read(struct file *fl, char __user *buf, size_t cnt, loff_t *lf) +{ + int lux_data = 0; + + //mutex_lock(&mutex); + lux_data = isl_get_lux_datap(l_sensorconfig->client); + //mutex_unlock(&mutex); + if (lux_data < 0) + { + errlog("Failed to read lux data!\n"); + return -1; + } + printk(KERN_ALERT "lux_data is %x\n",lux_data); + //return 0; + copy_to_user(buf, &lux_data, sizeof(lux_data)); + return sizeof(lux_data); +} + +static long +mmadl_ioctl(/*struct inode *inode,*/ struct file *file, unsigned int cmd, + unsigned long arg) +{ + void __user *argp = (void __user *)arg; + //char rwbuf[5]; + short enable; //amsr = -1; + unsigned int uval; + + //printk("l-sensor ioctr... cmd 0x%x arg %d\n", cmd, arg); + //memset(rwbuf, 0, sizeof(rwbuf)); + switch (cmd) { + case LIGHT_IOCTL_SET_ENABLE: + // enable/disable sensor + if (copy_from_user(&enable, argp, sizeof(short))) + { + printk(KERN_ERR "Can't get enable flag!!!\n"); + return -EFAULT; + } + dbg("enable=%d\n",enable); + if ((enable >=0) && (enable <=1)) + { + dbg("driver: disable/enable(%d) gsensor.\n", enable); + + //l_sensorconfig.sensor_enable = enable; + dbg("Should to implement d/e the light sensor!\n"); + l_enable = enable; + + } else { + printk(KERN_ERR "Wrong enable argument in %s !!!\n", __FUNCTION__); + return -EINVAL; + } + break; + case WMT_IOCTL_SENSOR_GET_DRVID: +#define DRVID 0 + uval = DRVID ; + if (copy_to_user((unsigned int*)arg, &uval, sizeof(unsigned int))) + { + return -EFAULT; + } + dbg("us5182_driver_id:%d\n",uval); + default: + break; + } + + return 0; +} + + +static long +mmadp_ioctl(/*struct inode *inode,*/ struct file *file, unsigned int cmd, + unsigned long arg) +{ + void __user *argp = (void __user *)arg; + //char rwbuf[5]; + short enable; //amsr = -1; + unsigned int uval; + unsigned char regval; + + dbg("l-sensor ioctr...\n"); + //memset(rwbuf, 0, sizeof(rwbuf)); + switch (cmd) { + case LIGHT_IOCTL_SET_ENABLE: + // enable/disable sensor + if (copy_from_user(&enable, argp, sizeof(short))) + { + printk(KERN_ERR "Can't get enable flag!!!\n"); + return -EFAULT; + } + dbg("enable=%d\n",enable); + if ((enable >=0) && (enable <=1)) + { + dbg("driver: disable/enable(%d) gsensor.\n", enable); + + //l_sensorconfig.sensor_enable = enable; + dbg("Should to implement d/e the light sensor!\n"); + p_enable = enable; + #if 1 + if(p_enable) + { + regval = us5182_i2c_read(l_sensorconfig->client, 0); + regval &= ~(3 << 4); + i2c_smbus_write_byte_data(l_sensorconfig->client, 0, regval); + } + else + { + regval = us5182_i2c_read(l_sensorconfig->client, 0); + regval &= ~(3 << 4); + regval |= (1 << 4); + i2c_smbus_write_byte_data(l_sensorconfig->client, 0, regval); + } + #endif + + } else { + printk(KERN_ERR "Wrong enable argument in %s !!!\n", __FUNCTION__); + return -EINVAL; + } + break; + case WMT_IOCTL_SENSOR_GET_DRVID: +#define DRVID 0 + uval = DRVID ; + if (copy_to_user((unsigned int*)arg, &uval, sizeof(unsigned int))) + { + return -EFAULT; + } + dbg("us5182_driver_id:%d\n",uval); + default: + break; + } + + return 0; +} + + +static struct file_operations mmadl_fops = { + .owner = THIS_MODULE, + .open = mmad_open, + .release = mmad_release, + .read = mmadl_read, + .unlocked_ioctl = mmadl_ioctl, +}; + +static struct miscdevice mmadl_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "lsensor_ctrl", + .fops = &mmadl_fops, +}; + +static struct file_operations mmadp_fops = { + .owner = THIS_MODULE, + .open = mmad_open, + .release = mmad_release, + .read = mmadp_read, + .unlocked_ioctl = mmadp_ioctl, +}; + +static struct miscdevice mmadp_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "psensor_ctrl", + .fops = &mmadp_fops, +}; + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void us5182_early_suspend(struct early_suspend *h) +{ + dbg("start\n"); + mutex_lock(&mutex); + //pm_runtime_get_sync(dev); + //isl_set_mod(client, ISL_MOD_POWERDOWN); + //pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + dbg("exit\n"); +} + +static void us5182_late_resume(struct early_suspend *h) +{ + struct i2c_client *client = l_sensorconfig->client; + + dbg("start\n"); + mutex_lock(&mutex); + //pm_runtime_get_sync(dev); + //isl_set_mod(client, last_mod); + //isl_set_default_config(client); + //pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + dbg("exit\n"); +} +#endif + +int us5182_i2c_write(struct i2c_client *client, u8 reg,u8 mask, u8 shift, int val ) { + //struct us5182_data *data = i2c_get_clientdata(client); + int err; + u8 tmp; + mutex_lock(&mutex); + + tmp = reg_cache[reg]; + tmp &= ~mask; + tmp |= val << shift; + + err = i2c_smbus_write_byte_data(client, reg, tmp); + if (!err) + reg_cache[reg] = tmp; + + mutex_unlock(&mutex); + if (err >= 0) return 0; + + printk("%s %d i2c transfer error\n", __func__, __LINE__); + return err; +} + + +static int set_word_mode(struct i2c_client *client, int mode) +{ + // + return us5182_i2c_write(client, REGS_CR00, + CR0_WORD_MASK, CR0_WORD_SHIFT, mode); +} + + +static int set_oneshotmode(struct i2c_client *client, int mode) +{ + return us5182_i2c_write(client,REGS_CR00,CR0_ONESHOT_MASK, CR0_ONESHOT_SHIFT, mode); +} + + +static int set_opmode(struct i2c_client *client, int mode) +{ + return us5182_i2c_write(client,REGS_CR00,CR0_OPMODE_MASK, + CR0_OPMODE_SHIFT, mode); +} + +/* power_status */ +static int set_power_status(struct i2c_client *client, int status) +{ + if(status == CR0_SHUTDOWN_EN ) + return us5182_i2c_write(client,REGS_CR00,CR0_SHUTDOWN_MASK, + CR0_SHUTDOWN_SHIFT,CR0_SHUTDOWN_EN); + else + return us5182_i2c_write(client,REGS_CR00,CR0_SHUTDOWN_MASK, + CR0_SHUTDOWN_SHIFT, CR0_OPERATION); +} + + +static int us5182_init_client(struct i2c_client *client) +{ + + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + int i = 0; + int v = -1; + if ( !i2c_check_functionality(adapter,I2C_FUNC_SMBUS_BYTE_DATA) ) { + printk(KERN_INFO "byte op is not permited.\n"); + return -EIO; + } + + /* read all the registers once to fill the cache. + * if one of the reads fails, we consider the init failed */ + + for (i = 0; i < ARRAY_SIZE(reg_cache); i++) { + v = us5182_i2c_read(client, i); + printk("reg 0x%x value 0x%x \n", i, v); + if (v < 0) + return -ENODEV; + reg_cache[i] = v; + } + + /*Set Default*/ + set_word_mode(client, 0);//word enable? //just byte one time + set_power_status(client,CR0_OPERATION); //power on? + set_opmode(client,CR0_OPMODE_ALSONLY); //CR0_OPMODE_ALSANDPS CR0_OPMODE_ALSONLY + set_oneshotmode(client, CR0_ONESHOT_DIS); + + us5182_i2c_write(client, REGS_CR03, CR3_LEDDR_MASK, CR3_LEDDR_SHIFT, CR3_LEDDR_50); + + //set als gain + us5182_i2c_write(client, REGS_CR01, CR1_ALS_GAIN_MASK, CR1_ALS_GAIN_SHIFT, CR1_ALS_GAIN_X8); + + //set ps threshold --> lth, hth + us5182_i2c_write(client, REGS_INT_LSB_TH_HI_PS, 0xff, 0, psh_l8th); // + us5182_i2c_write(client, REGS_INT_MSB_TH_HI_PS, 0xff, 0, psh_h8th); //0 default + + us5182_i2c_write(client, REGS_INT_LSB_TH_LO_PS, 0xff, 0, psl_l8th); // + us5182_i2c_write(client, REGS_INT_MSB_TH_LO_PS, 0xff, 0, psl_h8th); // 0 default + //set_resolution(client,us5182_RES_16); + //set_range(client,3); + //set_int_ht(client,0x3E8); //1000 lux + //set_int_lt(client,0x8); //8 lux + //dev_info(&data->client->dev, "us5182 ver. %s found.\n",DRIVER_VERSION); + + /*init global variable*/ + error_flag = 0; + previous_value = 0; + this_value = 0; + debounces = 2;//debounces 5 times + return 0; +} +//******add for sys debug devic_attribute +static ssize_t reg_show(struct device *dev, struct device_attribute *attr, char *buf) { + + int i = 0, val = 0; + printk("<<<<<<<<0x%x\n", reg, res, val); + + return count; +} +//struct device_attribute dev_attr_reg = __ATTR(reg, 0644, reg_show, reg_store); +//DEVICE_ATTR(reg, 0644, reg_show, reg_store); + +static ssize_t adc_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + + int i; + int size = sizeof(uadc)/sizeof(uadc[0]); + printk("<<<%s\n", __FUNCTION__); + for (i=0; i>>\n", buf); + n = sscanf(buf, "%d:%d", &index, &tmp); + printk("<<<=0 && index=0; i--) + device_remove_file(dev, &attr[i]);//&attr[i].attr + } + return err; +} + +static void device_remove_attribute(struct device *dev, struct device_attribute *attr) +{ + int i; + for (i=0; attr[i].attr.name != NULL; i++) + device_remove_file(dev, &attr[i]); //&attr[i].attr +} +//add end +static int +us5182_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + int res=0; + + struct us_device* idev = kzalloc(sizeof(struct us_device), GFP_KERNEL); + if(!idev) + return -ENOMEM; + + l_sensorconfig = idev; + + /*initial enable device id*/ + idev->enable_id = 0x00; + + gclient = client; + /* initialize the us5182 chip */ + res = us5182_init_client(client);// + + if (res != 0) + goto err_input_allocate_device; +/* last mod is ALS continuous */ + //pm_runtime_enable(&client->dev); + idev->input_poll_devl = input_allocate_polled_device(); + if(!idev->input_poll_devl) + { + res = -ENOMEM; + goto err_input_allocate_device; + } + idev->input_poll_devp = input_allocate_polled_device(); + if(!idev->input_poll_devp) + { + res = -ENOMEM; + goto err_input_allocate_device; + } + idev->client = client; + + idev->input_poll_devl->private = idev; + idev->input_poll_devl->poll = isl_input_lux_poll_l; + idev->input_poll_devl->poll_interval = 100;//50; + idev->input_poll_devl->input->open = isl_input_open; + idev->input_poll_devl->input->close = isl_input_close; + idev->input_poll_devl->input->name = "lsensor_lux"; + idev->input_poll_devl->input->id.bustype = BUS_I2C; + idev->input_poll_devl->input->dev.parent = &client->dev; + + input_set_drvdata(idev->input_poll_devl->input, idev); + input_set_capability(idev->input_poll_devl->input, EV_ABS, ABS_MISC); + input_set_abs_params(idev->input_poll_devl->input, ABS_MISC, 0, 16000, 0, 0); + + idev->input_poll_devp->private = idev; + idev->input_poll_devp->poll = isl_input_lux_poll_p; + idev->input_poll_devp->poll_interval = 10;//100; 50ms + idev->input_poll_devp->input->open = isl_input_open; + idev->input_poll_devp->input->close = isl_input_close; + idev->input_poll_devp->input->name = "psensor_lux"; + idev->input_poll_devp->input->id.bustype = BUS_I2C; + idev->input_poll_devp->input->dev.parent = &client->dev; + + input_set_drvdata(idev->input_poll_devp->input, idev); + input_set_capability(idev->input_poll_devp->input, EV_ABS, ABS_MISC); + input_set_abs_params(idev->input_poll_devp->input, ABS_MISC, 0, 16000, 0, 0); + i2c_set_clientdata(client, idev); + /* set default config after set_clientdata */ + //res = isl_set_default_config(client); + res = misc_register(&mmadl_device); + if (res) { + errlog("mmad_device register failed\n"); + goto err_misc_registerl; + } + res = misc_register(&mmadp_device); + if (res) { + errlog("mmad_device register failed\n"); + goto err_misc_registerp; + } + res = input_register_polled_device(idev->input_poll_devl); + if(res < 0) + goto err_input_register_devicel; + res = input_register_polled_device(idev->input_poll_devp); + if(res < 0) + goto err_input_register_devicep; + // suspend/resume register +#ifdef CONFIG_HAS_EARLYSUSPEND + idev->earlysuspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + idev->earlysuspend.suspend = us5182_early_suspend; + idev->earlysuspend.resume = us5182_late_resume; + register_early_suspend(&(idev->earlysuspend)); +#endif + + dbg("us5182 probe succeed!\n"); + res = alloc_chrdev_region(&idev->devno, 0, 1, "us5182"); + if(res) + { + printk("can't allocate chrdev\n"); + return 0; + } + idev->class = class_create(THIS_MODULE, "us5182-lsensor"); + if (IS_ERR(idev->class)) { + printk("<<< %s class_create() error!\n", __FUNCTION__); + return 0; + } + idev->lsdev = device_create(idev->class, NULL, idev->devno, NULL, "us5182"); + if (IS_ERR(idev->lsdev)) { + printk("<<< %s device_create() error!\n", __FUNCTION__); + return 0; + } + res = device_create_attribute(idev->lsdev, us5182_attr); + return 0; +err_input_register_devicep: + input_free_polled_device(idev->input_poll_devp); +err_input_register_devicel: + input_free_polled_device(idev->input_poll_devl); +err_misc_registerp: + misc_deregister(&mmadp_device); +err_misc_registerl: + misc_deregister(&mmadl_device); +err_input_allocate_device: + //__pm_runtime_disable(&client->dev, false); + kfree(idev); + return res; +} + +static int us5182_remove(struct i2c_client *client) +{ + int i = 0; + struct us_device* idev = i2c_get_clientdata(client); +#if 1 + //device_remove_file(idev->lsdev, &dev_attr_reg); + device_remove_attribute(idev->lsdev, us5182_attr); + unregister_chrdev_region(idev->devno, 1); + device_destroy(idev->class, idev->devno); + class_destroy(idev->class); +#endif + printk("%s %d\n", __FUNCTION__, i++); // 0 + //unregister_early_suspend(&(idev->earlysuspend)); + misc_deregister(&mmadl_device); + printk("%s %d\n", __FUNCTION__, i++); + misc_deregister(&mmadp_device); + printk("%s %d\n", __FUNCTION__, i++); + input_unregister_polled_device(idev->input_poll_devl);//here block?? + printk("%s %d\n", __FUNCTION__, i++); + input_unregister_polled_device(idev->input_poll_devp); + printk("%s %d\n", __FUNCTION__, i++); + input_free_polled_device(idev->input_poll_devl); + printk("%s %d\n", __FUNCTION__, i++); + input_free_polled_device(idev->input_poll_devp); + printk("%s %d\n", __FUNCTION__, i++); + //__pm_runtime_disable(&client->dev, false); + + kfree(idev); + printk(KERN_INFO MODULE_NAME ": %s us5182 remove call, \n", __func__); + return 0; +} +static void us5182_shutdown(struct i2c_client *client) +{ + l_enable = 0; + p_enable = 0; +} + +static int us5182_suspend(struct i2c_client *client, pm_message_t message) +{ + return 0; +} +static int us5182_resume(struct i2c_client *client) +{ + int res = 0; + res = us5182_init_client(client);// + return 0; +} + +static const struct i2c_device_id us5182_id[] = { + { SENSOR_I2C_NAME , 0 }, + {}, +}; + + +static struct i2c_driver us5182_i2c_driver = +{ + .probe = us5182_probe, + .remove = us5182_remove, + .suspend = us5182_suspend, + .resume = us5182_resume, + .shutdown = us5182_shutdown, + .driver = { + .name = SENSOR_I2C_NAME, + .owner = THIS_MODULE, + }, + .id_table = us5182_id, +}; + +static int get_adc_val(void) +{ + int i=0, varlen=0, n=0; + __u32 buf[8] = {0}; + char varbuf[50] ={0}; + char *name = "wmt.io.lsensor"; + char *psth = "wmt.io.psensor"; + int thbuf[4] = {0}; + + varlen = sizeof(varbuf); + if (wmt_getsyspara(psth, varbuf, &varlen)) + { + printk("<<<. All Rights Reserved. + * us5182 Light Sensor Driver for Linux 2.6 + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __us5182_H__ +#define __us5182_H__ + +#include + +#define SENSOR_I2C_NAME "us5182" +#define SENSOR_I2C_ADDR (0x72>>1) //0x72 //7bit 0x39 +/*us5182 Slave Addr*/ +#define LIGHT_ADDR 0x39 //0x72 //7bit 0x39 + +/*Interrupt PIN for S3C6410*/ +//#define IRQ_LIGHT_INT IRQ_EINT(6) //comment for compile error + +/*Register Set*/ +#define REGS_CR00 0x00 +#define REGS_CR01 0x01 +#define REGS_CR02 0x02 +#define REGS_CR03 0x03 +//ALS +#define REGS_INT_LSB_TH_LO 0x04 +#define REGS_INT_MSB_TH_LO 0x05 +#define REGS_INT_LSB_TH_HI 0x06 +#define REGS_INT_MSB_TH_HI 0x07 +//PS +#define REGS_INT_LSB_TH_LO_PS 0x08 +#define REGS_INT_MSB_TH_LO_PS 0x09 +#define REGS_INT_LSB_TH_HI_PS 0x0A +#define REGS_INT_MSB_TH_HI_PS 0x0B +//ALS data +#define REGS_LSB_SENSOR 0x0C +#define REGS_MSB_SENSOR 0x0D +//PS data +#define REGS_LSB_SENSOR_PS 0x0E +#define REGS_MSB_SENSOR_PS 0x0F + +#define REGS_CR10 0x10 +#define REGS_CR11 0x11 +#define REGS_CR16 0x16 +#define REGS_CR20 0x20 +#define REGS_CR21 0x21 +#define REGS_CR22 0x22 +#define REGS_CR29 0x29 +#define REGS_CR2A 0x2A +#define REGS_CR2B 0x2B +#define REGS_VERSION_ID 0x1F +#define REGS_CHIP_ID 0xB2 + +/*ShutDown_EN*/ +#define CR0_OPERATION 0x0 +#define CR0_SHUTDOWN_EN 0x1 + +#define CR0_SHUTDOWN_SHIFT (7) +#define CR0_SHUTDOWN_MASK (0x1 << CR0_SHUTDOWN_SHIFT) + +/*OneShot_EN*/ +#define CR0_ONESHOT_EN 0x01 +#define CR0_ONESHOT_DIS 0x00 +#define CR0_ONESHOT_SHIFT (6) +#define CR0_ONESHOT_MASK (0x1 << CR0_ONESHOT_SHIFT) + +/*Operation Mode*/ +#define CR0_OPMODE_ALSANDPS 0x0 +#define CR0_OPMODE_ALSONLY 0x1 +#define CR0_OPMODE_IRONLY 0x2 + +#define CR0_OPMODE_SHIFT (4) +#define CR0_OPMODE_MASK (0x3 << CR0_OPMODE_SHIFT) + +/*all int flag (PROX, INT_A, INT_P)*/ +#define CR0_ALL_INT_CLEAR 0x0 + +#define CR0_ALL_INT_SHIFT (1) +#define CR0_ALL_INT_MASK (0x7 << CR0_ALL_INT_SHIFT) + + +/*indicator of object proximity detection*/ +#define CR0_PROX_CLEAR 0x0 + +#define CR0_PROX_SHIFT (3) +#define CR0_PROX_MASK (0x1 << CR0_PROX_SHIFT) + +/*interrupt status of proximity sensor*/ +#define CR0_INTP_CLEAR 0x0 + +#define CR0_INTP_SHIFT (2) +#define CR0_INTP_MASK (0x1 << CR0_INTP_SHIFT) + +/*interrupt status of ambient sensor*/ +#define CR0_INTA_CLEAR 0x0 + +#define CR0_INTA_SHIFT (1) +#define CR0_INTA_MASK (0x1 << CR0_INTA_SHIFT) + +/*Word mode enable*/ +#define CR0_WORD_EN 0x1 + +#define CR0_WORD_SHIFT (0) +#define CR0_WORD_MASK (0x1 << CR0_WORD_SHIFT) + + +/*ALS fault queue depth for interrupt enent output*/ +#define CR1_ALS_FQ_1 0x0 +#define CR1_ALS_FQ_4 0x1 +#define CR1_ALS_FQ_8 0x2 +#define CR1_ALS_FQ_16 0x3 +#define CR1_ALS_FQ_24 0x4 +#define CR1_ALS_FQ_32 0x5 +#define CR1_ALS_FQ_48 0x6 +#define CR1_ALS_FQ_63 0x7 + +#define CR1_ALS_FQ_SHIFT (5) +#define CR1_ALS_FQ_MASK (0x7 << CR1_ALS_FQ_SHIFT) + +/*resolution for ALS*/ +#define CR1_ALS_RES_12BIT 0x0 +#define CR1_ALS_RES_14BIT 0x1 +#define CR1_ALS_RES_16BIT 0x2 +#define CR1_ALS_RES_16BIT_2 0x3 + +#define CR1_ALS_RES_SHIFT (3) +#define CR1_ALS_RES_MASK (0x3 << CR1_ALS_RES_SHIFT) + +/*sensing amplifier selection for ALS*/ +#define CR1_ALS_GAIN_X1 0x0 +#define CR1_ALS_GAIN_X2 0x1 +#define CR1_ALS_GAIN_X4 0x2 +#define CR1_ALS_GAIN_X8 0x3 +#define CR1_ALS_GAIN_X16 0x4 +#define CR1_ALS_GAIN_X32 0x5 +#define CR1_ALS_GAIN_X64 0x6 +#define CR1_ALS_GAIN_X128 0x7 + +#define CR1_ALS_GAIN_SHIFT (0) +#define CR1_ALS_GAIN_MASK (0x7 << CR1_ALS_GAIN_SHIFT) + + +/*PS fault queue depth for interrupt event output*/ +#define CR2_PS_FQ_1 0x0 +#define CR2_PS_FQ_4 0x1 +#define CR2_PS_FQ_8 0x2 +#define CR2_PS_FQ_15 0x3 + +#define CR2_PS_FQ_SHIFT (6) +#define CR2_PS_FQ_MASK (0x3 << CR2_PS_FQ_SHIFT) + +/*interrupt type setting */ +/*low active*/ +#define CR2_INT_LEVEL 0x0 +/*low pulse*/ +#define CR2_INT_PULSE 0x1 + +#define CR2_INT_SHIFT (5) +#define CR2_INT_MASK (0x1 << CR2_INT_SHIFT) + +/*resolution for PS*/ +#define CR2_PS_RES_12 0x0 +#define CR2_PS_RES_14 0x1 +#define CR2_PS_RES_16 0x2 +#define CR2_PS_RES_16_2 0x3 + +#define CR2_PS_RES_SHIFT (3) +#define CR2_PS_RES_MASK (0x3 << CR2_PS_RES_SHIFT) + +/*sensing amplifier selection for PS*/ +#define CR2_PS_GAIN_1 0x0 +#define CR2_PS_GAIN_2 0x1 +#define CR2_PS_GAIN_4 0x2 +#define CR2_PS_GAIN_8 0x3 +#define CR2_PS_GAIN_16 0x4 +#define CR2_PS_GAIN_32 0x5 +#define CR2_PS_GAIN_64 0x6 +#define CR2_PS_GAIN_128 0x7 + +#define CR2_PS_GAIN_SHIFT (0) +#define CR2_PS_GAIN_MASK (0x7 << CR2_PS_GAIN_SHIFT) + +/*wait-time slot selection*/ +#define CR3_WAIT_SEL_0 0x0 +#define CR3_WAIT_SEL_4 0x1 +#define CR3_WAIT_SEL_8 0x2 +#define CR3_WAIT_SEL_16 0x3 + +#define CR3_WAIT_SEL_SHIFT (6) +#define CR3_WAIT_SEL_MASK (0x3 << CR3_WAIT_SEL_SHIFT) + +/*IR-LED drive peak current setting*/ +#define CR3_LEDDR_12_5 0x0 +#define CR3_LEDDR_25 0x1 +#define CR3_LEDDR_50 0x2 +#define CR3_LEDDR_100 0x3 + +#define CR3_LEDDR_SHIFT (4) +#define CR3_LEDDR_MASK (0x3 << CR3_LEDDR_SHIFT) + +/*INT pin source selection*/ +#define CR3_INT_SEL_BATH 0x0 +#define CR3_INT_SEL_ALS 0x1 +#define CR3_INT_SEL_PS 0x2 +#define CR3_INT_SEL_PSAPP 0x3 + +#define CR3_INT_SEL_SHIFT (2) +#define CR3_INT_SEL_MASK (0x3 << CR3_INT_SEL_SHIFT) + +/*software reset for register and core*/ +#define CR3_SOFTRST_EN 0x1 + +#define CR3_SOFTRST_SHIFT (0) +#define CR3_SOFTRST_MASK (0x1 << CR3_SOFTRST_SHIFT) + +/*modulation frequency of LED driver*/ +#define CR10_FREQ_DIV2 0x0 +#define CR10_FREQ_DIV4 0x1 +#define CR10_FREQ_DIV8 0x2 +#define CR10_FREQ_DIV16 0x3 + +#define CR10_FREQ_SHIFT (1) +#define CR10_FREQ_MASK (0x3 << CR10_FREQ_SHIFT) + +/*50/60 Rejection enable*/ +#define CR10_REJ_5060_DIS 0x00 +#define CR10_REJ_5060_EN 0x01 + +#define CR10_REJ_5060_SHIFT (0) +#define CR10_REJ_5060_MASK (0x1 << CR10_REJ_5060_SHIFT) + +#define us5182_NUM_CACHABLE_REGS 0x12 + +/*enable sensor*/ +#define ID_LIGHT 0 +#define ID_PROXIMITY 1 + +#define DEVICE_LIGHT (1 << ID_LIGHT) +#define DEVICE_PROXIMITY (1 << ID_PROXIMITY) +#endif diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/Kconfig b/ANDROID_3.4.5/drivers/input/touchscreen/Kconfig index 1e7c563c..873ca6c3 100644 --- a/ANDROID_3.4.5/drivers/input/touchscreen/Kconfig +++ b/ANDROID_3.4.5/drivers/input/touchscreen/Kconfig @@ -851,4 +851,28 @@ config TOUCHSCREEN_TPS6507X To compile this driver as a module, choose M here: the module will be called tps6507x_ts. +config TOUCHSCREEN_VT1609 + tristate "Vt1609 Dual-touch Support,Compatible with Vt1603a Single-touch" + default y + depends on ARCH_WMT + help + Say Y here if you have a vt1603a single or vt1609 dual touchscreen and + want to enable support for the built-in touchscreen. + + To compile this driver as a module, choose M here: the + module will be called vt1609_dual_ts. + +source "drivers/input/touchscreen/gsl1680_ts/Kconfig" +source "drivers/input/touchscreen/sitronix/Kconfig" +source "drivers/input/touchscreen/zet6221_ts/Kconfig" +source "drivers/input/touchscreen/cyp140_ts/Kconfig" +source "drivers/input/touchscreen/ft5x0x/Kconfig" +source "drivers/input/touchscreen/ft6x0x/Kconfig" +source "drivers/input/touchscreen/aw5306_ts/Kconfig" +source "drivers/input/touchscreen/ssd253x_ts/Kconfig" +source "drivers/input/touchscreen/lw86x0_ts/Kconfig" +source "drivers/input/touchscreen/gt9xx_ts/Kconfig" +source "drivers/input/touchscreen/icn83xx_ts/Kconfig" +source "drivers/input/touchscreen/icn85xx_ts/Kconfig" +source "drivers/input/touchscreen/sis_usbhid_ts/Kconfig" endif diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/Makefile b/ANDROID_3.4.5/drivers/input/touchscreen/Makefile index 175d6414..b632eb48 100644 --- a/ANDROID_3.4.5/drivers/input/touchscreen/Makefile +++ b/ANDROID_3.4.5/drivers/input/touchscreen/Makefile @@ -70,3 +70,19 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o obj-$(CONFIG_TOUCHSCREEN_TPS6507X) += tps6507x-ts.o + +obj-$(CONFIG_TOUCHSCREEN_VT1609) += vt1609_ts/ +#GSL1680 touchscreen +obj-$(CONFIG_TOUCHSCREEN_GSL1680) += gsl1680_ts/ +obj-$(CONFIG_TOUCHSCREEN_SITRONIX) += sitronix/ +obj-$(CONFIG_TOUCHSCREEN_ZET6221) += zet6221_ts/ +obj-$(CONFIG_TOUCHSCREEN_CYP140) += cyp140_ts/ +obj-$(CONFIG_TOUCHSCREEN_FT5X0X) += ft5x0x/ +obj-$(CONFIG_TOUCHSCREEN_FT6X0X) += ft6x0x/ +obj-$(CONFIG_TOUCHSCREEN_AW5306) += aw5306_ts/ +obj-$(CONFIG_TOUCHSCREEN_SSD253X) += ssd253x_ts/ +obj-$(CONFIG_TOUCHSCREEN_LW86X0) += lw86x0_ts/ +obj-$(CONFIG_TOUCHSCREEN_GT9XX) += gt9xx_ts/ +obj-$(CONFIG_TOUCHSCREEN_ICN83XX) += icn83xx_ts/ +obj-$(CONFIG_TOUCHSCREEN_ICN85XX) += icn85xx_ts/ +obj-$(CONFIG_TOUCHSCREEN_SIS) += sis_usbhid_ts/ diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_Base.b b/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_Base.b new file mode 100755 index 00000000..e3e6c22a Binary files /dev/null and b/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_Base.b differ diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_Clb.b b/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_Clb.b new file mode 100755 index 00000000..40e49326 Binary files /dev/null and b/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_Clb.b differ diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_Drv.b b/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_Drv.b new file mode 100755 index 00000000..03f070a1 Binary files /dev/null and b/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_Drv.b differ diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_Drv.h b/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_Drv.h new file mode 100755 index 00000000..47042361 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_Drv.h @@ -0,0 +1,158 @@ +/************************************************************************** +* AW5306_Drv.h +* +* AW5306 Driver code version 1.0 +* +* Create Date : 2012/06/25 +* +* Modify Date : +* +* Create by : wuhaijun +* +**************************************************************************/ + +#ifndef AW5306_DRV_H + +#define AW5306_DRV_H + +#define Release_Ver 219 + + +#define MAX_POINT 5 + +#define NUM_TX 21 // TX number of TOUCH IC +#define NUM_RX 12 // RX number of TOUCH IC + +//#define NEWBASE_PROCESS //new base process need test!!! + +#define ABS(X) ((X > 0) ? (X) : (-X)) + + +typedef enum{ + RawDataMode = 0, + DeltaMode, + MonitorMode +}enumWorkMode; + +typedef enum{ + BASE_INITIAL, + BASE_FAST_TRACE, + BASE_STABLE, + TEMP_DRIFT +} CompensateMode; + +typedef struct { + unsigned short Base[NUM_TX][NUM_RX]; + unsigned short ChipBase[NUM_TX][NUM_RX]; + signed char Flag[NUM_TX][NUM_RX]; + signed char BaseCnt[NUM_TX][NUM_RX]; + unsigned char CompensateFlag; + unsigned char TraceTempIncCnt; + unsigned char TraceTempDecCnt; + unsigned char CompensateStateFrameCnt; + short LastMaxDiff; + CompensateMode CompensateState; + unsigned int InitialFrameCnt; + unsigned char PosBigAreaTouchFlag; + unsigned char NegBigAreaTouchFlag; + unsigned char BigAreaFirstFlag; + unsigned char BigAreaChangeFlag; + unsigned short BigTouchFrame; + unsigned short FrameCnt; + unsigned char LongStableCnt; + unsigned char PosPeakCnt; + unsigned char NegPeakCnt; + unsigned char PeakCheckFrameCnt; + unsigned char BaseFrozen; + unsigned char PosPeakCompensateCnt[MAX_POINT]; + unsigned char NegPeakCompensateCnt[MAX_POINT]; +}STRUCTBASE; + +typedef struct { + unsigned char Peak[MAX_POINT][2]; + unsigned char LastPeak[MAX_POINT][2]; + unsigned char NegPeak[MAX_POINT][2]; + unsigned char CurrentPointNum; + unsigned char CurrentNegPointNum; + unsigned char LastPointNum; +}STRUCTPEAK; + +typedef struct { + unsigned short X,Y; // X,Y coordinate + unsigned char PointID; // Assigned point ID + unsigned char Event; // Event of current point +}STRUCTPOINT; + +typedef struct { + STRUCTPOINT PointInfo[MAX_POINT]; + STRUCTPOINT RptPoint[MAX_POINT]; + unsigned char PointNum; + unsigned char LastPointNum; + unsigned char NegPointNum; + unsigned char FilterPointCnt; + unsigned char FirstLiftUpFlag; + unsigned char TouchStatus; + unsigned char PointHoldCnt[MAX_POINT]; + unsigned char PointPressCnt[MAX_POINT]; + +}STRUCTFRAME; + +typedef struct { + unsigned char fileflag[14]; + unsigned char TXOFFSET[(NUM_TX+1)/2]; + unsigned char RXOFFSET[(NUM_RX+1)/2]; + unsigned char TXCAC[NUM_TX]; + unsigned char RXCAC[NUM_RX]; + unsigned char TXGAIN[NUM_TX]; + short SOFTOFFSET[NUM_TX][NUM_RX]; +}STRUCTCALI; + +#define NOISE_LISTENING 0 +#define NOISE_SCAN 1 +#define NOISE_FREQ_JUMP 2 +#define NOISE_SEEK_FAIL 3 + +#define NOISE_FRM_NORMAL 0 +#define NOISE_FRM_PRE_MEASURE 1 +#define NOISE_FRM_MEASURE 2 + +typedef struct { + unsigned char AllFrmCnt; // Frame counter to generate noise meaure frame indicator + unsigned char NoiseFrmCnt; // Frame counter for noise level checking + unsigned char IdleFrmCnt; // No touch frame counter + unsigned char State; // Noise checking state: LISTENING, SCAN, JUMP + unsigned char FrmState; // Frame type indicator: PRE_MEAUSRE, MEAUSRE, NORMAL + short NoiseNormal; // Noise in working freq + short NoiseScan; // Noise in scan freq + short Better_NoiseScan; //pfx:smaller Noise in Scan freq + unsigned char Better_ScanFreqID; //pfx:the Scan Freq for the smaller Noise + unsigned char ScanFreqID; // Scan freq ID + unsigned char WorkFreqID; // Current freq ID + short NoiseTh1; // Diff threshold for noise too high judgement + char JumpTh; // frame number threshold for freq jumping + char FailedFreqList [32]; // Searched freq indicator for freq scanning +}STRUCTNOISE; + + +void AW5306_TP_Init(void); +void AW5306_TP_Reinit(void); +void AW5306_Sleep(void); +char AW5306_TouchProcess(void); +void AW5306_ChargeMode(char mode); +unsigned char AW5306_GetPointNum(void); +unsigned char AW5306_GetPeakNum(void); +char AW5306_GetPoint(int *x,int *y, int *id, int *event,char Index); +void AW5306_GetBase(unsigned short *data, char x,char y); +void AW5306_GetDiff(short *data, char x,char y); +char AW5306_GetPeak(unsigned char *x,unsigned char *y,unsigned char Index); +char AW5306_GetNegPeak(unsigned char *x,unsigned char *y,unsigned char Index); +char AW5306_GetCalcPoint(unsigned short *x,unsigned short *y,unsigned char Index); +char AW5306_CLB(void); +void AW5306_CLB_GetCfg(void); +void AW5306_CLB_WriteCfg(void); +void TP_Force_Calibration(void); +void FreqScan(unsigned char BaseFreq); + + + +#endif diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_Reg.h b/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_Reg.h new file mode 100755 index 00000000..2bbbeb00 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_Reg.h @@ -0,0 +1,187 @@ +/************************************************************************** +* AW5306_Reg.h +* +* AW5306 Driver code version 1.0 +* +* Create Date : 2012/06/25 +* +* Modify Date : +* +* Create by : wuhaijun +* +**************************************************************************/ + +#ifndef AW5306_REG_H + +#define AW5306_REG_H + +#define SA_PAGE 0x00 +#define SA_IDRST 0x01 +#define SA_CTRL 0x02 +#define SA_SCANMD 0x03 +#define SA_IER 0x04 +#define SA_RX_NUM 0x05 +#define SA_RX_START 0x06 +#define SA_TX_NUM 0x07 +#define SA_TX_INDEX0 0x08 +#define SA_TX_INDEX1 0x09 +#define SA_TX_INDEX2 0x0A +#define SA_TX_INDEX3 0x0B +#define SA_TX_INDEX4 0x0C +#define SA_TX_INDEX5 0x0D +#define SA_TX_INDEX6 0x0E +#define SA_TX_INDEX7 0x0F +#define SA_TX_INDEX8 0x10 +#define SA_TX_INDEX9 0x11 +#define SA_TX_INDEX10 0x12 +#define SA_TX_INDEX11 0x13 +#define SA_TX_INDEX12 0x14 +#define SA_TX_INDEX13 0x15 +#define SA_TX_INDEX14 0x16 +#define SA_TX_INDEX15 0x17 +#define SA_TX_INDEX16 0x18 +#define SA_TX_INDEX17 0x19 +#define SA_TX_INDEX18 0x1A +#define SA_TX_INDEX19 0x1B +#define SA_TX_INDEX20 0x1C +#define SA_TXCAC0 0x1D +#define SA_TXCAC1 0x1E +#define SA_TXCAC2 0x1F +#define SA_TXCAC3 0x20 +#define SA_TXCAC4 0x21 +#define SA_TXCAC5 0x22 +#define SA_TXCAC6 0x23 +#define SA_TXCAC7 0x24 +#define SA_TXCAC8 0x25 +#define SA_TXCAC9 0x26 +#define SA_TXCAC10 0x27 +#define SA_TXCAC11 0x28 +#define SA_TXCAC12 0x29 +#define SA_TXCAC13 0x2A +#define SA_TXCAC14 0x2B +#define SA_TXCAC15 0x2C +#define SA_TXCAC16 0x2D +#define SA_TXCAC17 0x2E +#define SA_TXCAC18 0x2F +#define SA_TXCAC19 0x30 +#define SA_TXCAC20 0x31 +#define SA_TXOFFSET0 0x32 +#define SA_TXOFFSET1 0x33 +#define SA_TXOFFSET2 0x34 +#define SA_TXOFFSET3 0x35 +#define SA_TXOFFSET4 0x36 +#define SA_TXOFFSET5 0x37 +#define SA_TXOFFSET6 0x38 +#define SA_TXOFFSET7 0x39 +#define SA_TXOFFSET8 0x3A +#define SA_TXOFFSET9 0x3B +#define SA_TXOFFSET10 0x3C +#define SA_RXCAC0 0x3E +#define SA_RXCAC1 0x3F +#define SA_RXCAC2 0x40 +#define SA_RXCAC3 0x41 +#define SA_RXCAC4 0x42 +#define SA_RXCAC5 0x43 +#define SA_RXCAC6 0x44 +#define SA_RXCAC7 0x45 +#define SA_RXCAC8 0x46 +#define SA_RXCAC9 0x47 +#define SA_RXCAC10 0x48 +#define SA_RXCAC11 0x49 +#define SA_RXOFFSET0 0x4A +#define SA_RXOFFSET1 0x4B +#define SA_RXOFFSET2 0x4C +#define SA_RXOFFSET3 0x4D +#define SA_RXOFFSET4 0x4E +#define SA_RXOFFSET5 0x4F +#define SA_DRV_VLT 0x51 +#define SA_SCANFREQ1 0x52 +#define SA_SCANFREQ2 0x53 +#define SA_SCANFREQ3 0x54 +#define SA_TXADCGAIN0 0x55 +#define SA_TXADCGAIN1 0x56 +#define SA_TXADCGAIN2 0x57 +#define SA_TXADCGAIN3 0x58 +#define SA_TXADCGAIN4 0x59 +#define SA_TXADCGAIN5 0x5A +#define SA_TXADCGAIN6 0x5B +#define SA_TXADCGAIN7 0x5C +#define SA_TXADCGAIN8 0x5D +#define SA_TXADCGAIN9 0x5E +#define SA_TXADCGAIN10 0x5F +#define SA_TXADCGAIN11 0x60 +#define SA_TXADCGAIN12 0x61 +#define SA_TXADCGAIN13 0x62 +#define SA_TXADCGAIN14 0x63 +#define SA_TXADCGAIN15 0x64 +#define SA_TXADCGAIN16 0x65 +#define SA_TXADCGAIN17 0x66 +#define SA_TXADCGAIN18 0x67 +#define SA_TXADCGAIN19 0x68 +#define SA_TXADCGAIN20 0x69 +#define SA_WAITTIME 0x6A +#define SA_TCLKDLY 0x6B +#define SA_FINEADJ 0x6C +#define SA_TXCLKFREQ 0x6D +#define SA_SCANTIM 0x6E +#define SA_READSEL 0x70 +#define SA_ISR 0x71 +#define SA_STATE1 0x72 +#define SA_POSCNT 0x73 +#define SA_NEGCNT 0x74 +#define SA_VLDNUM 0x75 +#define SA_ADDRH 0x7D +#define SA_ADDRL 0x7E +#define SA_RAWDATA 0x7F +//////////////////////// +// Page 2 +//////////////////////// +#define SA_SINETABE1 0x03 +#define SA_SINETABE2 0x04 +#define SA_DATAOFFSET 0x05 +#define SA_TRACECTRL1 0x10 +#define SA_TRACECTRL2 0x11 +#define SA_TRACECTRL3 0x12 +#define SA_TRACEST 0x13 +#define SA_RPTNEGTH 0x14 +#define SA_RPTPOSTH 0x15 +#define SA_TRACESTEP 0x16 +#define SA_TRCLVLLO 0x17 +#define SA_TRCLVLPOSHI 0x18 +#define SA_TRCLVLNEGHI 0x19 +#define SA_TRACEINTERVAL 0x1A +#define SA_RXSTABLETH 0x1B +#define SA_POSLEVELTH 0x1C +#define SA_POSNUMTH 0x1D +#define SA_NEGLEVELTH 0x1E +#define SA_NEGNUMTH 0x1F +#define SA_BIGPOINTTH 0x20 +#define SA_BIGPOSTIMTH 0x21 +#define SA_BIGNEGTIMTH 0x22 +#define SA_NEGTIMTH 0x23 +#define SA_TRACEHIGHTIM 0x24 +#define SA_INITPNTTH 0x25 +#define SA_TCHCLRTIMSET 0x26 +#define SA_INITLVTH 0x27 +#define SA_MAXCHKTH 0x28 +#define SA_MINCHKTH 0x29 +#define SA_INITFORCEQUIT 0x2A +#define SA_CHAMPCFG 0x30 +#define SA_ADCCFG 0x31 +#define SA_IBCFG1 0x32 +#define SA_IBCFG2 0x33 +#define SA_LDOCFG 0x34 +#define SA_OSCCFG1 0x35 +#define SA_OSCCFG2 0x36 +#define SA_OSCCFG3 0x37 +#define SA_EN_CLK_QNTZ1 0x38 +#define SA_EN_CLK_QNTZ2 0x39 +#define SA_CPFREQ 0x3A +#define SA_ATEST1 0x3B +#define SA_ATEST2 0x3C +#define SA_RAMTST 0x60 +#define SA_TESTCFG 0x61 +#define SA_TSTDATAH 0x62 +#define SA_TSTDATAL 0x63 +#endif + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_ts.c b/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_ts.c new file mode 100755 index 00000000..f623c646 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_ts.c @@ -0,0 +1,1614 @@ +/* + * drivers/input/touchscreen/aw5306/aw5306.c + * + * FocalTech aw5306 TouchScreen driver. + * + * Copyright (c) 2010 Focal tech Ltd. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + * + * note: only support mulititouch Wenfs 2010-10-01 + */ +#include +#include +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "AW5306_Drv.h" +#include "AW5306_userpara.h" +#include "irq_gpio.h" + +#define CONFIG_AW5306_MULTITOUCH (1) +#define DEV_AW5306 "touch_aw5306" +#define TS_I2C_NAME "aw5306-ts" +#define AW5306_I2C_ADDR 0x38 +#define AW5306_I2C_BUS 0x01 + +//#define DEBUG_EN + +#undef dbg +#ifdef DEBUG_EN + #define dbg(fmt,args...) printk("DBG:%s_%d:"fmt,__FUNCTION__,__LINE__,##args) +#else + #define dbg(fmt,args...) +#endif + +#undef dbg_err +#define dbg_err(fmt,args...) printk("ERR:%s_%d:"fmt,__FUNCTION__,__LINE__,##args) + + + +struct ts_event { + int x[5]; + int y[5]; + int pressure; + int touch_ID[5]; + int touch_point; + int pre_point; +}; + +struct AW5306_ts_data { + const char *name; + struct input_dev *input_dev; + struct ts_event event; + struct work_struct pen_event_work; + struct workqueue_struct *ts_workqueue; + struct kobject *kobj; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif + struct timer_list touch_timer; + + int irq; + int irqgpio; + int rstgpio; + + int reslx; + int resly; + int nt; + int nb; + int xch; + int ych; + int swap; + int dbg; + int lcd_exchg; +}; + + +struct AW5306_ts_data *pContext=NULL; +static struct i2c_client *l_client=NULL; +static unsigned char suspend_flag=0; //0: sleep out; 1: sleep in +static short tp_idlecnt = 0; +static char tp_SlowMode = 0; +//static struct class *i2c_dev_class; + +extern char AW5306_CLB(void); +extern void AW5306_CLB_GetCfg(void); +extern STRUCTCALI AW_Cali; +extern AW5306_UCF AWTPCfg; +extern STRUCTBASE AW_Base; +extern short Diff[NUM_TX][NUM_RX]; +extern short adbDiff[NUM_TX][NUM_RX]; +extern short AWDeltaData[32]; + +char AW_CALI_FILENAME[50] = {0,}; +char AW_UCF_FILENAME[50] = {0,}; + +extern int wmt_setsyspara(char *varname, unsigned char *varval); +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); + + +void __aeabi_unwind_cpp_pr0(void) +{ +} + +void __aeabi_unwind_cpp_pr1(void) +{ +} + + +int AW_nvram_read(char *filename, char *buf, ssize_t len, int offset) +{ + struct file *fd; + //ssize_t ret; + int retLen = -1; + + mm_segment_t old_fs = get_fs(); + set_fs(KERNEL_DS); + + fd = filp_open(filename, O_RDONLY, 0); + + if(IS_ERR(fd)) { + printk("[AW5306][nvram_read] : failed to open!!\n"); + return -1; + } + + do{ + if ((fd->f_op == NULL) || (fd->f_op->read == NULL)) + { + printk("[AW5306][nvram_read] : file can not be read!!\n"); + break; + } + + if (fd->f_pos != offset) { + if (fd->f_op->llseek) { + if(fd->f_op->llseek(fd, offset, 0) != offset) { + printk("[AW5306][nvram_read] : failed to seek!!\n"); + break; + } + } else { + fd->f_pos = offset; + } + } + + retLen = fd->f_op->read(fd, + buf, + len, + &fd->f_pos); + + }while(false); + + filp_close(fd, NULL); + + set_fs(old_fs); + + + return retLen; +} + +int AW_nvram_write(char *filename, char *buf, ssize_t len, int offset) +{ + struct file *fd; + //ssize_t ret; + int retLen = -1; + + mm_segment_t old_fs = get_fs(); + set_fs(KERNEL_DS); + + fd = filp_open(filename, O_WRONLY|O_CREAT, 0666); + + if(IS_ERR(fd)) { + printk("[AW5306][nvram_write] : failed to open!!\n"); + return -1; + } + + do{ + if ((fd->f_op == NULL) || (fd->f_op->write == NULL)) + { + printk("[AW5306][nvram_write] : file can not be write!!\n"); + break; + } /* End of if */ + + if (fd->f_pos != offset) { + if (fd->f_op->llseek) { + if(fd->f_op->llseek(fd, offset, 0) != offset) { + printk("[AW5306][nvram_write] : failed to seek!!\n"); + break; + } + } else { + fd->f_pos = offset; + } + } + + retLen = fd->f_op->write(fd, + buf, + len, + &fd->f_pos); + + }while(false); + + filp_close(fd, NULL); + + set_fs(old_fs); + + return retLen; +} + + +int AW_I2C_WriteByte(u8 addr, u8 para) +{ + int ret; + u8 buf[3]; + struct i2c_msg msg[] = { + { + .addr = l_client->addr, + .flags = 0, + .len = 2, + .buf = buf, + }, + }; + buf[0] = addr; + buf[1] = para; + ret = i2c_transfer(l_client->adapter, msg, 1); + return ret; +} + + +unsigned char AW_I2C_ReadByte(u8 addr) +{ + int ret; + u8 buf[2] = {0}; + struct i2c_msg msgs[] = { + { + .addr = l_client->addr, + .flags = 0, + .len = 1, + .buf = buf, + }, + { + .addr = l_client->addr, + .flags = I2C_M_RD, + .len = 1, + .buf = buf, + }, + }; + buf[0] = addr; + //msleep(1); + ret = i2c_transfer(l_client->adapter, msgs, 2); + return buf[0]; +} + +unsigned char AW_I2C_ReadXByte( unsigned char *buf, unsigned char addr, unsigned short len) +{ + int ret,i; + u8 rdbuf[512] = {0}; + struct i2c_msg msgs[] = { + { + .addr = l_client->addr, + .flags = 0, + .len = 1, + .buf = rdbuf, + }, + { + .addr = l_client->addr, + .flags = I2C_M_RD, + .len = len, + .buf = rdbuf, + }, + }; + rdbuf[0] = addr; + //msleep(1); + ret = i2c_transfer(l_client->adapter, msgs, 2); + if (ret < 0) + pr_err("msg %s i2c read error: %d\n", __func__, ret); + for(i = 0; i < len; i++) + { + buf[i] = rdbuf[i]; + } + return ret; +} + +unsigned char AW_I2C_WriteXByte( unsigned char *buf, unsigned char addr, unsigned short len) +{ + int ret,i; + u8 wdbuf[512] = {0}; + + struct i2c_msg msgs[] = { + { + .addr = l_client->addr, + .flags = 0, + .len = len+1, + .buf = wdbuf, + } + }; + + wdbuf[0] = addr; + for(i = 0; i < len; i++) + { + wdbuf[i+1] = buf[i]; + } + //msleep(1); + ret = i2c_transfer(l_client->adapter, msgs, 1); + if (ret < 0) + pr_err("msg %s i2c read error: %d\n", __func__, ret); + return ret; +} + + +void AW_Sleep(unsigned int msec) +{ + msleep(msec); +} + +static ssize_t AW5306_get_Cali(struct device* cd,struct device_attribute *attr, char* buf); +static ssize_t AW5306_set_Cali(struct device* cd,struct device_attribute *attr, const char *buf, size_t count); +static ssize_t AW5306_get_reg(struct device* cd,struct device_attribute *attr, char* buf); +static ssize_t AW5306_write_reg(struct device* cd,struct device_attribute *attr, const char *buf, size_t count); +static ssize_t AW5306_get_Base(struct device* cd,struct device_attribute *attr, char* buf); +static ssize_t AW5306_get_Diff(struct device* cd,struct device_attribute *attr, char* buf); +static ssize_t AW5306_get_adbBase(struct device* cd,struct device_attribute *attr, char* buf); +static ssize_t AW5306_get_adbDiff(struct device* cd,struct device_attribute *attr, char* buf); +static ssize_t AW5306_get_FreqScan(struct device* cd,struct device_attribute *attr, char* buf); +static ssize_t AW5306_Set_FreqScan(struct device* cd, struct device_attribute *attr,const char* buf, size_t len); +static ssize_t AW5306_GetUcf(struct device* cd,struct device_attribute *attr, char* buf); + + + +static DEVICE_ATTR(cali, S_IRUGO | S_IWUGO, AW5306_get_Cali, AW5306_set_Cali); +static DEVICE_ATTR(readreg, S_IRUGO | S_IWUGO, AW5306_get_reg, AW5306_write_reg); +static DEVICE_ATTR(base, S_IRUGO | S_IWUSR, AW5306_get_Base, NULL); +static DEVICE_ATTR(diff, S_IRUGO | S_IWUSR, AW5306_get_Diff, NULL); +static DEVICE_ATTR(adbbase, S_IRUGO | S_IWUSR, AW5306_get_adbBase, NULL); +static DEVICE_ATTR(adbdiff, S_IRUGO | S_IWUSR, AW5306_get_adbDiff, NULL); +static DEVICE_ATTR(freqscan, S_IRUGO | S_IWUGO, AW5306_get_FreqScan, AW5306_Set_FreqScan); +static DEVICE_ATTR(getucf, S_IRUGO | S_IWUSR, AW5306_GetUcf, NULL); + + +static ssize_t AW5306_get_Cali(struct device* cd,struct device_attribute *attr, char* buf) +{ + unsigned char i,j; + ssize_t len = 0; + + len += snprintf(buf+len, PAGE_SIZE-len,"AWINIC RELEASE CODE VER = %d\n", Release_Ver); + + len += snprintf(buf+len, PAGE_SIZE-len,"*****AW5306 Calibrate data*****\n"); + len += snprintf(buf+len, PAGE_SIZE-len,"TXOFFSET:"); + + for(i=0;i<11;i++) + { + len += snprintf(buf+len, PAGE_SIZE-len, "0x%02X ", AW_Cali.TXOFFSET[i]); + } + + len += snprintf(buf+len, PAGE_SIZE-len, "\n"); + len += snprintf(buf+len, PAGE_SIZE-len, "RXOFFSET:"); + + for(i=0;i<6;i++) + { + len += snprintf(buf+len, PAGE_SIZE-len, "0x%02X ", AW_Cali.RXOFFSET[i]); + } + + len += snprintf(buf+len, PAGE_SIZE-len, "\n"); + len += snprintf(buf+len, PAGE_SIZE-len, "TXCAC:"); + + for(i=0;i<21;i++) + { + len += snprintf(buf+len, PAGE_SIZE-len, "0x%02X ", AW_Cali.TXCAC[i]); + } + + len += snprintf(buf+len, PAGE_SIZE-len, "\n"); + len += snprintf(buf+len, PAGE_SIZE-len, "RXCAC:"); + + for(i=0;i<12;i++) + { + len += snprintf(buf+len, PAGE_SIZE-len, "0x%02X ", AW_Cali.RXCAC[i]); + } + + len += snprintf(buf+len, PAGE_SIZE-len, "\n"); + len += snprintf(buf+len, PAGE_SIZE-len, "TXGAIN:"); + + for(i=0;i<21;i++) + { + len += snprintf(buf+len, PAGE_SIZE-len, "0x%02X ", AW_Cali.TXGAIN[i]); + } + + len += snprintf(buf+len, PAGE_SIZE-len, "\n"); + + for(i=0;iirqgpio); + AW5306_Sleep(); + suspend_flag = 1; + AW_Sleep(50); + + TP_Force_Calibration(); + + AW5306_TP_Reinit(); + wmt_enable_gpirq(data->irqgpio); + suspend_flag = 0; + + #else + suspend_flag = 1; + AW_Sleep(50); + + TP_Force_Calibration(); + + AW5306_TP_Reinit(); + tp_idlecnt = 0; + tp_SlowMode = 0; + suspend_flag = 0; + data->touch_timer.expires = jiffies + HZ/AWTPCfg.FAST_FRAME; + add_timer(&data->touch_timer); + #endif + } + + return count; +} + + +static ssize_t AW5306_get_adbBase(struct device* cd,struct device_attribute *attr, char* buf) +{ + unsigned char i,j; + ssize_t len = 0; + + len += snprintf(buf+len, PAGE_SIZE-len, "base: \n"); + for(i=0;i< AWTPCfg.TX_LOCAL;i++) + { + for(j=0;j>8); + len++; + *(buf+len) = (char)((AW_Base.Base[i][j]+AW_Cali.SOFTOFFSET[i][j]) & 0x00FF); + len++; + } + } + return len; + +} + +static ssize_t AW5306_get_adbDiff(struct device* cd,struct device_attribute *attr, char* buf) +{ + unsigned char i,j; + ssize_t len = 0; + + len += snprintf(buf+len, PAGE_SIZE-len, "Diff: \n"); + for(i=0;i< AWTPCfg.TX_LOCAL;i++) + { + for(j=0;j>8); + len++; + *(buf+len) = (char)(adbDiff[i][j] & 0x00FF); + len++; + } + } + return len; +} + +static ssize_t AW5306_get_FreqScan(struct device* cd,struct device_attribute *attr, char* buf) +{ + unsigned char i; + ssize_t len = 0; + + for(i=0;i< 32;i++) + { + //*(buf+len) = (char)((AWDeltaData[i] & 0xFF00)>>8); + //len++; + //*(buf+len) = (char)(AWDeltaData[i] & 0x00FF); + //len++; + len += snprintf(buf+len, PAGE_SIZE-len, "%4d, ",AWDeltaData[i]); + } + + len += snprintf(buf+len, PAGE_SIZE-len, "\n"); + return len; +} + +static ssize_t AW5306_Set_FreqScan(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) +{ + struct AW5306_ts_data *data = i2c_get_clientdata(l_client); + unsigned long Basefreq = simple_strtoul(buf, NULL, 10); + + if(Basefreq < 16) + { + #ifdef INTMODE + wmt_disable_gpirq(data ->irqgpio); + AW5306_Sleep(); + suspend_flag = 1; + AW_Sleep(50); + + FreqScan(Basefreq); + + AW5306_TP_Reinit(); + wmt_enable_gpirq(data ->irqgpio); + suspend_flag = 0; + #else + suspend_flag = 1; + AW_Sleep(50); + + FreqScan(Basefreq); + + AW5306_TP_Reinit(); + tp_idlecnt = 0; + tp_SlowMode = 0; + suspend_flag = 0; + data->touch_timer.expires = jiffies + HZ/AWTPCfg.FAST_FRAME; + add_timer(&data->touch_timer); + #endif + } + + return len; +} + +static ssize_t AW5306_get_reg(struct device* cd,struct device_attribute *attr, char* buf) +{ + struct AW5306_ts_data *data = i2c_get_clientdata(l_client); + u8 reg_val[128]; + ssize_t len = 0; + u8 i; + + if(suspend_flag != 1) + { +#ifdef INTMODE + wmt_disable_gpirq(data ->irqgpio); + AW5306_Sleep(); + suspend_flag = 1; + AW_Sleep(50); + + AW_I2C_ReadXByte(reg_val,0,127); + + AW5306_TP_Reinit(); + wmt_enable_gpirq(data->irqgpio); + suspend_flag = 0; +#else + suspend_flag = 1; + + AW_Sleep(50); + + AW_I2C_ReadXByte(reg_val,0,127); + + AW5306_TP_Reinit(); + tp_idlecnt = 0; + tp_SlowMode = 0; + suspend_flag = 0; + data->touch_timer.expires = jiffies + HZ/AWTPCfg.FAST_FRAME; + add_timer(&data->touch_timer); +#endif + } + else + { + AW_I2C_ReadXByte(reg_val,0,127); + } + for(i=0;i<0x7F;i++) + { + len += snprintf(buf+len, PAGE_SIZE-len, "reg%02X = 0x%02X, ", i,reg_val[i]); + } + + return len; + +} + +static ssize_t AW5306_write_reg(struct device* cd,struct device_attribute *attr, const char *buf, size_t count) +{ + struct AW5306_ts_data *data = i2c_get_clientdata(l_client); + int databuf[2]; + + if(2 == sscanf(buf, "%d %d", &databuf[0], &databuf[1])) + { + if(suspend_flag != 1) + { + #ifdef INTMODE + wmt_disable_gpirq(data ->irqgpio); + AW5306_Sleep(); + suspend_flag = 1; + AW_Sleep(50); + + AW_I2C_WriteByte((u8)databuf[0],(u8)databuf[1]); + + AW5306_TP_Reinit(); + //ctp_enable_irq(); + wmt_enable_gpirq(data->irqgpio); + suspend_flag = 0; + #else + suspend_flag = 1; + AW_Sleep(50); + + AW_I2C_WriteByte((u8)databuf[0],(u8)databuf[1]); + + AW5306_TP_Reinit(); + tp_idlecnt = 0; + tp_SlowMode = 0; + suspend_flag = 0; + data->touch_timer.expires = jiffies + HZ/AWTPCfg.FAST_FRAME; + add_timer(&data->touch_timer); + #endif + } + else + { + AW_I2C_WriteByte((u8)databuf[0],(u8)databuf[1]); + } + } + else + { + printk("invalid content: '%s', length = %d\n", buf, count); + } + return count; +} + +static ssize_t AW5306_GetUcf(struct device* cd,struct device_attribute *attr, char* buf) +{ + ssize_t len = 0; + + len += snprintf(buf+len, PAGE_SIZE-len,"*****AW5306 UCF DATA*****\n"); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,\n",AWTPCfg.TX_LOCAL,AWTPCfg.RX_LOCAL); + len += snprintf(buf+len, PAGE_SIZE-len,"(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d}\n", + AWTPCfg.TX_ORDER[0],AWTPCfg.TX_ORDER[1],AWTPCfg.TX_ORDER[2],AWTPCfg.TX_ORDER[3],AWTPCfg.TX_ORDER[4], + AWTPCfg.TX_ORDER[5],AWTPCfg.TX_ORDER[6],AWTPCfg.TX_ORDER[7],AWTPCfg.TX_ORDER[8],AWTPCfg.TX_ORDER[9], + AWTPCfg.TX_ORDER[10],AWTPCfg.TX_ORDER[11],AWTPCfg.TX_ORDER[12],AWTPCfg.TX_ORDER[13],AWTPCfg.TX_ORDER[14], + AWTPCfg.TX_ORDER[15],AWTPCfg.TX_ORDER[16],AWTPCfg.TX_ORDER[17],AWTPCfg.TX_ORDER[19],AWTPCfg.TX_ORDER[19], + AWTPCfg.TX_ORDER[20]); + len += snprintf(buf+len, PAGE_SIZE-len,"{%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d},\n", + AWTPCfg.RX_ORDER[0],AWTPCfg.RX_ORDER[1],AWTPCfg.RX_ORDER[2],AWTPCfg.RX_ORDER[3], + AWTPCfg.RX_ORDER[4],AWTPCfg.RX_ORDER[5],AWTPCfg.RX_ORDER[6],AWTPCfg.RX_ORDER[7], + AWTPCfg.RX_ORDER[8],AWTPCfg.RX_ORDER[9],AWTPCfg.RX_ORDER[10],AWTPCfg.RX_ORDER[11]); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,\n",AWTPCfg.RX_START,AWTPCfg.HAVE_KEY_LINE); + len += snprintf(buf+len, PAGE_SIZE-len,"{%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d},\n", + AWTPCfg.KeyLineValid[0],AWTPCfg.KeyLineValid[1],AWTPCfg.KeyLineValid[2],AWTPCfg.KeyLineValid[3], + AWTPCfg.KeyLineValid[4],AWTPCfg.KeyLineValid[5],AWTPCfg.KeyLineValid[6],AWTPCfg.KeyLineValid[7], + AWTPCfg.KeyLineValid[8],AWTPCfg.KeyLineValid[9],AWTPCfg.KeyLineValid[10],AWTPCfg.KeyLineValid[11]); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,\n",AWTPCfg.MAPPING_MAX_X,AWTPCfg.MAPPING_MAX_Y); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,\n",AWTPCfg.GainClbDeltaMax,AWTPCfg.GainClbDeltaMin); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,\n",AWTPCfg.KeyLineDeltaMax,AWTPCfg.KeyLineDeltaMin); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,\n",AWTPCfg.OffsetClbExpectedMax,AWTPCfg.OffsetClbExpectedMin); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,\n",AWTPCfg.RawDataDeviation,AWTPCfg.CacMultiCoef); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,\n",AWTPCfg.RawDataCheckMin,AWTPCfg.RawDataCheckMax); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,%d,\n",AWTPCfg.FLYING_TH,AWTPCfg.MOVING_TH,AWTPCfg.MOVING_ACCELER); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,\n",AWTPCfg.PEAK_TH,AWTPCfg.GROUP_TH); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,%d,\n",AWTPCfg.BIGAREA_TH,AWTPCfg.BIGAREA_CNT,AWTPCfg.BIGAREA_FRESHCNT); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,%d,\n",AWTPCfg.CACULATE_COEF,AWTPCfg.FIRST_CALI,AWTPCfg.RAWDATA_DUMP_SWITCH); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,0x%x,\n",AWTPCfg.MULTI_SCANFREQ,AWTPCfg.BASE_FREQ,AWTPCfg.FREQ_OFFSET); + len += snprintf(buf+len, PAGE_SIZE-len,"0x%x,0x%x,0x%x,\n",AWTPCfg.WAIT_TIME,AWTPCfg.CHAMP_CFG,AWTPCfg.POSLEVEL_TH); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,\n",AWTPCfg.ESD_PROTECT); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,%d,%d,%d,\n",AWTPCfg.MARGIN_COMPENSATE,AWTPCfg.MARGIN_COMP_DATA_UP, + AWTPCfg.MARGIN_COMP_DATA_DOWN,AWTPCfg.MARGIN_COMP_DATA_LEFT,AWTPCfg.MARGIN_COMP_DATA_RIGHT); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,%d,%d,\n",AWTPCfg.POINT_RELEASEHOLD,AWTPCfg.MARGIN_RELEASEHOLD, + AWTPCfg.POINT_PRESSHOLD,AWTPCfg.KEY_PRESSHOLD); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,%d,\n",AWTPCfg.PEAK_ROW_COMPENSATE,AWTPCfg.PEAK_COL_COMPENSATE, + AWTPCfg.PEAK_COMPENSATE_COEF); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,\n",AWTPCfg.LCD_NOISE_PROCESS,AWTPCfg.LCD_NOISETH); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,\n",AWTPCfg.FALSE_PEAK_PROCESS,AWTPCfg.FALSE_PEAK_TH); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,\n",AWTPCfg.STABLE_DELTA_X,AWTPCfg.STABLE_DELTA_Y); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,%d,\n",AWTPCfg.DEBUG_LEVEL,AWTPCfg.FAST_FRAME,AWTPCfg.SLOW_FRAME); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,\n",AWTPCfg.GAIN_CLB_SEPERATE,AWTPCfg.MARGIN_PREFILTER); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,\n",AWTPCfg.BIGAREA_HOLDPOINT,AWTPCfg.CHARGE_NOISE); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,\n",AWTPCfg.FREQ_JUMP,AWTPCfg.PEAK_VALID_CHECK); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,\n",AWTPCfg.WATER_REMOVE,AWTPCfg.INT_MODE); + + return len; + +} + + +static int AW5306_create_sysfs(struct i2c_client *client) +{ + int err; + struct device *dev = &(client->dev); + + //TS_DBG("%s", __func__); + + err = device_create_file(dev, &dev_attr_cali); + err = device_create_file(dev, &dev_attr_readreg); + err = device_create_file(dev, &dev_attr_base); + err = device_create_file(dev, &dev_attr_diff); + err = device_create_file(dev, &dev_attr_adbbase); + err = device_create_file(dev, &dev_attr_adbdiff); + err = device_create_file(dev, &dev_attr_freqscan); + err = device_create_file(dev, &dev_attr_getucf); + return err; +} + +static void AW5306_ts_release(void) +{ + struct AW5306_ts_data *data = pContext; +#ifdef CONFIG_AW5306_MULTITOUCH + #ifdef TOUCH_KEY_SUPPORT + if(1 == key_tp){ + if(key_val == 1){ + input_report_key(data->input_dev, KEY_MENU, 0); + input_sync(data->input_dev); + } + else if(key_val == 2){ + input_report_key(data->input_dev, KEY_BACK, 0); + input_sync(data->input_dev); + // printk("===KEY 2 upupupupupu===++=\n"); + } + else if(key_val == 3){ + input_report_key(data->input_dev, KEY_SEARCH, 0); + input_sync(data->input_dev); + // printk("===KEY 3 upupupupupu===++=\n"); + } + else if(key_val == 4){ + input_report_key(data->input_dev, KEY_HOMEPAGE, 0); + input_sync(data->input_dev); + // printk("===KEY 4 upupupupupu===++=\n"); + } + else if(key_val == 5){ + input_report_key(data->input_dev, KEY_VOLUMEDOWN, 0); + input_sync(data->input_dev); + // printk("===KEY 5 upupupupupu===++=\n"); + } + else if(key_val == 6){ + input_report_key(data->input_dev, KEY_VOLUMEUP, 0); + input_sync(data->input_dev); + // printk("===KEY 6 upupupupupu===++=\n"); + } +// input_report_key(data->input_dev, key_val, 0); + //printk("Release Key = %d\n",key_val); + //printk("Release Keyi+++++++++++++++++++++++++++++\n"); + } else{ + input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, 0); + } + #else + input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, 0); + #endif + +#else + input_report_abs(data->input_dev, ABS_PRESSURE, 0); + input_report_key(data->input_dev, BTN_TOUCH, 0); +#endif + + input_mt_sync(data->input_dev); + input_sync(data->input_dev); + return; + +} + + +static void Point_adjust(int *x, int *y) +{ + struct AW5306_ts_data *AW5306_ts = pContext; + int temp; + + if (AW5306_ts->swap) { + temp = *x; + *x = *y; + *y = temp; + } + if (AW5306_ts->xch) + *x = AW5306_ts->reslx - *x; + if (AW5306_ts->ych) + *y = AW5306_ts->resly - *y; + + if (AW5306_ts->lcd_exchg) { + int tmp; + tmp = *x; + *x = *y; + *y = AW5306_ts->reslx - tmp; + } +} + + +static int AW5306_read_data(void) +{ + struct AW5306_ts_data *data = pContext; + struct ts_event *event = &data->event; + int Pevent; + int i = 0; + + AW5306_TouchProcess(); + + //memset(event, 0, sizeof(struct ts_event)); + event->touch_point = AW5306_GetPointNum(); + + for(i=0;itouch_point;i++) + { + AW5306_GetPoint(&event->x[i],&event->y[i],&event->touch_ID[i],&Pevent,i); + //swap(event->x[i], event->y[i]); + Point_adjust(&event->x[i], &event->y[i]); +// printk("key%d = %d,%d,%d \n",i,event->x[i],event->y[i],event->touch_ID[i] ); + } + + if (event->touch_point == 0) + { + if(tp_idlecnt <= AWTPCfg.FAST_FRAME*5) + { + tp_idlecnt++; + } + if(tp_idlecnt > AWTPCfg.FAST_FRAME*5) + { + tp_SlowMode = 1; + } + + if (event->pre_point != 0) + { + AW5306_ts_release(); + event->pre_point = 0; + } + return 1; + } + else + { + tp_SlowMode = 0; + tp_idlecnt = 0; + event->pre_point = event->touch_point; + event->pressure = 200; + dbg("%s: 1:%d %d 2:%d %d \n", __func__, + event->x[0], event->y[0], event->x[1], event->y[1]); + + return 0; + } +} + +static void AW5306_report_multitouch(void) +{ + struct AW5306_ts_data *data = pContext; + struct ts_event *event = &data->event; + +#ifdef TOUCH_KEY_SUPPORT + if(1 == key_tp){ + return; + } +#endif + + switch(event->touch_point) { + case 5: + input_report_abs(data->input_dev, ABS_MT_TRACKING_ID, event->touch_ID[4]); + //input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure); + input_report_abs(data->input_dev, ABS_MT_POSITION_X, event->x[4]); + input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->y[4]); + //input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, 1); + input_mt_sync(data->input_dev); + // printk("=++==x5 = %d,y5 = %d ====\n",event->x[4],event->y[4]); + case 4: + input_report_abs(data->input_dev, ABS_MT_TRACKING_ID, event->touch_ID[3]); + //input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure); + input_report_abs(data->input_dev, ABS_MT_POSITION_X, event->x[3]); + input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->y[3]); + //input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, 1); + input_mt_sync(data->input_dev); + // printk("===x4 = %d,y4 = %d ====\n",event->x[3],event->y[3]); + case 3: + input_report_abs(data->input_dev, ABS_MT_TRACKING_ID, event->touch_ID[2]); + //input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure); + input_report_abs(data->input_dev, ABS_MT_POSITION_X, event->x[2]); + input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->y[2]); + //input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, 1); + input_mt_sync(data->input_dev); + // printk("===x3 = %d,y3 = %d ====\n",event->x[2],event->y[2]); + case 2: + input_report_abs(data->input_dev, ABS_MT_TRACKING_ID, event->touch_ID[1]); + //input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure); + input_report_abs(data->input_dev, ABS_MT_POSITION_X, event->x[1]); + input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->y[1]); + //input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, 1); + input_mt_sync(data->input_dev); + // printk("===x2 = %d,y2 = %d ====\n",event->x[1],event->y[1]); + case 1: + input_report_abs(data->input_dev, ABS_MT_TRACKING_ID, event->touch_ID[0]); + //input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure); + input_report_abs(data->input_dev, ABS_MT_POSITION_X, event->x[0]); + input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->y[0]); + //input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, 1); + input_mt_sync(data->input_dev); + // printk("===x1 = %d,y1 = %d ====\n",event->x[0],event->y[0]); + break; + default: +// print_point_info("==touch_point default =\n"); + break; + } + + input_sync(data->input_dev); + dbg("%s: 1:%d %d 2:%d %d \n", __func__, + event->x[0], event->y[0], event->x[1], event->y[1]); + return; +} + +#ifdef TOUCH_KEY_SUPPORT +static void AW5306_report_touchkey(void) +{ + struct AW5306_ts_data *data = pContext; + struct ts_event *event = &data->event; + //printk("x=%d===Y=%d\n",event->x[0],event->y[0]); + +#ifdef TOUCH_KEY_FOR_ANGDA + if((1==event->touch_point)&&(event->x1 > TOUCH_KEY_X_LIMIT)){ + key_tp = 1; + if(event->x1 < 40){ + key_val = 1; + input_report_key(data->input_dev, key_val, 1); + input_sync(data->input_dev); + // print_point_info("===KEY 1====\n"); + }else if(event->y1 < 90){ + key_val = 2; + input_report_key(data->input_dev, key_val, 1); + input_sync(data->input_dev); + // print_point_info("===KEY 2 ====\n"); + }else{ + key_val = 3; + input_report_key(data->input_dev, key_val, 1); + input_sync(data->input_dev); + // print_point_info("===KEY 3====\n"); + } + } else{ + key_tp = 0; + } +#endif +#ifdef TOUCH_KEY_FOR_EVB13 + if((1==event->touch_point)&&((event->y[0] > 510)&&(event->y[0]<530))) + { + if(key_tp != 1) + { + input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, 0); + input_sync(data->input_dev); + } + else + { + //printk("===KEY touch ++++++++++====++=\n"); + + if(event->x[0] < 90){ + key_val = 1; + input_report_key(data->input_dev, KEY_MENU, 1); + input_sync(data->input_dev); + // printk("===KEY 1===++=\n"); + }else if((event->x[0] < 230)&&(event->x[0]>185)){ + key_val = 2; + input_report_key(data->input_dev, KEY_BACK, 1); + input_sync(data->input_dev); + // printk("===KEY 2 ====\n"); + }else if((event->x[0] < 355)&&(event->x[0]>305)){ + key_val = 3; + input_report_key(data->input_dev, KEY_SEARCH, 1); + input_sync(data->input_dev); + // print_point_info("===KEY 3====\n"); + }else if ((event->x[0] < 497)&&(event->x[0]>445)) { + key_val = 4; + input_report_key(data->input_dev, KEY_HOMEPAGE, 1); + input_sync(data->input_dev); + // print_point_info("===KEY 4====\n"); + }else if ((event->x[0] < 615)&&(event->x[0]>570)) { + key_val = 5; + input_report_key(data->input_dev, KEY_VOLUMEDOWN, 1); + input_sync(data->input_dev); + // print_point_info("===KEY 5====\n"); + }else if ((event->x[0] < 750)&&(event->x[0]>705)) { + key_val = 6; + input_report_key(data->input_dev, KEY_VOLUMEUP, 1); + input_sync(data->input_dev); + // print_point_info("===KEY 6====\n"); + } + } + key_tp = 1; + } + else + { + key_tp = 0; + } +#endif + +#ifdef TOUCH_KEY_LIGHT_SUPPORT + AW5306_lighting(); +#endif + return; +} +#endif + + +static void AW5306_report_value(void) +{ + AW5306_report_multitouch(); +#ifdef TOUCH_KEY_SUPPORT + AW5306_report_touchkey(); +#endif + return; +} /*end AW5306_report_value*/ + + +#ifdef INTMODE +static void AW5306_ts_pen_irq_work(struct work_struct *work) +{ + int ret = -1; + + ret = AW5306_read_data(); + if (ret == 0) + AW5306_report_value(); + + wmt_enable_gpirq(pContext->irqgpio); + + return; +} +#else +static void AW5306_ts_pen_irq_work(struct work_struct *work) +{ + int ret = -1; + + if(suspend_flag != 1) + { + ret = AW5306_read_data(); + if (ret == 0) { + AW5306_report_value(); + } + } + else + { + AW5306_Sleep(); + } +} + +#endif + + + +static irqreturn_t aw5306_interrupt(int irq, void *dev) +{ + struct AW5306_ts_data *AW5306_ts= dev; + +//printk("I\n"); + if (wmt_is_tsint(AW5306_ts->irqgpio)) + { + wmt_clr_int(AW5306_ts->irqgpio); + if (wmt_is_tsirq_enable(AW5306_ts->irqgpio)) + { + wmt_disable_gpirq(AW5306_ts->irqgpio); + #ifdef CONFIG_HAS_EARLYSUSPEND + if(!AW5306_ts->earlysus) queue_work(AW5306_ts->ts_workqueue , &AW5306_ts->pen_event_work); + #else + queue_work(AW5306_ts->ts_workqueue , &AW5306_ts->pen_event_work); + #endif + + } + return IRQ_HANDLED; + } + return IRQ_NONE; +} +/* +static void aw5306_reset(struct AW5306_ts_data *aw5306) +{ + gpio_set_value(aw5306->rstgpio, 0); + mdelay(5); + gpio_set_value(aw5306->rstgpio, 1); + mdelay(5); + gpio_set_value(aw5306->rstgpio, 0); + mdelay(5); + + return; +} +*/ + +void AW5306_tpd_polling(unsigned long data) + { + struct AW5306_ts_data *AW5306_ts = i2c_get_clientdata(l_client); + +#ifdef INTMODE + if (!work_pending(&AW5306_ts->pen_event_work)) { + queue_work(AW5306_ts->ts_workqueue, &AW5306_ts->pen_event_work); + } +#else + + if (!work_pending(&AW5306_ts->pen_event_work)) { + queue_work(AW5306_ts->ts_workqueue, &AW5306_ts->pen_event_work); + } + if(suspend_flag != 1) + { + #ifdef AUTO_RUDUCEFRAME + if(tp_SlowMode) + { + AW5306_ts->touch_timer.expires = jiffies + HZ/AWTPCfg.SLOW_FRAME; + } + else + { + AW5306_ts->touch_timer.expires = jiffies + HZ/AWTPCfg.FAST_FRAME; + } + #else + AW5306_ts->touch_timer.expires = jiffies + HZ/AWTPCfg.FAST_FRAME; + #endif + add_timer(&AW5306_ts->touch_timer); + } +#endif + } + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void aw5306_early_suspend(struct early_suspend *handler) +{ +#ifdef INTMODE + if(suspend_flag != 1) + { + wmt_disable_gpirq(AW5306_ts->irqgpio); + AW5306_Sleep(); + suspend_flag = 1; + } +#else + if(suspend_flag != 1) + { + printk("AW5306 SLEEP!!!"); + suspend_flag = 1; + } +#endif + + return; +} + +static void aw5306_late_resume(struct early_suspend *handler) +{ + struct AW5306_ts_data *AW5306_ts= container_of(handler, struct AW5306_ts_data , early_suspend); +#ifdef INTMODE + if(suspend_flag != 0) + { + gpio_direction_output(AW5306_ts->rstgpio, 0); + AW5306_User_Cfg1(); + AW5306_TP_Reinit(); + wmt_enable_gpirq(AW5306_ts->irqgpio); + suspend_flag = 0; + } +#else + if(suspend_flag != 0) + { + gpio_direction_output(AW5306_ts->rstgpio, 0); + AW5306_User_Cfg1(); + AW5306_TP_Reinit(); + tp_idlecnt = 0; + tp_SlowMode = 0; + suspend_flag = 0; + printk("AW5306 WAKE UP!!!"); + AW5306_ts->touch_timer.expires = jiffies + HZ/AWTPCfg.FAST_FRAME; + add_timer(&AW5306_ts->touch_timer); + } +#endif + + return; +} +#endif //CONFIG_HAS_EARLYSUSPEND + +#ifdef CONFIG_PM +static int aw5306_suspend(struct platform_device *pdev, pm_message_t state) +{ +#ifdef INTMODE + if(suspend_flag != 1) + { + wmt_disable_gpirq(pContext->irqgpio); + AW5306_Sleep(); + suspend_flag = 1; + } +#else + if(suspend_flag != 1) + { + printk("AW5306 SLEEP!!!"); + suspend_flag = 1; + } +#endif + return 0; + +} + +static int aw5306_resume(struct platform_device *pdev) +{ + struct AW5306_ts_data *AW5306_ts= dev_get_drvdata(&pdev->dev); + +#ifdef INTMODE + if(suspend_flag != 0) + { + gpio_direction_output(AW5306_ts->rstgpio, 0); + AW5306_User_Cfg1(); + AW5306_TP_Reinit(); + suspend_flag = 0; + printk("AW5306 WAKE UP_intmode!!!"); + wmt_enable_gpirq(AW5306_ts->irqgpio); + } +#else + if(suspend_flag != 0) + { + gpio_direction_output(AW5306_ts->rstgpio, 0); + AW5306_User_Cfg1(); + AW5306_TP_Reinit(); + tp_idlecnt = 0; + tp_SlowMode = 0; + suspend_flag = 0; + printk("AW5306 WAKE UP!!!"); + AW5306_ts->touch_timer.expires = jiffies + HZ/AWTPCfg.FAST_FRAME; + add_timer(&AW5306_ts->touch_timer); + } +#endif + + return 0; +} + +#else +#define aw5306_suspend NULL +#define aw5306_resume NULL +#endif + +static int aw5306_probe(struct platform_device *pdev) +{ + int err = 0; + struct AW5306_ts_data *AW5306_ts = platform_get_drvdata( pdev); + u8 reg_value; + + //aw5306_reset(AW5306_ts); + + reg_value = AW_I2C_ReadByte(0x01); + if(reg_value != 0xA8) + { + //l_client->addr = 0x39; + dbg_err("AW5306_ts_probe: CHIP ID NOT CORRECT\n"); + return -ENODEV; + } + + i2c_set_clientdata(l_client, AW5306_ts); + + INIT_WORK(&AW5306_ts->pen_event_work, AW5306_ts_pen_irq_work); + AW5306_ts->ts_workqueue = create_singlethread_workqueue(AW5306_ts->name); + if (!AW5306_ts->ts_workqueue ) { + err = -ESRCH; + goto exit_create_singlethread; + } + + AW5306_ts->input_dev = input_allocate_device(); + if (!AW5306_ts->input_dev) { + err = -ENOMEM; + dbg_err("failed to allocate input device\n"); + goto exit_input_dev_alloc_failed; + } + + AW5306_ts->input_dev->name = AW5306_ts->name; + AW5306_ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + set_bit(INPUT_PROP_DIRECT, AW5306_ts->input_dev->propbit); + + if (AW5306_ts->lcd_exchg) { + input_set_abs_params(AW5306_ts->input_dev, + ABS_MT_POSITION_X, 0, AW5306_ts->resly, 0, 0); + input_set_abs_params(AW5306_ts->input_dev, + ABS_MT_POSITION_Y, 0, AW5306_ts->reslx, 0, 0); + } else { + input_set_abs_params(AW5306_ts->input_dev, + ABS_MT_POSITION_X, 0, AW5306_ts->reslx, 0, 0); + input_set_abs_params(AW5306_ts->input_dev, + ABS_MT_POSITION_Y, 0, AW5306_ts->resly, 0, 0); + } + input_set_abs_params(AW5306_ts->input_dev, + ABS_MT_TRACKING_ID, 0, 4, 0, 0); + + err = input_register_device(AW5306_ts->input_dev); + if (err) { + dbg_err("aw5306_ts_probe: failed to register input device.\n"); + goto exit_input_register_device_failed; + } + +#ifdef CONFIG_HAS_EARLYSUSPEND + AW5306_ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + AW5306_ts->early_suspend.suspend = aw5306_early_suspend; + AW5306_ts->early_suspend.resume = aw5306_late_resume; + register_early_suspend(&AW5306_ts->early_suspend); +#endif + + AW5306_create_sysfs(l_client); + memcpy(AW_CALI_FILENAME,"/data/tpcali",12); + //memcpy(AW_UCF_FILENAME,"/data/AWTPucf",13); + printk("ucf file: %s\n", AW_UCF_FILENAME); + + AW5306_TP_Init(); + + AW5306_ts->touch_timer.function = AW5306_tpd_polling; + AW5306_ts->touch_timer.data = 0; + init_timer(&AW5306_ts->touch_timer); + AW5306_ts->touch_timer.expires = jiffies + HZ*10; + add_timer(&AW5306_ts->touch_timer); + +#ifdef INTMODE + + if(request_irq(AW5306_ts->irq, aw5306_interrupt, IRQF_SHARED, AW5306_ts->name, AW5306_ts) < 0){ + dbg_err("Could not allocate irq for ts_aw5306 !\n"); + err = -1; + goto exit_register_irq; + } + + wmt_set_gpirq(AW5306_ts->irqgpio, IRQ_TYPE_EDGE_FALLING); + wmt_enable_gpirq(AW5306_ts->irqgpio); + +#endif + + + + + return 0; + +exit_register_irq: +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&AW5306_ts->early_suspend); +#endif +exit_input_register_device_failed: + input_free_device(AW5306_ts->input_dev); +exit_input_dev_alloc_failed: +//exit_create_group: + cancel_work_sync(&AW5306_ts->pen_event_work); + destroy_workqueue(AW5306_ts->ts_workqueue ); +exit_create_singlethread: + return err; +} + +static int aw5306_remove(struct platform_device *pdev) +{ + struct AW5306_ts_data *AW5306_ts= platform_get_drvdata( pdev); + + del_timer(&AW5306_ts->touch_timer); + + +#ifdef INTMODE + wmt_disable_gpirq(AW5306_ts->irqgpio); + free_irq(AW5306_ts->irq, AW5306_ts); +#endif + + +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&AW5306_ts->early_suspend); +#endif + input_unregister_device(AW5306_ts->input_dev); + input_free_device(AW5306_ts->input_dev); + + cancel_work_sync(&AW5306_ts->pen_event_work); + flush_workqueue(AW5306_ts->ts_workqueue); + destroy_workqueue(AW5306_ts->ts_workqueue); + + dbg("remove...\n"); + return 0; +} + +static void aw5306_release(struct device *device) +{ + return; +} + +static struct platform_device aw5306_device = { + .name = DEV_AW5306, + .id = 0, + .dev = {.release = aw5306_release}, +}; + +static struct platform_driver aw5306_driver = { + .driver = { + .name = DEV_AW5306, + .owner = THIS_MODULE, + }, + .probe = aw5306_probe, + .remove = aw5306_remove, + .suspend = aw5306_suspend, + .resume = aw5306_resume, +}; + +static int check_touch_env(struct AW5306_ts_data *AW5306_ts) +{ + int ret = 0; + int len = 96; + int Enable; + char retval[96] = {0}; + char ucfname[20] = {0}; + char *p=NULL, *s=NULL; + + // Get u-boot parameter + ret = wmt_getsyspara("wmt.io.touch", retval, &len); + if(ret){ + //printk("MST FT5x0x:Read wmt.io.touch Failed.\n"); + return -EIO; + } + sscanf(retval,"%d:",&Enable); + //check touch enable + if(Enable == 0){ + //printk("FT5x0x Touch Screen Is Disabled.\n"); + return -ENODEV; + } + + p = strchr(retval,':'); + p++; + if(strncmp(p,"aw5306",6)) return -ENODEV; + AW5306_ts->name = DEV_AW5306; + s = strchr(p, ':'); + p = p + 7; + if (s <= p) + return -ENODEV; + strncpy(ucfname, p, s-p); + sprintf(AW_UCF_FILENAME, "/lib/firmware/%s", ucfname); + + s++; + sscanf(s,"%d:%d:%d:%d:%d:%d:%d:%d", &AW5306_ts->irqgpio, &AW5306_ts->reslx, &AW5306_ts->resly, &AW5306_ts->rstgpio, &AW5306_ts->swap, &AW5306_ts->xch, &AW5306_ts->ych, &AW5306_ts->nt); + + AW5306_ts->irq = IRQ_GPIO; + + printk("%s irqgpio=%d, reslx=%d, resly=%d, rstgpio=%d, swap=%d, xch=%d, ych=%d, nt=%d\n", AW5306_ts->name, AW5306_ts->irqgpio, AW5306_ts->reslx, AW5306_ts->resly, AW5306_ts->rstgpio, AW5306_ts->swap, AW5306_ts->xch, AW5306_ts->ych, AW5306_ts->nt); + + memset(retval,0,sizeof(retval)); + ret = wmt_getsyspara("wmt.display.fb0", retval, &len); + if (!ret) { + int tmp[6]; + p = retval; + sscanf(p, "%d:[%d:%d:%d:%d:%d", &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5]); + if (tmp[4] > tmp[5]) + AW5306_ts->lcd_exchg = 1; + } + + return 0; +} + +struct i2c_board_info ts_i2c_board_info = { + .type = TS_I2C_NAME, + .flags = 0x00, + .addr = AW5306_I2C_ADDR, + .platform_data = NULL, + .archdata = NULL, + .irq = -1, +}; + +static int ts_i2c_register_device (void) +{ + struct i2c_board_info *ts_i2c_bi; + struct i2c_adapter *adapter = NULL; + //struct i2c_client *client = NULL; + + //ts_i2c_board_info.addr = AW5306_I2C_ADDR; + ts_i2c_bi = &ts_i2c_board_info; + adapter = i2c_get_adapter(AW5306_I2C_BUS);/*in bus 1*/ + + if (NULL == adapter) { + printk("can not get i2c adapter, client address error\n"); + return -1; + } + l_client = i2c_new_device(adapter, ts_i2c_bi); + if (l_client == NULL) { + printk("allocate i2c client failed\n"); + return -1; + } + i2c_put_adapter(adapter); + return 0; +} + +static void ts_i2c_unregister_device(void) +{ + if (l_client != NULL) + { + i2c_unregister_device(l_client); + l_client = NULL; + } +} + +static int __init aw5306_init(void) +{ + int ret = -ENOMEM; + struct AW5306_ts_data *AW5306_ts=NULL; + + if (ts_i2c_register_device()<0) + { + dbg("Error to run ts_i2c_register_device()!\n"); + return -1; + } + + AW5306_ts = kzalloc(sizeof(struct AW5306_ts_data), GFP_KERNEL); + if(!AW5306_ts){ + dbg_err("mem alloc failed.\n"); + return -ENOMEM; + } + + pContext = AW5306_ts; + ret = check_touch_env(AW5306_ts); + if(ret < 0) + goto exit_free_mem; + + ret = gpio_request(AW5306_ts->irqgpio, "ts_irq"); + if (ret < 0) { + printk("gpio(%d) touchscreen irq request fail\n", AW5306_ts->irqgpio); + goto exit_free_mem; + } + //wmt_gpio_setpull(AW5306_ts->irqgpio, WMT_GPIO_PULL_UP); + gpio_direction_input(AW5306_ts->irqgpio); + + ret = gpio_request(AW5306_ts->rstgpio, "ts_rst"); + if (ret < 0) { + printk("gpio(%d) touchscreen reset request fail\n", AW5306_ts->rstgpio); + goto exit_free_irqgpio; + } + gpio_direction_output(AW5306_ts->rstgpio, 0); + + + ret = platform_device_register(&aw5306_device); + if(ret){ + dbg_err("register platform drivver failed!\n"); + goto exit_free_gpio; + } + platform_set_drvdata(&aw5306_device, AW5306_ts); + + ret = platform_driver_register(&aw5306_driver); + if(ret){ + dbg_err("register platform device failed!\n"); + goto exit_unregister_pdev; + } + +/* + i2c_dev_class = class_create(THIS_MODULE,"aw_i2c_dev"); + if (IS_ERR(i2c_dev_class)) { + ret = PTR_ERR(i2c_dev_class); + class_destroy(i2c_dev_class); + } +*/ + + + return ret; + +exit_unregister_pdev: + platform_device_unregister(&aw5306_device); +exit_free_gpio: + gpio_free(AW5306_ts->rstgpio); +exit_free_irqgpio: + gpio_free(AW5306_ts->irqgpio); +exit_free_mem: + kfree(AW5306_ts); + pContext = NULL; + return ret; +} + +static void aw5306_exit(void) +{ + if(!pContext) return; + + platform_driver_unregister(&aw5306_driver); + platform_device_unregister(&aw5306_device); + gpio_free(pContext->rstgpio); + gpio_free(pContext->irqgpio); + kfree(pContext); + ts_i2c_unregister_device(); + return; +} + +late_initcall(aw5306_init); +module_exit(aw5306_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("FocalTech.Touch"); diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_userpara.c b/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_userpara.c new file mode 100755 index 00000000..99f65f87 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_userpara.c @@ -0,0 +1,196 @@ +#include "AW5306_Reg.h" +#include "AW5306_Drv.h" +#include +#include +#include "AW5306_userpara.h" + +#define POS_PRECISION 64 + +extern AW5306_UCF AWTPCfg; +extern STRUCTCALI AW_Cali; +extern char AW5306_WorkMode; +extern STRUCTNOISE AW_Noise; + +extern void AW5306_CLB_WriteCfg(void); +extern int AW_I2C_WriteByte(unsigned char addr, unsigned char data); +extern unsigned char AW_I2C_ReadByte(unsigned char addr); +extern unsigned char AW_I2C_ReadXByte( unsigned char *buf, unsigned char addr, unsigned short len); +extern unsigned char AW5306_RAWDATACHK(void); + +const STRUCTCALI Default_Cali1 = +{ + "AWINIC TP CALI", + //{0x33,0x23,0x22,0x22,0x22,0x22,0x22,0x02,0x22,0x22}, //TXOFFSET + {0x32,0x32,0x23,0x32,0x33,0x33,0x33,0x03,0x22,0x22}, //TXOFFSET + //{0x9A,0xA9,0xAA,0xA9,0x9B,0x00}, //RXOFFSET + {0x35,0x44,0x55,0x54,0x34,0x00}, //RXOFFSET + //{0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c},//TXCAC + {0x2C,0x2B,0x2B,0x2A,0x2A,0x2C,0x2C,0x2C,0x2C,0x2C,0x2D,0x2D,0x2D,0x2D,0x31,0x2C,0x2C,0x2C,0x2C,0x2C},//TXCAC + //{0x3d,0x3c,0x3c,0x3c,0x3e,0x3a,0x3a,0x3e,0x3c,0x3b,0x3c,0x3c},//RXCAC + {0x84,0x84,0x82,0x82,0x80,0x86,0x86,0x80,0x8C,0x82,0x84,0x84},//RXCAC + //{0x0e,0x0e,0x0e,0x0e,0x0e,0x0e,0x0e,0x0e,0x0e,0x0e,0x0e,0x0e,0x0e,0x2e,0x2e,0x0e,0x0e,0x0e,0x0e,0x0e},//TXGAIN + {0x88,0x88,0x88,0x88,0x88,0x68,0x68,0x68,0x68,0x68,0x48,0x48,0x48,0x48,0x28,0x08,0x08,0x08,0x08,0x08},//TXGAIN +}; + +const AW5306_UCF Default_UCF = +{ + 15, //TX_NUM + 10, //RX_NUM + {17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,0,0}, //TX_ORDER + {9,8,7,6,5,4,3,2,1,0,0,0}, //RX_ORDER + 0, //RX_START + 0, //HAVE_KEY_LINE + {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, //KeyLineValid + + 600, //MAPPING_MAX_X + 1024, //MAPPING_MAX_Y + + 350, //GainClbDeltaMin + 450, //GainClbDeltaMax + 550, //KeyLineDeltaMin + 650, //KeyLineDeltaMax + 8300, //OffsetClbExpectedMin + 8500, //OffsetClbExpectedMax + 300, //RawDataDeviation + 8, //CacMultiCoef + + 7000, //RawDataCheckMin + 10000, //RawDataCheckMax + + 200, //FLYING_TH + 100, //MOVING_TH + 50, //MOVING_ACCELER + + 70, //PEAK_TH + 80, //GROUP_TH + 90, //BIGAREA_TH + 25, //BIGAREA_CNT + 20, //BIGAREA_FRESHCNT + + 1, //CACULATE_COEF + + 1, //FIRST_CALI + 0, //RAWDATA_DUMP_SWITCH + + 1, //MULTI_SCANFREQ + 5, //BASE_FREQ + 0x83, //FREQ_OFFSET + 0x00, //WAIT_TIME + 0x2b, //CHAMP_CFG + 0x10, //POSLEVEL_TH + + 1, //ESD_PROTECT + + 0, //MARGIN_COMPENSATE + 0, //MARGIN_COMP_DATA_UP + 0, //MARGIN_COMP_DATA_DOWN + 0, //MARGIN_COMP_DATA_LEFT + 0, //MARGIN_COMP_DATA_RIGHT + + 1, //POINT_RELEASEHOLD + 0, //MARGIN_RELEASEHOLD + 0, //POINT_PRESSHOLD + 1, //KEY_PRESSHOLD + + 0, //PEAK_ROW_COMPENSATE + 1, //PEAK_COL_COMPENSATE + 3, //PEAK_COMPENSATE_COEF + + 0, //LCD_NOISE_PROCESS + 50, //LCD_NOISETH + + 0, //FALSE_PEAK_PROCESS + 100, //FALSE_PEAK_TH + + 6, //STABLE_DELTA_X + 6, //STABLE_DELTA_Y + + 0, //DEBUG_LEVEL + + 50, //FAST_FRAME + 20, //SLOW_FRAME + + 0, //GAIN_CLB_SEPERATE + 5, //MARGIN_PREFILTER + 0, //BIGAREA_HOLDPOINT + 50, //CHARGE_NOISE + 0, //FREQ_JUMP + 0, //PEAK_VALID_CHECK + 1, //WATER_REMOVE + +#ifdef INTMODE + 1 //INT_MODE +#else + 0 //POLL_MODE +#endif +}; + +void AW5306_User_Cfg1(void) +{ + unsigned char i; + + + for(i=0;i +#include +#include +#include +#include "irq_gpio.h" + +int wmt_enable_gpirq(int num) +{ + if(num > 15) + return -1; + + if(num < 4) + REG32_VAL(__GPIO_BASE+0x0300) |= 1<<(num*8+7); //enable interrupt + else if(num >= 4 && num < 8) + REG32_VAL(__GPIO_BASE+0x0304) |= 1<<((num-4)*8+7); //enable interrupt + else if(num >= 8 && num < 12) + REG32_VAL(__GPIO_BASE+0x0308) |= 1<<((num-8)*8+7); //enable interrupt + else + REG32_VAL(__GPIO_BASE+0x030C) |= 1<<((num-12)*8+7); //enable interrupt + + return 0; +} + +int wmt_disable_gpirq(int num) +{ + if(num > 15) + return -1; + + if(num<4) + REG32_VAL(__GPIO_BASE+0x0300) &= ~(1<<(num*8+7)); //enable interrupt + else if(num >= 4 && num < 8) + REG32_VAL(__GPIO_BASE+0x0304) &= ~(1<<((num-4)*8+7)); //enable interrupt + else if(num >= 8 && num < 12) + REG32_VAL(__GPIO_BASE+0x0308) &= ~(1<<((num-8)*8+7)); //enable interrupt + else + REG32_VAL(__GPIO_BASE+0x030C) &= ~(1<<((num-12)*8+7)); //enable interrupt + + return 0; +} + +int wmt_is_tsirq_enable(int num) +{ + int val = 0; + + if(num > 15) + return 0; + + if(num<4) + val = REG32_VAL(__GPIO_BASE+0x0300) & (1<<(num*8+7)); + else if(num >= 4 && num < 8) + val = REG32_VAL(__GPIO_BASE+0x0304) & (1<<((num-4)*8+7)); + else if(num >= 8 && num < 12) + val = REG32_VAL(__GPIO_BASE+0x0308) & (1<<((num-8)*8+7)); + else + val = REG32_VAL(__GPIO_BASE+0x030C) & (1<<((num-12)*8+7)); + + return val?1:0; + +} + +int wmt_is_tsint(int num) +{ + if (num > 15) + { + return 0; + } + return (REG32_VAL(__GPIO_BASE+0x0360) & (1< 15) + { + return; + } + REG32_VAL(__GPIO_BASE+0x0360) = 1<15) + return -1; + //if (num > 9) + //GPIO_PIN_SHARING_SEL_4BYTE_VAL &= ~BIT4; // gpio10,11 as gpio + + REG32_VAL(__GPIO_BASE+0x0040) &= ~(1<= 4 && num < 8){//[4,7] + shift = num-4; + offset = 0x0304; + }else if(num >= 8 && num < 12){//[8,11] + shift = num-8; + offset = 0x0308; + }else{// [12,15] + shift = num-12; + offset = 0x030C; + } + + reg = REG32_VAL(__GPIO_BASE + offset); + + switch(type){ + case IRQ_TYPE_LEVEL_LOW: + reg &= ~(1<<(shift*8+2)); + reg &= ~(1<<(shift*8+1)); + reg &= ~(1<<(shift*8)); + break; + case IRQ_TYPE_LEVEL_HIGH: + reg &= ~(1<<(shift*8+2)); + reg &= ~(1<<(shift*8+1)); + reg |= (1<<(shift*8)); + break; + case IRQ_TYPE_EDGE_FALLING: + reg &= ~(1<<(shift*8+2)); + reg |= (1<<(shift*8+1)); + reg &= ~(1<<(shift*8)); + break; + case IRQ_TYPE_EDGE_RISING: + reg &= ~(1<<(shift*8+2)); + reg |= (1<<(shift*8+1)); + reg |= (1<<(shift*8)); + break; + default://both edge + reg |= (1<<(shift*8+2)); + reg &= ~(1<<(shift*8+1)); + reg &= ~(1<<(shift*8)); + break; + + } + //reg |= 1<<(shift*8+7);//enable interrupt + reg &= ~(1<<(shift*8+7)); //disable int + + REG32_VAL(__GPIO_BASE + offset) = reg; + REG32_VAL(__GPIO_BASE+0x0360) = 1< +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include +#include +#include +#include +#include +#include + +#include "wmt_ts.h" +#define TP_POINTS_CNT 5 +#define U8 unsigned char +//fw update. +//#include "cyp140_fw.h" + +//****************************add for cyp140 2013-1-6 +//extern struct tpd_device *tpd; +static struct i2c_client *i2c_client = NULL; +static struct task_struct *thread = NULL; + +static DECLARE_WAIT_QUEUE_HEAD(waiter); + +#define TPD_DEVICE "cyp140" +static int tpd_load_status = 0;//add !!!2013-1-6 +//static struct early_suspend early_suspend; + +#ifdef CONFIG_HAS_EARLYSUSPEND +static struct early_suspend early_suspend; +static void tpd_early_suspend(struct early_suspend *handler); +static void tpd_late_resume(struct early_suspend *handler); +#endif + +static int tilt = 1, rev_x = -1, rev_y = 1; +static int max_x = 1024, max_y = 600; +//static int max_x = 800, max_y = 480; + +//extern void mt65xx_eint_unmask(unsigned int line); +//extern void mt65xx_eint_mask(unsigned int line); +//extern void mt65xx_eint_set_hw_debounce(kal_uint8 eintno, kal_uint32 ms); +//extern kal_uint32 mt65xx_eint_set_sens(kal_uint8 eintno, kal_bool sens); +//extern mt65xx_eint_set_polarity(unsigned int eint_num, unsigned int pol); +//extern void mt65xx_eint_registration(kal_uint8 eintno, kal_bool Dbounce_En, + // kal_bool ACT_Polarity, void (EINT_FUNC_PTR)(void), + // kal_bool auto_umask); + + +static irqreturn_t tpd_eint_interrupt_handler(int irq, void *dev_id); +//static int tpd_get_bl_info(int show); +static int __devinit tpd_probe(struct i2c_client *client); +//static int tpd_detect(struct i2c_client *client, int kind, struct i2c_board_info *info); +//static int __devexit tpd_remove(struct i2c_client *client); +static int touch_event_handler(void *unused); +//static int tpd_initialize(struct i2c_client * client); + + +volatile static int tpd_flag = 0;//0; debug 2013-5-6 + +#ifdef TPD_HAVE_BUTTON +static int tpd_keys_local[TPD_KEY_COUNT] = TPD_KEYS; +static int tpd_keys_dim_local[TPD_KEY_COUNT][4] = TPD_KEYS_DIM; +#endif + +#define TPD_OK 0 +//#define TPD_EREA_Y 799 +//#define TPD_EREA_X 479 +#define TPD_EREA_Y 479 +#define TPD_EREA_X 319 + +#define TPD_DISTANCE_LIMIT 100 + +#define TPD_REG_BASE 0x00 +#define TPD_SOFT_RESET_MODE 0x01 +#define TPD_OP_MODE 0x00 +#define TPD_LOW_PWR_MODE 0x04 +#define TPD_SYSINFO_MODE 0x10 +#define GET_HSTMODE(reg) ((reg & 0x70) >> 4) // in op mode or not +#define GET_BOOTLOADERMODE(reg) ((reg & 0x10) >> 4) // in bl mode +//#define GPIO_CTP_EN_PIN_M_GPIO 0 +//#define GPIO_CTP_EN_PIN 0xff + +static u8 bl_cmd[] = { + 0x00, 0x00, 0xFF, 0xA5, + 0x00, 0x01, 0x02, + 0x03, 0x04, 0x05, + 0x06, 0x07}; +//exit bl mode +struct tpd_operation_data_t{ + U8 hst_mode; + U8 tt_mode; + U8 tt_stat; + + U8 x1_M,x1_L; + U8 y1_M,y1_L; + U8 x5_M; + U8 touch12_id; + + U8 x2_M,x2_L; + U8 y2_M,y2_L; + U8 x5_L; + U8 gest_cnt; + U8 gest_id; + //U8 gest_set; + + + U8 x3_M,x3_L; + U8 y3_M,y3_L; + U8 y5_M; + U8 touch34_id; + + U8 x4_M,x4_L; + U8 y4_M,y4_L; + U8 y5_L; + + //U8 x5_M,x5_L; + U8 Undefinei1B; + U8 Undefined1C; + U8 Undefined1D; + U8 GEST_SET; + U8 touch5_id; +}; + +struct tpd_bootloader_data_t{ + U8 bl_file; + U8 bl_status; + U8 bl_error; + U8 blver_hi,blver_lo; + U8 bld_blver_hi,bld_blver_lo; + + U8 ttspver_hi,ttspver_lo; + U8 appid_hi,appid_lo; + U8 appver_hi,appver_lo; + + U8 cid_0; + U8 cid_1; + U8 cid_2; + +}; + +struct tpd_sysinfo_data_t{ + U8 hst_mode; + U8 mfg_cmd; + U8 mfg_stat; + U8 cid[3]; + u8 tt_undef1; + + u8 uid[8]; + U8 bl_verh; + U8 bl_verl; + + u8 tts_verh; + u8 tts_verl; + + U8 app_idh; + U8 app_idl; + U8 app_verh; + U8 app_verl; + + u8 tt_undef2[6]; + U8 act_intrvl; + U8 tch_tmout; + U8 lp_intrvl; + +}; + +struct touch_info { + int x[5]; + int y[5]; + int p[5]; + int id[5]; + int count; +}; + +struct id_info{ + int pid1; + int pid2; + int reportid1; + int reportid2; + int id1; + int id2; + +}; +static struct tpd_operation_data_t g_operation_data; +//static struct tpd_bootloader_data_t g_bootloader_data; +//static struct tpd_sysinfo_data_t g_sysinfo_data; + +//******************************************************** + +/* -------------- global variable definition -----------*/ +#define _MACH_MSM_TOUCH_H_ + +#define ZET_TS_ID_NAME "cyp140-ts" + +#define MJ5_TS_NAME "cyp140_touchscreen" + +//#define TS_INT_GPIO S3C64XX_GPN(9) /*s3c6410*/ +//#define TS1_INT_GPIO AT91_PIN_PB17 /*AT91SAM9G45 external*/ +//#define TS1_INT_GPIO AT91_PIN_PA27 /*AT91SAM9G45 internal*/ +//#define TS_RST_GPIO S3C64XX_GPN(10) + +#define TS_RST_GPIO +#define TPINFO 1 +#define X_MAX 800 //1024 +#define Y_MAX 480 //576 +#define FINGER_NUMBER 5 +#define KEY_NUMBER 3 //0 +#define P_MAX 1 +#define D_POLLING_TIME 25000 +#define U_POLLING_TIME 25000 +#define S_POLLING_TIME 100 +#define REPORT_POLLING_TIME 5 + +#define MAX_KEY_NUMBER 8 +#define MAX_FINGER_NUMBER 16 +#define TRUE 1 +#define FALSE 0 + +//#define debug_mode 1 +//#define DPRINTK(fmt,args...) do { if (debug_mode) printk(KERN_EMERG "[%s][%d] "fmt"\n", __FUNCTION__, __LINE__, ##args);} while(0) + +//#define TRANSLATE_ENABLE 1 +#define TOPRIGHT 0 +#define TOPLEFT 1 +#define BOTTOMRIGHT 2 +#define BOTTOMLEFT 3 +#define ORIGIN BOTTOMRIGHT + +#define TIME_CHECK_CHARGE 3000 + +struct msm_ts_platform_data { + unsigned int x_max; + unsigned int y_max; + unsigned int pressure_max; +}; + +struct tpd_device{ + struct i2c_client * client;//i2c_ts; + struct work_struct work1; + struct input_dev *input; + struct timer_list polling_timer; + struct delayed_work work; // for polling + struct workqueue_struct *queue; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif + unsigned int gpio; /* GPIO used for interrupt of TS1*/ + unsigned int irq; + unsigned int x_max; + unsigned int y_max; + unsigned int pressure_max; +}; +// +struct tpd_device *tpd; + + +//static int l_suspend = 0; // 1:suspend, 0:normal state + +//static int resetCount = 0; //albert++ 20120807 + + +//static u16 polling_time = S_POLLING_TIME; + +//static int l_powermode = -1; +//static struct mutex i2c_mutex; + + +//static int __devinit cyp140_ts_probe(struct i2c_client *client, const struct i2c_device_id *id); +//static int __devexit cyp140_ts_remove(struct i2c_client *dev); + + + + + +//static int filterCount = 0; +//static u32 filterX[MAX_FINGER_NUMBER][2], filterY[MAX_FINGER_NUMBER][2]; + +//static u8 key_menu_pressed = 0x1; +//static u8 key_back_pressed = 0x1; +//static u8 key_search_pressed = 0x1; + +//static u16 ResolutionX=X_MAX; +//static u16 ResolutionY=Y_MAX; +//static u16 FingerNum=0; +//static u16 KeyNum=0; +//static int bufLength=0; +//static u8 xyExchange=0; +//static u16 inChargerMode = 0; +//static struct i2c_client *this_client; +struct workqueue_struct *ts_wq = NULL; +#if 0 +static int l_tskey[4][2] = { + {KEY_BACK,0}, + {KEY_MENU,0}, + {KEY_HOME,0}, + {KEY_SEARCH,0}, +}; +#endif +u8 pc[8]; +// {IC Model, FW Version, FW version,Codebase Type=0x08, Customer ID, Project ID, Config Board No, Config Serial No} + +//Touch Screen +/*static const struct i2c_device_id cyp140_ts_idtable[] = { + { ZET_TS_ID_NAME, 0 }, + { } +}; + +static struct i2c_driver cyp140_ts_driver = { + .driver = { + .owner = THIS_MODULE, + .name = ZET_TS_ID_NAME, + }, + .probe = cyp140_ts_probe, + .remove = __devexit_p(cyp140_ts_remove), + .id_table = cyp140_ts_idtable, +}; +*/ + + +/*********************************************************************** + [function]: + callback: Timer Function if there is no interrupt fuction; + [parameters]: + arg[in]: arguments; + [return]: + NULL; +************************************************************************/ + + +//extern int wmt_i2c_xfer_continue_if_4(struct i2c_msg *msg, unsigned int num,int bus_id); +/*********************************************************************** + [function]: + callback: read data by i2c interface; + [parameters]: + client[in]: struct i2c_client — represent an I2C slave device; + data [out]: data buffer to read; + length[in]: data length to read; + [return]: + Returns negative errno, else the number of messages executed; +************************************************************************/ +int cyp140_i2c_read_tsdata(struct i2c_client *client, u8 *data, u8 length) +{ + struct i2c_msg msg; + msg.addr = client->addr; + msg.flags = I2C_M_RD; + msg.len = length; + msg.buf = data; + return i2c_transfer(client->adapter,&msg, 1); + + /*int rc = 0; + + memset(data, 0, length); + rc = i2c_master_recv(client, data, length); + if (rc <= 0) + { + errlog("error!\n"); + return -EINVAL; + } else if (rc != length) + { + dbg("want:%d,real:%d\n", length, rc); + } + return rc;*/ +} + +/*********************************************************************** + [function]: + callback: write data by i2c interface; + [parameters]: + client[in]: struct i2c_client — represent an I2C slave device; + data [out]: data buffer to write; + length[in]: data length to write; + [return]: + Returns negative errno, else the number of messages executed; +************************************************************************/ +int cyp140_i2c_write_tsdata(struct i2c_client *client, u8 *data, u8 length) +{ + struct i2c_msg msg; + msg.addr = client->addr; + msg.flags = 0; + msg.len = length; + msg.buf = data; + return i2c_transfer(client->adapter,&msg, 1); + + /*int ret = i2c_master_recv(client, data, length); + if (ret <= 0) + { + errlog("error!\n"); + } + return ret; + */ +} + +/*********************************************************************** + [function]: + callback: coordinate traslating; + [parameters]: + px[out]: value of X axis; + py[out]: value of Y axis; + p [in]: pressed of released status of fingers; + [return]: + NULL; +************************************************************************/ +void touch_coordinate_traslating(u32 *px, u32 *py, u8 p) +{ + int i; + u8 pressure; + + #if ORIGIN == TOPRIGHT + for(i=0;i> (MAX_FINGER_NUMBER-i-1)) & 0x1; + if(pressure) + { + px[i] = X_MAX - px[i]; + } + } + #elif ORIGIN == BOTTOMRIGHT + for(i=0;i> (MAX_FINGER_NUMBER-i-1)) & 0x1; + if(pressure) + { + px[i] = X_MAX - px[i]; + py[i] = Y_MAX - py[i]; + } + } + #elif ORIGIN == BOTTOMLEFT + for(i=0;i> (MAX_FINGER_NUMBER-i-1)) & 0x1; + if(pressure) + { + py[i] = Y_MAX - py[i]; + } + } + #endif +} + +/*********************************************************************** + [function]: + callback: reset function; + [parameters]: + void; + [return]: + void; +************************************************************************/ +void ctp_reset(void) +{ +#if defined(TS_RST_GPIO) + //reset mcu + /* gpio_direction_output(TS_RST_GPIO, 1); + msleep(1); + gpio_direction_output(TS_RST_GPIO, 0); + msleep(10); + gpio_direction_output(TS_RST_GPIO, 1); + msleep(20);*/ + wmt_rst_output(1); + msleep(1); + wmt_rst_output(0); + msleep(10); + wmt_rst_output(1); + msleep(20); + dbg("has done\n"); +#else + u8 ts_reset_cmd[1] = {0xb0}; + cyp140_i2c_write_tsdata(this_client, ts_reset_cmd, 1); +#endif + +} + +//************************************************* +#if 1 +#include //wake_up_process() +#include //kthread_create()ã€kthread_run() +//#include //IS_ERR()ã€PTR_ERR() + +void cyttsp_sw_reset(void); +//static struct task_struct *esd_task; +volatile bool need_rst_flag = 0; +volatile int tp_interrupt_flag = 0; +volatile int tp_suspend_flag = 0; +volatile int tp_reseting_flag = 0; + +void cyttsp_print_reg(struct i2c_client *client) +{ +#if 1 + char buffer[20]; + int status=0; + int i; + + status = i2c_smbus_read_i2c_block_data(i2c_client, 0x00, 16, &(buffer[0])); + + printk("++++cyttsp_print_reg=%d: ",status); + for(i = 0; i<16;i++) + printk(" %02x", buffer[i]); + printk("\n"); +#endif + +} + +int exit_boot_mode(void) +{ + + //int retval = TPD_OK; + + char buffer[2]; + int status=0; + status = i2c_smbus_read_i2c_block_data(i2c_client, 0x01, 1, &(buffer[0])); + if(status<0) { + printk ("++++exit_boot_mode failed---1\n"); + return status; + } + else + { + if(buffer[0] & 0x10) + { + status = i2c_master_send(i2c_client, bl_cmd, 12); + if( status < 0) + { + printk ("++++exit_boot_mode failed---2\n"); + return status; + } + else + { + //printk("++++exit_boot_mode ok\n"); + } + msleep(300); + status = i2c_smbus_read_i2c_block_data(i2c_client, 0x01, 1, &(buffer[0])); + if(status<0) { + printk ("++++exit_boot_mode set failed\n"); + return status; + } +// printk("++++exit_boot_mode set: 0x%x\n",buffer[0]); + cyttsp_print_reg(i2c_client); + } + else + { + // printk("++++exit_boot_mode-- not in bootmode\n"); + } + + } + return 0; + +} + +void esd_check(void) +{ + if(need_rst_flag) + { + if(tp_suspend_flag == 0) + { + printk("++++esd_check---rst\n"); + //mt65xx_eint_mask(CUST_EINT_TOUCH_PANEL_NUM); + tp_reseting_flag = 1; + cyttsp_sw_reset(); + tp_reseting_flag = 0; + //mt65xx_eint_unmask(CUST_EINT_TOUCH_PANEL_NUM); + } + need_rst_flag = 0; + } +} +static int fp_count = 0; +#if 0 //close 2013-1-6 +void esd_thread(void) +{ + static int i = 0, j = 0; + while(1) + { + printk("++++esd_thread, need_rst_flag=%d, fp_count=%d\n", need_rst_flag,fp_count); + fp_count = 0; + if(need_rst_flag) + { + j = 0; + while(tp_interrupt_flag==1 && j<200) //wujinyou + { + j ++; + if(tp_suspend_flag) + msleep(1000); + else + msleep(10); + } + if(tp_suspend_flag == 0) + { + printk("++++esd_thread, start reset, mask int\n"); + //mt65xx_eint_mask(CUST_EINT_TOUCH_PANEL_NUM); + tp_reseting_flag = 1; + cyttsp_sw_reset(); + i = 0; + need_rst_flag = 0; + tp_reseting_flag = 0; + //mt65xx_eint_unmask(CUST_EINT_TOUCH_PANEL_NUM); + } + } + msleep(1000); + i ++; + if(i == 10) + { + i = 0; + //cyttsp_sw_reset(); + //need_rst_flag = 1; + } + } +} +static int esd_init_thread(void) +{ + int err; + printk("++++%s, line %d----\n", __FUNCTION__, __LINE__); + + esd_task = kthread_create(esd_thread, NULL, "esd_task"); + + if(IS_ERR(esd_task)){ + printk("++++Unable to start kernel thread.\n"); + err = PTR_ERR(esd_task); + esd_task = NULL; + return err; + } + + wake_up_process(esd_task); + + return 0; + +} +#endif //close 2013-1-6 + +#endif + +static void tpd_down(int x, int y, int p) { + + + //printk("<<<<< 480) { + tpd_button(x, y, 1); + } + } +#endif + //*****here process x y coord and then report!!!! 2013-1-7 + +#if 1//0 + int tmp; + if (tilt) + { + tmp = x; + x = y; + y =tmp; + } + if (rev_x < 0) + x = max_x -x; + if (rev_y < 0) + y = max_y -y; + + +#endif + if (wmt_ts_get_lcdexchg()) { + int t; + t = x; + x = y; + y = max_x - t; + } + + //printk("<<<<<< transfer x,y (%d, %d)\n", x, y);//debug 2013-5-6 + + input_report_abs(tpd->input, ABS_PRESSURE,p); + input_report_key(tpd->input, BTN_TOUCH, 1); + //input_report_abs(tpd->input,ABS_MT_TRACKING_ID,i); + input_report_abs(tpd->input, ABS_MT_TOUCH_MAJOR, 1); + input_report_abs(tpd->input, ABS_MT_POSITION_X, x); + input_report_abs(tpd->input, ABS_MT_POSITION_Y, y); + ////TPD_DEBUG("Down x:%4d, y:%4d, p:%4d \n ", x, y, p); + input_mt_sync(tpd->input); + //TPD_DOWN_DEBUG_TRACK(x,y); + fp_count ++; +} + +static void tpd_up(int x, int y,int p) { + + input_report_abs(tpd->input, ABS_PRESSURE, 0); + input_report_key(tpd->input, BTN_TOUCH, 0); + // input_report_abs(tpd->input,ABS_MT_TRACKING_ID,i); + input_report_abs(tpd->input, ABS_MT_TOUCH_MAJOR, 0); + //input_report_abs(tpd->input, ABS_MT_POSITION_X, x); + //input_report_abs(tpd->input, ABS_MT_POSITION_Y, y); //!!!! + //TPD_DEBUG("Up x:%4d, y:%4d, p:%4d \n", x, y, 0); + input_mt_sync(tpd->input); + // TPD_UP_DEBUG_TRACK(x,y); +} +void test_retval(s32 ret) +{ +#if 1 + if(ret<0) + { + need_rst_flag = 1; + printk("++++test_retval=1-------\n"); + } +#endif +} +static int tpd_touchinfo(struct touch_info *cinfo, struct touch_info *pinfo) +{ + + s32 retval; + static u8 tt_mode; + //pinfo->count = cinfo->count; + u8 data0,data1; + + memcpy(pinfo, cinfo, sizeof(struct touch_info)); + memset(cinfo, 0, sizeof(struct touch_info)); +// printk("pinfo->count =%d\n",pinfo->count); + + retval = i2c_smbus_read_i2c_block_data(i2c_client, TPD_REG_BASE, 8, (u8 *)&g_operation_data); + retval += i2c_smbus_read_i2c_block_data(i2c_client, TPD_REG_BASE + 8, 8, (((u8 *)(&g_operation_data)) + 8)); + retval += i2c_smbus_read_i2c_block_data(i2c_client, TPD_REG_BASE + 16, 8, (((u8 *)(&g_operation_data)) + 16)); + retval += i2c_smbus_read_i2c_block_data(i2c_client, TPD_REG_BASE + 24, 8, (((u8 *)(&g_operation_data)) + 24)); + + + //cyttsp_print_reg(i2c_client); + ////TPD_DEBUG("received raw data from touch panel as following:\n"); + + /*("hst_mode = %02X, tt_mode = %02X, tt_stat = %02X\n", \ + g_operation_data.hst_mode,\ + g_operation_data.tt_mode,\ + g_operation_data.tt_stat); */ + + cinfo->count = (g_operation_data.tt_stat & 0x0f) ; //point count + + //TPD_DEBUG("cinfo->count =%d\n",cinfo->count); + + //TPD_DEBUG("Procss raw data...\n"); + + cinfo->x[0] = (( g_operation_data.x1_M << 8) | ( g_operation_data.x1_L)); //point 1 + cinfo->y[0] = (( g_operation_data.y1_M << 8) | ( g_operation_data.y1_L)); + cinfo->p[0] = 0;//g_operation_data.z1; + + //printk("Before: cinfo->x0 = %3d, cinfo->y0 = %3d, cinfo->p0 = %3d cinfo->id0 = %3d\n", cinfo->x[0] ,cinfo->y[0] ,cinfo->p[0], cinfo->id[0]); + if(cinfo->x[0] < 1) cinfo->x[0] = 1; + if(cinfo->y[0] < 1) cinfo->y[0] = 1; + cinfo->id[0] = ((g_operation_data.touch12_id & 0xf0) >>4) -1; + //printk("After: cinfo->x0 = %3d, cinfo->y0 = %3d, cinfo->p0 = %3d cinfo->id0 = %3d\n", cinfo->x[0] ,cinfo->y[0] ,cinfo->p[0], cinfo->id[0]); + + if(cinfo->count >1) + { + cinfo->x[1] = (( g_operation_data.x2_M << 8) | ( g_operation_data.x2_L)); //point 2 + cinfo->y[1] = (( g_operation_data.y2_M << 8) | ( g_operation_data.y2_L)); + cinfo->p[1] = 0;//g_operation_data.z2; + + //printk("before: cinfo->x2 = %3d, cinfo->y2 = %3d, cinfo->p2 = %3d\n", cinfo->x2, cinfo->y2, cinfo->p2); + if(cinfo->x[1] < 1) cinfo->x[1] = 1; + if(cinfo->y[1] < 1) cinfo->y[1] = 1; + cinfo->id[1] = ((g_operation_data.touch12_id & 0x0f)) -1; + //printk("After: cinfo->x[1] = %3d, cinfo->y[1] = %3d, cinfo->p[1] = %3d, cinfo->id[1] = %3d\n", cinfo->x[1], cinfo->y[1], cinfo->p[1], cinfo->id[1]); + + if (cinfo->count > 2) + { + cinfo->x[2]= (( g_operation_data.x3_M << 8) | ( g_operation_data.x3_L)); //point 3 + cinfo->y[2] = (( g_operation_data.y3_M << 8) | ( g_operation_data.y3_L)); + cinfo->p[2] = 0;//g_operation_data.z3; + cinfo->id[2] = ((g_operation_data.touch34_id & 0xf0) >> 4) -1; + + //printk("before: cinfo->x[2] = %3d, cinfo->y[2] = %3d, cinfo->p[2] = %3d\n", cinfo->x[2], cinfo->y[2], cinfo->p[2]); + if(cinfo->x[2] < 1) cinfo->x[2] = 1; + if(cinfo->y[2]< 1) cinfo->y[2] = 1; + //printk("After: cinfo->x[2]= %3d, cinfo->y[2] = %3d, cinfo->p[2]= %3d, cinfo->id[2] = %3d\n", cinfo->x[2], cinfo->y[2], cinfo->p[2], cinfo->id[2]); + + if (cinfo->count > 3) + { + cinfo->x[3] = (( g_operation_data.x4_M << 8) | ( g_operation_data.x4_L)); //point 3 + cinfo->y[3] = (( g_operation_data.y4_M << 8) | ( g_operation_data.y4_L)); + cinfo->p[3] = 0;//g_operation_data.z4; + cinfo->id[3] = ((g_operation_data.touch34_id & 0x0f)) -1; + + //printk("before: cinfo->x[3] = %3d, cinfo->y[3] = %3d, cinfo->p[3] = %3d, cinfo->id[3] = %3d\n", cinfo->x[3], cinfo->y[3], cinfo->p[3], cinfo->id[3]); + //printk("before: x4_M = %3d, x4_L = %3d\n", g_operation_data.x4_M, g_operation_data.x4_L); + if(cinfo->x[3] < 1) cinfo->x[3] = 1; + if(cinfo->y[3] < 1) cinfo->y[3] = 1; + //printk("After: cinfo->x[3] = %3d, cinfo->y[3] = %3d, cinfo->p[3]= %3d, cinfo->id[3] = %3d\n", cinfo->x[3], cinfo->y[3], cinfo->p[3], cinfo->id[3]); + } + if (cinfo->count > 4) + { + cinfo->x[4] = (( g_operation_data.x5_M << 8) | ( g_operation_data.x5_L)); //point 3 + cinfo->y[4] = (( g_operation_data.y5_M << 8) | ( g_operation_data.y5_L)); + cinfo->p[4] = 0;//g_operation_data.z4; + cinfo->id[4] = ((g_operation_data.touch5_id & 0xf0) >> 4) -1; + + //printk("before: cinfo->x[4] = %3d, cinfo->y[4] = %3d, cinfo->id[4] = %3d\n", cinfo->x[4], cinfo->y[4], cinfo->id[4]); + //printk("before: x5_M = %3d, x5_L = %3d\n", g_operation_data.x5_M, g_operation_data.x5_L); + if(cinfo->x[4] < 1) cinfo->x[4] = 1; + if(cinfo->y[4] < 1) cinfo->y[4] = 1; + //printk("After: cinfo->x[4] = %3d, cinfo->y[4] = %3d, cinfo->id[4] = %3d\n", cinfo->x[4], cinfo->y[4], cinfo->id[4]); + } + } + + } + + if (!cinfo->count) return true; // this is a touch-up event + + if (g_operation_data.tt_mode & 0x20) { + //TPD_DEBUG("uffer is not ready for use!\n"); + memcpy(cinfo, pinfo, sizeof(struct touch_info)); + return false; + }//return false; // buffer is not ready for use// buffer is not ready for use + + // data toggle + + data0 = i2c_smbus_read_i2c_block_data(i2c_client, TPD_REG_BASE, 1, (u8*)&g_operation_data); + ////TPD_DEBUG("before hst_mode = %02X \n", g_operation_data.hst_mode); + + if((g_operation_data.hst_mode & 0x80)==0) + g_operation_data.hst_mode = g_operation_data.hst_mode|0x80; + else + g_operation_data.hst_mode = g_operation_data.hst_mode & (~0x80); + + ////TPD_DEBUG("after hst_mode = %02X \n", g_operation_data.hst_mode); + data1 = i2c_smbus_write_i2c_block_data(i2c_client, TPD_REG_BASE, sizeof(g_operation_data.hst_mode), &g_operation_data.hst_mode); + + + if (tt_mode == g_operation_data.tt_mode) { + //TPD_DEBUG("sampling not completed!\n"); + memcpy(cinfo, pinfo, sizeof(struct touch_info)); + return false; + }// sampling not completed + else + tt_mode = g_operation_data.tt_mode; + + return true; + +}; + +static int touch_event_handler(void *unused) +{ + int i,j; + int keeppoint[5]; + struct touch_info cinfo, pinfo; + struct sched_param param = { .sched_priority = 70/*RTPM_PRIO_TPD*/ }; + sched_setscheduler(current, SCHED_RR, ¶m); + + do + { + //printk("++++%s, line %d----unmask int\n", __FUNCTION__, __LINE__); + // mt65xx_eint_unmask(CUST_EINT_TOUCH_PANEL_NUM); + wmt_enable_gpirq(); + set_current_state(TASK_INTERRUPTIBLE); + tp_interrupt_flag = 0; + //printk("++++%s, line %d----end\n", __FUNCTION__, __LINE__); + wait_event_interruptible(waiter,tpd_flag!=0); +// printk("++++%s, line %d----start\n", __FUNCTION__, __LINE__); + + tpd_flag = 0; //debg 2013-5-6 + set_current_state(TASK_RUNNING); + + exit_boot_mode(); + if (tpd_touchinfo(&cinfo, &pinfo)) + { + memset(keeppoint, 0x0, sizeof(keeppoint)); + if(cinfo.count >0 && cinfo.count < (TP_POINTS_CNT+1)) + { + switch(cinfo.count) + { + case 5: + { + tpd_down(cinfo.x[4], cinfo.y[4], cinfo.p[4]); + } + case 4: + { + tpd_down(cinfo.x[3], cinfo.y[3], cinfo.p[3]); + } + case 3: + { + tpd_down(cinfo.x[2], cinfo.y[2], cinfo.p[2]); + } + case 2: + { + tpd_down(cinfo.x[1], cinfo.y[1], cinfo.p[1]); + } + case 1: + { + tpd_down(cinfo.x[0], cinfo.y[0], cinfo.p[0]); + } + default: + break; + } + for(i = 0; i < cinfo.count; i++) + for(j = 0; j < pinfo.count; j++) + { + if(cinfo.id[i] == pinfo.id[j])keeppoint[j] = 1; + else if(keeppoint[j] != 1)keeppoint[j] = 0; + } + + for(j = 0; j < pinfo.count; j++) + { + if(keeppoint[j] != 1) + { + tpd_up(pinfo.x[j], pinfo.y[j], pinfo.p[j]); + } + } + + } + else if(cinfo.count == 0 && pinfo.count !=0) + { + switch(pinfo.count ) + { + case 5: + { + tpd_up(pinfo.x[4], pinfo.y[4], pinfo.p[4]); + } + case 4: + { + tpd_up(pinfo.x[3], pinfo.y[3], pinfo.p[3]); + } + case 3: + { + tpd_up(pinfo.x[2], pinfo.y[2], pinfo.p[2]); + } + case 2: + { + tpd_up(pinfo.x[1], pinfo.y[1], pinfo.p[1]); + } + case 1: + { + tpd_up(pinfo.x[0], pinfo.y[0], pinfo.p[0]); + } + default: + break; + } + } + + input_sync(tpd->input); + + } + + + + }while(!kthread_should_stop()); + tp_interrupt_flag = 0; + + return 0; +} + + + + +static irqreturn_t tpd_eint_interrupt_handler(int irq, void *dev_id) +{ + static int i = 0; + i ++; + //printk("++++eint=%d\n",i); + + //mt65xx_eint_mask(CUST_EINT_TOUCH_PANEL_NUM); +// printk("++++%s, line %d, tpd_flag=%d,i=%d\n", __FUNCTION__, __LINE__, tpd_flag,i); + + if (wmt_is_tsint()) + { + // printk("<<<client/*i2c_ts*/ = client; + i2c_set_clientdata(client, tpd); + tpd->input = input_dev; + + input_dev->name = "touch_cyp140"; //MJ5_TS_NAME; + input_dev->phys = "cyp140_touch/input0"; + input_dev->id.bustype = BUS_HOST; + input_dev->id.vendor = 0x0001; + input_dev->id.product = 0x0002; + input_dev->id.version = 0x0100; + + input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + set_bit(INPUT_PROP_DIRECT, input_dev->propbit); + if (wmt_ts_get_lcdexchg()) { + input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, max_y/*480*//*600*//*ResolutionX*//*ResolutionX*/, 0, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, max_x /*ResolutionY*//*800*//* 1024*/, 0, 0); + } else { + input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, max_x/*480*//*600*//*ResolutionX*//*ResolutionX*/, 0, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, max_y /*ResolutionY*//*800*//* 1024*/, 0, 0); + } + + set_bit(KEY_BACK, input_dev->keybit); + set_bit(KEY_HOME, input_dev->keybit); + set_bit(KEY_MENU, input_dev->keybit); + retval = input_register_device(input_dev); + if (retval) + { + printk("%s input register device error!!\n", __FUNCTION__); + goto E_REG_INPUT; + } + //**************************** + //ctp_power_on(1); //wujinyou //!!!!2013-1-6 + + msleep(1000); + + //printk("<<<irq = wmt_get_tsirqnum(); + retval = request_irq(tpd->irq, tpd_eint_interrupt_handler,IRQF_SHARED, "cypcm", tpd); + //**************************************** + + printk("tpd_probe request_irq retval=%d!\n",retval); + msleep(100); + msleep(1000); + + cust_ts.client = i2c_client; +// cyttsp_fw_upgrade(); //!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +#if 0 //by linda 20130126 + status = i2c_smbus_read_i2c_block_data(i2c_client, 0x01, 1, &(buffer[0])); + printk("tpd_probe request_irq status=%d!\n",status); + + retval = i2c_master_send(i2c_client, bl_cmd, 12); + if( retval < 0) + { + printk("tpd_probe i2c_master_send retval=%d!\n",retval); + + //return retval; + goto I2C_ERR; + } +#else + retval = exit_boot_mode(); + if (retval) + { + printk("%s exit_boot_mod error!\n", __FUNCTION__); + goto I2C_ERR; + } + +#endif +/* + msleep(1000); + retval = i2c_smbus_read_i2c_block_data(i2c_client, 0x00, 1, &(buffer[0])); + if(retval<0) { + retval = i2c_smbus_read_i2c_block_data(i2c_client, 0x00, 1, &(buffer[0])); + if(retval<0) { + printk("error read !%d\n", __LINE__); + + goto I2C_ERR; + } + } +*/ + //TPD_DEBUG("[mtk-tpd], cyttsp tpd_i2c_probe success!!\n"); + tpd_load_status = 1; + thread = kthread_run(touch_event_handler, 0, TPD_DEVICE); + if (IS_ERR(thread)) { + retval = PTR_ERR(thread); + return retval; + + } + + + msleep(100); + printk("++++tpd_probe,retval=%d\n", retval); +#ifdef CONFIG_HAS_EARLYSUSPEND + tpd->early_suspend.suspend = tpd_early_suspend, + tpd->early_suspend.resume = tpd_late_resume, + tpd->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 1;//,EARLY_SUSPEND_LEVEL_DISABLE_FB + 2; + register_early_suspend(&tpd->early_suspend); +#endif + //disable_irq(cyp140_ts->irq); + + wmt_enable_gpirq(); + +//cust_timer_init(); +// esd_init_thread(); //close it 2013-1-6 + return 0; //retval; + I2C_ERR: + free_irq(tpd->irq, tpd); + input_unregister_device(input_dev); // + E_REG_INPUT: + input_free_device(input_dev); + kfree(tpd); + //return retval; + Fail_request_rstgpio: + gpio_free(gpio_rst); + gpio_free(gpio_irq); + return retval; + +} +//******************************* + +//module_init(cyp140_ts_init); +static int tpd_local_init(void) +{ + if (tpd_probe(ts_get_i2c_client()))// ???? + { + return -1; + } + + + if(tpd_load_status == 0){ + //return -1; + ; + } + +#ifdef TPD_HAVE_BUTTON + tpd_button_setting(TPD_KEY_COUNT, tpd_keys_local, tpd_keys_dim_local);// initialize tpd button data + boot_mode = get_boot_mode(); +#endif + return 0;//!!!!2013-1-7 +} + +//**********************suspend & resume +static int tpd_resume(/*struct i2c_client *client*/struct platform_device *pdev) +{ + int retval = TPD_OK; + int status = 0; + printk("++++%s, line %d----end\n", __FUNCTION__, __LINE__); + //mt65xx_eint_mask(CUST_EINT_TOUCH_PANEL_NUM); + msleep(100); + #if 1 + ctp_power_on(1); + #endif + + msleep(1); + wmt_rst_output(0); + msleep(1); + wmt_rst_output(1); + msleep(100); + + wmt_set_gpirq(IRQ_TYPE_EDGE_FALLING);//sometimes gpio7 will in low after resume 2013-5-9 + wmt_enable_gpirq(); + printk("++++%s, line %d----end\n", __FUNCTION__, __LINE__); + + //TPD_DEBUG("TPD wake up\n"); + + #if 0 //0 // by linda 20120126 change rambo 2013-5-6 + status = i2c_master_send(i2c_client, bl_cmd, 12); + #else + exit_boot_mode(); + #endif + printk("++++%s, line %d----end\n", __FUNCTION__, __LINE__); + + if( status < 0) + { + printk("++++ [mtk-tpd], cyttsp tpd exit bootloader mode failed--tpd_resume!\n"); + return status; + } + //exit_boot_mode(); + printk("++++%s, line %d----end\n", __FUNCTION__, __LINE__); + msleep(300); + //wmt_enable_gpirq(); //debg 2013-5-6 + tp_suspend_flag = 0; + return retval; +} + +static int tpd_suspend(/*struct i2c_client *client*/struct platform_device *pdev, pm_message_t message) +{ + int i = 0; + int retval = TPD_OK; + //u8 sleep_mode = 0x02; // 0x02--CY_DEEP_SLEEP_MODE, 0x04--CY_LOW_PWR_MODE + //TPD_DEBUG("TPD enter sleep\n"); + //u8 sleep_reg[2] = {0, 2}; + printk("++++%s, line %d----end\n", __FUNCTION__, __LINE__); + wmt_disable_gpirq(); + //wmt_disable_gpirq(); //dbg 2013-5-6 + + while((tp_reseting_flag || tp_interrupt_flag) && i<30) + { + i ++; + msleep(100); + } + tp_suspend_flag = 1; +#if 1 + //retval = i2c_smbus_write_i2c_block_data(i2c_client,0x00,sizeof(sleep_mode), &sleep_mode); + //retval = i2c_master_send(i2c_client, sleep_reg, 2); //send cmd error -5! + msleep(1); + ctp_power_on(0); + mdelay(1); +#else + mt_set_gpio_mode(GPIO_CTP_RST_PIN, GPIO_CTP_RST_PIN_M_GPIO); + mt_set_gpio_dir(GPIO_CTP_RST_PIN, GPIO_DIR_OUT); + mt_set_gpio_out(GPIO_CTP_RST_PIN, GPIO_OUT_ONE); +#endif + + return retval; +} + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void tpd_early_suspend(struct early_suspend *handler) +{ + tpd_suspend(i2c_client, PMSG_SUSPEND); +} + +static void tpd_late_resume(struct early_suspend *handler) +{ + tpd_resume(i2c_client); +} +#endif +//**************************** + + +static void cyp140_ts_exit(void) +{ + printk("<<<%s\n", __FUNCTION__); + + wmt_disable_gpirq(); + free_irq(tpd->irq, tpd); + //kthread_stop(thread); // halt rmmod?? + input_unregister_device(tpd->input); // + + input_free_device(tpd->input); + kfree(tpd); + gpio_free(wmt_ts_get_irqgpnum()); + gpio_free(wmt_ts_get_resetgpnum()); +} +//module_exit(cyp140_ts_exit); + +void cyp140_set_ts_mode(u8 mode) +{ + dbg( "[Touch Screen]ts mode = %d \n", mode); +} +//EXPORT_SYMBOL_GPL(cyp140_set_ts_mode); + +struct wmtts_device cyp140_tsdev = { + .driver_name = WMT_TS_I2C_NAME, + .ts_id = "cyp140", + .init = tpd_local_init, + .exit = cyp140_ts_exit, + .suspend = tpd_suspend, + .resume = tpd_resume, +}; + + + +MODULE_DESCRIPTION("cyp140 I2C Touch Screen driver"); +MODULE_LICENSE("GPL v2"); diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/cyttsp.h b/ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/cyttsp.h new file mode 100755 index 00000000..6020018f --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/cyttsp.h @@ -0,0 +1,696 @@ +/* Header file for: + * Cypress TrueTouch(TM) Standard Product touchscreen drivers. + * include/linux/cyttsp.h + * + * Copyright (C) 2009, 2010 Cypress Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2, and only version 2, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Cypress reserves the right to make changes without further notice + * to the materials described herein. Cypress does not assume any + * liability arising out of the application described herein. + * + * Contact Cypress Semiconductor at www.cypress.com + * + */ + + +#ifndef __CYTTSP_H__ +#define __CYTTSP_H__ + +#include +#include +#include +#include +#include + +#include + +#define CYPRESS_TTSP_NAME "cyttsp" +#define CY_I2C_NAME "cyttsp-i2c" +#define CY_SPI_NAME "cyttsp-spi" + +#ifdef CY_DECLARE_GLOBALS + uint32_t cyttsp_tsdebug; + module_param_named(tsdebug, cyttsp_tsdebug, uint, 0664); + uint32_t cyttsp_tsxdebug; + module_param_named(tsxdebug, cyttsp_tsxdebug, uint, 0664); + + uint32_t cyttsp_disable_touch; + module_param_named(disable_touch, cyttsp_disable_touch, uint, 0664); +#else + extern uint32_t cyttsp_tsdebug; + extern uint32_t cyttsp_tsxdebug; + extern uint32_t cyttsp_disable_touch; +#endif + + + +/****************************************************************************** + * Global Control, Used to control the behavior of the driver + */ + +/* defines for Gen2 (Txx2xx); Gen3 (Txx3xx) + * use these defines to set cyttsp_platform_data.gen in board config file + */ +#define CY_GEN2 2 +#define CY_GEN3 3 + +/* define for using I2C driver + */ +#define CY_USE_I2C_DRIVER + +/* defines for using SPI driver */ +/* +#define CY_USE_SPI_DRIVER + */ +#define CY_SPI_DFLT_SPEED_HZ 1000000 +#define CY_SPI_MAX_SPEED_HZ 4000000 +#define CY_SPI_SPEED_HZ CY_SPI_DFLT_SPEED_HZ +#define CY_SPI_BITS_PER_WORD 8 +#define CY_SPI_DAV 139 /* set correct gpio id */ +#define CY_SPI_BUFSIZE 512 + +/* Voltage and Current ratings */ +#define CY_TMA300_VTG_MAX_UV 5500000 +#define CY_TMA300_VTG_MIN_UV 1710000 +#define CY_TMA300_CURR_24HZ_UA 17500 +#define CY_I2C_VTG_MAX_UV 1800000 +#define CY_I2C_VTG_MIN_UV 1800000 +#define CY_I2C_CURR_UA 9630 + + +/* define for inclusion of TTSP App Update Load File + * use this define if update to the TTSP Device is desired + */ +/* +#define CY_INCLUDE_LOAD_FILE +*/ + +/* define if force new load file for bootloader load */ +/* +#define CY_FORCE_FW_UPDATE +*/ + +/* undef for production use */ +/* +#define CY_USE_DEBUG +*/ + +/* undef for irq use; use this define in the board configuration file */ +/* +#define CY_USE_TIMER + */ + +/* undef to allow use of extra debug capability */ +/* +#define CY_ALLOW_EXTRA_DEBUG +*/ + +/* undef to remove additional debug prints */ +/* +#define CY_USE_EXTRA_DEBUG +*/ + +/* undef to remove additional debug prints */ +/* +#define CY_USE_EXTRA_DEBUG1 + */ + +/* undef to use operational touch timer jiffies; else use test jiffies */ +/* + */ + /* +#define CY_USE_TIMER_DEBUG +*/ +/* define to use canned test data */ +/* +#define CY_USE_TEST_DATA + */ + +/* define if gesture signaling is used + * and which gesture groups to use + */ +/* +#define CY_USE_GEST +#define CY_USE_GEST_GRP1 +#define CY_USE_GEST_GRP2 +#define CY_USE_GEST_GRP3 +#define CY_USE_GEST_GRP4 + */ +/* Active distance in pixels for a gesture to be reported + * if set to 0, then all gesture movements are reported + */ +#define CY_ACT_DIST_DFLT 8 +#define CY_ACT_DIST CY_ACT_DIST_DFLT + +/* define if MT signals are desired */ +/* +*/ +#define CY_USE_MT_SIGNALS + +/* define if MT tracking id signals are used */ +/* +#define CY_USE_MT_TRACK_ID + */ + +/* define if ST signals are required */ +/* +*/ +//#define CY_USE_ST_SIGNALS + +/* define to send handshake to device */ +/* +*/ +#define CY_USE_HNDSHK + +/* define if log all raw motion signals to a sysfs file */ +/* +#define CY_LOG_TO_FILE +*/ + + +/* End of the Global Control section + ****************************************************************************** + */ +#define CY_DIFF(m, n) ((m) != (n)) + +#ifdef CY_LOG_TO_FILE + #define cyttsp_openlog() /* use sysfs */ +#else + #define cyttsp_openlog() +#endif /* CY_LOG_TO_FILE */ + +/* see kernel.h for pr_xxx def'ns */ +#define cyttsp_info(f, a...) pr_info("%s:" f, __func__ , ## a) +#define cyttsp_error(f, a...) pr_err("%s:" f, __func__ , ## a) +#define cyttsp_alert(f, a...) pr_alert("%s:" f, __func__ , ## a) + +#ifdef CY_USE_DEBUG + #define cyttsp_debug(f, a...) pr_alert("%s:" f, __func__ , ## a) +#else + #define cyttsp_debug(f, a...) {if (cyttsp_tsdebug) \ + pr_alert("%s:" f, __func__ , ## a); } +#endif /* CY_USE_DEBUG */ + +#ifdef CY_ALLOW_EXTRA_DEBUG +#ifdef CY_USE_EXTRA_DEBUG + #define cyttsp_xdebug(f, a...) pr_alert("%s:" f, __func__ , ## a) +#else + #define cyttsp_xdebug(f, a...) {if (cyttsp_tsxdebug) \ + pr_alert("%s:" f, __func__ , ## a); } +#endif /* CY_USE_EXTRA_DEBUG */ + +#ifdef CY_USE_EXTRA_DEBUG1 + #define cyttsp_xdebug1(f, a...) pr_alert("%s:" f, __func__ , ## a) +#else + #define cyttsp_xdebug1(f, a...) +#endif /* CY_USE_EXTRA_DEBUG1 */ +#else + #define cyttsp_xdebug(f, a...) + #define cyttsp_xdebug1(f, a...) +#endif /* CY_ALLOW_EXTRA_DEBUG */ + +#ifdef CY_USE_TIMER_DEBUG + #define TOUCHSCREEN_TIMEOUT (msecs_to_jiffies(1000)) +#else + #define TOUCHSCREEN_TIMEOUT (msecs_to_jiffies(28)) +#endif + +/* reduce extra signals in MT only build + * be careful not to lose backward compatibility for pre-MT apps + */ +#ifdef CY_USE_ST_SIGNALS + #define CY_USE_ST 1 +#else + #define CY_USE_ST 0 +#endif /* CY_USE_ST_SIGNALS */ + +/* rely on kernel input.h to define Multi-Touch capability */ +/* if input.h defines the Multi-Touch signals, then use MT */ +#if defined(ABS_MT_TOUCH_MAJOR) && defined(CY_USE_MT_SIGNALS) + #define CY_USE_MT 1 + #define CY_MT_SYNC(input) input_mt_sync(input) +#else + #define CY_USE_MT 0 + #define CY_MT_SYNC(input) + /* the following includes are provided to ensure a compile; + * the code that compiles with these defines will not be executed if + * the CY_USE_MT is properly used in the platform structure init + */ + #ifndef ABS_MT_TOUCH_MAJOR + #define ABS_MT_TOUCH_MAJOR 0x30 /* touching ellipse */ + #define ABS_MT_TOUCH_MINOR 0x31 /* (omit if circular) */ + #define ABS_MT_WIDTH_MAJOR 0x32 /* approaching ellipse */ + #define ABS_MT_WIDTH_MINOR 0x33 /* (omit if circular) */ + #define ABS_MT_ORIENTATION 0x34 /* Ellipse orientation */ + #define ABS_MT_POSITION_X 0x35 /* Center X ellipse position */ + #define ABS_MT_POSITION_Y 0x36 /* Center Y ellipse position */ + #define ABS_MT_TOOL_TYPE 0x37 /* Type of touching device */ + #define ABS_MT_BLOB_ID 0x38 /* Group set of pkts as blob */ + #endif /* ABS_MT_TOUCH_MAJOR */ +#endif /* ABS_MT_TOUCH_MAJOR and CY_USE_MT_SIGNALS */ +#if defined(ABS_MT_TRACKING_ID) && defined(CY_USE_MT_TRACK_ID) + #define CY_USE_TRACKING_ID 1 +#else + #define CY_USE_TRACKING_ID 0 +/* define only if not defined already by system; + * value based on linux kernel 2.6.30.10 + */ +#ifndef ABS_MT_TRACKING_ID + #define ABS_MT_TRACKING_ID (ABS_MT_BLOB_ID+1) +#endif +#endif /* ABS_MT_TRACKING_ID */ + +#define CY_USE_DEEP_SLEEP_SEL 0x80 +#define CY_USE_LOW_POWER_SEL 0x01 + +#ifdef CY_USE_TEST_DATA + #define cyttsp_testdat(ray1, ray2, sizeofray) \ + { \ + int i; \ + u8 *up1 = (u8 *)ray1; \ + u8 *up2 = (u8 *)ray2; \ + for (i = 0; i < sizeofray; i++) { \ + up1[i] = up2[i]; \ + } \ + } +#else + #define cyttsp_testdat(xy, test_xy, sizeofray) +#endif /* CY_USE_TEST_DATA */ + +/* helper macros */ +#define GET_NUM_TOUCHES(x) ((x) & 0x0F) +#define GET_TOUCH1_ID(x) (((x) & 0xF0) >> 4) +#define GET_TOUCH2_ID(x) ((x) & 0x0F) +#define GET_TOUCH3_ID(x) (((x) & 0xF0) >> 4) +#define GET_TOUCH4_ID(x) ((x) & 0x0F) +#define IS_LARGE_AREA(x) (((x) & 0x10) >> 4) +#define FLIP_DATA_FLAG 0x01 +#define REVERSE_X_FLAG 0x02 +#define REVERSE_Y_FLAG 0x04 +#define FLIP_DATA(flags) ((flags) & FLIP_DATA_FLAG) +#define REVERSE_X(flags) ((flags) & REVERSE_X_FLAG) +#define REVERSE_Y(flags) ((flags) & REVERSE_Y_FLAG) +#define FLIP_XY(x, y) { \ + u16 tmp; \ + tmp = (x); \ + (x) = (y); \ + (y) = tmp; \ + } +#define INVERT_X(x, xmax) ((xmax) - (x)) +#define INVERT_Y(y, maxy) ((maxy) - (y)) +#define SET_HSTMODE(reg, mode) ((reg) & (mode)) +#define GET_HSTMODE(reg) ((reg & 0x70) >> 4) +#define GET_BOOTLOADERMODE(reg) ((reg & 0x10) >> 4) + +/* constant definitions */ +/* maximum number of concurrent ST track IDs */ +#define CY_NUM_ST_TCH_ID 2 + +/* maximum number of concurrent MT track IDs */ +#define CY_NUM_MT_TCH_ID 4 + +/* maximum number of track IDs */ +#define CY_NUM_TRK_ID 16 + +#define CY_NTCH 0 /* no touch (lift off) */ +#define CY_TCH 1 /* active touch (touchdown) */ +#define CY_ST_FNGR1_IDX 0 +#define CY_ST_FNGR2_IDX 1 +#define CY_MT_TCH1_IDX 0 +#define CY_MT_TCH2_IDX 1 +#define CY_MT_TCH3_IDX 2 +#define CY_MT_TCH4_IDX 3 +#define CY_XPOS 0 +#define CY_YPOS 1 +#define CY_IGNR_TCH (-1) +#define CY_SMALL_TOOL_WIDTH 10 +#define CY_LARGE_TOOL_WIDTH 255 +#define CY_REG_BASE 0x00 +#define CY_REG_GEST_SET 0x1E +#define CY_REG_ACT_INTRVL 0x1D +#define CY_REG_TCH_TMOUT (CY_REG_ACT_INTRVL+1) +#define CY_REG_LP_INTRVL (CY_REG_TCH_TMOUT+1) +#define CY_SOFT_RESET ((1 << 0)) +#define CY_DEEP_SLEEP ((1 << 1)) +#define CY_LOW_POWER ((1 << 2)) +#define CY_MAXZ 255 +#define CY_OK 0 +#define CY_INIT 1 +#define CY_DLY_DFLT 10 /* ms */ +#define CY_DLY_SYSINFO 20 /* ms */ +#define CY_DLY_BL 300 +#define CY_DLY_DNLOAD 100 /* ms */ +#define CY_NUM_RETRY 4 /* max num touch data read */ + +/* handshake bit in the hst_mode reg */ +#define CY_HNDSHK_BIT 0x80 +#ifdef CY_USE_HNDSHK + #define CY_SEND_HNDSHK 1 +#else + #define CY_SEND_HNDSHK 0 +#endif + +/* Bootloader File 0 offset */ +#define CY_BL_FILE0 0x00 + +/* Bootloader command directive */ +#define CY_BL_CMD 0xFF + +/* Bootloader Initiate Bootload */ +#define CY_BL_INIT_LOAD 0x38 + +/* Bootloader Write a Block */ +#define CY_BL_WRITE_BLK 0x39 + +/* Bootloader Terminate Bootload */ +#define CY_BL_TERMINATE 0x3B + +/* Bootloader Exit and Verify Checksum command */ +#define CY_BL_EXIT 0xA5 + +/* Bootloader default keys */ +#define CY_BL_KEY0 0x00 +#define CY_BL_KEY1 0x01 +#define CY_BL_KEY2 0x02 +#define CY_BL_KEY3 0x03 +#define CY_BL_KEY4 0x04 +#define CY_BL_KEY5 0x05 +#define CY_BL_KEY6 0x06 +#define CY_BL_KEY7 0x07 + +/* Active Power state scanning/processing refresh interval */ +#define CY_ACT_INTRVL_DFLT 0x00 + +/* touch timeout for the Active power */ +#define CY_TCH_TMOUT_DFLT 0xFF + +/* Low Power state scanning/processing refresh interval */ +#define CY_LP_INTRVL_DFLT 0x0A + +#define CY_IDLE_STATE 0 +#define CY_ACTIVE_STATE 1 +#define CY_LOW_PWR_STATE 2 +#define CY_SLEEP_STATE 3 + +/* device mode bits */ +#define CY_OP_MODE 0x00 +#define CY_SYSINFO_MODE 0x10 + +/* power mode select bits */ +#define CY_SOFT_RESET_MODE 0x01 /* return to Bootloader mode */ +#define CY_DEEP_SLEEP_MODE 0x02 +#define CY_LOW_PWR_MODE 0x04 + +#define CY_NUM_KEY 8 + +#ifdef CY_USE_GEST + #define CY_USE_GESTURES 1 +#else + #define CY_USE_GESTURES 0 +#endif /* CY_USE_GESTURE_SIGNALS */ + +#ifdef CY_USE_GEST_GRP1 + #define CY_GEST_GRP1 0x10 +#else + #define CY_GEST_GRP1 0x00 +#endif /* CY_USE_GEST_GRP1 */ +#ifdef CY_USE_GEST_GRP2 + #define CY_GEST_GRP2 0x20 +#else + #define CY_GEST_GRP2 0x00 +#endif /* CY_USE_GEST_GRP2 */ +#ifdef CY_USE_GEST_GRP3 + #define CY_GEST_GRP3 0x40 +#else + #define CY_GEST_GRP3 0x00 +#endif /* CY_USE_GEST_GRP3 */ +#ifdef CY_USE_GEST_GRP4 + #define CY_GEST_GRP4 0x80 +#else + #define CY_GEST_GRP4 0x00 +#endif /* CY_USE_GEST_GRP4 */ + +struct cyttsp_regulator { + const char *name; + u32 min_uV; + u32 max_uV; + u32 load_uA; +}; + +struct cyttsp_platform_data { + u32 panel_maxx; + u32 panel_maxy; + u32 disp_resx; + u32 disp_resy; + u32 disp_minx; + u32 disp_miny; + u32 disp_maxx; + u32 disp_maxy; + u8 correct_fw_ver; + u32 flags; + u8 gen; + u8 use_st; + u8 use_mt; + u8 use_hndshk; + u8 use_trk_id; + u8 use_sleep; + u8 use_gestures; + u8 gest_set; + u8 act_intrvl; + u8 tch_tmout; + u8 lp_intrvl; + u8 power_state; + bool wakeup; + int sleep_gpio; + int resout_gpio; + int irq_gpio; + struct cyttsp_regulator *regulator_info; + u8 num_regulators; + const char *fw_fname; +#ifdef CY_USE_I2C_DRIVER + s32 (*init)(struct i2c_client *client); + s32 (*resume)(struct i2c_client *client); +#endif +#ifdef CY_USE_SPI_DRIVER + s32 (*init)(struct spi_device *spi); + s32 (*resume)(struct spi_device *spi); +#endif +}; + +/* TrueTouch Standard Product Gen3 (Txx3xx) interface definition */ +struct cyttsp_gen3_xydata_t { + u8 hst_mode; + u8 tt_mode; + u8 tt_stat; + u16 x1 __attribute__ ((packed)); + u16 y1 __attribute__ ((packed)); + u8 z1; + u8 touch12_id; + u16 x2 __attribute__ ((packed)); + u16 y2 __attribute__ ((packed)); + u8 z2; + u8 gest_cnt; + u8 gest_id; + u16 x3 __attribute__ ((packed)); + u16 y3 __attribute__ ((packed)); + u8 z3; + u8 touch34_id; + u16 x4 __attribute__ ((packed)); + u16 y4 __attribute__ ((packed)); + u8 z4; + u8 tt_undef[3]; + u8 gest_set; + u8 tt_reserved; +}; + +/* TrueTouch Standard Product Gen2 (Txx2xx) interface definition */ +#define CY_GEN2_NOTOUCH 0x03 /* Both touches removed */ +#define CY_GEN2_GHOST 0x02 /* ghost */ +#define CY_GEN2_2TOUCH 0x03 /* 2 touch; no ghost */ +#define CY_GEN2_1TOUCH 0x01 /* 1 touch only */ +#define CY_GEN2_TOUCH2 0x01 /* 1st touch removed; + * 2nd touch remains */ +struct cyttsp_gen2_xydata_t { + u8 hst_mode; + u8 tt_mode; + u8 tt_stat; + u16 x1 __attribute__ ((packed)); + u16 y1 __attribute__ ((packed)); + u8 z1; + u8 evnt_idx; + u16 x2 __attribute__ ((packed)); + u16 y2 __attribute__ ((packed)); + u8 tt_undef1; + u8 gest_cnt; + u8 gest_id; + u8 tt_undef[14]; + u8 gest_set; + u8 tt_reserved; +}; + +/* TTSP System Information interface definition */ +struct cyttsp_sysinfo_data_t { + u8 hst_mode; + u8 mfg_cmd; + u8 mfg_stat; + u8 cid[3]; + u8 tt_undef1; + u8 uid[8]; + u8 bl_verh; + u8 bl_verl; + u8 tts_verh; + u8 tts_verl; + u8 app_idh; + u8 app_idl; + u8 app_verh; + u8 app_verl; + u8 tt_undef[6]; + u8 act_intrvl; + u8 tch_tmout; + u8 lp_intrvl; +}; + +/* TTSP Bootloader Register Map interface definition */ +#define CY_BL_CHKSUM_OK 0x01 +struct cyttsp_bootloader_data_t { + u8 bl_file; + u8 bl_status; + u8 bl_error; + u8 blver_hi; + u8 blver_lo; + u8 bld_blver_hi; + u8 bld_blver_lo; + u8 ttspver_hi; + u8 ttspver_lo; + u8 appid_hi; + u8 appid_lo; + u8 appver_hi; + u8 appver_lo; + u8 cid_0; + u8 cid_1; + u8 cid_2; +}; + +#define cyttsp_wake_data_t cyttsp_gen3_xydata_t +#ifdef CY_DECLARE_GLOBALS + #ifdef CY_INCLUDE_LOAD_FILE + /* this file declares: + * firmware download block array (cyttsp_fw[]), + * the number of command block records (cyttsp_fw_records), + * and the version variables + */ + #include "cyttsp_fw.h" /* imports cyttsp_fw[] array */ + #define cyttsp_app_load() 1 + #ifdef CY_FORCE_FW_UPDATE + #define cyttsp_force_fw_load() 1 + #else + #define cyttsp_force_fw_load() 0 + #endif + + #else + /* the following declarations are to allow + * some debugging capability + */ + unsigned char cyttsp_fw_tts_verh = 0x00; + unsigned char cyttsp_fw_tts_verl = 0x01; + unsigned char cyttsp_fw_app_idh = 0x02; + unsigned char cyttsp_fw_app_idl = 0x03; + unsigned char cyttsp_fw_app_verh = 0x04; + unsigned char cyttsp_fw_app_verl = 0x05; + unsigned char cyttsp_fw_cid_0 = 0x06; + unsigned char cyttsp_fw_cid_1 = 0x07; + unsigned char cyttsp_fw_cid_2 = 0x08; + #define cyttsp_app_load() 0 + #define cyttsp_force_fw_load() 0 + #endif + #define cyttsp_tts_verh() cyttsp_fw_tts_verh + #define cyttsp_tts_verl() cyttsp_fw_tts_verl + #define cyttsp_app_idh() cyttsp_fw_app_idh + #define cyttsp_app_idl() cyttsp_fw_app_idl + #define cyttsp_app_verh() cyttsp_fw_app_verh + #define cyttsp_app_verl() cyttsp_fw_app_verl + #define cyttsp_cid_0() cyttsp_fw_cid_0 + #define cyttsp_cid_1() cyttsp_fw_cid_1 + #define cyttsp_cid_2() cyttsp_fw_cid_2 + #ifdef CY_USE_TEST_DATA + static struct cyttsp_gen2_xydata_t tt_gen2_testray[] = { + {0x00}, {0x00}, {0x04}, + {0x4000}, {0x8000}, {0x80}, + {0x03}, + {0x2000}, {0x1000}, {0x00}, + {0x00}, + {0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00}, + {0x00} + }; + + static struct cyttsp_gen3_xydata_t tt_gen3_testray[] = { + {0x00}, {0x00}, {0x04}, + {0x4000}, {0x8000}, {0x80}, + {0x12}, + {0x2000}, {0x1000}, {0xA0}, + {0x00}, {0x00}, + {0x8000}, {0x4000}, {0xB0}, + {0x34}, + {0x4000}, {0x1000}, {0xC0}, + {0x00, 0x00, 0x00}, + {0x00}, + {0x00} + }; + #endif /* CY_USE_TEST_DATA */ + +#else + extern u8 g_appload_ray[]; +#endif +#define FW_FNAME_LEN 40 +#define TP_ID_GPIO 85 + + +/* CY TTSP I2C Driver private data */ +struct cyttsp { + struct i2c_client *client; + struct input_dev *input; + struct work_struct work; + struct timer_list timer; + struct mutex mutex; + char phys[32]; + struct cyttsp_platform_data *platform_data; + u8 num_prv_st_tch; + u16 act_trk[CY_NUM_TRK_ID]; + u16 prv_st_tch[CY_NUM_ST_TCH_ID]; + u16 prv_mt_tch[CY_NUM_MT_TCH_ID]; + u16 prv_mt_pos[CY_NUM_TRK_ID][2]; + atomic_t irq_enabled; + bool cyttsp_update_fw; + bool cyttsp_fwloader_mode; + bool is_suspended; + struct regulator **vdd; + char fw_fname[FW_FNAME_LEN]; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif /* CONFIG_HAS_EARLYSUSPEND */ + int tpid; + +}; +extern struct cyttsp cust_ts; +extern void cyttsp_fw_upgrade(void); +extern void cyttsp_hw_reset(void); + + +#endif /* __CYTTSP_H__ */ diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/cyttsp_fw_upgrade.c b/ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/cyttsp_fw_upgrade.c new file mode 100755 index 00000000..ca6e9d10 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/cyttsp_fw_upgrade.c @@ -0,0 +1,993 @@ +/* Source for: + * Cypress TrueTouch(TM) Standard Product I2C touchscreen driver. + * drivers/input/touchscreen/cyttsp-i2c.c + * + * Copyright (C) 2009, 2010 Cypress Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2, and only version 2, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Cypress reserves the right to make changes without further notice + * to the materials described herein. Cypress does not assume any + * liability arising out of the application described herein. + * + * Contact Cypress Semiconductor at www.cypress.com + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif /* CONFIG_HAS_EARLYSUSPEND */ +//#include + +#define CY_DECLARE_GLOBALS + +#include "cyttsp.h" + +#include +#include + +#include + +#define LOG_TP() printk("++++%s, Line %d\n", __FUNCTION__, __LINE__); + + +#define CYTTSP_SUPPORT_READ_TP_VERSION + +#define CYTTSP_SUPPORT_TP_SENSOR +// need upgrade,add MACRO +//#ifdef CONFIG_LCT_AW551_YL +#define CYTTSP_SUPPORT_SYS_NODE +//#endif + +extern struct tpd_device *tpd;//add 2013-1-7 + +int cyttsp_vendor_id=20; +int cyttsp_firmware_version= -1; + +int cyttsp_has_bootloader=0; + +#ifdef CYTTSP_SUPPORT_TP_SENSOR + +#define CYTTSP_DEBUG_TP_SENSOR + +#define CYTTSP_SUPPORT_TP_SENSOR_FIRMWARE_VERSION (0xc) //if we change this value we should also change func apds9900_init_dev in file apds9000.c +static DEFINE_MUTEX(cyttsp_sensor_mutex); +static DECLARE_WAIT_QUEUE_HEAD(cyttsp_sensor_waitqueue); + +//static char cyttsp_sensor_data = 0; // 0 near 1 far +//static int cyttsp_sensor_data_changed = 0; +//static struct i2c_client *tp_sensor_I2Cclient = NULL; +//static int cyttsp_sensor_opened = 0; + + + +#endif + + + +#define CYTTSP_AW551_OFILM "cyttspfw_aw551_ofilm.fw" +#define CYTTSP_AW551_TRULY "cyttspfw_aw551_truly.fw" +#define CYTTSP_AW550_TRULY "cyttspfw_aw550_truly.fw" + +uint32_t cyttsp_tsdebug1 = 0xff; + +module_param_named(tsdebug1, cyttsp_tsdebug1, uint, 0664); + +#define FW_FNAME_LEN 40 +#define TP_ID_GPIO 85 + +//static u8 irq_cnt; /* comparison counter with register valuw */ +//static u32 irq_cnt_total; /* total interrupts */ +//static u32 irq_err_cnt; /* count number of touch interrupts with err */ +#define CY_IRQ_CNT_MASK 0x000000FF /* mapped for sizeof count in reg */ +#define CY_IRQ_CNT_REG 0x00 /* tt_undef[0]=reg 0x1B - Gen3 only */ + + + +/* **************************************************************************** + * Prototypes for static functions + * ************************************************************************** */ + +static int cyttsp_putbl(struct cyttsp *ts, int show, + int show_status, int show_version, int show_cid); +/*static int __devinit cyttsp_probe(struct i2c_client *client, + const struct i2c_device_id *id); */ +//static int __devexit cyttsp_remove(struct i2c_client *client); +//static int cyttsp_resume(struct device *dev); +//static int cyttsp_suspend(struct device *dev); + +#ifdef CYTTSP_SUPPORT_SYS_NODE +//static int cyttsp_power_down(void); +#endif + + + +/* Static variables */ +//static struct cyttsp_gen3_xydata_t g_xy_data; +static struct cyttsp_bootloader_data_t g_bl_data; +static struct cyttsp_sysinfo_data_t g_sysinfo_data; +static const struct i2c_device_id cyttsp_id[] = { + { CY_I2C_NAME, 0 }, { } +}; +static u8 bl_cmd[] = { + CY_BL_FILE0, CY_BL_CMD, CY_BL_EXIT, + CY_BL_KEY0, CY_BL_KEY1, CY_BL_KEY2, + CY_BL_KEY3, CY_BL_KEY4, CY_BL_KEY5, + CY_BL_KEY6, CY_BL_KEY7}; + +MODULE_DEVICE_TABLE(i2c, cyttsp_id); + + + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard touchscreen driver"); +MODULE_AUTHOR("Cypress"); + + + +#ifdef CYTTSP_SUPPORT_TP_SENSOR +#define CYTTSP_SENSOR_IOM 'r' + +#define CYTTSP_SENSOR_IOC_SET_PS_ENABLE _IOW(CYTTSP_SENSOR_IOM, 0, char *) +#define CYTTSP_SENSOR_READ_PS_DATA _IOR(CYTTSP_SENSOR_IOM, 2, char *) + + + + +#endif + + + + + + + + + +static void cyttsp_exit_bl_mode(struct cyttsp *ts); + + + + + +#ifdef CYTTSP_SUPPORT_SYS_NODE +/* firmware flashing block */ +#define BLK_SIZE 16 +#define DATA_REC_LEN 64 +#define START_ADDR 0x0880//0x0b00 +#define BLK_SEED 0xff +#define RECAL_REG 0x1b + +enum bl_commands { + BL_CMD_WRBLK = 0x39, + BL_CMD_INIT = 0x38, + BL_CMD_TERMINATE = 0x3b, +}; +/* TODO: Add key as part of platform data */ +#define KEY_CS (0 + 1 + 2 + 3 + 4 + 5 + 6 + 7) +#define KEY {0, 1, 2, 3, 4, 5, 6, 7} + +static const char _key[] = KEY; +#define KEY_LEN sizeof(_key) + +static int rec_cnt; +struct fw_record { + u8 seed; + u8 cmd; + u8 key[KEY_LEN]; + u8 blk_hi; + u8 blk_lo; + u8 data[DATA_REC_LEN]; + u8 data_cs; + u8 rec_cs; +}; +#define fw_rec_size (sizeof(struct fw_record)) + +struct cmd_record { + u8 reg; + u8 seed; + u8 cmd; + u8 key[KEY_LEN]; +}; +#define cmd_rec_size (sizeof(struct cmd_record)) + +static struct fw_record data_record = { + .seed = BLK_SEED, + .cmd = BL_CMD_WRBLK, + .key = KEY, +}; + +static const struct cmd_record terminate_rec = { + .reg = 0, + .seed = BLK_SEED, + .cmd = BL_CMD_TERMINATE, + .key = KEY, +}; +static const struct cmd_record initiate_rec = { + .reg = 0, + .seed = BLK_SEED, + .cmd = BL_CMD_INIT, + .key = KEY, +}; + +#define BL_REC1_ADDR 0x0780 +#define BL_REC2_ADDR 0x07c0 + +#define ID_INFO_REC ":40078000" +#define ID_INFO_OFFSET_IN_REC 77 + +#define REC_START_CHR ':' +#define REC_LEN_OFFSET 1 +#define REC_ADDR_HI_OFFSET 3 +#define REC_ADDR_LO_OFFSET 5 +#define REC_TYPE_OFFSET 7 +#define REC_DATA_OFFSET 9 +#define REC_LINE_SIZE 141 + +static int cyttsp_soft_reset(struct cyttsp *ts) +{ + int retval = 0, tries = 0; + u8 host_reg = CY_SOFT_RESET_MODE; + + #if 0 + gpio_set_value(ts->platform_data->resout_gpio, 1); //reset high valid + msleep(100); + gpio_set_value(ts->platform_data->resout_gpio, 0); + msleep(1000); + #endif + LOG_TP(); + + #if 1// 0 modify 2013-1-7!!!!!!!!!!! + do { + retval = i2c_smbus_write_i2c_block_data(ts->client, + CY_REG_BASE, sizeof(host_reg), &host_reg); + if (retval < 0) + msleep(20); + } while (tries++ < 10 && (retval < 0)); + + if (retval < 0) { + pr_err("%s: failed\n", __func__); + return retval; + } + #else + cyttsp_hw_reset(); //!!!! 2013-1-7 may not go here !!! + #endif + + LOG_TP(); + tries = 0; + do { + msleep(20); + cyttsp_putbl(ts, 1, true, true, false); + } while (g_bl_data.bl_status != 0x10 && + g_bl_data.bl_status != 0x11 && + tries++ < 100); + LOG_TP(); + if (g_bl_data.bl_status != 0x11 && g_bl_data.bl_status != 0x10) + return -EINVAL; + LOG_TP(); + return 0; +} + +static void cyttsp_exit_bl_mode(struct cyttsp *ts) +{ + int retval, tries = 0; + + do { + retval = i2c_smbus_write_i2c_block_data(ts->client, + CY_REG_BASE, sizeof(bl_cmd), bl_cmd); + if (retval < 0) + msleep(20); + } while (tries++ < 10 && (retval < 0)); +} + +static void cyttsp_set_sysinfo_mode(struct cyttsp *ts) +{ + int retval, tries = 0; + u8 host_reg = CY_SYSINFO_MODE; + + do { + retval = i2c_smbus_write_i2c_block_data(ts->client, + CY_REG_BASE, sizeof(host_reg), &host_reg); + if (retval < 0) + msleep(20); + } while (tries++ < 10 && (retval < 0)); + + /* wait for TTSP Device to complete switch to SysInfo mode */ + if (!(retval < 0)) { + retval = i2c_smbus_read_i2c_block_data(ts->client, + CY_REG_BASE, + sizeof(struct cyttsp_sysinfo_data_t), + (u8 *)&g_sysinfo_data); + } else + pr_err("%s: failed\n", __func__); +} + +static void cyttsp_set_opmode(struct cyttsp *ts) +{ + int retval, tries = 0; + u8 host_reg = CY_OP_MODE; + + do { + retval = i2c_smbus_write_i2c_block_data(ts->client, + CY_REG_BASE, sizeof(host_reg), &host_reg); + if (retval < 0) + msleep(20); + } while (tries++ < 10 && (retval < 0)); +} + +static int str2uc(char *str, u8 *val) +{ + char substr[3]; + unsigned long ulval; + int rc; + + if (!str && strlen(str) < 2) + return -EINVAL; + + substr[0] = str[0]; + substr[1] = str[1]; + substr[2] = '\0'; + + rc = strict_strtoul(substr, 16, &ulval); + if (rc != 0) + return rc; + + *val = (u8) ulval; + + return 0; +} + +static int flash_block(struct cyttsp *ts, u8 *blk, int len) +{ + int retval, i, tries = 0; + char buf[(2 * (BLK_SIZE + 1)) + 1]; + char *p = buf; + + for (i = 0; i < len; i++, p += 2) + sprintf(p, "%02x", blk[i]); + pr_debug("%s: size %d, pos %ld payload %s\n", + __func__, len, (long)0, buf); + + do { + retval = i2c_smbus_write_i2c_block_data(ts->client, + CY_REG_BASE, len, blk); + if (retval < 0) + msleep(20); + } while (tries++ < 20 && (retval < 0)); + + if (retval < 0) { + pr_err("%s: failed\n", __func__); + return retval; + } + + return 0; +} + +static int flash_command(struct cyttsp *ts, const struct cmd_record *record) +{ + return flash_block(ts, (u8 *)record, cmd_rec_size); +} + +static void init_data_record(struct fw_record *rec, unsigned short addr) +{ + addr >>= 6; + rec->blk_hi = (addr >> 8) & 0xff; + rec->blk_lo = addr & 0xff; + rec->rec_cs = rec->blk_hi + rec->blk_lo + + (unsigned char)(BLK_SEED + BL_CMD_WRBLK + KEY_CS); + rec->data_cs = 0; +} + +static int check_record(u8 *rec) +{ + int rc; + u16 addr; + u8 r_len, type, hi_off, lo_off; + + rc = str2uc(rec + REC_LEN_OFFSET, &r_len); + if (rc < 0) + return rc; + + rc = str2uc(rec + REC_TYPE_OFFSET, &type); + if (rc < 0) + return rc; + + if (*rec != REC_START_CHR || r_len != DATA_REC_LEN || type != 0) + return -EINVAL; + + rc = str2uc(rec + REC_ADDR_HI_OFFSET, &hi_off); + if (rc < 0) + return rc; + + rc = str2uc(rec + REC_ADDR_LO_OFFSET, &lo_off); + if (rc < 0) + return rc; + + addr = (hi_off << 8) | lo_off; + + if (addr >= START_ADDR || addr == BL_REC1_ADDR || addr == BL_REC2_ADDR) + return 0; + + return -EINVAL; +} + +static struct fw_record *prepare_record(u8 *rec) +{ + int i, rc; + u16 addr; + u8 hi_off, lo_off; + u8 *p; + + rc = str2uc(rec + REC_ADDR_HI_OFFSET, &hi_off); + if (rc < 0) + return ERR_PTR((long) rc); + + rc = str2uc(rec + REC_ADDR_LO_OFFSET, &lo_off); + if (rc < 0) + return ERR_PTR((long) rc); + + addr = (hi_off << 8) | lo_off; + + init_data_record(&data_record, addr); + p = rec + REC_DATA_OFFSET; + for (i = 0; i < DATA_REC_LEN; i++) { + rc = str2uc(p, &data_record.data[i]); + if (rc < 0) + return ERR_PTR((long) rc); + data_record.data_cs += data_record.data[i]; + data_record.rec_cs += data_record.data[i]; + p += 2; + } + data_record.rec_cs += data_record.data_cs; + + return &data_record; +} + +static int flash_record(struct cyttsp *ts, const struct fw_record *record) +{ + int len = fw_rec_size; + int blk_len, rc; + u8 *rec = (u8 *)record; + u8 data[BLK_SIZE + 1]; + u8 blk_offset; + + for (blk_offset = 0; len; len -= blk_len) { + data[0] = blk_offset; + blk_len = len > BLK_SIZE ? BLK_SIZE : len; + memcpy(data + 1, rec, blk_len); + rec += blk_len; + rc = flash_block(ts, data, blk_len + 1); + if (rc < 0) + return rc; + blk_offset += blk_len; + } + return 0; +} + +static int flash_data_rec(struct cyttsp *ts, u8 *buf) +{ + struct fw_record *rec; + int rc, tries; +LOG_TP(); + if (!buf) + return -EINVAL; + + rc = check_record(buf); + + if (rc < 0) { + pr_debug("%s: record ignored %s", __func__, buf); + return 0; + } + + rec = prepare_record(buf); + if (IS_ERR_OR_NULL(rec)) + return PTR_ERR(rec); + + rc = flash_record(ts, rec); + if (rc < 0) + return rc; + + tries = 0; + do { +//printk("++++%s, Line %d, tries=%d\n", __FUNCTION__, __LINE__,tries ); //wujinyou + + //if (rec_cnt%2) + //msleep(20); + if(tries >50) + { + printk("++++%s, Line %d, tries=%d\n", __FUNCTION__, __LINE__,tries ); //wujinyou + msleep(20); + } + cyttsp_putbl(ts, 4, true, false, false); + } while (g_bl_data.bl_status != 0x10 && + g_bl_data.bl_status != 0x11 && + tries++ < 100); + rec_cnt++; + return rc; +} + +static int cyttspfw_flash_firmware(struct cyttsp *ts, const u8 *data, + int data_len) +{ + u8 *buf; + int i, j; + int rc, tries = 0; + LOG_TP(); + + /* initiate bootload: this will erase all the existing data */ + rc = flash_command(ts, &initiate_rec); + if (rc < 0) + return rc; + + do { +// LOG_TP(); +printk("++++%s, Line %d, tries=%d\n", __FUNCTION__, __LINE__,tries ); + msleep(60); + cyttsp_putbl(ts, 4, true, false, false); + } while (g_bl_data.bl_status != 0x10 && + g_bl_data.bl_status != 0x11 && + tries++ < 100); + + buf = kzalloc(REC_LINE_SIZE + 1, GFP_KERNEL); + if (!buf) { + pr_err("%s: no memory\n", __func__); + return -ENOMEM; + } + LOG_TP(); + rec_cnt = 0; + /* flash data records */ + for (i = 0, j = 0; i < data_len; i++, j++) { + if ((data[i] == REC_START_CHR) && j) { + buf[j] = 0; + rc = flash_data_rec(ts, buf); + if (rc < 0) + return rc; + j = 0; + } + buf[j] = data[i]; + } + LOG_TP(); + /* flash last data record */ + if (j) { + buf[j] = 0; + rc = flash_data_rec(ts, buf); + if (rc < 0) + return rc; + } + LOG_TP(); + kfree(buf); + + /* termiate bootload */ + tries = 0; + rc = flash_command(ts, &terminate_rec); + do { + msleep(100); +printk("++++%s, Line %d, tries=%d\n", __FUNCTION__, __LINE__,tries ); + + cyttsp_putbl(ts, 4, true, false, false); + } while (g_bl_data.bl_status != 0x10 && + g_bl_data.bl_status != 0x11 && + tries++ < 100); + LOG_TP(); + return rc; +} + +static int get_hex_fw_ver(u8 *p, u8 *ttspver_hi, u8 *ttspver_lo, + u8 *appid_hi, u8 *appid_lo, u8 *appver_hi, + u8 *appver_lo, u8 *cid_0, u8 *cid_1, u8 *cid_2) +{ + int rc; + + p = p + ID_INFO_OFFSET_IN_REC; + rc = str2uc(p, ttspver_hi); + if (rc < 0) + return rc; + p += 2; + rc = str2uc(p, ttspver_lo); + if (rc < 0) + return rc; + p += 2; + rc = str2uc(p, appid_hi); + if (rc < 0) + return rc; + p += 2; + rc = str2uc(p, appid_lo); + if (rc < 0) + return rc; + p += 2; + rc = str2uc(p, appver_hi); + if (rc < 0) + return rc; + p += 2; + rc = str2uc(p, appver_lo); + if (rc < 0) + return rc; + p += 2; + rc = str2uc(p, cid_0); + if (rc < 0) + return rc; + p += 2; + rc = str2uc(p, cid_1); + if (rc < 0) + return rc; + p += 2; + rc = str2uc(p, cid_2); + if (rc < 0) + return rc; + + return 0; +} + +static void cyttspfw_flash_start(struct cyttsp *ts, const u8 *data, + int data_len, u8 *buf, bool force) +{ + int rc; + u8 ttspver_hi = 0, ttspver_lo = 0, fw_upgrade = 0; + u8 appid_hi = 0, appid_lo = 0; + u8 appver_hi = 0, appver_lo = 0; + u8 cid_0 = 0, cid_1 = 0, cid_2 = 0; + char *p = buf; + + /* get hex firmware version */ + rc = get_hex_fw_ver(p, &ttspver_hi, &ttspver_lo, + &appid_hi, &appid_lo, &appver_hi, + &appver_lo, &cid_0, &cid_1, &cid_2); +printk("++++tpd-fw-ver: %x %x %x %x %x %x %x %x %x\n", ttspver_hi, ttspver_lo, appid_hi, appid_lo, appver_hi,appver_lo, cid_0, cid_1,cid_2); + if (rc < 0) { + pr_err("%s: unable to get hex firmware version\n", __func__); + return; + } +#if 0 //wujinyou + /* disable interrupts before flashing */ + if (ts->client->irq == 0) + del_timer(&ts->timer); + else + disable_irq(ts->client->irq); + + rc = cancel_work_sync(&ts->work); + + if (rc && ts->client->irq) + enable_irq(ts->client->irq); +#endif + + /* enter bootloader idle mode */ + rc = cyttsp_soft_reset(ts); + //LOG_TP(); + printk("++++%s, Line %d, rc=%d\n", __FUNCTION__, __LINE__,rc); + + if (rc < 0) { + LOG_TP(); + pr_err("%s: cyttsp_soft_reset try entering into idle mode" + " second time\n", __func__); + msleep(1000); + + rc = cyttsp_soft_reset(ts); + } + + if (rc < 0) { + LOG_TP(); + pr_err("%s:cyttsp_soft_reset try again later\n", __func__); + return; + } + + LOG_TP(); + + pr_info("Current firmware:lusongbai %d.%d.%d", g_bl_data.appid_lo, + g_bl_data.appver_hi, g_bl_data.appver_lo); + pr_info("New firmware: %d.%d.%d", appid_lo, appver_hi, appver_lo); + LOG_TP(); + + if (force) + fw_upgrade = 1; + else + if ((appid_hi == g_bl_data.appid_hi) && + (appid_lo == g_bl_data.appid_lo)) { + if (appver_hi > g_bl_data.appver_hi) { + fw_upgrade = 1; + } else if ((appver_hi == g_bl_data.appver_hi) && + (appver_lo > g_bl_data.appver_lo)) { + fw_upgrade = 1; + } else { + fw_upgrade = 0; + pr_info("%s: Firmware version " + "lesser/equal to existing firmware, " + "upgrade not needed\n", __func__); + } + } else { + fw_upgrade = 0; + pr_info("%s: Firware versions do not match, " + "cannot upgrade\n", __func__); + } + + printk("++++%s, Line %d, fw_upgrade=%d\n", __FUNCTION__, __LINE__,fw_upgrade); + + if (fw_upgrade) { + pr_info("%s: Starting firmware upgrade\n", __func__); + rc = cyttspfw_flash_firmware(ts, data, data_len); + if (rc < 0) + pr_err("%s: firmware upgrade failed\n", __func__); + else + pr_info("%s: lusongbai firmware upgrade success\n", __func__); + } + LOG_TP(); + + /* enter bootloader idle mode */ + cyttsp_soft_reset(ts); + LOG_TP(); + + /* exit bootloader mode */ + cyttsp_exit_bl_mode(ts); + LOG_TP(); + + msleep(100); + /* set sysinfo details */ + cyttsp_set_sysinfo_mode(ts); + LOG_TP(); + + /* enter application mode */ + cyttsp_set_opmode(ts); + LOG_TP(); + + if((fw_upgrade == 1) && (rc >= 0)) + { + u8 tmpData[18] = {0}; + rc = i2c_smbus_read_i2c_block_data(ts->client,CY_REG_BASE,18, tmpData); + if(rc < 0) + { + printk(KERN_ERR"cyttspfw_flash_start read version and module error\n"); + } + else + { + cyttsp_vendor_id=tmpData[16]; + cyttsp_firmware_version = tmpData[17]; + printk(KERN_ERR"cyttspfw_flash_start tp module is:%x firmware version is %x:\n",tmpData[16],tmpData[17]); + } + } + LOG_TP(); + + /* enable interrupts */ +#if 0 + if (ts->client->irq == 0) + mod_timer(&ts->timer, jiffies + TOUCHSCREEN_TIMEOUT); + else + enable_irq(ts->client->irq); +#endif + LOG_TP(); + +} + +static void cyttspfw_upgrade_start(struct cyttsp *ts, const u8 *data, + int data_len, bool force) +{ + int i, j; + u8 *buf; + + buf = kzalloc(REC_LINE_SIZE + 1, GFP_KERNEL); + if (!buf) { + pr_err("%s: no memory\n", __func__); + return; + } + + for (i = 0, j = 0; i < data_len; i++, j++) { + if ((data[i] == REC_START_CHR) && j) { + buf[j] = 0; + j = 0; + if (!strncmp(buf, ID_INFO_REC, strlen(ID_INFO_REC))) { + cyttspfw_flash_start(ts, data, data_len, + buf, force); + break; + } + } + buf[j] = data[i]; + } + + /* check in the last record of firmware */ + if (j) { + buf[j] = 0; + if (!strncmp(buf, ID_INFO_REC, strlen(ID_INFO_REC))) { + cyttspfw_flash_start(ts, data, data_len, + buf, force); + } + } + + kfree(buf); +} +static bool cyttsp_IsTpInBootloader(struct cyttsp *ts) +{ + int retval = -1; + u8 tmpData[18] = {0}; + retval = i2c_smbus_read_i2c_block_data(ts->client,CY_REG_BASE,18, tmpData); + if(retval < 0) + { + printk(KERN_ERR"cyttsp_IsTpInBootloader read version and module error\n"); + return false; + } + else + { + retval = 0; + retval = ((tmpData[1] & 0x10) >> 4); + + printk(KERN_ERR"cyttsp_IsTpInBootloader tmpData[1]:%x retval:%x\n",tmpData[1],retval); + } + if(retval == 0) + { + return false; + } + return true; + +} + +const u8 fw_hex_of[] = { +// #include "BOOT_AG500_OF_DW_2802_V2_20120702.i" +// #include "BOOT_AG500_OF_DW_2803_V3_20120711.i" +}; +const u8 fw_hex_hhx[] = { +// #include "BOOT_AG500_F5_HHX_2503_V3_20120711.i" +}; +struct cyttsp cust_ts; +const u8* fw_hex = fw_hex_hhx; +extern void cyttsp_print_reg(struct i2c_client *client); + +int read_vender_id(void) +{ + char buffer[32]; + int ret =0; + + ret = i2c_smbus_read_i2c_block_data(cust_ts.client, 0x00, 24, &(buffer[0])); + if(ret<0) + { + return -1; + } + cyttsp_vendor_id = buffer[3]; + printk("++++cyttp read_vender_id=0x%x\n", cyttsp_vendor_id); + cyttsp_print_reg(cust_ts.client); + return 0; +} + + +void cyttsp_fw_upgrade(void) +{ + struct cyttsp *ts = &cust_ts; + bool force = 1; + /* check and start upgrade */ + //if upgrade failed we should force upgrage when next power up + + if(read_vender_id() != 0) + { + printk("++++cyttspfw_upgrade read vender id failed!\n"); + return; + } + switch(cyttsp_vendor_id) + { + case 0x28: + fw_hex = fw_hex_of; + break; + case 0x25: + fw_hex = fw_hex_hhx; + break; + case 0x0: + break; + default: + break; + } + + if(cyttsp_IsTpInBootloader(ts) == true) + { + LOG_TP(); + printk(KERN_ERR"cyttspfw_upgrade we should force upgrade tp fw\n"); + cyttspfw_upgrade_start(ts, fw_hex, + sizeof(fw_hex_of), true); + } + else + { + LOG_TP(); + cyttspfw_upgrade_start(ts, fw_hex, + sizeof(fw_hex_of), force); + } +} + +#endif + + + +static int cyttsp_putbl(struct cyttsp *ts, int show, + int show_status, int show_version, int show_cid) +{ + int retval = CY_OK; + + int num_bytes = (show_status * 3) + (show_version * 6) + (show_cid * 3); + + if (show_cid) + num_bytes = sizeof(struct cyttsp_bootloader_data_t); + else if (show_version) + num_bytes = sizeof(struct cyttsp_bootloader_data_t) - 3; + else + num_bytes = sizeof(struct cyttsp_bootloader_data_t) - 9; + LOG_TP(); + + if (show) { + retval = i2c_smbus_read_i2c_block_data(ts->client, + CY_REG_BASE, num_bytes, (u8 *)&g_bl_data); + + { + int i = 0; + printk("cyttsp_putbl:"); + for(i=0; iclient, + CY_REG_BASE, sizeof(bl_cmd), bl_cmd); + if (retval < 0) + msleep(20); + } while (tries++ < 10 && (retval < 0)); +} +#endif + + + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/debug.txt b/ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/debug.txt new file mode 100755 index 00000000..a424c186 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/debug.txt @@ -0,0 +1,3 @@ +/ # wmtenv get wmt.io.touch +1:cyp140:7:600:1024:4:0:1:-1:5 //it seems ok + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/wmt_ts.c b/ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/wmt_ts.c new file mode 100755 index 00000000..d7234ac3 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/wmt_ts.c @@ -0,0 +1,1094 @@ +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "wmt_ts.h" +//#include "zet6221_ts.h" + +///////////////////////////////////////////////////////////////// + +// commands for ui +#define TS_IOC_MAGIC 't' + +#define TS_IOCTL_CAL_START _IO(TS_IOC_MAGIC, 1) +#define TS_IOCTL_CAL_DONE _IOW(TS_IOC_MAGIC, 2, int*) +#define TS_IOCTL_GET_RAWDATA _IOR(TS_IOC_MAGIC, 3, int*) +#define TS_IOCTL_CAL_QUIT _IOW(TS_IOC_MAGIC, 4, int*) +#define TS_IOCTL_AUTO_CALIBRATION _IOW(TS_IOC_MAGIC, 5, int*) +#define TS_IOC_MAXNR 5 + +#define TP_INFOR_ARRAY_SIZE (sizeof(l_tpinfor)/sizeof(l_tpinfor[1])) +// +#define TS_MAJOR 11 +#define TS_DRIVER_NAME "wmtts_touch" +#define TS_NAME "wmtts" +#define WMTTS_PROC_NAME "wmtts_config" + +#define EXT_GPIO0 0 +#define EXT_GPIO1 1 +#define EXT_GPIO2 2 +#define EXT_GPIO3 3 +#define EXT_GPIO4 4 +#define EXT_GPIO5 5 +#define EXT_GPIO6 6 +#define EXT_GPIO7 7 + +typedef struct { + int a1; + int b1; + int c1; + int a2; + int b2; + int c2; + int delta; +}CALIBRATION_PARAMETER, *PCALIBRATION_PARAMETER; + + +static int irq_gpio = 7;//!!!2012-12-28 +static int rst_gpio = 4;// +static int panelres_x; +static int panelres_y; +static DECLARE_WAIT_QUEUE_HEAD(queue); +static CALIBRATION_PARAMETER g_CalcParam; +static TS_EVENT g_evLast; +static struct mutex cal_mutex; +static DECLARE_WAIT_QUEUE_HEAD(ts_penup_wait_queue); +static int lcd_exchg = 0; + +static struct class* l_dev_class = NULL; +static struct device *l_clsdevice = NULL; +extern struct wmtts_device cyp140_tsdev; +static struct wmtts_device* l_tsdev = &cyp140_tsdev; +struct proc_dir_entry* l_tsproc = NULL; +static struct i2c_client *l_client=NULL; +static int l_penup = 1; // 1-pen up,0-pen down + +struct tp_infor +{ + //enum tp_type type; + char name[64]; + //unsigned int i2caddr; + unsigned int xaxis; //0: x,1: x swap with y + unsigned int xdir; // 1: positive,-1: revert + unsigned int ydir; // 1: positive,-1: revert + unsigned int max_finger_num; +}; + +static int l_tpindex = -1; +static struct tp_infor l_tpinfor[1]; + +///////////////////////////////////////////////////// +// function declare +///////////////////////////////////////////////////// +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); +extern int wmt_setsyspara(char *varname, unsigned char *varval); +static int ts_writeproc( struct file *file, + const char *buffer, + unsigned long count, + void *data ); +static int ts_readproc(char *page, char **start, off_t off, + int count, int *eof, void *data); +/////////////////////////////////////////////////////////////////////// +void TouchPanelCalibrateAPoint( + int UncalX, //@PARM The uncalibrated X coordinate + int UncalY, //@PARM The uncalibrated Y coordinate + int *pCalX, //@PARM The calibrated X coordinate + int *pCalY //@PARM The calibrated Y coordinate + ) +{ + int x, y; + mutex_lock(&cal_mutex); + x = (g_CalcParam.a1 * UncalX + g_CalcParam.b1 * UncalY + + g_CalcParam.c1) / g_CalcParam.delta; + y = (g_CalcParam.a2 * UncalX + g_CalcParam.b2 * UncalY + + g_CalcParam.c2) / g_CalcParam.delta; + +//klog("afer(%d,%d)(%d,%d)\n", x,y,panelres_x,panelres_y); + if ( x < 0 ) + x = 0; + + if ( y < 0 ) + y = 0; + if (x >= panelres_x) + x = panelres_x-1; + if (y >= panelres_y) + y = panelres_y-1; + + *pCalX = x; + *pCalY = y; + mutex_unlock(&cal_mutex); + return; +} + +int wmt_ts_if_updatefw(void) +{ + /*if ((!strcmp(l_tpinfor[l_tpindex].name,"ZET6221_7dgntpc0350")) || + (!strcmp(l_tpinfor[l_tpindex].name,"ZET6221_7zcc1950")) || + (!strcmp(l_tpinfor[l_tpindex].name,"ZET6221_8dgntpc0406")) || + (!strcmp(l_tpinfor[l_tpindex].name,"ZET6221_7adc700148")) || + (!strcmp(l_tpinfor[l_tpindex].name,"ZET6221_8xdc806")) || + (!strcmp(l_tpinfor[l_tpindex].name,"ZET6221_7tp070005q8")) || + (!strcmp(l_tpinfor[l_tpindex].name,"ZET6221_7yiheng7002")) || + (!strcmp(l_tpinfor[l_tpindex].name,"ZET6221_7atc7031"))|| + (!strcmp(l_tpinfor[l_tpindex].name,"ZET6221_7xclg7027a")) || + (!strcmp(l_tpinfor[l_tpindex].name,"ZET6221_7est07000416"))) + { + return 1; + } + + return 0; + */ + + struct file *fp; + char filepath[128]; + + sprintf(filepath,"/lib/firmware/%s_fw.ts",l_tpinfor[l_tpindex].name); + + fp = filp_open(filepath, O_RDONLY, 0); + if (IS_ERR(fp)) + { + //printk("create file error\n"); + return 0; + } + filp_close(fp, NULL); + return 1; +} + +unsigned int wmt_ts_get_xaxis(void) +{ + return l_tpinfor[l_tpindex].xaxis; +} + +unsigned int wmt_ts_get_xdir(void) +{ + return l_tpinfor[l_tpindex].xdir; +} + +unsigned int wmt_ts_get_ydir(void) +{ + return l_tpinfor[l_tpindex].ydir; +} + +unsigned int wmt_ts_get_maxfingernum(void) +{ + return l_tpinfor[l_tpindex].max_finger_num; +} + +#if 0 +static int parse_firmwarefile(char* filedata, unsigned char** firmarr, int maxlen) +{ + char endflag[]="/* End flag */"; + char* p = filedata; + int i = 0; + int j = 0; + char* s = NULL; + + s = p; + // calculate the number of array + while (strncmp(p,endflag,strlen(endflag))) + { + if (!strncmp(p,"0x",strlen("0x"))) + { + i++; + } + p++; + }; + dbg("the number of arry:0x%x\n", i); + // alloc the memory for array + j = i + i%4; + *firmarr = kzalloc(sizeof(unsigned char)*j, GFP_KERNEL); + // parse the value of array + p = s; + j = 0; + while (strncmp(p,endflag,strlen(endflag))) + { + if (!strncmp(p,"0x",strlen("0x"))) + { + //dbg("find 0x!\n"); + sscanf(p,"0x%x", &((*firmarr)[j])); + //dbg("arry[0x%x]:%x\n",j,(*firmarr)[j]); + j++; + p+=4; + } else { + p++; + } + //p = strchr(p,'}'); + if (j>=i-2) + { + dbg("%s",p); + } + + }; + if (i != j) + { + errlog("Error parsing file(the number of arry not match)!\n"); + return -1; + }; + dbg("paring firmware file end.\n"); + return i; +} + +//filepath:the path of firmware file; +//firmdata:store the data from firmware file; +//return:0-successful,negative-parsing error. +int read_firmwarefile(char* filepath, unsigned char** firmdata) +{ + struct file *fp; + mm_segment_t fs; + loff_t pos; + char* data = NULL; + long fsize; + int alloclen = 2052*(8*5+2)+200; + int i = 0; + + klog("ts firmware file:%s\n",filepath); + data = kzalloc(alloclen, GFP_KERNEL); + if (data == NULL) + { + errlog("Error when alloc memory for firmware file!\n"); + return -1; + } + fp = filp_open(filepath, O_RDONLY, 0); + if (IS_ERR(fp)) { + printk("create file error\n"); + goto error_flip_open; + } + fs = get_fs(); + set_fs(KERNEL_DS); + pos = 0; + fsize = vfs_read(fp, data, alloclen, &pos); + dbg("filesize:0x%x,alloclen:0x%x\n",fsize,alloclen); + if (fsize <= 0) + { + errlog("alloc size is too small.\n"); + goto error_vfs_read; + } + i = parse_firmwarefile(data,firmdata,fsize); + // Check the parsing and ori file + /* for (i=0;i < maxlen; i++) + { + if (firmdata[i]!=nvctp_BinaryFile_default[i]) + { + errlog("Don't match:i=%x,parse:0x%x,ori:0x%x\n",i,firmdata[i], nvctp_BinaryFile_default[i]); + break; + } + }; + dbg("parsing match with ori.\n"); + */ + filp_close(fp, NULL); + set_fs(fs); + kfree(data); + dbg("success to read firmware file!\n");; + + //sscanf(data,"%hd %hd %hd",&offset.u.x,&offset.u.y,&offset.u.z); + return i; +error_vfs_read: + filp_close(fp, NULL); + set_fs(fs); +error_flip_open: + kfree(data); + return -1; +} +#endif + +void wmt_ts_get_firmwname(char* firmname) +{ + sprintf(firmname,"/lib/firmware/%s_fw.ts",l_tpinfor[l_tpindex].name); +} + + int wmt_ts_get_irqgpnum(void) +{ + return irq_gpio; +} + +int wmt_ts_get_resetgpnum(void) +{ + return rst_gpio; +} + + int wmt_ts_get_lcdexchg(void) +{ + return lcd_exchg; +} + +int wmt_ts_get_resolvX(void) +{ + return panelres_x; +} + +int wmt_ts_get_resolvY(void) +{ + return panelres_y; +} + +//up:1-pen up,0-pen down +void wmt_ts_set_penup(int up) +{ + l_penup = up; +} + +// +int wmt_ts_wait_penup(void) +{ + int ret = wait_event_interruptible( + ts_penup_wait_queue, + (1==l_penup)); + return ret; +} + +// return:1-pen up,0-pen dwon +int wmt_ts_ispenup(void) +{ + return l_penup; +} + + +void wmt_ts_wakeup_penup(void) +{ + wake_up(&ts_penup_wait_queue); +} + +int wmt_is_tsirq_enable(void) +{ + int val = 0; + int num = irq_gpio; + + if(num > 11) + return 0; + + if(num<4) + val = REG32_VAL(__GPIO_BASE+0x0300) & (1<<(num*8+7)); + else if(num >= 4 && num < 8) + val = REG32_VAL(__GPIO_BASE+0x0304) & (1<<((num-4)*8+7)); + else + val = REG32_VAL(__GPIO_BASE+0x0308) & (1<<((num-8)*8+7)); + + return val?1:0; + +} + +int wmt_is_tsint(void) +{ + int num = irq_gpio; + + if (num > 11) + { + return 0; + } + return (REG32_VAL(__GPIO_BASE+0x0360) & (1< 11) + { + return; + } + REG32_VAL(__GPIO_BASE+0x0360) = 1<11) + return -1; + //if (num > 9) + //GPIO_PIN_SHARING_SEL_4BYTE_VAL &= ~BIT4; // gpio10,11 as gpio + REG32_VAL(__GPIO_BASE+0x0040) &= ~(1<= 4 && num < 8){//[4,7] + shift = num-4; + offset = 0x0304; + }else{// [8,11] + shift = num-8; + offset = 0x0308; + } + + reg = REG32_VAL(__GPIO_BASE + offset); + + switch(type){ + case IRQ_TYPE_LEVEL_LOW: + reg &= ~(1<<(shift*8+2)); + reg &= ~(1<<(shift*8+1)); + reg &= ~(1<<(shift*8)); + break; + case IRQ_TYPE_LEVEL_HIGH: + reg &= ~(1<<(shift*8+2)); + reg &= ~(1<<(shift*8+1)); + reg |= (1<<(shift*8)); + break; + case IRQ_TYPE_EDGE_FALLING: + reg &= ~(1<<(shift*8+2)); + reg |= (1<<(shift*8+1)); + reg &= ~(1<<(shift*8)); + break; + case IRQ_TYPE_EDGE_RISING: + reg &= ~(1<<(shift*8+2)); + reg |= (1<<(shift*8+1)); + reg |= (1<<(shift*8)); + break; + default://both edge + reg |= (1<<(shift*8+2)); + reg &= ~(1<<(shift*8+1)); + reg &= ~(1<<(shift*8)); + break; + + } + //reg |= 1<<(shift*8+7);//enable interrupt + reg &= ~(1<<(shift*8+7)); //disable int + + REG32_VAL(__GPIO_BASE + offset) = reg; + REG32_VAL(__GPIO_BASE+0x0360) = 1< 11) + return -1; + + if(num<4) + REG32_VAL(__GPIO_BASE+0x0300) |= 1<<(num*8+7); //enable interrupt + else if(num >= 4 && num < 8) + REG32_VAL(__GPIO_BASE+0x0304) |= 1<<((num-4)*8+7); //enable interrupt + else + REG32_VAL(__GPIO_BASE+0x0308) |= 1<<((num-8)*8+7); //enable interrupt + + return 0; +} + +int wmt_disable_gpirq(void) +{ + int num = irq_gpio; + + if(num > 11) + return -1; + + if(num<4) + REG32_VAL(__GPIO_BASE+0x0300) &= ~(1<<(num*8+7)); //enable interrupt + else if(num >= 4 && num < 8) + REG32_VAL(__GPIO_BASE+0x0304) &= ~(1<<((num-4)*8+7)); //enable interrupt + else + REG32_VAL(__GPIO_BASE+0x0308) &= ~(1<<((num-8)*8+7)); //enable interrupt + + return 0; +} + + +int wmt_get_tsirqnum(void) +{ + return IRQ_GPIO; +} + + +int wmt_ts_set_rawcoord(unsigned short x, unsigned short y) +{ + g_evLast.x = x; + g_evLast.y = y; + //dbg("raw(%d,%d)*\n", x, y); + return 0; +} + +static void wmt_ts_platform_release(struct device *device) +{ + return; +} + +static struct platform_device wmt_ts_plt_device = { + .name = TS_DRIVER_NAME, + .id = 0, + .dev = { + .release = wmt_ts_platform_release, + }, +// .num_resources = ARRAY_SIZE(wm9715_ts_resources), +// .resource = wm9715_ts_resources, +}; + +static int wmt_ts_suspend(struct platform_device *pdev, pm_message_t state) +{ + dbg("ts suspend....\n"); + return l_tsdev->suspend(pdev, state); +} +static int wmt_ts_resume(struct platform_device *pdev) +{ + dbg("ts resume....\n"); + return l_tsdev->resume(pdev); +} + +static int wmt_ts_probe(struct platform_device *pdev) +{ + l_tsproc= create_proc_entry(WMTTS_PROC_NAME, 0666, NULL/*&proc_root*/); + if (l_tsproc != NULL) + { + l_tsproc->read_proc = ts_readproc; + l_tsproc->write_proc = ts_writeproc; + } + + if (l_tsdev->probe != NULL) + return l_tsdev->probe(pdev); + else + return 0; +} + +static int wmt_ts_remove(struct platform_device *pdev) +{ + if (l_tsproc != NULL) + { + remove_proc_entry(WMTTS_PROC_NAME, NULL); + l_tsproc = NULL; + } + + if (l_tsdev->remove != NULL) + return l_tsdev->remove(pdev); + else + return 0; +} + +static struct platform_driver wmt_ts_plt_driver = { + .driver = { + .name = TS_DRIVER_NAME, + .owner = THIS_MODULE, + }, + .probe = wmt_ts_probe, + .remove = wmt_ts_remove, + .suspend = wmt_ts_suspend, + .resume = wmt_ts_resume, +}; + +static int wmt_ts_open(struct inode *inode, struct file *filp) +{ + int ret = 0; + + klog("wmt ts driver opening...\n"); + + //ts_clear(); + //try_module_get(THIS_MODULE); + + return ret; +} + +static int wmt_ts_close(struct inode *inode, struct file *filp) +{ + klog("wmt ts driver closing...\n"); + //ts_clear(); + //module_put(THIS_MODULE); + + return 0; +} + +static unsigned int wmt_ts_poll(struct file *filp, struct poll_table_struct *wait) +{ +#if 0 + poll_wait(filp, &queue, wait); + if ( head != tail ) + return (POLLIN | POLLRDNORM); +#endif + return 0; +} + +static long wmt_ts_ioctl(/*struct inode * node,*/ struct file *dev, unsigned int cmd, unsigned long arg) +{ + int nBuff[7]; + char env_val[96]={0}; + //dbg("wmt_ts_ioctl(node=0x%p, dev=0x%p, cmd=0x%08x, arg=0x%08lx)\n", node, dev, cmd, arg); + + if (_IOC_TYPE(cmd) != TS_IOC_MAGIC){ + dbg("CMD ERROR!"); + return -ENOTTY; + } + + if (_IOC_NR(cmd) > TS_IOC_MAXNR){ + dbg("NO SUCH IO CMD!\n"); + return -ENOTTY; + } + + switch (cmd) { + + case TS_IOCTL_CAL_DONE: + klog("wmt_ts_ioctl: TS_IOCTL_CAL_DONE\n"); + copy_from_user(nBuff, (unsigned int*)arg, 7*sizeof(int)); + + mutex_lock(&cal_mutex); + g_CalcParam.a1 = nBuff[0]; + g_CalcParam.b1 = nBuff[1]; + g_CalcParam.c1 = nBuff[2]; + g_CalcParam.a2 = nBuff[3]; + g_CalcParam.b2 = nBuff[4]; + g_CalcParam.c2 = nBuff[5]; + g_CalcParam.delta = nBuff[6]; + + if(g_CalcParam.delta == 0) + g_CalcParam.delta =1;//avoid divide by zero + + mutex_unlock(&cal_mutex); + + sprintf(env_val,"%d %d %d %d %d %d %d",nBuff[0],nBuff[1],nBuff[2],nBuff[3],nBuff[4],nBuff[5],nBuff[6]); + wmt_setsyspara("wmt.io.ts.2dcal", env_val); + klog("Tsc calibrate done data: [%s]\n",env_val); + + return 0; + + + case TS_IOCTL_GET_RAWDATA: + // wait for point up + dbg("test wait_penup\n"); + //l_tsdev->wait_penup(>811_tsdev); + klog("wmt_ts_ioctl: TS_IOCTL_GET_RAWDATA\n"); + wmt_ts_wait_penup(); + + nBuff[0] = g_evLast.x; + nBuff[1] = g_evLast.y; + copy_to_user((unsigned int*)arg, nBuff, 2*sizeof(int)); + klog("raw data: x=%d, y=%d\n", nBuff[0], nBuff[1]); + + return 0; + } + + return -EINVAL; +} + +static ssize_t wmt_ts_read(struct file *filp, char *buf, size_t count, loff_t *l) +{ + // read firmware file + + return 0; +} + + +static struct file_operations wmt_ts_fops = { + .read = wmt_ts_read, + .poll = wmt_ts_poll, + .unlocked_ioctl = wmt_ts_ioctl, + .open = wmt_ts_open, + .release = wmt_ts_close, +}; + +static int ts_writeproc( struct file *file, + const char *buffer, + unsigned long count, + void *data ) +{ + int calibrate = 0; + int val = 0; + + if (sscanf(buffer, "calibrate=%d\n", &calibrate)) + { + if (1 == calibrate) + { + if((l_tsdev->capacitance_calibrate != NULL) && + (0 == l_tsdev->capacitance_calibrate())) + { + printk(KERN_ALERT "%s calibration successfully!\n", l_tsdev->ts_id); + } else { + printk(KERN_ALERT "%s calibration failed!\n", l_tsdev->ts_id); + } + } + } else if (sscanf(buffer, "reset=%d\n", &val)) + { + + } + return count; +} + +static int ts_readproc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = 0; + + len = sprintf(page, + "echo calibrate=1 > /proc/wmtts_config to calibrate ts.\n"); + return len; +} + +static int wmt_check_touch_env(void) +{ + int ret = 0; + int len = 96, i = 0; + char retval[200] = {0},*p=NULL,*s=NULL; + //int nBuff[7] = {0}; + int Enable=0; //Gpio=0,PX=0,PY=0; + int val,val1; + + // Get u-boot parameter + ret = wmt_getsyspara("wmt.io.touch", retval, &len); + if(ret){ + errlog("Read wmt.io.touch Failed.\n"); + return -EIO; + } + memset(l_tpinfor,0,sizeof(l_tpinfor[0])); + p = retval; + sscanf(p,"%d:", &Enable); + p = strchr(p,':');p++; + s = strchr(p,':'); + strncpy(l_tpinfor[0].name,p, (s-p)); + p = s+1; + dbg("ts_name=%s\n", l_tpinfor[0].name); + + ret = sscanf(p,"%d:%d:%d:%d:%d:%d:%d:%d", + &irq_gpio,&panelres_x,&panelres_y,&rst_gpio, + &(l_tpinfor[0].xaxis),&(l_tpinfor[0].xdir),&(l_tpinfor[0].ydir), + &(l_tpinfor[0].max_finger_num)); + if (ret != 8) + { + dbg("Wrong format ts u-boot param(%d)!\n",ret); + return -ENODEV; + } + //check touch enable + if(Enable == 0){ + errlog("Touch Screen Is Disabled.\n"); + return -ENODEV; + } + + /*p = strchr(retval,':'); + p++; + if(strncmp(p, l_tsdev->ts_id,strlen(l_tsdev->ts_id))){//check touch ID + //errlog(" %s!=====\n", l_tsdev->ts_id); + return -ENODEV; + }*/ + + //sscanf(p,"%s:", ); +#if 1 + if (strstr(l_tpinfor[0].name, l_tsdev->ts_id) == NULL)// cyp140 + { + dbg("Can't find %s!\n", l_tsdev->ts_id); + return -ENODEV; + } +#endif //comment 2012-12-31 + l_tpindex = 0; + +/* + p = strchr(p,':'); + p++; + sscanf(p,"%d:%d:%d:%d",&irq_gpio,&panelres_x,&panelres_y,&rst_gpio); + + irq_gpio = Gpio; + panelres_x = PX; + panelres_y = PY; + */ + klog("p.x = %d, p.y = %d, gpio=%d, resetgpio=%d,xaxis=%d,xdir=%d,ydri=%d,maxfingernum=%d\n", + panelres_x, panelres_y, irq_gpio, rst_gpio, + l_tpinfor[0].xaxis,l_tpinfor[0].xdir,l_tpinfor[0].ydir, + l_tpinfor[0].max_finger_num); + + // parse touch key param + memset(retval,0,sizeof(retval)); + ret = wmt_getsyspara("wmt.io.tskeyindex", retval, &len); + if(ret){ + dbg("no touch key!\n"); + //return -EIO; + } else { + p = retval; + // the number of touch key + sscanf(retval,"%d:", &val); + dbg("tskey num:%d\n",val); + p = strchr(p,':'); + p++; + // touch key range + for (i=0;i tmp[5]) + lcd_exchg = 1; + } + +/* memset(retval,0,sizeof(retval)); + ret = wmt_getsyspara("wmt.io.ts.2dcal", retval, &len); + if(ret){ + errlog("Read env wmt.io.ts.2dcal Failed.\n "); + //return -EIO; + } + i = 0; + while(i < sizeof(retval)){ + if(retval[i]==' ' || retval[i]==',' || retval[i]==':') + retval[i] = '\0'; + i++; + } + + i = 0; + p = retval; + while(i<7 && p < (retval + sizeof(retval))){ + if(*p == '\0') + p++; + else{ + sscanf(p,"%d",&nBuff[i]); + //printk("%d\n",nBuff[i]); + p=p+strlen(p); + i++; + } + } + //sscanf(retval,"%d %d %d %d %d %d %d %d",&nBuff[0],&nBuff[1],&nBuff[2],&nBuff[3],&nBuff[4],&nBuff[5],&nBuff[6]); + dbg("Tsc calibrate init data: [%d %d %d %d %d %d %d]\n",nBuff[0],nBuff[1],nBuff[2],nBuff[3],nBuff[4],nBuff[5],nBuff[6]); + + g_CalcParam.a1 = nBuff[0]; + g_CalcParam.b1 = nBuff[1]; + g_CalcParam.c1 = nBuff[2]; + g_CalcParam.a2 = nBuff[3]; + g_CalcParam.b2 = nBuff[4]; + g_CalcParam.c2 = nBuff[5]; + g_CalcParam.delta = nBuff[6]; + + if(g_CalcParam.delta == 0) + g_CalcParam.delta =1;//avoid divide by zero +*/ + return 0; +} + +struct i2c_board_info ts_i2c_board_info = { + .type = WMT_TS_I2C_NAME, + .flags = 0x00, + .addr = WMT_TS_I2C_ADDR, + .platform_data = NULL, + .archdata = NULL, + .irq = -1, +}; + +static int ts_i2c_register_device (void) +{ + struct i2c_board_info *ts_i2c_bi; + struct i2c_adapter *adapter = NULL; + //struct i2c_client *client = NULL; + ts_i2c_bi = &ts_i2c_board_info; + adapter = i2c_get_adapter(1);/*in bus 1*/ + + if (NULL == adapter) { + printk("can not get i2c adapter, client address error\n"); + return -1; + } + l_client = i2c_new_device(adapter, ts_i2c_bi); + if (l_client == NULL) { + printk("allocate i2c client failed\n"); + return -1; + } + i2c_put_adapter(adapter); + return 0; +} + +static void ts_i2c_unregister_device(void) +{ + if (l_client != NULL) + { + i2c_unregister_device(l_client); + l_client = NULL; + } +} + +struct i2c_client* ts_get_i2c_client(void) +{ + return l_client; +} + +static int __init wmt_ts_init(void) +{ + int ret = 0; + + + + if(wmt_check_touch_env()) + return -ENODEV; + + //ts_i2c_board_info.addr = l_tpinfor[l_tpindex].i2caddr; + if (ts_i2c_register_device()<0) + { + dbg("Error to run ts_i2c_register_device()!\n"); + return -1; + } + mutex_init(&cal_mutex); + + if (l_tsdev->init() < 0){ + dbg("Errors to init %s ts IC!!!\n", l_tsdev->ts_id); + ret = -1; + goto err_init; + } + // Create device node + if (register_chrdev (TS_MAJOR, TS_NAME, &wmt_ts_fops)) { + printk (KERN_ERR "wmt touch: unable to get major %d\n", TS_MAJOR); + return -EIO; + } + + l_dev_class = class_create(THIS_MODULE, TS_NAME); + if (IS_ERR(l_dev_class)){ + ret = PTR_ERR(l_dev_class); + printk(KERN_ERR "Can't class_create touch device !!\n"); + return ret; + } + l_clsdevice = device_create(l_dev_class, NULL, MKDEV(TS_MAJOR, 0), NULL, TS_NAME); + if (IS_ERR(l_clsdevice)){ + ret = PTR_ERR(l_clsdevice); + printk(KERN_ERR "Failed to create device %s !!!",TS_NAME); + return ret; + } + + // register device and driver of platform + ret = platform_device_register(&wmt_ts_plt_device); + if(ret){ + errlog("wmt ts plat device register failed!\n"); + return ret; + } + ret = platform_driver_register(&wmt_ts_plt_driver); + if(ret){ + errlog("can not register platform_driver_register\n"); + platform_device_unregister(&wmt_ts_plt_device); + return ret; + } + + klog("%s driver init ok!\n",l_tsdev->ts_id); + return 0; +err_init: + ts_i2c_unregister_device(); + return ret; +} + +static void __exit wmt_ts_exit(void) +{ + dbg("%s\n",__FUNCTION__); + + l_tsdev->exit(); + platform_driver_unregister(&wmt_ts_plt_driver); + platform_device_unregister(&wmt_ts_plt_device); + device_destroy(l_dev_class, MKDEV(TS_MAJOR, 0)); + unregister_chrdev(TS_MAJOR, TS_NAME); + class_destroy(l_dev_class); + mutex_destroy(&cal_mutex); + ts_i2c_unregister_device(); +} + + +module_init(wmt_ts_init); +module_exit(wmt_ts_exit); + +MODULE_LICENSE("GPL"); + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/wmt_ts.h b/ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/wmt_ts.h new file mode 100755 index 00000000..11261348 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/wmt_ts.h @@ -0,0 +1,120 @@ + +#ifndef WMT_TSH_201010191758 +#define WMT_TSH_201010191758 + +#include +#include +#include +#include +#include + + +//#define DEBUG_WMT_TS +#ifdef DEBUG_WMT_TS +#undef dbg +#define dbg(fmt, args...) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__ , ## args) + +//#define dbg(fmt, args...) if (kpadall_isrundbg()) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__, ## args) + +#else +#define dbg(fmt, args...) +#endif + +#undef errlog +#undef klog +#define errlog(fmt, args...) printk("[%s]: " fmt, __FUNCTION__, ## args) +#define klog(fmt, args...) printk("[%s]: " fmt, __FUNCTION__, ## args) + +#define WMT_TS_I2C_NAME "cyp140-ts" +#define WMT_TS_I2C_ADDR 0x24 //0x76 + + + + + +//////////////////////////////data type/////////////////////////// +typedef struct { + short pressure; + short x; + short y; + //short millisecs; +} TS_EVENT; + +struct wmtts_device +{ + //data + char* driver_name; + char* ts_id; + //function + int (*init)(void); + int (*probe)(struct platform_device *platdev); + int (*remove)(struct platform_device *pdev); + void (*exit)(void); + int (*suspend)(struct platform_device *pdev, pm_message_t state); + int (*resume)(struct platform_device *pdev); + int (*capacitance_calibrate)(void); + int (*wait_penup)(struct wmtts_device*tsdev); // waiting untill penup + int penup; // 0--pendown;1--penup + +}; + +//////////////////////////function interface///////////////////////// +extern int wmt_ts_get_irqgpnum(void); +extern int wmt_ts_iscalibrating(void); +extern int wmt_ts_get_resolvX(void); +extern int wmt_ts_get_resolvY(void); +extern int wmt_ts_set_rawcoord(unsigned short x, unsigned short y); +extern int wmt_set_gpirq(int type); +extern int wmt_get_tsirqnum(void); +extern int wmt_disable_gpirq(void); +extern int wmt_enable_gpirq(void); +extern int wmt_is_tsirq_enable(void); +extern int wmt_is_tsint(void); +extern void wmt_clr_int(void); +extern void wmt_tsreset_init(void); +extern int wmt_ts_get_resetgpnum(void); +extern int wmt_ts_get_lcdexchg(void); +extern void wmt_disable_rst_pull(void); +extern void wmt_set_rst_pull(int up); +extern void wmt_rst_output(int high); +extern void wmt_rst_input(void); +extern void wmt_set_intasgp(void); +extern void wmt_intgp_out(int val); +extern void wmt_ts_set_irqinput(void); +extern unsigned int wmt_ts_irqinval(void); +extern void wmt_ts_set_penup(int up); +extern int wmt_ts_wait_penup(void); +extern void wmt_ts_wakeup_penup(void); +extern struct i2c_client* ts_get_i2c_client(void); +extern int wmt_ts_ispenup(void); +extern void wmt_ts_get_firmwname(char* firmname); +extern unsigned int wmt_ts_get_maxfingernum(void); +extern unsigned int wmt_ts_get_ictype(void); +extern unsigned int wmt_ts_get_xaxis(void); +extern unsigned int wmt_ts_get_xdir(void); +extern unsigned int wmt_ts_get_ydir(void); +// short +extern unsigned int wmt_ts_get_touchheight(void); +// long +extern unsigned int wmt_ts_get_touchwidth(void); +extern int wmt_ts_if_updatefw(void); + + + +extern void TouchPanelCalibrateAPoint( + int UncalX, //@PARM The uncalibrated X coordinate + int UncalY, //@PARM The uncalibrated Y coordinate + int *pCalX, //@PARM The calibrated X coordinate + int *pCalY //@PARM The calibrated Y coordinate + ); + +//filepath:the path of firmware file; +//firmdata:store the data from firmware file; +//maxlen: the max len of firmdata; +//return:the length of firmware data,negative-parsing error. +//extern int read_firmwarefile(char* filepath, unsigned char** firmdata); + +#endif + + + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/Kconfig b/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/Kconfig new file mode 100755 index 00000000..7dadb37f --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/Kconfig @@ -0,0 +1,11 @@ +config TOUCHSCREEN_FT5X0X + tristate "FT5X0X Capacity Touchscreen Device Support" + default y + depends on ARCH_WMT + ---help--- + Say Y here if you have an WMT based board with touchscreen + attached to it. + If unsure, say N. + To compile this driver as a module, choose M here: the + module will be called ft5x0x. + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/Makefile b/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/Makefile new file mode 100755 index 00000000..0283c3ec --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/Makefile @@ -0,0 +1,34 @@ +KERNELDIR=../../../../ +CROSS = arm_1103_le- +CC= $(CROSS)gcc +LD= $(CROSS)ld +STRIP = $(CROSS)strip + +DEBUG = n + +# Add your debugging flag (or not) to EXTRA_CFLAGS +ifeq ($(DEBUG),y) +# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines +DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines + +else + DEBFLAGS = -O2 -Wall +endif + +EXTRA_CFLAGS += $(DEBFLAGS) + + +MY_MODULE_NAME=s_wmt_ts_ft5x0x + +#obj-$(CONFIG_TOUCHSCREEN_FT5X0X) := $(MY_MODULE_NAME).o +obj-m := $(MY_MODULE_NAME).o +$(MY_MODULE_NAME)-objs := ft5x0x.o ft5x0x_upg.o ft5402_config.o ini.o + +default: + $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules + $(STRIP) --strip-debug $(MY_MODULE_NAME).ko + @rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions *.order *.symvers + +clean: + @rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ft5402_config.c b/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ft5402_config.c new file mode 100755 index 00000000..58683ebd --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ft5402_config.c @@ -0,0 +1,2295 @@ +#include "ft5402_config.h" +//#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "ini.h" +#include "ft5402_ini_config.h" +#include "ft5x0x.h" + + +extern int ft5x0x_i2c_txdata(char *txdata, int length); + +int ft5402_write_reg(struct i2c_client * client, u8 regaddr, u8 regvalue) +{ + unsigned char buf[2] = {0}; + buf[0] = regaddr; + buf[1] = regvalue; + + return ft5x0x_i2c_txdata(buf, 2); +} + +int ft5402_read_reg(struct i2c_client * client, u8 regaddr, u8 * regvalue) +{ + int ret; + + struct i2c_msg msgs[] = { + { + .addr = client->addr, + .flags = 0, + .len = 1, + .buf = ®addr, + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = 1, + .buf = regvalue, + }, + }; + ret = i2c_transfer(client->adapter, msgs, 2); + if (ret < 0) + pr_err("function:%s. i2c read error: %d\n", __func__, ret); + return ret; +} + +/*set tx order +*@txNO: offset from tx order start +*@txNO1: tx NO. +*/ +static int ft5402_set_tx_order(struct i2c_client * client, u8 txNO, u8 txNO1) +{ + unsigned char ReCode = 0; + if (txNO < FT5402_TX_TEST_MODE_1) + ReCode = ft5402_write_reg(client, FT5402_REG_TX_ORDER_START + txNO, + txNO1); + else { + ReCode = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, + FT5402_REG_TEST_MODE_2<<4); /*enter Test mode 2*/ + if (ReCode >= 0) + ReCode = ft5402_write_reg(client, + FT5402_REG_TX_ORDER_START + txNO - FT5402_TX_TEST_MODE_1, + txNO1); + ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, + FT5402_REG_TEST_MODE<<4); /*enter Test mode*/ + } + return ReCode; +} + +/*set tx order +*@txNO: offset from tx order start +*@pTxNo: return value of tx NO. +*/ +static int ft5402_get_tx_order(struct i2c_client * client, u8 txNO, u8 *pTxNo) +{ + unsigned char ReCode = 0; + if (txNO < FT5402_TX_TEST_MODE_1) + ReCode = ft5402_read_reg(client, FT5402_REG_TX_ORDER_START + txNO, + pTxNo); + else { + ReCode = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, + FT5402_REG_TEST_MODE_2<<4); /*enter Test mode 2*/ + if(ReCode >= 0) + ReCode = ft5402_read_reg(client, + FT5402_REG_TX_ORDER_START + txNO - FT5402_TX_TEST_MODE_1, + pTxNo); + ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, + FT5402_REG_TEST_MODE<<4); /*enter Test mode*/ + } + return ReCode; +} + +/*set tx cap +*@txNO: tx NO. +*@cap_value: value of cap +*/ +static int ft5402_set_tx_cap(struct i2c_client * client, u8 txNO, u8 cap_value) +{ + unsigned char ReCode = 0; + if (txNO < FT5402_TX_TEST_MODE_1) + ReCode = ft5402_write_reg(client, FT5402_REG_TX_CAP_START + txNO, + cap_value); + else { + ReCode = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, + FT5402_REG_TEST_MODE_2<<4); /*enter Test mode 2*/ + if (ReCode >= 0) + ReCode = ft5402_write_reg(client, + FT5402_REG_TX_CAP_START + txNO - FT5402_TX_TEST_MODE_1, + cap_value); + ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, + FT5402_REG_TEST_MODE<<4); /*enter Test mode*/ + } + return ReCode; +} + +/*get tx cap*/ +static int ft5402_get_tx_cap(struct i2c_client * client, u8 txNO, u8 *pCap) +{ + unsigned char ReCode = 0; + if (txNO < FT5402_TX_TEST_MODE_1) + ReCode = ft5402_read_reg(client, FT5402_REG_TX_CAP_START + txNO, + pCap); + else { + ReCode = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, + FT5402_REG_TEST_MODE_2<<4); /*enter Test mode 2*/ + if (ReCode >= 0) + ReCode = ft5402_read_reg(client, + FT5402_REG_TX_CAP_START + txNO - FT5402_TX_TEST_MODE_1, + pCap); + ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, + FT5402_REG_TEST_MODE<<4); /*enter Test mode*/ + } + return ReCode; +} + +/*set tx offset*/ +static int ft5402_set_tx_offset(struct i2c_client * client, u8 txNO, u8 offset_value) +{ + unsigned char temp=0; + unsigned char ReCode = 0; + if (txNO < FT5402_TX_TEST_MODE_1) { + ReCode = ft5402_read_reg(client, + FT5402_REG_TX_OFFSET_START + (txNO>>1), &temp); + if (ReCode >= 0) { + if (txNO%2 == 0) + ReCode = ft5402_write_reg(client, + FT5402_REG_TX_OFFSET_START + (txNO>>1), + (temp&0xf0) + (offset_value&0x0f)); + else + ReCode = ft5402_write_reg(client, + FT5402_REG_TX_OFFSET_START + (txNO>>1), + (temp&0x0f) + (offset_value<<4)); + } + } else { + ReCode = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, + FT5402_REG_TEST_MODE_2<<4); /*enter Test mode 2*/ + if (ReCode >= 0) { + ReCode = ft5402_read_reg(client, + FT5402_REG_DEVICE_MODE+((txNO-FT5402_TX_TEST_MODE_1)>>1), + &temp); /*enter Test mode 2*/ + if (ReCode >= 0) { + if(txNO%2 == 0) + ReCode = ft5402_write_reg(client, + FT5402_REG_TX_OFFSET_START+((txNO-FT5402_TX_TEST_MODE_1)>>1), + (temp&0xf0)+(offset_value&0x0f)); + else + ReCode = ft5402_write_reg(client, + FT5402_REG_TX_OFFSET_START+((txNO-FT5402_TX_TEST_MODE_1)>>1), + (temp&0xf0)+(offset_value<<4)); + } + } + ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, + FT5402_REG_TEST_MODE<<4); /*enter Test mode*/ + } + + return ReCode; +} + +/*get tx offset*/ +static int ft5402_get_tx_offset(struct i2c_client * client, u8 txNO, u8 *pOffset) +{ + unsigned char temp=0; + unsigned char ReCode = 0; + if (txNO < FT5402_TX_TEST_MODE_1) + ReCode = ft5402_read_reg(client, + FT5402_REG_TX_OFFSET_START + (txNO>>1), &temp); + else { + ReCode = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, + FT5402_REG_TEST_MODE_2<<4); /*enter Test mode 2*/ + if (ReCode >= 0) + ReCode = ft5402_read_reg(client, + FT5402_REG_TX_OFFSET_START+((txNO-FT5402_TX_TEST_MODE_1)>>1), + &temp); + ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, + FT5402_REG_TEST_MODE<<4); /*enter Test mode*/ + } + + if (ReCode >= 0) + (txNO%2 == 0) ? (*pOffset = (temp&0x0f)) : (*pOffset = (temp>>4)); + return ReCode; +} + +/*set rx order*/ +static int ft5402_set_rx_order(struct i2c_client * client, u8 rxNO, u8 rxNO1) +{ + unsigned char ReCode = 0; + ReCode = ft5402_write_reg(client, FT5402_REG_RX_ORDER_START + rxNO, + rxNO1); + return ReCode; +} + +/*get rx order*/ +static int ft5402_get_rx_order(struct i2c_client * client, u8 rxNO, u8 *prxNO1) +{ + unsigned char ReCode = 0; + ReCode = ft5402_read_reg(client, FT5402_REG_RX_ORDER_START + rxNO, + prxNO1); + return ReCode; +} + +/*set rx cap*/ +static int ft5402_set_rx_cap(struct i2c_client * client, u8 rxNO, u8 cap_value) +{ + unsigned char ReCode = 0; + if (rxNO < FT5402_RX_TEST_MODE_1) + ReCode = ft5402_write_reg(client, FT5402_REG_RX_CAP_START + rxNO, + cap_value); + else { + ReCode = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, + FT5402_REG_TEST_MODE_2<<4); /*enter Test mode 2*/ + if(ReCode >= 0) + ReCode = ft5402_write_reg(client, + FT5402_REG_RX_CAP_START + rxNO - FT5402_RX_TEST_MODE_1, + cap_value); + ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, + FT5402_REG_TEST_MODE<<4); /*enter Test mode*/ + } + + return ReCode; +} + +/*get rx cap*/ +static int ft5402_get_rx_cap(struct i2c_client * client, u8 rxNO, u8 *pCap) +{ + unsigned char ReCode = 0; + if (rxNO < FT5402_RX_TEST_MODE_1) + ReCode = ft5402_read_reg(client, FT5402_REG_RX_CAP_START + rxNO, + pCap); + else { + ReCode = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, + FT5402_REG_TEST_MODE_2<<4); /*enter Test mode 2*/ + if(ReCode >= 0) + ReCode = ft5402_read_reg(client, + FT5402_REG_RX_CAP_START + rxNO - FT5402_RX_TEST_MODE_1, + pCap); + ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, + FT5402_REG_TEST_MODE<<4); /*enter Test mode*/ + } + + return ReCode; +} + +/*set rx offset*/ +static int ft5402_set_rx_offset(struct i2c_client * client, u8 rxNO, u8 offset_value) +{ + unsigned char temp=0; + unsigned char ReCode = 0; + if (rxNO < FT5402_RX_TEST_MODE_1) { + ReCode = ft5402_read_reg(client, + FT5402_REG_RX_OFFSET_START + (rxNO>>1), &temp); + if (ReCode >= 0) { + if (rxNO%2 == 0) + ReCode = ft5402_write_reg(client, + FT5402_REG_RX_OFFSET_START + (rxNO>>1), + (temp&0xf0) + (offset_value&0x0f)); + else + ReCode = ft5402_write_reg(client, + FT5402_REG_RX_OFFSET_START + (rxNO>>1), + (temp&0x0f) + (offset_value<<4)); + } + } + else { + ReCode = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, + FT5402_REG_TEST_MODE_2<<4); /*enter Test mode 2*/ + if (ReCode >= 0) { + ReCode = ft5402_read_reg(client, + FT5402_REG_DEVICE_MODE+((rxNO-FT5402_RX_TEST_MODE_1)>>1), + &temp); /*enter Test mode 2*/ + if (ReCode >= 0) { + if (rxNO%2 == 0) + ReCode = ft5402_write_reg(client, + FT5402_REG_RX_OFFSET_START+((rxNO-FT5402_RX_TEST_MODE_1)>>1), + (temp&0xf0)+(offset_value&0x0f)); + else + ReCode = ft5402_write_reg(client, + FT5402_REG_RX_OFFSET_START+((rxNO-FT5402_RX_TEST_MODE_1)>>1), + (temp&0xf0)+(offset_value<<4)); + } + } + ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, + FT5402_REG_TEST_MODE<<4); /*enter Test mode*/ + } + + return ReCode; +} + +/*get rx offset*/ +static int ft5402_get_rx_offset(struct i2c_client * client, u8 rxNO, u8 *pOffset) +{ + unsigned char temp = 0; + unsigned char ReCode = 0; + if (rxNO < FT5402_RX_TEST_MODE_1) + ReCode = ft5402_read_reg(client, + FT5402_REG_RX_OFFSET_START + (rxNO>>1), &temp); + else { + ReCode = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, + FT5402_REG_TEST_MODE_2<<4); /*enter Test mode 2*/ + if (ReCode >= 0) + ReCode = ft5402_read_reg(client, + FT5402_REG_RX_OFFSET_START+((rxNO-FT5402_RX_TEST_MODE_1)>>1), + &temp); + + ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, + FT5402_REG_TEST_MODE<<4); /*enter Test mode*/ + } + + if (ReCode >= 0) { + if (0 == (rxNO%2)) + *pOffset = (temp&0x0f); + else + *pOffset = (temp>>4); + } + + return ReCode; +} + +/*set tx num*/ +static int ft5402_set_tx_num(struct i2c_client *client, u8 txnum) +{ + return ft5402_write_reg(client, FT5402_REG_TX_NUM, txnum); +} + +/*get tx num*/ +static int ft5402_get_tx_num(struct i2c_client *client, u8 *ptxnum) +{ + return ft5402_read_reg(client, FT5402_REG_TX_NUM, ptxnum); +} + +/*set rx num*/ +static int ft5402_set_rx_num(struct i2c_client *client, u8 rxnum) +{ + return ft5402_write_reg(client, FT5402_REG_RX_NUM, rxnum); +} + +/*get rx num*/ +static int ft5402_get_rx_num(struct i2c_client *client, u8 *prxnum) +{ + return ft5402_read_reg(client, FT5402_REG_RX_NUM, prxnum); +} + +/*set resolution*/ +static int ft5402_set_Resolution(struct i2c_client *client, u16 x, u16 y) +{ + unsigned char cRet = 0; + cRet &= ft5402_write_reg(client, + FT5402_REG_RESOLUTION_X_H, ((unsigned char)(x>>8))); + cRet &= ft5402_write_reg(client, + FT5402_REG_RESOLUTION_X_L, ((unsigned char)(x&0x00ff))); + + cRet &= ft5402_write_reg(client, + FT5402_REG_RESOLUTION_Y_H, ((unsigned char)(y>>8))); + cRet &= ft5402_write_reg(client, + FT5402_REG_RESOLUTION_Y_L, ((unsigned char)(y&0x00ff))); + + return cRet; +} + +/*get resolution*/ +static int ft5402_get_Resolution(struct i2c_client *client, + u16 *px, u16 *py) +{ + unsigned char cRet = 0, temp1 = 0, temp2 = 0; + cRet &= ft5402_read_reg(client, + FT5402_REG_RESOLUTION_X_H, &temp1); + cRet &= ft5402_read_reg(client, + FT5402_REG_RESOLUTION_X_L, &temp2); + (*px) = (((u16)temp1) << 8) | ((u16)temp2); + + cRet &= ft5402_read_reg(client, + FT5402_REG_RESOLUTION_Y_H, &temp1); + cRet &= ft5402_read_reg(client, + FT5402_REG_RESOLUTION_Y_L, &temp2); + (*py) = (((u16)temp1) << 8) | ((u16)temp2); + + return cRet; +} + + +/*set voltage*/ +static int ft5402_set_vol(struct i2c_client *client, u8 Vol) +{ + return ft5402_write_reg(client, FT5402_REG_VOLTAGE, Vol); +} + +/*get voltage*/ +static int ft5402_get_vol(struct i2c_client *client, u8 *pVol) +{ + return ft5402_read_reg(client, FT5402_REG_VOLTAGE, pVol); +} + +/*set gain*/ +static int ft5402_set_gain(struct i2c_client *client, u8 Gain) +{ + return ft5402_write_reg(client, FT5402_REG_GAIN, Gain); +} + +/*get gain*/ +static int ft5402_get_gain(struct i2c_client *client, u8 *pGain) +{ + return ft5402_read_reg(client, FT5402_REG_GAIN, pGain); +} + +/*get start rx*/ +static int ft5402_get_start_rx(struct i2c_client *client, u8 *pRx) +{ + return ft5402_read_reg(client, FT5402_REG_START_RX, pRx); +} + + +/*get adc target*/ +static int ft5402_get_adc_target(struct i2c_client *client, u16 *pvalue) +{ + int err = 0; + u8 tmp1, tmp2; + err = ft5402_read_reg(client, FT5402_REG_ADC_TARGET_HIGH, + &tmp1); + if (err < 0) + dev_err(&client->dev, "%s:get adc target high failed\n", + __func__); + err = ft5402_read_reg(client, FT5402_REG_ADC_TARGET_LOW, + &tmp2); + if (err < 0) + dev_err(&client->dev, "%s:get adc target low failed\n", + __func__); + + *pvalue = ((u16)tmp1<<8) + (u16)tmp2; + return err; +} + +static int ft5402_set_face_detect_statistics_tx_num(struct i2c_client *client, u8 prevalue) +{ + return ft5402_write_reg(client, FT5402_REG_FACE_DETECT_STATISTICS_TX_NUM, + prevalue); +} + +static int ft5402_get_face_detect_statistics_tx_num(struct i2c_client *client, u8 *pprevalue) +{ + return ft5402_read_reg(client, FT5402_REG_FACE_DETECT_STATISTICS_TX_NUM, + pprevalue); +} + +static int ft5402_set_face_detect_pre_value(struct i2c_client *client, u8 prevalue) +{ + return ft5402_write_reg(client, FT5402_REG_FACE_DETECT_PRE_VALUE, + prevalue); +} + +static int ft5402_get_face_detect_pre_value(struct i2c_client *client, u8 *pprevalue) +{ + return ft5402_read_reg(client, FT5402_REG_FACE_DETECT_PRE_VALUE, + pprevalue); +} + +static int ft5402_set_face_detect_num(struct i2c_client *client, u8 num) +{ + return ft5402_write_reg(client, FT5402_REG_FACE_DETECT_NUM, + num); +} + +static int ft5402_get_face_detect_num(struct i2c_client *client, u8 *pnum) +{ + return ft5402_read_reg(client, FT5402_REG_FACE_DETECT_NUM, + pnum); +} + + +static int ft5402_set_peak_value_min(struct i2c_client *client, u8 min) +{ + return ft5402_write_reg(client, FT5402_REG_BIGAREA_PEAK_VALUE_MIN, + min); +} + +static int ft5402_get_peak_value_min(struct i2c_client *client, u8 *pmin) +{ + return ft5402_read_reg(client, FT5402_REG_BIGAREA_PEAK_VALUE_MIN, + pmin); +} + +static int ft5402_set_diff_value_over_num(struct i2c_client *client, u8 num) +{ + return ft5402_write_reg(client, FT5402_REG_BIGAREA_DIFF_VALUE_OVER_NUM, + num); +} +static int ft5402_get_diff_value_over_num(struct i2c_client *client, u8 *pnum) +{ + return ft5402_read_reg(client, FT5402_REG_BIGAREA_DIFF_VALUE_OVER_NUM, + pnum); +} + + +static int ft5402_set_customer_id(struct i2c_client *client, u8 num) +{ + return ft5402_write_reg(client, FT5402_REG_CUSTOMER_ID, + num); +} +static int ft5402_get_customer_id(struct i2c_client *client, u8 *pnum) +{ + return ft5402_read_reg(client, FT5402_REG_CUSTOMER_ID, + pnum); +} + +static int ft5402_set_kx(struct i2c_client *client, u16 value) +{ + int err = 0; + err = ft5402_write_reg(client, FT5402_REG_KX_H, + value >> 8); + if (err < 0) + dev_err(&client->dev, "%s:set kx high failed\n", + __func__); + err = ft5402_write_reg(client, FT5402_REG_KX_L, + value); + if (err < 0) + dev_err(&client->dev, "%s:set kx low failed\n", + __func__); + + return err; +} + +static int ft5402_get_kx(struct i2c_client *client, u16 *pvalue) +{ + int err = 0; + u8 tmp1, tmp2; + err = ft5402_read_reg(client, FT5402_REG_KX_H, + &tmp1); + if (err < 0) + dev_err(&client->dev, "%s:get kx high failed\n", + __func__); + err = ft5402_read_reg(client, FT5402_REG_KX_L, + &tmp2); + if (err < 0) + dev_err(&client->dev, "%s:get kx low failed\n", + __func__); + + *pvalue = ((u16)tmp1<<8) + (u16)tmp2; + return err; +} +static int ft5402_set_ky(struct i2c_client *client, u16 value) +{ + int err = 0; + err = ft5402_write_reg(client, FT5402_REG_KY_H, + value >> 8); + if (err < 0) + dev_err(&client->dev, "%s:set ky high failed\n", + __func__); + err = ft5402_write_reg(client, FT5402_REG_KY_L, + value); + if (err < 0) + dev_err(&client->dev, "%s:set ky low failed\n", + __func__); + + return err; +} + +static int ft5402_get_ky(struct i2c_client *client, u16 *pvalue) +{ + int err = 0; + u8 tmp1, tmp2; + err = ft5402_read_reg(client, FT5402_REG_KY_H, + &tmp1); + if (err < 0) + dev_err(&client->dev, "%s:get ky high failed\n", + __func__); + err = ft5402_read_reg(client, FT5402_REG_KY_L, + &tmp2); + if (err < 0) + dev_err(&client->dev, "%s:get ky low failed\n", + __func__); + + *pvalue = ((u16)tmp1<<8) + (u16)tmp2; + return err; +} +static int ft5402_set_lemda_x(struct i2c_client *client, u8 value) +{ + return ft5402_write_reg(client, FT5402_REG_LEMDA_X, + value); +} + +static int ft5402_get_lemda_x(struct i2c_client *client, u8 *pvalue) +{ + return ft5402_read_reg(client, FT5402_REG_LEMDA_X, + pvalue); +} +static int ft5402_set_lemda_y(struct i2c_client *client, u8 value) +{ + return ft5402_write_reg(client, FT5402_REG_LEMDA_Y, + value); +} + +static int ft5402_get_lemda_y(struct i2c_client *client, u8 *pvalue) +{ + return ft5402_read_reg(client, FT5402_REG_LEMDA_Y, + pvalue); +} +static int ft5402_set_pos_x(struct i2c_client *client, u8 value) +{ + return ft5402_write_reg(client, FT5402_REG_DIRECTION, + value); +} + +static int ft5402_get_pos_x(struct i2c_client *client, u8 *pvalue) +{ + return ft5402_read_reg(client, FT5402_REG_DIRECTION, + pvalue); +} + +static int ft5402_set_scan_select(struct i2c_client *client, u8 value) +{ + return ft5402_write_reg(client, FT5402_REG_SCAN_SELECT, + value); +} + +static int ft5402_get_scan_select(struct i2c_client *client, u8 *pvalue) +{ + return ft5402_read_reg(client, FT5402_REG_SCAN_SELECT, + pvalue); +} + +static int ft5402_set_other_param(struct i2c_client *client) +{ + int err = 0; + err = ft5402_write_reg(client, FT5402_REG_THGROUP, (u8)(g_param_ft5402.ft5402_THGROUP)); + if (err < 0) { + dev_err(&client->dev, "%s:write THGROUP failed.\n", __func__); + return err; + } + err = ft5402_write_reg(client, FT5402_REG_THPEAK, g_param_ft5402.ft5402_THPEAK); + if (err < 0) { + dev_err(&client->dev, "%s:write THPEAK failed.\n", + __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_PWMODE_CTRL, + g_param_ft5402.ft5402_PWMODE_CTRL); + if (err < 0) { + dev_err(&client->dev, "%s:write PERIOD_CTRL failed.\n", __func__); + return err; + } + err = ft5402_write_reg(client, FT5402_REG_PERIOD_ACTIVE, + g_param_ft5402.ft5402_PERIOD_ACTIVE); + if (err < 0) { + dev_err(&client->dev, "%s:write PERIOD_ACTIVE failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FACE_DETECT_STATISTICS_TX_NUM, + g_param_ft5402.ft5402_FACE_DETECT_STATISTICS_TX_NUM); + if (err < 0) { + dev_err(&client->dev, "%s:write FACE_DETECT_STATISTICS_TX_NUM failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_MAX_TOUCH_VALUE_HIGH, + g_param_ft5402.ft5402_MAX_TOUCH_VALUE>>8); + if (err < 0) { + dev_err(&client->dev, "%s:write MAX_TOUCH_VALUE_HIGH failed.\n", __func__); + return err; + } + err = ft5402_write_reg(client, FT5402_REG_MAX_TOUCH_VALUE_LOW, + g_param_ft5402.ft5402_MAX_TOUCH_VALUE); + if (err < 0) { + dev_err(&client->dev, "%s:write MAX_TOUCH_VALUE_LOW failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FACE_DETECT_MODE, + g_param_ft5402.ft5402_FACE_DETECT_MODE); + if (err < 0) { + dev_err(&client->dev, "%s:write FACE_DETECT_MODE failed.\n", __func__); + return err; + } + err = ft5402_write_reg(client, FT5402_REG_DRAW_LINE_TH, + g_param_ft5402.ft5402_DRAW_LINE_TH); + if (err < 0) { + dev_err(&client->dev, "%s:write DRAW_LINE_TH failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_POINTS_SUPPORTED, + g_param_ft5402.ft5402_POINTS_SUPPORTED); + if (err < 0) { + dev_err(&client->dev, "%s:write POINTS_SUPPORTED failed.\n", __func__); + return err; + } + err = ft5402_write_reg(client, FT5402_REG_ESD_FILTER_FRAME, + g_param_ft5402.ft5402_ESD_FILTER_FRAME); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_ESD_FILTER_FRAME failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_POINTS_STABLE_MACRO, + g_param_ft5402.ft5402_POINTS_STABLE_MACRO); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_POINTS_STABLE_MACRO failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_MIN_DELTA_X, + g_param_ft5402.ft5402_MIN_DELTA_X); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_MIN_DELTA_X failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_MIN_DELTA_Y, + g_param_ft5402.ft5402_MIN_DELTA_Y); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_MIN_DELTA_Y failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_MIN_DELTA_STEP, + g_param_ft5402.ft5402_MIN_DELTA_STEP); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_MIN_DELTA_STEP failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_ESD_NOISE_MACRO, + g_param_ft5402.ft5402_ESD_NOISE_MACRO); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_ESD_NOISE_MACRO failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_ESD_DIFF_VAL, + g_param_ft5402.ft5402_ESD_DIFF_VAL); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_ESD_DIFF_VAL failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_ESD_NEGTIVE, + g_param_ft5402.ft5402_ESD_NEGTIVE); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_ESD_NEGTIVE failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_ESD_FILTER_FRAMES, + g_param_ft5402.ft5402_ESD_FILTER_FRAMES); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_ESD_FILTER_FRAMES failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_IO_LEVEL_SELECT, + g_param_ft5402.ft5402_IO_LEVEL_SELECT); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_IO_LEVEL_SELECT failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_POINTID_DELAY_COUNT, + g_param_ft5402.ft5402_POINTID_DELAY_COUNT); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_POINTID_DELAY_COUNT failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_LIFTUP_FILTER_MACRO, + g_param_ft5402.ft5402_LIFTUP_FILTER_MACRO); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_LIFTUP_FILTER_MACRO failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_DIFF_HANDLE_MACRO, + g_param_ft5402.ft5402_DIFF_HANDLE_MACRO); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_DIFF_HANDLE_MACRO failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_MIN_WATER, + g_param_ft5402.ft5402_MIN_WATER); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_MIN_WATER failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_MAX_NOISE, + g_param_ft5402.ft5402_MAX_NOISE); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_MAX_NOISE failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_WATER_START_RX, + g_param_ft5402.ft5402_WATER_START_RX); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_WATER_START_RX failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_WATER_START_TX, + g_param_ft5402.ft5402_WATER_START_TX); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_WATER_START_TX failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_HOST_NUMBER_SUPPORTED_MACRO, + g_param_ft5402.ft5402_HOST_NUMBER_SUPPORTED_MACRO); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_HOST_NUMBER_SUPPORTED_MACRO failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_RAISE_THGROUP, + g_param_ft5402.ft5402_RAISE_THGROUP); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_RAISE_THGROUP failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_CHARGER_STATE, + g_param_ft5402.ft5402_CHARGER_STATE); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_CHARGER_STATE failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_FILTERID_START, + g_param_ft5402.ft5402_FILTERID_START); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_FILTERID_START failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_FRAME_FILTER_EN_MACRO, + g_param_ft5402.ft5402_FRAME_FILTER_EN_MACRO); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_FRAME_FILTER_EN_MACRO failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_FRAME_FILTER_SUB_MAX_TH, + g_param_ft5402.ft5402_FRAME_FILTER_SUB_MAX_TH); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_FRAME_FILTER_SUB_MAX_TH failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_FRAME_FILTER_ADD_MAX_TH, + g_param_ft5402.ft5402_FRAME_FILTER_ADD_MAX_TH); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_FRAME_FILTER_ADD_MAX_TH failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_FRAME_FILTER_SKIP_START_FRAME, + g_param_ft5402.ft5402_FRAME_FILTER_SKIP_START_FRAME); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_FRAME_FILTER_SKIP_START_FRAME failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_FRAME_FILTER_BAND_EN, + g_param_ft5402.ft5402_FRAME_FILTER_BAND_EN); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_FRAME_FILTER_BAND_EN failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_FRAME_FILTER_BAND_WIDTH, + g_param_ft5402.ft5402_FRAME_FILTER_BAND_WIDTH); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_FRAME_FILTER_BAND_WIDTH failed.\n", __func__); + return err; + } + + return err; +} + +static int ft5402_get_other_param(struct i2c_client *client) +{ + int err = 0; + u8 value = 0x00; + err = ft5402_read_reg(client, FT5402_REG_THGROUP, &value); + if (err < 0) { + dev_err(&client->dev, "%s:write THGROUP failed.\n", __func__); + return err; + } else + DBG("THGROUP=%02x\n", value); + err = ft5402_read_reg(client, FT5402_REG_THPEAK, &value); + if (err < 0) { + dev_err(&client->dev, "%s:write THPEAK failed.\n", + __func__); + return err; + } else + DBG("THPEAK=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_PWMODE_CTRL, &value); + if (err < 0) { + dev_err(&client->dev, "%s:write PWMODE_CTRL failed.\n", __func__); + return err; + } else + DBG("CTRL=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_PERIOD_ACTIVE, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write PERIOD_ACTIVE failed.\n", __func__); + return err; + } else + DBG("PERIOD_ACTIVE=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_MAX_TOUCH_VALUE_HIGH, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write MAX_TOUCH_VALUE_HIGH failed.\n", __func__); + return err; + } else + DBG("MAX_TOUCH_VALUE_HIGH=%02x\n", value); + err = ft5402_read_reg(client, FT5402_REG_MAX_TOUCH_VALUE_LOW, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write MAX_TOUCH_VALUE_LOW failed.\n", __func__); + return err; + } else + DBG("MAX_TOUCH_VALUE_LOW=%02x\n", value); + err = ft5402_read_reg(client, FT5402_REG_FACE_DETECT_MODE, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FACE_DETECT_MODE failed.\n", __func__); + return err; + } else + DBG("FACE_DEC_MODE=%02x\n", value); + err = ft5402_read_reg(client, FT5402_REG_DRAW_LINE_TH, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write DRAW_LINE_TH failed.\n", __func__); + return err; + } else + DBG("DRAW_LINE_TH=%02x\n", value); + err = ft5402_read_reg(client, FT5402_REG_POINTS_SUPPORTED, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_POINTS_SUPPORTED failed.\n", __func__); + return err; + } else + DBG("ft5402_POINTS_SUPPORTED=%02x\n", value); + err = ft5402_read_reg(client, FT5402_REG_ESD_FILTER_FRAME, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_ESD_FILTER_FRAME failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_ESD_FILTER_FRAME=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_POINTS_STABLE_MACRO, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_POINTS_STABLE_MACRO failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_POINTS_STABLE_MACRO=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_MIN_DELTA_X, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_MIN_DELTA_X failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_MIN_DELTA_X=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_MIN_DELTA_Y, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_MIN_DELTA_Y failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_MIN_DELTA_Y=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_MIN_DELTA_STEP, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_MIN_DELTA_STEP failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_MIN_DELTA_STEP=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_ESD_NOISE_MACRO, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_ESD_NOISE_MACRO failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_ESD_NOISE_MACRO=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_ESD_DIFF_VAL, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_ESD_DIFF_VAL failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_ESD_DIFF_VAL=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_ESD_NEGTIVE, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_ESD_NEGTIVE failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_ESD_NEGTIVE=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_ESD_FILTER_FRAMES, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_ESD_FILTER_FRAMES failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_ESD_FILTER_FRAMES=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_IO_LEVEL_SELECT, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_IO_LEVEL_SELECT failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_IO_LEVEL_SELECT=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_POINTID_DELAY_COUNT, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_POINTID_DELAY_COUNT failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_POINTID_DELAY_COUNT=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_LIFTUP_FILTER_MACRO, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_LIFTUP_FILTER_MACRO failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_LIFTUP_FILTER_MACRO=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_DIFF_HANDLE_MACRO, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_DIFF_HANDLE_MACRO failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_DIFF_HANDLE_MACRO=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_MIN_WATER, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_MIN_WATER failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_MIN_WATER=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_MAX_NOISE, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_MAX_NOISE failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_MAX_NOISE=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_WATER_START_RX, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_WATER_START_RX failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_WATER_START_RX=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_WATER_START_TX, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_WATER_START_TX failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_WATER_START_TX=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_HOST_NUMBER_SUPPORTED_MACRO, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_HOST_NUMBER_SUPPORTED_MACRO failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_HOST_NUMBER_SUPPORTED_MACRO=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_RAISE_THGROUP, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_RAISE_THGROUP failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_RAISE_THGROUP=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_CHARGER_STATE, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_CHARGER_STATE failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_CHARGER_STATE=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_FILTERID_START, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_FILTERID_START failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_FILTERID_START=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_FRAME_FILTER_EN_MACRO, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_FRAME_FILTER_EN_MACRO failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_FRAME_FILTER_EN_MACRO=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_FRAME_FILTER_SUB_MAX_TH, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_FRAME_FILTER_SUB_MAX_TH failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_FRAME_FILTER_SUB_MAX_TH=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_FRAME_FILTER_ADD_MAX_TH, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_FRAME_FILTER_ADD_MAX_TH failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_FRAME_FILTER_ADD_MAX_TH=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_FRAME_FILTER_SKIP_START_FRAME, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_FRAME_FILTER_SKIP_START_FRAME failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_FRAME_FILTER_SKIP_START_FRAME=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_FRAME_FILTER_BAND_EN, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_FRAME_FILTER_BAND_EN failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_FRAME_FILTER_BAND_EN=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_FRAME_FILTER_BAND_WIDTH, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_FRAME_FILTER_BAND_WIDTH failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_FRAME_FILTER_BAND_WIDTH=%02x\n", value); + + return err; +} +int ft5402_get_ic_param(struct i2c_client *client) +{ + int err = 0; + int i = 0; + u8 value = 0x00; + u16 xvalue = 0x0000, yvalue = 0x0000; + + /*enter factory mode*/ + err = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, FT5402_FACTORYMODE_VALUE); + if (err < 0) { + dev_err(&client->dev, "%s:enter factory mode failed.\n", __func__); + goto RETURN_WORK; + } + + for (i = 0; i < g_ft5402_tx_num; i++) { + DBG("tx%d:", i); + /*get tx order*/ + err = ft5402_get_tx_order(client, i, &value); + if (err < 0) { + dev_err(&client->dev, "%s:could not get tx%d order.\n", + __func__, i); + goto RETURN_WORK; + } + DBG("order=%d ", value); + /*get tx cap*/ + err = ft5402_get_tx_cap(client, i, &value); + if (err < 0) { + dev_err(&client->dev, "%s:could not get tx%d cap.\n", + __func__, i); + goto RETURN_WORK; + } + DBG("cap=%02x\n", value); + } + /*get tx offset*/ + err = ft5402_get_tx_offset(client, 0, &value); + if (err < 0) { + dev_err(&client->dev, "%s:could not get tx 0 offset.\n", + __func__); + goto RETURN_WORK; + } else + DBG("tx offset = %02x\n", value); + + /*get rx offset and cap*/ + for (i = 0; i < g_ft5402_rx_num; i++) { + /*get rx order*/ + DBG("rx%d:", i); + err = ft5402_get_rx_order(client, i, &value); + if (err < 0) { + dev_err(&client->dev, "%s:could not get rx%d order.\n", + __func__, i); + goto RETURN_WORK; + } + DBG("order=%d ", value); + /*get rx cap*/ + err = ft5402_get_rx_cap(client, i, &value); + if (err < 0) { + dev_err(&client->dev, "%s:could not get rx%d cap.\n", + __func__, i); + goto RETURN_WORK; + } + DBG("cap=%02x ", value); + err = ft5402_get_rx_offset(client, i, &value); + if (err < 0) { + dev_err(&client->dev, "%s:could not get rx offset.\n", + __func__); + goto RETURN_WORK; + } + DBG("offset=%02x\n", value); + } + + /*get scan select*/ + err = ft5402_get_scan_select(client, &value); + if (err < 0) { + dev_err(&client->dev, "%s:could not get scan select.\n", + __func__); + goto RETURN_WORK; + } else + DBG("scan select = %02x\n", value); + + /*get tx number*/ + err = ft5402_get_tx_num(client, &value); + if (err < 0) { + dev_err(&client->dev, "%s:could not get tx num.\n", + __func__); + goto RETURN_WORK; + } else + DBG("tx num = %02x\n", value); + /*get rx number*/ + err = ft5402_get_rx_num(client, &value); + if (err < 0) { + dev_err(&client->dev, "%s:could not get rx num.\n", + __func__); + goto RETURN_WORK; + } else + DBG("rx num = %02x\n", value); + + /*get gain*/ + err = ft5402_get_gain(client, &value); + if (err < 0) { + dev_err(&client->dev, "%s:could not get gain.\n", + __func__); + goto RETURN_WORK; + } else + DBG("gain = %02x\n", value); + /*get voltage*/ + err = ft5402_get_vol(client, &value); + if (err < 0) { + dev_err(&client->dev, "%s:could not get voltage.\n", + __func__); + goto RETURN_WORK; + } else + DBG("voltage = %02x\n", value); + /*get start rx*/ + err = ft5402_get_start_rx(client, &value); + if (err < 0) { + dev_err(&client->dev, "%s:could not get start rx.\n", + __func__); + goto RETURN_WORK; + } else + DBG("start rx = %02x\n", value); + /*get adc target*/ + err = ft5402_get_adc_target(client, &xvalue); + if (err < 0) { + dev_err(&client->dev, "%s:could not get adc target.\n", + __func__); + goto ERR_EXIT; + } else + DBG("ADC target = %02x\n", xvalue); + + +RETURN_WORK: + /*enter work mode*/ + err = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, FT5402_WORKMODE_VALUE); + if (err < 0) { + dev_err(&client->dev, "%s:enter work mode failed.\n", __func__); + goto ERR_EXIT; + } + + /*get resolution*/ + err = ft5402_get_Resolution(client, &xvalue, &yvalue); + if (err < 0) { + dev_err(&client->dev, "%s:could not get resolution.\n", + __func__); + goto ERR_EXIT; + } else + DBG("resolution X = %d Y = %d\n", xvalue, yvalue); + + + /*get face detect statistics tx num*/ + err = ft5402_get_face_detect_statistics_tx_num(client, + &value); + if (err < 0) { + dev_err(&client->dev, + "%s:could not get face detect statistics tx num.\n", + __func__); + goto ERR_EXIT; + } else + DBG("FT5402_FACE_DETECT_STATISTICS_TX_NUM = %02x\n", value); + /*get face detect pre value*/ + err = ft5402_get_face_detect_pre_value(client, + &value); + if (err < 0) { + dev_err(&client->dev, + "%s:could not get face detect pre value.\n", + __func__); + goto ERR_EXIT; + } else + DBG("FT5402_FACE_DETECT_PRE_VALUE = %02x\n", value); + /*get face detect num*/ + err = ft5402_get_face_detect_num(client, &value); + if (err < 0) { + dev_err(&client->dev, "%s:could not get face detect num.\n", + __func__); + goto ERR_EXIT; + } else + DBG("face detect num = %02x\n", value); + + /*get min peak value*/ + err = ft5402_get_peak_value_min(client, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:could not get min peak value.\n", + __func__); + goto ERR_EXIT; + } else + DBG("FT5402_BIGAREA_PEAK_VALUE_MIN = %02x\n", value); + /*get diff value over num*/ + err = ft5402_get_diff_value_over_num(client, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:could not get diff value over num.\n", + __func__); + goto ERR_EXIT; + } else + DBG("FT5402_BIGAREA_DIFF_VALUE_OVER_NUM = %02x\n", value); + /*get customer id*/ + err = ft5402_get_customer_id(client, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:could not get customer id.\n", + __func__); + goto ERR_EXIT; + } else + DBG("FT5402_CUSTOMER_ID = %02x\n", value); + /*get kx*/ + err = ft5402_get_kx(client, &xvalue); + if (err < 0) { + dev_err(&client->dev, "%s:could not get kx.\n", + __func__); + goto ERR_EXIT; + } else + DBG("kx = %02x\n", xvalue); + /*get ky*/ + err = ft5402_get_ky(client, &xvalue); + if (err < 0) { + dev_err(&client->dev, "%s:could not get ky.\n", + __func__); + goto ERR_EXIT; + } else + DBG("ky = %02x\n", xvalue); + /*get lemda x*/ + err = ft5402_get_lemda_x(client, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:could not get lemda x.\n", + __func__); + goto ERR_EXIT; + } else + DBG("lemda x = %02x\n", value); + /*get lemda y*/ + err = ft5402_get_lemda_y(client, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:could not get lemda y.\n", + __func__); + goto ERR_EXIT; + } else + DBG("lemda y = %02x\n", value); + /*get pos x*/ + err = ft5402_get_pos_x(client, &value); + if (err < 0) { + dev_err(&client->dev, "%s:could not get pos x.\n", + __func__); + goto ERR_EXIT; + } else + DBG("pos x = %02x\n", value); + + err = ft5402_get_other_param(client); + +ERR_EXIT: + return err; +} + +int ft5402_Init_IC_Param(struct i2c_client *client) +{ + int err = 0; + int i = 0; + + /*enter factory mode*/ + err = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, FT5402_FACTORYMODE_VALUE); + if (err < 0) { + dev_err(&client->dev, "%s:enter factory mode failed.\n", __func__); + goto RETURN_WORK; + } + + for (i = 0; i < g_ft5402_tx_num; i++) { + if (g_ft5402_tx_order[i] != 0xFF) { + /*set tx order*/ + err = ft5402_set_tx_order(client, i, g_ft5402_tx_order[i]); + if (err < 0) { + dev_err(&client->dev, "%s:could not set tx%d order.\n", + __func__, i); + goto RETURN_WORK; + } + } + /*set tx cap*/ + err = ft5402_set_tx_cap(client, i, g_ft5402_tx_cap[i]); + if (err < 0) { + dev_err(&client->dev, "%s:could not set tx%d cap.\n", + __func__, i); + goto RETURN_WORK; + } + } + /*set tx offset*/ + err = ft5402_set_tx_offset(client, 0, g_ft5402_tx_offset); + if (err < 0) { + dev_err(&client->dev, "%s:could not set tx 0 offset.\n", + __func__); + goto RETURN_WORK; + } + + /*set rx offset and cap*/ + for (i = 0; i < g_ft5402_rx_num; i++) { + /*set rx order*/ + err = ft5402_set_rx_order(client, i, g_ft5402_rx_order[i]); + if (err < 0) { + dev_err(&client->dev, "%s:could not set rx%d order.\n", + __func__, i); + goto RETURN_WORK; + } + /*set rx cap*/ + err = ft5402_set_rx_cap(client, i, g_ft5402_rx_cap[i]); + if (err < 0) { + dev_err(&client->dev, "%s:could not set rx%d cap.\n", + __func__, i); + goto RETURN_WORK; + } + } + for (i = 0; i < g_ft5402_rx_num/2; i++) { + err = ft5402_set_rx_offset(client, i*2, g_ft5402_rx_offset[i]>>4); + if (err < 0) { + dev_err(&client->dev, "%s:could not set rx offset.\n", + __func__); + goto RETURN_WORK; + } + err = ft5402_set_rx_offset(client, i*2+1, g_ft5402_rx_offset[i]&0x0F); + if (err < 0) { + dev_err(&client->dev, "%s:could not set rx offset.\n", + __func__); + goto RETURN_WORK; + } + } + + /*set scan select*/ + err = ft5402_set_scan_select(client, g_ft5402_scanselect); + if (err < 0) { + dev_err(&client->dev, "%s:could not set scan select.\n", + __func__); + goto RETURN_WORK; + } + + /*set tx number*/ + err = ft5402_set_tx_num(client, g_ft5402_tx_num); + if (err < 0) { + dev_err(&client->dev, "%s:could not set tx num.\n", + __func__); + goto RETURN_WORK; + } + /*set rx number*/ + err = ft5402_set_rx_num(client, g_ft5402_rx_num); + if (err < 0) { + dev_err(&client->dev, "%s:could not set rx num.\n", + __func__); + goto RETURN_WORK; + } + + /*set gain*/ + err = ft5402_set_gain(client, g_ft5402_gain); + if (err < 0) { + dev_err(&client->dev, "%s:could not set gain.\n", + __func__); + goto RETURN_WORK; + } + /*set voltage*/ + err = ft5402_set_vol(client, g_ft5402_voltage); + if (err < 0) { + dev_err(&client->dev, "%s:could not set voltage.\n", + __func__); + goto RETURN_WORK; + } + + err = ft5402_write_reg(client, FT5402_REG_ADC_TARGET_HIGH, + g_param_ft5402.ft5402_ADC_TARGET>>8); + if (err < 0) { + dev_err(&client->dev, "%s:write ADC_TARGET_HIGH failed.\n", __func__); + return err; + } + err = ft5402_write_reg(client, FT5402_REG_ADC_TARGET_LOW, + g_param_ft5402.ft5402_ADC_TARGET); + if (err < 0) { + dev_err(&client->dev, "%s:write ADC_TARGET_LOW failed.\n", __func__); + return err; + } + +RETURN_WORK: + /*enter work mode*/ + err = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, FT5402_WORKMODE_VALUE); + if (err < 0) { + dev_err(&client->dev, "%s:enter work mode failed.\n", __func__); + goto ERR_EXIT; + } + + /*set resolution*/ + err = ft5402_set_Resolution(client, g_param_ft5402.ft5402_RESOLUTION_X, + g_param_ft5402.ft5402_RESOLUTION_Y); + if (err < 0) { + dev_err(&client->dev, "%s:could not set resolution.\n", + __func__); + goto ERR_EXIT; + } + + /*set face detect statistics tx num*/ + err = ft5402_set_face_detect_statistics_tx_num(client, + g_param_ft5402.ft5402_FACE_DETECT_STATISTICS_TX_NUM); + if (err < 0) { + dev_err(&client->dev, + "%s:could not set face detect statistics tx num.\n", + __func__); + goto ERR_EXIT; + } + /*set face detect pre value*/ + err = ft5402_set_face_detect_pre_value(client, + g_param_ft5402.ft5402_FACE_DETECT_PRE_VALUE); + if (err < 0) { + dev_err(&client->dev, + "%s:could not set face detect pre value.\n", + __func__); + goto ERR_EXIT; + } + /*set face detect num*/ + err = ft5402_set_face_detect_num(client, + g_param_ft5402.ft5402_FACE_DETECT_NUM); + if (err < 0) { + dev_err(&client->dev, "%s:could not set face detect num.\n", + __func__); + goto ERR_EXIT; + } + + /*set min peak value*/ + err = ft5402_set_peak_value_min(client, + g_param_ft5402.ft5402_BIGAREA_PEAK_VALUE_MIN); + if (err < 0) { + dev_err(&client->dev, "%s:could not set min peak value.\n", + __func__); + goto ERR_EXIT; + } + /*set diff value over num*/ + err = ft5402_set_diff_value_over_num(client, + g_param_ft5402.ft5402_BIGAREA_DIFF_VALUE_OVER_NUM); + if (err < 0) { + dev_err(&client->dev, "%s:could not set diff value over num.\n", + __func__); + goto ERR_EXIT; + } + /*set customer id*/ + err = ft5402_set_customer_id(client, + g_param_ft5402.ft5402_CUSTOMER_ID); + if (err < 0) { + dev_err(&client->dev, "%s:could not set customer id.\n", + __func__); + goto ERR_EXIT; + } + /*set kx*/ + err = ft5402_set_kx(client, g_param_ft5402.ft5402_KX); + if (err < 0) { + dev_err(&client->dev, "%s:could not set kx.\n", + __func__); + goto ERR_EXIT; + } + /*set ky*/ + err = ft5402_set_ky(client, g_param_ft5402.ft5402_KY); + if (err < 0) { + dev_err(&client->dev, "%s:could not set ky.\n", + __func__); + goto ERR_EXIT; + } + /*set lemda x*/ + err = ft5402_set_lemda_x(client, + g_param_ft5402.ft5402_LEMDA_X); + if (err < 0) { + dev_err(&client->dev, "%s:could not set lemda x.\n", + __func__); + goto ERR_EXIT; + } + /*set lemda y*/ + err = ft5402_set_lemda_y(client, + g_param_ft5402.ft5402_LEMDA_Y); + if (err < 0) { + dev_err(&client->dev, "%s:could not set lemda y.\n", + __func__); + goto ERR_EXIT; + } + /*set pos x*/ + err = ft5402_set_pos_x(client, g_param_ft5402.ft5402_DIRECTION); + if (err < 0) { + dev_err(&client->dev, "%s:could not set pos x.\n", + __func__); + goto ERR_EXIT; + } + + err = ft5402_set_other_param(client); + +ERR_EXIT: + return err; +} + + +char dst[512]; +static char * ft5402_sub_str(char * src, int n) +{ + char *p = src; + int i; + int m = 0; + int len = strlen(src); + + while (n >= 1 && m <= len) { + i = 0; + dst[10] = ' '; + n--; + while ( *p != ',' && *p != ' ') { + dst[i++] = *(p++); + m++; + if (i >= len) + break; + } + dst[i++] = '\0'; + p++; + } + return dst; +} +static int ft5402_GetInISize(char *config_name) +{ + struct file *pfile = NULL; + struct inode *inode; + unsigned long magic; + off_t fsize = 0; + char filepath[128]; + memset(filepath, 0, sizeof(filepath)); + + sprintf(filepath, "%s%s", FT5402_INI_FILEPATH, config_name); + + if (NULL == pfile) + pfile = filp_open(filepath, O_RDONLY, 0); + + if (IS_ERR(pfile)) { + pr_err("error occured while opening file %s.\n", filepath); + return -EIO; + } + + inode = pfile->f_dentry->d_inode; + magic = inode->i_sb->s_magic; + fsize = inode->i_size; + filp_close(pfile, NULL); + return fsize; +} + +static int ft5x0x_ReadInIData(char *config_name, + char *config_buf) +{ + struct file *pfile = NULL; + struct inode *inode; + unsigned long magic; + off_t fsize; + char filepath[128]; + loff_t pos; + mm_segment_t old_fs; + + memset(filepath, 0, sizeof(filepath)); + sprintf(filepath, "%s%s", FT5402_INI_FILEPATH, config_name); + if (NULL == pfile) + pfile = filp_open(filepath, O_RDONLY, 0); + if (IS_ERR(pfile)) { + pr_err("error occured while opening file %s.\n", filepath); + return -EIO; + } + + inode = pfile->f_dentry->d_inode; + magic = inode->i_sb->s_magic; + fsize = inode->i_size; + old_fs = get_fs(); + set_fs(KERNEL_DS); + pos = 0; + vfs_read(pfile, config_buf, fsize, &pos); + filp_close(pfile, NULL); + set_fs(old_fs); + + return 0; +} + +int ft5402_Get_Param_From_Ini(char *config_name) +{ + char key[64]; + char value[512]; + char section[64]; + int i = 0;//,ret=0; + int j = 0; + char *filedata = NULL; + unsigned char legal_byte1 = 0x00; + unsigned char legal_byte2 = 0x00; + + int inisize = ft5402_GetInISize(config_name); + + if (inisize <= 0) { + pr_err("%s ERROR:Get firmware size failed\n", + __func__); + return -EIO; + } + + filedata = kmalloc(inisize + 1, GFP_ATOMIC); + + if (ft5x0x_ReadInIData(config_name, filedata)) { + pr_err("%s() - ERROR: request_firmware failed\n", + __func__); + kfree(filedata); + return -EIO; + } + + /*check ini if it is illegal*/ + sprintf(section, "%s", FT5402_APP_LEGAL); + sprintf(key, "%s", FT5402_APP_LEGAL_BYTE_1_STR); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + legal_byte1 = atoi(value); + DBG("legal_byte1=%s\n", value); + sprintf(key, "%s", FT5402_APP_LEGAL_BYTE_2_STR); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + legal_byte2 = atoi(value); + DBG("lega2_byte1=%s\n", value); + if(FT5402_APP_LEGAL_BYTE_1_VALUE == legal_byte1 && + FT5402_APP_LEGAL_BYTE_2_VALUE == legal_byte2) + DBG("the ini file is valid\n"); + else { + pr_err("[FTS]-----the ini file is invalid!please check it.\n"); + goto ERROR_RETURN; + } + + /*get ini param*/ + sprintf(section, "%s", FT5402_APP_NAME); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_KX = atoi(value); + DBG("ft5402_KX=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_KY = atoi(value); + DBG("ft5402_KY=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_LEMDA_X = atoi(value); + DBG("ft5402_LEMDA_X=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_LEMDA_Y = atoi(value); + DBG("ft5402_LEMDA_Y=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_RESOLUTION_X = atoi(value); + DBG("ft5402_RESOLUTION_X=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_RESOLUTION_Y = atoi(value); + DBG("ft5402_RESOLUTION_Y=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_DIRECTION= atoi(value); + DBG("ft5402_DIRECTION=%s\n", value); + + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_FACE_DETECT_PRE_VALUE = atoi(value); + DBG("ft5402_FACE_DETECT_PRE_VALUE=%s\n", value); + + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_FACE_DETECT_NUM = atoi(value); + DBG("ft5402_FACE_DETECT_NUM=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_BIGAREA_PEAK_VALUE_MIN = atoi(value);/*The min value to be decided as the big point*/ + DBG("ft5402_BIGAREA_PEAK_VALUE_MIN=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_BIGAREA_DIFF_VALUE_OVER_NUM = atoi(value);/*The min big points of the big area*/ + DBG("ft5402_BIGAREA_DIFF_VALUE_OVER_NUM=%s\n", value); + + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_CUSTOMER_ID = atoi(value); + DBG("ft5402_CUSTOM_ID=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_PERIOD_ACTIVE = atoi(value); + DBG("ft5402_PERIOD_ACTIVE=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_FACE_DETECT_STATISTICS_TX_NUM = atoi(value); + DBG("ft5402_FACE_DETECT_STATISTICS_TX_NUM=%s\n", value); + + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_THGROUP = atoi(value); + DBG("ft5402_THGROUP=%s\n", value); + + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_THPEAK = atoi(value); + DBG("ft5402_THPEAK=%s\n", value); + + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_FACE_DETECT_MODE = atoi(value); + DBG("ft5402_FACE_DETECT_MODE=%s\n", value); + + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_MAX_TOUCH_VALUE = atoi(value); + DBG("ft5402_MAX_TOUCH_VALUE=%s\n", value); + + + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_PWMODE_CTRL= atoi(value); + DBG("ft5402_PWMODE_CTRL=%s\n", value); + + + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + + i++; + g_param_ft5402.ft5402_DRAW_LINE_TH = atoi(value); + DBG("ft5402_DRAW_LINE_TH=%s\n", value); + + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_POINTS_SUPPORTED= atoi(value); + DBG("ft5402_POINTS_SUPPORTED=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_START_RX = atoi(value); + DBG("ft5402_START_RX=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + + g_param_ft5402.ft5402_ADC_TARGET = atoi(value); + DBG("ft5402_ADC_TARGET=%s\n", value); + + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + + g_param_ft5402.ft5402_ESD_FILTER_FRAME = atoi(value); + DBG("ft5402_ESD_FILTER_FRAME=%s\n", value); + +/*********************************************************************/ + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_ft5402_tx_num = atoi(value); + DBG("ft5402_tx_num=%s\n", value); + + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_ft5402_rx_num = atoi(value); + DBG("ft5402_rx_num=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_ft5402_gain = atoi(value); + DBG("ft5402_gain=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_ft5402_voltage = atoi(value); + DBG("ft5402_voltage=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_ft5402_scanselect = atoi(value); + DBG("ft5402_scanselect=%s\n", value); + + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + for(j = 0; j < g_ft5402_tx_num; j++) + { + char * psrc = value; + g_ft5402_tx_order[j] = atoi(ft5402_sub_str(psrc, j+1)); + } + DBG("ft5402_tx_order=%s\n", value); + + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_ft5402_tx_offset = atoi(value); + DBG("ft5402_tx_offset=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + for(j = 0; j < g_ft5402_tx_num; j++) + { + char * psrc = value; + g_ft5402_tx_cap[j] = atoi(ft5402_sub_str(psrc, j+1)); + } + DBG("ft5402_tx_cap=%s\n", value); + + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + for(j = 0; j < g_ft5402_rx_num; j++) + { + char * psrc = value; + g_ft5402_rx_order[j] = atoi(ft5402_sub_str(psrc, j+1)); + } + DBG("ft5402_rx_order=%s\n", value); + + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + for(j = 0; j < g_ft5402_rx_num/2; j++) + { + char * psrc = value; + g_ft5402_rx_offset[j] = atoi(ft5402_sub_str(psrc, j+1)); + } + DBG("ft5402_rx_offset=%s\n", value); + + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + for(j = 0; j < g_ft5402_rx_num; j++) + { + char * psrc = value; + g_ft5402_rx_cap[j] = atoi(ft5402_sub_str(psrc, j+1)); + } + DBG("ft5402_rx_cap=%s\n", value); + + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_POINTS_STABLE_MACRO = atoi(value); + DBG("ft5402_POINTS_STABLE_MACRO=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_MIN_DELTA_X = atoi(value); + DBG("ft5402_MIN_DELTA_X=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_MIN_DELTA_Y = atoi(value); + DBG("ft5402_MIN_DELTA_Y=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_MIN_DELTA_STEP = atoi(value); + DBG("ft5402_MIN_DELTA_STEP=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_ESD_NOISE_MACRO = atoi(value); + DBG("ft5402_ESD_NOISE_MACRO=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_ESD_DIFF_VAL = atoi(value); + DBG("ft5402_ESD_DIFF_VAL=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_ESD_NEGTIVE = atoi(value); + DBG("ft5402_ESD_NEGTIVE=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_ESD_FILTER_FRAMES = atoi(value); + DBG("ft5402_ESD_FILTER_FRAMES=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_IO_LEVEL_SELECT = atoi(value); + DBG("ft5402_IO_LEVEL_SELECT=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_POINTID_DELAY_COUNT = atoi(value); + DBG("ft5402_POINTID_DELAY_COUNT=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_LIFTUP_FILTER_MACRO = atoi(value); + DBG("ft5402_LIFTUP_FILTER_MACRO=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_DIFF_HANDLE_MACRO = atoi(value); + DBG("ft5402_DIFF_HANDLE_MACRO=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_MIN_WATER = atoi(value); + DBG("ft5402_MIN_WATER=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_MAX_NOISE = atoi(value); + DBG("ft5402_MAX_NOISE=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_WATER_START_RX = atoi(value); + DBG("ft5402_WATER_START_RX=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_WATER_START_TX = atoi(value); + DBG("ft5402_WATER_START_TX=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_HOST_NUMBER_SUPPORTED_MACRO = atoi(value); + DBG("ft5402_HOST_NUMBER_SUPPORTED_MACRO=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_RAISE_THGROUP = atoi(value); + DBG("ft5402_RAISE_THGROUP=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_CHARGER_STATE = atoi(value); + DBG("ft5402_CHARGER_STATE=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_FILTERID_START = atoi(value); + DBG("ft5402_FILTERID_START=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_FRAME_FILTER_EN_MACRO = atoi(value); + DBG("ft5402_FRAME_FILTER_EN_MACRO=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_FRAME_FILTER_SUB_MAX_TH = atoi(value); + DBG("ft5402_FRAME_FILTER_SUB_MAX_TH=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_FRAME_FILTER_ADD_MAX_TH = atoi(value); + DBG("ft5402_FRAME_FILTER_ADD_MAX_TH=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_FRAME_FILTER_SKIP_START_FRAME = atoi(value); + DBG("ft5402_FRAME_FILTER_SKIP_START_FRAME=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_FRAME_FILTER_BAND_EN = atoi(value); + DBG("ft5402_FRAME_FILTER_BAND_EN=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_FRAME_FILTER_BAND_WIDTH = atoi(value); + DBG("ft5402_FRAME_FILTER_BAND_WIDTH=%s\n", value); + + + if (filedata) + kfree(filedata); + return 0; +ERROR_RETURN: + if (filedata) + kfree(filedata); + return -1; +} + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ft5402_config.h b/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ft5402_config.h new file mode 100755 index 00000000..b0c63889 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ft5402_config.h @@ -0,0 +1,71 @@ +#ifndef __FT5402_CONFIG_H__ +#define __FT5402_CONFIG_H__ +/*FT5402 config*/ + + +#define FT5402_START_RX 0 +#define FT5402_ADC_TARGET 8500 +#define FT5402_KX 120 +#define FT5402_KY 120 +#define FT5402_RESOLUTION_X 480 +#define FT5402_RESOLUTION_Y 800 +#define FT5402_LEMDA_X 0 +#define FT5402_LEMDA_Y 0 +#define FT5402_PWMODE_CTRL 1 +#define FT5402_POINTS_SUPPORTED 5 +#define FT5402_DRAW_LINE_TH 150 +#define FT5402_FACE_DETECT_MODE 0 +#define FT5402_FACE_DETECT_STATISTICS_TX_NUM 3 +#define FT5402_FACE_DETECT_PRE_VALUE 20 +#define FT5402_FACE_DETECT_NUM 10 +#define FT5402_THGROUP 25 +#define FT5402_THPEAK 60 +#define FT5402_BIGAREA_PEAK_VALUE_MIN 100 +#define FT5402_BIGAREA_DIFF_VALUE_OVER_NUM 50 +#define FT5402_MIN_DELTA_X 2 +#define FT5402_MIN_DELTA_Y 2 +#define FT5402_MIN_DELTA_STEP 2 +#define FT5402_ESD_DIFF_VAL 20 +#define FT5402_ESD_NEGTIVE -50 +#define FT5402_ESD_FILTER_FRAME 10 +#define FT5402_MAX_TOUCH_VALUE 600 +#define FT5402_CUSTOMER_ID 121 +#define FT5402_IO_LEVEL_SELECT 0 +#define FT5402_DIRECTION 1 +#define FT5402_POINTID_DELAY_COUNT 3 +#define FT5402_LIFTUP_FILTER_MACRO 1 +#define FT5402_POINTS_STABLE_MACRO 1 +#define FT5402_ESD_NOISE_MACRO 1 +#define FT5402_RV_G_PERIOD_ACTIVE 16 +#define FT5402_DIFFDATA_HANDLE 1 +#define FT5402_MIN_WATER_VAL -50 +#define FT5402_MAX_NOISE_VAL 10 +#define FT5402_WATER_HANDLE_START_RX 0 +#define FT5402_WATER_HANDLE_START_TX 0 +#define FT5402_HOST_NUMBER_SUPPORTED 1 +#define FT5402_RV_G_RAISE_THGROUP 30 +#define FT5402_RV_G_CHARGER_STATE 0 +#define FT5402_RV_G_FILTERID_START 2 +#define FT5402_FRAME_FILTER_EN 1 +#define FT5402_FRAME_FILTER_SUB_MAX_TH 2 +#define FT5402_FRAME_FILTER_ADD_MAX_TH 2 +#define FT5402_FRAME_FILTER_SKIP_START_FRAME 6 +#define FT5402_FRAME_FILTER_BAND_EN 1 +#define FT5402_FRAME_FILTER_BAND_WIDTH 128 +#define FT5402_OTP_PARAM_ID 0 + + +unsigned char g_ft5402_tx_num = 27; +unsigned char g_ft5402_rx_num = 16; +unsigned char g_ft5402_gain = 10; +unsigned char g_ft5402_voltage = 3; +unsigned char g_ft5402_scanselect = 12; +unsigned char g_ft5402_tx_order[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26}; +unsigned char g_ft5402_tx_offset = 2; +unsigned char g_ft5402_tx_cap[] = {42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42}; +unsigned char g_ft5402_rx_order[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; +unsigned char g_ft5402_rx_offset[] = {68,68,68,68,68,68,68,68}; +unsigned char g_ft5402_rx_cap[] = {84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84}; + + +#endif \ No newline at end of file diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ft5402_ini_config.h b/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ft5402_ini_config.h new file mode 100755 index 00000000..138f42e2 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ft5402_ini_config.h @@ -0,0 +1,411 @@ +#ifndef __LINUX_FT5402_INI_CONFIG_H__ +#define __LINUX_FT5402_INI_CONFIG_H + + +/*Init param register address*/ +/*factory mode register from 14-131*/ +#define FT5402_REG_TX_NUM 0x03 +#define FT5402_REG_RX_NUM 0x04 +#define FT5402_REG_VOLTAGE 0x05 +#define FT5402_REG_GAIN 0x07 +#define FT5402_REG_SCAN_SELECT 0x4E +#define FT5402_REG_TX_ORDER_START 0x50 +#define FT5402_REG_TX_CAP_START 0x78 +#define FT5402_REG_TX_OFFSET_START 0xBF +#define FT5402_REG_RX_ORDER_START 0xeb +#define FT5402_REG_RX_CAP_START 0xA0 +#define FT5402_REG_RX_OFFSET_START 0xD3 +#define FT5402_REG_START_RX 0x06 +#define FT5402_REG_ADC_TARGET_HIGH 0x08 +#define FT5402_REG_ADC_TARGET_LOW 0x09 + + +#define FT5402_REG_DEVICE_MODE 0x00 + + +/*work mode register from 0-13(0,1,12,13verify or Reserved)and 132-177(159 Reserved)*/ +#define FT5402_REG_THGROUP (0x00+0x80) +#define FT5402_REG_THPEAK (0x01+0x80) +#define FT5402_REG_PWMODE_CTRL (0x06+0x80) +#define FT5402_REG_PERIOD_ACTIVE (0x59+0x80) +#define FT5402_REG_POINTS_SUPPORTED (0x0A+0x80) +#define FT5402_REG_ESD_FILTER_FRAME (0x4F+0x80) + +#define FT5402_REG_RESOLUTION_X_H (0x18+0x80) +#define FT5402_REG_RESOLUTION_X_L (0x19+0x80) +#define FT5402_REG_RESOLUTION_Y_H (0x1a+0x80) +#define FT5402_REG_RESOLUTION_Y_L (0x1b+0x80) +#define FT5402_REG_KX_H (0x1c+0x80) +#define FT5402_REG_KX_L (0x9d) +#define FT5402_REG_KY_H (0x9e) +#define FT5402_REG_KY_L (0x1f+0x80) +#define FT5402_REG_CUSTOMER_ID (0xA8) +#define FT5402_REG_DRAW_LINE_TH (0xAe) +#define FT5402_REG_FACE_DETECT_MODE (0xB0) +#define FT5402_REG_MAX_TOUCH_VALUE_HIGH (0xD0) +#define FT5402_REG_MAX_TOUCH_VALUE_LOW (0xD1) + +#define FT5402_REG_DIRECTION (0x53+0x80) +#define FT5402_REG_LEMDA_X (0x41+0x80) +#define FT5402_REG_LEMDA_Y (0x42+0x80) +#define FT5402_REG_FACE_DETECT_STATISTICS_TX_NUM (0x43+0x80) +#define FT5402_REG_FACE_DETECT_PRE_VALUE (0x44+0x80) +#define FT5402_REG_FACE_DETECT_NUM (0x45+0x80) +#define FT5402_REG_BIGAREA_PEAK_VALUE_MIN (0x33+0x80) +#define FT5402_REG_BIGAREA_DIFF_VALUE_OVER_NUM (0x34+0x80) + +/**************************************************************************/ +#define FT5402_REG_FT5402_POINTS_STABLE_MACRO (0x57+0x80) +#define FT5402_REG_FT5402_MIN_DELTA_X (0x4a+0x80) +#define FT5402_REG_FT5402_MIN_DELTA_Y (0x4b+0x80) +#define FT5402_REG_FT5402_MIN_DELTA_STEP (0x4c+0x80) + +#define FT5402_REG_FT5402_ESD_NOISE_MACRO (0x58+0x80) +#define FT5402_REG_FT5402_ESD_DIFF_VAL (0x4d+0x80) +#define FT5402_REG_FT5402_ESD_NEGTIVE (0xCe) +#define FT5402_REG_FT5402_ESD_FILTER_FRAMES (0x4f+0x80) + +#define FT5402_REG_FT5402_IO_LEVEL_SELECT (0x52+0x80) + +#define FT5402_REG_FT5402_POINTID_DELAY_COUNT (0x54+0x80) + +#define FT5402_REG_FT5402_LIFTUP_FILTER_MACRO (0x55+0x80) + +#define FT5402_REG_FT5402_DIFF_HANDLE_MACRO (0x5A+0x80) +#define FT5402_REG_FT5402_MIN_WATER (0x5B+0x80) +#define FT5402_REG_FT5402_MAX_NOISE (0x5C+0x80) +#define FT5402_REG_FT5402_WATER_START_RX (0x5D+0x80) +#define FT5402_REG_FT5402_WATER_START_TX (0xDE) + +#define FT5402_REG_FT5402_HOST_NUMBER_SUPPORTED_MACRO (0x38+0x80) +#define FT5402_REG_FT5402_RAISE_THGROUP (0x36+0x80) +#define FT5402_REG_FT5402_CHARGER_STATE (0x35+0x80) + +#define FT5402_REG_FT5402_FILTERID_START (0x37+0x80) + +#define FT5402_REG_FT5402_FRAME_FILTER_EN_MACRO (0x5F+0x80) +#define FT5402_REG_FT5402_FRAME_FILTER_SUB_MAX_TH (0x60+0x80) +#define FT5402_REG_FT5402_FRAME_FILTER_ADD_MAX_TH (0x61+0x80) +#define FT5402_REG_FT5402_FRAME_FILTER_SKIP_START_FRAME (0x62+0x80) +#define FT5402_REG_FT5402_FRAME_FILTER_BAND_EN (0x63+0x80) +#define FT5402_REG_FT5402_FRAME_FILTER_BAND_WIDTH (0x64+0x80) +/**************************************************************************/ + +#define FT5402_REG_TEST_MODE 0x04 +#define FT5402_REG_TEST_MODE_2 0x05 +#define FT5402_TX_TEST_MODE_1 0x28 +#define FT5402_RX_TEST_MODE_1 0x1E +#define FT5402_FACTORYMODE_VALUE 0x40 +#define FT5402_WORKMODE_VALUE 0x00 + +/************************************************************************/ +/* string */ +/************************************************************************/ +#define STRING_FT5402_KX "FT5X02_KX" +#define STRING_FT5402_KY "FT5X02_KY" +#define STRING_FT5402_LEMDA_X "FT5X02_LEMDA_X" +#define STRING_FT5402_LEMDA_Y "FT5X02_LEMDA_Y" +#define STRING_FT5402_RESOLUTION_X "FT5X02_RESOLUTION_X" +#define STRING_FT5402_RESOLUTION_Y "FT5X02_RESOLUTION_Y" +#define STRING_FT5402_DIRECTION "FT5X02_DIRECTION" + + + +#define STRING_FT5402_FACE_DETECT_PRE_VALUE "FT5X02_FACE_DETECT_PRE_VALUE" +#define STRING_FT5402_FACE_DETECT_NUM "FT5X02_FACE_DETECT_NUM" +#define STRING_FT5402_BIGAREA_PEAK_VALUE_MIN "FT5X02_BIGAREA_PEAK_VALUE_MIN" +#define STRING_FT5402_BIGAREA_DIFF_VALUE_OVER_NUM "FT5X02_BIGAREA_DIFF_VALUE_OVER_NUM" +#define STRING_FT5402_CUSTOMER_ID "FT5X02_CUSTOMER_ID" +#define STRING_FT5402_PERIOD_ACTIVE "FT5X02_RV_G_PERIOD_ACTIVE" +#define STRING_FT5402_FACE_DETECT_STATISTICS_TX_NUM "FT5X02_FACE_DETECT_STATISTICS_TX_NUM" + +#define STRING_FT5402_THGROUP "FT5X02_THGROUP" +#define STRING_FT5402_THPEAK "FT5X02_THPEAK" +#define STRING_FT5402_FACE_DETECT_MODE "FT5X02_FACE_DETECT_MODE" +#define STRING_FT5402_MAX_TOUCH_VALUE "FT5X02_MAX_TOUCH_VALUE" + +#define STRING_FT5402_PWMODE_CTRL "FT5X02_PWMODE_CTRL" +#define STRING_FT5402_DRAW_LINE_TH "FT5X02_DRAW_LINE_TH" + +#define STRING_FT5402_POINTS_SUPPORTED "FT5X02_POINTS_SUPPORTED" + +#define STRING_FT5402_START_RX "FT5X02_START_RX" +#define STRING_FT5402_ADC_TARGET "FT5X02_ADC_TARGET" +#define STRING_FT5402_ESD_FILTER_FRAME "FT5X02_ESD_FILTER_FRAME" + +#define STRING_FT5402_POINTS_STABLE_MACRO "FT5X02_POINTS_STABLE_MACRO" +#define STRING_FT5402_MIN_DELTA_X "FT5X02_MIN_DELTA_X" +#define STRING_FT5402_MIN_DELTA_Y "FT5X02_MIN_DELTA_Y" +#define STRING_FT5402_MIN_DELTA_STEP "FT5X02_MIN_DELTA_STEP" + +#define STRING_FT5402_ESD_NOISE_MACRO "FT5X02_ESD_NOISE_MACRO" +#define STRING_FT5402_ESD_DIFF_VAL "FT5X02_ESD_DIFF_VAL" +#define STRING_FT5402_ESD_NEGTIVE "FT5X02_ESD_NEGTIVE" +#define STRING_FT5402_ESD_FILTER_FRAME "FT5X02_ESD_FILTER_FRAME" + +#define STRING_FT5402_IO_LEVEL_SELECT "FT5X02_IO_LEVEL_SELECT" +#define STRING_FT5402_POINTID_DELAY_COUNT "FT5X02_POINTID_DELAY_COUNT" + +#define STRING_FT5402_LIFTUP_FILTER_MACRO "FT5X02_LIFTUP_FILTER_MACRO" + +#define STRING_FT5402_DIFFDATA_HANDLE "FT5X02_DIFFDATA_HANDLE" //_MACRO +#define STRING_FT5402_MIN_WATER_VAL "FT5X02_MIN_WATER_VAL" +#define STRING_FT5402_MAX_NOISE_VAL "FT5X02_MAX_NOISE_VAL" +#define STRING_FT5402_WATER_HANDLE_START_RX "FT5X02_WATER_HANDLE_START_RX" +#define STRING_FT5402_WATER_HANDLE_START_TX "FT5X02_WATER_HANDLE_START_TX" + +#define STRING_FT5402_HOST_NUMBER_SUPPORTED "FT5X02_HOST_NUMBER_SUPPORTED" +#define STRING_FT5402_RV_G_RAISE_THGROUP "FT5X02_RV_G_RAISE_THGROUP" +#define STRING_FT5402_RV_G_CHARGER_STATE "FT5X02_RV_G_CHARGER_STATE" + +#define STRING_FT5402_RV_G_FILTERID_START "FT5X02_RV_G_FILTERID_START" + +#define STRING_FT5402_FRAME_FILTER_EN "FT5X02_FRAME_FILTER_EN" +#define STRING_FT5402_FRAME_FILTER_SUB_MAX_TH "FT5X02_FRAME_FILTER_SUB_MAX_TH" +#define STRING_FT5402_FRAME_FILTER_ADD_MAX_TH "FT5X02_FRAME_FILTER_ADD_MAX_TH" +#define STRING_FT5402_FRAME_FILTER_SKIP_START_FRAME "FT5X02_FRAME_FILTER_SKIP_START_FRAME" +#define STRING_FT5402_FRAME_FILTER_BAND_EN "FT5X02_FRAME_FILTER_BAND_EN" +#define STRING_FT5402_FRAME_FILTER_BAND_WIDTH "FT5X02_FRAME_FILTER_BAND_WIDTH" + + +#define STRING_ft5402_tx_num "FT5X02_tx_num" +#define STRING_ft5402_rx_num "FT5X02_rx_num" +#define STRING_ft5402_gain "FT5X02_gain" +#define STRING_ft5402_voltage "FT5X02_voltage" +#define STRING_ft5402_scanselect "FT5X02_scanselect" + +#define STRING_ft5402_tx_order "FT5X02_tx_order" +#define STRING_ft5402_tx_offset "FT5X02_tx_offset" +#define STRING_ft5402_tx_cap "FT5X02_tx_cap" + +#define STRING_ft5402_rx_order "FT5X02_rx_order" +#define STRING_ft5402_rx_offset "FT5X02_rx_offset" +#define STRING_ft5402_rx_cap "FT5X02_rx_cap" + +struct Struct_Param_FT5402 { + short ft5402_KX; + short ft5402_KY; + unsigned char ft5402_LEMDA_X; + unsigned char ft5402_LEMDA_Y; + short ft5402_RESOLUTION_X; + short ft5402_RESOLUTION_Y; + unsigned char ft5402_DIRECTION; + unsigned char ft5402_FACE_DETECT_PRE_VALUE; + unsigned char ft5402_FACE_DETECT_NUM; + + unsigned char ft5402_BIGAREA_PEAK_VALUE_MIN; + unsigned char ft5402_BIGAREA_DIFF_VALUE_OVER_NUM; + unsigned char ft5402_CUSTOMER_ID; + unsigned char ft5402_PERIOD_ACTIVE; + unsigned char ft5402_FACE_DETECT_STATISTICS_TX_NUM; + + short ft5402_THGROUP; + unsigned char ft5402_THPEAK; + unsigned char ft5402_FACE_DETECT_MODE; + short ft5402_MAX_TOUCH_VALUE; + + unsigned char ft5402_PWMODE_CTRL; + unsigned char ft5402_DRAW_LINE_TH; + unsigned char ft5402_POINTS_SUPPORTED; + + unsigned char ft5402_START_RX; + short ft5402_ADC_TARGET; + unsigned char ft5402_ESD_FILTER_FRAME; + + unsigned char ft5402_POINTS_STABLE_MACRO; + unsigned char ft5402_MIN_DELTA_X; + unsigned char ft5402_MIN_DELTA_Y; + unsigned char ft5402_MIN_DELTA_STEP; + + unsigned char ft5402_ESD_NOISE_MACRO; + unsigned char ft5402_ESD_DIFF_VAL; + char ft5402_ESD_NEGTIVE; //negtive + unsigned char ft5402_ESD_FILTER_FRAMES; + + unsigned char ft5402_IO_LEVEL_SELECT; + + unsigned char ft5402_POINTID_DELAY_COUNT; + + unsigned char ft5402_LIFTUP_FILTER_MACRO; + + unsigned char ft5402_DIFF_HANDLE_MACRO; + char ft5402_MIN_WATER; //negtive + unsigned char ft5402_MAX_NOISE; + unsigned char ft5402_WATER_START_RX; + unsigned char ft5402_WATER_START_TX; + + unsigned char ft5402_HOST_NUMBER_SUPPORTED_MACRO; + unsigned char ft5402_RAISE_THGROUP; + unsigned char ft5402_CHARGER_STATE; + + unsigned char ft5402_FILTERID_START; + + unsigned char ft5402_FRAME_FILTER_EN_MACRO; + unsigned char ft5402_FRAME_FILTER_SUB_MAX_TH; + unsigned char ft5402_FRAME_FILTER_ADD_MAX_TH; + unsigned char ft5402_FRAME_FILTER_SKIP_START_FRAME; + unsigned char ft5402_FRAME_FILTER_BAND_EN; + unsigned char ft5402_FRAME_FILTER_BAND_WIDTH; + +}; + +struct Struct_Param_FT5402 g_param_ft5402 = { + FT5402_KX, + FT5402_KY, + FT5402_LEMDA_X, + FT5402_LEMDA_Y, + FT5402_RESOLUTION_X, + FT5402_RESOLUTION_Y, + FT5402_DIRECTION, + + FT5402_FACE_DETECT_PRE_VALUE, + FT5402_FACE_DETECT_NUM, + FT5402_BIGAREA_PEAK_VALUE_MIN, + FT5402_BIGAREA_DIFF_VALUE_OVER_NUM, + FT5402_CUSTOMER_ID, + FT5402_RV_G_PERIOD_ACTIVE, + FT5402_FACE_DETECT_STATISTICS_TX_NUM, + + FT5402_THGROUP, + FT5402_THPEAK, + FT5402_FACE_DETECT_MODE, + FT5402_MAX_TOUCH_VALUE, + + FT5402_PWMODE_CTRL, + FT5402_DRAW_LINE_TH, + FT5402_POINTS_SUPPORTED, + + FT5402_START_RX, + FT5402_ADC_TARGET, + FT5402_ESD_FILTER_FRAME, + + FT5402_POINTS_STABLE_MACRO, + FT5402_MIN_DELTA_X, + FT5402_MIN_DELTA_Y, + FT5402_MIN_DELTA_STEP, + + FT5402_ESD_NOISE_MACRO, + FT5402_ESD_DIFF_VAL, + FT5402_ESD_NEGTIVE, + FT5402_ESD_FILTER_FRAME, + + FT5402_IO_LEVEL_SELECT, + + FT5402_POINTID_DELAY_COUNT, + + FT5402_LIFTUP_FILTER_MACRO, + + FT5402_DIFFDATA_HANDLE, + FT5402_MIN_WATER_VAL, + FT5402_MAX_NOISE_VAL, + FT5402_WATER_HANDLE_START_RX, + FT5402_WATER_HANDLE_START_TX, + + FT5402_HOST_NUMBER_SUPPORTED, + FT5402_RV_G_RAISE_THGROUP, + FT5402_RV_G_CHARGER_STATE, + + FT5402_RV_G_FILTERID_START, + + FT5402_FRAME_FILTER_EN, + FT5402_FRAME_FILTER_SUB_MAX_TH, + FT5402_FRAME_FILTER_ADD_MAX_TH, + FT5402_FRAME_FILTER_SKIP_START_FRAME, + FT5402_FRAME_FILTER_BAND_EN, + FT5402_FRAME_FILTER_BAND_WIDTH, +}; + +char String_Param_FT5402[][64] = { + STRING_FT5402_KX, + STRING_FT5402_KY, + STRING_FT5402_LEMDA_X, + STRING_FT5402_LEMDA_Y, + STRING_FT5402_RESOLUTION_X, + STRING_FT5402_RESOLUTION_Y, + STRING_FT5402_DIRECTION, + STRING_FT5402_FACE_DETECT_PRE_VALUE, + STRING_FT5402_FACE_DETECT_NUM, + STRING_FT5402_BIGAREA_PEAK_VALUE_MIN, + STRING_FT5402_BIGAREA_DIFF_VALUE_OVER_NUM, + STRING_FT5402_CUSTOMER_ID, + STRING_FT5402_PERIOD_ACTIVE, + STRING_FT5402_FACE_DETECT_STATISTICS_TX_NUM, + + STRING_FT5402_THGROUP, + STRING_FT5402_THPEAK, + STRING_FT5402_FACE_DETECT_MODE, + STRING_FT5402_MAX_TOUCH_VALUE, + + STRING_FT5402_PWMODE_CTRL, + STRING_FT5402_DRAW_LINE_TH, + STRING_FT5402_POINTS_SUPPORTED, + + STRING_FT5402_START_RX, + STRING_FT5402_ADC_TARGET, + STRING_FT5402_ESD_FILTER_FRAME, + + + STRING_ft5402_tx_num, + STRING_ft5402_rx_num, + STRING_ft5402_gain, + STRING_ft5402_voltage , + STRING_ft5402_scanselect, + + STRING_ft5402_tx_order, + STRING_ft5402_tx_offset, + STRING_ft5402_tx_cap, + + STRING_ft5402_rx_order, + STRING_ft5402_rx_offset, + STRING_ft5402_rx_cap, + + STRING_FT5402_POINTS_STABLE_MACRO, + STRING_FT5402_MIN_DELTA_X, + STRING_FT5402_MIN_DELTA_Y, + STRING_FT5402_MIN_DELTA_STEP, + + STRING_FT5402_ESD_NOISE_MACRO, + STRING_FT5402_ESD_DIFF_VAL, + STRING_FT5402_ESD_NEGTIVE, + STRING_FT5402_ESD_FILTER_FRAME, + + STRING_FT5402_IO_LEVEL_SELECT, + + STRING_FT5402_POINTID_DELAY_COUNT, + + STRING_FT5402_LIFTUP_FILTER_MACRO, + + STRING_FT5402_DIFFDATA_HANDLE, + STRING_FT5402_MIN_WATER_VAL, + STRING_FT5402_MAX_NOISE_VAL, + STRING_FT5402_WATER_HANDLE_START_RX, + STRING_FT5402_WATER_HANDLE_START_TX, + + STRING_FT5402_HOST_NUMBER_SUPPORTED, + STRING_FT5402_RV_G_RAISE_THGROUP, + STRING_FT5402_RV_G_CHARGER_STATE, + + STRING_FT5402_RV_G_FILTERID_START, + + STRING_FT5402_FRAME_FILTER_EN, + STRING_FT5402_FRAME_FILTER_SUB_MAX_TH, + STRING_FT5402_FRAME_FILTER_ADD_MAX_TH, + STRING_FT5402_FRAME_FILTER_SKIP_START_FRAME, + STRING_FT5402_FRAME_FILTER_BAND_EN, + STRING_FT5402_FRAME_FILTER_BAND_WIDTH, + +}; + +#define FT5402_APP_NAME "FT5X02_param" + +#define FT5402_APP_LEGAL "Legal_File" +#define FT5402_APP_LEGAL_BYTE_1_STR "BYTE_1" +#define FT5402_APP_LEGAL_BYTE_2_STR "BYTE_2" + +#define FT5402_APP_LEGAL_BYTE_1_VALUE 107 +#define FT5402_APP_LEGAL_BYTE_2_VALUE 201 + + +#define FT5402_INI_FILEPATH "/system/etc/firmware/" + +#endif diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ft5x0x.c b/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ft5x0x.c new file mode 100755 index 00000000..9bb63b83 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ft5x0x.c @@ -0,0 +1,937 @@ +/* + * drivers/input/touchscreen/ft5x0x/ft5x0x.c + * + * FocalTech ft5x0x TouchScreen driver. + * + * Copyright (c) 2010 Focal tech Ltd. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + * + * note: only support mulititouch Wenfs 2010-10-01 + */ +#include +#include +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ft5x0x.h" +#include "../../../video/backlight/wmt_bl.h" + +struct ft5x0x_data *pContext=NULL; +static struct i2c_client *l_client=NULL; + +#ifdef TOUCH_KEY +static int keycodes[NUM_KEYS] ={ + KEY_MENU, + KEY_HOME, + KEY_BACK, + KEY_SEARCH +}; +#endif + +#define FT5402_CONFIG_NAME "fttpconfig_5402public.ini" +extern int ft5x0x_read_fw_ver(void); +extern int ft5x0x_auto_clb(void); +extern int ft5x0x_upg_fw_bin(struct ft5x0x_data *ft5x0x, int check_ver); +extern int ft5402_Get_Param_From_Ini(char *config_name); +extern int ft5402_Init_IC_Param(struct i2c_client *client); +extern int ft5402_get_ic_param(struct i2c_client *client); +extern int ft5402_read_reg(struct i2c_client * client, u8 regaddr, u8 * regvalue); + +extern int register_bl_notifier(struct notifier_block *nb); + +extern int unregister_bl_notifier(struct notifier_block *nb); + + +int ft5x0x_i2c_rxdata(char *rxdata, int length) +{ + int ret; + struct i2c_msg msg[2]; + + msg[0].addr = pContext->addr; + msg[0].flags = 0 | I2C_M_NOSTART; + msg[0].len = 1; + msg[0].buf = rxdata; + + msg[1].addr = pContext->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = length; + msg[1].buf = rxdata; + + ret = i2c_transfer(pContext->client->adapter, msg, 2); + if (ret <= 0) + dbg_err("msg i2c read error: %d\n", ret); + + return ret; +} + + +int ft5x0x_i2c_txdata(char *txdata, int length) +{ + int ret; + struct i2c_msg msg[1]; + + msg[0].addr = pContext->addr; + msg[0].flags = 0; + msg[0].len = length; + msg[0].buf = txdata; + + ret = i2c_transfer(pContext->client->adapter, msg, 1); + if (ret <= 0) + dbg_err("msg i2c read error: %d\n", ret); + + return ret; +} + +static void ft5x0x_penup(struct ft5x0x_data *ft5x0x) +{ + input_mt_sync(ft5x0x->input_dev); + input_sync(ft5x0x->input_dev); +#ifdef TOUCH_KEY + if(ft5x0x->tskey_used && ft5x0x->tkey_pressed && ft5x0x->tkey_idx < NUM_KEYS ){ + input_report_key(ft5x0x->input_dev, keycodes[ft5x0x->tkey_idx], 1); + input_sync(ft5x0x->input_dev); + input_report_key(ft5x0x->input_dev, keycodes[ft5x0x->tkey_idx], 0); + input_sync(ft5x0x->input_dev); + dbg("report as key event %d \n",ft5x0x->tkey_idx); + } +#endif + + dbg("pen up\n"); + return; +} + +#ifdef TOUCH_KEY +static int ft5x0x_read_tskey(struct ft5x0x_data *ft5x0x,int x,int y) +{ + int px,py; + + if(ft5x0x->tkey.axis){ + px = y; + py = x; + }else{ + px = x; + py = y; + } + + if(px >= ft5x0x->tkey.x_lower && px<=ft5x0x->tkey.x_upper){ + ft5x0x->tkey_pressed = 1; + if(py>= ft5x0x->tkey.ypos[0].y_lower && py<= ft5x0x->tkey.ypos[0].y_upper){ + ft5x0x->tkey_idx= 0; + }else if(py>= ft5x0x->tkey.ypos[1].y_lower && py<= ft5x0x->tkey.ypos[1].y_upper){ + ft5x0x->tkey_idx = 1; + }else if(py>= ft5x0x->tkey.ypos[2].y_lower && py<= ft5x0x->tkey.ypos[2].y_upper){ + ft5x0x->tkey_idx = 2; + }else if(py>= ft5x0x->tkey.ypos[3].y_lower && py<= ft5x0x->tkey.ypos[3].y_upper){ + ft5x0x->tkey_idx = 3; + }else{ + ft5x0x->tkey_idx = NUM_KEYS; + } + + return 1; + } + + ft5x0x->tkey_pressed = 0; + return 0; +} +#endif + +static int ft5x0x_read_data(struct ft5x0x_data *ft5x0x) +{ + int ret = -1; + int i = 0; + u16 x,y,px,py; + u8 buf[64] = {0}, id; + struct ts_event *event = &ft5x0x->event; + + if(ft5x0x->nt == 10) + ret = ft5x0x_i2c_rxdata(buf, 64); + else if(ft5x0x->nt == 5) + ret = ft5x0x_i2c_rxdata(buf, 31); + + if (ret <= 0) { + dbg_err("read_data i2c_rxdata failed: %d\n", ret); + return ret; + } + + memset(event, 0, sizeof(struct ts_event)); + //event->tpoint = buf[2] & 0x03;// 0000 0011 + //event->tpoint = buf[2] & 0x07;// 000 0111 + event->tpoint = buf[2]&0x0F; + if (event->tpoint == 0) { + ft5x0x_penup(ft5x0x); + return 1; + } + + if (event->tpoint > ft5x0x->nt){ + dbg_err("tounch pointnum=%d > max:%d\n", event->tpoint,ft5x0x->nt); + return -1; + } + + for (i = 0; i < event->tpoint; i++){ + id = (buf[5+i*6] >>4) & 0x0F;//get track id + if(ft5x0x->swap){ + px = (buf[3+i*6] & 0x0F)<<8 |buf[4+i*6]; + py = (buf[5+i*6] & 0x0F)<<8 |buf[6+i*6]; + }else{ + px = (buf[5+i*6] & 0x0F)<<8 |buf[6+i*6]; + py = (buf[3+i*6] & 0x0F)<<8 |buf[4+i*6]; + } + + x = px; + y = py; + + if(ft5x0x->xch) + x = ft5x0x->reslx - px; + + if(ft5x0x->ych) + y = ft5x0x->resly - py; + + if(ft5x0x->dbg) printk("F%d: Tid=%d,px=%d,py=%d; x=%d,y=%d\n", i, id, px, py, x, y); + +#ifdef TOUCH_KEY + if(ft5x0x->tskey_used && event->tpoint==1) { + if(ft5x0x_read_tskey(ft5x0x,px,py) > 0) return -1; + } +#endif + if (ft5x0x->lcd_exchg) { + int tmp; + tmp = x; + x = y; + y = ft5x0x->reslx - tmp; + } + event->x[i] = x; + event->y[i] = y; + event->tid[i] = id; + + } + + return 0; +} + +static void ft5x0x_report(struct ft5x0x_data *ft5x0x) +{ + int i = 0; + struct ts_event *event = &ft5x0x->event; + + for (i = 0; i < event->tpoint; i++){ + input_report_abs(ft5x0x->input_dev, ABS_MT_TRACKING_ID, event->tid[i]); + input_report_abs(ft5x0x->input_dev, ABS_MT_POSITION_X, event->x[i]); + input_report_abs(ft5x0x->input_dev, ABS_MT_POSITION_Y, event->y[i]); + input_mt_sync(ft5x0x->input_dev); + } + input_sync(ft5x0x->input_dev); + + return; +} + +static void ft5x0x_read_work(struct work_struct *work) +{ + int ret = -1; + struct ft5x0x_data *ft5x0x = container_of(work, struct ft5x0x_data, read_work); + + mutex_lock(&ft5x0x->ts_mutex); + ret = ft5x0x_read_data(ft5x0x); + + if (ret == 0) ft5x0x_report(ft5x0x); + + wmt_gpio_unmask_irq(ft5x0x->irqgpio); + mutex_unlock(&ft5x0x->ts_mutex); + + return; +} + +static irqreturn_t ft5x0x_interrupt(int irq, void *dev) +{ + struct ft5x0x_data *ft5x0x = dev; + + if (gpio_irqstatus(ft5x0x->irqgpio)) + { + wmt_gpio_ack_irq(ft5x0x->irqgpio); + if (is_gpio_irqenable(ft5x0x->irqgpio)) + { + wmt_gpio_mask_irq(ft5x0x->irqgpio); +#ifdef CONFIG_HAS_EARLYSUSPEND + if(!ft5x0x->earlysus) queue_work(ft5x0x->workqueue, &ft5x0x->read_work); +#else + queue_work(ft5x0x->workqueue, &ft5x0x->read_work); +#endif + + } + return IRQ_HANDLED; + } + return IRQ_NONE; +} + +static void ft5x0x_reset(struct ft5x0x_data *ft5x0x) +{ + gpio_set_value(ft5x0x->rstgpio, 1); + mdelay(5); + gpio_set_value(ft5x0x->rstgpio, 0); + mdelay(20); + gpio_set_value(ft5x0x->rstgpio, 1); + mdelay(5); + + return; +} + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void ft5x0x_early_suspend(struct early_suspend *handler) +{ + struct ft5x0x_data *ft5x0x = container_of(handler, struct ft5x0x_data, early_suspend); + ft5x0x->earlysus = 1; + wmt_gpio_mask_irq(ft5x0x->irqgpio); + return; +} + +static void ft5x0x_late_resume(struct early_suspend *handler) +{ + struct ft5x0x_data *ft5x0x = container_of(handler, struct ft5x0x_data, early_suspend); + + ft5x0x_reset(ft5x0x); + ft5x0x->earlysus = 0; + + wmt_gpio_set_irq_type(ft5x0x->irqgpio, IRQ_TYPE_EDGE_FALLING); + wmt_gpio_unmask_irq(ft5x0x->irqgpio); + + return; +} +#endif //CONFIG_HAS_EARLYSUSPEND + +#ifdef CONFIG_PM +static int ft5x0x_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct ft5x0x_data *ft5x0x = dev_get_drvdata(&pdev->dev); + ft5x0x->earlysus = 1; + wmt_gpio_mask_irq(ft5x0x->irqgpio); + return 0; +} + +static int ft5x0x_resume(struct platform_device *pdev) +{ + struct ft5x0x_data *ft5x0x = dev_get_drvdata(&pdev->dev); + ft5x0x_reset(ft5x0x); + ft5x0x->earlysus = 0; + + if (ft5x0x->load_cfg) { + msleep(350); + ft5402_Init_IC_Param(ft5x0x->client); + //msleep(50); + ft5402_get_ic_param(ft5x0x->client); + } + wmt_gpio_set_irq_type(ft5x0x->irqgpio, IRQ_TYPE_EDGE_FALLING); + wmt_gpio_unmask_irq(ft5x0x->irqgpio); + return 0; +} + +#else +#define ft5x0x_suspend NULL +#define ft5x0x_resume NULL +#endif + +static ssize_t cat_dbg(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "dbg \n"); +} + +static ssize_t echo_dbg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned int dbg = simple_strtoul(buf, NULL, 10); + struct ft5x0x_data *ft5x0x = pContext; + + if(dbg){ + ft5x0x->dbg = 1; + }else{ + ft5x0x->dbg = 0; + } + + return count; +} +static DEVICE_ATTR(dbg, S_IRUGO | S_IWUSR, cat_dbg, echo_dbg); + +static ssize_t cat_clb(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "calibrate \n"); +} + +static ssize_t echo_clb(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned int cal = simple_strtoul(buf, NULL, 10); + + if(cal){ + if(ft5x0x_auto_clb()) printk("Calibrate Failed.\n"); + }else{ + printk("calibrate --echo 1 >clb.\n"); + } + + return count; +} + +static DEVICE_ATTR(clb, S_IRUGO | S_IWUSR, cat_clb, echo_clb); + +static ssize_t cat_fupg(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "fupg \n"); +} + +static ssize_t echo_fupg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct ft5x0x_data *ft5x0x = pContext; + unsigned int upg = simple_strtoul(buf, NULL, 10); + + wmt_gpio_mask_irq(ft5x0x->irqgpio); + if(upg){ + if(ft5x0x_upg_fw_bin(ft5x0x, 0)) printk("Upgrade Failed.\n"); + }else{ + printk("upgrade --echo 1 > fupg.\n"); + } + wmt_gpio_unmask_irq(ft5x0x->irqgpio); + + return count; +} +static DEVICE_ATTR(fupg, S_IRUGO | S_IWUSR, cat_fupg, echo_fupg); + + +static ssize_t cat_fver(struct device *dev, struct device_attribute *attr, char *buf) +{ + int fw_ver = ft5x0x_read_fw_ver(); + return sprintf(buf, "firmware version:0x%02x \n",fw_ver); +} + +static ssize_t echo_fver(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return count; +} +static DEVICE_ATTR(fver, S_IRUGO | S_IWUSR, cat_fver, echo_fver); + +static ssize_t cat_addr(struct device *dev, struct device_attribute *attr, char *buf) +{ + int ret; + u8 addrs[32]; + int cnt=0; + struct i2c_msg msg[2]; + struct ft5x0x_data *ft5x0x = pContext; + u8 ver[1]= {0xa6}; + + ft5x0x->addr = 1; + + msg[0].addr = ft5x0x->addr; + msg[0].flags = 0; + msg[0].len = 1; + msg[0].buf = ver; + + msg[1].addr = ft5x0x->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = 1; + msg[1].buf = ver; + + while(ft5x0x->addr < 0x80){ + ret = i2c_transfer(ft5x0x->client->adapter, msg, 2); + if(ret == 2) sprintf(&addrs[5*cnt++], " 0x%02x",ft5x0x->addr); + + ft5x0x->addr++; + msg[0].addr = msg[1].addr = ft5x0x->addr; + } + + return sprintf(buf, "i2c addr:%s\n",addrs); +} + +static ssize_t echo_addr(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned int addr; + struct ft5x0x_data *ft5x0x = pContext; + + sscanf(buf,"%x", &addr); + ft5x0x->addr = addr; + + return count; +} +static DEVICE_ATTR(addr, S_IRUGO | S_IWUSR, cat_addr, echo_addr); + +static struct attribute *ft5x0x_attributes[] = { + &dev_attr_clb.attr, + &dev_attr_fupg.attr, + &dev_attr_fver.attr, + &dev_attr_dbg.attr, + &dev_attr_addr.attr, + NULL +}; + +static const struct attribute_group ft5x0x_group = { + .attrs = ft5x0x_attributes, +}; + +static int ft5x0x_sysfs_create_group(struct ft5x0x_data *ft5x0x, const struct attribute_group *group) +{ + int err; + + ft5x0x->kobj = kobject_create_and_add("wmtts", NULL) ; + if(!ft5x0x->kobj){ + dbg_err("kobj create failed.\n"); + return -ENOMEM; + } + + /* Register sysfs hooks */ + err = sysfs_create_group(ft5x0x->kobj, group); + if (err < 0){ + kobject_del(ft5x0x->kobj); + dbg_err("Create sysfs group failed!\n"); + return -ENOMEM; + } + + return 0; +} + +static void ft5x0x_sysfs_remove_group(struct ft5x0x_data *ft5x0x, const struct attribute_group *group) +{ + sysfs_remove_group(ft5x0x->kobj, group); + kobject_del(ft5x0x->kobj); + return; +} + +static int bl_notify_irqgpio = -1; +static int wmt_wakeup_bl_notify(struct notifier_block *nb, unsigned long event, + void *dummy) +{ + switch (event) { + case BL_CLOSE: + errlog("ft5x0x: BL_CLOSE, disable irq\n"); + wmt_gpio_mask_irq(bl_notify_irqgpio); + break; + case BL_OPEN: + errlog("ft5x0x: BL_OPEN, enable irq\n"); + wmt_gpio_unmask_irq(bl_notify_irqgpio); + break; + } + return NOTIFY_OK; +} + +static struct notifier_block wmt_bl_notify = { + .notifier_call = wmt_wakeup_bl_notify, +}; + +static int ft5x0x_probe(struct platform_device *pdev) +{ + int i,err = 0; + u8 value = 0; + u8 cfg_name[32]; + struct ft5x0x_data *ft5x0x = platform_get_drvdata( pdev); + + ft5x0x->client = l_client; + INIT_WORK(&ft5x0x->read_work, ft5x0x_read_work); + mutex_init(&ft5x0x->ts_mutex); + + ft5x0x->workqueue = create_singlethread_workqueue(ft5x0x->name); + if (!ft5x0x->workqueue) { + err = -ESRCH; + goto exit_create_singlethread; + } + + err = ft5x0x_sysfs_create_group(ft5x0x, &ft5x0x_group); + if(err < 0){ + dbg("create sysfs group failed.\n"); + goto exit_create_group; + } + + ft5x0x->input_dev = input_allocate_device(); + if (!ft5x0x->input_dev) { + err = -ENOMEM; + dbg("failed to allocate input device\n"); + goto exit_input_dev_alloc_failed; + } + + ft5x0x->input_dev->name = ft5x0x->name; + ft5x0x->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + set_bit(INPUT_PROP_DIRECT, ft5x0x->input_dev->propbit); + + if (ft5x0x->lcd_exchg) { + input_set_abs_params(ft5x0x->input_dev, + ABS_MT_POSITION_X, 0, ft5x0x->resly, 0, 0); + input_set_abs_params(ft5x0x->input_dev, + ABS_MT_POSITION_Y, 0, ft5x0x->reslx, 0, 0); + } else { + input_set_abs_params(ft5x0x->input_dev, + ABS_MT_POSITION_X, 0, ft5x0x->reslx, 0, 0); + input_set_abs_params(ft5x0x->input_dev, + ABS_MT_POSITION_Y, 0, ft5x0x->resly, 0, 0); + } + input_set_abs_params(ft5x0x->input_dev, + ABS_MT_TRACKING_ID, 0, 20, 0, 0); +#ifdef TOUCH_KEY + if(ft5x0x->tskey_used){ + for (i = 0; i input_dev->keybit); + + ft5x0x->input_dev->keycode = keycodes; + ft5x0x->input_dev->keycodesize = sizeof(unsigned int); + ft5x0x->input_dev->keycodemax = NUM_KEYS; + } +#endif + + err = input_register_device(ft5x0x->input_dev); + if (err) { + dbg_err("ft5x0x_ts_probe: failed to register input device.\n"); + goto exit_input_register_device_failed; + } + +#ifdef CONFIG_HAS_EARLYSUSPEND + ft5x0x->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + ft5x0x->early_suspend.suspend = ft5x0x_early_suspend; + ft5x0x->early_suspend.resume = ft5x0x_late_resume; + register_early_suspend(&ft5x0x->early_suspend); +#endif + + if(ft5x0x->upg){ + if(ft5x0x_upg_fw_bin(ft5x0x, 1)) printk("Upgrade Failed.\n"); + else wmt_setsyspara("wmt.io.ts.upg",""); + ft5x0x->upg = 0x00; + } + + if(request_irq(ft5x0x->irq, ft5x0x_interrupt, IRQF_SHARED, ft5x0x->name, ft5x0x) < 0){ + dbg_err("Could not allocate irq for ts_ft5x0x !\n"); + err = -1; + goto exit_register_irq; + } + + { // check if need to load config to IC or not + err = ft5402_read_reg(ft5x0x->client, 0xa3, &value); + if (err < 0) + dbg_err("Read reg 0xa3 failed.\n"); + else + printk("0xa3 reg = %d\n", value); + if (value == 3) + ft5x0x->load_cfg = 1; + else + ft5x0x->load_cfg = 0; + } + ft5x0x_reset(ft5x0x); + + if (ft5x0x->load_cfg) { + msleep(350); /*make sure CTP already finish startup process*/ + sprintf(cfg_name, "%s.ini", ft5x0x->cfg_name); + printk("Config file name: %s\n", cfg_name); + if (ft5402_Get_Param_From_Ini(cfg_name) >= 0) + ft5402_Init_IC_Param(ft5x0x->client); + else + dbg_err("[FTS]-------Get ft5402 param from INI file failed\n"); + ft5402_get_ic_param(ft5x0x->client); + } + + wmt_gpio_set_irq_type(ft5x0x->irqgpio, IRQ_TYPE_EDGE_FALLING); + wmt_gpio_unmask_irq(ft5x0x->irqgpio); + + if(bl_notify_irqgpio < 0){ + register_bl_notifier(&wmt_bl_notify); + bl_notify_irqgpio = ft5x0x->irqgpio; + } + + return 0; + +exit_register_irq: +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&ft5x0x->early_suspend); +#endif +exit_input_register_device_failed: + input_free_device(ft5x0x->input_dev); +exit_input_dev_alloc_failed: + ft5x0x_sysfs_remove_group(ft5x0x, &ft5x0x_group); +exit_create_group: + cancel_work_sync(&ft5x0x->read_work); + destroy_workqueue(ft5x0x->workqueue); +exit_create_singlethread: + return err; +} + +static int ft5x0x_remove(struct platform_device *pdev) +{ + struct ft5x0x_data *ft5x0x = platform_get_drvdata( pdev); + + if( bl_notify_irqgpio > 0){ + unregister_bl_notifier(&wmt_bl_notify); + bl_notify_irqgpio = -1; + } + cancel_work_sync(&ft5x0x->read_work); + flush_workqueue(ft5x0x->workqueue); + destroy_workqueue(ft5x0x->workqueue); + + free_irq(ft5x0x->irq, ft5x0x); + wmt_gpio_mask_irq(ft5x0x->irqgpio); + +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&ft5x0x->early_suspend); +#endif + input_unregister_device(ft5x0x->input_dev); + + ft5x0x_sysfs_remove_group(ft5x0x, &ft5x0x_group); + + mutex_destroy(&ft5x0x->ts_mutex); + dbg("remove...\n"); + return 0; +} + +static void ft5x0x_release(struct device *device) +{ + return; +} + +static struct platform_device ft5x0x_device = { + .name = DEV_FT5X0X, + .id = 0, + .dev = {.release = ft5x0x_release}, +}; + +static struct platform_driver ft5x0x_driver = { + .driver = { + .name = DEV_FT5X0X, + .owner = THIS_MODULE, + }, + .probe = ft5x0x_probe, + .remove = ft5x0x_remove, + .suspend = ft5x0x_suspend, + .resume = ft5x0x_resume, +}; + +static int check_touch_env(struct ft5x0x_data *ft5x0x) +{ + int i,ret = 0; + int len = 96; + int Enable; + char retval[96] = {0}; + char *p=NULL; + char *s=NULL; + + // Get u-boot parameter + ret = wmt_getsyspara("wmt.io.touch", retval, &len); + if(ret){ + //printk("MST FT5x0x:Read wmt.io.touch Failed.\n"); + return -EIO; + } + sscanf(retval,"%d:",&Enable); + //check touch enable + if(Enable == 0){ + //printk("FT5x0x Touch Screen Is Disabled.\n"); + return -ENODEV; + } + + p = strchr(retval,':'); + p++; + if(strncmp(p,"ft5301",6)==0){//check touch ID + ft5x0x->id = FT5301; + ft5x0x->name = DEV_FT5301; + }else if(strncmp(p,"ft5406",6)==0){ + ft5x0x->id = FT5406; + ft5x0x->name = DEV_FT5406; + }else if(strncmp(p,"ft5206",6)==0){ + ft5x0x->id = FT5206; + ft5x0x->name = DEV_FT5206; + }else if(strncmp(p,"ft5606",6)==0){ + ft5x0x->id = FT5606; + ft5x0x->name = DEV_FT5606; + }else if(strncmp(p,"ft5306",6)==0){ + ft5x0x->id = FT5306; + ft5x0x->name = DEV_FT5306; + }else if(strncmp(p,"ft5302",6)==0){ + ft5x0x->id = FT5302; + ft5x0x->name = DEV_FT5302; + }else if(strncmp(p,"ft5",3)==0) + { + ft5x0x->id = FT5X0X; + ft5x0x->name = DEV_FT5X0X; + }else{ + printk("FT5x0x touch disabled.\n"); + return -ENODEV; + } + + s = strchr(p,':'); + strncpy(ft5x0x->cfg_name, p, s-p); + + p = s + 1; + sscanf(p,"%d:%d:%d:%d:%d:%d:%d:%d:%x", &ft5x0x->irqgpio, &ft5x0x->reslx, &ft5x0x->resly, &ft5x0x->rstgpio, &ft5x0x->swap, &ft5x0x->xch, &ft5x0x->ych, &ft5x0x->nt, &ft5x0x->addr); + + ft5x0x->irq = IRQ_GPIO; + printk("%s irqgpio=%d, reslx=%d, resly=%d, rstgpio=%d, swap=%d, xch=%d, ych=%d, nt=%d, addr=%x\n", ft5x0x->name, ft5x0x->irqgpio, ft5x0x->reslx, ft5x0x->resly, ft5x0x->rstgpio, ft5x0x->swap, ft5x0x->xch, ft5x0x->ych, ft5x0x->nt, ft5x0x->addr); + + memset(retval,0x00,sizeof(retval)); + ret = wmt_getsyspara("wmt.io.ts.upg", retval, &len); + if(!ret){ + ft5x0x->upg = 1; + strncpy(ft5x0x->fw_name, retval, sizeof(ft5x0x->fw_name)); + } + +#ifdef TOUCH_KEY + memset(retval,0x00,sizeof(retval)); + ret = wmt_getsyspara("wmt.io.tskey", retval, &len); + if(!ret){ + sscanf(retval,"%d:", &ft5x0x->nkeys); + p = strchr(retval,':'); + p++; + for(i=0; i < ft5x0x->nkeys; i++ ){ + sscanf(p,"%d:%d", &ft5x0x->tkey.ypos[i].y_lower, &ft5x0x->tkey.ypos[i].y_upper); + p = strchr(p,':'); + p++; + p = strchr(p,':'); + p++; + } + sscanf(p,"%d:%d:%d", &ft5x0x->tkey.axis, &ft5x0x->tkey.x_lower, &ft5x0x->tkey.x_upper); + ft5x0x->tskey_used = 1; + } +#endif + + memset(retval,0x00,sizeof(retval)); + ret = wmt_getsyspara("wmt.display.fb0", retval, &len); + if (!ret) { + int tmp[6]; + p = retval; + sscanf(p, "%d:[%d:%d:%d:%d:%d", &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5]); + if (tmp[4] > tmp[5]) + ft5x0x->lcd_exchg = 1; + } + + return 0; +} + +struct i2c_board_info ts_i2c_board_info = { + .type = TS_I2C_NAME, + .flags = 0x00, + .addr = FT5406_I2C_ADDR, + .platform_data = NULL, + .archdata = NULL, + .irq = -1, +}; + +static int ts_i2c_register_device (void) +{ + struct i2c_board_info *ts_i2c_bi; + struct i2c_adapter *adapter = NULL; + //struct i2c_client *client = NULL; + + //ts_i2c_board_info.addr = FT5406_I2C_ADDR; + ts_i2c_bi = &ts_i2c_board_info; + adapter = i2c_get_adapter(FT5X0X_I2C_BUS);/*in bus 1*/ + + if (NULL == adapter) { + printk("can not get i2c adapter, client address error\n"); + return -1; + } + l_client = i2c_new_device(adapter, ts_i2c_bi); + if (l_client == NULL) { + printk("allocate i2c client failed\n"); + return -1; + } + i2c_put_adapter(adapter); + return 0; +} + +static void ts_i2c_unregister_device(void) +{ + if (l_client != NULL) + { + i2c_unregister_device(l_client); + l_client = NULL; + } +} + +static int __init ft5x0x_init(void) +{ + int ret = -ENOMEM; + struct ft5x0x_data *ft5x0x=NULL; + + if (ts_i2c_register_device()<0) + { + dbg("Error to run ts_i2c_register_device()!\n"); + return -1; + } + + ft5x0x = kzalloc(sizeof(struct ft5x0x_data), GFP_KERNEL); + if(!ft5x0x){ + dbg_err("mem alloc failed.\n"); + return -ENOMEM; + } + + pContext = ft5x0x; + ret = check_touch_env(ft5x0x); + if(ret < 0) + goto exit_free_mem; + + ret = gpio_request(ft5x0x->irqgpio, "ts_irq"); + if (ret < 0) { + printk("gpio(%d) touchscreen irq request fail\n", ft5x0x->irqgpio); + goto exit_free_mem; + } + wmt_gpio_setpull(ft5x0x->irqgpio, WMT_GPIO_PULL_UP); + gpio_direction_input(ft5x0x->irqgpio); + + ret = gpio_request(ft5x0x->rstgpio, "ts_rst"); + if (ret < 0) { + printk("gpio(%d) touchscreen reset request fail\n", ft5x0x->rstgpio); + goto exit_free_irqgpio; + } + gpio_direction_output(ft5x0x->rstgpio, 1); + + + ret = platform_device_register(&ft5x0x_device); + if(ret){ + dbg_err("register platform drivver failed!\n"); + goto exit_free_gpio; + } + platform_set_drvdata(&ft5x0x_device, ft5x0x); + + ret = platform_driver_register(&ft5x0x_driver); + if(ret){ + dbg_err("register platform device failed!\n"); + goto exit_unregister_pdev; + } + + return ret; + +exit_unregister_pdev: + platform_device_unregister(&ft5x0x_device); +exit_free_gpio: + gpio_free(ft5x0x->rstgpio); +exit_free_irqgpio: + gpio_free(ft5x0x->irqgpio); +exit_free_mem: + kfree(ft5x0x); + pContext = NULL; + return ret; +} + +static void ft5x0x_exit(void) +{ + if(!pContext) return; + + gpio_free(pContext->rstgpio); + gpio_free(pContext->irqgpio); + platform_driver_unregister(&ft5x0x_driver); + platform_device_unregister(&ft5x0x_device); + kfree(pContext); + ts_i2c_unregister_device(); + return; +} + +late_initcall(ft5x0x_init); +module_exit(ft5x0x_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("FocalTech.Touch"); diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ft5x0x.h b/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ft5x0x.h new file mode 100755 index 00000000..03836b49 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ft5x0x.h @@ -0,0 +1,207 @@ +#ifndef __LINUX_FT5X0X_TS_H__ +#define __LINUX_FT5X0X_TS_H__ + +#define DEV_FT5206 "touch_ft5206" +#define DEV_FT5301 "touch_ft5301" +#define DEV_FT5302 "touch_ft5302" +#define DEV_FT5306 "touch_ft5306" +#define DEV_FT5406 "touch_ft5406" +#define DEV_FT5606 "touch_ft5606" + +#define DEV_FT5X0X "touch_ft5x0x" +#define TS_I2C_NAME "ft5x0x-ts" +#define FT5406_I2C_ADDR 0x38 +#define FT5X0X_I2C_BUS 0x01 + +enum FT5X0X_ID{ + FT5206 =1, + FT5301, + FT5302, + FT5306, + FT5406, + FT5606, + FT5X0X, +}; + +struct vt1603_ts_cal_info { + int a1; + int b1; + int c1; + int a2; + int b2; + int c2; + int delta; +}; + +#define SUPPORT_POINT_NUM 10 +struct ts_event { + int x[SUPPORT_POINT_NUM]; + int y[SUPPORT_POINT_NUM]; + int tid[SUPPORT_POINT_NUM]; + int tpoint; +}; + +#define TOUCH_KEY + +#ifdef TOUCH_KEY +#define NUM_KEYS 4 +struct key_pos{ + int y_lower; + int y_upper; +}; + +struct ts_key{ + int axis; + int x_lower; + int x_upper; + struct key_pos ypos[NUM_KEYS]; +}; +#endif + +struct ft5x0x_data { + int id; + unsigned int addr; + const char *name; + u8 fw_name[64]; + u8 cfg_name[32]; + + struct i2c_client *client; + struct input_dev *input_dev; + struct ts_event event; + struct work_struct read_work; + struct workqueue_struct *workqueue; + struct mutex ts_mutex; + struct kobject *kobj; + #ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif + int earlysus; + + int reslx; + int resly; + + int tw; + int th; + + int irq; + int irqgpio; + int rstgpio; +/* + int igp_idx; + int igp_bit; + + int rgp_idx; + int rgp_bit; +*/ + + int nt; + int nb; + int xch; + int ych; + int swap; + int lcd_exchg; + + int upg; + int load_cfg; + int dbg; +#ifdef TOUCH_KEY + int tskey_used; + int tkey_pressed; + int nkeys; + int tkey_idx; + struct ts_key tkey; +#endif + +}; + +enum ft5x0x_ts_regs { + FT5X0X_REG_THGROUP = 0x80, /* touch threshold, related to sensitivity */ + FT5X0X_REG_THPEAK = 0x81, + FT5X0X_REG_THCAL = 0x82, + FT5X0X_REG_THWATER = 0x83, + FT5X0X_REG_THTEMP = 0x84, + FT5X0X_REG_THDIFF = 0x85, + FT5X0X_REG_CTRL = 0x86, + FT5X0X_REG_TIMEENTERMONITOR = 0x87, + FT5X0X_REG_PERIODACTIVE = 0x88, /* report rate */ + FT5X0X_REG_PERIODMONITOR = 0x89, + FT5X0X_REG_HEIGHT_B = 0x8a, + FT5X0X_REG_MAX_FRAME = 0x8b, + FT5X0X_REG_DIST_MOVE = 0x8c, + FT5X0X_REG_DIST_POINT = 0x8d, + FT5X0X_REG_FEG_FRAME = 0x8e, + FT5X0X_REG_SINGLE_CLICK_OFFSET = 0x8f, + FT5X0X_REG_DOUBLE_CLICK_TIME_MIN = 0x90, + FT5X0X_REG_SINGLE_CLICK_TIME = 0x91, + FT5X0X_REG_LEFT_RIGHT_OFFSET = 0x92, + FT5X0X_REG_UP_DOWN_OFFSET = 0x93, + FT5X0X_REG_DISTANCE_LEFT_RIGHT = 0x94, + FT5X0X_REG_DISTANCE_UP_DOWN = 0x95, + FT5X0X_REG_ZOOM_DIS_SQR = 0x96, + FT5X0X_REG_RADIAN_VALUE =0x97, + FT5X0X_REG_MAX_X_HIGH = 0x98, + FT5X0X_REG_MAX_X_LOW = 0x99, + FT5X0X_REG_MAX_Y_HIGH = 0x9a, + FT5X0X_REG_MAX_Y_LOW = 0x9b, + FT5X0X_REG_K_X_HIGH = 0x9c, + FT5X0X_REG_K_X_LOW = 0x9d, + FT5X0X_REG_K_Y_HIGH = 0x9e, + FT5X0X_REG_K_Y_LOW = 0x9f, + FT5X0X_REG_AUTO_CLB_MODE = 0xa0, + FT5X0X_REG_LIB_VERSION_H = 0xa1, + FT5X0X_REG_LIB_VERSION_L = 0xa2, + FT5X0X_REG_CIPHER = 0xa3, + FT5X0X_REG_MODE = 0xa4, + FT5X0X_REG_PMODE = 0xa5, /* Power Consume Mode */ + FT5X0X_REG_FIRMID = 0xa6, /* Firmware version */ + FT5X0X_REG_STATE = 0xa7, + FT5X0X_REG_FT5201ID = 0xa8, + FT5X0X_REG_ERR = 0xa9, + FT5X0X_REG_CLB = 0xaa, +}; + +//FT5X0X_REG_PMODE +#define PMODE_ACTIVE 0x00 +#define PMODE_MONITOR 0x01 +#define PMODE_STANDBY 0x02 +#define PMODE_HIBERNATE 0x03 + +#define DEV_NAME "wmtts" +#define DEV_MAJOR 11 + +#define TS_IOC_MAGIC 't' +#define TS_IOCTL_CAL_START _IO(TS_IOC_MAGIC, 1) +#define TS_IOCTL_CAL_DONE _IOW(TS_IOC_MAGIC, 2, int*) +#define TS_IOCTL_GET_RAWDATA _IOR(TS_IOC_MAGIC, 3, int*) +#define TS_IOCTL_CAL_QUIT _IOW(TS_IOC_MAGIC, 4, int*) +#define TS_IOCTL_CAL_CAP _IOW(TS_IOC_MAGIC, 5, int*) +#define TS_IOC_MAXNR 5 + +extern int wmt_setsyspara(char *varname, unsigned char *varval); +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); +extern int wmt_i2c_xfer_continue_if_4(struct i2c_msg *msg, unsigned int num,int bus_id); + +//#define FT_DEBUG + +#undef dbg +#ifdef FT_DEBUG + #define dbg(fmt,args...) printk("DBG:%s_%d:"fmt,__FUNCTION__,__LINE__,##args) +#else + #define dbg(fmt,args...) +#endif + +#undef dbg_err +#define dbg_err(fmt,args...) printk("ERR:%s_%d:"fmt,__FUNCTION__,__LINE__,##args) + +//#define FTS_DBG +#ifdef FTS_DBG +#define DBG(fmt, args...) printk("[FTS]" fmt, ## args) +#else +#define DBG(fmt, args...) do{}while(0) +#endif + +#ifndef errlog +#define errlog(fmt, args...) printk(KERN_ERR "[%s:%d]: " fmt, __FUNCTION__,__LINE__, ## args) +#endif + +#endif diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ft5x0x_upg.c b/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ft5x0x_upg.c new file mode 100755 index 00000000..9db72130 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ft5x0x_upg.c @@ -0,0 +1,506 @@ +#include +#include +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include +#include +#include +#include +#include +#include +#include "ft5x0x.h" + +typedef enum +{ + ERR_OK, + ERR_MODE, + ERR_READID, + ERR_ERASE, + ERR_STATUS, + ERR_ECC, + ERR_DL_ERASE_FAIL, + ERR_DL_PROGRAM_FAIL, + ERR_DL_VERIFY_FAIL, + ERR_FMID +}E_UPGRADE_ERR_TYPE; + +#define FT5X_CTPM_ID_L 0X79 +#define FT5X_CTPM_ID_H 0X03 + +#define FT56_CTPM_ID_L 0X79 +#define FT56_CTPM_ID_H 0X06 + +#define FTS_PACKET_LENGTH 128 + +extern struct ft5x0x_data *pContext; +extern int ft5x0x_i2c_rxdata(char *rxdata, int length); +extern int ft5x0x_i2c_txdata(char *txdata, int length); + +static int ft5x0x_write_reg(u8 addr, u8 para) +{ + u8 buf[2]; + int ret = -1; + + buf[0] = addr; + buf[1] = para; + ret = ft5x0x_i2c_txdata(buf, 2); + if (ret <= 0) { + printk("write reg failed! %x ret: %d", buf[0], ret); + return -1; + } + + return 0; +} + +static int ft5x0x_read_reg(u8 addr, u8 *pdata) +{ + int ret; + u8 buf[2]; + struct i2c_msg msgs[2]; + + // + buf[0] = addr; //register address + + msgs[0].addr = pContext->addr; + msgs[0].flags = 0 | I2C_M_NOSTART; + msgs[0].len = 1; + msgs[0].buf = buf; + + msgs[1].addr = pContext->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = 1; + msgs[1].buf = pdata; + + //ret = wmt_i2c_xfer_continue_if_4(msgs, 2, FT5X0X_I2C_BUS); + ret = i2c_transfer(pContext->client->adapter, msgs, 2); + if (ret <= 0) + printk("msg %s i2c read error: %d\n", __func__, ret); + + return ret; + +} + + +/* +[function]: + send a command to ctpm. +[parameters]: + btcmd[in] :command code; + btPara1[in] :parameter 1; + btPara2[in] :parameter 2; + btPara3[in] :parameter 3; + num[in] :the valid input parameter numbers, if only command code needed and no parameters followed,then the num is 1; +[return]: + FTS_TRUE :success; + FTS_FALSE :io fail; +*/ +static u8 cmd_write(u8 *cmd,u8 num) +{ + return ft5x0x_i2c_txdata(cmd, num); +} + +/* +[function]: + write data to ctpm , the destination address is 0. +[parameters]: + pbt_buf[in] :point to data buffer; + bt_len[in] :the data numbers; +[return]: + FTS_TRUE :success; + FTS_FALSE :io fail; +*/ +static u8 byte_write(u8* pbt_buf, int dw_len) +{ + + return ft5x0x_i2c_txdata( pbt_buf, dw_len); +} + +/* +[function]: + read out data from ctpm,the destination address is 0. +[parameters]: + pbt_buf[out] :point to data buffer; + bt_len[in] :the data numbers; +[return]: + FTS_TRUE :success; + FTS_FALSE :io fail; +*/ +static u8 byte_read(u8* pbt_buf, u8 bt_len) +{ + int ret; + struct i2c_msg msg[1]; + + msg[0].addr = pContext->addr; + msg[0].flags = I2C_M_RD; + msg[0].len = bt_len; + msg[0].buf = pbt_buf; + + ret = i2c_transfer(pContext->client->adapter, msg, 1); + //ret = wmt_i2c_xfer_continue_if_4(msg, 1, FT5X0X_I2C_BUS); + if (ret <= 0) + printk("msg i2c read error: %d\n", ret); + + return ret; +} + + +/* +[function]: + burn the FW to ctpm. +[parameters]:(ref. SPEC) + pbt_buf[in] :point to Head+FW ; + dw_lenth[in]:the length of the FW + 6(the Head length); + bt_ecc[in] :the ECC of the FW +[return]: + ERR_OK :no error; + ERR_MODE :fail to switch to UPDATE mode; + ERR_READID :read id fail; + ERR_ERASE :erase chip fail; + ERR_STATUS :status error; + ERR_ECC :ecc error. +*/ +static E_UPGRADE_ERR_TYPE ft5x0x_fw_upgrade(struct ft5x0x_data *ft5x0x, u8* pbt_buf, int dw_lenth) +{ + int i = 0,j = 0,i_ret; + int packet_number; + int temp,lenght; + u8 packet_buf[FTS_PACKET_LENGTH + 6]; + u8 auc_i2c_write_buf[10]; + u8 reg_val[2] = {0}; + u8 ctpm_id[2] = {0}; + u8 cmd[4]; + u8 bt_ecc; + + /*********Step 1:Reset CTPM *****/ + /*write 0xaa to register 0xfc*/ + ft5x0x_write_reg(0xfc,0xaa); + msleep(50); + /*write 0x55 to register 0xfc*/ + ft5x0x_write_reg(0xfc,0x55); + printk("[FTS] Step 1: Reset CTPM.\n"); + msleep(30); + + /*********Step 2:Enter upgrade mode *****/ + auc_i2c_write_buf[0] = 0x55; + auc_i2c_write_buf[1] = 0xaa; + do{ + i ++; + i_ret = byte_write(auc_i2c_write_buf, 2); + mdelay(5); + }while(i_ret <= 0 && i < 5 ); + msleep(20); + + /*********Step 3:check READ-ID**********/ + if(ft5x0x->id == FT5606){ + ctpm_id[0] = FT56_CTPM_ID_L; + ctpm_id[1] = FT56_CTPM_ID_H; + }else{ + ctpm_id[0] = FT5X_CTPM_ID_L; + ctpm_id[1] = FT5X_CTPM_ID_H; + } + + cmd[0] = 0x90; + cmd[1] = 0x00; + cmd[2] = 0x00; + cmd[3] = 0x00; + cmd_write(cmd,4); + byte_read(reg_val,2); + if (reg_val[0] == ctpm_id[0] && reg_val[1] == ctpm_id[1]){ + printk("[FTS] Step 3: CTPM ID,ID1 = 0x%x,ID2 = 0x%x\n",reg_val[0],reg_val[1]); + }else{ + printk("[FTS] ID_ERROR: CTPM ID,ID1 = 0x%x,ID2 = 0x%x\n",reg_val[0],reg_val[1]); + return ERR_READID; + } + + cmd[0] = 0xcd; + cmd_write(cmd,1); + byte_read(reg_val,1); + printk("[FTS] bootloader version = 0x%x\n", reg_val[0]); + + /******Step 4:erase app and panel paramenter area *********/ + cmd[0] = 0x61; + cmd_write(cmd,1); //erase app area + msleep(1500); + cmd[0] = 0x63; + cmd_write(cmd,1); //erase panel parameter area + msleep(100); + printk("[FTS] Step 4: erase. \n"); + + /*********Step 5:write firmware(FW) to ctpm flash*********/ + bt_ecc = 0; + printk("[FTS] Step 5: start upgrade. \n"); + dw_lenth = dw_lenth - 8; + packet_number = (dw_lenth) / FTS_PACKET_LENGTH; + packet_buf[0] = 0xbf; + packet_buf[1] = 0x00; + for (j=0;j>8); + packet_buf[3] = (u8)temp; + lenght = FTS_PACKET_LENGTH; + packet_buf[4] = (u8)(lenght>>8); + packet_buf[5] = (u8)lenght; + + for (i=0;i 0){ + temp = packet_number * FTS_PACKET_LENGTH; + packet_buf[2] = (u8)(temp>>8); + packet_buf[3] = (u8)temp; + + temp = (dw_lenth) % FTS_PACKET_LENGTH; + packet_buf[4] = (u8)(temp>>8); + packet_buf[5] = (u8)temp; + + for (i=0;i>8); + packet_buf[3] = (u8)temp; + temp =1; + packet_buf[4] = (u8)(temp>>8); + packet_buf[5] = (u8)temp; + packet_buf[6] = pbt_buf[ dw_lenth + i]; + bt_ecc ^= packet_buf[6]; + + byte_write(&packet_buf[0],7); + mdelay(20); + } + + /*********Step 6: read out checksum********************/ + /*send the opration head*/ + cmd[0] = 0xcc; + cmd_write(cmd,1); + byte_read(reg_val,1); + printk("[FTS] Step 6:read ECC 0x%x, firmware ECC 0x%x. \n", reg_val[0], bt_ecc); + if(reg_val[0] != bt_ecc){ + return ERR_ECC; + } + + /*********Step 7: reset the new FW***********************/ + cmd[0] = 0x07; + cmd_write(cmd,1); + + msleep(300); //make sure CTP startup normally + + return ERR_OK; +} + +int ft5x0x_auto_clb(void) +{ + u8 uc_temp; + u8 i ; + + printk("[FTS] start auto CLB.\n"); + msleep(200); + ft5x0x_write_reg(0, 0x40); + msleep(100); //make sure already enter factory mode + ft5x0x_write_reg(2, 0x4); //write command to start calibration + msleep(300); + for(i=0;i<100;i++){ + ft5x0x_read_reg(0,&uc_temp); + if ( ((uc_temp&0x70)>>4) == 0x0){ //return to normal mode, calibration finish + break; + } + msleep(200); + printk("[FTS] waiting calibration %d\n",i); + } + printk("[FTS] calibration OK.\n"); + + msleep(300); + ft5x0x_write_reg(0, 0x40); //goto factory mode + msleep(100); //make sure already enter factory mode + ft5x0x_write_reg(2, 0x5); //store CLB result + msleep(300); + ft5x0x_write_reg(0, 0x0); //return to normal mode + msleep(300); + printk("[FTS] store CLB result OK.\n"); + return 0; +} + +static int ft5x0x_get_bin_ver(const u8 *fw, int fw_szie) +{ + if (fw_szie > 2){ + return fw[fw_szie - 2]; + }else{ + return 0xff; //default value + } + return 0xff; +} + +int ft5x0x_read_fw_ver(void) +{ + u8 ver=0; + int ret=0; + + ret = ft5x0x_read_reg(FT5X0X_REG_FIRMID, &ver); + if(ret > 0) + return ver; + + return ret; +} + + +static int ft5x0x_get_fw_szie(const char *fw_name) +{ + struct file *pfile = NULL; + struct inode *inode; + unsigned long magic; + off_t fsize = 0; + + if(fw_name == NULL){ + dbg_err("Firmware name error.\n"); + return -EFAULT; + } + + if (NULL == pfile) + pfile = filp_open(fw_name, O_RDONLY, 0); + + if (IS_ERR(pfile)) { + dbg_err("File open error: %s.\n", fw_name); + return -EIO; + } + + inode = pfile->f_dentry->d_inode; + magic = inode->i_sb->s_magic; + fsize = inode->i_size; + filp_close(pfile, NULL); + return fsize; +} + +static int ft5x0x_read_fw(const char *fw_name, u8 *buf) +{ + struct file *pfile = NULL; + struct inode *inode; + unsigned long magic; + off_t fsize; + loff_t pos; + mm_segment_t fs; + + if(fw_name == NULL){ + dbg_err("Firmware name error.\n"); + return -EFAULT; + } + + if (NULL == pfile) + pfile = filp_open(fw_name, O_RDONLY, 0); + if (IS_ERR(pfile)) { + dbg_err("File open error: %s.\n", fw_name); + return -EIO; + } + + inode = pfile->f_dentry->d_inode; + magic = inode->i_sb->s_magic; + fsize = inode->i_size; + fs = get_fs(); + set_fs(KERNEL_DS); + pos = 0; + vfs_read(pfile, buf, fsize, &pos); + filp_close(pfile, NULL); + set_fs(fs); + + return 0; +} + +#define FW_SUFFFIX ".bin" +#define SD_UPG_BIN_PATH "/sdcard/_wmt_ft5x0x_fw_app.bin" +#define FS_UPG_BIN_PATH "/lib/firmware/" + +int ft5x0x_upg_fw_bin(struct ft5x0x_data *ft5x0x, int check_ver) +{ + int i_ret = 0; + int fwsize = 0; + int hw_fw_ver; + int bin_fw_ver; + int do_upg; + u8 *pbt_buf = NULL; + u8 fw_path[128] = {0}; + + if(ft5x0x->upg) + sprintf(fw_path,"%s%s%s", FS_UPG_BIN_PATH, ft5x0x->fw_name,FW_SUFFFIX);//get fw binary file from filesystem + else + strcpy(fw_path,SD_UPG_BIN_PATH); //get fw binary file from SD card + + fwsize = ft5x0x_get_fw_szie(fw_path); + if (fwsize <= 0) { + dbg_err("Get firmware size failed\n"); + return -EIO; + } + + if (fwsize < 8 || fwsize > 32 * 1024) { + dbg_err("FW length error\n"); + return -EIO; + } + + pbt_buf = kmalloc(fwsize + 1, GFP_KERNEL); + if (ft5x0x_read_fw(fw_path, pbt_buf)) { + dbg_err("Request_firmware failed\n"); + i_ret = -EIO; + goto exit; + } + + hw_fw_ver =ft5x0x_read_fw_ver(); + if(hw_fw_ver <= 0){ + dbg_err("Read firmware version failed\n"); + i_ret = hw_fw_ver; + goto exit; + } + + bin_fw_ver = ft5x0x_get_bin_ver(pbt_buf, fwsize); + printk("[FTS] hardware fw ver 0x%0x, binary ver 0x%0x\n",hw_fw_ver, bin_fw_ver); + + if(check_ver){ + if(hw_fw_ver == 0xa6 || hw_fw_ver < bin_fw_ver) + do_upg = 1; + else + do_upg = 0; + }else{ + do_upg = 1; + } + + if(do_upg){ + if ((pbt_buf[fwsize - 8] ^ pbt_buf[fwsize - 6]) == 0xFF && + (pbt_buf[fwsize - 7] ^ pbt_buf[fwsize - 5]) == 0xFF && + (pbt_buf[fwsize - 3] ^ pbt_buf[fwsize - 4]) == 0xFF) { + i_ret = ft5x0x_fw_upgrade(ft5x0x, pbt_buf, fwsize); + if (i_ret) + dbg_err("Upgrade failed, i_ret=%d\n",i_ret); + else { + hw_fw_ver = ft5x0x_read_fw_ver(); + printk("[FTS] upgrade to new version 0x%x\n", hw_fw_ver); + } + } else { + dbg_err("FW format error\n"); + } + } + + ft5x0x_auto_clb();/*start auto CLB*/ + +exit: + kfree(pbt_buf); + return i_ret; +} + + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ini.c b/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ini.c new file mode 100755 index 00000000..a4f8dc38 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ini.c @@ -0,0 +1,406 @@ +#include +#include +#include + +#include "ini.h" + + +char CFG_SSL = '['; /* Ïî±êÖ¾·ûSection Symbol --¿É¸ù¾ÝÌØÊâÐèÒª½øÐж¨Òå¸ü¸Ä£¬Èç { }µÈ*/ +char CFG_SSR = ']'; /* Ïî±êÖ¾·ûSection Symbol --¿É¸ù¾ÝÌØÊâÐèÒª½øÐж¨Òå¸ü¸Ä£¬Èç { }µÈ*/ +char CFG_NIS = ':'; /* name Óë index Ö®¼äµÄ·Ö¸ô·û */ +char CFG_NTS = '#'; /* ×¢ÊÍ·û*/ + +static char * ini_str_trim_r(char * buf); +static char * ini_str_trim_l(char * buf); +static int ini_file_get_line(char *filedata, char *buffer, int maxlen); +static int ini_split_key_value(char *buf, char **key, char **val); +static long atol(char *nptr); + + +/************************************************************* +Function: »ñµÃkeyµÄÖµ +Input: char * filedata¡¡Îļþ£»char * section¡¡ÏîÖµ£»char * key¡¡¼üÖµ +Output: char * value¡¡keyµÄÖµ +Return: 0 SUCCESS + -1 δÕÒµ½section + -2 δÕÒµ½key + -10 Îļþ´ò¿ªÊ§°Ü + -12 ¶ÁÈ¡Îļþʧ°Ü + -14 Îļþ¸ñʽ´íÎó + -22 ³¬³ö»º³åÇø´óС +Note: +*************************************************************/ +int ini_get_key(char *filedata, char * section, char * key, char * value) +{ + //char buf1[MAX_CFG_BUF + 1], buf2[MAX_CFG_BUF + 1]; + char *buf1, *buf2; + char *key_ptr, *val_ptr; + int n, ret; + int dataoff = 0; + + *value='\0'; + + buf1 = kzalloc(MAX_CFG_BUF + 1, GFP_KERNEL); + if(!buf1){ + printk("buf1: mem alloc failed.\n"); + return -ENOMEM; + } + buf2 = kzalloc(MAX_CFG_BUF + 1, GFP_KERNEL); + if(!buf2){ + printk("buf2: mem alloc failed.\n"); + kfree(buf1); + return -ENOMEM; + } + + while(1) { /* ËÑÕÒÏîsection */ + ret = CFG_ERR_READ_FILE; + n = ini_file_get_line(filedata+dataoff, buf1, MAX_CFG_BUF); + dataoff += n; + if(n < -1) + goto r_cfg_end; + ret = CFG_SECTION_NOT_FOUND; + if(n < 0) + goto r_cfg_end; /* Îļþβ£¬Î´·¢ÏÖ */ + + n = strlen(ini_str_trim_l(ini_str_trim_r(buf1))); + if(n == 0 || buf1[0] == CFG_NTS) + continue; /* ¿ÕÐÐ »ò ×¢ÊÍÐÐ */ + + ret = CFG_ERR_FILE_FORMAT; + if(n > 2 && ((buf1[0] == CFG_SSL && buf1[n-1] != CFG_SSR))) + goto r_cfg_end; + if(buf1[0] == CFG_SSL) { + buf1[n-1] = 0x00; + if(strcmp(buf1+1, section) == 0) + break; /* ÕÒµ½Ïîsection */ + } + } + + while(1){ /* ËÑÕÒkey */ + ret = CFG_ERR_READ_FILE; + n = ini_file_get_line(filedata+dataoff, buf1, MAX_CFG_BUF); + dataoff += n; + if(n < -1) + goto r_cfg_end; + ret = CFG_KEY_NOT_FOUND; + if(n < 0) + goto r_cfg_end;/* Îļþβ£¬Î´·¢ÏÖkey */ + + n = strlen(ini_str_trim_l(ini_str_trim_r(buf1))); + if(n == 0 || buf1[0] == CFG_NTS) + continue; /* ¿ÕÐÐ »ò ×¢ÊÍÐÐ */ + ret = CFG_KEY_NOT_FOUND; + if(buf1[0] == CFG_SSL) + goto r_cfg_end; + if(buf1[n-1] == '+') { /* Óö+ºÅ±íʾÏÂÒ»ÐмÌÐø */ + buf1[n-1] = 0x00; + while(1) { + ret = CFG_ERR_READ_FILE; + n = ini_file_get_line(filedata+dataoff, buf2, MAX_CFG_BUF); + dataoff += n; + if(n < -1) + goto r_cfg_end; + if(n < 0) + break;/* Îļþ½áÊø */ + + n = strlen(ini_str_trim_r(buf2)); + ret = CFG_ERR_EXCEED_BUF_SIZE; + if(n > 0 && buf2[n-1] == '+'){/* Óö+ºÅ±íʾÏÂÒ»ÐмÌÐø */ + buf2[n-1] = 0x00; + if( (strlen(buf1) + strlen(buf2)) > MAX_CFG_BUF) + goto r_cfg_end; + strcat(buf1, buf2); + continue; + } + if(strlen(buf1) + strlen(buf2) > MAX_CFG_BUF) + goto r_cfg_end; + strcat(buf1, buf2); + break; + } + } + ret = CFG_ERR_FILE_FORMAT; + if(ini_split_key_value(buf1, &key_ptr, &val_ptr) != 1) + goto r_cfg_end; + ini_str_trim_l(ini_str_trim_r(key_ptr)); + if(strcmp(key_ptr, key) != 0) + continue; /* ºÍkeyÖµ²»Æ¥Åä */ + strcpy(value, val_ptr); + break; + } + ret = CFG_OK; +r_cfg_end: + //if(fp != NULL) fclose(fp); + kfree(buf1); + kfree(buf2); + return ret; +} +/************************************************************* +Function: »ñµÃËùÓÐsection +Input: char *filename¡¡Îļþ,int max ×î´ó¿É·µ»ØµÄsectionµÄ¸öÊý +Output: char *sections[]¡¡´æ·ÅsectionÃû×Ö +Return: ·µ»Øsection¸öÊý¡£Èô³ö´í£¬·µ»Ø¸ºÊý¡£ + -10 Îļþ´ò¿ª³ö´í + -12 Îļþ¶ÁÈ¡´íÎó + -14 Îļþ¸ñʽ´íÎó +Note: +*************************************************************/ +int ini_get_sections(char *filedata, unsigned char * sections[], int max) +{ + //FILE *fp; + char buf1[MAX_CFG_BUF + 1]; + int n, n_sections = 0, ret; + int dataoff = 0; + +// if((fp = fopen(filename, "rb")) == NULL) +// return CFG_ERR_OPEN_FILE; + + while(1) {/*ËÑÕÒÏîsection */ + ret = CFG_ERR_READ_FILE; + n = ini_file_get_line(filedata+dataoff, buf1, MAX_CFG_BUF); + dataoff += n; + if(n < -1) + goto cfg_scts_end; + if(n < 0) + break;/* Îļþβ */ + n = strlen(ini_str_trim_l(ini_str_trim_r(buf1))); + if(n == 0 || buf1[0] == CFG_NTS) + continue; /* ¿ÕÐÐ »ò ×¢ÊÍÐÐ */ + ret = CFG_ERR_FILE_FORMAT; + if(n > 2 && ((buf1[0] == CFG_SSL && buf1[n-1] != CFG_SSR))) + goto cfg_scts_end; + if(buf1[0] == CFG_SSL) { + if (max!=0){ + buf1[n-1] = 0x00; + strcpy((char *)sections[n_sections], buf1+1); + if (n_sections>=max) + break; /* ³¬¹ý¿É·µ»Ø×î´ó¸öÊý */ + } + n_sections++; + } + + } + ret = n_sections; +cfg_scts_end: +// if(fp != NULL) +// fclose(fp); + return ret; +} + + +/************************************************************* +Function: È¥³ý×Ö·û´®ÓұߵĿÕ×Ö·û +Input: char * buf ×Ö·û´®Ö¸Õë +Output: +Return: ×Ö·û´®Ö¸Õë +Note: +*************************************************************/ +static char * ini_str_trim_r(char * buf) +{ + int len,i; + char tmp[128]; + + memset(tmp, 0, sizeof(tmp)); + len = strlen(buf); +// tmp = (char *)malloc(len); + + memset(tmp,0x00,len); + for(i = 0;i < len;i++) { + if (buf[i] !=' ') + break; + } + if (i < len) { + strncpy(tmp,(buf+i),(len-i)); + } + strncpy(buf,tmp,len); +// free(tmp); + return buf; +} + +/************************************************************* +Function: È¥³ý×Ö·û´®×ó±ßµÄ¿Õ×Ö·û +Input: char * buf ×Ö·û´®Ö¸Õë +Output: +Return: ×Ö·û´®Ö¸Õë +Note: +*************************************************************/ +static char * ini_str_trim_l(char * buf) +{ + int len,i; + char tmp[128]; + + memset(tmp, 0, sizeof(tmp)); + len = strlen(buf); + //tmp = (char *)malloc(len); + + memset(tmp,0x00,len); + + for(i = 0;i < len;i++) { + if (buf[len-i-1] !=' ') + break; + } + if (i < len) { + strncpy(tmp,buf,len-i); + } + strncpy(buf,tmp,len); + //free(tmp); + return buf; +} +/************************************************************* +Function: ´ÓÎļþÖжÁÈ¡Ò»ÐÐ +Input: FILE *fp Îļþ¾ä±ú£»int maxlen »º³åÇø×î´ó³¤¶È +Output: char *buffer Ò»ÐÐ×Ö·û´® +Return: >0 ʵ¼Ê¶ÁµÄ³¤¶È + -1 Îļþ½áÊø + -2 ¶ÁÎļþ³ö´í +Note: +*************************************************************/ +static int ini_file_get_line(char *filedata, char *buffer, int maxlen) +{ + int i, j; + char ch1; + + for(i=0, j=0; i= n) + return 0; + + if(buf[i] == '=') + return -1; + + k1 = i; + for(i++; i < n; i++) + if(buf[i] == '=') + break; + + if(i >= n) + return -2; + k2 = i; + + for(i++; i < n; i++) + if(buf[i] != ' ' && buf[i] != '\t') + break; + + buf[k2] = '\0'; + + *key = buf + k1; + *val = buf + i; + return 1; +} + +int my_atoi(const char *str) +{ + int result = 0; + int signal = 1; /* ĬÈÏΪÕýÊý */ + if((*str>='0'&&*str<='9')||*str=='-'||*str=='+') { + if(*str=='-'||*str=='+') { + if(*str=='-') + signal = -1; /*ÊäÈ븺Êý*/ + str++; + } + } + else + return 0; + /*¿ªÊ¼×ª»»*/ + while(*str>='0' && *str<='9') + result = result*10 + (*str++ - '0' ); + + return signal*result; +} + +int isspace(int x) +{ + if(x==' '||x=='\t'||x=='\n'||x=='\f'||x=='\b'||x=='\r') + return 1; + else + return 0; +} + +int isdigit(int x) +{ + if(x<='9' && x>='0') + return 1; + else + return 0; + +} + +static long atol(char *nptr) +{ + int c; /* current char */ + long total; /* current total */ + int sign; /* if ''-'', then negative, otherwise positive */ + /* skip whitespace */ + while ( isspace((int)(unsigned char)*nptr) ) + ++nptr; + c = (int)(unsigned char)*nptr++; + sign = c; /* save sign indication */ + if (c == '-' || c == '+') + c = (int)(unsigned char)*nptr++; /* skip sign */ + total = 0; + while (isdigit(c)) { + total = 10 * total + (c - '0'); /* accumulate digit */ + c = (int)(unsigned char)*nptr++; /* get next char */ + } + if (sign == '-') + return -total; + else + return total; /* return result, negated if necessary */ +} +/*** +*int atoi(char *nptr) - Convert string to long +* +*Purpose: +* Converts ASCII string pointed to by nptr to binary. +* Overflow is not detected. Because of this, we can just use +* atol(). +* +*Entry: +* nptr = ptr to string to convert +* +*Exit: +* return int value of the string +* +*Exceptions: +* None - overflow is not detected. +* +*******************************************************************************/ +int atoi(char *nptr) +{ + return (int)atol(nptr); +} + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ini.h b/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ini.h new file mode 100755 index 00000000..72434b53 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ini.h @@ -0,0 +1,43 @@ +#ifndef INI_H +#define INI_H + +#define MAX_CFG_BUF 512 +#define SUCCESS 0 +/* return value */ +#define CFG_OK SUCCESS +#define CFG_SECTION_NOT_FOUND -1 +#define CFG_KEY_NOT_FOUND -2 +#define CFG_ERR -10 + +#define CFG_ERR_OPEN_FILE -10 +#define CFG_ERR_CREATE_FILE -11 +#define CFG_ERR_READ_FILE -12 +#define CFG_ERR_WRITE_FILE -13 +#define CFG_ERR_FILE_FORMAT -14 + + +#define CFG_ERR_EXCEED_BUF_SIZE -22 + +#define COPYF_OK SUCCESS +#define COPYF_ERR_OPEN_FILE -10 +#define COPYF_ERR_CREATE_FILE -11 +#define COPYF_ERR_READ_FILE -12 +#define COPYF_ERR_WRITE_FILE -13 + + +struct ini_key_location { + int ini_section_line_no; + int ini_key_line_no; + int ini_key_lines; +}; + + +int ini_get_key(char *filedata, char * section, char * key, char * value); +int ini_get_sections(char *filedata, unsigned char * sections[], int max); + +int ini_split_section(char *section, char **name, char **index); +//int ini_join_section(char **section, char *name, char *index); + +int atoi(char *nptr); + +#endif diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/Kconfig b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/Kconfig new file mode 100755 index 00000000..eb11a558 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/Kconfig @@ -0,0 +1,11 @@ +config TOUCHSCREEN_FT6X0X + tristate "FT5X0X Capacity Touchscreen Device Support" + default y + depends on ARCH_WMT + ---help--- + Say Y here if you have an WMT based board with touchscreen + attached to it. + If unsure, say N. + To compile this driver as a module, choose M here: the + module will be called ft5x0x. + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/Makefile b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/Makefile new file mode 100755 index 00000000..859008b8 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/Makefile @@ -0,0 +1,34 @@ +KERNELDIR=../../../../ +CROSS = arm_1103_le- +CC= $(CROSS)gcc +LD= $(CROSS)ld +STRIP = $(CROSS)strip + +DEBUG = n + +# Add your debugging flag (or not) to EXTRA_CFLAGS +ifeq ($(DEBUG),y) +# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines +DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines + +else + DEBFLAGS = -O2 -Wall +endif + +EXTRA_CFLAGS += $(DEBFLAGS) + + +MY_MODULE_NAME=s_wmt_ts_ft6x0x + +#obj-$(CONFIG_TOUCHSCREEN_FT5X0X) := $(MY_MODULE_NAME).o +obj-m := $(MY_MODULE_NAME).o +$(MY_MODULE_NAME)-objs := ft5x0x.o ft5x0x_upg.o ft5402_config.o ft6x06_ex_fun.o ini.o ft6x06_ts.o + +default: + $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules + $(STRIP) --strip-debug $(MY_MODULE_NAME).ko + @rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions *.order *.symvers + +clean: + @rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/focaltech_ctl.h b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/focaltech_ctl.h new file mode 100755 index 00000000..7c58a15a --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/focaltech_ctl.h @@ -0,0 +1,27 @@ +#ifndef __FOCALTECH_CTL_H__ +#define __FOCALTECH_CTL_H__ + +#define FT_RW_IIC_DRV "ft_rw_iic_drv" +#define FT_RW_IIC_DRV_MAJOR 210 /*Ô¤ÉèµÄft_rw_iic_drvµÄÖ÷É豸ºÅ*/ + +#define FT_I2C_RDWR_MAX_QUEUE 36 +#define FT_I2C_SLAVEADDR 11 +#define FT_I2C_RW 12 +#define FT_RESET_TP 13 + +typedef struct ft_rw_i2c +{ + u8 *buf; + u8 flag; /*0-write 1-read*/ + __u16 length; //the length of data +}*pft_rw_i2c; + +typedef struct ft_rw_i2c_queue +{ + struct ft_rw_i2c __user *i2c_queue; + int queuenum; +}*pft_rw_i2c_queue; + +int ft_rw_iic_drv_init(struct i2c_client *client); +void ft_rw_iic_drv_exit(void); +#endif \ No newline at end of file diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft5402_config.c b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft5402_config.c new file mode 100755 index 00000000..58683ebd --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft5402_config.c @@ -0,0 +1,2295 @@ +#include "ft5402_config.h" +//#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "ini.h" +#include "ft5402_ini_config.h" +#include "ft5x0x.h" + + +extern int ft5x0x_i2c_txdata(char *txdata, int length); + +int ft5402_write_reg(struct i2c_client * client, u8 regaddr, u8 regvalue) +{ + unsigned char buf[2] = {0}; + buf[0] = regaddr; + buf[1] = regvalue; + + return ft5x0x_i2c_txdata(buf, 2); +} + +int ft5402_read_reg(struct i2c_client * client, u8 regaddr, u8 * regvalue) +{ + int ret; + + struct i2c_msg msgs[] = { + { + .addr = client->addr, + .flags = 0, + .len = 1, + .buf = ®addr, + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = 1, + .buf = regvalue, + }, + }; + ret = i2c_transfer(client->adapter, msgs, 2); + if (ret < 0) + pr_err("function:%s. i2c read error: %d\n", __func__, ret); + return ret; +} + +/*set tx order +*@txNO: offset from tx order start +*@txNO1: tx NO. +*/ +static int ft5402_set_tx_order(struct i2c_client * client, u8 txNO, u8 txNO1) +{ + unsigned char ReCode = 0; + if (txNO < FT5402_TX_TEST_MODE_1) + ReCode = ft5402_write_reg(client, FT5402_REG_TX_ORDER_START + txNO, + txNO1); + else { + ReCode = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, + FT5402_REG_TEST_MODE_2<<4); /*enter Test mode 2*/ + if (ReCode >= 0) + ReCode = ft5402_write_reg(client, + FT5402_REG_TX_ORDER_START + txNO - FT5402_TX_TEST_MODE_1, + txNO1); + ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, + FT5402_REG_TEST_MODE<<4); /*enter Test mode*/ + } + return ReCode; +} + +/*set tx order +*@txNO: offset from tx order start +*@pTxNo: return value of tx NO. +*/ +static int ft5402_get_tx_order(struct i2c_client * client, u8 txNO, u8 *pTxNo) +{ + unsigned char ReCode = 0; + if (txNO < FT5402_TX_TEST_MODE_1) + ReCode = ft5402_read_reg(client, FT5402_REG_TX_ORDER_START + txNO, + pTxNo); + else { + ReCode = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, + FT5402_REG_TEST_MODE_2<<4); /*enter Test mode 2*/ + if(ReCode >= 0) + ReCode = ft5402_read_reg(client, + FT5402_REG_TX_ORDER_START + txNO - FT5402_TX_TEST_MODE_1, + pTxNo); + ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, + FT5402_REG_TEST_MODE<<4); /*enter Test mode*/ + } + return ReCode; +} + +/*set tx cap +*@txNO: tx NO. +*@cap_value: value of cap +*/ +static int ft5402_set_tx_cap(struct i2c_client * client, u8 txNO, u8 cap_value) +{ + unsigned char ReCode = 0; + if (txNO < FT5402_TX_TEST_MODE_1) + ReCode = ft5402_write_reg(client, FT5402_REG_TX_CAP_START + txNO, + cap_value); + else { + ReCode = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, + FT5402_REG_TEST_MODE_2<<4); /*enter Test mode 2*/ + if (ReCode >= 0) + ReCode = ft5402_write_reg(client, + FT5402_REG_TX_CAP_START + txNO - FT5402_TX_TEST_MODE_1, + cap_value); + ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, + FT5402_REG_TEST_MODE<<4); /*enter Test mode*/ + } + return ReCode; +} + +/*get tx cap*/ +static int ft5402_get_tx_cap(struct i2c_client * client, u8 txNO, u8 *pCap) +{ + unsigned char ReCode = 0; + if (txNO < FT5402_TX_TEST_MODE_1) + ReCode = ft5402_read_reg(client, FT5402_REG_TX_CAP_START + txNO, + pCap); + else { + ReCode = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, + FT5402_REG_TEST_MODE_2<<4); /*enter Test mode 2*/ + if (ReCode >= 0) + ReCode = ft5402_read_reg(client, + FT5402_REG_TX_CAP_START + txNO - FT5402_TX_TEST_MODE_1, + pCap); + ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, + FT5402_REG_TEST_MODE<<4); /*enter Test mode*/ + } + return ReCode; +} + +/*set tx offset*/ +static int ft5402_set_tx_offset(struct i2c_client * client, u8 txNO, u8 offset_value) +{ + unsigned char temp=0; + unsigned char ReCode = 0; + if (txNO < FT5402_TX_TEST_MODE_1) { + ReCode = ft5402_read_reg(client, + FT5402_REG_TX_OFFSET_START + (txNO>>1), &temp); + if (ReCode >= 0) { + if (txNO%2 == 0) + ReCode = ft5402_write_reg(client, + FT5402_REG_TX_OFFSET_START + (txNO>>1), + (temp&0xf0) + (offset_value&0x0f)); + else + ReCode = ft5402_write_reg(client, + FT5402_REG_TX_OFFSET_START + (txNO>>1), + (temp&0x0f) + (offset_value<<4)); + } + } else { + ReCode = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, + FT5402_REG_TEST_MODE_2<<4); /*enter Test mode 2*/ + if (ReCode >= 0) { + ReCode = ft5402_read_reg(client, + FT5402_REG_DEVICE_MODE+((txNO-FT5402_TX_TEST_MODE_1)>>1), + &temp); /*enter Test mode 2*/ + if (ReCode >= 0) { + if(txNO%2 == 0) + ReCode = ft5402_write_reg(client, + FT5402_REG_TX_OFFSET_START+((txNO-FT5402_TX_TEST_MODE_1)>>1), + (temp&0xf0)+(offset_value&0x0f)); + else + ReCode = ft5402_write_reg(client, + FT5402_REG_TX_OFFSET_START+((txNO-FT5402_TX_TEST_MODE_1)>>1), + (temp&0xf0)+(offset_value<<4)); + } + } + ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, + FT5402_REG_TEST_MODE<<4); /*enter Test mode*/ + } + + return ReCode; +} + +/*get tx offset*/ +static int ft5402_get_tx_offset(struct i2c_client * client, u8 txNO, u8 *pOffset) +{ + unsigned char temp=0; + unsigned char ReCode = 0; + if (txNO < FT5402_TX_TEST_MODE_1) + ReCode = ft5402_read_reg(client, + FT5402_REG_TX_OFFSET_START + (txNO>>1), &temp); + else { + ReCode = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, + FT5402_REG_TEST_MODE_2<<4); /*enter Test mode 2*/ + if (ReCode >= 0) + ReCode = ft5402_read_reg(client, + FT5402_REG_TX_OFFSET_START+((txNO-FT5402_TX_TEST_MODE_1)>>1), + &temp); + ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, + FT5402_REG_TEST_MODE<<4); /*enter Test mode*/ + } + + if (ReCode >= 0) + (txNO%2 == 0) ? (*pOffset = (temp&0x0f)) : (*pOffset = (temp>>4)); + return ReCode; +} + +/*set rx order*/ +static int ft5402_set_rx_order(struct i2c_client * client, u8 rxNO, u8 rxNO1) +{ + unsigned char ReCode = 0; + ReCode = ft5402_write_reg(client, FT5402_REG_RX_ORDER_START + rxNO, + rxNO1); + return ReCode; +} + +/*get rx order*/ +static int ft5402_get_rx_order(struct i2c_client * client, u8 rxNO, u8 *prxNO1) +{ + unsigned char ReCode = 0; + ReCode = ft5402_read_reg(client, FT5402_REG_RX_ORDER_START + rxNO, + prxNO1); + return ReCode; +} + +/*set rx cap*/ +static int ft5402_set_rx_cap(struct i2c_client * client, u8 rxNO, u8 cap_value) +{ + unsigned char ReCode = 0; + if (rxNO < FT5402_RX_TEST_MODE_1) + ReCode = ft5402_write_reg(client, FT5402_REG_RX_CAP_START + rxNO, + cap_value); + else { + ReCode = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, + FT5402_REG_TEST_MODE_2<<4); /*enter Test mode 2*/ + if(ReCode >= 0) + ReCode = ft5402_write_reg(client, + FT5402_REG_RX_CAP_START + rxNO - FT5402_RX_TEST_MODE_1, + cap_value); + ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, + FT5402_REG_TEST_MODE<<4); /*enter Test mode*/ + } + + return ReCode; +} + +/*get rx cap*/ +static int ft5402_get_rx_cap(struct i2c_client * client, u8 rxNO, u8 *pCap) +{ + unsigned char ReCode = 0; + if (rxNO < FT5402_RX_TEST_MODE_1) + ReCode = ft5402_read_reg(client, FT5402_REG_RX_CAP_START + rxNO, + pCap); + else { + ReCode = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, + FT5402_REG_TEST_MODE_2<<4); /*enter Test mode 2*/ + if(ReCode >= 0) + ReCode = ft5402_read_reg(client, + FT5402_REG_RX_CAP_START + rxNO - FT5402_RX_TEST_MODE_1, + pCap); + ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, + FT5402_REG_TEST_MODE<<4); /*enter Test mode*/ + } + + return ReCode; +} + +/*set rx offset*/ +static int ft5402_set_rx_offset(struct i2c_client * client, u8 rxNO, u8 offset_value) +{ + unsigned char temp=0; + unsigned char ReCode = 0; + if (rxNO < FT5402_RX_TEST_MODE_1) { + ReCode = ft5402_read_reg(client, + FT5402_REG_RX_OFFSET_START + (rxNO>>1), &temp); + if (ReCode >= 0) { + if (rxNO%2 == 0) + ReCode = ft5402_write_reg(client, + FT5402_REG_RX_OFFSET_START + (rxNO>>1), + (temp&0xf0) + (offset_value&0x0f)); + else + ReCode = ft5402_write_reg(client, + FT5402_REG_RX_OFFSET_START + (rxNO>>1), + (temp&0x0f) + (offset_value<<4)); + } + } + else { + ReCode = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, + FT5402_REG_TEST_MODE_2<<4); /*enter Test mode 2*/ + if (ReCode >= 0) { + ReCode = ft5402_read_reg(client, + FT5402_REG_DEVICE_MODE+((rxNO-FT5402_RX_TEST_MODE_1)>>1), + &temp); /*enter Test mode 2*/ + if (ReCode >= 0) { + if (rxNO%2 == 0) + ReCode = ft5402_write_reg(client, + FT5402_REG_RX_OFFSET_START+((rxNO-FT5402_RX_TEST_MODE_1)>>1), + (temp&0xf0)+(offset_value&0x0f)); + else + ReCode = ft5402_write_reg(client, + FT5402_REG_RX_OFFSET_START+((rxNO-FT5402_RX_TEST_MODE_1)>>1), + (temp&0xf0)+(offset_value<<4)); + } + } + ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, + FT5402_REG_TEST_MODE<<4); /*enter Test mode*/ + } + + return ReCode; +} + +/*get rx offset*/ +static int ft5402_get_rx_offset(struct i2c_client * client, u8 rxNO, u8 *pOffset) +{ + unsigned char temp = 0; + unsigned char ReCode = 0; + if (rxNO < FT5402_RX_TEST_MODE_1) + ReCode = ft5402_read_reg(client, + FT5402_REG_RX_OFFSET_START + (rxNO>>1), &temp); + else { + ReCode = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, + FT5402_REG_TEST_MODE_2<<4); /*enter Test mode 2*/ + if (ReCode >= 0) + ReCode = ft5402_read_reg(client, + FT5402_REG_RX_OFFSET_START+((rxNO-FT5402_RX_TEST_MODE_1)>>1), + &temp); + + ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, + FT5402_REG_TEST_MODE<<4); /*enter Test mode*/ + } + + if (ReCode >= 0) { + if (0 == (rxNO%2)) + *pOffset = (temp&0x0f); + else + *pOffset = (temp>>4); + } + + return ReCode; +} + +/*set tx num*/ +static int ft5402_set_tx_num(struct i2c_client *client, u8 txnum) +{ + return ft5402_write_reg(client, FT5402_REG_TX_NUM, txnum); +} + +/*get tx num*/ +static int ft5402_get_tx_num(struct i2c_client *client, u8 *ptxnum) +{ + return ft5402_read_reg(client, FT5402_REG_TX_NUM, ptxnum); +} + +/*set rx num*/ +static int ft5402_set_rx_num(struct i2c_client *client, u8 rxnum) +{ + return ft5402_write_reg(client, FT5402_REG_RX_NUM, rxnum); +} + +/*get rx num*/ +static int ft5402_get_rx_num(struct i2c_client *client, u8 *prxnum) +{ + return ft5402_read_reg(client, FT5402_REG_RX_NUM, prxnum); +} + +/*set resolution*/ +static int ft5402_set_Resolution(struct i2c_client *client, u16 x, u16 y) +{ + unsigned char cRet = 0; + cRet &= ft5402_write_reg(client, + FT5402_REG_RESOLUTION_X_H, ((unsigned char)(x>>8))); + cRet &= ft5402_write_reg(client, + FT5402_REG_RESOLUTION_X_L, ((unsigned char)(x&0x00ff))); + + cRet &= ft5402_write_reg(client, + FT5402_REG_RESOLUTION_Y_H, ((unsigned char)(y>>8))); + cRet &= ft5402_write_reg(client, + FT5402_REG_RESOLUTION_Y_L, ((unsigned char)(y&0x00ff))); + + return cRet; +} + +/*get resolution*/ +static int ft5402_get_Resolution(struct i2c_client *client, + u16 *px, u16 *py) +{ + unsigned char cRet = 0, temp1 = 0, temp2 = 0; + cRet &= ft5402_read_reg(client, + FT5402_REG_RESOLUTION_X_H, &temp1); + cRet &= ft5402_read_reg(client, + FT5402_REG_RESOLUTION_X_L, &temp2); + (*px) = (((u16)temp1) << 8) | ((u16)temp2); + + cRet &= ft5402_read_reg(client, + FT5402_REG_RESOLUTION_Y_H, &temp1); + cRet &= ft5402_read_reg(client, + FT5402_REG_RESOLUTION_Y_L, &temp2); + (*py) = (((u16)temp1) << 8) | ((u16)temp2); + + return cRet; +} + + +/*set voltage*/ +static int ft5402_set_vol(struct i2c_client *client, u8 Vol) +{ + return ft5402_write_reg(client, FT5402_REG_VOLTAGE, Vol); +} + +/*get voltage*/ +static int ft5402_get_vol(struct i2c_client *client, u8 *pVol) +{ + return ft5402_read_reg(client, FT5402_REG_VOLTAGE, pVol); +} + +/*set gain*/ +static int ft5402_set_gain(struct i2c_client *client, u8 Gain) +{ + return ft5402_write_reg(client, FT5402_REG_GAIN, Gain); +} + +/*get gain*/ +static int ft5402_get_gain(struct i2c_client *client, u8 *pGain) +{ + return ft5402_read_reg(client, FT5402_REG_GAIN, pGain); +} + +/*get start rx*/ +static int ft5402_get_start_rx(struct i2c_client *client, u8 *pRx) +{ + return ft5402_read_reg(client, FT5402_REG_START_RX, pRx); +} + + +/*get adc target*/ +static int ft5402_get_adc_target(struct i2c_client *client, u16 *pvalue) +{ + int err = 0; + u8 tmp1, tmp2; + err = ft5402_read_reg(client, FT5402_REG_ADC_TARGET_HIGH, + &tmp1); + if (err < 0) + dev_err(&client->dev, "%s:get adc target high failed\n", + __func__); + err = ft5402_read_reg(client, FT5402_REG_ADC_TARGET_LOW, + &tmp2); + if (err < 0) + dev_err(&client->dev, "%s:get adc target low failed\n", + __func__); + + *pvalue = ((u16)tmp1<<8) + (u16)tmp2; + return err; +} + +static int ft5402_set_face_detect_statistics_tx_num(struct i2c_client *client, u8 prevalue) +{ + return ft5402_write_reg(client, FT5402_REG_FACE_DETECT_STATISTICS_TX_NUM, + prevalue); +} + +static int ft5402_get_face_detect_statistics_tx_num(struct i2c_client *client, u8 *pprevalue) +{ + return ft5402_read_reg(client, FT5402_REG_FACE_DETECT_STATISTICS_TX_NUM, + pprevalue); +} + +static int ft5402_set_face_detect_pre_value(struct i2c_client *client, u8 prevalue) +{ + return ft5402_write_reg(client, FT5402_REG_FACE_DETECT_PRE_VALUE, + prevalue); +} + +static int ft5402_get_face_detect_pre_value(struct i2c_client *client, u8 *pprevalue) +{ + return ft5402_read_reg(client, FT5402_REG_FACE_DETECT_PRE_VALUE, + pprevalue); +} + +static int ft5402_set_face_detect_num(struct i2c_client *client, u8 num) +{ + return ft5402_write_reg(client, FT5402_REG_FACE_DETECT_NUM, + num); +} + +static int ft5402_get_face_detect_num(struct i2c_client *client, u8 *pnum) +{ + return ft5402_read_reg(client, FT5402_REG_FACE_DETECT_NUM, + pnum); +} + + +static int ft5402_set_peak_value_min(struct i2c_client *client, u8 min) +{ + return ft5402_write_reg(client, FT5402_REG_BIGAREA_PEAK_VALUE_MIN, + min); +} + +static int ft5402_get_peak_value_min(struct i2c_client *client, u8 *pmin) +{ + return ft5402_read_reg(client, FT5402_REG_BIGAREA_PEAK_VALUE_MIN, + pmin); +} + +static int ft5402_set_diff_value_over_num(struct i2c_client *client, u8 num) +{ + return ft5402_write_reg(client, FT5402_REG_BIGAREA_DIFF_VALUE_OVER_NUM, + num); +} +static int ft5402_get_diff_value_over_num(struct i2c_client *client, u8 *pnum) +{ + return ft5402_read_reg(client, FT5402_REG_BIGAREA_DIFF_VALUE_OVER_NUM, + pnum); +} + + +static int ft5402_set_customer_id(struct i2c_client *client, u8 num) +{ + return ft5402_write_reg(client, FT5402_REG_CUSTOMER_ID, + num); +} +static int ft5402_get_customer_id(struct i2c_client *client, u8 *pnum) +{ + return ft5402_read_reg(client, FT5402_REG_CUSTOMER_ID, + pnum); +} + +static int ft5402_set_kx(struct i2c_client *client, u16 value) +{ + int err = 0; + err = ft5402_write_reg(client, FT5402_REG_KX_H, + value >> 8); + if (err < 0) + dev_err(&client->dev, "%s:set kx high failed\n", + __func__); + err = ft5402_write_reg(client, FT5402_REG_KX_L, + value); + if (err < 0) + dev_err(&client->dev, "%s:set kx low failed\n", + __func__); + + return err; +} + +static int ft5402_get_kx(struct i2c_client *client, u16 *pvalue) +{ + int err = 0; + u8 tmp1, tmp2; + err = ft5402_read_reg(client, FT5402_REG_KX_H, + &tmp1); + if (err < 0) + dev_err(&client->dev, "%s:get kx high failed\n", + __func__); + err = ft5402_read_reg(client, FT5402_REG_KX_L, + &tmp2); + if (err < 0) + dev_err(&client->dev, "%s:get kx low failed\n", + __func__); + + *pvalue = ((u16)tmp1<<8) + (u16)tmp2; + return err; +} +static int ft5402_set_ky(struct i2c_client *client, u16 value) +{ + int err = 0; + err = ft5402_write_reg(client, FT5402_REG_KY_H, + value >> 8); + if (err < 0) + dev_err(&client->dev, "%s:set ky high failed\n", + __func__); + err = ft5402_write_reg(client, FT5402_REG_KY_L, + value); + if (err < 0) + dev_err(&client->dev, "%s:set ky low failed\n", + __func__); + + return err; +} + +static int ft5402_get_ky(struct i2c_client *client, u16 *pvalue) +{ + int err = 0; + u8 tmp1, tmp2; + err = ft5402_read_reg(client, FT5402_REG_KY_H, + &tmp1); + if (err < 0) + dev_err(&client->dev, "%s:get ky high failed\n", + __func__); + err = ft5402_read_reg(client, FT5402_REG_KY_L, + &tmp2); + if (err < 0) + dev_err(&client->dev, "%s:get ky low failed\n", + __func__); + + *pvalue = ((u16)tmp1<<8) + (u16)tmp2; + return err; +} +static int ft5402_set_lemda_x(struct i2c_client *client, u8 value) +{ + return ft5402_write_reg(client, FT5402_REG_LEMDA_X, + value); +} + +static int ft5402_get_lemda_x(struct i2c_client *client, u8 *pvalue) +{ + return ft5402_read_reg(client, FT5402_REG_LEMDA_X, + pvalue); +} +static int ft5402_set_lemda_y(struct i2c_client *client, u8 value) +{ + return ft5402_write_reg(client, FT5402_REG_LEMDA_Y, + value); +} + +static int ft5402_get_lemda_y(struct i2c_client *client, u8 *pvalue) +{ + return ft5402_read_reg(client, FT5402_REG_LEMDA_Y, + pvalue); +} +static int ft5402_set_pos_x(struct i2c_client *client, u8 value) +{ + return ft5402_write_reg(client, FT5402_REG_DIRECTION, + value); +} + +static int ft5402_get_pos_x(struct i2c_client *client, u8 *pvalue) +{ + return ft5402_read_reg(client, FT5402_REG_DIRECTION, + pvalue); +} + +static int ft5402_set_scan_select(struct i2c_client *client, u8 value) +{ + return ft5402_write_reg(client, FT5402_REG_SCAN_SELECT, + value); +} + +static int ft5402_get_scan_select(struct i2c_client *client, u8 *pvalue) +{ + return ft5402_read_reg(client, FT5402_REG_SCAN_SELECT, + pvalue); +} + +static int ft5402_set_other_param(struct i2c_client *client) +{ + int err = 0; + err = ft5402_write_reg(client, FT5402_REG_THGROUP, (u8)(g_param_ft5402.ft5402_THGROUP)); + if (err < 0) { + dev_err(&client->dev, "%s:write THGROUP failed.\n", __func__); + return err; + } + err = ft5402_write_reg(client, FT5402_REG_THPEAK, g_param_ft5402.ft5402_THPEAK); + if (err < 0) { + dev_err(&client->dev, "%s:write THPEAK failed.\n", + __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_PWMODE_CTRL, + g_param_ft5402.ft5402_PWMODE_CTRL); + if (err < 0) { + dev_err(&client->dev, "%s:write PERIOD_CTRL failed.\n", __func__); + return err; + } + err = ft5402_write_reg(client, FT5402_REG_PERIOD_ACTIVE, + g_param_ft5402.ft5402_PERIOD_ACTIVE); + if (err < 0) { + dev_err(&client->dev, "%s:write PERIOD_ACTIVE failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FACE_DETECT_STATISTICS_TX_NUM, + g_param_ft5402.ft5402_FACE_DETECT_STATISTICS_TX_NUM); + if (err < 0) { + dev_err(&client->dev, "%s:write FACE_DETECT_STATISTICS_TX_NUM failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_MAX_TOUCH_VALUE_HIGH, + g_param_ft5402.ft5402_MAX_TOUCH_VALUE>>8); + if (err < 0) { + dev_err(&client->dev, "%s:write MAX_TOUCH_VALUE_HIGH failed.\n", __func__); + return err; + } + err = ft5402_write_reg(client, FT5402_REG_MAX_TOUCH_VALUE_LOW, + g_param_ft5402.ft5402_MAX_TOUCH_VALUE); + if (err < 0) { + dev_err(&client->dev, "%s:write MAX_TOUCH_VALUE_LOW failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FACE_DETECT_MODE, + g_param_ft5402.ft5402_FACE_DETECT_MODE); + if (err < 0) { + dev_err(&client->dev, "%s:write FACE_DETECT_MODE failed.\n", __func__); + return err; + } + err = ft5402_write_reg(client, FT5402_REG_DRAW_LINE_TH, + g_param_ft5402.ft5402_DRAW_LINE_TH); + if (err < 0) { + dev_err(&client->dev, "%s:write DRAW_LINE_TH failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_POINTS_SUPPORTED, + g_param_ft5402.ft5402_POINTS_SUPPORTED); + if (err < 0) { + dev_err(&client->dev, "%s:write POINTS_SUPPORTED failed.\n", __func__); + return err; + } + err = ft5402_write_reg(client, FT5402_REG_ESD_FILTER_FRAME, + g_param_ft5402.ft5402_ESD_FILTER_FRAME); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_ESD_FILTER_FRAME failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_POINTS_STABLE_MACRO, + g_param_ft5402.ft5402_POINTS_STABLE_MACRO); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_POINTS_STABLE_MACRO failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_MIN_DELTA_X, + g_param_ft5402.ft5402_MIN_DELTA_X); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_MIN_DELTA_X failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_MIN_DELTA_Y, + g_param_ft5402.ft5402_MIN_DELTA_Y); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_MIN_DELTA_Y failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_MIN_DELTA_STEP, + g_param_ft5402.ft5402_MIN_DELTA_STEP); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_MIN_DELTA_STEP failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_ESD_NOISE_MACRO, + g_param_ft5402.ft5402_ESD_NOISE_MACRO); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_ESD_NOISE_MACRO failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_ESD_DIFF_VAL, + g_param_ft5402.ft5402_ESD_DIFF_VAL); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_ESD_DIFF_VAL failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_ESD_NEGTIVE, + g_param_ft5402.ft5402_ESD_NEGTIVE); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_ESD_NEGTIVE failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_ESD_FILTER_FRAMES, + g_param_ft5402.ft5402_ESD_FILTER_FRAMES); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_ESD_FILTER_FRAMES failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_IO_LEVEL_SELECT, + g_param_ft5402.ft5402_IO_LEVEL_SELECT); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_IO_LEVEL_SELECT failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_POINTID_DELAY_COUNT, + g_param_ft5402.ft5402_POINTID_DELAY_COUNT); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_POINTID_DELAY_COUNT failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_LIFTUP_FILTER_MACRO, + g_param_ft5402.ft5402_LIFTUP_FILTER_MACRO); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_LIFTUP_FILTER_MACRO failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_DIFF_HANDLE_MACRO, + g_param_ft5402.ft5402_DIFF_HANDLE_MACRO); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_DIFF_HANDLE_MACRO failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_MIN_WATER, + g_param_ft5402.ft5402_MIN_WATER); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_MIN_WATER failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_MAX_NOISE, + g_param_ft5402.ft5402_MAX_NOISE); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_MAX_NOISE failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_WATER_START_RX, + g_param_ft5402.ft5402_WATER_START_RX); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_WATER_START_RX failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_WATER_START_TX, + g_param_ft5402.ft5402_WATER_START_TX); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_WATER_START_TX failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_HOST_NUMBER_SUPPORTED_MACRO, + g_param_ft5402.ft5402_HOST_NUMBER_SUPPORTED_MACRO); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_HOST_NUMBER_SUPPORTED_MACRO failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_RAISE_THGROUP, + g_param_ft5402.ft5402_RAISE_THGROUP); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_RAISE_THGROUP failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_CHARGER_STATE, + g_param_ft5402.ft5402_CHARGER_STATE); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_CHARGER_STATE failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_FILTERID_START, + g_param_ft5402.ft5402_FILTERID_START); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_FILTERID_START failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_FRAME_FILTER_EN_MACRO, + g_param_ft5402.ft5402_FRAME_FILTER_EN_MACRO); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_FRAME_FILTER_EN_MACRO failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_FRAME_FILTER_SUB_MAX_TH, + g_param_ft5402.ft5402_FRAME_FILTER_SUB_MAX_TH); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_FRAME_FILTER_SUB_MAX_TH failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_FRAME_FILTER_ADD_MAX_TH, + g_param_ft5402.ft5402_FRAME_FILTER_ADD_MAX_TH); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_FRAME_FILTER_ADD_MAX_TH failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_FRAME_FILTER_SKIP_START_FRAME, + g_param_ft5402.ft5402_FRAME_FILTER_SKIP_START_FRAME); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_FRAME_FILTER_SKIP_START_FRAME failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_FRAME_FILTER_BAND_EN, + g_param_ft5402.ft5402_FRAME_FILTER_BAND_EN); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_FRAME_FILTER_BAND_EN failed.\n", __func__); + return err; + } + + err = ft5402_write_reg(client, FT5402_REG_FT5402_FRAME_FILTER_BAND_WIDTH, + g_param_ft5402.ft5402_FRAME_FILTER_BAND_WIDTH); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_FRAME_FILTER_BAND_WIDTH failed.\n", __func__); + return err; + } + + return err; +} + +static int ft5402_get_other_param(struct i2c_client *client) +{ + int err = 0; + u8 value = 0x00; + err = ft5402_read_reg(client, FT5402_REG_THGROUP, &value); + if (err < 0) { + dev_err(&client->dev, "%s:write THGROUP failed.\n", __func__); + return err; + } else + DBG("THGROUP=%02x\n", value); + err = ft5402_read_reg(client, FT5402_REG_THPEAK, &value); + if (err < 0) { + dev_err(&client->dev, "%s:write THPEAK failed.\n", + __func__); + return err; + } else + DBG("THPEAK=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_PWMODE_CTRL, &value); + if (err < 0) { + dev_err(&client->dev, "%s:write PWMODE_CTRL failed.\n", __func__); + return err; + } else + DBG("CTRL=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_PERIOD_ACTIVE, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write PERIOD_ACTIVE failed.\n", __func__); + return err; + } else + DBG("PERIOD_ACTIVE=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_MAX_TOUCH_VALUE_HIGH, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write MAX_TOUCH_VALUE_HIGH failed.\n", __func__); + return err; + } else + DBG("MAX_TOUCH_VALUE_HIGH=%02x\n", value); + err = ft5402_read_reg(client, FT5402_REG_MAX_TOUCH_VALUE_LOW, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write MAX_TOUCH_VALUE_LOW failed.\n", __func__); + return err; + } else + DBG("MAX_TOUCH_VALUE_LOW=%02x\n", value); + err = ft5402_read_reg(client, FT5402_REG_FACE_DETECT_MODE, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FACE_DETECT_MODE failed.\n", __func__); + return err; + } else + DBG("FACE_DEC_MODE=%02x\n", value); + err = ft5402_read_reg(client, FT5402_REG_DRAW_LINE_TH, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write DRAW_LINE_TH failed.\n", __func__); + return err; + } else + DBG("DRAW_LINE_TH=%02x\n", value); + err = ft5402_read_reg(client, FT5402_REG_POINTS_SUPPORTED, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write ft5402_POINTS_SUPPORTED failed.\n", __func__); + return err; + } else + DBG("ft5402_POINTS_SUPPORTED=%02x\n", value); + err = ft5402_read_reg(client, FT5402_REG_ESD_FILTER_FRAME, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_ESD_FILTER_FRAME failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_ESD_FILTER_FRAME=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_POINTS_STABLE_MACRO, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_POINTS_STABLE_MACRO failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_POINTS_STABLE_MACRO=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_MIN_DELTA_X, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_MIN_DELTA_X failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_MIN_DELTA_X=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_MIN_DELTA_Y, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_MIN_DELTA_Y failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_MIN_DELTA_Y=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_MIN_DELTA_STEP, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_MIN_DELTA_STEP failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_MIN_DELTA_STEP=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_ESD_NOISE_MACRO, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_ESD_NOISE_MACRO failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_ESD_NOISE_MACRO=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_ESD_DIFF_VAL, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_ESD_DIFF_VAL failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_ESD_DIFF_VAL=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_ESD_NEGTIVE, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_ESD_NEGTIVE failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_ESD_NEGTIVE=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_ESD_FILTER_FRAMES, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_ESD_FILTER_FRAMES failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_ESD_FILTER_FRAMES=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_IO_LEVEL_SELECT, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_IO_LEVEL_SELECT failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_IO_LEVEL_SELECT=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_POINTID_DELAY_COUNT, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_POINTID_DELAY_COUNT failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_POINTID_DELAY_COUNT=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_LIFTUP_FILTER_MACRO, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_LIFTUP_FILTER_MACRO failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_LIFTUP_FILTER_MACRO=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_DIFF_HANDLE_MACRO, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_DIFF_HANDLE_MACRO failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_DIFF_HANDLE_MACRO=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_MIN_WATER, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_MIN_WATER failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_MIN_WATER=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_MAX_NOISE, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_MAX_NOISE failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_MAX_NOISE=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_WATER_START_RX, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_WATER_START_RX failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_WATER_START_RX=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_WATER_START_TX, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_WATER_START_TX failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_WATER_START_TX=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_HOST_NUMBER_SUPPORTED_MACRO, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_HOST_NUMBER_SUPPORTED_MACRO failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_HOST_NUMBER_SUPPORTED_MACRO=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_RAISE_THGROUP, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_RAISE_THGROUP failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_RAISE_THGROUP=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_CHARGER_STATE, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_CHARGER_STATE failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_CHARGER_STATE=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_FILTERID_START, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_FILTERID_START failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_FILTERID_START=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_FRAME_FILTER_EN_MACRO, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_FRAME_FILTER_EN_MACRO failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_FRAME_FILTER_EN_MACRO=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_FRAME_FILTER_SUB_MAX_TH, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_FRAME_FILTER_SUB_MAX_TH failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_FRAME_FILTER_SUB_MAX_TH=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_FRAME_FILTER_ADD_MAX_TH, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_FRAME_FILTER_ADD_MAX_TH failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_FRAME_FILTER_ADD_MAX_TH=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_FRAME_FILTER_SKIP_START_FRAME, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_FRAME_FILTER_SKIP_START_FRAME failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_FRAME_FILTER_SKIP_START_FRAME=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_FRAME_FILTER_BAND_EN, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_FRAME_FILTER_BAND_EN failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_FRAME_FILTER_BAND_EN=%02x\n", value); + + err = ft5402_read_reg(client, FT5402_REG_FT5402_FRAME_FILTER_BAND_WIDTH, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:write FT5402_REG_FT5402_FRAME_FILTER_BAND_WIDTH failed.\n", __func__); + return err; + } else + DBG("FT5402_REG_FT5402_FRAME_FILTER_BAND_WIDTH=%02x\n", value); + + return err; +} +int ft5402_get_ic_param(struct i2c_client *client) +{ + int err = 0; + int i = 0; + u8 value = 0x00; + u16 xvalue = 0x0000, yvalue = 0x0000; + + /*enter factory mode*/ + err = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, FT5402_FACTORYMODE_VALUE); + if (err < 0) { + dev_err(&client->dev, "%s:enter factory mode failed.\n", __func__); + goto RETURN_WORK; + } + + for (i = 0; i < g_ft5402_tx_num; i++) { + DBG("tx%d:", i); + /*get tx order*/ + err = ft5402_get_tx_order(client, i, &value); + if (err < 0) { + dev_err(&client->dev, "%s:could not get tx%d order.\n", + __func__, i); + goto RETURN_WORK; + } + DBG("order=%d ", value); + /*get tx cap*/ + err = ft5402_get_tx_cap(client, i, &value); + if (err < 0) { + dev_err(&client->dev, "%s:could not get tx%d cap.\n", + __func__, i); + goto RETURN_WORK; + } + DBG("cap=%02x\n", value); + } + /*get tx offset*/ + err = ft5402_get_tx_offset(client, 0, &value); + if (err < 0) { + dev_err(&client->dev, "%s:could not get tx 0 offset.\n", + __func__); + goto RETURN_WORK; + } else + DBG("tx offset = %02x\n", value); + + /*get rx offset and cap*/ + for (i = 0; i < g_ft5402_rx_num; i++) { + /*get rx order*/ + DBG("rx%d:", i); + err = ft5402_get_rx_order(client, i, &value); + if (err < 0) { + dev_err(&client->dev, "%s:could not get rx%d order.\n", + __func__, i); + goto RETURN_WORK; + } + DBG("order=%d ", value); + /*get rx cap*/ + err = ft5402_get_rx_cap(client, i, &value); + if (err < 0) { + dev_err(&client->dev, "%s:could not get rx%d cap.\n", + __func__, i); + goto RETURN_WORK; + } + DBG("cap=%02x ", value); + err = ft5402_get_rx_offset(client, i, &value); + if (err < 0) { + dev_err(&client->dev, "%s:could not get rx offset.\n", + __func__); + goto RETURN_WORK; + } + DBG("offset=%02x\n", value); + } + + /*get scan select*/ + err = ft5402_get_scan_select(client, &value); + if (err < 0) { + dev_err(&client->dev, "%s:could not get scan select.\n", + __func__); + goto RETURN_WORK; + } else + DBG("scan select = %02x\n", value); + + /*get tx number*/ + err = ft5402_get_tx_num(client, &value); + if (err < 0) { + dev_err(&client->dev, "%s:could not get tx num.\n", + __func__); + goto RETURN_WORK; + } else + DBG("tx num = %02x\n", value); + /*get rx number*/ + err = ft5402_get_rx_num(client, &value); + if (err < 0) { + dev_err(&client->dev, "%s:could not get rx num.\n", + __func__); + goto RETURN_WORK; + } else + DBG("rx num = %02x\n", value); + + /*get gain*/ + err = ft5402_get_gain(client, &value); + if (err < 0) { + dev_err(&client->dev, "%s:could not get gain.\n", + __func__); + goto RETURN_WORK; + } else + DBG("gain = %02x\n", value); + /*get voltage*/ + err = ft5402_get_vol(client, &value); + if (err < 0) { + dev_err(&client->dev, "%s:could not get voltage.\n", + __func__); + goto RETURN_WORK; + } else + DBG("voltage = %02x\n", value); + /*get start rx*/ + err = ft5402_get_start_rx(client, &value); + if (err < 0) { + dev_err(&client->dev, "%s:could not get start rx.\n", + __func__); + goto RETURN_WORK; + } else + DBG("start rx = %02x\n", value); + /*get adc target*/ + err = ft5402_get_adc_target(client, &xvalue); + if (err < 0) { + dev_err(&client->dev, "%s:could not get adc target.\n", + __func__); + goto ERR_EXIT; + } else + DBG("ADC target = %02x\n", xvalue); + + +RETURN_WORK: + /*enter work mode*/ + err = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, FT5402_WORKMODE_VALUE); + if (err < 0) { + dev_err(&client->dev, "%s:enter work mode failed.\n", __func__); + goto ERR_EXIT; + } + + /*get resolution*/ + err = ft5402_get_Resolution(client, &xvalue, &yvalue); + if (err < 0) { + dev_err(&client->dev, "%s:could not get resolution.\n", + __func__); + goto ERR_EXIT; + } else + DBG("resolution X = %d Y = %d\n", xvalue, yvalue); + + + /*get face detect statistics tx num*/ + err = ft5402_get_face_detect_statistics_tx_num(client, + &value); + if (err < 0) { + dev_err(&client->dev, + "%s:could not get face detect statistics tx num.\n", + __func__); + goto ERR_EXIT; + } else + DBG("FT5402_FACE_DETECT_STATISTICS_TX_NUM = %02x\n", value); + /*get face detect pre value*/ + err = ft5402_get_face_detect_pre_value(client, + &value); + if (err < 0) { + dev_err(&client->dev, + "%s:could not get face detect pre value.\n", + __func__); + goto ERR_EXIT; + } else + DBG("FT5402_FACE_DETECT_PRE_VALUE = %02x\n", value); + /*get face detect num*/ + err = ft5402_get_face_detect_num(client, &value); + if (err < 0) { + dev_err(&client->dev, "%s:could not get face detect num.\n", + __func__); + goto ERR_EXIT; + } else + DBG("face detect num = %02x\n", value); + + /*get min peak value*/ + err = ft5402_get_peak_value_min(client, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:could not get min peak value.\n", + __func__); + goto ERR_EXIT; + } else + DBG("FT5402_BIGAREA_PEAK_VALUE_MIN = %02x\n", value); + /*get diff value over num*/ + err = ft5402_get_diff_value_over_num(client, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:could not get diff value over num.\n", + __func__); + goto ERR_EXIT; + } else + DBG("FT5402_BIGAREA_DIFF_VALUE_OVER_NUM = %02x\n", value); + /*get customer id*/ + err = ft5402_get_customer_id(client, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:could not get customer id.\n", + __func__); + goto ERR_EXIT; + } else + DBG("FT5402_CUSTOMER_ID = %02x\n", value); + /*get kx*/ + err = ft5402_get_kx(client, &xvalue); + if (err < 0) { + dev_err(&client->dev, "%s:could not get kx.\n", + __func__); + goto ERR_EXIT; + } else + DBG("kx = %02x\n", xvalue); + /*get ky*/ + err = ft5402_get_ky(client, &xvalue); + if (err < 0) { + dev_err(&client->dev, "%s:could not get ky.\n", + __func__); + goto ERR_EXIT; + } else + DBG("ky = %02x\n", xvalue); + /*get lemda x*/ + err = ft5402_get_lemda_x(client, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:could not get lemda x.\n", + __func__); + goto ERR_EXIT; + } else + DBG("lemda x = %02x\n", value); + /*get lemda y*/ + err = ft5402_get_lemda_y(client, + &value); + if (err < 0) { + dev_err(&client->dev, "%s:could not get lemda y.\n", + __func__); + goto ERR_EXIT; + } else + DBG("lemda y = %02x\n", value); + /*get pos x*/ + err = ft5402_get_pos_x(client, &value); + if (err < 0) { + dev_err(&client->dev, "%s:could not get pos x.\n", + __func__); + goto ERR_EXIT; + } else + DBG("pos x = %02x\n", value); + + err = ft5402_get_other_param(client); + +ERR_EXIT: + return err; +} + +int ft5402_Init_IC_Param(struct i2c_client *client) +{ + int err = 0; + int i = 0; + + /*enter factory mode*/ + err = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, FT5402_FACTORYMODE_VALUE); + if (err < 0) { + dev_err(&client->dev, "%s:enter factory mode failed.\n", __func__); + goto RETURN_WORK; + } + + for (i = 0; i < g_ft5402_tx_num; i++) { + if (g_ft5402_tx_order[i] != 0xFF) { + /*set tx order*/ + err = ft5402_set_tx_order(client, i, g_ft5402_tx_order[i]); + if (err < 0) { + dev_err(&client->dev, "%s:could not set tx%d order.\n", + __func__, i); + goto RETURN_WORK; + } + } + /*set tx cap*/ + err = ft5402_set_tx_cap(client, i, g_ft5402_tx_cap[i]); + if (err < 0) { + dev_err(&client->dev, "%s:could not set tx%d cap.\n", + __func__, i); + goto RETURN_WORK; + } + } + /*set tx offset*/ + err = ft5402_set_tx_offset(client, 0, g_ft5402_tx_offset); + if (err < 0) { + dev_err(&client->dev, "%s:could not set tx 0 offset.\n", + __func__); + goto RETURN_WORK; + } + + /*set rx offset and cap*/ + for (i = 0; i < g_ft5402_rx_num; i++) { + /*set rx order*/ + err = ft5402_set_rx_order(client, i, g_ft5402_rx_order[i]); + if (err < 0) { + dev_err(&client->dev, "%s:could not set rx%d order.\n", + __func__, i); + goto RETURN_WORK; + } + /*set rx cap*/ + err = ft5402_set_rx_cap(client, i, g_ft5402_rx_cap[i]); + if (err < 0) { + dev_err(&client->dev, "%s:could not set rx%d cap.\n", + __func__, i); + goto RETURN_WORK; + } + } + for (i = 0; i < g_ft5402_rx_num/2; i++) { + err = ft5402_set_rx_offset(client, i*2, g_ft5402_rx_offset[i]>>4); + if (err < 0) { + dev_err(&client->dev, "%s:could not set rx offset.\n", + __func__); + goto RETURN_WORK; + } + err = ft5402_set_rx_offset(client, i*2+1, g_ft5402_rx_offset[i]&0x0F); + if (err < 0) { + dev_err(&client->dev, "%s:could not set rx offset.\n", + __func__); + goto RETURN_WORK; + } + } + + /*set scan select*/ + err = ft5402_set_scan_select(client, g_ft5402_scanselect); + if (err < 0) { + dev_err(&client->dev, "%s:could not set scan select.\n", + __func__); + goto RETURN_WORK; + } + + /*set tx number*/ + err = ft5402_set_tx_num(client, g_ft5402_tx_num); + if (err < 0) { + dev_err(&client->dev, "%s:could not set tx num.\n", + __func__); + goto RETURN_WORK; + } + /*set rx number*/ + err = ft5402_set_rx_num(client, g_ft5402_rx_num); + if (err < 0) { + dev_err(&client->dev, "%s:could not set rx num.\n", + __func__); + goto RETURN_WORK; + } + + /*set gain*/ + err = ft5402_set_gain(client, g_ft5402_gain); + if (err < 0) { + dev_err(&client->dev, "%s:could not set gain.\n", + __func__); + goto RETURN_WORK; + } + /*set voltage*/ + err = ft5402_set_vol(client, g_ft5402_voltage); + if (err < 0) { + dev_err(&client->dev, "%s:could not set voltage.\n", + __func__); + goto RETURN_WORK; + } + + err = ft5402_write_reg(client, FT5402_REG_ADC_TARGET_HIGH, + g_param_ft5402.ft5402_ADC_TARGET>>8); + if (err < 0) { + dev_err(&client->dev, "%s:write ADC_TARGET_HIGH failed.\n", __func__); + return err; + } + err = ft5402_write_reg(client, FT5402_REG_ADC_TARGET_LOW, + g_param_ft5402.ft5402_ADC_TARGET); + if (err < 0) { + dev_err(&client->dev, "%s:write ADC_TARGET_LOW failed.\n", __func__); + return err; + } + +RETURN_WORK: + /*enter work mode*/ + err = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, FT5402_WORKMODE_VALUE); + if (err < 0) { + dev_err(&client->dev, "%s:enter work mode failed.\n", __func__); + goto ERR_EXIT; + } + + /*set resolution*/ + err = ft5402_set_Resolution(client, g_param_ft5402.ft5402_RESOLUTION_X, + g_param_ft5402.ft5402_RESOLUTION_Y); + if (err < 0) { + dev_err(&client->dev, "%s:could not set resolution.\n", + __func__); + goto ERR_EXIT; + } + + /*set face detect statistics tx num*/ + err = ft5402_set_face_detect_statistics_tx_num(client, + g_param_ft5402.ft5402_FACE_DETECT_STATISTICS_TX_NUM); + if (err < 0) { + dev_err(&client->dev, + "%s:could not set face detect statistics tx num.\n", + __func__); + goto ERR_EXIT; + } + /*set face detect pre value*/ + err = ft5402_set_face_detect_pre_value(client, + g_param_ft5402.ft5402_FACE_DETECT_PRE_VALUE); + if (err < 0) { + dev_err(&client->dev, + "%s:could not set face detect pre value.\n", + __func__); + goto ERR_EXIT; + } + /*set face detect num*/ + err = ft5402_set_face_detect_num(client, + g_param_ft5402.ft5402_FACE_DETECT_NUM); + if (err < 0) { + dev_err(&client->dev, "%s:could not set face detect num.\n", + __func__); + goto ERR_EXIT; + } + + /*set min peak value*/ + err = ft5402_set_peak_value_min(client, + g_param_ft5402.ft5402_BIGAREA_PEAK_VALUE_MIN); + if (err < 0) { + dev_err(&client->dev, "%s:could not set min peak value.\n", + __func__); + goto ERR_EXIT; + } + /*set diff value over num*/ + err = ft5402_set_diff_value_over_num(client, + g_param_ft5402.ft5402_BIGAREA_DIFF_VALUE_OVER_NUM); + if (err < 0) { + dev_err(&client->dev, "%s:could not set diff value over num.\n", + __func__); + goto ERR_EXIT; + } + /*set customer id*/ + err = ft5402_set_customer_id(client, + g_param_ft5402.ft5402_CUSTOMER_ID); + if (err < 0) { + dev_err(&client->dev, "%s:could not set customer id.\n", + __func__); + goto ERR_EXIT; + } + /*set kx*/ + err = ft5402_set_kx(client, g_param_ft5402.ft5402_KX); + if (err < 0) { + dev_err(&client->dev, "%s:could not set kx.\n", + __func__); + goto ERR_EXIT; + } + /*set ky*/ + err = ft5402_set_ky(client, g_param_ft5402.ft5402_KY); + if (err < 0) { + dev_err(&client->dev, "%s:could not set ky.\n", + __func__); + goto ERR_EXIT; + } + /*set lemda x*/ + err = ft5402_set_lemda_x(client, + g_param_ft5402.ft5402_LEMDA_X); + if (err < 0) { + dev_err(&client->dev, "%s:could not set lemda x.\n", + __func__); + goto ERR_EXIT; + } + /*set lemda y*/ + err = ft5402_set_lemda_y(client, + g_param_ft5402.ft5402_LEMDA_Y); + if (err < 0) { + dev_err(&client->dev, "%s:could not set lemda y.\n", + __func__); + goto ERR_EXIT; + } + /*set pos x*/ + err = ft5402_set_pos_x(client, g_param_ft5402.ft5402_DIRECTION); + if (err < 0) { + dev_err(&client->dev, "%s:could not set pos x.\n", + __func__); + goto ERR_EXIT; + } + + err = ft5402_set_other_param(client); + +ERR_EXIT: + return err; +} + + +char dst[512]; +static char * ft5402_sub_str(char * src, int n) +{ + char *p = src; + int i; + int m = 0; + int len = strlen(src); + + while (n >= 1 && m <= len) { + i = 0; + dst[10] = ' '; + n--; + while ( *p != ',' && *p != ' ') { + dst[i++] = *(p++); + m++; + if (i >= len) + break; + } + dst[i++] = '\0'; + p++; + } + return dst; +} +static int ft5402_GetInISize(char *config_name) +{ + struct file *pfile = NULL; + struct inode *inode; + unsigned long magic; + off_t fsize = 0; + char filepath[128]; + memset(filepath, 0, sizeof(filepath)); + + sprintf(filepath, "%s%s", FT5402_INI_FILEPATH, config_name); + + if (NULL == pfile) + pfile = filp_open(filepath, O_RDONLY, 0); + + if (IS_ERR(pfile)) { + pr_err("error occured while opening file %s.\n", filepath); + return -EIO; + } + + inode = pfile->f_dentry->d_inode; + magic = inode->i_sb->s_magic; + fsize = inode->i_size; + filp_close(pfile, NULL); + return fsize; +} + +static int ft5x0x_ReadInIData(char *config_name, + char *config_buf) +{ + struct file *pfile = NULL; + struct inode *inode; + unsigned long magic; + off_t fsize; + char filepath[128]; + loff_t pos; + mm_segment_t old_fs; + + memset(filepath, 0, sizeof(filepath)); + sprintf(filepath, "%s%s", FT5402_INI_FILEPATH, config_name); + if (NULL == pfile) + pfile = filp_open(filepath, O_RDONLY, 0); + if (IS_ERR(pfile)) { + pr_err("error occured while opening file %s.\n", filepath); + return -EIO; + } + + inode = pfile->f_dentry->d_inode; + magic = inode->i_sb->s_magic; + fsize = inode->i_size; + old_fs = get_fs(); + set_fs(KERNEL_DS); + pos = 0; + vfs_read(pfile, config_buf, fsize, &pos); + filp_close(pfile, NULL); + set_fs(old_fs); + + return 0; +} + +int ft5402_Get_Param_From_Ini(char *config_name) +{ + char key[64]; + char value[512]; + char section[64]; + int i = 0;//,ret=0; + int j = 0; + char *filedata = NULL; + unsigned char legal_byte1 = 0x00; + unsigned char legal_byte2 = 0x00; + + int inisize = ft5402_GetInISize(config_name); + + if (inisize <= 0) { + pr_err("%s ERROR:Get firmware size failed\n", + __func__); + return -EIO; + } + + filedata = kmalloc(inisize + 1, GFP_ATOMIC); + + if (ft5x0x_ReadInIData(config_name, filedata)) { + pr_err("%s() - ERROR: request_firmware failed\n", + __func__); + kfree(filedata); + return -EIO; + } + + /*check ini if it is illegal*/ + sprintf(section, "%s", FT5402_APP_LEGAL); + sprintf(key, "%s", FT5402_APP_LEGAL_BYTE_1_STR); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + legal_byte1 = atoi(value); + DBG("legal_byte1=%s\n", value); + sprintf(key, "%s", FT5402_APP_LEGAL_BYTE_2_STR); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + legal_byte2 = atoi(value); + DBG("lega2_byte1=%s\n", value); + if(FT5402_APP_LEGAL_BYTE_1_VALUE == legal_byte1 && + FT5402_APP_LEGAL_BYTE_2_VALUE == legal_byte2) + DBG("the ini file is valid\n"); + else { + pr_err("[FTS]-----the ini file is invalid!please check it.\n"); + goto ERROR_RETURN; + } + + /*get ini param*/ + sprintf(section, "%s", FT5402_APP_NAME); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_KX = atoi(value); + DBG("ft5402_KX=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_KY = atoi(value); + DBG("ft5402_KY=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_LEMDA_X = atoi(value); + DBG("ft5402_LEMDA_X=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_LEMDA_Y = atoi(value); + DBG("ft5402_LEMDA_Y=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_RESOLUTION_X = atoi(value); + DBG("ft5402_RESOLUTION_X=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_RESOLUTION_Y = atoi(value); + DBG("ft5402_RESOLUTION_Y=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_DIRECTION= atoi(value); + DBG("ft5402_DIRECTION=%s\n", value); + + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_FACE_DETECT_PRE_VALUE = atoi(value); + DBG("ft5402_FACE_DETECT_PRE_VALUE=%s\n", value); + + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_FACE_DETECT_NUM = atoi(value); + DBG("ft5402_FACE_DETECT_NUM=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_BIGAREA_PEAK_VALUE_MIN = atoi(value);/*The min value to be decided as the big point*/ + DBG("ft5402_BIGAREA_PEAK_VALUE_MIN=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_BIGAREA_DIFF_VALUE_OVER_NUM = atoi(value);/*The min big points of the big area*/ + DBG("ft5402_BIGAREA_DIFF_VALUE_OVER_NUM=%s\n", value); + + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_CUSTOMER_ID = atoi(value); + DBG("ft5402_CUSTOM_ID=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_PERIOD_ACTIVE = atoi(value); + DBG("ft5402_PERIOD_ACTIVE=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_FACE_DETECT_STATISTICS_TX_NUM = atoi(value); + DBG("ft5402_FACE_DETECT_STATISTICS_TX_NUM=%s\n", value); + + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_THGROUP = atoi(value); + DBG("ft5402_THGROUP=%s\n", value); + + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_THPEAK = atoi(value); + DBG("ft5402_THPEAK=%s\n", value); + + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_FACE_DETECT_MODE = atoi(value); + DBG("ft5402_FACE_DETECT_MODE=%s\n", value); + + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_MAX_TOUCH_VALUE = atoi(value); + DBG("ft5402_MAX_TOUCH_VALUE=%s\n", value); + + + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_PWMODE_CTRL= atoi(value); + DBG("ft5402_PWMODE_CTRL=%s\n", value); + + + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + + i++; + g_param_ft5402.ft5402_DRAW_LINE_TH = atoi(value); + DBG("ft5402_DRAW_LINE_TH=%s\n", value); + + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_POINTS_SUPPORTED= atoi(value); + DBG("ft5402_POINTS_SUPPORTED=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_START_RX = atoi(value); + DBG("ft5402_START_RX=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + + g_param_ft5402.ft5402_ADC_TARGET = atoi(value); + DBG("ft5402_ADC_TARGET=%s\n", value); + + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + + g_param_ft5402.ft5402_ESD_FILTER_FRAME = atoi(value); + DBG("ft5402_ESD_FILTER_FRAME=%s\n", value); + +/*********************************************************************/ + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_ft5402_tx_num = atoi(value); + DBG("ft5402_tx_num=%s\n", value); + + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_ft5402_rx_num = atoi(value); + DBG("ft5402_rx_num=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_ft5402_gain = atoi(value); + DBG("ft5402_gain=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_ft5402_voltage = atoi(value); + DBG("ft5402_voltage=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_ft5402_scanselect = atoi(value); + DBG("ft5402_scanselect=%s\n", value); + + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + for(j = 0; j < g_ft5402_tx_num; j++) + { + char * psrc = value; + g_ft5402_tx_order[j] = atoi(ft5402_sub_str(psrc, j+1)); + } + DBG("ft5402_tx_order=%s\n", value); + + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_ft5402_tx_offset = atoi(value); + DBG("ft5402_tx_offset=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + for(j = 0; j < g_ft5402_tx_num; j++) + { + char * psrc = value; + g_ft5402_tx_cap[j] = atoi(ft5402_sub_str(psrc, j+1)); + } + DBG("ft5402_tx_cap=%s\n", value); + + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + for(j = 0; j < g_ft5402_rx_num; j++) + { + char * psrc = value; + g_ft5402_rx_order[j] = atoi(ft5402_sub_str(psrc, j+1)); + } + DBG("ft5402_rx_order=%s\n", value); + + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + for(j = 0; j < g_ft5402_rx_num/2; j++) + { + char * psrc = value; + g_ft5402_rx_offset[j] = atoi(ft5402_sub_str(psrc, j+1)); + } + DBG("ft5402_rx_offset=%s\n", value); + + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + for(j = 0; j < g_ft5402_rx_num; j++) + { + char * psrc = value; + g_ft5402_rx_cap[j] = atoi(ft5402_sub_str(psrc, j+1)); + } + DBG("ft5402_rx_cap=%s\n", value); + + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_POINTS_STABLE_MACRO = atoi(value); + DBG("ft5402_POINTS_STABLE_MACRO=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_MIN_DELTA_X = atoi(value); + DBG("ft5402_MIN_DELTA_X=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_MIN_DELTA_Y = atoi(value); + DBG("ft5402_MIN_DELTA_Y=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_MIN_DELTA_STEP = atoi(value); + DBG("ft5402_MIN_DELTA_STEP=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_ESD_NOISE_MACRO = atoi(value); + DBG("ft5402_ESD_NOISE_MACRO=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_ESD_DIFF_VAL = atoi(value); + DBG("ft5402_ESD_DIFF_VAL=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_ESD_NEGTIVE = atoi(value); + DBG("ft5402_ESD_NEGTIVE=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_ESD_FILTER_FRAMES = atoi(value); + DBG("ft5402_ESD_FILTER_FRAMES=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_IO_LEVEL_SELECT = atoi(value); + DBG("ft5402_IO_LEVEL_SELECT=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_POINTID_DELAY_COUNT = atoi(value); + DBG("ft5402_POINTID_DELAY_COUNT=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_LIFTUP_FILTER_MACRO = atoi(value); + DBG("ft5402_LIFTUP_FILTER_MACRO=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_DIFF_HANDLE_MACRO = atoi(value); + DBG("ft5402_DIFF_HANDLE_MACRO=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_MIN_WATER = atoi(value); + DBG("ft5402_MIN_WATER=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_MAX_NOISE = atoi(value); + DBG("ft5402_MAX_NOISE=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_WATER_START_RX = atoi(value); + DBG("ft5402_WATER_START_RX=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_WATER_START_TX = atoi(value); + DBG("ft5402_WATER_START_TX=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_HOST_NUMBER_SUPPORTED_MACRO = atoi(value); + DBG("ft5402_HOST_NUMBER_SUPPORTED_MACRO=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_RAISE_THGROUP = atoi(value); + DBG("ft5402_RAISE_THGROUP=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_CHARGER_STATE = atoi(value); + DBG("ft5402_CHARGER_STATE=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_FILTERID_START = atoi(value); + DBG("ft5402_FILTERID_START=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_FRAME_FILTER_EN_MACRO = atoi(value); + DBG("ft5402_FRAME_FILTER_EN_MACRO=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_FRAME_FILTER_SUB_MAX_TH = atoi(value); + DBG("ft5402_FRAME_FILTER_SUB_MAX_TH=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_FRAME_FILTER_ADD_MAX_TH = atoi(value); + DBG("ft5402_FRAME_FILTER_ADD_MAX_TH=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_FRAME_FILTER_SKIP_START_FRAME = atoi(value); + DBG("ft5402_FRAME_FILTER_SKIP_START_FRAME=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_FRAME_FILTER_BAND_EN = atoi(value); + DBG("ft5402_FRAME_FILTER_BAND_EN=%s\n", value); + + sprintf(key, "%s", String_Param_FT5402[i]); + if (ini_get_key(filedata,section,key,value)<0) + goto ERROR_RETURN; + i++; + g_param_ft5402.ft5402_FRAME_FILTER_BAND_WIDTH = atoi(value); + DBG("ft5402_FRAME_FILTER_BAND_WIDTH=%s\n", value); + + + if (filedata) + kfree(filedata); + return 0; +ERROR_RETURN: + if (filedata) + kfree(filedata); + return -1; +} + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft5402_config.h b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft5402_config.h new file mode 100755 index 00000000..4d4935ed --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft5402_config.h @@ -0,0 +1,71 @@ +#ifndef __FT5402_CONFIG_H__ +#define __FT5402_CONFIG_H__ +/*FT5402 config*/ + + +#define FT5402_START_RX 0 +#define FT5402_ADC_TARGET 8500 +#define FT5402_KX 120 +#define FT5402_KY 120 +#define FT5402_RESOLUTION_X 480 +#define FT5402_RESOLUTION_Y 800 +#define FT5402_LEMDA_X 0 +#define FT5402_LEMDA_Y 0 +#define FT5402_PWMODE_CTRL 1 +#define FT5402_POINTS_SUPPORTED 5 +#define FT5402_DRAW_LINE_TH 150 +#define FT5402_FACE_DETECT_MODE 0 +#define FT5402_FACE_DETECT_STATISTICS_TX_NUM 3 +#define FT5402_FACE_DETECT_PRE_VALUE 20 +#define FT5402_FACE_DETECT_NUM 10 +#define FT5402_THGROUP 25 +#define FT5402_THPEAK 60 +#define FT5402_BIGAREA_PEAK_VALUE_MIN 100 +#define FT5402_BIGAREA_DIFF_VALUE_OVER_NUM 50 +#define FT5402_MIN_DELTA_X 2 +#define FT5402_MIN_DELTA_Y 2 +#define FT5402_MIN_DELTA_STEP 2 +#define FT5402_ESD_DIFF_VAL 20 +#define FT5402_ESD_NEGTIVE -50 +#define FT5402_ESD_FILTER_FRAME 10 +#define FT5402_MAX_TOUCH_VALUE 600 +#define FT5402_CUSTOMER_ID 121 +#define FT5402_IO_LEVEL_SELECT 0 +#define FT5402_DIRECTION 1 +#define FT5402_POINTID_DELAY_COUNT 3 +#define FT5402_LIFTUP_FILTER_MACRO 1 +#define FT5402_POINTS_STABLE_MACRO 1 +#define FT5402_ESD_NOISE_MACRO 1 +#define FT5402_RV_G_PERIOD_ACTIVE 16 +#define FT5402_DIFFDATA_HANDLE 1 +#define FT5402_MIN_WATER_VAL -50 +#define FT5402_MAX_NOISE_VAL 10 +#define FT5402_WATER_HANDLE_START_RX 0 +#define FT5402_WATER_HANDLE_START_TX 0 +#define FT5402_HOST_NUMBER_SUPPORTED 1 +#define FT5402_RV_G_RAISE_THGROUP 30 +#define FT5402_RV_G_CHARGER_STATE 0 +#define FT5402_RV_G_FILTERID_START 2 +#define FT5402_FRAME_FILTER_EN 1 +#define FT5402_FRAME_FILTER_SUB_MAX_TH 2 +#define FT5402_FRAME_FILTER_ADD_MAX_TH 2 +#define FT5402_FRAME_FILTER_SKIP_START_FRAME 6 +#define FT5402_FRAME_FILTER_BAND_EN 1 +#define FT5402_FRAME_FILTER_BAND_WIDTH 128 +#define FT5402_OTP_PARAM_ID 0 + + +unsigned char g_ft5402_tx_num = 27; +unsigned char g_ft5402_rx_num = 16; +unsigned char g_ft5402_gain = 10; +unsigned char g_ft5402_voltage = 3; +unsigned char g_ft5402_scanselect = 8; +unsigned char g_ft5402_tx_order[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26}; +unsigned char g_ft5402_tx_offset = 2; +unsigned char g_ft5402_tx_cap[] = {42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42}; +unsigned char g_ft5402_rx_order[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; +unsigned char g_ft5402_rx_offset[] = {68,68,68,68,68,68,68,68}; +unsigned char g_ft5402_rx_cap[] = {84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84}; + + +#endif \ No newline at end of file diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft5402_ini_config.h b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft5402_ini_config.h new file mode 100755 index 00000000..138f42e2 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft5402_ini_config.h @@ -0,0 +1,411 @@ +#ifndef __LINUX_FT5402_INI_CONFIG_H__ +#define __LINUX_FT5402_INI_CONFIG_H + + +/*Init param register address*/ +/*factory mode register from 14-131*/ +#define FT5402_REG_TX_NUM 0x03 +#define FT5402_REG_RX_NUM 0x04 +#define FT5402_REG_VOLTAGE 0x05 +#define FT5402_REG_GAIN 0x07 +#define FT5402_REG_SCAN_SELECT 0x4E +#define FT5402_REG_TX_ORDER_START 0x50 +#define FT5402_REG_TX_CAP_START 0x78 +#define FT5402_REG_TX_OFFSET_START 0xBF +#define FT5402_REG_RX_ORDER_START 0xeb +#define FT5402_REG_RX_CAP_START 0xA0 +#define FT5402_REG_RX_OFFSET_START 0xD3 +#define FT5402_REG_START_RX 0x06 +#define FT5402_REG_ADC_TARGET_HIGH 0x08 +#define FT5402_REG_ADC_TARGET_LOW 0x09 + + +#define FT5402_REG_DEVICE_MODE 0x00 + + +/*work mode register from 0-13(0,1,12,13verify or Reserved)and 132-177(159 Reserved)*/ +#define FT5402_REG_THGROUP (0x00+0x80) +#define FT5402_REG_THPEAK (0x01+0x80) +#define FT5402_REG_PWMODE_CTRL (0x06+0x80) +#define FT5402_REG_PERIOD_ACTIVE (0x59+0x80) +#define FT5402_REG_POINTS_SUPPORTED (0x0A+0x80) +#define FT5402_REG_ESD_FILTER_FRAME (0x4F+0x80) + +#define FT5402_REG_RESOLUTION_X_H (0x18+0x80) +#define FT5402_REG_RESOLUTION_X_L (0x19+0x80) +#define FT5402_REG_RESOLUTION_Y_H (0x1a+0x80) +#define FT5402_REG_RESOLUTION_Y_L (0x1b+0x80) +#define FT5402_REG_KX_H (0x1c+0x80) +#define FT5402_REG_KX_L (0x9d) +#define FT5402_REG_KY_H (0x9e) +#define FT5402_REG_KY_L (0x1f+0x80) +#define FT5402_REG_CUSTOMER_ID (0xA8) +#define FT5402_REG_DRAW_LINE_TH (0xAe) +#define FT5402_REG_FACE_DETECT_MODE (0xB0) +#define FT5402_REG_MAX_TOUCH_VALUE_HIGH (0xD0) +#define FT5402_REG_MAX_TOUCH_VALUE_LOW (0xD1) + +#define FT5402_REG_DIRECTION (0x53+0x80) +#define FT5402_REG_LEMDA_X (0x41+0x80) +#define FT5402_REG_LEMDA_Y (0x42+0x80) +#define FT5402_REG_FACE_DETECT_STATISTICS_TX_NUM (0x43+0x80) +#define FT5402_REG_FACE_DETECT_PRE_VALUE (0x44+0x80) +#define FT5402_REG_FACE_DETECT_NUM (0x45+0x80) +#define FT5402_REG_BIGAREA_PEAK_VALUE_MIN (0x33+0x80) +#define FT5402_REG_BIGAREA_DIFF_VALUE_OVER_NUM (0x34+0x80) + +/**************************************************************************/ +#define FT5402_REG_FT5402_POINTS_STABLE_MACRO (0x57+0x80) +#define FT5402_REG_FT5402_MIN_DELTA_X (0x4a+0x80) +#define FT5402_REG_FT5402_MIN_DELTA_Y (0x4b+0x80) +#define FT5402_REG_FT5402_MIN_DELTA_STEP (0x4c+0x80) + +#define FT5402_REG_FT5402_ESD_NOISE_MACRO (0x58+0x80) +#define FT5402_REG_FT5402_ESD_DIFF_VAL (0x4d+0x80) +#define FT5402_REG_FT5402_ESD_NEGTIVE (0xCe) +#define FT5402_REG_FT5402_ESD_FILTER_FRAMES (0x4f+0x80) + +#define FT5402_REG_FT5402_IO_LEVEL_SELECT (0x52+0x80) + +#define FT5402_REG_FT5402_POINTID_DELAY_COUNT (0x54+0x80) + +#define FT5402_REG_FT5402_LIFTUP_FILTER_MACRO (0x55+0x80) + +#define FT5402_REG_FT5402_DIFF_HANDLE_MACRO (0x5A+0x80) +#define FT5402_REG_FT5402_MIN_WATER (0x5B+0x80) +#define FT5402_REG_FT5402_MAX_NOISE (0x5C+0x80) +#define FT5402_REG_FT5402_WATER_START_RX (0x5D+0x80) +#define FT5402_REG_FT5402_WATER_START_TX (0xDE) + +#define FT5402_REG_FT5402_HOST_NUMBER_SUPPORTED_MACRO (0x38+0x80) +#define FT5402_REG_FT5402_RAISE_THGROUP (0x36+0x80) +#define FT5402_REG_FT5402_CHARGER_STATE (0x35+0x80) + +#define FT5402_REG_FT5402_FILTERID_START (0x37+0x80) + +#define FT5402_REG_FT5402_FRAME_FILTER_EN_MACRO (0x5F+0x80) +#define FT5402_REG_FT5402_FRAME_FILTER_SUB_MAX_TH (0x60+0x80) +#define FT5402_REG_FT5402_FRAME_FILTER_ADD_MAX_TH (0x61+0x80) +#define FT5402_REG_FT5402_FRAME_FILTER_SKIP_START_FRAME (0x62+0x80) +#define FT5402_REG_FT5402_FRAME_FILTER_BAND_EN (0x63+0x80) +#define FT5402_REG_FT5402_FRAME_FILTER_BAND_WIDTH (0x64+0x80) +/**************************************************************************/ + +#define FT5402_REG_TEST_MODE 0x04 +#define FT5402_REG_TEST_MODE_2 0x05 +#define FT5402_TX_TEST_MODE_1 0x28 +#define FT5402_RX_TEST_MODE_1 0x1E +#define FT5402_FACTORYMODE_VALUE 0x40 +#define FT5402_WORKMODE_VALUE 0x00 + +/************************************************************************/ +/* string */ +/************************************************************************/ +#define STRING_FT5402_KX "FT5X02_KX" +#define STRING_FT5402_KY "FT5X02_KY" +#define STRING_FT5402_LEMDA_X "FT5X02_LEMDA_X" +#define STRING_FT5402_LEMDA_Y "FT5X02_LEMDA_Y" +#define STRING_FT5402_RESOLUTION_X "FT5X02_RESOLUTION_X" +#define STRING_FT5402_RESOLUTION_Y "FT5X02_RESOLUTION_Y" +#define STRING_FT5402_DIRECTION "FT5X02_DIRECTION" + + + +#define STRING_FT5402_FACE_DETECT_PRE_VALUE "FT5X02_FACE_DETECT_PRE_VALUE" +#define STRING_FT5402_FACE_DETECT_NUM "FT5X02_FACE_DETECT_NUM" +#define STRING_FT5402_BIGAREA_PEAK_VALUE_MIN "FT5X02_BIGAREA_PEAK_VALUE_MIN" +#define STRING_FT5402_BIGAREA_DIFF_VALUE_OVER_NUM "FT5X02_BIGAREA_DIFF_VALUE_OVER_NUM" +#define STRING_FT5402_CUSTOMER_ID "FT5X02_CUSTOMER_ID" +#define STRING_FT5402_PERIOD_ACTIVE "FT5X02_RV_G_PERIOD_ACTIVE" +#define STRING_FT5402_FACE_DETECT_STATISTICS_TX_NUM "FT5X02_FACE_DETECT_STATISTICS_TX_NUM" + +#define STRING_FT5402_THGROUP "FT5X02_THGROUP" +#define STRING_FT5402_THPEAK "FT5X02_THPEAK" +#define STRING_FT5402_FACE_DETECT_MODE "FT5X02_FACE_DETECT_MODE" +#define STRING_FT5402_MAX_TOUCH_VALUE "FT5X02_MAX_TOUCH_VALUE" + +#define STRING_FT5402_PWMODE_CTRL "FT5X02_PWMODE_CTRL" +#define STRING_FT5402_DRAW_LINE_TH "FT5X02_DRAW_LINE_TH" + +#define STRING_FT5402_POINTS_SUPPORTED "FT5X02_POINTS_SUPPORTED" + +#define STRING_FT5402_START_RX "FT5X02_START_RX" +#define STRING_FT5402_ADC_TARGET "FT5X02_ADC_TARGET" +#define STRING_FT5402_ESD_FILTER_FRAME "FT5X02_ESD_FILTER_FRAME" + +#define STRING_FT5402_POINTS_STABLE_MACRO "FT5X02_POINTS_STABLE_MACRO" +#define STRING_FT5402_MIN_DELTA_X "FT5X02_MIN_DELTA_X" +#define STRING_FT5402_MIN_DELTA_Y "FT5X02_MIN_DELTA_Y" +#define STRING_FT5402_MIN_DELTA_STEP "FT5X02_MIN_DELTA_STEP" + +#define STRING_FT5402_ESD_NOISE_MACRO "FT5X02_ESD_NOISE_MACRO" +#define STRING_FT5402_ESD_DIFF_VAL "FT5X02_ESD_DIFF_VAL" +#define STRING_FT5402_ESD_NEGTIVE "FT5X02_ESD_NEGTIVE" +#define STRING_FT5402_ESD_FILTER_FRAME "FT5X02_ESD_FILTER_FRAME" + +#define STRING_FT5402_IO_LEVEL_SELECT "FT5X02_IO_LEVEL_SELECT" +#define STRING_FT5402_POINTID_DELAY_COUNT "FT5X02_POINTID_DELAY_COUNT" + +#define STRING_FT5402_LIFTUP_FILTER_MACRO "FT5X02_LIFTUP_FILTER_MACRO" + +#define STRING_FT5402_DIFFDATA_HANDLE "FT5X02_DIFFDATA_HANDLE" //_MACRO +#define STRING_FT5402_MIN_WATER_VAL "FT5X02_MIN_WATER_VAL" +#define STRING_FT5402_MAX_NOISE_VAL "FT5X02_MAX_NOISE_VAL" +#define STRING_FT5402_WATER_HANDLE_START_RX "FT5X02_WATER_HANDLE_START_RX" +#define STRING_FT5402_WATER_HANDLE_START_TX "FT5X02_WATER_HANDLE_START_TX" + +#define STRING_FT5402_HOST_NUMBER_SUPPORTED "FT5X02_HOST_NUMBER_SUPPORTED" +#define STRING_FT5402_RV_G_RAISE_THGROUP "FT5X02_RV_G_RAISE_THGROUP" +#define STRING_FT5402_RV_G_CHARGER_STATE "FT5X02_RV_G_CHARGER_STATE" + +#define STRING_FT5402_RV_G_FILTERID_START "FT5X02_RV_G_FILTERID_START" + +#define STRING_FT5402_FRAME_FILTER_EN "FT5X02_FRAME_FILTER_EN" +#define STRING_FT5402_FRAME_FILTER_SUB_MAX_TH "FT5X02_FRAME_FILTER_SUB_MAX_TH" +#define STRING_FT5402_FRAME_FILTER_ADD_MAX_TH "FT5X02_FRAME_FILTER_ADD_MAX_TH" +#define STRING_FT5402_FRAME_FILTER_SKIP_START_FRAME "FT5X02_FRAME_FILTER_SKIP_START_FRAME" +#define STRING_FT5402_FRAME_FILTER_BAND_EN "FT5X02_FRAME_FILTER_BAND_EN" +#define STRING_FT5402_FRAME_FILTER_BAND_WIDTH "FT5X02_FRAME_FILTER_BAND_WIDTH" + + +#define STRING_ft5402_tx_num "FT5X02_tx_num" +#define STRING_ft5402_rx_num "FT5X02_rx_num" +#define STRING_ft5402_gain "FT5X02_gain" +#define STRING_ft5402_voltage "FT5X02_voltage" +#define STRING_ft5402_scanselect "FT5X02_scanselect" + +#define STRING_ft5402_tx_order "FT5X02_tx_order" +#define STRING_ft5402_tx_offset "FT5X02_tx_offset" +#define STRING_ft5402_tx_cap "FT5X02_tx_cap" + +#define STRING_ft5402_rx_order "FT5X02_rx_order" +#define STRING_ft5402_rx_offset "FT5X02_rx_offset" +#define STRING_ft5402_rx_cap "FT5X02_rx_cap" + +struct Struct_Param_FT5402 { + short ft5402_KX; + short ft5402_KY; + unsigned char ft5402_LEMDA_X; + unsigned char ft5402_LEMDA_Y; + short ft5402_RESOLUTION_X; + short ft5402_RESOLUTION_Y; + unsigned char ft5402_DIRECTION; + unsigned char ft5402_FACE_DETECT_PRE_VALUE; + unsigned char ft5402_FACE_DETECT_NUM; + + unsigned char ft5402_BIGAREA_PEAK_VALUE_MIN; + unsigned char ft5402_BIGAREA_DIFF_VALUE_OVER_NUM; + unsigned char ft5402_CUSTOMER_ID; + unsigned char ft5402_PERIOD_ACTIVE; + unsigned char ft5402_FACE_DETECT_STATISTICS_TX_NUM; + + short ft5402_THGROUP; + unsigned char ft5402_THPEAK; + unsigned char ft5402_FACE_DETECT_MODE; + short ft5402_MAX_TOUCH_VALUE; + + unsigned char ft5402_PWMODE_CTRL; + unsigned char ft5402_DRAW_LINE_TH; + unsigned char ft5402_POINTS_SUPPORTED; + + unsigned char ft5402_START_RX; + short ft5402_ADC_TARGET; + unsigned char ft5402_ESD_FILTER_FRAME; + + unsigned char ft5402_POINTS_STABLE_MACRO; + unsigned char ft5402_MIN_DELTA_X; + unsigned char ft5402_MIN_DELTA_Y; + unsigned char ft5402_MIN_DELTA_STEP; + + unsigned char ft5402_ESD_NOISE_MACRO; + unsigned char ft5402_ESD_DIFF_VAL; + char ft5402_ESD_NEGTIVE; //negtive + unsigned char ft5402_ESD_FILTER_FRAMES; + + unsigned char ft5402_IO_LEVEL_SELECT; + + unsigned char ft5402_POINTID_DELAY_COUNT; + + unsigned char ft5402_LIFTUP_FILTER_MACRO; + + unsigned char ft5402_DIFF_HANDLE_MACRO; + char ft5402_MIN_WATER; //negtive + unsigned char ft5402_MAX_NOISE; + unsigned char ft5402_WATER_START_RX; + unsigned char ft5402_WATER_START_TX; + + unsigned char ft5402_HOST_NUMBER_SUPPORTED_MACRO; + unsigned char ft5402_RAISE_THGROUP; + unsigned char ft5402_CHARGER_STATE; + + unsigned char ft5402_FILTERID_START; + + unsigned char ft5402_FRAME_FILTER_EN_MACRO; + unsigned char ft5402_FRAME_FILTER_SUB_MAX_TH; + unsigned char ft5402_FRAME_FILTER_ADD_MAX_TH; + unsigned char ft5402_FRAME_FILTER_SKIP_START_FRAME; + unsigned char ft5402_FRAME_FILTER_BAND_EN; + unsigned char ft5402_FRAME_FILTER_BAND_WIDTH; + +}; + +struct Struct_Param_FT5402 g_param_ft5402 = { + FT5402_KX, + FT5402_KY, + FT5402_LEMDA_X, + FT5402_LEMDA_Y, + FT5402_RESOLUTION_X, + FT5402_RESOLUTION_Y, + FT5402_DIRECTION, + + FT5402_FACE_DETECT_PRE_VALUE, + FT5402_FACE_DETECT_NUM, + FT5402_BIGAREA_PEAK_VALUE_MIN, + FT5402_BIGAREA_DIFF_VALUE_OVER_NUM, + FT5402_CUSTOMER_ID, + FT5402_RV_G_PERIOD_ACTIVE, + FT5402_FACE_DETECT_STATISTICS_TX_NUM, + + FT5402_THGROUP, + FT5402_THPEAK, + FT5402_FACE_DETECT_MODE, + FT5402_MAX_TOUCH_VALUE, + + FT5402_PWMODE_CTRL, + FT5402_DRAW_LINE_TH, + FT5402_POINTS_SUPPORTED, + + FT5402_START_RX, + FT5402_ADC_TARGET, + FT5402_ESD_FILTER_FRAME, + + FT5402_POINTS_STABLE_MACRO, + FT5402_MIN_DELTA_X, + FT5402_MIN_DELTA_Y, + FT5402_MIN_DELTA_STEP, + + FT5402_ESD_NOISE_MACRO, + FT5402_ESD_DIFF_VAL, + FT5402_ESD_NEGTIVE, + FT5402_ESD_FILTER_FRAME, + + FT5402_IO_LEVEL_SELECT, + + FT5402_POINTID_DELAY_COUNT, + + FT5402_LIFTUP_FILTER_MACRO, + + FT5402_DIFFDATA_HANDLE, + FT5402_MIN_WATER_VAL, + FT5402_MAX_NOISE_VAL, + FT5402_WATER_HANDLE_START_RX, + FT5402_WATER_HANDLE_START_TX, + + FT5402_HOST_NUMBER_SUPPORTED, + FT5402_RV_G_RAISE_THGROUP, + FT5402_RV_G_CHARGER_STATE, + + FT5402_RV_G_FILTERID_START, + + FT5402_FRAME_FILTER_EN, + FT5402_FRAME_FILTER_SUB_MAX_TH, + FT5402_FRAME_FILTER_ADD_MAX_TH, + FT5402_FRAME_FILTER_SKIP_START_FRAME, + FT5402_FRAME_FILTER_BAND_EN, + FT5402_FRAME_FILTER_BAND_WIDTH, +}; + +char String_Param_FT5402[][64] = { + STRING_FT5402_KX, + STRING_FT5402_KY, + STRING_FT5402_LEMDA_X, + STRING_FT5402_LEMDA_Y, + STRING_FT5402_RESOLUTION_X, + STRING_FT5402_RESOLUTION_Y, + STRING_FT5402_DIRECTION, + STRING_FT5402_FACE_DETECT_PRE_VALUE, + STRING_FT5402_FACE_DETECT_NUM, + STRING_FT5402_BIGAREA_PEAK_VALUE_MIN, + STRING_FT5402_BIGAREA_DIFF_VALUE_OVER_NUM, + STRING_FT5402_CUSTOMER_ID, + STRING_FT5402_PERIOD_ACTIVE, + STRING_FT5402_FACE_DETECT_STATISTICS_TX_NUM, + + STRING_FT5402_THGROUP, + STRING_FT5402_THPEAK, + STRING_FT5402_FACE_DETECT_MODE, + STRING_FT5402_MAX_TOUCH_VALUE, + + STRING_FT5402_PWMODE_CTRL, + STRING_FT5402_DRAW_LINE_TH, + STRING_FT5402_POINTS_SUPPORTED, + + STRING_FT5402_START_RX, + STRING_FT5402_ADC_TARGET, + STRING_FT5402_ESD_FILTER_FRAME, + + + STRING_ft5402_tx_num, + STRING_ft5402_rx_num, + STRING_ft5402_gain, + STRING_ft5402_voltage , + STRING_ft5402_scanselect, + + STRING_ft5402_tx_order, + STRING_ft5402_tx_offset, + STRING_ft5402_tx_cap, + + STRING_ft5402_rx_order, + STRING_ft5402_rx_offset, + STRING_ft5402_rx_cap, + + STRING_FT5402_POINTS_STABLE_MACRO, + STRING_FT5402_MIN_DELTA_X, + STRING_FT5402_MIN_DELTA_Y, + STRING_FT5402_MIN_DELTA_STEP, + + STRING_FT5402_ESD_NOISE_MACRO, + STRING_FT5402_ESD_DIFF_VAL, + STRING_FT5402_ESD_NEGTIVE, + STRING_FT5402_ESD_FILTER_FRAME, + + STRING_FT5402_IO_LEVEL_SELECT, + + STRING_FT5402_POINTID_DELAY_COUNT, + + STRING_FT5402_LIFTUP_FILTER_MACRO, + + STRING_FT5402_DIFFDATA_HANDLE, + STRING_FT5402_MIN_WATER_VAL, + STRING_FT5402_MAX_NOISE_VAL, + STRING_FT5402_WATER_HANDLE_START_RX, + STRING_FT5402_WATER_HANDLE_START_TX, + + STRING_FT5402_HOST_NUMBER_SUPPORTED, + STRING_FT5402_RV_G_RAISE_THGROUP, + STRING_FT5402_RV_G_CHARGER_STATE, + + STRING_FT5402_RV_G_FILTERID_START, + + STRING_FT5402_FRAME_FILTER_EN, + STRING_FT5402_FRAME_FILTER_SUB_MAX_TH, + STRING_FT5402_FRAME_FILTER_ADD_MAX_TH, + STRING_FT5402_FRAME_FILTER_SKIP_START_FRAME, + STRING_FT5402_FRAME_FILTER_BAND_EN, + STRING_FT5402_FRAME_FILTER_BAND_WIDTH, + +}; + +#define FT5402_APP_NAME "FT5X02_param" + +#define FT5402_APP_LEGAL "Legal_File" +#define FT5402_APP_LEGAL_BYTE_1_STR "BYTE_1" +#define FT5402_APP_LEGAL_BYTE_2_STR "BYTE_2" + +#define FT5402_APP_LEGAL_BYTE_1_VALUE 107 +#define FT5402_APP_LEGAL_BYTE_2_VALUE 201 + + +#define FT5402_INI_FILEPATH "/system/etc/firmware/" + +#endif diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft5x0x.c b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft5x0x.c new file mode 100755 index 00000000..a3f6c4c9 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft5x0x.c @@ -0,0 +1,896 @@ +/* + * drivers/input/touchscreen/ft5x0x/ft5x0x.c + * + * FocalTech ft5x0x TouchScreen driver. + * + * Copyright (c) 2010 Focal tech Ltd. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + * + * note: only support mulititouch Wenfs 2010-10-01 + */ +#include +#include +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ft5x0x.h" + +struct ft5x0x_data *pContext=NULL; +static struct i2c_client *l_client=NULL; + +#ifdef TOUCH_KEY +static int keycodes[NUM_KEYS] ={ + KEY_MENU, + KEY_HOME, + KEY_BACK, + KEY_SEARCH +}; +#endif + +#define FT5402_CONFIG_NAME "fttpconfig_5402public.ini" +extern int ft5x0x_read_fw_ver(void); +extern int ft5x0x_auto_clb(void); +extern int ft5x0x_upg_fw_bin(struct ft5x0x_data *ft5x0x, int check_ver); +extern int ft5402_Get_Param_From_Ini(char *config_name); +extern int ft5402_Init_IC_Param(struct i2c_client *client); +extern int ft5402_get_ic_param(struct i2c_client *client); +extern int ft5402_read_reg(struct i2c_client * client, u8 regaddr, u8 * regvalue); +static unsigned char ft5x0x_debug = 0; + +extern int fts_ctpm_fw_upgrade_with_i_file(struct i2c_client * client); +int ft5x0x_i2c_rxdata(char *rxdata, int length) +{ + int ret; + struct i2c_msg msg[2]; + + msg[0].addr = pContext->addr; + msg[0].flags = 0 | I2C_M_NOSTART; + msg[0].len = 1; + msg[0].buf = rxdata; + + msg[1].addr = pContext->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = length; + msg[1].buf = rxdata; + + ret = i2c_transfer(pContext->client->adapter, msg, 2); + if (ret <= 0) + dbg_err("msg i2c read error: %d\n", ret); + + return ret; +} + + +int ft5x0x_i2c_txdata(char *txdata, int length) +{ + int ret; + struct i2c_msg msg[1]; + + msg[0].addr = pContext->addr; + msg[0].flags = 0; + msg[0].len = length; + msg[0].buf = txdata; + + ret = i2c_transfer(pContext->client->adapter, msg, 1); + if (ret <= 0) + dbg_err("msg i2c read error: %d\n", ret); + + return ret; +} + +static void ft5x0x_penup(struct ft5x0x_data *ft5x0x) +{ + input_mt_sync(ft5x0x->input_dev); + input_sync(ft5x0x->input_dev); +#ifdef TOUCH_KEY + if(ft5x0x->tskey_used && ft5x0x->tkey_pressed && ft5x0x->tkey_idx < NUM_KEYS ){ + input_report_key(ft5x0x->input_dev, keycodes[ft5x0x->tkey_idx], 1); + input_sync(ft5x0x->input_dev); + input_report_key(ft5x0x->input_dev, keycodes[ft5x0x->tkey_idx], 0); + input_sync(ft5x0x->input_dev); + dbg("report as key event %d \n",ft5x0x->tkey_idx); + } +#endif + + dbg("pen up\n"); + return; +} + +#ifdef TOUCH_KEY +static int ft5x0x_read_tskey(struct ft5x0x_data *ft5x0x,int x,int y) +{ + int px,py; + + if(ft5x0x->tkey.axis){ + px = y; + py = x; + }else{ + px = x; + py = y; + } + + if(px >= ft5x0x->tkey.x_lower && px<=ft5x0x->tkey.x_upper){ + ft5x0x->tkey_pressed = 1; + if(py>= ft5x0x->tkey.ypos[0].y_lower && py<= ft5x0x->tkey.ypos[0].y_upper){ + ft5x0x->tkey_idx= 0; + }else if(py>= ft5x0x->tkey.ypos[1].y_lower && py<= ft5x0x->tkey.ypos[1].y_upper){ + ft5x0x->tkey_idx = 1; + }else if(py>= ft5x0x->tkey.ypos[2].y_lower && py<= ft5x0x->tkey.ypos[2].y_upper){ + ft5x0x->tkey_idx = 2; + }else if(py>= ft5x0x->tkey.ypos[3].y_lower && py<= ft5x0x->tkey.ypos[3].y_upper){ + ft5x0x->tkey_idx = 3; + }else{ + ft5x0x->tkey_idx = NUM_KEYS; + } + + return 1; + } + + ft5x0x->tkey_pressed = 0; + return 0; +} +#endif + +static int ft5x0x_read_data(struct ft5x0x_data *ft5x0x) +{ + int ret = -1; + int i = 0; + u16 x,y,px,py; + u8 buf[64] = {0}, id; + struct ts_event *event = &ft5x0x->event; + + if(ft5x0x->nt == 10) + ret = ft5x0x_i2c_rxdata(buf, 64); + else if(ft5x0x->nt == 5) + ret = ft5x0x_i2c_rxdata(buf, 31); + + if (ret <= 0) { + dbg_err("read_data i2c_rxdata failed: %d\n", ret); + return ret; + } + + memset(event, 0, sizeof(struct ts_event)); + //event->tpoint = buf[2] & 0x03;// 0000 0011 + //event->tpoint = buf[2] & 0x07;// 000 0111 + event->tpoint = buf[2]&0x0F; + if (event->tpoint == 0) { + ft5x0x_penup(ft5x0x); + return 1; + } + + if (event->tpoint > ft5x0x->nt){ + dbg_err("tounch pointnum=%d > max:%d\n", event->tpoint,ft5x0x->nt); + return -1; + } + + for (i = 0; i < event->tpoint; i++){ + id = (buf[5+i*6] >>4) & 0x0F;//get track id + if(ft5x0x->swap){ + px = (buf[3+i*6] & 0x0F)<<8 |buf[4+i*6]; + py = (buf[5+i*6] & 0x0F)<<8 |buf[6+i*6]; + }else{ + px = (buf[5+i*6] & 0x0F)<<8 |buf[6+i*6]; + py = (buf[3+i*6] & 0x0F)<<8 |buf[4+i*6]; + } + + x = px; + y = py; + + if(ft5x0x->xch) + x = ft5x0x->reslx - px; + + if(ft5x0x->ych) + y = ft5x0x->resly - py; + + if(ft5x0x->dbg) printk("F%d: Tid=%d,px=%d,py=%d; x=%d,y=%d\n", i, id, px, py, x, y); + +#ifdef TOUCH_KEY + if(ft5x0x->tskey_used && event->tpoint==1) { + if(ft5x0x_read_tskey(ft5x0x,px,py) > 0) return -1; + } +#endif + event->x[i] = x; + event->y[i] = y; + event->tid[i] = id; + + } + + return 0; +} + +static void ft5x0x_report(struct ft5x0x_data *ft5x0x) +{ + int i = 0; + struct ts_event *event = &ft5x0x->event; + + for (i = 0; i < event->tpoint; i++){ + input_report_abs(ft5x0x->input_dev, ABS_MT_TRACKING_ID, event->tid[i]); + input_report_abs(ft5x0x->input_dev, ABS_MT_POSITION_X, event->x[i]); + input_report_abs(ft5x0x->input_dev, ABS_MT_POSITION_Y, event->y[i]); + input_mt_sync(ft5x0x->input_dev); + } + input_sync(ft5x0x->input_dev); + + return; +} + +static void ft5x0x_read_work(struct work_struct *work) +{ + int ret = -1; + struct ft5x0x_data *ft5x0x = container_of(work, struct ft5x0x_data, read_work); + + mutex_lock(&ft5x0x->ts_mutex); + ret = ft5x0x_read_data(ft5x0x); + + if (ret == 0) ft5x0x_report(ft5x0x); + + wmt_gpio_unmask_irq(ft5x0x->irqgpio); + mutex_unlock(&ft5x0x->ts_mutex); + + return; +} + +static irqreturn_t ft5x0x_interrupt(int irq, void *dev) +{ + struct ft5x0x_data *ft5x0x = dev; + + if (gpio_irqstatus(ft5x0x->irqgpio)) + { + + if(ft5x0x_debug == 1) + { + printk("++++++++++++%s\n",__func__); + } + wmt_gpio_ack_irq(ft5x0x->irqgpio); + if (is_gpio_irqenable(ft5x0x->irqgpio)) + { + wmt_gpio_mask_irq(ft5x0x->irqgpio); +#ifdef CONFIG_HAS_EARLYSUSPEND + if(!ft5x0x->earlysus) queue_work(ft5x0x->workqueue, &ft5x0x->read_work); +#else + queue_work(ft5x0x->workqueue, &ft5x0x->read_work); +#endif + + } + return IRQ_HANDLED; + } + return IRQ_NONE; +} + +static void ft5x0x_reset(struct ft5x0x_data *ft5x0x) +{ + gpio_set_value(ft5x0x->rstgpio, 1); + mdelay(5); + gpio_set_value(ft5x0x->rstgpio, 0); + mdelay(20); + gpio_set_value(ft5x0x->rstgpio, 1); + mdelay(5); + + return; +} + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void ft5x0x_early_suspend(struct early_suspend *handler) +{ + struct ft5x0x_data *ft5x0x = container_of(handler, struct ft5x0x_data, early_suspend); + ft5x0x->earlysus = 1; + wmt_gpio_mask_irq(ft5x0x->irqgpio); + return; +} + +static void ft5x0x_late_resume(struct early_suspend *handler) +{ + struct ft5x0x_data *ft5x0x = container_of(handler, struct ft5x0x_data, early_suspend); + + ft5x0x_reset(ft5x0x); + ft5x0x->earlysus = 0; + + wmt_gpio_set_irq_type(ft5x0x->irqgpio, IRQ_TYPE_EDGE_FALLING); + wmt_gpio_unmask_irq(ft5x0x->irqgpio); + + return; +} +#endif //CONFIG_HAS_EARLYSUSPEND + +#ifdef CONFIG_PM +static int ft5x0x_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct ft5x0x_data *ft5x0x = dev_get_drvdata(&pdev->dev); + ft5x0x->earlysus = 1; + wmt_gpio_mask_irq(ft5x0x->irqgpio); + return 0; +} + +static int ft5x0x_resume(struct platform_device *pdev) +{ + struct ft5x0x_data *ft5x0x = dev_get_drvdata(&pdev->dev); + ft5x0x_reset(ft5x0x); + ft5x0x->earlysus = 0; + + if (ft5x0x->load_cfg) { + msleep(350); + ft5402_Init_IC_Param(ft5x0x->client); + //msleep(50); + ft5402_get_ic_param(ft5x0x->client); + } + wmt_gpio_set_irq_type(ft5x0x->irqgpio, IRQ_TYPE_EDGE_FALLING); + wmt_gpio_unmask_irq(ft5x0x->irqgpio); + return 0; +} + +#else +#define ft5x0x_suspend NULL +#define ft5x0x_resume NULL +#endif + +static ssize_t cat_dbg(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "dbg \n"); +} + +static ssize_t echo_dbg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned int dbg = simple_strtoul(buf, NULL, 10); + struct ft5x0x_data *ft5x0x = pContext; + + if(dbg){ + ft5x0x->dbg = 1; + }else{ + ft5x0x->dbg = 0; + } + + return count; +} +static DEVICE_ATTR(dbg, S_IRUGO | S_IWUSR, cat_dbg, echo_dbg); + +static ssize_t cat_clb(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "calibrate \n"); +} + +static ssize_t echo_clb(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned int cal = simple_strtoul(buf, NULL, 10); + + if(cal){ + if(ft5x0x_auto_clb()) printk("Calibrate Failed.\n"); + }else{ + printk("calibrate --echo 1 >clb.\n"); + } + + return count; +} + +static DEVICE_ATTR(clb, S_IRUGO | S_IWUSR, cat_clb, echo_clb); + +static ssize_t cat_fupg(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "fupg \n"); +} + +static ssize_t echo_fupg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct ft5x0x_data *ft5x0x = pContext; + unsigned int upg = simple_strtoul(buf, NULL, 10); + + wmt_gpio_mask_irq(ft5x0x->irqgpio); + if(upg){ + if(ft5x0x_upg_fw_bin(ft5x0x, 0)) printk("Upgrade Failed.\n"); + }else{ + printk("upgrade --echo 1 > fupg.\n"); + } + wmt_gpio_unmask_irq(ft5x0x->irqgpio); + + return count; +} +static DEVICE_ATTR(fupg, S_IRUGO | S_IWUSR, cat_fupg, echo_fupg); + + +static ssize_t cat_fver(struct device *dev, struct device_attribute *attr, char *buf) +{ + int fw_ver = ft5x0x_read_fw_ver(); + return sprintf(buf, "firmware version:0x%02x \n",fw_ver); +} + +static ssize_t echo_fver(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return count; +} +static DEVICE_ATTR(fver, S_IRUGO | S_IWUSR, cat_fver, echo_fver); + +static ssize_t cat_addr(struct device *dev, struct device_attribute *attr, char *buf) +{ + int ret; + u8 addrs[32]; + int cnt=0; + struct i2c_msg msg[2]; + struct ft5x0x_data *ft5x0x = pContext; + u8 ver[1]= {0xa6}; + + ft5x0x->addr = 1; + + msg[0].addr = ft5x0x->addr; + msg[0].flags = 0; + msg[0].len = 1; + msg[0].buf = ver; + + msg[1].addr = ft5x0x->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = 1; + msg[1].buf = ver; + + while(ft5x0x->addr < 0x80){ + ret = i2c_transfer(ft5x0x->client->adapter, msg, 2); + if(ret == 2) sprintf(&addrs[5*cnt++], " 0x%02x",ft5x0x->addr); + + ft5x0x->addr++; + msg[0].addr = msg[1].addr = ft5x0x->addr; + } + + return sprintf(buf, "i2c addr:%s\n",addrs); +} + +static ssize_t echo_addr(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned int addr; + struct ft5x0x_data *ft5x0x = pContext; + + sscanf(buf,"%x", &addr); + ft5x0x->addr = addr; + + return count; +} +static DEVICE_ATTR(addr, S_IRUGO | S_IWUSR, cat_addr, echo_addr); + +static struct attribute *ft5x0x_attributes[] = { + &dev_attr_clb.attr, + &dev_attr_fupg.attr, + &dev_attr_fver.attr, + &dev_attr_dbg.attr, + &dev_attr_addr.attr, + NULL +}; + +static const struct attribute_group ft5x0x_group = { + .attrs = ft5x0x_attributes, +}; + +static int ft5x0x_sysfs_create_group(struct ft5x0x_data *ft5x0x, const struct attribute_group *group) +{ + int err; + + ft5x0x->kobj = kobject_create_and_add("wmtts", NULL) ; + if(!ft5x0x->kobj){ + dbg_err("kobj create failed.\n"); + return -ENOMEM; + } + + /* Register sysfs hooks */ + err = sysfs_create_group(ft5x0x->kobj, group); + if (err < 0){ + kobject_del(ft5x0x->kobj); + dbg_err("Create sysfs group failed!\n"); + return -ENOMEM; + } + + return 0; +} + +static void ft5x0x_sysfs_remove_group(struct ft5x0x_data *ft5x0x, const struct attribute_group *group) +{ + sysfs_remove_group(ft5x0x->kobj, group); + kobject_del(ft5x0x->kobj); + return; +} + +static int ft5x0x_probe(struct platform_device *pdev) +{ + int i,err = 0; + u8 value = 0; + u8 cfg_name[32]; + struct ft5x0x_data *ft5x0x = platform_get_drvdata( pdev); + + ft5x0x->client = l_client; + INIT_WORK(&ft5x0x->read_work, ft5x0x_read_work); + mutex_init(&ft5x0x->ts_mutex); + + ft5x0x->workqueue = create_singlethread_workqueue(ft5x0x->name); + if (!ft5x0x->workqueue) { + err = -ESRCH; + goto exit_create_singlethread; + } + + err = ft5x0x_sysfs_create_group(ft5x0x, &ft5x0x_group); + if(err < 0){ + dbg("create sysfs group failed.\n"); + goto exit_create_group; + } + + ft5x0x->input_dev = input_allocate_device(); + if (!ft5x0x->input_dev) { + err = -ENOMEM; + dbg("failed to allocate input device\n"); + goto exit_input_dev_alloc_failed; + } + + ft5x0x->input_dev->name = ft5x0x->name; + ft5x0x->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + set_bit(INPUT_PROP_DIRECT, ft5x0x->input_dev->propbit); + + input_set_abs_params(ft5x0x->input_dev, + ABS_MT_POSITION_X, 0, ft5x0x->reslx, 0, 0); + input_set_abs_params(ft5x0x->input_dev, + ABS_MT_POSITION_Y, 0, ft5x0x->resly, 0, 0); + input_set_abs_params(ft5x0x->input_dev, + ABS_MT_TRACKING_ID, 0, 20, 0, 0); +#ifdef TOUCH_KEY + if(ft5x0x->tskey_used){ + for (i = 0; i input_dev->keybit); + + ft5x0x->input_dev->keycode = keycodes; + ft5x0x->input_dev->keycodesize = sizeof(unsigned int); + ft5x0x->input_dev->keycodemax = NUM_KEYS; + } +#endif + + err = input_register_device(ft5x0x->input_dev); + if (err) { + dbg_err("ft5x0x_ts_probe: failed to register input device.\n"); + goto exit_input_register_device_failed; + } + +#ifdef CONFIG_HAS_EARLYSUSPEND + ft5x0x->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + ft5x0x->early_suspend.suspend = ft5x0x_early_suspend; + ft5x0x->early_suspend.resume = ft5x0x_late_resume; + register_early_suspend(&ft5x0x->early_suspend); +#endif + + if(ft5x0x->upg){ + if (fts_ctpm_fw_upgrade_with_i_file(ft5x0x->client) < 0) { + printk("ft5x0x_probe -----upgrade failed!-\n"); + } + else + { + printk("ft5x0x_probe -----upgrade successful!-\n"); + wmt_setsyspara("wmt.io.ts.upg",""); + ft5x0x_reset(ft5x0x); + } + ft5x0x->upg = 0x00; + } + + if(request_irq(ft5x0x->irq, ft5x0x_interrupt, IRQF_SHARED, ft5x0x->name, ft5x0x) < 0){ + dbg_err("Could not allocate irq for ts_ft5x0x !\n"); + err = -1; + goto exit_register_irq; + } + + { // check if need to load config to IC or not + err = ft5402_read_reg(ft5x0x->client, 0xa3, &value); + if (err < 0) + dbg_err("Read reg 0xa3 failed.\n"); + else + printk("0xa3 reg = %d\n", value); + if (value == 3) + ft5x0x->load_cfg = 1; + else + ft5x0x->load_cfg = 0; + } + ft5x0x_reset(ft5x0x); + + if (ft5x0x->load_cfg) { + msleep(350); /*make sure CTP already finish startup process*/ + sprintf(cfg_name, "%s.ini", ft5x0x->cfg_name); + printk("Config file name: %s\n", cfg_name); + if (ft5402_Get_Param_From_Ini(cfg_name) >= 0) + ft5402_Init_IC_Param(ft5x0x->client); + else + dbg_err("[FTS]-------Get ft5402 param from INI file failed\n"); + ft5402_get_ic_param(ft5x0x->client); + } + + wmt_gpio_set_irq_type(ft5x0x->irqgpio, IRQ_TYPE_EDGE_FALLING); + wmt_gpio_unmask_irq(ft5x0x->irqgpio); + + + return 0; + +exit_register_irq: +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&ft5x0x->early_suspend); +#endif +exit_input_register_device_failed: + input_free_device(ft5x0x->input_dev); +exit_input_dev_alloc_failed: + ft5x0x_sysfs_remove_group(ft5x0x, &ft5x0x_group); +exit_create_group: + cancel_work_sync(&ft5x0x->read_work); + destroy_workqueue(ft5x0x->workqueue); +exit_create_singlethread: + return err; +} + +static int ft5x0x_remove(struct platform_device *pdev) +{ + struct ft5x0x_data *ft5x0x = platform_get_drvdata( pdev); + + cancel_work_sync(&ft5x0x->read_work); + flush_workqueue(ft5x0x->workqueue); + destroy_workqueue(ft5x0x->workqueue); + + free_irq(ft5x0x->irq, ft5x0x); + wmt_gpio_mask_irq(ft5x0x->irqgpio); + +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&ft5x0x->early_suspend); +#endif + input_unregister_device(ft5x0x->input_dev); + + ft5x0x_sysfs_remove_group(ft5x0x, &ft5x0x_group); + + mutex_destroy(&ft5x0x->ts_mutex); + dbg("remove...\n"); + return 0; +} + +static void ft5x0x_release(struct device *device) +{ + return; +} + +static struct platform_device ft5x0x_device = { + .name = DEV_FT5X0X, + .id = 0, + .dev = {.release = ft5x0x_release}, +}; + +static struct platform_driver ft5x0x_driver = { + .driver = { + .name = DEV_FT5X0X, + .owner = THIS_MODULE, + }, + .probe = ft5x0x_probe, + .remove = ft5x0x_remove, + .suspend = ft5x0x_suspend, + .resume = ft5x0x_resume, +}; + +static int check_touch_env(struct ft5x0x_data *ft5x0x) +{ + int i,ret = 0; + int len = 96; + int Enable; + char retval[96] = {0}; + char *p=NULL; + char *s=NULL; + + // Get u-boot parameter + ret = wmt_getsyspara("wmt.io.touch", retval, &len); + if(ret){ + //printk("MST FT5x0x:Read wmt.io.touch Failed.\n"); + return -EIO; + } + sscanf(retval,"%d:",&Enable); + //check touch enable + if(Enable == 0){ + //printk("FT5x0x Touch Screen Is Disabled.\n"); + return -ENODEV; + } + + p = strchr(retval,':'); + p++; + if(strncmp(p,"ft5301",6)==0){//check touch ID + ft5x0x->id = FT5301; + ft5x0x->name = DEV_FT5301; + }else if(strncmp(p,"ft5406",6)==0){ + ft5x0x->id = FT5406; + ft5x0x->name = DEV_FT5406; + }else if(strncmp(p,"ft6336",6)==0){ + ft5x0x->id = FT6336; + ft5x0x->name = DEV_FT6336; + }else if(strncmp(p,"ft5206",6)==0){ + ft5x0x->id = FT5206; + ft5x0x->name = DEV_FT5206; + }else if(strncmp(p,"ft5606",6)==0){ + ft5x0x->id = FT5606; + ft5x0x->name = DEV_FT5606; + }else if(strncmp(p,"ft5306",6)==0){ + ft5x0x->id = FT5306; + ft5x0x->name = DEV_FT5306; + }else if(strncmp(p,"ft5302",6)==0){ + ft5x0x->id = FT5302; + ft5x0x->name = DEV_FT5302; + }else if(strncmp(p,"ft5",3)==0) + { + ft5x0x->id = FT5X0X; + ft5x0x->name = DEV_FT5X0X; + }else{ + printk("FT5x0x touch disabled.\n"); + return -ENODEV; + } + + s = strchr(p,':'); + strncpy(ft5x0x->cfg_name, p, s-p); + + p = s + 1; + sscanf(p,"%d:%d:%d:%d:%d:%d:%d:%d:%x", &ft5x0x->irqgpio, &ft5x0x->reslx, &ft5x0x->resly, &ft5x0x->rstgpio, &ft5x0x->swap, &ft5x0x->xch, &ft5x0x->ych, &ft5x0x->nt, &ft5x0x->addr); + + ft5x0x->irq = IRQ_GPIO; + printk("%s irqgpio=%d, reslx=%d, resly=%d, rstgpio=%d, swap=%d, xch=%d, ych=%d, nt=%d, addr=%x\n", ft5x0x->name, ft5x0x->irqgpio, ft5x0x->reslx, ft5x0x->resly, ft5x0x->rstgpio, ft5x0x->swap, ft5x0x->xch, ft5x0x->ych, ft5x0x->nt, ft5x0x->addr); + + memset(retval,0x00,sizeof(retval)); + ret = wmt_getsyspara("wmt.io.ts.upg", retval, &len); + if(!ret){ + ft5x0x->upg = 1; + strncpy(ft5x0x->fw_name, retval, sizeof(ft5x0x->fw_name)); + } + +#ifdef TOUCH_KEY + memset(retval,0x00,sizeof(retval)); + ret = wmt_getsyspara("wmt.io.tskey", retval, &len); + if(!ret){ + sscanf(retval,"%d:", &ft5x0x->nkeys); + p = strchr(retval,':'); + p++; + for(i=0; i < ft5x0x->nkeys; i++ ){ + sscanf(p,"%d:%d", &ft5x0x->tkey.ypos[i].y_lower, &ft5x0x->tkey.ypos[i].y_upper); + p = strchr(p,':'); + p++; + p = strchr(p,':'); + p++; + } + sscanf(p,"%d:%d:%d", &ft5x0x->tkey.axis, &ft5x0x->tkey.x_lower, &ft5x0x->tkey.x_upper); + ft5x0x->tskey_used = 1; + } +#endif + return 0; +} + +struct i2c_board_info ts_i2c_board_info = { + .type = TS_I2C_NAME, + .flags = 0x00, + .addr = FT5406_I2C_ADDR, + .platform_data = NULL, + .archdata = NULL, + .irq = -1, +}; + +static int ts_i2c_register_device (void) +{ + struct i2c_board_info *ts_i2c_bi; + struct i2c_adapter *adapter = NULL; + //struct i2c_client *client = NULL; + + //ts_i2c_board_info.addr = FT5406_I2C_ADDR; + ts_i2c_bi = &ts_i2c_board_info; + adapter = i2c_get_adapter(FT5X0X_I2C_BUS);/*in bus 1*/ + + if (NULL == adapter) { + printk("can not get i2c adapter, client address error\n"); + return -1; + } + l_client = i2c_new_device(adapter, ts_i2c_bi); + if (l_client == NULL) { + printk("allocate i2c client failed\n"); + return -1; + } + i2c_put_adapter(adapter); + return 0; +} + +static void ts_i2c_unregister_device(void) +{ + if (l_client != NULL) + { + i2c_unregister_device(l_client); + l_client = NULL; + } +} + +static int __init ft5x0x_init(void) +{ + int ret = -ENOMEM; + struct ft5x0x_data *ft5x0x=NULL; + + if (ts_i2c_register_device()<0) + { + dbg("Error to run ts_i2c_register_device()!\n"); + return -1; + } + + ft5x0x = kzalloc(sizeof(struct ft5x0x_data), GFP_KERNEL); + if(!ft5x0x){ + dbg_err("mem alloc failed.\n"); + return -ENOMEM; + } + + pContext = ft5x0x; + ret = check_touch_env(ft5x0x); + if(ret < 0) + goto exit_free_mem; + + ret = gpio_request(ft5x0x->irqgpio, "ts_irq"); + if (ret < 0) { + printk("gpio(%d) touchscreen irq request fail\n", ft5x0x->irqgpio); + goto exit_free_mem; + } + wmt_gpio_setpull(ft5x0x->irqgpio, WMT_GPIO_PULL_UP); + gpio_direction_input(ft5x0x->irqgpio); + + ret = gpio_request(ft5x0x->rstgpio, "ts_rst"); + if (ret < 0) { + printk("gpio(%d) touchscreen reset request fail\n", ft5x0x->rstgpio); + goto exit_free_irqgpio; + } + gpio_direction_output(ft5x0x->rstgpio, 1); + + + ret = platform_device_register(&ft5x0x_device); + if(ret){ + dbg_err("register platform drivver failed!\n"); + goto exit_free_gpio; + } + platform_set_drvdata(&ft5x0x_device, ft5x0x); + + ret = platform_driver_register(&ft5x0x_driver); + if(ret){ + dbg_err("register platform device failed!\n"); + goto exit_unregister_pdev; + } + + return ret; + +exit_unregister_pdev: + platform_device_unregister(&ft5x0x_device); +exit_free_gpio: + gpio_free(ft5x0x->rstgpio); +exit_free_irqgpio: + gpio_free(ft5x0x->irqgpio); +exit_free_mem: + kfree(ft5x0x); + pContext = NULL; + return ret; +} + +static void ft5x0x_exit(void) +{ + if(!pContext) return; + + gpio_free(pContext->rstgpio); + gpio_free(pContext->irqgpio); + platform_driver_unregister(&ft5x0x_driver); + platform_device_unregister(&ft5x0x_device); + kfree(pContext); + ts_i2c_unregister_device(); + return; +} + +late_initcall(ft5x0x_init); +module_exit(ft5x0x_exit); +module_param (ft5x0x_debug, byte, 0644); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("FocalTech.Touch"); diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft5x0x.h b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft5x0x.h new file mode 100755 index 00000000..417af1f5 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft5x0x.h @@ -0,0 +1,205 @@ +#ifndef __LINUX_FT5X0X_TS_H__ +#define __LINUX_FT5X0X_TS_H__ + +#define DEV_FT5206 "touch_ft5206" +#define DEV_FT5301 "touch_ft5301" +#define DEV_FT5302 "touch_ft5302" +#define DEV_FT5306 "touch_ft5306" +#define DEV_FT5406 "touch_ft5406" +#define DEV_FT5606 "touch_ft5606" +#define DEV_FT6336 "touch_ft6336" + + +#define DEV_FT5X0X "touch_ft5x0x" +#define TS_I2C_NAME "ft5x0x-ts" +#define FT5406_I2C_ADDR 0x38 +#define FT5X0X_I2C_BUS 0x01 + +enum FT5X0X_ID{ + FT5206 =1, + FT5301, + FT5302, + FT5306, + FT5406, + FT5606, + FT6336, + FT5X0X, +}; + +struct vt1603_ts_cal_info { + int a1; + int b1; + int c1; + int a2; + int b2; + int c2; + int delta; +}; + +#define SUPPORT_POINT_NUM 5//10 +struct ts_event { + int x[SUPPORT_POINT_NUM]; + int y[SUPPORT_POINT_NUM]; + int tid[SUPPORT_POINT_NUM]; + int tpoint; +}; + +#define TOUCH_KEY + +#ifdef TOUCH_KEY +#define NUM_KEYS 4 +struct key_pos{ + int y_lower; + int y_upper; +}; + +struct ts_key{ + int axis; + int x_lower; + int x_upper; + struct key_pos ypos[NUM_KEYS]; +}; +#endif + +struct ft5x0x_data { + int id; + unsigned int addr; + const char *name; + u8 fw_name[64]; + u8 cfg_name[32]; + + struct i2c_client *client; + struct input_dev *input_dev; + struct ts_event event; + struct work_struct read_work; + struct workqueue_struct *workqueue; + struct mutex ts_mutex; + struct kobject *kobj; + #ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif + int earlysus; + + int reslx; + int resly; + + int tw; + int th; + + int irq; + int irqgpio; + int rstgpio; +/* + int igp_idx; + int igp_bit; + + int rgp_idx; + int rgp_bit; +*/ + + int nt; + int nb; + int xch; + int ych; + int swap; + + int upg; + int load_cfg; + int dbg; +#ifdef TOUCH_KEY + int tskey_used; + int tkey_pressed; + int nkeys; + int tkey_idx; + struct ts_key tkey; +#endif + +}; + +enum ft5x0x_ts_regs { + FT5X0X_REG_THGROUP = 0x80, /* touch threshold, related to sensitivity */ + FT5X0X_REG_THPEAK = 0x81, + FT5X0X_REG_THCAL = 0x82, + FT5X0X_REG_THWATER = 0x83, + FT5X0X_REG_THTEMP = 0x84, + FT5X0X_REG_THDIFF = 0x85, + FT5X0X_REG_CTRL = 0x86, + FT5X0X_REG_TIMEENTERMONITOR = 0x87, + FT5X0X_REG_PERIODACTIVE = 0x88, /* report rate */ + FT5X0X_REG_PERIODMONITOR = 0x89, + FT5X0X_REG_HEIGHT_B = 0x8a, + FT5X0X_REG_MAX_FRAME = 0x8b, + FT5X0X_REG_DIST_MOVE = 0x8c, + FT5X0X_REG_DIST_POINT = 0x8d, + FT5X0X_REG_FEG_FRAME = 0x8e, + FT5X0X_REG_SINGLE_CLICK_OFFSET = 0x8f, + FT5X0X_REG_DOUBLE_CLICK_TIME_MIN = 0x90, + FT5X0X_REG_SINGLE_CLICK_TIME = 0x91, + FT5X0X_REG_LEFT_RIGHT_OFFSET = 0x92, + FT5X0X_REG_UP_DOWN_OFFSET = 0x93, + FT5X0X_REG_DISTANCE_LEFT_RIGHT = 0x94, + FT5X0X_REG_DISTANCE_UP_DOWN = 0x95, + FT5X0X_REG_ZOOM_DIS_SQR = 0x96, + FT5X0X_REG_RADIAN_VALUE =0x97, + FT5X0X_REG_MAX_X_HIGH = 0x98, + FT5X0X_REG_MAX_X_LOW = 0x99, + FT5X0X_REG_MAX_Y_HIGH = 0x9a, + FT5X0X_REG_MAX_Y_LOW = 0x9b, + FT5X0X_REG_K_X_HIGH = 0x9c, + FT5X0X_REG_K_X_LOW = 0x9d, + FT5X0X_REG_K_Y_HIGH = 0x9e, + FT5X0X_REG_K_Y_LOW = 0x9f, + FT5X0X_REG_AUTO_CLB_MODE = 0xa0, + FT5X0X_REG_LIB_VERSION_H = 0xa1, + FT5X0X_REG_LIB_VERSION_L = 0xa2, + FT5X0X_REG_CIPHER = 0xa3, + FT5X0X_REG_MODE = 0xa4, + FT5X0X_REG_PMODE = 0xa5, /* Power Consume Mode */ + FT5X0X_REG_FIRMID = 0xa6, /* Firmware version */ + FT5X0X_REG_STATE = 0xa7, + FT5X0X_REG_FT5201ID = 0xa8, + FT5X0X_REG_ERR = 0xa9, + FT5X0X_REG_CLB = 0xaa, +}; + +//FT5X0X_REG_PMODE +#define PMODE_ACTIVE 0x00 +#define PMODE_MONITOR 0x01 +#define PMODE_STANDBY 0x02 +#define PMODE_HIBERNATE 0x03 + +#define DEV_NAME "wmtts" +#define DEV_MAJOR 11 + +#define TS_IOC_MAGIC 't' +#define TS_IOCTL_CAL_START _IO(TS_IOC_MAGIC, 1) +#define TS_IOCTL_CAL_DONE _IOW(TS_IOC_MAGIC, 2, int*) +#define TS_IOCTL_GET_RAWDATA _IOR(TS_IOC_MAGIC, 3, int*) +#define TS_IOCTL_CAL_QUIT _IOW(TS_IOC_MAGIC, 4, int*) +#define TS_IOCTL_CAL_CAP _IOW(TS_IOC_MAGIC, 5, int*) +#define TS_IOC_MAXNR 5 + +extern int wmt_setsyspara(char *varname, unsigned char *varval); +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); +extern int wmt_i2c_xfer_continue_if_4(struct i2c_msg *msg, unsigned int num,int bus_id); + +//#define FT_DEBUG + +#undef dbg +#ifdef FT_DEBUG + #define dbg(fmt,args...) printk("DBG:%s_%d:"fmt,__FUNCTION__,__LINE__,##args) +#else + #define dbg(fmt,args...) +#endif + +#undef dbg_err +#define dbg_err(fmt,args...) printk("ERR:%s_%d:"fmt,__FUNCTION__,__LINE__,##args) + +//#define FTS_DBG +#ifdef FTS_DBG +#define DBG(fmt, args...) printk("[FTS]" fmt, ## args) +#else +#define DBG(fmt, args...) do{}while(0) +#endif + +#endif diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft5x0x_upg.c b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft5x0x_upg.c new file mode 100755 index 00000000..9db72130 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft5x0x_upg.c @@ -0,0 +1,506 @@ +#include +#include +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include +#include +#include +#include +#include +#include +#include "ft5x0x.h" + +typedef enum +{ + ERR_OK, + ERR_MODE, + ERR_READID, + ERR_ERASE, + ERR_STATUS, + ERR_ECC, + ERR_DL_ERASE_FAIL, + ERR_DL_PROGRAM_FAIL, + ERR_DL_VERIFY_FAIL, + ERR_FMID +}E_UPGRADE_ERR_TYPE; + +#define FT5X_CTPM_ID_L 0X79 +#define FT5X_CTPM_ID_H 0X03 + +#define FT56_CTPM_ID_L 0X79 +#define FT56_CTPM_ID_H 0X06 + +#define FTS_PACKET_LENGTH 128 + +extern struct ft5x0x_data *pContext; +extern int ft5x0x_i2c_rxdata(char *rxdata, int length); +extern int ft5x0x_i2c_txdata(char *txdata, int length); + +static int ft5x0x_write_reg(u8 addr, u8 para) +{ + u8 buf[2]; + int ret = -1; + + buf[0] = addr; + buf[1] = para; + ret = ft5x0x_i2c_txdata(buf, 2); + if (ret <= 0) { + printk("write reg failed! %x ret: %d", buf[0], ret); + return -1; + } + + return 0; +} + +static int ft5x0x_read_reg(u8 addr, u8 *pdata) +{ + int ret; + u8 buf[2]; + struct i2c_msg msgs[2]; + + // + buf[0] = addr; //register address + + msgs[0].addr = pContext->addr; + msgs[0].flags = 0 | I2C_M_NOSTART; + msgs[0].len = 1; + msgs[0].buf = buf; + + msgs[1].addr = pContext->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = 1; + msgs[1].buf = pdata; + + //ret = wmt_i2c_xfer_continue_if_4(msgs, 2, FT5X0X_I2C_BUS); + ret = i2c_transfer(pContext->client->adapter, msgs, 2); + if (ret <= 0) + printk("msg %s i2c read error: %d\n", __func__, ret); + + return ret; + +} + + +/* +[function]: + send a command to ctpm. +[parameters]: + btcmd[in] :command code; + btPara1[in] :parameter 1; + btPara2[in] :parameter 2; + btPara3[in] :parameter 3; + num[in] :the valid input parameter numbers, if only command code needed and no parameters followed,then the num is 1; +[return]: + FTS_TRUE :success; + FTS_FALSE :io fail; +*/ +static u8 cmd_write(u8 *cmd,u8 num) +{ + return ft5x0x_i2c_txdata(cmd, num); +} + +/* +[function]: + write data to ctpm , the destination address is 0. +[parameters]: + pbt_buf[in] :point to data buffer; + bt_len[in] :the data numbers; +[return]: + FTS_TRUE :success; + FTS_FALSE :io fail; +*/ +static u8 byte_write(u8* pbt_buf, int dw_len) +{ + + return ft5x0x_i2c_txdata( pbt_buf, dw_len); +} + +/* +[function]: + read out data from ctpm,the destination address is 0. +[parameters]: + pbt_buf[out] :point to data buffer; + bt_len[in] :the data numbers; +[return]: + FTS_TRUE :success; + FTS_FALSE :io fail; +*/ +static u8 byte_read(u8* pbt_buf, u8 bt_len) +{ + int ret; + struct i2c_msg msg[1]; + + msg[0].addr = pContext->addr; + msg[0].flags = I2C_M_RD; + msg[0].len = bt_len; + msg[0].buf = pbt_buf; + + ret = i2c_transfer(pContext->client->adapter, msg, 1); + //ret = wmt_i2c_xfer_continue_if_4(msg, 1, FT5X0X_I2C_BUS); + if (ret <= 0) + printk("msg i2c read error: %d\n", ret); + + return ret; +} + + +/* +[function]: + burn the FW to ctpm. +[parameters]:(ref. SPEC) + pbt_buf[in] :point to Head+FW ; + dw_lenth[in]:the length of the FW + 6(the Head length); + bt_ecc[in] :the ECC of the FW +[return]: + ERR_OK :no error; + ERR_MODE :fail to switch to UPDATE mode; + ERR_READID :read id fail; + ERR_ERASE :erase chip fail; + ERR_STATUS :status error; + ERR_ECC :ecc error. +*/ +static E_UPGRADE_ERR_TYPE ft5x0x_fw_upgrade(struct ft5x0x_data *ft5x0x, u8* pbt_buf, int dw_lenth) +{ + int i = 0,j = 0,i_ret; + int packet_number; + int temp,lenght; + u8 packet_buf[FTS_PACKET_LENGTH + 6]; + u8 auc_i2c_write_buf[10]; + u8 reg_val[2] = {0}; + u8 ctpm_id[2] = {0}; + u8 cmd[4]; + u8 bt_ecc; + + /*********Step 1:Reset CTPM *****/ + /*write 0xaa to register 0xfc*/ + ft5x0x_write_reg(0xfc,0xaa); + msleep(50); + /*write 0x55 to register 0xfc*/ + ft5x0x_write_reg(0xfc,0x55); + printk("[FTS] Step 1: Reset CTPM.\n"); + msleep(30); + + /*********Step 2:Enter upgrade mode *****/ + auc_i2c_write_buf[0] = 0x55; + auc_i2c_write_buf[1] = 0xaa; + do{ + i ++; + i_ret = byte_write(auc_i2c_write_buf, 2); + mdelay(5); + }while(i_ret <= 0 && i < 5 ); + msleep(20); + + /*********Step 3:check READ-ID**********/ + if(ft5x0x->id == FT5606){ + ctpm_id[0] = FT56_CTPM_ID_L; + ctpm_id[1] = FT56_CTPM_ID_H; + }else{ + ctpm_id[0] = FT5X_CTPM_ID_L; + ctpm_id[1] = FT5X_CTPM_ID_H; + } + + cmd[0] = 0x90; + cmd[1] = 0x00; + cmd[2] = 0x00; + cmd[3] = 0x00; + cmd_write(cmd,4); + byte_read(reg_val,2); + if (reg_val[0] == ctpm_id[0] && reg_val[1] == ctpm_id[1]){ + printk("[FTS] Step 3: CTPM ID,ID1 = 0x%x,ID2 = 0x%x\n",reg_val[0],reg_val[1]); + }else{ + printk("[FTS] ID_ERROR: CTPM ID,ID1 = 0x%x,ID2 = 0x%x\n",reg_val[0],reg_val[1]); + return ERR_READID; + } + + cmd[0] = 0xcd; + cmd_write(cmd,1); + byte_read(reg_val,1); + printk("[FTS] bootloader version = 0x%x\n", reg_val[0]); + + /******Step 4:erase app and panel paramenter area *********/ + cmd[0] = 0x61; + cmd_write(cmd,1); //erase app area + msleep(1500); + cmd[0] = 0x63; + cmd_write(cmd,1); //erase panel parameter area + msleep(100); + printk("[FTS] Step 4: erase. \n"); + + /*********Step 5:write firmware(FW) to ctpm flash*********/ + bt_ecc = 0; + printk("[FTS] Step 5: start upgrade. \n"); + dw_lenth = dw_lenth - 8; + packet_number = (dw_lenth) / FTS_PACKET_LENGTH; + packet_buf[0] = 0xbf; + packet_buf[1] = 0x00; + for (j=0;j>8); + packet_buf[3] = (u8)temp; + lenght = FTS_PACKET_LENGTH; + packet_buf[4] = (u8)(lenght>>8); + packet_buf[5] = (u8)lenght; + + for (i=0;i 0){ + temp = packet_number * FTS_PACKET_LENGTH; + packet_buf[2] = (u8)(temp>>8); + packet_buf[3] = (u8)temp; + + temp = (dw_lenth) % FTS_PACKET_LENGTH; + packet_buf[4] = (u8)(temp>>8); + packet_buf[5] = (u8)temp; + + for (i=0;i>8); + packet_buf[3] = (u8)temp; + temp =1; + packet_buf[4] = (u8)(temp>>8); + packet_buf[5] = (u8)temp; + packet_buf[6] = pbt_buf[ dw_lenth + i]; + bt_ecc ^= packet_buf[6]; + + byte_write(&packet_buf[0],7); + mdelay(20); + } + + /*********Step 6: read out checksum********************/ + /*send the opration head*/ + cmd[0] = 0xcc; + cmd_write(cmd,1); + byte_read(reg_val,1); + printk("[FTS] Step 6:read ECC 0x%x, firmware ECC 0x%x. \n", reg_val[0], bt_ecc); + if(reg_val[0] != bt_ecc){ + return ERR_ECC; + } + + /*********Step 7: reset the new FW***********************/ + cmd[0] = 0x07; + cmd_write(cmd,1); + + msleep(300); //make sure CTP startup normally + + return ERR_OK; +} + +int ft5x0x_auto_clb(void) +{ + u8 uc_temp; + u8 i ; + + printk("[FTS] start auto CLB.\n"); + msleep(200); + ft5x0x_write_reg(0, 0x40); + msleep(100); //make sure already enter factory mode + ft5x0x_write_reg(2, 0x4); //write command to start calibration + msleep(300); + for(i=0;i<100;i++){ + ft5x0x_read_reg(0,&uc_temp); + if ( ((uc_temp&0x70)>>4) == 0x0){ //return to normal mode, calibration finish + break; + } + msleep(200); + printk("[FTS] waiting calibration %d\n",i); + } + printk("[FTS] calibration OK.\n"); + + msleep(300); + ft5x0x_write_reg(0, 0x40); //goto factory mode + msleep(100); //make sure already enter factory mode + ft5x0x_write_reg(2, 0x5); //store CLB result + msleep(300); + ft5x0x_write_reg(0, 0x0); //return to normal mode + msleep(300); + printk("[FTS] store CLB result OK.\n"); + return 0; +} + +static int ft5x0x_get_bin_ver(const u8 *fw, int fw_szie) +{ + if (fw_szie > 2){ + return fw[fw_szie - 2]; + }else{ + return 0xff; //default value + } + return 0xff; +} + +int ft5x0x_read_fw_ver(void) +{ + u8 ver=0; + int ret=0; + + ret = ft5x0x_read_reg(FT5X0X_REG_FIRMID, &ver); + if(ret > 0) + return ver; + + return ret; +} + + +static int ft5x0x_get_fw_szie(const char *fw_name) +{ + struct file *pfile = NULL; + struct inode *inode; + unsigned long magic; + off_t fsize = 0; + + if(fw_name == NULL){ + dbg_err("Firmware name error.\n"); + return -EFAULT; + } + + if (NULL == pfile) + pfile = filp_open(fw_name, O_RDONLY, 0); + + if (IS_ERR(pfile)) { + dbg_err("File open error: %s.\n", fw_name); + return -EIO; + } + + inode = pfile->f_dentry->d_inode; + magic = inode->i_sb->s_magic; + fsize = inode->i_size; + filp_close(pfile, NULL); + return fsize; +} + +static int ft5x0x_read_fw(const char *fw_name, u8 *buf) +{ + struct file *pfile = NULL; + struct inode *inode; + unsigned long magic; + off_t fsize; + loff_t pos; + mm_segment_t fs; + + if(fw_name == NULL){ + dbg_err("Firmware name error.\n"); + return -EFAULT; + } + + if (NULL == pfile) + pfile = filp_open(fw_name, O_RDONLY, 0); + if (IS_ERR(pfile)) { + dbg_err("File open error: %s.\n", fw_name); + return -EIO; + } + + inode = pfile->f_dentry->d_inode; + magic = inode->i_sb->s_magic; + fsize = inode->i_size; + fs = get_fs(); + set_fs(KERNEL_DS); + pos = 0; + vfs_read(pfile, buf, fsize, &pos); + filp_close(pfile, NULL); + set_fs(fs); + + return 0; +} + +#define FW_SUFFFIX ".bin" +#define SD_UPG_BIN_PATH "/sdcard/_wmt_ft5x0x_fw_app.bin" +#define FS_UPG_BIN_PATH "/lib/firmware/" + +int ft5x0x_upg_fw_bin(struct ft5x0x_data *ft5x0x, int check_ver) +{ + int i_ret = 0; + int fwsize = 0; + int hw_fw_ver; + int bin_fw_ver; + int do_upg; + u8 *pbt_buf = NULL; + u8 fw_path[128] = {0}; + + if(ft5x0x->upg) + sprintf(fw_path,"%s%s%s", FS_UPG_BIN_PATH, ft5x0x->fw_name,FW_SUFFFIX);//get fw binary file from filesystem + else + strcpy(fw_path,SD_UPG_BIN_PATH); //get fw binary file from SD card + + fwsize = ft5x0x_get_fw_szie(fw_path); + if (fwsize <= 0) { + dbg_err("Get firmware size failed\n"); + return -EIO; + } + + if (fwsize < 8 || fwsize > 32 * 1024) { + dbg_err("FW length error\n"); + return -EIO; + } + + pbt_buf = kmalloc(fwsize + 1, GFP_KERNEL); + if (ft5x0x_read_fw(fw_path, pbt_buf)) { + dbg_err("Request_firmware failed\n"); + i_ret = -EIO; + goto exit; + } + + hw_fw_ver =ft5x0x_read_fw_ver(); + if(hw_fw_ver <= 0){ + dbg_err("Read firmware version failed\n"); + i_ret = hw_fw_ver; + goto exit; + } + + bin_fw_ver = ft5x0x_get_bin_ver(pbt_buf, fwsize); + printk("[FTS] hardware fw ver 0x%0x, binary ver 0x%0x\n",hw_fw_ver, bin_fw_ver); + + if(check_ver){ + if(hw_fw_ver == 0xa6 || hw_fw_ver < bin_fw_ver) + do_upg = 1; + else + do_upg = 0; + }else{ + do_upg = 1; + } + + if(do_upg){ + if ((pbt_buf[fwsize - 8] ^ pbt_buf[fwsize - 6]) == 0xFF && + (pbt_buf[fwsize - 7] ^ pbt_buf[fwsize - 5]) == 0xFF && + (pbt_buf[fwsize - 3] ^ pbt_buf[fwsize - 4]) == 0xFF) { + i_ret = ft5x0x_fw_upgrade(ft5x0x, pbt_buf, fwsize); + if (i_ret) + dbg_err("Upgrade failed, i_ret=%d\n",i_ret); + else { + hw_fw_ver = ft5x0x_read_fw_ver(); + printk("[FTS] upgrade to new version 0x%x\n", hw_fw_ver); + } + } else { + dbg_err("FW format error\n"); + } + } + + ft5x0x_auto_clb();/*start auto CLB*/ + +exit: + kfree(pbt_buf); + return i_ret; +} + + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft6x06_ex_fun.c b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft6x06_ex_fun.c new file mode 100755 index 00000000..08fc6069 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft6x06_ex_fun.c @@ -0,0 +1,1021 @@ +/* + *drivers/input/touchscreen/ft5x06_ex_fun.c + * + *FocalTech ft6x06 expand function for debug. + * + *Copyright (c) 2010 Focal tech Ltd. + * + *This software is licensed under the terms of the GNU General Public + *License version 2, as published by the Free Software Foundation, and + *may be copied, distributed, and modified under those terms. + * + *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. + * + *Note:the error code of EIO is the general error in this file. + */ + + +#include "ft6x06_ex_fun.h" +#include "ft6x06_ts.h" + +#include +#include +#include + +struct Upgrade_Info { + u16 delay_aa; /*delay of write FT_UPGRADE_AA */ + u16 delay_55; /*delay of write FT_UPGRADE_55 */ + u8 upgrade_id_1; /*upgrade id 1 */ + u8 upgrade_id_2; /*upgrade id 2 */ + u16 delay_readid; /*delay of read id */ + u16 delay_earse_flash; /*delay of earse flash*/ +}; + + +int fts_ctpm_fw_upgrade(struct i2c_client *client, u8 *pbt_buf, + u32 dw_lenth); + +static unsigned char CTPM_FW[] = { + #include "FT5406.i" +}; + +static struct mutex g_device_mutex; + +int ft6x06_write_reg(struct i2c_client *client, u8 regaddr, u8 regvalue) +{ + unsigned char buf[2] = {0}; + buf[0] = regaddr; + buf[1] = regvalue; + + return ft6x06_i2c_Write(client, buf, sizeof(buf)); +} + + +int ft6x06_read_reg(struct i2c_client *client, u8 regaddr, u8 *regvalue) +{ + return ft6x06_i2c_Read(client, ®addr, 1, regvalue, 1); +} + + +int fts_ctpm_auto_clb(struct i2c_client *client) +{ + unsigned char uc_temp = 0x00; + unsigned char i = 0; + + /*start auto CLB */ + msleep(200); + + ft6x06_write_reg(client, 0, FTS_FACTORYMODE_VALUE); + /*make sure already enter factory mode */ + msleep(100); + /*write command to start calibration */ + ft6x06_write_reg(client, 2, 0x4); + msleep(300); + for (i = 0; i < 100; i++) { + ft6x06_read_reg(client, 0, &uc_temp); + /*return to normal mode, calibration finish */ + if (0x0 == ((uc_temp & 0x70) >> 4)) + break; + } + + msleep(200); + /*calibration OK */ + msleep(300); + ft6x06_write_reg(client, 0, FTS_FACTORYMODE_VALUE); /*goto factory mode for store */ + msleep(100); /*make sure already enter factory mode */ + ft6x06_write_reg(client, 2, 0x5); /*store CLB result */ + msleep(300); + ft6x06_write_reg(client, 0, FTS_WORKMODE_VALUE); /*return to normal mode */ + msleep(300); + + /*store CLB result OK */ + return 0; +} + +/* +upgrade with *.i file +*/ +int fts_ctpm_fw_upgrade_with_i_file(struct i2c_client *client) +{ + u8 *pbt_buf = NULL; + int i_ret; + int fw_len = sizeof(CTPM_FW); + + /*judge the fw that will be upgraded + * if illegal, then stop upgrade and return. + */ + + if (fw_len < 8 || fw_len > 32 * 1024) { + dev_err(&client->dev, "%s:FW length error\n", __func__); + return -EIO; + } + + /*FW upgrade */ + pbt_buf = CTPM_FW; + /*call the upgrade function */ + + i_ret = fts_ctpm_fw_upgrade(client, pbt_buf, sizeof(CTPM_FW)); + if (i_ret != 0) + dev_err(&client->dev, "%s:upgrade failed. err.\n", + __func__); + + return i_ret; +} + +u8 fts_ctpm_get_i_file_ver(void) +{ + u16 ui_sz; + ui_sz = sizeof(CTPM_FW); + if (ui_sz > 2) + return CTPM_FW[0x10a]; + + return 0x00; /*default value */ +} + +/*update project setting +*only update these settings for COB project, or for some special case +*/ +int fts_ctpm_update_project_setting(struct i2c_client *client) +{ + u8 uc_i2c_addr; /*I2C slave address (7 bit address)*/ + u8 uc_io_voltage; /*IO Voltage 0---3.3v; 1----1.8v*/ + u8 uc_panel_factory_id; /*TP panel factory ID*/ + u8 buf[FTS_SETTING_BUF_LEN]; + u8 reg_val[2] = {0}; + u8 auc_i2c_write_buf[10] = {0}; + u8 packet_buf[FTS_SETTING_BUF_LEN + 6]; + u32 i = 0; + int i_ret; + + uc_i2c_addr = client->addr; + uc_io_voltage = 0x0; + uc_panel_factory_id = 0x5a; + + + /*Step 1:Reset CTPM + *write 0xaa to register 0xfc + */ + ft6x06_write_reg(client, 0xfc, 0xaa); + msleep(50); + + /*write 0x55 to register 0xfc */ + ft6x06_write_reg(client, 0xfc, 0x55); + msleep(30); + + /*********Step 2:Enter upgrade mode *****/ + auc_i2c_write_buf[0] = 0x55; + auc_i2c_write_buf[1] = 0xaa; + do { + i++; + i_ret = ft6x06_i2c_Write(client, auc_i2c_write_buf, 2); + msleep(5); + } while (i_ret <= 0 && i < 5); + + + /*********Step 3:check READ-ID***********************/ + auc_i2c_write_buf[0] = 0x90; + auc_i2c_write_buf[1] = auc_i2c_write_buf[2] = auc_i2c_write_buf[3] = + 0x00; + + ft6x06_i2c_Read(client, auc_i2c_write_buf, 4, reg_val, 2); + + if (reg_val[0] == 0x79 && reg_val[1] == 0x3) + dev_dbg(&client->dev, "[FTS] Step 3: CTPM ID,ID1 = 0x%x,ID2 = 0x%x\n", + reg_val[0], reg_val[1]); + else + return -EIO; + + auc_i2c_write_buf[0] = 0xcd; + ft6x06_i2c_Read(client, auc_i2c_write_buf, 1, reg_val, 1); + dev_dbg(&client->dev, "bootloader version = 0x%x\n", reg_val[0]); + + /*--------- read current project setting ---------- */ + /*set read start address */ + buf[0] = 0x3; + buf[1] = 0x0; + buf[2] = 0x78; + buf[3] = 0x0; + + ft6x06_i2c_Read(client, buf, 4, buf, FTS_SETTING_BUF_LEN); + dev_dbg(&client->dev, "[FTS] old setting: uc_i2c_addr = 0x%x,\ + uc_io_voltage = %d, uc_panel_factory_id = 0x%x\n", + buf[0], buf[2], buf[4]); + + /*--------- Step 4:erase project setting --------------*/ + auc_i2c_write_buf[0] = 0x63; + ft6x06_i2c_Write(client, auc_i2c_write_buf, 1); + msleep(100); + + /*---------- Set new settings ---------------*/ + buf[0] = uc_i2c_addr; + buf[1] = ~uc_i2c_addr; + buf[2] = uc_io_voltage; + buf[3] = ~uc_io_voltage; + buf[4] = uc_panel_factory_id; + buf[5] = ~uc_panel_factory_id; + packet_buf[0] = 0xbf; + packet_buf[1] = 0x00; + packet_buf[2] = 0x78; + packet_buf[3] = 0x0; + packet_buf[4] = 0; + packet_buf[5] = FTS_SETTING_BUF_LEN; + + for (i = 0; i < FTS_SETTING_BUF_LEN; i++) + packet_buf[6 + i] = buf[i]; + + ft6x06_i2c_Write(client, packet_buf, FTS_SETTING_BUF_LEN + 6); + msleep(100); + + /********* reset the new FW***********************/ + auc_i2c_write_buf[0] = 0x07; + ft6x06_i2c_Write(client, auc_i2c_write_buf, 1); + + msleep(200); + return 0; +} + +int fts_ctpm_auto_upgrade(struct i2c_client *client) +{ + u8 uc_host_fm_ver = FT6x06_REG_FW_VER; + u8 uc_tp_fm_ver; + int i_ret; + + ft6x06_read_reg(client, FT6x06_REG_FW_VER, &uc_tp_fm_ver); + uc_host_fm_ver = fts_ctpm_get_i_file_ver(); + + if (/*the firmware in touch panel maybe corrupted */ + uc_tp_fm_ver == FT6x06_REG_FW_VER || + /*the firmware in host flash is new, need upgrade */ + uc_tp_fm_ver < uc_host_fm_ver + ) { + msleep(100); + dev_dbg(&client->dev, "[FTS] uc_tp_fm_ver = 0x%x, uc_host_fm_ver = 0x%x\n", + uc_tp_fm_ver, uc_host_fm_ver); + i_ret = fts_ctpm_fw_upgrade_with_i_file(client); + if (i_ret == 0) { + msleep(300); + uc_host_fm_ver = fts_ctpm_get_i_file_ver(); + dev_dbg(&client->dev, "[FTS] upgrade to new version 0x%x\n", + uc_host_fm_ver); + } else { + pr_err("[FTS] upgrade failed ret=%d.\n", i_ret); + return -EIO; + } + } + + return 0; +} + +void delay_qt_ms(unsigned long w_ms) +{ + unsigned long i; + unsigned long j; + + for (i = 0; i < w_ms; i++) + { + for (j = 0; j < 1000; j++) + { + udelay(1); + } + } +} + +int fts_ctpm_fw_upgrade(struct i2c_client *client, u8 *pbt_buf, + u32 dw_lenth) +{ + u8 reg_val[2] = {0}; + u32 i = 0; + u32 packet_number; + u32 j; + u32 temp; + u32 lenght; + u32 fw_length; + u8 packet_buf[FTS_PACKET_LENGTH + 6]; + u8 auc_i2c_write_buf[10]; + u8 bt_ecc; + int i_ret; + + + if(pbt_buf[0] != 0x02) + { + DBG("[FTS] FW first byte is not 0x02. so it is invalid \n"); + return -1; + } + + if(dw_lenth > 0x11f) + { + fw_length = ((u32)pbt_buf[0x100]<<8) + pbt_buf[0x101]; + if(dw_lenth < fw_length) + { + DBG("[FTS] Fw length is invalid \n"); + return -1; + } + } + else + { + DBG("[FTS] Fw length is invalid \n"); + return -1; + } + + //DBG("[FTS] Step 3: CTPM ID,ID1 = 0x%x,ID2 = 0x%x\n", reg_val[0], reg_val[1]); + + for (i = 0; i < FTS_UPGRADE_LOOP; i++) { + /*********Step 1:Reset CTPM *****/ + /*write 0xaa to register 0xbc */ + + ft6x06_write_reg(client, 0xbc, FT_UPGRADE_AA); + msleep(FT6X06_UPGRADE_AA_DELAY); + + /*write 0x55 to register 0xbc */ + ft6x06_write_reg(client, 0xbc, FT_UPGRADE_55); + + msleep(FT6X06_UPGRADE_55_DELAY); + + /*********Step 2:Enter upgrade mode *****/ + auc_i2c_write_buf[0] = FT_UPGRADE_55; + ft6x06_i2c_Write(client, auc_i2c_write_buf, 1); + + auc_i2c_write_buf[0] = FT_UPGRADE_AA; + ft6x06_i2c_Write(client, auc_i2c_write_buf, 1); + msleep(FT6X06_UPGRADE_READID_DELAY); + + /*********Step 3:check READ-ID***********************/ + auc_i2c_write_buf[0] = 0x90; + auc_i2c_write_buf[1] = auc_i2c_write_buf[2] = auc_i2c_write_buf[3] = + 0x00; + reg_val[0] = 0x00; + reg_val[1] = 0x00; + ft6x06_i2c_Read(client, auc_i2c_write_buf, 4, reg_val, 2); + + + if (reg_val[0] == FT6X06_UPGRADE_ID_1 + && reg_val[1] == FT6X06_UPGRADE_ID_2) { + //dev_dbg(&client->dev, "[FTS] Step 3: CTPM ID,ID1 = 0x%x,ID2 = 0x%x\n", + //reg_val[0], reg_val[1]); + DBG("[FTS] Step 3: GET CTPM ID OK,ID1 = 0x%x,ID2 = 0x%x\n", + reg_val[0], reg_val[1]); + break; + } else { + dev_err(&client->dev, "[FTS] Step 3: GET CTPM ID FAIL,ID1 = 0x%x,ID2 = 0x%x\n", + reg_val[0], reg_val[1]); + } + } + if (i >= FTS_UPGRADE_LOOP) + return -EIO; + + auc_i2c_write_buf[0] = 0x90; + auc_i2c_write_buf[1] = 0x00; + auc_i2c_write_buf[2] = 0x00; + auc_i2c_write_buf[3] = 0x00; + auc_i2c_write_buf[4] = 0x00; + ft6x06_i2c_Write(client, auc_i2c_write_buf, 5); + + //auc_i2c_write_buf[0] = 0xcd; + //ft6x06_i2c_Read(client, auc_i2c_write_buf, 1, reg_val, 1); + + + /*Step 4:erase app and panel paramenter area*/ + DBG("Step 4:erase app and panel paramenter area\n"); + auc_i2c_write_buf[0] = 0x61; + ft6x06_i2c_Write(client, auc_i2c_write_buf, 1); /*erase app area */ + msleep(FT6X06_UPGRADE_EARSE_DELAY); + + for(i = 0;i < 200;i++) + { + auc_i2c_write_buf[0] = 0x6a; + auc_i2c_write_buf[1] = 0x00; + auc_i2c_write_buf[2] = 0x00; + auc_i2c_write_buf[3] = 0x00; + reg_val[0] = 0x00; + reg_val[1] = 0x00; + ft6x06_i2c_Read(client, auc_i2c_write_buf, 4, reg_val, 2); + if(0xb0 == reg_val[0] && 0x02 == reg_val[1]) + { + DBG("[FTS] erase app finished \n"); + break; + } + msleep(50); + } + + /*********Step 5:write firmware(FW) to ctpm flash*********/ + bt_ecc = 0; + DBG("Step 5:write firmware(FW) to ctpm flash\n"); + + dw_lenth = fw_length; + packet_number = (dw_lenth) / FTS_PACKET_LENGTH; + packet_buf[0] = 0xbf; + packet_buf[1] = 0x00; + + for (j = 0; j < packet_number; j++) { + temp = j * FTS_PACKET_LENGTH; + packet_buf[2] = (u8) (temp >> 8); + packet_buf[3] = (u8) temp; + lenght = FTS_PACKET_LENGTH; + packet_buf[4] = (u8) (lenght >> 8); + packet_buf[5] = (u8) lenght; + + for (i = 0; i < FTS_PACKET_LENGTH; i++) { + packet_buf[6 + i] = pbt_buf[j * FTS_PACKET_LENGTH + i]; + bt_ecc ^= packet_buf[6 + i]; + } + + ft6x06_i2c_Write(client, packet_buf, FTS_PACKET_LENGTH + 6); + + for(i = 0;i < 30;i++) + { + auc_i2c_write_buf[0] = 0x6a; + auc_i2c_write_buf[1] = 0x00; + auc_i2c_write_buf[2] = 0x00; + auc_i2c_write_buf[3] = 0x00; + reg_val[0] = 0x00; + reg_val[1] = 0x00; + ft6x06_i2c_Read(client, auc_i2c_write_buf, 4, reg_val, 2); + if(0xb0 == (reg_val[0] & 0xf0) && (0x03 + (j % 0x0ffd)) == (((reg_val[0] & 0x0f) << 8) |reg_val[1])) + { + DBG("[FTS] write a block data finished \n"); + break; + } + msleep(1); + } + //msleep(FTS_PACKET_LENGTH / 6 + 1); + //DBG("write bytes:0x%04x\n", (j+1) * FTS_PACKET_LENGTH); + //delay_qt_ms(FTS_PACKET_LENGTH / 6 + 1); + } + + if ((dw_lenth) % FTS_PACKET_LENGTH > 0) { + temp = packet_number * FTS_PACKET_LENGTH; + packet_buf[2] = (u8) (temp >> 8); + packet_buf[3] = (u8) temp; + temp = (dw_lenth) % FTS_PACKET_LENGTH; + packet_buf[4] = (u8) (temp >> 8); + packet_buf[5] = (u8) temp; + + for (i = 0; i < temp; i++) { + packet_buf[6 + i] = pbt_buf[packet_number * FTS_PACKET_LENGTH + i]; + bt_ecc ^= packet_buf[6 + i]; + } + + ft6x06_i2c_Write(client, packet_buf, temp + 6); + + for(i = 0;i < 30;i++) + { + auc_i2c_write_buf[0] = 0x6a; + auc_i2c_write_buf[1] = 0x00; + auc_i2c_write_buf[2] = 0x00; + auc_i2c_write_buf[3] = 0x00; + reg_val[0] = 0x00; + reg_val[1] = 0x00; + ft6x06_i2c_Read(client, auc_i2c_write_buf, 4, reg_val, 2); + if(0xb0 == (reg_val[0] & 0xf0) && (0x03 + (j % 0x0ffd)) == (((reg_val[0] & 0x0f) << 8) |reg_val[1])) + { + DBG("[FTS] write a block data finished \n"); + break; + } + msleep(1); + } + //msleep(20); + } + + + /*********Step 6: read out checksum***********************/ + /*send the opration head */ + DBG("Step 6: read out checksum\n"); + auc_i2c_write_buf[0] = 0xcc; + ft6x06_i2c_Read(client, auc_i2c_write_buf, 1, reg_val, 1); + if (reg_val[0] != bt_ecc) { + dev_err(&client->dev, "[FTS]--ecc error! FW=%02x bt_ecc=%02x\n", + reg_val[0], + bt_ecc); + return -EIO; + } + + /*********Step 7: reset the new FW***********************/ + DBG("Step 7: reset the new FW\n"); + auc_i2c_write_buf[0] = 0x07; + ft6x06_i2c_Write(client, auc_i2c_write_buf, 1); + msleep(300); /*make sure CTP startup normally */ + + return 0; +} + +/*sysfs debug*/ + +/* +*get firmware size + +@firmware_name:firmware name +*note:the firmware default path is sdcard. + if you want to change the dir, please modify by yourself. +*/ +static int ft6x06_GetFirmwareSize(char *firmware_name) +{ + struct file *pfile = NULL; + struct inode *inode; + unsigned long magic; + off_t fsize = 0; + char filepath[128]; + memset(filepath, 0, sizeof(filepath)); + + sprintf(filepath, "/sdcard/%s", firmware_name); + + if (NULL == pfile) + pfile = filp_open(filepath, O_RDONLY, 0); + + if (IS_ERR(pfile)) { + pr_err("error occured while opening file %s.\n", filepath); + return -EIO; + } + + inode = pfile->f_dentry->d_inode; + magic = inode->i_sb->s_magic; + fsize = inode->i_size; + filp_close(pfile, NULL); + return fsize; +} + + + +/* +*read firmware buf for .bin file. + +@firmware_name: fireware name +@firmware_buf: data buf of fireware + +note:the firmware default path is sdcard. + if you want to change the dir, please modify by yourself. +*/ +static int ft6x06_ReadFirmware(char *firmware_name, + unsigned char *firmware_buf) +{ + struct file *pfile = NULL; + struct inode *inode; + unsigned long magic; + off_t fsize; + char filepath[128]; + loff_t pos; + mm_segment_t old_fs; + + memset(filepath, 0, sizeof(filepath)); + sprintf(filepath, "/sdcard/%s", firmware_name); + if (NULL == pfile) + pfile = filp_open(filepath, O_RDONLY, 0); + if (IS_ERR(pfile)) { + pr_err("error occured while opening file %s.\n", filepath); + return -EIO; + } + + inode = pfile->f_dentry->d_inode; + magic = inode->i_sb->s_magic; + fsize = inode->i_size; + old_fs = get_fs(); + set_fs(KERNEL_DS); + pos = 0; + vfs_read(pfile, firmware_buf, fsize, &pos); + filp_close(pfile, NULL); + set_fs(old_fs); + + return 0; +} + + + +/* +upgrade with *.bin file +*/ + +int fts_ctpm_fw_upgrade_with_app_file(struct i2c_client *client, + char *firmware_name) +{ + u8 *pbt_buf = NULL; + int i_ret; + int fwsize = ft6x06_GetFirmwareSize(firmware_name); + + if (fwsize <= 0) { + dev_err(&client->dev, "%s ERROR:Get firmware size failed\n", + __func__); + return -EIO; + } + + if (fwsize < 8 || fwsize > 32 * 1024) { + dev_dbg(&client->dev, "%s:FW length error\n", __func__); + return -EIO; + } + + /*=========FW upgrade========================*/ + pbt_buf = kmalloc(fwsize + 1, GFP_ATOMIC); + + if (ft6x06_ReadFirmware(firmware_name, pbt_buf)) { + dev_err(&client->dev, "%s() - ERROR: request_firmware failed\n", + __func__); + kfree(pbt_buf); + return -EIO; + } + + /*call the upgrade function */ + i_ret = fts_ctpm_fw_upgrade(client, pbt_buf, fwsize); + if (i_ret != 0) + dev_err(&client->dev, "%s() - ERROR:[FTS] upgrade failed..\n", + __func__); + //else + //fts_ctpm_auto_clb(client); + kfree(pbt_buf); + + return i_ret; +} + +static ssize_t ft6x06_tpfwver_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + ssize_t num_read_chars = 0; + u8 fwver = 0; + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + + mutex_lock(&g_device_mutex); + + if (ft6x06_read_reg(client, FT6x06_REG_FW_VER, &fwver) < 0) + num_read_chars = snprintf(buf, PAGE_SIZE, + "get tp fw version fail!\n"); + else + num_read_chars = snprintf(buf, PAGE_SIZE, "%02X\n", fwver); + + mutex_unlock(&g_device_mutex); + + return num_read_chars; +} + +static ssize_t ft6x06_tpfwver_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + /*place holder for future use*/ + return -EPERM; +} + + + +static ssize_t ft6x06_tprwreg_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + /*place holder for future use*/ + return -EPERM; +} + +static ssize_t ft6x06_tprwreg_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + ssize_t num_read_chars = 0; + int retval; + long unsigned int wmreg = 0; + u8 regaddr = 0xff, regvalue = 0xff; + u8 valbuf[5] = {0}; + + memset(valbuf, 0, sizeof(valbuf)); + mutex_lock(&g_device_mutex); + num_read_chars = count - 1; + + if (num_read_chars != 2) { + if (num_read_chars != 4) { + pr_info("please input 2 or 4 character\n"); + goto error_return; + } + } + + memcpy(valbuf, buf, num_read_chars); + retval = strict_strtoul(valbuf, 16, &wmreg); + + if (0 != retval) { + dev_err(&client->dev, "%s() - ERROR: Could not convert the "\ + "given input to a number." \ + "The given input was: \"%s\"\n", + __func__, buf); + goto error_return; + } + + if (2 == num_read_chars) { + /*read register*/ + regaddr = wmreg; + if (ft6x06_read_reg(client, regaddr, ®value) < 0) + dev_err(&client->dev, "Could not read the register(0x%02x)\n", + regaddr); + else + pr_info("the register(0x%02x) is 0x%02x\n", + regaddr, regvalue); + } else { + regaddr = wmreg >> 8; + regvalue = wmreg; + if (ft6x06_write_reg(client, regaddr, regvalue) < 0) + dev_err(&client->dev, "Could not write the register(0x%02x)\n", + regaddr); + else + dev_err(&client->dev, "Write 0x%02x into register(0x%02x) successful\n", + regvalue, regaddr); + } + +error_return: + mutex_unlock(&g_device_mutex); + + return count; +} + +static ssize_t ft6x06_fwupdate_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + /* place holder for future use */ + return -EPERM; +} + +/*upgrade from *.i*/ +static ssize_t ft6x06_fwupdate_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ft6x06_ts_data *data = NULL; + u8 uc_host_fm_ver; + int i_ret; + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + + data = (struct ft6x06_ts_data *)i2c_get_clientdata(client); + + mutex_lock(&g_device_mutex); + + disable_irq(client->irq); + i_ret = fts_ctpm_fw_upgrade_with_i_file(client); + if (i_ret == 0) { + msleep(300); + uc_host_fm_ver = fts_ctpm_get_i_file_ver(); + pr_info("%s [FTS] upgrade to new version 0x%x\n", __func__, + uc_host_fm_ver); + } else + dev_err(&client->dev, "%s ERROR:[FTS] upgrade failed.\n", + __func__); + + enable_irq(client->irq); + mutex_unlock(&g_device_mutex); + + return count; +} + +static ssize_t ft6x06_fwupgradeapp_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + /*place holder for future use*/ + return -EPERM; +} + + +/*upgrade from app.bin*/ +static ssize_t ft6x06_fwupgradeapp_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + char fwname[128]; + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + + memset(fwname, 0, sizeof(fwname)); + sprintf(fwname, "%s", buf); + fwname[count - 1] = '\0'; + + mutex_lock(&g_device_mutex); + disable_irq(client->irq); + + fts_ctpm_fw_upgrade_with_app_file(client, fwname); + + enable_irq(client->irq); + mutex_unlock(&g_device_mutex); + + return count; +} + + +/*sysfs */ +/*get the fw version +*example:cat ftstpfwver +*/ +static DEVICE_ATTR(ftstpfwver, S_IRUGO | S_IWUSR, ft6x06_tpfwver_show, + ft6x06_tpfwver_store); + +/*upgrade from *.i +*example: echo 1 > ftsfwupdate +*/ +static DEVICE_ATTR(ftsfwupdate, S_IRUGO | S_IWUSR, ft6x06_fwupdate_show, + ft6x06_fwupdate_store); + +/*read and write register +*read example: echo 88 > ftstprwreg ---read register 0x88 +*write example:echo 8807 > ftstprwreg ---write 0x07 into register 0x88 +* +*note:the number of input must be 2 or 4.if it not enough,please fill in the 0. +*/ +static DEVICE_ATTR(ftstprwreg, S_IRUGO | S_IWUSR, ft6x06_tprwreg_show, + ft6x06_tprwreg_store); + + +/*upgrade from app.bin +*example:echo "*_app.bin" > ftsfwupgradeapp +*/ +static DEVICE_ATTR(ftsfwupgradeapp, S_IRUGO | S_IWUSR, ft6x06_fwupgradeapp_show, + ft6x06_fwupgradeapp_store); + + +/*add your attr in here*/ +static struct attribute *ft6x06_attributes[] = { + &dev_attr_ftstpfwver.attr, + &dev_attr_ftsfwupdate.attr, + &dev_attr_ftstprwreg.attr, + &dev_attr_ftsfwupgradeapp.attr, + NULL +}; + +static struct attribute_group ft6x06_attribute_group = { + .attrs = ft6x06_attributes +}; + +/*create sysfs for debug*/ +int ft6x06_create_sysfs(struct i2c_client *client) +{ + int err; + err = sysfs_create_group(&client->dev.kobj, &ft6x06_attribute_group); + if (0 != err) { + dev_err(&client->dev, + "%s() - ERROR: sysfs_create_group() failed.\n", + __func__); + sysfs_remove_group(&client->dev.kobj, &ft6x06_attribute_group); + return -EIO; + } else { + mutex_init(&g_device_mutex); + pr_info("ft6x06:%s() - sysfs_create_group() succeeded.\n", + __func__); + } + return err; +} + +void ft6x06_release_sysfs(struct i2c_client *client) +{ + sysfs_remove_group(&client->dev.kobj, &ft6x06_attribute_group); + mutex_destroy(&g_device_mutex); +} + +/*create apk debug channel*/ +#define PROC_UPGRADE 0 +#define PROC_READ_REGISTER 1 +#define PROC_WRITE_REGISTER 2 +#define PROC_AUTOCLB 4 +#define PROC_UPGRADE_INFO 5 +#define PROC_WRITE_DATA 6 +#define PROC_READ_DATA 7 + + +#define PROC_NAME "ft5x0x-debug" +static unsigned char proc_operate_mode = PROC_UPGRADE; +static struct proc_dir_entry *ft6x06_proc_entry; +/*interface of write proc*/ +static int ft6x06_debug_write(struct file *filp, + const char __user *buff, unsigned long len, void *data) +{ + struct i2c_client *client = (struct i2c_client *)ft6x06_proc_entry->data; + unsigned char writebuf[FTS_PACKET_LENGTH]; + int buflen = len; + int writelen = 0; + int ret = 0; + + if (copy_from_user(&writebuf, buff, buflen)) { + dev_err(&client->dev, "%s:copy from user error\n", __func__); + return -EFAULT; + } + proc_operate_mode = writebuf[0]; + + switch (proc_operate_mode) { + case PROC_UPGRADE: + { + char upgrade_file_path[128]; + memset(upgrade_file_path, 0, sizeof(upgrade_file_path)); + sprintf(upgrade_file_path, "%s", writebuf + 1); + upgrade_file_path[buflen-1] = '\0'; + DBG("%s\n", upgrade_file_path); + disable_irq(client->irq); + + ret = fts_ctpm_fw_upgrade_with_app_file(client, upgrade_file_path); + + enable_irq(client->irq); + if (ret < 0) { + dev_err(&client->dev, "%s:upgrade failed.\n", __func__); + return ret; + } + } + break; + case PROC_READ_REGISTER: + writelen = 1; + ret = ft6x06_i2c_Write(client, writebuf + 1, writelen); + if (ret < 0) { + dev_err(&client->dev, "%s:write iic error\n", __func__); + return ret; + } + break; + case PROC_WRITE_REGISTER: + writelen = 2; + ret = ft6x06_i2c_Write(client, writebuf + 1, writelen); + if (ret < 0) { + dev_err(&client->dev, "%s:write iic error\n", __func__); + return ret; + } + break; + case PROC_AUTOCLB: + DBG("%s: autoclb\n", __func__); + fts_ctpm_auto_clb(client); + break; + case PROC_READ_DATA: + case PROC_WRITE_DATA: + writelen = len - 1; + ret = ft6x06_i2c_Write(client, writebuf + 1, writelen); + if (ret < 0) { + dev_err(&client->dev, "%s:write iic error\n", __func__); + return ret; + } + break; + default: + break; + } + + + return len; +} + +/*interface of read proc*/ +static int ft6x06_debug_read( char *page, char **start, + off_t off, int count, int *eof, void *data ) +{ + struct i2c_client *client = (struct i2c_client *)ft6x06_proc_entry->data; + int ret = 0; + unsigned char buf[PAGE_SIZE]; + int num_read_chars = 0; + int readlen = 0; + u8 regvalue = 0x00, regaddr = 0x00; + + switch (proc_operate_mode) { + case PROC_UPGRADE: + /*after calling ft5x0x_debug_write to upgrade*/ + regaddr = 0xA6; + ret = ft6x06_read_reg(client, regaddr, ®value); + if (ret < 0) + num_read_chars = sprintf(buf, "%s", "get fw version failed.\n"); + else + num_read_chars = sprintf(buf, "current fw version:0x%02x\n", regvalue); + break; + case PROC_READ_REGISTER: + readlen = 1; + ret = ft6x06_i2c_Read(client, NULL, 0, buf, readlen); + if (ret < 0) { + dev_err(&client->dev, "%s:read iic error\n", __func__); + return ret; + } + num_read_chars = 1; + break; + case PROC_READ_DATA: + readlen = count; + ret = ft6x06_i2c_Read(client, NULL, 0, buf, readlen); + if (ret < 0) { + dev_err(&client->dev, "%s:read iic error\n", __func__); + return ret; + } + + num_read_chars = readlen; + break; + case PROC_WRITE_DATA: + break; + default: + break; + } + + memcpy(page, buf, num_read_chars); + return num_read_chars; +} +int ft6x06_create_apk_debug_channel(struct i2c_client * client) +{ + ft6x06_proc_entry = create_proc_entry(PROC_NAME, 0777, NULL); + if (NULL == ft6x06_proc_entry) { + dev_err(&client->dev, "Couldn't create proc entry!\n"); + return -ENOMEM; + } else { + dev_info(&client->dev, "Create proc entry success!\n"); + ft6x06_proc_entry->data = client; + ft6x06_proc_entry->write_proc = ft6x06_debug_write; + ft6x06_proc_entry->read_proc = ft6x06_debug_read; + } + return 0; +} + +void ft6x06_release_apk_debug_channel(void) +{ + if (ft6x06_proc_entry) + remove_proc_entry(PROC_NAME, NULL); +} + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft6x06_ex_fun.h b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft6x06_ex_fun.h new file mode 100755 index 00000000..e25675c0 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft6x06_ex_fun.h @@ -0,0 +1,79 @@ +#ifndef __LINUX_FT6X06_EX_FUN_H__ +#define __LINUX_FT6X06_EX_FUN_H__ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + + +#define FT_UPGRADE_AA 0xAA +#define FT_UPGRADE_55 0x55 + + +//upgrade config of FT6X06 +/* +#define FT6X06_UPGRADE_AA_DELAY 100 +#define FT6X06_UPGRADE_55_DELAY 10 +#define FT6X06_UPGRADE_ID_1 0x79 +#define FT6X06_UPGRADE_ID_2 0x08 +#define FT6X06_UPGRADE_READID_DELAY 10 +#define FT6X06_UPGRADE_EARSE_DELAY 2000 +*/ + +/*upgrade config of FT6X36*/ +#define FT6X06_UPGRADE_AA_DELAY 10 +#define FT6X06_UPGRADE_55_DELAY 10 +#define FT6X06_UPGRADE_ID_1 0x79 +#define FT6X06_UPGRADE_ID_2 0x18 +#define FT6X06_UPGRADE_READID_DELAY 10 +#define FT6X06_UPGRADE_EARSE_DELAY 2000 + +#define FTS_PACKET_LENGTH 128 +#define FTS_SETTING_BUF_LEN 128 + +#define FTS_UPGRADE_LOOP 20 + +#define FTS_FACTORYMODE_VALUE 0x40 +#define FTS_WORKMODE_VALUE 0x00 + +//#define AUTO_CLB +#define FTS_DBG +#ifdef FTS_DBG +#define DBG(fmt, args...) printk("[FTS]" fmt, ## args) +#else +#define DBG(fmt, args...) do{}while(0) +#endif + +/*create sysfs for debug*/ +int ft6x06_create_sysfs(struct i2c_client * client); + +void ft6x06_release_sysfs(struct i2c_client * client); + +int ft6x06_create_apk_debug_channel(struct i2c_client *client); + +void ft6x06_release_apk_debug_channel(void); + +/* +*ft6x06_write_reg- write register +*@client: handle of i2c +*@regaddr: register address +*@regvalue: register value +* +*/ +int ft6x06_write_reg(struct i2c_client * client,u8 regaddr, u8 regvalue); + +int ft6x06_read_reg(struct i2c_client * client,u8 regaddr, u8 *regvalue); + +#endif diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft6x06_ts.c b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft6x06_ts.c new file mode 100755 index 00000000..56148177 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft6x06_ts.c @@ -0,0 +1,511 @@ +/* drivers/input/touchscreen/ft5x06_ts.c + * + * FocalTech ft6x06 TouchScreen driver. + * + * Copyright (c) 2010 Focal tech Ltd. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#include +#include +#include +#include "ft6x06_ts.h" +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//#define FTS_CTL_FACE_DETECT +#define FTS_CTL_IIC +#define SYSFS_DEBUG +#define FTS_APK_DEBUG +//#define FT6X06_DOWNLOAD + +#ifdef FTS_CTL_IIC +#include "focaltech_ctl.h" +#endif +#ifdef FTS_CTL_FACE_DETECT +#include "ft_psensor_drv.h" +#endif +#ifdef SYSFS_DEBUG +#include "ft6x06_ex_fun.h" +#endif + +#if 0 +struct ts_event { + u16 au16_x[CFG_MAX_TOUCH_POINTS]; /*x coordinate */ + u16 au16_y[CFG_MAX_TOUCH_POINTS]; /*y coordinate */ + u8 au8_touch_event[CFG_MAX_TOUCH_POINTS]; /*touch event: + 0 -- down; 1-- up; 2 -- contact */ + u8 au8_finger_id[CFG_MAX_TOUCH_POINTS]; /*touch ID */ + u16 pressure; + u8 touch_point; +}; + +struct ft6x06_ts_data { + unsigned int irq; + unsigned int x_max; + unsigned int y_max; + struct i2c_client *client; + struct input_dev *input_dev; + struct ts_event event; + struct ft6x06_platform_data *pdata; +#ifdef CONFIG_PM + struct early_suspend *early_suspend; +#endif +}; + +#define FTS_POINT_UP 0x01 +#define FTS_POINT_DOWN 0x00 +#define FTS_POINT_CONTACT 0x02 +#endif + +/* +*ft6x06_i2c_Read-read data and write data by i2c +*@client: handle of i2c +*@writebuf: Data that will be written to the slave +*@writelen: How many bytes to write +*@readbuf: Where to store data read from slave +*@readlen: How many bytes to read +* +*Returns negative errno, else the number of messages executed +* +* +*/ +int ft6x06_i2c_Read(struct i2c_client *client, char *writebuf, + int writelen, char *readbuf, int readlen) +{ + int ret; + + if (writelen > 0) { + struct i2c_msg msgs[] = { + { + .addr = client->addr, + .flags = 0, + .len = writelen, + .buf = writebuf, + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = readlen, + .buf = readbuf, + }, + }; + ret = i2c_transfer(client->adapter, msgs, 2); + if (ret < 0) + dev_err(&client->dev, "f%s: i2c read error.\n", + __func__); + } else { + struct i2c_msg msgs[] = { + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = readlen, + .buf = readbuf, + }, + }; + ret = i2c_transfer(client->adapter, msgs, 1); + if (ret < 0) + dev_err(&client->dev, "%s:i2c read error.\n", __func__); + } + return ret; +} +/*write data by i2c*/ +int ft6x06_i2c_Write(struct i2c_client *client, char *writebuf, int writelen) +{ + int ret; + + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = writelen, + .buf = writebuf, + }, + }; + + ret = i2c_transfer(client->adapter, msg, 1); + if (ret < 0) + dev_err(&client->dev, "%s i2c write error.\n", __func__); + + return ret; +} + +#if 0 +/*Read touch point information when the interrupt is asserted.*/ +static int ft6x06_read_Touchdata(struct ft6x06_ts_data *data) +{ + struct ts_event *event = &data->event; + u8 buf[POINT_READ_BUF] = { 0 }; + int ret = -1; + int i = 0; + u8 pointid = FT_MAX_ID; + + ret = ft6x06_i2c_Read(data->client, buf, 1, buf, POINT_READ_BUF); + if (ret < 0) { + dev_err(&data->client->dev, "%s read touchdata failed.\n", + __func__); + return ret; + } + memset(event, 0, sizeof(struct ts_event)); + + //event->touch_point = buf[2] & 0x0F; + + //event->touch_point = 0; + + for (i = 0; i < CFG_MAX_TOUCH_POINTS; i++) + { + pointid = (buf[FT_TOUCH_ID_POS + FT_TOUCH_STEP * i]) >> 4; + if (pointid >= FT_MAX_ID) + break; + else + event->touch_point++; + event->au16_x[i] = + (s16) (buf[FT_TOUCH_X_H_POS + FT_TOUCH_STEP * i] & 0x0F) << + 8 | (s16) buf[FT_TOUCH_X_L_POS + FT_TOUCH_STEP * i]; + event->au16_y[i] = + (s16) (buf[FT_TOUCH_Y_H_POS + FT_TOUCH_STEP * i] & 0x0F) << + 8 | (s16) buf[FT_TOUCH_Y_L_POS + FT_TOUCH_STEP * i]; + event->au8_touch_event[i] = + buf[FT_TOUCH_EVENT_POS + FT_TOUCH_STEP * i] >> 6; + event->au8_finger_id[i] = + (buf[FT_TOUCH_ID_POS + FT_TOUCH_STEP * i]) >> 4; + } + + //event->pressure = FT_PRESS; + + return 0; +} + +/* +*report the point information +*/ +static void ft6x06_report_value(struct ft6x06_ts_data *data) +{ + struct ts_event *event = &data->event; + int i = 0; + int up_point = 0; + + for (i = 0; i < event->touch_point; i++) + { + input_mt_slot(data->input_dev, event->au8_finger_id[i]); + + if (event->au8_touch_event[i]== 0 || event->au8_touch_event[i] == 2) + { + input_mt_report_slot_state(data->input_dev, MT_TOOL_FINGER, + true); + //input_report_abs(data->input_dev, ABS_MT_TRACKING_ID, + //event->au8_finger_id[i]); + input_report_abs(data->input_dev, ABS_MT_PRESSURE, + 0x3f); + input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, + 0x05); + input_report_abs(data->input_dev, ABS_MT_POSITION_X, + event->au16_x[i]); + input_report_abs(data->input_dev, ABS_MT_POSITION_Y, + event->au16_y[i]); + + } + else + { + up_point++; + input_mt_report_slot_state(data->input_dev, MT_TOOL_FINGER, + false); + } + + } + + if(event->touch_point == up_point) + input_report_key(data->input_dev, BTN_TOUCH, 0); + else + input_report_key(data->input_dev, BTN_TOUCH, 1); + + input_sync(data->input_dev); + +} + +/*The ft6x06 device will signal the host about TRIGGER_FALLING. +*Processed when the interrupt is asserted. +*/ +static irqreturn_t ft6x06_ts_interrupt(int irq, void *dev_id) +{ + struct ft6x06_ts_data *ft6x06_ts = dev_id; + int ret = 0; + disable_irq_nosync(ft6x06_ts->irq); + + ret = ft6x06_read_Touchdata(ft6x06_ts); + if (ret == 0) + ft6x06_report_value(ft6x06_ts); + + enable_irq(ft6x06_ts->irq); + + //printk(KERN_WARNING "interrupt \n"); + + return IRQ_HANDLED; +} + +static int ft6x06_ts_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct ft6x06_platform_data *pdata = + (struct ft6x06_platform_data *)client->dev.platform_data; + struct ft6x06_ts_data *ft6x06_ts; + struct input_dev *input_dev; + int err = 0; + unsigned char uc_reg_value; + unsigned char uc_reg_addr; + + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + err = -ENODEV; + goto exit_check_functionality_failed; + } + + ft6x06_ts = kzalloc(sizeof(struct ft6x06_ts_data), GFP_KERNEL); + + if (!ft6x06_ts) { + err = -ENOMEM; + goto exit_alloc_data_failed; + } + + i2c_set_clientdata(client, ft6x06_ts); + ft6x06_ts->irq = client->irq; + ft6x06_ts->client = client; + ft6x06_ts->pdata = pdata; + ft6x06_ts->x_max = pdata->x_max - 1; + ft6x06_ts->y_max = pdata->y_max - 1; + ft6x06_ts->pdata->irq = ft6x06_ts->irq; + client->irq = ft6x06_ts->irq; + pr_info("irq = %d\n", client->irq); + +#ifdef CONFIG_PM + #if 0 + err = gpio_request(pdata->reset, "ft6x06 reset"); + if (err < 0) { + dev_err(&client->dev, "%s:failed to set gpio reset.\n", + __func__); + goto exit_request_reset; + } + #endif +#endif + + err = request_threaded_irq(client->irq, NULL, ft6x06_ts_interrupt, + IRQF_TRIGGER_FALLING, client->dev.driver->name, + ft6x06_ts); + + if (err < 0) { + dev_err(&client->dev, "ft6x06_probe: request irq failed\n"); + goto exit_irq_request_failed; + } + disable_irq(client->irq); + + input_dev = input_allocate_device(); + if (!input_dev) { + err = -ENOMEM; + dev_err(&client->dev, "failed to allocate input device\n"); + goto exit_input_dev_alloc_failed; + } + + ft6x06_ts->input_dev = input_dev; + + __set_bit(EV_ABS, input_dev->evbit); + __set_bit(EV_KEY, input_dev->evbit); + __set_bit(BTN_TOUCH, input_dev->keybit); + __set_bit(INPUT_PROP_DIRECT, input_dev->propbit); + + input_mt_init_slots(input_dev, MT_MAX_TOUCH_POINTS); + input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, + 0, PRESS_MAX, 0, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_X, + 0, ft6x06_ts->x_max, 0, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_Y, + 0, ft6x06_ts->y_max, 0, 0); + input_set_abs_params(input_dev, ABS_MT_PRESSURE, + 0, PRESS_MAX, 0, 0); + + input_dev->name = FT6X06_NAME; + err = input_register_device(input_dev); + if (err) { + dev_err(&client->dev, + "ft6x06_ts_probe: failed to register input device: %s\n", + dev_name(&client->dev)); + goto exit_input_register_device_failed; + } + /*make sure CTP already finish startup process */ + msleep(150); + + /*get some register information */ + uc_reg_addr = FT6x06_REG_FW_VER; + ft6x06_i2c_Read(client, &uc_reg_addr, 1, &uc_reg_value, 1); + dev_dbg(&client->dev, "[FTS] Firmware version = 0x%x\n", uc_reg_value); + + uc_reg_addr = FT6x06_REG_POINT_RATE; + ft6x06_i2c_Read(client, &uc_reg_addr, 1, &uc_reg_value, 1); + dev_dbg(&client->dev, "[FTS] report rate is %dHz.\n", + uc_reg_value * 10); + + uc_reg_addr = FT6x06_REG_THGROUP; + ft6x06_i2c_Read(client, &uc_reg_addr, 1, &uc_reg_value, 1); + dev_dbg(&client->dev, "[FTS] touch threshold is %d.\n", + uc_reg_value * 4); + +#ifdef SYSFS_DEBUG + ft6x06_create_sysfs(client); +#endif + +#ifdef FTS_CTL_IIC + if (ft_rw_iic_drv_init(client) < 0) + dev_err(&client->dev, "%s:[FTS] create fts control iic driver failed\n", + __func__); +#endif + +#ifdef FTS_APK_DEBUG + ft6x06_create_apk_debug_channel(client); +#endif + +#ifdef FTS_CTL_FACE_DETECT + if (ft_psensor_drv_init(client) < 0) + dev_err(&client->dev, "%s:[FTS] create fts control psensor driver failed\n", + __func__); +#endif + + enable_irq(client->irq); + return 0; + +exit_input_register_device_failed: + input_free_device(input_dev); + +exit_input_dev_alloc_failed: + free_irq(client->irq, ft6x06_ts); +#ifdef CONFIG_PM +exit_request_reset: + gpio_free(ft6x06_ts->pdata->reset); +#endif + +exit_irq_request_failed: + i2c_set_clientdata(client, NULL); + kfree(ft6x06_ts); + +exit_alloc_data_failed: +exit_check_functionality_failed: + return err; +} + +#ifdef CONFIG_PM +static void ft6x06_ts_suspend(struct early_suspend *handler) +{ + struct ft6x06_ts_data *ts = container_of(handler, struct ft6x06_ts_data, + early_suspend); + + dev_dbg(&ts->client->dev, "[FTS]ft6x06 suspend\n"); + disable_irq(ts->pdata->irq); +} + +static void ft6x06_ts_resume(struct early_suspend *handler) +{ + struct ft6x06_ts_data *ts = container_of(handler, struct ft6x06_ts_data, + early_suspend); + + dev_dbg(&ts->client->dev, "[FTS]ft6x06 resume.\n"); + gpio_set_value(ts->pdata->reset, 0); + msleep(20); + gpio_set_value(ts->pdata->reset, 1); + enable_irq(ts->pdata->irq); +} +#else +#define ft6x06_ts_suspend NULL +#define ft6x06_ts_resume NULL +#endif + +static int __devexit ft6x06_ts_remove(struct i2c_client *client) +{ + struct ft6x06_ts_data *ft6x06_ts; + ft6x06_ts = i2c_get_clientdata(client); + input_unregister_device(ft6x06_ts->input_dev); + #ifdef CONFIG_PM + gpio_free(ft6x06_ts->pdata->reset); + #endif + + #ifdef SYSFS_DEBUG + ft6x06_release_sysfs(client); + #endif + #ifdef FTS_CTL_IIC + ft_rw_iic_drv_exit(); + #endif + #ifdef FTS_CTL_FACE_DETECT + ft_psensor_drv_exit(); + #endif + free_irq(client->irq, ft6x06_ts); + kfree(ft6x06_ts); + i2c_set_clientdata(client, NULL); + return 0; +} + +static const struct i2c_device_id ft6x06_ts_id[] = { + {FT6X06_NAME, 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, ft6x06_ts_id); + +static struct i2c_driver ft6x06_ts_driver = { + .probe = ft6x06_ts_probe, + .remove = __devexit_p(ft6x06_ts_remove), + .id_table = ft6x06_ts_id, + .suspend = ft6x06_ts_suspend, + .resume = ft6x06_ts_resume, + .driver = { + .name = FT6X06_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init ft6x06_ts_init(void) +{ + int ret; + ret = i2c_add_driver(&ft6x06_ts_driver); + if (ret) { + printk(KERN_WARNING "Adding ft6x06 driver failed " + "(errno = %d)\n", ret); + } else { + pr_info("Successfully added driver %s\n", + ft6x06_ts_driver.driver.name); + } + return ret; +} + +static void __exit ft6x06_ts_exit(void) +{ + i2c_del_driver(&ft6x06_ts_driver); +} + +module_init(ft6x06_ts_init); +module_exit(ft6x06_ts_exit); + +MODULE_AUTHOR(""); +MODULE_DESCRIPTION("FocalTech ft6x06 TouchScreen driver"); +MODULE_LICENSE("GPL"); + +#endif diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft6x06_ts.h b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft6x06_ts.h new file mode 100755 index 00000000..83859c05 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft6x06_ts.h @@ -0,0 +1,52 @@ +#ifndef __LINUX_FT6X06_TS_H__ +#define __LINUX_FT6X06_TS_H__ + +/* -- dirver configure -- */ +#define CFG_MAX_TOUCH_POINTS 2 +#define MT_MAX_TOUCH_POINTS 9 + +#define PRESS_MAX 0xFF +#define FT_PRESS 0x7F + +#define Proximity_Max 32 + +#define FT_FACE_DETECT_ON 0xc0 +#define FT_FACE_DETECT_OFF 0xe0 + +#define FT_FACE_DETECT_ENABLE 1 +#define FT_FACE_DETECT_DISABLE 0 +#define FT_FACE_DETECT_REG 0xB0 + +#define FT6X06_NAME "ft6x06_ts" + +#define FT_MAX_ID 0x0F +#define FT_TOUCH_STEP 6 +#define FT_FACE_DETECT_POS 1 +#define FT_TOUCH_X_H_POS 3 +#define FT_TOUCH_X_L_POS 4 +#define FT_TOUCH_Y_H_POS 5 +#define FT_TOUCH_Y_L_POS 6 +#define FT_TOUCH_EVENT_POS 3 +#define FT_TOUCH_ID_POS 5 + +#define POINT_READ_BUF (3 + FT_TOUCH_STEP * CFG_MAX_TOUCH_POINTS) + +/*register address*/ +#define FT6x06_REG_FW_VER 0xA6 +#define FT6x06_REG_POINT_RATE 0x88 +#define FT6x06_REG_THGROUP 0x80 + +int ft6x06_i2c_Read(struct i2c_client *client, char *writebuf, int writelen, + char *readbuf, int readlen); +int ft6x06_i2c_Write(struct i2c_client *client, char *writebuf, int writelen); + +/* The platform data for the Focaltech ft6x06 touchscreen driver */ +struct ft6x06_platform_data { + unsigned int x_max; + unsigned int y_max; + unsigned long irqflags; + unsigned int irq; + unsigned int reset; +}; + +#endif diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ini.c b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ini.c new file mode 100755 index 00000000..a4f8dc38 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ini.c @@ -0,0 +1,406 @@ +#include +#include +#include + +#include "ini.h" + + +char CFG_SSL = '['; /* Ïî±êÖ¾·ûSection Symbol --¿É¸ù¾ÝÌØÊâÐèÒª½øÐж¨Òå¸ü¸Ä£¬Èç { }µÈ*/ +char CFG_SSR = ']'; /* Ïî±êÖ¾·ûSection Symbol --¿É¸ù¾ÝÌØÊâÐèÒª½øÐж¨Òå¸ü¸Ä£¬Èç { }µÈ*/ +char CFG_NIS = ':'; /* name Óë index Ö®¼äµÄ·Ö¸ô·û */ +char CFG_NTS = '#'; /* ×¢ÊÍ·û*/ + +static char * ini_str_trim_r(char * buf); +static char * ini_str_trim_l(char * buf); +static int ini_file_get_line(char *filedata, char *buffer, int maxlen); +static int ini_split_key_value(char *buf, char **key, char **val); +static long atol(char *nptr); + + +/************************************************************* +Function: »ñµÃkeyµÄÖµ +Input: char * filedata¡¡Îļþ£»char * section¡¡ÏîÖµ£»char * key¡¡¼üÖµ +Output: char * value¡¡keyµÄÖµ +Return: 0 SUCCESS + -1 δÕÒµ½section + -2 δÕÒµ½key + -10 Îļþ´ò¿ªÊ§°Ü + -12 ¶ÁÈ¡Îļþʧ°Ü + -14 Îļþ¸ñʽ´íÎó + -22 ³¬³ö»º³åÇø´óС +Note: +*************************************************************/ +int ini_get_key(char *filedata, char * section, char * key, char * value) +{ + //char buf1[MAX_CFG_BUF + 1], buf2[MAX_CFG_BUF + 1]; + char *buf1, *buf2; + char *key_ptr, *val_ptr; + int n, ret; + int dataoff = 0; + + *value='\0'; + + buf1 = kzalloc(MAX_CFG_BUF + 1, GFP_KERNEL); + if(!buf1){ + printk("buf1: mem alloc failed.\n"); + return -ENOMEM; + } + buf2 = kzalloc(MAX_CFG_BUF + 1, GFP_KERNEL); + if(!buf2){ + printk("buf2: mem alloc failed.\n"); + kfree(buf1); + return -ENOMEM; + } + + while(1) { /* ËÑÕÒÏîsection */ + ret = CFG_ERR_READ_FILE; + n = ini_file_get_line(filedata+dataoff, buf1, MAX_CFG_BUF); + dataoff += n; + if(n < -1) + goto r_cfg_end; + ret = CFG_SECTION_NOT_FOUND; + if(n < 0) + goto r_cfg_end; /* Îļþβ£¬Î´·¢ÏÖ */ + + n = strlen(ini_str_trim_l(ini_str_trim_r(buf1))); + if(n == 0 || buf1[0] == CFG_NTS) + continue; /* ¿ÕÐÐ »ò ×¢ÊÍÐÐ */ + + ret = CFG_ERR_FILE_FORMAT; + if(n > 2 && ((buf1[0] == CFG_SSL && buf1[n-1] != CFG_SSR))) + goto r_cfg_end; + if(buf1[0] == CFG_SSL) { + buf1[n-1] = 0x00; + if(strcmp(buf1+1, section) == 0) + break; /* ÕÒµ½Ïîsection */ + } + } + + while(1){ /* ËÑÕÒkey */ + ret = CFG_ERR_READ_FILE; + n = ini_file_get_line(filedata+dataoff, buf1, MAX_CFG_BUF); + dataoff += n; + if(n < -1) + goto r_cfg_end; + ret = CFG_KEY_NOT_FOUND; + if(n < 0) + goto r_cfg_end;/* Îļþβ£¬Î´·¢ÏÖkey */ + + n = strlen(ini_str_trim_l(ini_str_trim_r(buf1))); + if(n == 0 || buf1[0] == CFG_NTS) + continue; /* ¿ÕÐÐ »ò ×¢ÊÍÐÐ */ + ret = CFG_KEY_NOT_FOUND; + if(buf1[0] == CFG_SSL) + goto r_cfg_end; + if(buf1[n-1] == '+') { /* Óö+ºÅ±íʾÏÂÒ»ÐмÌÐø */ + buf1[n-1] = 0x00; + while(1) { + ret = CFG_ERR_READ_FILE; + n = ini_file_get_line(filedata+dataoff, buf2, MAX_CFG_BUF); + dataoff += n; + if(n < -1) + goto r_cfg_end; + if(n < 0) + break;/* Îļþ½áÊø */ + + n = strlen(ini_str_trim_r(buf2)); + ret = CFG_ERR_EXCEED_BUF_SIZE; + if(n > 0 && buf2[n-1] == '+'){/* Óö+ºÅ±íʾÏÂÒ»ÐмÌÐø */ + buf2[n-1] = 0x00; + if( (strlen(buf1) + strlen(buf2)) > MAX_CFG_BUF) + goto r_cfg_end; + strcat(buf1, buf2); + continue; + } + if(strlen(buf1) + strlen(buf2) > MAX_CFG_BUF) + goto r_cfg_end; + strcat(buf1, buf2); + break; + } + } + ret = CFG_ERR_FILE_FORMAT; + if(ini_split_key_value(buf1, &key_ptr, &val_ptr) != 1) + goto r_cfg_end; + ini_str_trim_l(ini_str_trim_r(key_ptr)); + if(strcmp(key_ptr, key) != 0) + continue; /* ºÍkeyÖµ²»Æ¥Åä */ + strcpy(value, val_ptr); + break; + } + ret = CFG_OK; +r_cfg_end: + //if(fp != NULL) fclose(fp); + kfree(buf1); + kfree(buf2); + return ret; +} +/************************************************************* +Function: »ñµÃËùÓÐsection +Input: char *filename¡¡Îļþ,int max ×î´ó¿É·µ»ØµÄsectionµÄ¸öÊý +Output: char *sections[]¡¡´æ·ÅsectionÃû×Ö +Return: ·µ»Øsection¸öÊý¡£Èô³ö´í£¬·µ»Ø¸ºÊý¡£ + -10 Îļþ´ò¿ª³ö´í + -12 Îļþ¶ÁÈ¡´íÎó + -14 Îļþ¸ñʽ´íÎó +Note: +*************************************************************/ +int ini_get_sections(char *filedata, unsigned char * sections[], int max) +{ + //FILE *fp; + char buf1[MAX_CFG_BUF + 1]; + int n, n_sections = 0, ret; + int dataoff = 0; + +// if((fp = fopen(filename, "rb")) == NULL) +// return CFG_ERR_OPEN_FILE; + + while(1) {/*ËÑÕÒÏîsection */ + ret = CFG_ERR_READ_FILE; + n = ini_file_get_line(filedata+dataoff, buf1, MAX_CFG_BUF); + dataoff += n; + if(n < -1) + goto cfg_scts_end; + if(n < 0) + break;/* Îļþβ */ + n = strlen(ini_str_trim_l(ini_str_trim_r(buf1))); + if(n == 0 || buf1[0] == CFG_NTS) + continue; /* ¿ÕÐÐ »ò ×¢ÊÍÐÐ */ + ret = CFG_ERR_FILE_FORMAT; + if(n > 2 && ((buf1[0] == CFG_SSL && buf1[n-1] != CFG_SSR))) + goto cfg_scts_end; + if(buf1[0] == CFG_SSL) { + if (max!=0){ + buf1[n-1] = 0x00; + strcpy((char *)sections[n_sections], buf1+1); + if (n_sections>=max) + break; /* ³¬¹ý¿É·µ»Ø×î´ó¸öÊý */ + } + n_sections++; + } + + } + ret = n_sections; +cfg_scts_end: +// if(fp != NULL) +// fclose(fp); + return ret; +} + + +/************************************************************* +Function: È¥³ý×Ö·û´®ÓұߵĿÕ×Ö·û +Input: char * buf ×Ö·û´®Ö¸Õë +Output: +Return: ×Ö·û´®Ö¸Õë +Note: +*************************************************************/ +static char * ini_str_trim_r(char * buf) +{ + int len,i; + char tmp[128]; + + memset(tmp, 0, sizeof(tmp)); + len = strlen(buf); +// tmp = (char *)malloc(len); + + memset(tmp,0x00,len); + for(i = 0;i < len;i++) { + if (buf[i] !=' ') + break; + } + if (i < len) { + strncpy(tmp,(buf+i),(len-i)); + } + strncpy(buf,tmp,len); +// free(tmp); + return buf; +} + +/************************************************************* +Function: È¥³ý×Ö·û´®×ó±ßµÄ¿Õ×Ö·û +Input: char * buf ×Ö·û´®Ö¸Õë +Output: +Return: ×Ö·û´®Ö¸Õë +Note: +*************************************************************/ +static char * ini_str_trim_l(char * buf) +{ + int len,i; + char tmp[128]; + + memset(tmp, 0, sizeof(tmp)); + len = strlen(buf); + //tmp = (char *)malloc(len); + + memset(tmp,0x00,len); + + for(i = 0;i < len;i++) { + if (buf[len-i-1] !=' ') + break; + } + if (i < len) { + strncpy(tmp,buf,len-i); + } + strncpy(buf,tmp,len); + //free(tmp); + return buf; +} +/************************************************************* +Function: ´ÓÎļþÖжÁÈ¡Ò»ÐÐ +Input: FILE *fp Îļþ¾ä±ú£»int maxlen »º³åÇø×î´ó³¤¶È +Output: char *buffer Ò»ÐÐ×Ö·û´® +Return: >0 ʵ¼Ê¶ÁµÄ³¤¶È + -1 Îļþ½áÊø + -2 ¶ÁÎļþ³ö´í +Note: +*************************************************************/ +static int ini_file_get_line(char *filedata, char *buffer, int maxlen) +{ + int i, j; + char ch1; + + for(i=0, j=0; i= n) + return 0; + + if(buf[i] == '=') + return -1; + + k1 = i; + for(i++; i < n; i++) + if(buf[i] == '=') + break; + + if(i >= n) + return -2; + k2 = i; + + for(i++; i < n; i++) + if(buf[i] != ' ' && buf[i] != '\t') + break; + + buf[k2] = '\0'; + + *key = buf + k1; + *val = buf + i; + return 1; +} + +int my_atoi(const char *str) +{ + int result = 0; + int signal = 1; /* ĬÈÏΪÕýÊý */ + if((*str>='0'&&*str<='9')||*str=='-'||*str=='+') { + if(*str=='-'||*str=='+') { + if(*str=='-') + signal = -1; /*ÊäÈ븺Êý*/ + str++; + } + } + else + return 0; + /*¿ªÊ¼×ª»»*/ + while(*str>='0' && *str<='9') + result = result*10 + (*str++ - '0' ); + + return signal*result; +} + +int isspace(int x) +{ + if(x==' '||x=='\t'||x=='\n'||x=='\f'||x=='\b'||x=='\r') + return 1; + else + return 0; +} + +int isdigit(int x) +{ + if(x<='9' && x>='0') + return 1; + else + return 0; + +} + +static long atol(char *nptr) +{ + int c; /* current char */ + long total; /* current total */ + int sign; /* if ''-'', then negative, otherwise positive */ + /* skip whitespace */ + while ( isspace((int)(unsigned char)*nptr) ) + ++nptr; + c = (int)(unsigned char)*nptr++; + sign = c; /* save sign indication */ + if (c == '-' || c == '+') + c = (int)(unsigned char)*nptr++; /* skip sign */ + total = 0; + while (isdigit(c)) { + total = 10 * total + (c - '0'); /* accumulate digit */ + c = (int)(unsigned char)*nptr++; /* get next char */ + } + if (sign == '-') + return -total; + else + return total; /* return result, negated if necessary */ +} +/*** +*int atoi(char *nptr) - Convert string to long +* +*Purpose: +* Converts ASCII string pointed to by nptr to binary. +* Overflow is not detected. Because of this, we can just use +* atol(). +* +*Entry: +* nptr = ptr to string to convert +* +*Exit: +* return int value of the string +* +*Exceptions: +* None - overflow is not detected. +* +*******************************************************************************/ +int atoi(char *nptr) +{ + return (int)atol(nptr); +} + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ini.h b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ini.h new file mode 100755 index 00000000..72434b53 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ini.h @@ -0,0 +1,43 @@ +#ifndef INI_H +#define INI_H + +#define MAX_CFG_BUF 512 +#define SUCCESS 0 +/* return value */ +#define CFG_OK SUCCESS +#define CFG_SECTION_NOT_FOUND -1 +#define CFG_KEY_NOT_FOUND -2 +#define CFG_ERR -10 + +#define CFG_ERR_OPEN_FILE -10 +#define CFG_ERR_CREATE_FILE -11 +#define CFG_ERR_READ_FILE -12 +#define CFG_ERR_WRITE_FILE -13 +#define CFG_ERR_FILE_FORMAT -14 + + +#define CFG_ERR_EXCEED_BUF_SIZE -22 + +#define COPYF_OK SUCCESS +#define COPYF_ERR_OPEN_FILE -10 +#define COPYF_ERR_CREATE_FILE -11 +#define COPYF_ERR_READ_FILE -12 +#define COPYF_ERR_WRITE_FILE -13 + + +struct ini_key_location { + int ini_section_line_no; + int ini_key_line_no; + int ini_key_lines; +}; + + +int ini_get_key(char *filedata, char * section, char * key, char * value); +int ini_get_sections(char *filedata, unsigned char * sections[], int max); + +int ini_split_section(char *section, char **name, char **index); +//int ini_join_section(char **section, char *name, char *index); + +int atoi(char *nptr); + +#endif diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/Kconfig b/ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/Kconfig new file mode 100755 index 00000000..0f47c8bc --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/Kconfig @@ -0,0 +1,16 @@ +# +# GSL1680 capacity touch screen driver configuration +# +config TOUCHSCREEN_GSL1680 + tristate "ilead GSL1680 I2C Touchscreen Input Driver Support" + depends on ARCH_WMT + default y + help + Say Y here if you have an WMT based board with touchscreen + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called s_wmt_ts_gsl1680. + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/Makefile b/ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/Makefile new file mode 100755 index 00000000..372a0fce --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/Makefile @@ -0,0 +1,33 @@ +#KERNELDIR=/home/hangyan/android8850/kernel/ANDROID_3.0.8 +KERNELDIR=../../../../ +CROSS = arm_1103_le- +CC= $(CROSS)gcc +LD= $(CROSS)ld +STRIP = $(CROSS)strip + +DEBUG = n + +# Add your debugging flag (or not) to EXTRA_CFLAGS +ifeq ($(DEBUG),y) +# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines +DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines + +else + DEBFLAGS = -O2 -Wall +endif + +EXTRA_CFLAGS += $(DEBFLAGS) + + +MY_MODULE_NAME=s_wmt_ts_gsl1680 + +obj-m := $(MY_MODULE_NAME).o +$(MY_MODULE_NAME)-objs := gslX680.o wmt_ts.o gsl_point_id.b + +default: + $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules + $(STRIP) --strip-debug $(MY_MODULE_NAME).ko + rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions *.order *.symvers + +clean: + rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/gslX680.c b/ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/gslX680.c new file mode 100755 index 00000000..bcb252a5 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/gslX680.c @@ -0,0 +1,1416 @@ +/* + * drivers/input/touchscreen/gslX680.c + * + * Copyright (c) 2012 Shanghai Basewin + * Guan Yuwei + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + + + +#include +#include +#include +#include +#include +#include +//#include +//#include +#include +#include +#include +#include + +#if defined(CONFIG_HAS_EARLYSUSPEND) +#include +#endif +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include + + +//#include +//#include + +//#include +//#include +//#include +#include "gslX680.h" +#include "wmt_ts.h" +#include "../../../video/backlight/wmt_bl.h" + +//#define GSL_DEBUG +//#define GSL_TIMER +//#define REPORT_DATA_ANDROID_4_0 + +#define HAVE_TOUCH_KEY + +#define SCREEN_MAX_X 480 +#define SCREEN_MAX_Y 800 + + +#define GSLX680_I2C_NAME "touch_gslX680" +#define GSLX680_I2C_ADDR 0x40 +#define IRQ_PORT INT_GPIO_0 + +#define GSL_DATA_REG 0x80 +#define GSL_STATUS_REG 0xe0 +#define GSL_PAGE_REG 0xf0 + +#define PRESS_MAX 255 +#define MAX_FINGERS 5 +#define MAX_CONTACTS 10 +#define DMA_TRANS_LEN 0x20 + +#ifdef GSL_NOID_VERSION +int gsl_noid_ver = 0; +unsigned int gsl_config_data_id[512] = {0}; +#endif + +#ifdef HAVE_TOUCH_KEY +static u16 key = 0; +static int key_state_flag = 0; +struct key_data { + u16 key; + u16 x_min; + u16 x_max; + u16 y_min; + u16 y_max; +}; + +const u16 key_array[]={ + KEY_BACK, + KEY_HOME, + KEY_MENU, + KEY_SEARCH, + }; +#define MAX_KEY_NUM (sizeof(key_array)/sizeof(key_array[0])) + +struct key_data gsl_key_data[MAX_KEY_NUM] = { + {KEY_BACK, 2048, 2048, 2048, 2048}, + {KEY_HOME, 2048, 2048, 2048, 2048}, + {KEY_MENU, 2048, 2048, 2048, 2048}, + {KEY_SEARCH, 2048, 2048, 2048, 2048}, +}; +#endif + +struct gsl_ts_data { + u8 x_index; + u8 y_index; + u8 z_index; + u8 id_index; + u8 touch_index; + u8 data_reg; + u8 status_reg; + u8 data_size; + u8 touch_bytes; + u8 update_data; + u8 touch_meta_data; + u8 finger_size; +}; + +static struct gsl_ts_data devices[] = { + { + .x_index = 6, + .y_index = 4, + .z_index = 5, + .id_index = 7, + .data_reg = GSL_DATA_REG, + .status_reg = GSL_STATUS_REG, + .update_data = 0x4, + .touch_bytes = 4, + .touch_meta_data = 4, + .finger_size = 70, + }, +}; + +struct gsl_ts { + struct i2c_client *client; + struct input_dev *input; + struct work_struct work; + struct workqueue_struct *wq; + struct gsl_ts_data *dd; + u8 *touch_data; + u8 device_id; + u8 prev_touches; + bool is_suspended; + bool int_pending; + struct mutex sus_lock; +// uint32_t gpio_irq; + int irq; +#if defined(CONFIG_HAS_EARLYSUSPEND) + struct early_suspend early_suspend; +#endif +#ifdef GSL_TIMER + struct timer_list gsl_timer; +#endif + + struct workqueue_struct *timeout_queue; + struct delayed_work timeout_work; + struct mutex timeout_mutex; + int timeout_count; +}; + +#define DELAY_TIMEOUT 1000 +#define DELAY_TIMEOUT_MAX 3 + + + +struct gsl_ts *l_ts=NULL; + +static u32 id_sign[MAX_CONTACTS+1] = {0}; +static u8 id_state_flag[MAX_CONTACTS+1] = {0}; +static u8 id_state_old_flag[MAX_CONTACTS+1] = {0}; +static u16 x_old[MAX_CONTACTS+1] = {0}; +static u16 y_old[MAX_CONTACTS+1] = {0}; +static u16 x_new = 0; +static u16 y_new = 0; + +static struct fw_data* GSLX680_FW = NULL; +static int l_fwlen = 0; +static struct task_struct *resume_download_task; +static struct wake_lock downloadWakeLock; +static int is_delay = 0; + +extern int tp_led_gpio; +extern int tp_led_gpio_active; + +extern int sel_reg_bit; +extern int sel_reg_active; + + +extern int register_bl_notifier(struct notifier_block *nb); + +extern int unregister_bl_notifier(struct notifier_block *nb); + +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); + +//////////////////////////////////////////////////////////////////// +static int wmt_get_fwdata(void); + +//////////////////////////////////////////////////////////////////// +static int gslX680_chip_init(void) +{ + //gpio_set_status(PAD_GPIOA_6, gpio_status_out); + //gpio_out(PAD_GPIOA_6, 1); + // shutdown pin + wmt_rst_output(1); + // irq pin + //gpio_set_status(PAD_GPIOA_16, gpio_status_in); + //gpio_irq_set(PAD_GPIOA_16, GPIO_IRQ(INT_GPIO_0-INT_GPIO_0, GPIO_IRQ_RISING)); + wmt_set_gpirq(IRQ_TYPE_EDGE_RISING);//GIRQ_FALLING); + wmt_disable_gpirq(); + msleep(20); + return 0; +} + +static int gslX680_shutdown_low(void) +{ + //gpio_set_status(PAD_GPIOA_6, gpio_status_out); + //gpio_out(PAD_GPIOA_6, 0); + wmt_rst_output(0); + return 0; +} + +static int gslX680_shutdown_high(void) +{ + //gpio_set_status(PAD_GPIOA_6, gpio_status_out); + //gpio_out(PAD_GPIOA_6, 1); + wmt_rst_output(1); + return 0; +} + +static inline u16 join_bytes(u8 a, u8 b) +{ + u16 ab = 0; + ab = ab | a; + ab = ab << 8 | b; + return ab; +} + +#if 0 +static u32 gsl_read_interface(struct i2c_client *client, u8 reg, u8 *buf, u32 num) +{ + struct i2c_msg xfer_msg[2]; + + xfer_msg[0].addr = client->addr; + xfer_msg[0].len = 1; + xfer_msg[0].flags = client->flags & I2C_M_TEN; + xfer_msg[0].buf = ® + + xfer_msg[1].addr = client->addr; + xfer_msg[1].len = num; + xfer_msg[1].flags |= I2C_M_RD; + xfer_msg[1].buf = buf; + + if (reg < 0x80) { + i2c_transfer(client->adapter, xfer_msg, ARRAY_SIZE(xfer_msg)); + msleep(5); + } + + return i2c_transfer(client->adapter, xfer_msg, ARRAY_SIZE(xfer_msg)) == ARRAY_SIZE(xfer_msg) ? 0 : -EFAULT; +} +#endif + +static u32 gsl_write_interface(struct i2c_client *client, const u8 reg, u8 *buf, u32 num) +{ + struct i2c_msg xfer_msg[1]; + + buf[0] = reg; + + xfer_msg[0].addr = client->addr; + xfer_msg[0].len = num + 1; + xfer_msg[0].flags = client->flags & I2C_M_TEN; + xfer_msg[0].buf = buf; + + return i2c_transfer(client->adapter, xfer_msg, 1) == 1 ? 0 : -EFAULT; +} + +static __inline__ void fw2buf(u8 *buf, const u32 *fw) +{ + u32 *u32_buf = (int *)buf; + *u32_buf = *fw; +} + +static int wmt_get_fwdata(void) +{ + char fwname[128]; + + // get the firmware file name + memset(fwname,0,sizeof(fwname)); + wmt_ts_get_firmwfilename(fwname); + // load the data into GSLX680_FW + l_fwlen = read_firmwfile(fwname, &GSLX680_FW, gsl_config_data_id); + return ((l_fwlen>0)?0:-1); +} + +static void gsl_load_fw(struct i2c_client *client) +{ + u8 buf[DMA_TRANS_LEN*4 + 1] = {0}; + u8 send_flag = 1; + u8 *cur = buf + 1; + u32 source_line = 0; + u32 source_len = l_fwlen;//ARRAY_SIZE(GSLX680_FW); + + printk("=============gsl_load_fw start==============\n"); + + for (source_line = 0; source_line < source_len; source_line++) + { + /* init page trans, set the page val */ + if (GSL_PAGE_REG == GSLX680_FW[source_line].offset) + { + fw2buf(cur, &GSLX680_FW[source_line].val); + gsl_write_interface(client, GSL_PAGE_REG, buf, 4); + send_flag = 1; + } + else + { + if (1 == send_flag % (DMA_TRANS_LEN < 0x20 ? DMA_TRANS_LEN : 0x20)) + buf[0] = (u8)GSLX680_FW[source_line].offset; + + fw2buf(cur, &GSLX680_FW[source_line].val); + cur += 4; + + if (0 == send_flag % (DMA_TRANS_LEN < 0x20 ? DMA_TRANS_LEN : 0x20)) + { + gsl_write_interface(client, buf[0], buf, cur - buf - 1); + cur = buf + 1; + } + + send_flag++; + } + } + + printk("=============gsl_load_fw end==============\n"); + +} + + +static int gsl_ts_write(struct i2c_client *client, u8 addr, u8 *pdata, int datalen) +{ + int ret = 0; + u8 tmp_buf[128]; + unsigned int bytelen = 0; + if (datalen > 125) + { + dbg("%s too big datalen = %d!\n", __func__, datalen); + return -1; + } + + tmp_buf[0] = addr; + bytelen++; + + if (datalen != 0 && pdata != NULL) + { + memcpy(&tmp_buf[bytelen], pdata, datalen); + bytelen += datalen; + } + + ret = i2c_master_send(client, tmp_buf, bytelen); + return ret; +} + +static int gsl_ts_read(struct i2c_client *client, u8 addr, u8 *pdata, unsigned int datalen) +{ + int ret = 0; + + if (datalen > 126) + { + dbg("%s too big datalen = %d!\n", __func__, datalen); + return -1; + } + + ret = gsl_ts_write(client, addr, NULL, 0); + if (ret < 0) + { + dbg("%s set data address fail!\n", __func__); + return ret; + } + + return i2c_master_recv(client, pdata, datalen); +} + +#if 0 +static void test_i2c(struct i2c_client *client) +{ + u8 read_buf = 0; + u8 write_buf = 0x12; + int ret; + ret = gsl_ts_read( client, 0xf0, &read_buf, sizeof(read_buf) ); + if (ret < 0) + { + pr_info("I2C transfer error!\n"); + } + else + { + pr_info("I read reg 0xf0 is %x\n", read_buf); + } + msleep(10); + + ret = gsl_ts_write(client, 0xf0, &write_buf, sizeof(write_buf)); + if (ret < 0) + { + pr_info("I2C transfer error!\n"); + } + else + { + pr_info("I write reg 0xf0 0x12\n"); + } + msleep(10); + + ret = gsl_ts_read( client, 0xf0, &read_buf, sizeof(read_buf) ); + if (ret < 0 ) + { + pr_info("I2C transfer error!\n"); + } + else + { + pr_info("I read reg 0xf0 is 0x%x\n", read_buf); + } + msleep(10); + +} +#endif + +static int test_i2c(struct i2c_client *client) +{ + u8 read_buf = 0; + u8 write_buf = 0x12; + int ret, rc = 1; + + ret = gsl_ts_read( client, 0xf0, &read_buf, sizeof(read_buf) ); + if (ret < 0) + rc --; + else + dbg("I read reg 0xf0 is %x\n", read_buf); + + msleep(2); + ret = gsl_ts_write(client, 0xf0, &write_buf, sizeof(write_buf)); + if(ret >= 0 ) + dbg("I write reg 0xf0 0x12\n"); + + msleep(2); + ret = gsl_ts_read( client, 0xf0, &read_buf, sizeof(read_buf) ); + if(ret < 0 ) + rc --; + else + dbg("I read reg 0xf0 is 0x%x\n", read_buf); + + return rc; +} + +static void startup_chip(struct i2c_client *client) +{ + u8 tmp = 0x00; +#ifdef GSL_NOID_VERSION + if (gsl_noid_ver) + gsl_DataInit(gsl_config_data_id); +#endif + gsl_ts_write(client, 0xe0, &tmp, 1); + msleep(10); +} + +static void reset_chip(struct i2c_client *client) +{ + u8 buf[4] = {0x00}; + u8 tmp = 0x88; + gsl_ts_write(client, 0xe0, &tmp, sizeof(tmp)); + msleep(10); + + tmp = 0x04; + gsl_ts_write(client, 0xe4, &tmp, sizeof(tmp)); + msleep(10); + + gsl_ts_write(client, 0xbc, buf, sizeof(buf)); + msleep(10); +} + +static void clr_reg(struct i2c_client *client) +{ + u8 write_buf[4] = {0}; + + write_buf[0] = 0x88; + gsl_ts_write(client, 0xe0, &write_buf[0], 1); + msleep(20); + write_buf[0] = 0x03; + gsl_ts_write(client, 0x80, &write_buf[0], 1); + msleep(5); + write_buf[0] = 0x04; + gsl_ts_write(client, 0xe4, &write_buf[0], 1); + msleep(5); + write_buf[0] = 0x00; + gsl_ts_write(client, 0xe0, &write_buf[0], 1); + msleep(20); +} + +static void init_chip(struct i2c_client *client) +{ + int rc; + + gslX680_shutdown_low(); + msleep(20); + gslX680_shutdown_high(); + msleep(20); + rc = test_i2c(client); + if(rc < 0) + { + printk("------gslX680 test_i2c error------\n"); + return; + } + clr_reg(client); + reset_chip(client); + gsl_load_fw(client); + startup_chip(client); + reset_chip(client); + startup_chip(client); +} + +static void check_mem_data(struct i2c_client *client) +{ + /*char write_buf; + char read_buf[4] = {0}; + + msleep(30); + write_buf = 0x00; + gsl_ts_write(client,0xf0, &write_buf, sizeof(write_buf)); + gsl_ts_read(client,0x00, read_buf, sizeof(read_buf)); + gsl_ts_read(client,0x00, read_buf, sizeof(read_buf)); + if (read_buf[3] != 0x1 || read_buf[2] != 0 || read_buf[1] != 0 || read_buf[0] != 0) + { + dbg("!!!!!!!!!!!page: %x offset: %x val: %x %x %x %x\n",0x0, 0x0, read_buf[3], read_buf[2], read_buf[1], read_buf[0]); + init_chip(client); + }*/ + + u8 read_buf[4] = {0}; + + msleep(30); + gsl_ts_read(client,0xb0, read_buf, sizeof(read_buf)); + + if (read_buf[3] != 0x5a || read_buf[2] != 0x5a || read_buf[1] != 0x5a || read_buf[0] != 0x5a) + { + printk("#########check mem read 0xb0 = %x %x %x %x #########\n", read_buf[3], read_buf[2], read_buf[1], read_buf[0]); + init_chip(client); + } + +} + +static void record_point(u16 x, u16 y , u8 id) +{ + u16 x_err =0; + u16 y_err =0; + + id_sign[id]=id_sign[id]+1; + + if(id_sign[id]==1){ + x_old[id]=x; + y_old[id]=y; + } + + x = (x_old[id] + x)/2; + y = (y_old[id] + y)/2; + + if(x>x_old[id]){ + x_err=x -x_old[id]; + } + else{ + x_err=x_old[id]-x; + } + + if(y>y_old[id]){ + y_err=y -y_old[id]; + } + else{ + y_err=y_old[id]-y; + } + + if( (x_err > 3 && y_err > 1) || (x_err > 1 && y_err > 3) ){ + x_new = x; x_old[id] = x; + y_new = y; y_old[id] = y; + } + else{ + if(x_err > 3){ + x_new = x; x_old[id] = x; + } + else + x_new = x_old[id]; + if(y_err> 3){ + y_new = y; y_old[id] = y; + } + else + y_new = y_old[id]; + } + + if(id_sign[id]==1){ + x_new= x_old[id]; + y_new= y_old[id]; + } + +} + +void wmt_set_keypos(int index,int xmin,int xmax,int ymin,int ymax) +{ + gsl_key_data[index].x_min = xmin; + gsl_key_data[index].x_max = xmax; + gsl_key_data[index].y_min = ymin; + gsl_key_data[index].y_max = ymax; +} + +#ifdef HAVE_TOUCH_KEY +static void report_key(struct gsl_ts *ts, u16 x, u16 y) +{ + u16 i = 0; + + for(i = 0; i < MAX_KEY_NUM; i++) + { + if((gsl_key_data[i].x_min <= x) && (x <= gsl_key_data[i].x_max)&&(gsl_key_data[i].y_min <= y) && (y <= gsl_key_data[i].y_max)) + { + key = gsl_key_data[i].key; + input_report_key(ts->input, key, 1); + input_sync(ts->input); + key_state_flag = 1; + dbg("rport key:%d\n",key); + + if( tp_led_gpio >= 0 ){ + gpio_set_value(tp_led_gpio,tp_led_gpio_active); + + mutex_lock(&ts->timeout_mutex); + if( ts->timeout_count < 0 ){ + queue_delayed_work(ts->timeout_queue, &ts->timeout_work, msecs_to_jiffies(DELAY_TIMEOUT)); + } + ts->timeout_count = DELAY_TIMEOUT_MAX; + mutex_unlock(&ts->timeout_mutex); + } + break; + } + } +} +#endif + +static void report_data(struct gsl_ts *ts, u16 x, u16 y, u8 pressure, u8 id) +{ + //swap(x, y); + int tx,ty; + int keyx,keyy; + + dbg("#####id=%d,x=%d,y=%d######\n",id,x,y); + + + tx = x; + ty = y; + keyx = x; + keyy = y; + + if( (x>=wmt_ts_get_resolvX()&&x>=wmt_ts_get_resolvY()) + || (y>= wmt_ts_get_resolvX()&&y>= wmt_ts_get_resolvY())) + { + #ifdef HAVE_TOUCH_KEY + if (wmt_ts_if_tskey()) + { + report_key(ts,keyx,keyy); + } + #endif + return; + } + + + if (wmt_ts_get_xaxis()==1) + { + tx = y; + ty = x; + } + if (wmt_ts_get_xdir()==-1) + { + tx = wmt_ts_get_resolvX() - tx - 1; + } + if (wmt_ts_get_ydir()==-1) + { + ty = wmt_ts_get_resolvY() - ty - 1; + } + /*if ((tx < 0) || (tx >= wmt_ts_get_resolvX()) || + (ty < 0) || (ty >= wmt_ts_get_resolvY())) + { + dbg("Invalid point(%d,%d)\n"); + return; + }*/ + x = tx; + y = ty; + + + if (wmt_ts_get_lcdexchg()) { + int tmp; + tmp = x; + x = y; + y = wmt_ts_get_resolvX() - tmp; + } + + dbg("rpt%d(%d,%d)\n",id,x,y); +#ifdef REPORT_DATA_ANDROID_4_0 + input_mt_slot(ts->input, id); + input_report_abs(ts->input, ABS_MT_TRACKING_ID, id); + //input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, pressure); + input_report_abs(ts->input, ABS_MT_POSITION_X, x); + input_report_abs(ts->input, ABS_MT_POSITION_Y, y); + //input_report_abs(ts->input, ABS_MT_WIDTH_MAJOR, 1); +#else + //add for cross finger 2013-1-10 + input_report_key(ts->input, BTN_TOUCH, 1); + input_report_abs(ts->input, ABS_MT_TRACKING_ID, id); + //input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, pressure); + input_report_abs(ts->input, ABS_MT_POSITION_X,x); + input_report_abs(ts->input, ABS_MT_POSITION_Y, y); + //input_report_abs(ts->input, ABS_MT_WIDTH_MAJOR, 1); + input_mt_sync(ts->input); +#endif +} + +static void process_gslX680_data(struct gsl_ts *ts) +{ + u8 id, touches; + u16 x, y; + int i = 0; +#ifdef GSL_NOID_VERSION + u32 tmp1; + u8 buf[4] = {0}; + struct gsl_touch_info cinfo; +#endif + touches = ts->touch_data[ts->dd->touch_index]; + +#ifdef GSL_NOID_VERSION + if (gsl_noid_ver) { + cinfo.finger_num = touches; + dbg("tp-gsl finger_num = %d\n",cinfo.finger_num); + for(i = 0; i < (touches < MAX_CONTACTS ? touches : MAX_CONTACTS); i ++) { + cinfo.x[i] = join_bytes( ( ts->touch_data[ts->dd->x_index + 4 * i + 1] & 0xf), + ts->touch_data[ts->dd->x_index + 4 * i]); + cinfo.y[i] = join_bytes(ts->touch_data[ts->dd->y_index + 4 * i + 1], + ts->touch_data[ts->dd->y_index + 4 * i ]); + cinfo.id[i] = ((ts->touch_data[ts->dd->x_index + 4 * i + 1] & 0xf0)>>4); + dbg("tp-gsl x = %d y = %d \n",cinfo.x[i],cinfo.y[i]); + } + cinfo.finger_num=(ts->touch_data[3]<<24)|(ts->touch_data[2]<<16) + |(ts->touch_data[1]<<8)|(ts->touch_data[0]); + gsl_alg_id_main(&cinfo); + tmp1=gsl_mask_tiaoping(); + dbg("[tp-gsl] tmp1=%x\n",tmp1); + if(tmp1>0&&tmp1<0xffffffff) { + buf[0]=0xa;buf[1]=0;buf[2]=0;buf[3]=0; + gsl_ts_write(ts->client,0xf0,buf,4); + buf[0]=(u8)(tmp1 & 0xff); + buf[1]=(u8)((tmp1>>8) & 0xff); + buf[2]=(u8)((tmp1>>16) & 0xff); + buf[3]=(u8)((tmp1>>24) & 0xff); + dbg("tmp1=%08x,buf[0]=%02x,buf[1]=%02x,buf[2]=%02x,buf[3]=%02x\n", + tmp1,buf[0],buf[1],buf[2],buf[3]); + gsl_ts_write(ts->client,0x8,buf,4); + } + touches = cinfo.finger_num; + } +#endif + + for(i=1;i<=MAX_CONTACTS;i++) + { + if(touches == 0) + id_sign[i] = 0; + id_state_flag[i] = 0; + } + for(i= 0;i < (touches > MAX_FINGERS ? MAX_FINGERS : touches);i ++) + { + #ifdef GSL_NOID_VERSION + if (gsl_noid_ver) { + id = cinfo.id[i]; + x = cinfo.x[i]; + y = cinfo.y[i]; + } + else { + x = join_bytes( ( ts->touch_data[ts->dd->x_index + 4 * i + 1] & 0xf), + ts->touch_data[ts->dd->x_index + 4 * i]); + y = join_bytes(ts->touch_data[ts->dd->y_index + 4 * i + 1], + ts->touch_data[ts->dd->y_index + 4 * i ]); + id = ts->touch_data[ts->dd->id_index + 4 * i] >> 4; + } + #endif + + if(1 <=id && id <= MAX_CONTACTS) + { + dbg("raw%d(%d,%d)\n", id, x, y); + record_point(x, y , id); + dbg("new%d(%d,%d)\n", id, x_new, y_new); + report_data(ts, x_new, y_new, 10, id); + id_state_flag[id] = 1; + } + } + for(i=1;i<=MAX_CONTACTS;i++) + { + if( (0 == touches) || ((0 != id_state_old_flag[i]) && (0 == id_state_flag[i])) ) + { + #ifdef REPORT_DATA_ANDROID_4_0 + input_mt_slot(ts->input, i); + input_report_abs(ts->input, ABS_MT_TRACKING_ID, -1); + input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, false); + #endif + id_sign[i]=0; + } + id_state_old_flag[i] = id_state_flag[i]; + } +#ifndef REPORT_DATA_ANDROID_4_0 + if(0 == touches) + { + //add 2013-1-10 cross fingers + //input_report_abs(ts->input, ABS_MT_TRACKING_ID, -1); + input_report_key(ts->input, BTN_TOUCH, 0); + //********************** + input_mt_sync(ts->input); + #ifdef HAVE_TOUCH_KEY + if (wmt_ts_if_tskey()) + { + if(key_state_flag) + { + input_report_key(ts->input, key, 0); + input_sync(ts->input); + key_state_flag = 0; + } + } + #endif + } +#endif + input_sync(ts->input); + ts->prev_touches = touches; +} + + +static void gsl_ts_xy_worker(struct work_struct *work) +{ + int rc; + u8 read_buf[4] = {0}; + + struct gsl_ts *ts = container_of(work, struct gsl_ts,work); + + dbg("---gsl_ts_xy_worker---\n"); + + if (ts->is_suspended == true) { + dev_dbg(&ts->client->dev, "TS is supended\n"); + ts->int_pending = true; + goto schedule; + } + + /* read data from DATA_REG */ + rc = gsl_ts_read(ts->client, 0x80, ts->touch_data, ts->dd->data_size); + dbg("---touches: %d ---\n",ts->touch_data[0]); + + if (rc < 0) + { + dev_err(&ts->client->dev, "read failed\n"); + goto schedule; + } + + if (ts->touch_data[ts->dd->touch_index] == 0xff) { + goto schedule; + } + + rc = gsl_ts_read( ts->client, 0xbc, read_buf, sizeof(read_buf)); + if (rc < 0) + { + dev_err(&ts->client->dev, "read 0xbc failed\n"); + goto schedule; + } + dbg("//////// reg %x : %x %x %x %x\n",0xbc, read_buf[3], read_buf[2], read_buf[1], read_buf[0]); + + if (read_buf[3] == 0 && read_buf[2] == 0 && read_buf[1] == 0 && read_buf[0] == 0) + { + process_gslX680_data(ts); + } + else + { + reset_chip(ts->client); + startup_chip(ts->client); + } + +schedule: + //enable_irq(ts->irq); + wmt_enable_gpirq(); + +} + +static irqreturn_t gsl_ts_irq(int irq, void *dev_id) +{ + struct gsl_ts *ts = dev_id; + + if (wmt_is_tsint()) + { + wmt_clr_int(); + if (wmt_is_tsirq_enable() && ts->is_suspended == false) + { + wmt_disable_gpirq(); + dbg("begin..\n"); + //if (!work_pending(&l_tsdata.pen_event_work)) + { + queue_work(ts->wq, &ts->work); + } + } + return IRQ_HANDLED; + } + return IRQ_NONE; + + + /*disable_irq_nosync(ts->irq); + + if (!work_pending(&ts->work)) + { + queue_work(ts->wq, &ts->work); + } + + return IRQ_HANDLED;*/ + +} + +#ifdef GSL_TIMER +static void gsl_timer_handle(unsigned long data) +{ + struct gsl_ts *ts = (struct gsl_ts *)data; + +#ifdef GSL_DEBUG + dbg("----------------gsl_timer_handle-----------------\n"); +#endif + + disable_irq_nosync(ts->irq); + check_mem_data(ts->client); + ts->gsl_timer.expires = jiffies + 3 * HZ; + add_timer(&ts->gsl_timer); + enable_irq(ts->irq); + +} +#endif + +static int gsl_ts_init_ts(struct i2c_client *client, struct gsl_ts *ts) +{ + struct input_dev *input_device; + int i; + int rc = 0; + + dbg("[GSLX680] Enter %s\n", __func__); + + + ts->dd = &devices[ts->device_id]; + + if (ts->device_id == 0) { + ts->dd->data_size = MAX_FINGERS * ts->dd->touch_bytes + ts->dd->touch_meta_data; + ts->dd->touch_index = 0; + } + + ts->touch_data = kzalloc(ts->dd->data_size, GFP_KERNEL); + if (!ts->touch_data) { + pr_err("%s: Unable to allocate memory\n", __func__); + return -ENOMEM; + } + + ts->prev_touches = 0; + + input_device = input_allocate_device(); + if (!input_device) { + rc = -ENOMEM; + goto error_alloc_dev; + } + + ts->input = input_device; + input_device->name = GSLX680_I2C_NAME; + input_device->id.bustype = BUS_I2C; + input_device->dev.parent = &client->dev; + input_set_drvdata(input_device, ts); + +#ifdef REPORT_DATA_ANDROID_4_0 + __set_bit(EV_ABS, input_device->evbit); + __set_bit(EV_KEY, input_device->evbit); + __set_bit(EV_REP, input_device->evbit); + __set_bit(INPUT_PROP_DIRECT, input_device->propbit); + input_mt_init_slots(input_device, (MAX_CONTACTS+1)); +#else + //input_set_abs_params(input_device,ABS_MT_TRACKING_ID, 0, (MAX_CONTACTS+1), 0, 0); + set_bit(EV_ABS, input_device->evbit); + set_bit(EV_KEY, input_device->evbit); + __set_bit(INPUT_PROP_DIRECT, input_device->propbit); +#endif + + input_device->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); +#ifdef HAVE_TOUCH_KEY + //input_device->evbit[0] = BIT_MASK(EV_KEY); + if (wmt_ts_if_tskey()) + { + for (i = 0; i < MAX_KEY_NUM; i++) + set_bit(key_array[i], input_device->keybit); + } +#endif + + set_bit(ABS_MT_POSITION_X, input_device->absbit); + set_bit(ABS_MT_POSITION_Y, input_device->absbit); + //set_bit(ABS_MT_TOUCH_MAJOR, input_device->absbit); + //set_bit(ABS_MT_WIDTH_MAJOR, input_device->absbit); + //****************add 2013-1-10 + set_bit(BTN_TOUCH, input_device->keybit); + set_bit(ABS_MT_TRACKING_ID, input_device->absbit); + + dbg("regsister:x=%d,y=%d\n",wmt_ts_get_resolvX(),wmt_ts_get_resolvY()); + if (wmt_ts_get_lcdexchg()) { + input_set_abs_params(input_device,ABS_MT_POSITION_X, 0, wmt_ts_get_resolvY(), 0, 0); + input_set_abs_params(input_device,ABS_MT_POSITION_Y, 0, wmt_ts_get_resolvX(), 0, 0); + } else { + input_set_abs_params(input_device,ABS_MT_POSITION_X, 0, wmt_ts_get_resolvX(), 0, 0); + input_set_abs_params(input_device,ABS_MT_POSITION_Y, 0, wmt_ts_get_resolvY(), 0, 0); + } + //input_set_abs_params(input_device,ABS_MT_TOUCH_MAJOR, 0, PRESS_MAX, 0, 0); + //input_set_abs_params(input_device,ABS_MT_WIDTH_MAJOR, 0, 200, 0, 0); + + //client->irq = IRQ_PORT, + //ts->irq = client->irq; + + ts->wq = create_singlethread_workqueue("kworkqueue_ts"); + if (!ts->wq) { + dev_err(&client->dev, "Could not create workqueue\n"); + goto error_wq_create; + } + flush_workqueue(ts->wq); + + INIT_WORK(&ts->work, gsl_ts_xy_worker); + + rc = input_register_device(input_device); + if (rc) + goto error_unreg_device; + + + + return 0; + +error_unreg_device: + destroy_workqueue(ts->wq); +error_wq_create: + input_free_device(input_device); +error_alloc_dev: + kfree(ts->touch_data); + return rc; +} + +static int gsl_ts_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct gsl_ts *ts = l_ts; //dev_get_drvdata(dev); + //int rc = 0; + + printk("I'am in gsl_ts_suspend() start\n"); + ts->is_suspended = true; + +#ifdef GSL_TIMER + printk( "gsl_ts_suspend () : delete gsl_timer\n"); + + del_timer(&ts->gsl_timer); +#endif + //disable_irq_nosync(ts->irq); + wmt_disable_gpirq(); + + reset_chip(ts->client); + gslX680_shutdown_low(); + msleep(10); + + return 0; +} + +int resume_download_thread(void *arg) +{ + wake_lock(&downloadWakeLock); + gslX680_chip_init(); + gslX680_shutdown_high(); + msleep(20); + reset_chip(l_ts->client); + startup_chip(l_ts->client); + //check_mem_data(l_ts->client); + init_chip(l_ts->client); + + l_ts->is_suspended = false; + if (!earlysus_en) + wmt_enable_gpirq(); + wake_unlock(&downloadWakeLock); + return 0; +} + +static int gsl_ts_resume(struct platform_device *pdev) +{ + + gpio_direction_output(tp_led_gpio, !tp_led_gpio_active); +#ifdef GSL_TIMER + dbg( "gsl_ts_resume () : add gsl_timer\n"); + + init_timer(&ts->gsl_timer); + ts->gsl_timer.expires = jiffies + 3 * HZ; + ts->gsl_timer.function = &gsl_timer_handle; + ts->gsl_timer.data = (unsigned long)ts; + add_timer(&ts->gsl_timer); +#endif + if (is_delay) { + resume_download_task = kthread_create(resume_download_thread, NULL , "resume_download"); + if(IS_ERR(resume_download_task)) { + errlog("cread thread failed\n"); + } + wake_up_process(resume_download_task); + } else + resume_download_thread(NULL); + + return 0; +} + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void gsl_ts_early_suspend(struct early_suspend *h) +{ + //struct gsl_ts *ts = container_of(h, struct gsl_ts, early_suspend); + dbg("[GSL1680] Enter %s\n", __func__); + //gsl_ts_suspend(&ts->client->dev); + wmt_disable_gpirq(); +} + +static void gsl_ts_late_resume(struct early_suspend *h) +{ + //struct gsl_ts *ts = container_of(h, struct gsl_ts, early_suspend); + dbg("[GSL1680] Enter %s\n", __func__); + //gsl_ts_resume(&ts->client->dev); + wmt_enable_gpirq(); +} +#endif + +static void check_Backlight_delay(void) +{ + int ret; + int len = 7; + char retval[8]; + + ret = wmt_getsyspara("wmt.backlight.delay", retval, &len); + if(ret) { + dbg("Read wmt.backlight.delay Failed.\n"); + is_delay = 0; + } else + is_delay = 1; +} + +static void timeout_func(struct work_struct *work){ + struct gsl_ts *ts = + container_of(work, struct gsl_ts, timeout_work.work); + int button_up = -1; + + mutex_lock(&ts->timeout_mutex); + button_up = --ts->timeout_count; + mutex_unlock(&ts->timeout_mutex); + + if( button_up < 0){ + gpio_set_value(tp_led_gpio,!tp_led_gpio_active); + }else{ + queue_delayed_work(ts->timeout_queue, &ts->timeout_work, msecs_to_jiffies(DELAY_TIMEOUT)); + } + +} + + +static int gsl_ts_probe(struct i2c_client *client) +{ + struct gsl_ts *ts; + int rc; + + dbg("GSLX680 Enter %s\n", __func__); + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, "I2C functionality not supported\n"); + return -ENODEV; + } + if (wmt_get_fwdata()) + { + errlog("Failed to load the firmware data!\n"); + return -1; + } + ts = kzalloc(sizeof(*ts), GFP_KERNEL); + if (!ts) { + rc = -ENOMEM; + goto error_kfree_fw; + } + dbg("==kzalloc success=\n"); + l_ts = ts; + + ts->client = client; + i2c_set_clientdata(client, ts); + ts->device_id = 0;//id->driver_data; + + ts->is_suspended = false; + ts->int_pending = false; + wake_lock_init(&downloadWakeLock, WAKE_LOCK_SUSPEND, "resume_download"); + mutex_init(&ts->sus_lock); + + rc = gsl_ts_init_ts(client, ts); + if (rc < 0) { + dev_err(&client->dev, "GSLX680 init failed\n"); + goto error_mutex_destroy; + } + + gslX680_chip_init(); + init_chip(ts->client); + check_mem_data(ts->client); + + ts->irq = wmt_get_tsirqnum(); + rc= request_irq(wmt_get_tsirqnum(), gsl_ts_irq, IRQF_SHARED, client->name, ts); + if (rc < 0) { + dbg( "gsl_probe: request irq failed\n"); + goto error_req_irq_fail; + } + + if( tp_led_gpio >= 0 ){ + if(gpio_request(tp_led_gpio, "tp_led_gpio") >= 0){ + wmt_gpio_setpull(tp_led_gpio, tp_led_gpio_active ? WMT_GPIO_PULL_UP : WMT_GPIO_PULL_DOWN); + gpio_direction_output(tp_led_gpio, !tp_led_gpio_active); + #if 0 + errlog("sel_reg_bit:%d sel_reg_active:%d\n",sel_reg_bit,sel_reg_active); + if(sel_reg_bit >= 0 && sel_reg_active >= 0){ + if(sel_reg_active == 0){ + REG32_VAL(__GPIO_BASE+PIN_SHARING_SEL_OFFSET) &= ~(1<timeout_mutex); + ts->timeout_count = -1; + ts->timeout_queue= create_singlethread_workqueue("timeout_queue"); + INIT_DELAYED_WORK(&ts->timeout_work,timeout_func); + + } + + + + +#ifdef GSL_TIMER + dbg( "gsl_ts_probe () : add gsl_timer\n"); + + init_timer(&ts->gsl_timer); + ts->gsl_timer.expires = jiffies + 3 * HZ; //¶¨Ê±3 ÃëÖÓ + ts->gsl_timer.function = &gsl_timer_handle; + ts->gsl_timer.data = (unsigned long)ts; + add_timer(&ts->gsl_timer); +#endif + + /* create debug attribute */ + //rc = device_create_file(&ts->input->dev, &dev_attr_debug_enable); + +#ifdef CONFIG_HAS_EARLYSUSPEND + ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + ts->early_suspend.suspend = gsl_ts_early_suspend; + ts->early_suspend.resume = gsl_ts_late_resume; + register_early_suspend(&ts->early_suspend); +#endif + + dbg("[GSLX680] End %s\n", __func__); + wmt_enable_gpirq(); + + check_Backlight_delay(); + return 0; + + + +error_req_irq_fail: + free_irq(ts->irq, ts); + +error_mutex_destroy: + mutex_destroy(&ts->sus_lock); + wake_lock_destroy(&downloadWakeLock); + input_free_device(ts->input); + kfree(ts); +error_kfree_fw: + kfree(GSLX680_FW); + return rc; +} + +static int gsl_ts_remove(struct i2c_client *client) +{ + + + struct gsl_ts *ts = i2c_get_clientdata(client); + dbg("==gsl_ts_remove=\n"); + +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&ts->early_suspend); +#endif + + //device_init_wakeup(&client->dev, 0); + cancel_work_sync(&ts->work); + + if( tp_led_gpio >= 0 ){ + mutex_destroy(&ts->timeout_mutex); + gpio_free(tp_led_gpio); + tp_led_gpio = -1; + tp_led_gpio_active = -1; + } + + free_irq(ts->irq, ts); + destroy_workqueue(ts->wq); + input_unregister_device(ts->input); + mutex_destroy(&ts->sus_lock); + wake_lock_destroy(&downloadWakeLock); + + //device_remove_file(&ts->input->dev, &dev_attr_debug_enable); + + if(GSLX680_FW){ + kfree(GSLX680_FW); + GSLX680_FW = NULL; + } + + kfree(ts->touch_data); + kfree(ts); + + return 0; +} + +/* +static const struct i2c_device_id gsl_ts_id[] = { + {GSLX680_I2C_NAME, 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, gsl_ts_id); + + +static struct i2c_driver gsl_ts_driver = { + .driver = { + .name = GSLX680_I2C_NAME, + .owner = THIS_MODULE, + }, +#ifndef CONFIG_HAS_EARLYSUSPEND + .suspend = gsl_ts_suspend, + .resume = gsl_ts_resume, +#endif + .probe = gsl_ts_probe, + .remove = __devexit_p(gsl_ts_remove), + .id_table = gsl_ts_id, +}; +*/ +static int wmt_wakeup_bl_notify(struct notifier_block *nb, unsigned long event, + void *dummy) +{ + //printk("get notify\n"); + switch (event) { + case BL_CLOSE: + l_ts->is_suspended = true; + //printk("\nclose backlight\n\n"); + //printk("disable irq\n\n"); + wmt_disable_gpirq(); + break; + case BL_OPEN: + l_ts->is_suspended = false; + //printk("\nopen backlight\n\n"); + //printk("enable irq\n\n"); + wmt_enable_gpirq(); + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block wmt_bl_notify = { + .notifier_call = wmt_wakeup_bl_notify, +}; + +static int gsl_ts_init(void) +{ + int ret = 0; + ret = gsl_ts_probe(ts_get_i2c_client()); + if (ret) + { + dbg("Can't load gsl1680 ts driver!\n"); + } + //dbg("ret=%d\n",ret); + if (earlysus_en) + register_bl_notifier(&wmt_bl_notify); + return ret; +} +static void gsl_ts_exit(void) +{ + dbg("==gsl_ts_exit==\n"); + //i2c_del_driver(&gsl_ts_driver); + gsl_ts_remove(ts_get_i2c_client()); + if (earlysus_en) + unregister_bl_notifier(&wmt_bl_notify); + return; +} + +struct wmtts_device gslx680_tsdev = { + .driver_name = WMT_TS_I2C_NAME, + .ts_id = "GSL1680", + .init = gsl_ts_init, + .exit = gsl_ts_exit, + .suspend = gsl_ts_suspend, + .resume = gsl_ts_resume, +}; + + +//module_init(gsl_ts_init); +//module_exit(gsl_ts_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("GSLX680 touchscreen controller driver"); +MODULE_AUTHOR("Guan Yuwei, guanyuwei@basewin.com"); +MODULE_ALIAS("platform:gsl_ts"); diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/gslX680.h b/ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/gslX680.h new file mode 100755 index 00000000..c146127c --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/gslX680.h @@ -0,0 +1,35 @@ +#ifndef _GSLX680_H_ +#define _GSLX680_H_ + + + +#define GSL_NOID_VERSION +#ifdef GSL_NOID_VERSION +struct gsl_touch_info +{ + int x[10]; + int y[10]; + int id[10]; + int finger_num; +}; +extern unsigned int gsl_mask_tiaoping(void); +extern unsigned int gsl_version_id(void); +extern void gsl_alg_id_main(struct gsl_touch_info *cinfo); +extern void gsl_DataInit(int *ret); + +extern int gsl_noid_ver; +extern unsigned int gsl_config_data_id[512]; +#endif + +struct fw_data +{ + //u32 offset : 8; + //u32 : 0; + u32 offset; + u32 val; +}; + +extern void wmt_set_keypos(int index,int xmin,int xmax,int ymin,int ymax); + + +#endif diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/gsl_point_id.b b/ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/gsl_point_id.b new file mode 100755 index 00000000..f25fccd3 Binary files /dev/null and b/ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/gsl_point_id.b differ diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/wmt_ts.c b/ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/wmt_ts.c new file mode 100755 index 00000000..e0ddf9e7 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/wmt_ts.c @@ -0,0 +1,1102 @@ +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "gslX680.h" +#include "wmt_ts.h" + +///////////////////////////////////////////////////////////////// + +// commands for ui +#define TS_IOC_MAGIC 't' + +#define TS_IOCTL_CAL_START _IO(TS_IOC_MAGIC, 1) +#define TS_IOCTL_CAL_DONE _IOW(TS_IOC_MAGIC, 2, int*) +#define TS_IOCTL_GET_RAWDATA _IOR(TS_IOC_MAGIC, 3, int*) +#define TS_IOCTL_CAL_QUIT _IOW(TS_IOC_MAGIC, 4, int*) +#define TS_IOCTL_AUTO_CALIBRATION _IOW(TS_IOC_MAGIC, 5, int*) +#define TS_IOC_MAXNR 5 + +// +#define TS_MAJOR 11 +#define TS_DRIVER_NAME "wmtts_touch" +#define TS_NAME "wmtts" +#define WMTTS_PROC_NAME "wmtts_config" + +#define EXT_GPIO0 0 +#define EXT_GPIO1 1 +#define EXT_GPIO2 2 +#define EXT_GPIO3 3 +#define EXT_GPIO4 4 +#define EXT_GPIO5 5 +#define EXT_GPIO6 6 +#define EXT_GPIO7 7 + +typedef struct { + int a1; + int b1; + int c1; + int a2; + int b2; + int c2; + int delta; +}CALIBRATION_PARAMETER, *PCALIBRATION_PARAMETER; + + +static int irq_gpio; +static int rst_gpio; +static int panelres_x; +static int panelres_y; +static int lcd_exchg = 0; +static DECLARE_WAIT_QUEUE_HEAD(queue); +static CALIBRATION_PARAMETER g_CalcParam; +static TS_EVENT g_evLast; +static struct mutex cal_mutex; +static DECLARE_WAIT_QUEUE_HEAD(ts_penup_wait_queue); + +static struct class* l_dev_class = NULL; +static struct device *l_clsdevice = NULL; +extern struct wmtts_device gslx680_tsdev; +static struct wmtts_device* l_tsdev = &gslx680_tsdev; +struct proc_dir_entry* l_tsproc = NULL; +static struct i2c_client *l_client=NULL; +static int l_penup = 0; // 1-pen up,0-pen down +static int l_iftskey = -1; // 1:have ts key +int earlysus_en = 0; + +int tp_led_gpio; +int tp_led_gpio_active; + +int sel_reg_bit; +int sel_reg_active; + + +struct tp_infor +{ + //enum tp_type type; + char name[64]; + int i2caddr; + int xaxis; //0: x,1: x swap with y + int xdir; // 1: positive,-1: revert + int ydir; // 1: positive,-1: revert + int finger_num; +}; + +static int l_tpindex = -1; +static struct tp_infor l_tpinfor[1]; + + +///////////////////////////////////////////////////// +// function declare +///////////////////////////////////////////////////// +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); +extern int wmt_setsyspara(char *varname, unsigned char *varval); +static int ts_writeproc( struct file *file, + const char *buffer, + unsigned long count, + void *data ); +static int ts_readproc(char *page, char **start, off_t off, + int count, int *eof, void *data); +/////////////////////////////////////////////////////////////////////// +void TouchPanelCalibrateAPoint( + int UncalX, //@PARM The uncalibrated X coordinate + int UncalY, //@PARM The uncalibrated Y coordinate + int *pCalX, //@PARM The calibrated X coordinate + int *pCalY //@PARM The calibrated Y coordinate + ) +{ + int x, y; + mutex_lock(&cal_mutex); + x = (g_CalcParam.a1 * UncalX + g_CalcParam.b1 * UncalY + + g_CalcParam.c1) / g_CalcParam.delta; + y = (g_CalcParam.a2 * UncalX + g_CalcParam.b2 * UncalY + + g_CalcParam.c2) / g_CalcParam.delta; + +//klog("afer(%d,%d)(%d,%d)\n", x,y,panelres_x,panelres_y); + if ( x < 0 ) + x = 0; + + if ( y < 0 ) + y = 0; + if (x >= panelres_x) + x = panelres_x-1; + if (y >= panelres_y) + y = panelres_y-1; + + *pCalX = x; + *pCalY = y; + mutex_unlock(&cal_mutex); + return; +} + +int wmt_ts_if_tskey(void) +{ + return ((l_iftskey==1) ? 1: 0); +} + +int wmt_ts_get_firmwfilename(char* fname) +{ + sprintf(fname,"%s_fw.tpf",l_tpinfor[l_tpindex].name); + return 0; +} + + +static struct device* get_tp_device(void){ + if(l_client == NULL){ + errlog("l_client is NULL\n"); + } + return &l_client->dev; +} + + +unsigned int wmt_ts_get_xaxis(void) +{ + return l_tpinfor[l_tpindex].xaxis; +} + +unsigned int wmt_ts_get_xdir(void) +{ + return l_tpinfor[l_tpindex].xdir; +} + +unsigned int wmt_ts_get_ydir(void) +{ + return l_tpinfor[l_tpindex].ydir; +} + +static int parse_firmwarefile(const char* filedata, struct fw_data** firmarr, unsigned int* id_config) +{ + char endflag[]="/* End flag */"; + const char *p = filedata; + u32 val[2]; + int i = 0; + int j = 0; + int k = 0; + const char *s = NULL; + int hex = 0; + +#ifdef GSL_NOID_VERSION + if (gsl_noid_ver) { + while (*p != '{') p++; + p++; + s = p; + while (*s != '}') { + if (*s == '0' && *(s+1) == 'x') { + hex = 1; + break; + } + s++; + } + while (*p != '}') { + sscanf(p,hex ? "%x" : "%u,",&(id_config[k++])); + p = strchr(p,',');p++; + } + } +#endif + + // the first { + while (*p!='{') p++; + p++; + s = p; + // calculate the number of array + while (strncmp(p,endflag,strlen(endflag))) + { + if (*p=='{') + { + i++; + } + p++; + }; + dbg("the number of arry:0x%x\n", i); + // alloc the memory for array + *firmarr = kzalloc(sizeof(struct fw_data)*i, GFP_KERNEL); + // parse the value of array + p = s; + j = 0; + while (strncmp(p,endflag,strlen(endflag))) + { + if (*p=='{') + { + memset(val,0,sizeof(val)); + sscanf(p,"{%x,%x}",val,val+1); + (*firmarr)[j].offset = val[0]&0x00FF; + (*firmarr)[j].val= val[1]; + //dbg("data%x{%x,%x}\n",j,(*firmarr)[j].offset,(*firmarr)[j].val); + j++; + } + //p = strchr(p,'}'); + p++; + if (j>=i-2) + { + dbg("%s",p); + } + + }; + if (i != j) + { + errlog("Error parsing file(the number of arry not match)!\n"); + errlog("i=0x%x,j=0x%x\n", i,j); + kfree(*firmarr); + return -1; + }; + dbg("paring firmware file end.\n"); + return i; +} + + + +//filepath:the path of firmware file; +//firmdata:store the data from firmware file; +//id_config:config data for some ICs whitch have no id; +//return:the lengthen of firmware data,negative-parsing error. +int read_firmwfile(char* filepath, struct fw_data** firmdata, unsigned int* id_config) +{ + const u8 *data = NULL; + int i = 0; + int ret = -1; + const struct firmware* tpfirmware = NULL; + + klog("ts firmware file:%s\n",filepath); + ret = request_firmware(&tpfirmware, filepath, get_tp_device()); + if (ret < 0) { + errlog("Failed load tp firmware: %s ret=%d\n", filepath,ret); + goto err_end; + } + data = tpfirmware->data; + + i = parse_firmwarefile(data,firmdata,id_config); + + if (i <= 0){ + dbg("Failed to pare firmware file!\n"); + ret = -1; + goto error_parse_fw; + } + dbg("firmware arry len=0x%x\n", i); + ret = i; + dbg("success to read firmware file!\n");; +error_parse_fw: + if(tpfirmware){ + release_firmware(tpfirmware); + tpfirmware = NULL; + } +err_end: + return ret; +} + + + + int wmt_ts_get_gpionum(void) +{ + return irq_gpio; +} + +int wmt_ts_get_resetgpnum(void) +{ + return rst_gpio; +} + +int wmt_ts_get_lcdexchg(void) +{ + return lcd_exchg; +} + +int wmt_ts_get_resolvX(void) +{ + return panelres_x; +} + +int wmt_ts_get_resolvY(void) +{ + return panelres_y; +} + +//up:1-pen up,0-pen down +void wmt_ts_set_penup(int up) +{ + l_penup = up; +} + +// +int wmt_ts_wait_penup(void) +{ + int ret = wait_event_interruptible( + ts_penup_wait_queue, + (1==l_penup)); + return ret; +} + +// return:1-pen up,0-pen dwon +int wmt_ts_ispenup(void) +{ + return l_penup; +} + + +void wmt_ts_wakeup_penup(void) +{ + wake_up(&ts_penup_wait_queue); +} + +int wmt_is_tsirq_enable(void) +{ + int val = 0; + int num = irq_gpio; + + if(num > 11) + return 0; + + if(num<4) + val = REG32_VAL(__GPIO_BASE+0x0300) & (1<<(num*8+7)); + else if(num >= 4 && num < 8) + val = REG32_VAL(__GPIO_BASE+0x0304) & (1<<((num-4)*8+7)); + else + val = REG32_VAL(__GPIO_BASE+0x0308) & (1<<((num-8)*8+7)); + + return val?1:0; + +} + +int wmt_is_tsint(void) +{ + int num = irq_gpio; + + if (num > 11) + { + return 0; + } + return (REG32_VAL(__GPIO_BASE+0x0360) & (1< 11) + { + return; + } + REG32_VAL(__GPIO_BASE+0x0360) = 1<11) + return -1; + //if (num > 9) + //GPIO_PIN_SHARING_SEL_4BYTE_VAL &= ~BIT4; // gpio10,11 as gpio + REG32_VAL(__GPIO_BASE+0x0040) &= ~(1<= 4 && num < 8){//[4,7] + shift = num-4; + offset = 0x0304; + }else{// [8,11] + shift = num-8; + offset = 0x0308; + } + + reg = REG32_VAL(__GPIO_BASE + offset); + + switch(type){ + case IRQ_TYPE_LEVEL_LOW: + reg &= ~(1<<(shift*8+2)); + reg &= ~(1<<(shift*8+1)); + reg &= ~(1<<(shift*8)); + break; + case IRQ_TYPE_LEVEL_HIGH: + reg &= ~(1<<(shift*8+2)); + reg &= ~(1<<(shift*8+1)); + reg |= (1<<(shift*8)); + break; + case IRQ_TYPE_EDGE_FALLING: + reg &= ~(1<<(shift*8+2)); + reg |= (1<<(shift*8+1)); + reg &= ~(1<<(shift*8)); + break; + case IRQ_TYPE_EDGE_RISING: + reg &= ~(1<<(shift*8+2)); + reg |= (1<<(shift*8+1)); + reg |= (1<<(shift*8)); + break; + default://both edge + reg |= (1<<(shift*8+2)); + reg &= ~(1<<(shift*8+1)); + reg &= ~(1<<(shift*8)); + break; + + } + //reg |= 1<<(shift*8+7);//enable interrupt + reg &= ~(1<<(shift*8+7)); //disable int + + REG32_VAL(__GPIO_BASE + offset) = reg; + REG32_VAL(__GPIO_BASE+0x0360) = 1< 11) + return -1; + + if(num<4) + REG32_VAL(__GPIO_BASE+0x0300) |= 1<<(num*8+7); //enable interrupt + else if(num >= 4 && num < 8) + REG32_VAL(__GPIO_BASE+0x0304) |= 1<<((num-4)*8+7); //enable interrupt + else + REG32_VAL(__GPIO_BASE+0x0308) |= 1<<((num-8)*8+7); //enable interrupt + + return 0; +} + +int wmt_disable_gpirq(void) +{ + int num = irq_gpio; + + if(num > 11) + return -1; + + if(num<4) + REG32_VAL(__GPIO_BASE+0x0300) &= ~(1<<(num*8+7)); //enable interrupt + else if(num >= 4 && num < 8) + REG32_VAL(__GPIO_BASE+0x0304) &= ~(1<<((num-4)*8+7)); //enable interrupt + else + REG32_VAL(__GPIO_BASE+0x0308) &= ~(1<<((num-8)*8+7)); //enable interrupt + + return 0; +} + + +int wmt_get_tsirqnum(void) +{ + return IRQ_GPIO; +} + + +int wmt_ts_set_rawcoord(unsigned short x, unsigned short y) +{ + g_evLast.x = x; + g_evLast.y = y; + //dbg("raw(%d,%d)*\n", x, y); + return 0; +} + +static void wmt_ts_platform_release(struct device *device) +{ + return; +} + +static struct platform_device wmt_ts_plt_device = { + .name = TS_DRIVER_NAME, + .id = 0, + .dev = { + .release = wmt_ts_platform_release, + }, +// .num_resources = ARRAY_SIZE(wm9715_ts_resources), +// .resource = wm9715_ts_resources, +}; + +static int wmt_ts_suspend(struct platform_device *pdev, pm_message_t state) +{ + dbg("ts suspend....\n"); + if (l_tsdev->suspend != NULL) + { + return l_tsdev->suspend(pdev, state); + } + return 0; +} +static int wmt_ts_resume(struct platform_device *pdev) +{ + dbg("ts resume....\n"); + if (l_tsdev->resume != NULL) + { + return l_tsdev->resume(pdev); + } + klog("...\n"); + return 0; +} + +static int wmt_ts_probe(struct platform_device *pdev) +{ + l_tsproc= create_proc_entry(WMTTS_PROC_NAME, 0666, NULL/*&proc_root*/); + if (l_tsproc != NULL) + { + l_tsproc->read_proc = ts_readproc; + l_tsproc->write_proc = ts_writeproc; + } + + if (l_tsdev->probe != NULL) + return l_tsdev->probe(pdev); + else + return 0; +} + +static int wmt_ts_remove(struct platform_device *pdev) +{ + if (l_tsproc != NULL) + { + remove_proc_entry(WMTTS_PROC_NAME, NULL); + l_tsproc = NULL; + } + + if (l_tsdev->remove != NULL) + return l_tsdev->remove(pdev); + else + return 0; +} + +static struct platform_driver wmt_ts_plt_driver = { + .driver = { + .name = TS_DRIVER_NAME, + .owner = THIS_MODULE, + }, + .probe = wmt_ts_probe, + .remove = wmt_ts_remove, + .suspend = wmt_ts_suspend, + .resume = wmt_ts_resume, +}; + +static int wmt_ts_open(struct inode *inode, struct file *filp) +{ + int ret = 0; + + klog("wmt ts driver opening...\n"); + + //ts_clear(); + //try_module_get(THIS_MODULE); + + return ret; +} + +static int wmt_ts_close(struct inode *inode, struct file *filp) +{ + klog("wmt ts driver closing...\n"); + //ts_clear(); + //module_put(THIS_MODULE); + + return 0; +} + +static unsigned int wmt_ts_poll(struct file *filp, struct poll_table_struct *wait) +{ +#if 0 + poll_wait(filp, &queue, wait); + if ( head != tail ) + return (POLLIN | POLLRDNORM); +#endif + return 0; +} + +static long wmt_ts_ioctl(/*struct inode * node,*/ struct file *dev, unsigned int cmd, unsigned long arg) +{ + int nBuff[7]; + char env_val[96]={0}; + //dbg("wmt_ts_ioctl(node=0x%p, dev=0x%p, cmd=0x%08x, arg=0x%08lx)\n", node, dev, cmd, arg); + + if (_IOC_TYPE(cmd) != TS_IOC_MAGIC){ + dbg("CMD ERROR!"); + return -ENOTTY; + } + + if (_IOC_NR(cmd) > TS_IOC_MAXNR){ + dbg("NO SUCH IO CMD!\n"); + return -ENOTTY; + } + + switch (cmd) { + + case TS_IOCTL_CAL_DONE: + klog("wmt_ts_ioctl: TS_IOCTL_CAL_DONE\n"); + copy_from_user(nBuff, (unsigned int*)arg, 7*sizeof(int)); + + mutex_lock(&cal_mutex); + g_CalcParam.a1 = nBuff[0]; + g_CalcParam.b1 = nBuff[1]; + g_CalcParam.c1 = nBuff[2]; + g_CalcParam.a2 = nBuff[3]; + g_CalcParam.b2 = nBuff[4]; + g_CalcParam.c2 = nBuff[5]; + g_CalcParam.delta = nBuff[6]; + + if(g_CalcParam.delta == 0) + g_CalcParam.delta =1;//avoid divide by zero + + mutex_unlock(&cal_mutex); + + sprintf(env_val,"%d %d %d %d %d %d %d",nBuff[0],nBuff[1],nBuff[2],nBuff[3],nBuff[4],nBuff[5],nBuff[6]); + wmt_setsyspara("wmt.io.ts.2dcal", env_val); + klog("Tsc calibrate done data: [%s]\n",env_val); + + return 0; + + + case TS_IOCTL_GET_RAWDATA: + // wait for point up + dbg("test wait_penup\n"); + //l_tsdev->wait_penup(>811_tsdev); + klog("wmt_ts_ioctl: TS_IOCTL_GET_RAWDATA\n"); + wmt_ts_wait_penup(); + + nBuff[0] = g_evLast.x; + nBuff[1] = g_evLast.y; + copy_to_user((unsigned int*)arg, nBuff, 2*sizeof(int)); + klog("raw data: x=%d, y=%d\n", nBuff[0], nBuff[1]); + + return 0; + } + + return -EINVAL; +} + +static ssize_t wmt_ts_read(struct file *filp, char *buf, size_t count, loff_t *l) +{ + // read firmware file + + return 0; +} + + +static struct file_operations wmt_ts_fops = { + .read = wmt_ts_read, + .poll = wmt_ts_poll, + .unlocked_ioctl = wmt_ts_ioctl, + .open = wmt_ts_open, + .release = wmt_ts_close, +}; + +static int ts_writeproc( struct file *file, + const char *buffer, + unsigned long count, + void *data ) +{ + int calibrate = 0; + int val = 0; + + if (sscanf(buffer, "calibrate=%d\n", &calibrate)) + { + if (1 == calibrate) + { + if((l_tsdev->capacitance_calibrate != NULL) && + (0 == l_tsdev->capacitance_calibrate())) + { + printk(KERN_ALERT "%s calibration successfully!\n", l_tsdev->ts_id); + } else { + printk(KERN_ALERT "%s calibration failed!\n", l_tsdev->ts_id); + } + } + } else if (sscanf(buffer, "reset=%d\n", &val)) + { + + } + return count; +} + +static int ts_readproc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = 0; + + len = sprintf(page, + "echo calibrate=1 > /proc/wmtts_config to calibrate ts.\n"); + return len; +} + +static int wmt_check_touch_env(void) +{ + int ret = 0; + int len = 127, i = 0; + char retval[128] = {0},*p=NULL,*s=NULL; + int Enable=0; + int keypos[4][4]; + + // Get u-boot parameter + ret = wmt_getsyspara("wmt.io.touch", retval, &len); + if(ret){ + errlog("Read wmt.io.touch Failed.\n"); + return -EIO; + } + memset(l_tpinfor,0,sizeof(l_tpinfor[0])); + p = retval; + sscanf(p,"%d:", &Enable); + p = strchr(p,':');p++; + s = strchr(p,':'); + strncpy(l_tpinfor[0].name,p, (s-p)); + p = s+1; + dbg("ts_name=%s\n", l_tpinfor[0].name); + + ret = sscanf(p,"%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", + &irq_gpio,&panelres_x,&panelres_y,&rst_gpio, + &(l_tpinfor[0].xaxis),&(l_tpinfor[0].xdir),&(l_tpinfor[0].ydir), + &(l_tpinfor[0].finger_num), + &(l_tpinfor[0].i2caddr),&gsl_noid_ver); + if (ret < 9) + { + dbg("Wrong format ts u-boot param(%d)!\n",ret); + return -ENODEV; + } + //check touch enable + if(Enable == 0){ + errlog("Touch Screen Is Disabled.\n"); + return -ENODEV; + } + + /*if (strstr(l_tpinfor[0].name, l_tsdev->ts_id) == NULL) + { + dbg("Can't find %s!\n", l_tsdev->ts_id); + return -ENODEV; + }*/ + l_tpindex = 0; + + klog("p.x = %d, p.y = %d, gpio=%d, resetgpio=%d,xaxis=%d,xdir=%d,ydri=%d,i2caddr=%d,gsl_noid_ver=%d\n", + panelres_x, panelres_y, irq_gpio, rst_gpio, + l_tpinfor[0].xaxis,l_tpinfor[0].xdir,l_tpinfor[0].ydir, + l_tpinfor[0].i2caddr, gsl_noid_ver); + + + memset(retval,0,sizeof(retval)); + ret = wmt_getsyspara("wmt.io.tskey", retval, &len); + if(ret) + { + l_iftskey = 0; + } else { + // get touch key + p = retval; + sscanf(p,"%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", \ + keypos[0],keypos[0]+1,keypos[0]+2,keypos[0]+3, \ + keypos[1],keypos[1]+1,keypos[1]+2,keypos[1]+3, \ + keypos[2],keypos[2]+1,keypos[2]+2,keypos[2]+3, \ + keypos[3],keypos[3]+1,keypos[3]+2,keypos[3]+3); + for (i = 0; i < 4; i++) + { + wmt_set_keypos(i,keypos[i][0],keypos[i][1],keypos[i][2],keypos[i][3]); + dbg("%d:%d,%d,%d,%d\n",i,keypos[i][0],keypos[i][1],keypos[i][2],keypos[i][3]); + }; + l_iftskey = 1; + } + + memset(retval,0,sizeof(retval)); + ret = wmt_getsyspara("wmt.touch.earlysus", retval, &len); + if(!ret) { + p = retval; + sscanf(p, "%d", &earlysus_en); + } + + ret = wmt_getsyspara("wmt.display.fb0", retval, &len); + if (!ret) { + int tmp[6]; + p = retval; + sscanf(p, "%d:[%d:%d:%d:%d:%d", &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5]); + if (tmp[4] > tmp[5]) + lcd_exchg = 1; + } + + //wmt.tpkey.led 141:1 + tp_led_gpio = -1; + tp_led_gpio_active = -1; + sel_reg_bit = -1; + sel_reg_active = -1; + ret = wmt_getsyspara("wmt.tpkey.led", retval, &len); + + errlog("wmt.tpkey.led: %s \n",retval); + + if (!ret) { + int tmp[4] = {0}; + p = retval; + ret = sscanf(p, "%d:%d:%d:%d", &tmp[0], &tmp[1], &tmp[2], &tmp[3]); + if(ret == 2){ + tp_led_gpio = tmp[0]; + tp_led_gpio_active = tmp[1]; + } + if(ret == 4){ + tp_led_gpio = tmp[0]; + tp_led_gpio_active = tmp[1]; + sel_reg_bit = tmp[2]; + sel_reg_active = tmp[3]; + } + errlog("tp_led_gpio:%d tp_led_gpio_active:%d sel_reg_bit:%d sel_reg_active:%d \n" + ,tp_led_gpio,tp_led_gpio_active,sel_reg_bit,sel_reg_active); + } + +/* + memset(retval,0,sizeof(retval)); + ret = wmt_getsyspara("wmt.io.ts.2dcal", retval, &len); + if(ret){ + errlog("Read env wmt.io.ts.2dcal Failed.\n "); + //return -EIO; + } + i = 0; + while(i < sizeof(retval)){ + if(retval[i]==' ' || retval[i]==',' || retval[i]==':') + retval[i] = '\0'; + i++; + } + + i = 0; + p = retval; + while(i<7 && p < (retval + sizeof(retval))){ + if(*p == '\0') + p++; + else{ + sscanf(p,"%d",&nBuff[i]); + //printk("%d\n",nBuff[i]); + p=p+strlen(p); + i++; + } + } + //sscanf(retval,"%d %d %d %d %d %d %d %d",&nBuff[0],&nBuff[1],&nBuff[2],&nBuff[3],&nBuff[4],&nBuff[5],&nBuff[6]); + printk("Tsc calibrate init data: [%d %d %d %d %d %d %d]\n",nBuff[0],nBuff[1],nBuff[2],nBuff[3],nBuff[4],nBuff[5],nBuff[6]); + + g_CalcParam.a1 = nBuff[0]; + g_CalcParam.b1 = nBuff[1]; + g_CalcParam.c1 = nBuff[2]; + g_CalcParam.a2 = nBuff[3]; + g_CalcParam.b2 = nBuff[4]; + g_CalcParam.c2 = nBuff[5]; + g_CalcParam.delta = nBuff[6]; + + if(g_CalcParam.delta == 0) + g_CalcParam.delta =1;//avoid divide by zero +*/ + return 0; +} + +struct i2c_board_info ts_i2c_board_info = { + .type = WMT_TS_I2C_NAME, + .flags = 0x00, + //.addr = WMT_TS_I2C_ADDR, + .platform_data = NULL, + .archdata = NULL, + .irq = -1, +}; + +static int ts_i2c_register_device (void) +{ + struct i2c_board_info *ts_i2c_bi; + struct i2c_adapter *adapter = NULL; + //struct i2c_client *client = NULL; + + ts_i2c_board_info.addr = l_tpinfor[0].i2caddr; + ts_i2c_bi = &ts_i2c_board_info; + adapter = i2c_get_adapter(1);/*in bus 1*/ + + if (NULL == adapter) { + printk("can not get i2c adapter, client address error\n"); + return -1; + } + l_client = i2c_new_device(adapter, ts_i2c_bi); + if (l_client == NULL) { + printk("allocate i2c client failed\n"); + return -1; + } + i2c_put_adapter(adapter); + return 0; +} + +static void ts_i2c_unregister_device(void) +{ + if (l_client != NULL) + { + i2c_unregister_device(l_client); + l_client = NULL; + } +} + +struct i2c_client* ts_get_i2c_client(void) +{ + return l_client; +} + +static int __init wmt_ts_init(void) +{ + int ret = 0; + + if(wmt_check_touch_env()) + return -ENODEV; + + if (ts_i2c_register_device()<0) + { + dbg("Error to run ts_i2c_register_device()!\n"); + return -1; + } + mutex_init(&cal_mutex); + + if (l_tsdev->init() < 0){ + dbg("Errors to init %s ts IC!!!\n", l_tsdev->ts_id); + ret = -1; + goto err_init; + } + // Create device node + if (register_chrdev (TS_MAJOR, TS_NAME, &wmt_ts_fops)) { + printk (KERN_ERR "wmt touch: unable to get major %d\n", TS_MAJOR); + return -EIO; + } + + l_dev_class = class_create(THIS_MODULE, TS_NAME); + if (IS_ERR(l_dev_class)){ + ret = PTR_ERR(l_dev_class); + printk(KERN_ERR "Can't class_create touch device !!\n"); + return ret; + } + l_clsdevice = device_create(l_dev_class, NULL, MKDEV(TS_MAJOR, 0), NULL, TS_NAME); + if (IS_ERR(l_clsdevice)){ + ret = PTR_ERR(l_clsdevice); + printk(KERN_ERR "Failed to create device %s !!!",TS_NAME); + return ret; + } + + // register device and driver of platform + ret = platform_device_register(&wmt_ts_plt_device); + if(ret){ + errlog("wmt ts plat device register failed!\n"); + return ret; + } + ret = platform_driver_register(&wmt_ts_plt_driver); + if(ret){ + errlog("can not register platform_driver_register\n"); + platform_device_unregister(&wmt_ts_plt_device); + return ret; + } + + klog("%s driver init ok!\n",l_tsdev->ts_id); + return 0; +err_init: + ts_i2c_unregister_device(); + return ret; +} + +static void __exit wmt_ts_exit(void) +{ + dbg("%s\n",__FUNCTION__); + + l_tsdev->exit(); + platform_driver_unregister(&wmt_ts_plt_driver); + platform_device_unregister(&wmt_ts_plt_device); + device_destroy(l_dev_class, MKDEV(TS_MAJOR, 0)); + unregister_chrdev(TS_MAJOR, TS_NAME); + class_destroy(l_dev_class); + mutex_destroy(&cal_mutex); + ts_i2c_unregister_device(); +} + + +module_init(wmt_ts_init); +module_exit(wmt_ts_exit); + +MODULE_LICENSE("GPL"); + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/wmt_ts.h b/ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/wmt_ts.h new file mode 100755 index 00000000..ea764fd4 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/wmt_ts.h @@ -0,0 +1,117 @@ + +#ifndef WMT_TSH_201010191758 +#define WMT_TSH_201010191758 + +#include +#include +#include +#include +#include +#include +#include + + +//#define DEBUG_WMT_TS // kinseyli +#ifdef DEBUG_WMT_TS +#undef dbg +#define dbg(fmt, args...) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__ , ## args) + +//#define dbg(fmt, args...) if (kpadall_isrundbg()) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__, ## args) + +#else +#define dbg(fmt, args...) +#endif + +#undef errlog +#undef klog +#define errlog(fmt, args...) printk("[%s]: " fmt, __FUNCTION__, ## args) +#define klog(fmt, args...) printk("[%s]: " fmt, __FUNCTION__, ## args) + +#define WMT_TS_I2C_NAME "gsl1680-ts" +//#define WMT_TS_I2C_ADDR 0x15 + +#define PIN_SHARING_SEL_OFFSET 0x200 + + +#define FW_BINARYFILE_SIZE 0x8000 + +extern int earlysus_en; + +//////////////////////////////data type/////////////////////////// +typedef struct { + short pressure; + short x; + short y; + //short millisecs; +} TS_EVENT; + +struct wmtts_device +{ + //data + char* driver_name; + char* ts_id; + //function + int (*init)(void); + int (*probe)(struct platform_device *platdev); + int (*remove)(struct platform_device *pdev); + void (*exit)(void); + int (*suspend)(struct platform_device *pdev, pm_message_t state); + int (*resume)(struct platform_device *pdev); + int (*capacitance_calibrate)(void); + int (*wait_penup)(struct wmtts_device*tsdev); // waiting untill penup + int penup; // 0--pendown;1--penup + +}; + + +//////////////////////////function interface///////////////////////// +extern int wmt_ts_get_gpionum(void); +extern int wmt_ts_iscalibrating(void); +extern int wmt_ts_get_resolvX(void); +extern int wmt_ts_get_resolvY(void); +extern int wmt_ts_set_rawcoord(unsigned short x, unsigned short y); +extern int wmt_set_gpirq(int type); +extern int wmt_get_tsirqnum(void); +extern int wmt_disable_gpirq(void); +extern int wmt_enable_gpirq(void); +extern int wmt_is_tsirq_enable(void); +extern int wmt_is_tsint(void); +extern void wmt_clr_int(void); +extern void wmt_tsreset_init(void); +extern int wmt_ts_get_resetgpnum(void); +extern int wmt_ts_get_lcdexchg(void); +extern void wmt_enable_rst_pull(int enable); +extern void wmt_set_rst_pull(int up); +extern void wmt_rst_output(int high); +extern void wmt_rst_input(void); +extern void wmt_set_intasgp(void); +extern void wmt_intgp_out(int val); +extern void wmt_ts_set_irqinput(void); +extern unsigned int wmt_ts_irqinval(void); +extern void wmt_ts_set_penup(int up); +extern int wmt_ts_wait_penup(void); +extern void wmt_ts_wakeup_penup(void); +extern struct i2c_client* ts_get_i2c_client(void); +extern int wmt_ts_ispenup(void); +extern unsigned int wmt_ts_get_xaxis(void); +extern unsigned int wmt_ts_get_xdir(void); +extern unsigned int wmt_ts_get_ydir(void); +extern int wmt_ts_if_tskey(void); + +extern void TouchPanelCalibrateAPoint( + int UncalX, //@PARM The uncalibrated X coordinate + int UncalY, //@PARM The uncalibrated Y coordinate + int *pCalX, //@PARM The calibrated X coordinate + int *pCalY //@PARM The calibrated Y coordinate + ); + +//filepath:the path of firmware file; +//firmdata:store the data from firmware file; +//return:the lengthen of firmware data,negative-parsing error. +extern int read_firmwfile(char* filepath, struct fw_data** firmdata, unsigned int* id_config); +extern int wmt_ts_get_firmwfilename(char* fname); + +#endif + + + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/Kconfig b/ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/Kconfig new file mode 100755 index 00000000..d5d6a394 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/Kconfig @@ -0,0 +1,11 @@ +config TOUCHSCREEN_GT9XX + tristate "GT9XX Capacity Touchscreen Device Support" + default y + depends on ARCH_WMT + ---help--- + Say Y here if you have an WMT based board with touchscreen + attached to it. + If unsure, say N. + To compile this driver as a module, choose M here: the + module will be called gt9xx. + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/Makefile b/ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/Makefile new file mode 100755 index 00000000..642b1271 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/Makefile @@ -0,0 +1,34 @@ +KERNELDIR=../../../../ +CROSS = arm_1103_le- +CC= $(CROSS)gcc +LD= $(CROSS)ld +STRIP = $(CROSS)strip + +DEBUG = n + +# Add your debugging flag (or not) to EXTRA_CFLAGS +ifeq ($(DEBUG),y) +# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines +DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines + +else + DEBFLAGS = -O2 -Wall +endif + +EXTRA_CFLAGS += $(DEBFLAGS) + + +MY_MODULE_NAME=s_wmt_ts_gt9xx + +#obj-$(CONFIG_TOUCHSCREEN_FT5X0X) := $(MY_MODULE_NAME).o +obj-m := $(MY_MODULE_NAME).o +$(MY_MODULE_NAME)-objs := gt9xx.o gt9xx_update.o goodix_tool.o + +default: + $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules + $(STRIP) --strip-debug $(MY_MODULE_NAME).ko + @rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions *.order *.symvers + +clean: + @rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/goodix_tool.c b/ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/goodix_tool.c new file mode 100755 index 00000000..3dfe4e1d --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/goodix_tool.c @@ -0,0 +1,615 @@ +/* drivers/input/touchscreen/goodix_tool.c + * + * 2010 - 2012 Goodix Technology. + * + * 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 a reference + * to you, when you are integrating the GOODiX's CTP IC into your system, + * 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. + * + * Version:1.6 + * V1.0:2012/05/01,create file. + * V1.2:2012/06/08,modify some warning. + * V1.4:2012/08/28,modified to support GT9XX + * V1.6:new proc name + */ + +#include "gt9xx.h" + +#define DATA_LENGTH_UINT 512 +#define CMD_HEAD_LENGTH (sizeof(st_cmd_head) - sizeof(u8*)) +static char procname[20] = {0}; + +#define UPDATE_FUNCTIONS + +#ifdef UPDATE_FUNCTIONS +extern s32 gup_enter_update_mode(struct i2c_client *client); +extern void gup_leave_update_mode(void); +extern s32 gup_update_proc(void *dir); +#endif + +extern void gtp_irq_disable(struct goodix_ts_data *); +extern void gtp_irq_enable(struct goodix_ts_data *); + +#pragma pack(1) +typedef struct{ + u8 wr; //write read flag£¬0:R 1:W 2:PID 3: + u8 flag; //0:no need flag/int 1: need flag 2:need int + u8 flag_addr[2]; //flag address + u8 flag_val; //flag val + u8 flag_relation; //flag_val:flag 0:not equal 1:equal 2:> 3:< + u16 circle; //polling cycle + u8 times; //plling times + u8 retry; //I2C retry times + u16 delay; //delay befor read or after write + u16 data_len; //data length + u8 addr_len; //address length + u8 addr[2]; //address + u8 res[3]; //reserved + u8* data; //data pointer +}st_cmd_head; +#pragma pack() +st_cmd_head cmd_head; + +static struct i2c_client *gt_client = NULL; + +static struct proc_dir_entry *goodix_proc_entry; + +static s32 goodix_tool_write(struct file *filp, const char __user *buff, unsigned long len, void *data); +static s32 goodix_tool_read( char *page, char **start, off_t off, int count, int *eof, void *data ); +static s32 (*tool_i2c_read)(u8 *, u16); +static s32 (*tool_i2c_write)(u8 *, u16); + +#if GTP_ESD_PROTECT +extern void gtp_esd_switch(struct i2c_client *, s32); +#endif +s32 DATA_LENGTH = 0; +s8 IC_TYPE[16] = {0}; + +static void tool_set_proc_name(char * procname) +{ + char *months[12] = {"Jan", "Feb", "Mar", "Apr", "May", + "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + char date[20] = {0}; + char month[4] = {0}; + int i = 0, n_month = 1, n_day = 0, n_year = 0; + + sprintf(date, "%s", __DATE__); + + //GTP_DEBUG("compile date: %s", date); + + sscanf(date, "%s %d %d", month, &n_day, &n_year); + + for (i = 0; i < 12; ++i) + { + if (!memcmp(months[i], month, 3)) + { + n_month = i+1; + break; + } + } + + sprintf(procname, "gmnode%04d%02d%02d", n_year, n_month, n_day); + + //GTP_DEBUG("procname = %s", procname); +} + + +static s32 tool_i2c_read_no_extra(u8* buf, u16 len) +{ + s32 ret = -1; + s32 i = 0; + struct i2c_msg msgs[2]; + + msgs[0].flags = !I2C_M_RD; + msgs[0].addr = gt_client->addr; + msgs[0].len = cmd_head.addr_len; + msgs[0].buf = &buf[0]; + + msgs[1].flags = I2C_M_RD; + msgs[1].addr = gt_client->addr; + msgs[1].len = len; + msgs[1].buf = &buf[GTP_ADDR_LENGTH]; + + for (i = 0; i < cmd_head.retry; i++) + { + ret=i2c_transfer(gt_client->adapter, msgs, 2); + if (ret > 0) + { + break; + } + } + return ret; +} + +static s32 tool_i2c_write_no_extra(u8* buf, u16 len) +{ + s32 ret = -1; + s32 i = 0; + struct i2c_msg msg; + + msg.flags = !I2C_M_RD; + msg.addr = gt_client->addr; + msg.len = len; + msg.buf = buf; + + for (i = 0; i < cmd_head.retry; i++) + { + ret=i2c_transfer(gt_client->adapter, &msg, 1); + if (ret > 0) + { + break; + } + } + return ret; +} + +static s32 tool_i2c_read_with_extra(u8* buf, u16 len) +{ + s32 ret = -1; + u8 pre[2] = {0x0f, 0xff}; + u8 end[2] = {0x80, 0x00}; + + tool_i2c_write_no_extra(pre, 2); + ret = tool_i2c_read_no_extra(buf, len); + tool_i2c_write_no_extra(end, 2); + + return ret; +} + +static s32 tool_i2c_write_with_extra(u8* buf, u16 len) +{ + s32 ret = -1; + u8 pre[2] = {0x0f, 0xff}; + u8 end[2] = {0x80, 0x00}; + + tool_i2c_write_no_extra(pre, 2); + ret = tool_i2c_write_no_extra(buf, len); + tool_i2c_write_no_extra(end, 2); + + return ret; +} + +static void register_i2c_func(void) +{ +// if (!strncmp(IC_TYPE, "GT818", 5) || !strncmp(IC_TYPE, "GT816", 5) +// || !strncmp(IC_TYPE, "GT811", 5) || !strncmp(IC_TYPE, "GT818F", 6) +// || !strncmp(IC_TYPE, "GT827", 5) || !strncmp(IC_TYPE,"GT828", 5) +// || !strncmp(IC_TYPE, "GT813", 5)) + if (strncmp(IC_TYPE, "GT8110", 6) && strncmp(IC_TYPE, "GT8105", 6) + && strncmp(IC_TYPE, "GT801", 5) && strncmp(IC_TYPE, "GT800", 5) + && strncmp(IC_TYPE, "GT801PLUS", 9) && strncmp(IC_TYPE, "GT811", 5) + && strncmp(IC_TYPE, "GTxxx", 5)) + { + tool_i2c_read = tool_i2c_read_with_extra; + tool_i2c_write = tool_i2c_write_with_extra; + GTP_DEBUG("I2C function: with pre and end cmd!"); + } + else + { + tool_i2c_read = tool_i2c_read_no_extra; + tool_i2c_write = tool_i2c_write_no_extra; + GTP_INFO("I2C function: without pre and end cmd!"); + } +} + +static void unregister_i2c_func(void) +{ + tool_i2c_read = NULL; + tool_i2c_write = NULL; + GTP_INFO("I2C function: unregister i2c transfer function!"); +} + + +s32 init_wr_node(struct i2c_client *client) +{ + s32 i; + + gt_client = client; + memset(&cmd_head, 0, sizeof(cmd_head)); + cmd_head.data = NULL; + + i = 5; + while ((!cmd_head.data) && i) + { + cmd_head.data = kzalloc(i * DATA_LENGTH_UINT, GFP_KERNEL); + if (NULL != cmd_head.data) + { + break; + } + i--; + } + if (i) + { + DATA_LENGTH = i * DATA_LENGTH_UINT + GTP_ADDR_LENGTH; + GTP_INFO("Applied memory size:%d.", DATA_LENGTH); + } + else + { + GTP_ERROR("Apply for memory failed."); + return FAIL; + } + + cmd_head.addr_len = 2; + cmd_head.retry = 5; + + register_i2c_func(); + + tool_set_proc_name(procname); + goodix_proc_entry = create_proc_entry(procname, 0666, NULL); + if (goodix_proc_entry == NULL) + { + GTP_ERROR("Couldn't create proc entry!"); + return FAIL; + } + else + { + GTP_INFO("Create proc entry success!"); + goodix_proc_entry->write_proc = goodix_tool_write; + goodix_proc_entry->read_proc = goodix_tool_read; + } + + return SUCCESS; +} + +void uninit_wr_node(void) +{ + kfree(cmd_head.data); + cmd_head.data = NULL; + unregister_i2c_func(); + remove_proc_entry(procname, NULL); +} + +static u8 relation(u8 src, u8 dst, u8 rlt) +{ + u8 ret = 0; + + switch (rlt) + { + case 0: + ret = (src != dst) ? true : false; + break; + + case 1: + ret = (src == dst) ? true : false; + GTP_DEBUG("equal:src:0x%02x dst:0x%02x ret:%d.", src, dst, (s32)ret); + break; + + case 2: + ret = (src > dst) ? true : false; + break; + + case 3: + ret = (src < dst) ? true : false; + break; + + case 4: + ret = (src & dst) ? true : false; + break; + + case 5: + ret = (!(src | dst)) ? true : false; + break; + + default: + ret = false; + break; + } + + return ret; +} + +/******************************************************* +Function: + Comfirm function. +Input: + None. +Output: + Return write length. +********************************************************/ +static u8 comfirm(void) +{ + s32 i = 0; + u8 buf[32]; + +// memcpy(&buf[GTP_ADDR_LENGTH - cmd_head.addr_len], &cmd_head.flag_addr, cmd_head.addr_len); +// memcpy(buf, &cmd_head.flag_addr, cmd_head.addr_len);//Modified by Scott, 2012-02-17 + memcpy(buf, cmd_head.flag_addr, cmd_head.addr_len); + + for (i = 0; i < cmd_head.times; i++) + { + if (tool_i2c_read(buf, 1) <= 0) + { + GTP_ERROR("Read flag data failed!"); + return FAIL; + } + if (true == relation(buf[GTP_ADDR_LENGTH], cmd_head.flag_val, cmd_head.flag_relation)) + { + GTP_DEBUG("value at flag addr:0x%02x.", buf[GTP_ADDR_LENGTH]); + GTP_DEBUG("flag value:0x%02x.", cmd_head.flag_val); + break; + } + + msleep(cmd_head.circle); + } + + if (i >= cmd_head.times) + { + GTP_ERROR("Didn't get the flag to continue!"); + return FAIL; + } + + return SUCCESS; +} + +/******************************************************* +Function: + Goodix tool write function. +Input: + standard proc write function param. +Output: + Return write length. +********************************************************/ +static s32 goodix_tool_write(struct file *filp, const char __user *buff, unsigned long len, void *data) +{ + s32 ret = 0; + GTP_DEBUG_FUNC(); + GTP_DEBUG_ARRAY((u8*)buff, len); + + ret = copy_from_user(&cmd_head, buff, CMD_HEAD_LENGTH); + if(ret) + { + GTP_ERROR("copy_from_user failed."); + } + + GTP_DEBUG("wr :0x%02x.", cmd_head.wr); + GTP_DEBUG("flag:0x%02x.", cmd_head.flag); + GTP_DEBUG("flag addr:0x%02x%02x.", cmd_head.flag_addr[0], cmd_head.flag_addr[1]); + GTP_DEBUG("flag val:0x%02x.", cmd_head.flag_val); + GTP_DEBUG("flag rel:0x%02x.", cmd_head.flag_relation); + GTP_DEBUG("circle :%d.", (s32)cmd_head.circle); + GTP_DEBUG("times :%d.", (s32)cmd_head.times); + GTP_DEBUG("retry :%d.", (s32)cmd_head.retry); + GTP_DEBUG("delay :%d.", (s32)cmd_head.delay); + GTP_DEBUG("data len:%d.", (s32)cmd_head.data_len); + GTP_DEBUG("addr len:%d.", (s32)cmd_head.addr_len); + GTP_DEBUG("addr:0x%02x%02x.", cmd_head.addr[0], cmd_head.addr[1]); + GTP_DEBUG("len:%d.", (s32)len); + GTP_DEBUG("buf[20]:0x%02x.", buff[CMD_HEAD_LENGTH]); + + if (1 == cmd_head.wr) + { + // copy_from_user(&cmd_head.data[cmd_head.addr_len], &buff[CMD_HEAD_LENGTH], cmd_head.data_len); + ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH], &buff[CMD_HEAD_LENGTH], cmd_head.data_len); + if(ret) + { + GTP_ERROR("copy_from_user failed."); + } + memcpy(&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len], cmd_head.addr, cmd_head.addr_len); + + GTP_DEBUG_ARRAY(cmd_head.data, cmd_head.data_len + cmd_head.addr_len); + GTP_DEBUG_ARRAY((u8*)&buff[CMD_HEAD_LENGTH], cmd_head.data_len); + + if (1 == cmd_head.flag) + { + if (FAIL == comfirm()) + { + GTP_ERROR("[WRITE]Comfirm fail!"); + return FAIL; + } + } + else if (2 == cmd_head.flag) + { + //Need interrupt! + } + if (tool_i2c_write(&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len], + cmd_head.data_len + cmd_head.addr_len) <= 0) + { + GTP_ERROR("[WRITE]Write data failed!"); + return FAIL; + } + + GTP_DEBUG_ARRAY(&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len],cmd_head.data_len + cmd_head.addr_len); + if (cmd_head.delay) + { + msleep(cmd_head.delay); + } + + return cmd_head.data_len + CMD_HEAD_LENGTH; + } + else if (3 == cmd_head.wr) //Write ic type + { + ret = copy_from_user(&cmd_head.data[0], &buff[CMD_HEAD_LENGTH], cmd_head.data_len); + if(ret) + { + GTP_ERROR("copy_from_user failed."); + } + memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len); + + register_i2c_func(); + + return cmd_head.data_len + CMD_HEAD_LENGTH; + } + else if (5 == cmd_head.wr) + { + //memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len); + + return cmd_head.data_len + CMD_HEAD_LENGTH; + } + else if (7 == cmd_head.wr)//disable irq! + { + gtp_irq_disable(i2c_get_clientdata(gt_client)); + + #if GTP_ESD_PROTECT + gtp_esd_switch(gt_client, SWITCH_OFF); + #endif + return CMD_HEAD_LENGTH; + } + else if (9 == cmd_head.wr) //enable irq! + { + gtp_irq_enable(i2c_get_clientdata(gt_client)); + + #if GTP_ESD_PROTECT + gtp_esd_switch(gt_client, SWITCH_ON); + #endif + return CMD_HEAD_LENGTH; + } + else if(17 == cmd_head.wr) + { + struct goodix_ts_data *ts = i2c_get_clientdata(gt_client); + ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH], &buff[CMD_HEAD_LENGTH], cmd_head.data_len); + if(ret) + { + GTP_DEBUG("copy_from_user failed."); + } + if(cmd_head.data[GTP_ADDR_LENGTH]) + { + GTP_DEBUG("gtp enter rawdiff."); + ts->gtp_rawdiff_mode = true; + } + else + { + ts->gtp_rawdiff_mode = false; + GTP_DEBUG("gtp leave rawdiff."); + } + return CMD_HEAD_LENGTH; + } +#ifdef UPDATE_FUNCTIONS + else if (11 == cmd_head.wr)//Enter update mode! + { + if (FAIL == gup_enter_update_mode(gt_client)) + { + return FAIL; + } + } + else if (13 == cmd_head.wr)//Leave update mode! + { + gup_leave_update_mode(); + } + else if (15 == cmd_head.wr) //Update firmware! + { + show_len = 0; + total_len = 0; + memset(cmd_head.data, 0, cmd_head.data_len + 1); + memcpy(cmd_head.data, &buff[CMD_HEAD_LENGTH], cmd_head.data_len); + + if (FAIL == gup_update_proc((void*)cmd_head.data)) + { + return FAIL; + } + } +#endif + + return CMD_HEAD_LENGTH; +} + +/******************************************************* +Function: + Goodix tool read function. +Input: + standard proc read function param. +Output: + Return read length. +********************************************************/ +static s32 goodix_tool_read( char *page, char **start, off_t off, int count, int *eof, void *data ) +{ + GTP_DEBUG_FUNC(); + + if (cmd_head.wr % 2) + { + return FAIL; + } + else if (!cmd_head.wr) + { + u16 len = 0; + s16 data_len = 0; + u16 loc = 0; + + if (1 == cmd_head.flag) + { + if (FAIL == comfirm()) + { + GTP_ERROR("[READ]Comfirm fail!"); + return FAIL; + } + } + else if (2 == cmd_head.flag) + { + //Need interrupt! + } + + memcpy(cmd_head.data, cmd_head.addr, cmd_head.addr_len); + + GTP_DEBUG("[CMD HEAD DATA] ADDR:0x%02x%02x.", cmd_head.data[0], cmd_head.data[1]); + GTP_DEBUG("[CMD HEAD ADDR] ADDR:0x%02x%02x.", cmd_head.addr[0], cmd_head.addr[1]); + + if (cmd_head.delay) + { + msleep(cmd_head.delay); + } + + data_len = cmd_head.data_len; + while(data_len > 0) + { + if (data_len > DATA_LENGTH) + { + len = DATA_LENGTH; + } + else + { + len = data_len; + } + data_len -= DATA_LENGTH; + + if (tool_i2c_read(cmd_head.data, len) <= 0) + { + GTP_ERROR("[READ]Read data failed!"); + return FAIL; + } + memcpy(&page[loc], &cmd_head.data[GTP_ADDR_LENGTH], len); + loc += len; + + GTP_DEBUG_ARRAY(&cmd_head.data[GTP_ADDR_LENGTH], len); + GTP_DEBUG_ARRAY(page, len); + } + } + else if (2 == cmd_head.wr) + { + // memcpy(page, "gt8", cmd_head.data_len); + // memcpy(page, "GT818", 5); + // page[5] = 0; + + GTP_DEBUG("Return ic type:%s len:%d.", page, (s32)cmd_head.data_len); + return cmd_head.data_len; + //return sizeof(IC_TYPE_NAME); + } + else if (4 == cmd_head.wr) + { + page[0] = show_len >> 8; + page[1] = show_len & 0xff; + page[2] = total_len >> 8; + page[3] = total_len & 0xff; + + return cmd_head.data_len; + } + else if (6 == cmd_head.wr) + { + //Read error code! + } + else if (8 == cmd_head.wr) //Read driver version + { + // memcpy(page, GTP_DRIVER_VERSION, strlen(GTP_DRIVER_VERSION)); + s32 tmp_len; + tmp_len = strlen(GTP_DRIVER_VERSION); + memcpy(page, GTP_DRIVER_VERSION, tmp_len); + page[tmp_len] = 0; + } + + return cmd_head.data_len; +} diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/gt9xx.c b/ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/gt9xx.c new file mode 100755 index 00000000..cc02513e --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/gt9xx.c @@ -0,0 +1,2163 @@ +/* drivers/input/touchscreen/gt9xx.c + * + * 2010 - 2013 Goodix Technology. + * + * 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 a reference + * to you, when you are integrating the GOODiX's CTP IC into your system, + * 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. + * + * Version: 1.8 + * Authors: andrew@goodix.com, meta@goodix.com + * Release Date: 2013/04/25 + * Revision record: + * V1.0: + * first Release. By Andrew, 2012/08/31 + * V1.2: + * modify gtp_reset_guitar,slot report,tracking_id & 0x0F. By Andrew, 2012/10/15 + * V1.4: + * modify gt9xx_update.c. By Andrew, 2012/12/12 + * V1.6: + * 1. new heartbeat/esd_protect mechanism(add external watchdog) + * 2. doze mode, sliding wakeup + * 3. 3 more cfg_group(GT9 Sensor_ID: 0~5) + * 3. config length verification + * 4. names & comments + * By Meta, 2013/03/11 + * V1.8: + * 1. pen/stylus identification + * 2. read double check & fixed config support + * 2. new esd & slide wakeup optimization + * By Meta, 2013/06/08 + */ + +#include +#include +#include "gt9xx.h" + +#if GTP_ICS_SLOT_REPORT + #include +#endif + +static const char *goodix_ts_name = "Goodix Capacitive TouchScreen"; +static struct workqueue_struct *goodix_wq; +struct goodix_ts_data *l_ts; +int l_suspend = 0; +struct i2c_client * i2c_connect_client = NULL; +u8 config[GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH] + = {GTP_REG_CONFIG_DATA >> 8, GTP_REG_CONFIG_DATA & 0xff}; + +#if GTP_HAVE_TOUCH_KEY + static const u16 touch_key_array[] = GTP_KEY_TAB; + #define GTP_MAX_KEY_NUM (sizeof(touch_key_array)/sizeof(touch_key_array[0])) + +#if GTP_DEBUG_ON + static const int key_codes[] = {KEY_HOME, KEY_BACK, KEY_MENU, KEY_SEARCH}; + static const char *key_names[] = {"Key_Home", "Key_Back", "Key_Menu", "Key_Search"}; +#endif + +#endif + +static s8 gtp_i2c_test(struct i2c_client *client); +void gtp_reset_guitar(struct i2c_client *client, s32 ms); +void gtp_int_sync(s32 ms); + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void goodix_ts_early_suspend(struct early_suspend *h); +static void goodix_ts_late_resume(struct early_suspend *h); +#endif + +#if GTP_CREATE_WR_NODE +extern s32 init_wr_node(struct i2c_client*); +extern void uninit_wr_node(void); +#endif + +#if GTP_AUTO_UPDATE +extern u8 gup_init_update_proc(struct goodix_ts_data *); +#endif + +#if GTP_ESD_PROTECT +static struct delayed_work gtp_esd_check_work; +static struct workqueue_struct * gtp_esd_check_workqueue = NULL; +static void gtp_esd_check_func(struct work_struct *); +static s32 gtp_init_ext_watchdog(struct i2c_client *client); +void gtp_esd_switch(struct goodix_ts_data *, s32); +#endif + + +#if GTP_SLIDE_WAKEUP +typedef enum +{ + DOZE_DISABLED = 0, + DOZE_ENABLED = 1, + DOZE_WAKEUP = 2, +}DOZE_T; +static DOZE_T doze_status = DOZE_DISABLED; +static s8 gtp_enter_doze(struct goodix_ts_data *ts); +#endif + +static u8 chip_gt9xxs = 0; // true if ic is gt9xxs, like gt915s +u8 grp_cfg_version = 0; + +/******************************************************* +Function: + Read data from the i2c slave device. +Input: + client: i2c device. + buf[0~1]: read start address. + buf[2~len-1]: read data buffer. + len: GTP_ADDR_LENGTH + read bytes count +Output: + numbers of i2c_msgs to transfer: + 2: succeed, otherwise: failed +*********************************************************/ +s32 gtp_i2c_read(struct i2c_client *client, u8 *buf, s32 len) +{ + struct i2c_msg msgs[2]; + s32 ret=-1; + s32 retries = 0; + + GTP_DEBUG_FUNC(); + + //msgs[0].flags = !I2C_M_RD; + msgs[0].flags = 0 | I2C_M_NOSTART; + msgs[0].addr = client->addr; + msgs[0].len = GTP_ADDR_LENGTH; + msgs[0].buf = &buf[0]; + //msgs[0].scl_rate = 300 * 1000; // for Rockchip + + msgs[1].flags = I2C_M_RD; + msgs[1].addr = client->addr; + msgs[1].len = len - GTP_ADDR_LENGTH; + msgs[1].buf = &buf[GTP_ADDR_LENGTH]; + //msgs[1].scl_rate = 300 * 1000; + + while(retries < 5) + { + ret = i2c_transfer(client->adapter, msgs, 2); + if(ret == 2)break; + retries++; + } + if((retries >= 5)) + { + #if GTP_SLIDE_WAKEUP + // reset chip would quit doze mode + if (DOZE_ENABLED == doze_status) + { + return ret; + } + #endif + GTP_DEBUG("I2C communication timeout, resetting chip..."); + gtp_reset_guitar(client, 10); + } + return ret; +} + +/******************************************************* +Function: + Write data to the i2c slave device. +Input: + client: i2c device. + buf[0~1]: write start address. + buf[2~len-1]: data buffer + len: GTP_ADDR_LENGTH + write bytes count +Output: + numbers of i2c_msgs to transfer: + 1: succeed, otherwise: failed +*********************************************************/ +s32 gtp_i2c_write(struct i2c_client *client,u8 *buf,s32 len) +{ + struct i2c_msg msg; + s32 ret = -1; + s32 retries = 0; + + GTP_DEBUG_FUNC(); + + msg.flags = !I2C_M_RD; + msg.addr = client->addr; + msg.len = len; + msg.buf = buf; + //msg.scl_rate = 300 * 1000; // for Rockchip + + while(retries < 5) + { + ret = i2c_transfer(client->adapter, &msg, 1); + if (ret == 1)break; + retries++; + } + if((retries >= 5)) + { + #if GTP_SLIDE_WAKEUP + if (DOZE_ENABLED == doze_status) + { + return ret; + } + #endif + GTP_DEBUG("I2C communication timeout, resetting chip..."); + gtp_reset_guitar(client, 10); + } + return ret; +} +/******************************************************* +Function: + i2c read twice, compare the results +Input: + client: i2c device + addr: operate address + rxbuf: read data to store, if compare successful + len: bytes to read +Output: + FAIL: read failed + SUCCESS: read successful +*********************************************************/ +s32 gtp_i2c_read_dbl_check(struct i2c_client *client, u16 addr, u8 *rxbuf, int len) +{ + u8 buf[16] = {0}; + u8 confirm_buf[16] = {0}; + u8 retry = 0; + + while (retry++ < 3) + { + memset(buf, 0xAA, 16); + buf[0] = (u8)(addr >> 8); + buf[1] = (u8)(addr & 0xFF); + gtp_i2c_read(client, buf, len + 2); + + memset(confirm_buf, 0xAB, 16); + confirm_buf[0] = (u8)(addr >> 8); + confirm_buf[1] = (u8)(addr & 0xFF); + gtp_i2c_read(client, confirm_buf, len + 2); + + if (!memcmp(buf, confirm_buf, len+2)) + { + break; + } + } + if (retry < 3) + { + memcpy(rxbuf, confirm_buf+2, len); + return SUCCESS; + } + else + { + GTP_ERROR("i2c read 0x%04X, %d bytes, double check failed!", addr, len); + return FAIL; + } +} + +/******************************************************* +Function: + Send config. +Input: + client: i2c device. +Output: + result of i2c write operation. + 1: succeed, otherwise: failed +*********************************************************/ +s32 gtp_send_cfg(struct goodix_ts_data * ts) +{ + s32 ret = 2; + +#if GTP_DRIVER_SEND_CFG + s32 retry = 0; + + if (ts->fixed_cfg) + { + GTP_INFO("Ic fixed config, no config sent!"); + return 2; + } + GTP_INFO("driver send config"); + for (retry = 0; retry < 5; retry++) + { + ret = gtp_i2c_write(ts->client, config , GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH); + if (ret > 0) + { + break; + } + } +#endif + + return ret; +} + +/******************************************************* +Function: + Disable irq function +Input: + ts: goodix i2c_client private data +Output: + None. +*********************************************************/ +void gtp_irq_disable(struct goodix_ts_data *ts) +{ + //unsigned long irqflags; + + GTP_DEBUG_FUNC(); + + //spin_lock_irqsave(&ts->irq_lock, irqflags); + if (!ts->irq_is_disable) + { + ts->irq_is_disable = 1; + //disable_irq_nosync(ts->client->irq); + wmt_gpio_mask_irq(ts->irq_gpio); + } + //spin_unlock_irqrestore(&ts->irq_lock, irqflags); +} + +/******************************************************* +Function: + Enable irq function +Input: + ts: goodix i2c_client private data +Output: + None. +*********************************************************/ +void gtp_irq_enable(struct goodix_ts_data *ts) +{ + //unsigned long irqflags = 0; + + GTP_DEBUG_FUNC(); + + //spin_lock_irqsave(&ts->irq_lock, irqflags); + if (ts->irq_is_disable) + { + //enable_irq(ts->client->irq); + wmt_gpio_unmask_irq(ts->irq_gpio); + ts->irq_is_disable = 0; + } + //spin_unlock_irqrestore(&ts->irq_lock, irqflags); +} + + +/******************************************************* +Function: + Report touch point event +Input: + ts: goodix i2c_client private data + id: trackId + x: input x coordinate + y: input y coordinate + w: input pressure +Output: + None. +*********************************************************/ +static void gtp_touch_down(struct goodix_ts_data* ts,s32 id,s32 x,s32 y,s32 w) +{ + s32 px = 0, py = 0; +#if GTP_CHANGE_X2Y + GTP_SWAP(x, y); +#endif + + if (ts->swap) { + px = y; + py = x; + } else { + px = x; + py = y; + } + if (ts->xdir == -1) + px = ts->abs_x_max - px; + if (ts->ydir == -1) + py = ts->abs_y_max - py; + + if (ts->lcd_exchg) { + int tmp; + tmp = px; + px = py; + py = ts->abs_x_max - tmp; + } + +#if GTP_ICS_SLOT_REPORT + input_mt_slot(ts->input_dev, id); + input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, id); + input_report_abs(ts->input_dev, ABS_MT_POSITION_X, x); + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, y); + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, w); + input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, w); +#else + input_report_abs(ts->input_dev, ABS_MT_POSITION_X, px); + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, py); + //input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, w); + //input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, w); + input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, id); + input_mt_sync(ts->input_dev); +#endif + + GTP_DEBUG("ID:%d, X:%d, Y:%d, W:%d", id, px, py, w); +} + +/******************************************************* +Function: + Report touch release event +Input: + ts: goodix i2c_client private data +Output: + None. +*********************************************************/ +static void gtp_touch_up(struct goodix_ts_data* ts, s32 id) +{ +#if GTP_ICS_SLOT_REPORT + input_mt_slot(ts->input_dev, id); + input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, -1); + GTP_DEBUG("Touch id[%2d] release!", id); +#else + //input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0); + //input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0); + input_mt_sync(ts->input_dev); +#endif +} + + +/******************************************************* +Function: + Goodix touchscreen work function +Input: + work: work struct of goodix_workqueue +Output: + None. +*********************************************************/ +static void goodix_ts_work_func(struct work_struct *work) +{ + u8 end_cmd[3] = {GTP_READ_COOR_ADDR >> 8, GTP_READ_COOR_ADDR & 0xFF, 0}; + u8 point_data[2 + 1 + 8 * GTP_MAX_TOUCH + 1]={GTP_READ_COOR_ADDR >> 8, GTP_READ_COOR_ADDR & 0xFF}; + u8 touch_num = 0; + u8 finger = 0; + static u16 pre_touch = 0; + static u8 pre_key = 0; +#if GTP_WITH_PEN + static u8 pre_pen = 0; +#endif + u8 key_value = 0; + u8* coor_data = NULL; + s32 input_x = 0; + s32 input_y = 0; + s32 input_w = 0; + s32 id = 0; + s32 i = 0; + s32 ret = -1; + struct goodix_ts_data *ts = NULL; + +#if GTP_SLIDE_WAKEUP + u8 doze_buf[3] = {0x81, 0x4B}; +#endif + + GTP_DEBUG_FUNC(); + ts = container_of(work, struct goodix_ts_data, work); + if (ts->enter_update) + { + return; + } +#if GTP_SLIDE_WAKEUP + if (DOZE_ENABLED == doze_status) + { + ret = gtp_i2c_read(i2c_connect_client, doze_buf, 3); + GTP_DEBUG("0x814B = 0x%02X", doze_buf[2]); + if (ret > 0) + { + if (doze_buf[2] == 0xAA) + { + GTP_INFO("Slide(0xAA) To Light up the screen!"); + doze_status = DOZE_WAKEUP; + input_report_key(ts->input_dev, KEY_POWER, 1); + input_sync(ts->input_dev); + input_report_key(ts->input_dev, KEY_POWER, 0); + input_sync(ts->input_dev); + // clear 0x814B + doze_buf[2] = 0x00; + gtp_i2c_write(i2c_connect_client, doze_buf, 3); + } + else if (doze_buf[2] == 0xBB) + { + GTP_INFO("Slide(0xBB) To Light up the screen!"); + doze_status = DOZE_WAKEUP; + input_report_key(ts->input_dev, KEY_POWER, 1); + input_sync(ts->input_dev); + input_report_key(ts->input_dev, KEY_POWER, 0); + input_sync(ts->input_dev); + // clear 0x814B + doze_buf[2] = 0x00; + gtp_i2c_write(i2c_connect_client, doze_buf, 3); + } + else if (0xC0 == (doze_buf[2] & 0xC0)) + { + GTP_INFO("double click to light up the screen!"); + doze_status = DOZE_WAKEUP; + input_report_key(ts->input_dev, KEY_POWER, 1); + input_sync(ts->input_dev); + input_report_key(ts->input_dev, KEY_POWER, 0); + input_sync(ts->input_dev); + // clear 0x814B + doze_buf[2] = 0x00; + gtp_i2c_write(i2c_connect_client, doze_buf, 3); + } + else + { + gtp_enter_doze(ts); + } + } + if (ts->use_irq) + { + gtp_irq_enable(ts); + } + return; + } +#endif + + ret = gtp_i2c_read(ts->client, point_data, 12); + if (ret < 0) + { + GTP_ERROR("I2C transfer error. errno:%d\n ", ret); + goto exit_work_func; + } + + finger = point_data[GTP_ADDR_LENGTH]; + if((finger & 0x80) == 0) + { + goto exit_work_func; + } + + touch_num = finger & 0x0f; + if (touch_num > GTP_MAX_TOUCH) + { + goto exit_work_func; + } + + if (touch_num > 1) + { + u8 buf[8 * GTP_MAX_TOUCH] = {(GTP_READ_COOR_ADDR + 10) >> 8, (GTP_READ_COOR_ADDR + 10) & 0xff}; + + ret = gtp_i2c_read(ts->client, buf, 2 + 8 * (touch_num - 1)); + memcpy(&point_data[12], &buf[2], 8 * (touch_num - 1)); + } + +#if GTP_HAVE_TOUCH_KEY + key_value = point_data[3 + 8 * touch_num]; + + if(key_value || pre_key) + { + for (i = 0; i < GTP_MAX_KEY_NUM; i++) + { + #if GTP_DEBUG_ON + for (ret = 0; ret < 4; ++ret) + { + if (key_codes[ret] == touch_key_array[i]) + { + GTP_DEBUG("Key: %s %s", key_names[ret], (key_value & (0x01 << i)) ? "Down" : "Up"); + break; + } + } + #endif + input_report_key(ts->input_dev, touch_key_array[i], key_value & (0x01<input_dev, BTN_TOOL_PEN, 0); + input_mt_slot(ts->input_dev, 5); + input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, -1); + pre_pen = 0; + } +#endif + if (pre_touch || touch_num) + { + s32 pos = 0; + u16 touch_index = 0; + + coor_data = &point_data[3]; + + if(touch_num) + { + id = coor_data[pos] & 0x0F; + + #if GTP_WITH_PEN + id = coor_data[pos]; + if ((id == 128)) + { + GTP_DEBUG("Pen touch DOWN(Slot)!"); + input_x = coor_data[pos + 1] | (coor_data[pos + 2] << 8); + input_y = coor_data[pos + 3] | (coor_data[pos + 4] << 8); + input_w = coor_data[pos + 5] | (coor_data[pos + 6] << 8); + + input_report_key(ts->input_dev, BTN_TOOL_PEN, 1); + input_mt_slot(ts->input_dev, 5); + input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, 5); + input_report_abs(ts->input_dev, ABS_MT_POSITION_X, input_x); + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, input_y); + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, input_w); + GTP_DEBUG("Pen/Stylus: (%d, %d)[%d]", input_x, input_y, input_w); + pre_pen = 1; + pre_touch = 0; + } + #endif + + touch_index |= (0x01<input_dev, BTN_TOUCH, (touch_num || key_value)); + if (touch_num) + { + for (i = 0; i < touch_num; i++) + { + coor_data = &point_data[i * 8 + 3]; + + id = coor_data[0]; // & 0x0F; + input_x = coor_data[1] | (coor_data[2] << 8); + input_y = coor_data[3] | (coor_data[4] << 8); + input_w = coor_data[5] | (coor_data[6] << 8); + + #if GTP_WITH_PEN + if (id == 128) + { + GTP_DEBUG("Pen touch DOWN!"); + input_report_key(ts->input_dev, BTN_TOOL_PEN, 1); + pre_pen = 1; + id = 0; + } + #endif + + gtp_touch_down(ts, id, input_x, input_y, input_w); + } + } + else if (pre_touch) + { + #if GTP_WITH_PEN + if (pre_pen == 1) + { + GTP_DEBUG("Pen touch UP!"); + input_report_key(ts->input_dev, BTN_TOOL_PEN, 0); + pre_pen = 0; + } + #endif + + GTP_DEBUG("Touch Release!"); + gtp_touch_up(ts, 0); + } + + pre_touch = touch_num; +#endif + + input_sync(ts->input_dev); + +exit_work_func: + if(!ts->gtp_rawdiff_mode) + { + ret = gtp_i2c_write(ts->client, end_cmd, 3); + if (ret < 0) + { + GTP_INFO("I2C write end_cmd error!"); + } + } + if (ts->use_irq) + { + gtp_irq_enable(ts); + } +} + +/******************************************************* +Function: + Timer interrupt service routine for polling mode. +Input: + timer: timer struct pointer +Output: + Timer work mode. + HRTIMER_NORESTART: no restart mode +*********************************************************/ +static enum hrtimer_restart goodix_ts_timer_handler(struct hrtimer *timer) +{ + struct goodix_ts_data *ts = container_of(timer, struct goodix_ts_data, timer); + + GTP_DEBUG_FUNC(); + + queue_work(goodix_wq, &ts->work); + hrtimer_start(&ts->timer, ktime_set(0, (GTP_POLL_TIME+6)*1000000), HRTIMER_MODE_REL); + return HRTIMER_NORESTART; +} + +/******************************************************* +Function: + External interrupt service routine for interrupt mode. +Input: + irq: interrupt number. + dev_id: private data pointer +Output: + Handle Result. + IRQ_HANDLED: interrupt handled successfully +*********************************************************/ +static irqreturn_t goodix_ts_irq_handler(int irq, void *dev_id) +{ + struct goodix_ts_data *ts = dev_id; + + GTP_DEBUG_FUNC(); + + if (gpio_irqstatus(ts->irq_gpio)) + { + wmt_gpio_ack_irq(ts->irq_gpio); + if (is_gpio_irqenable(ts->irq_gpio) && l_suspend == 0) + { + gtp_irq_disable(ts); + queue_work(goodix_wq, &ts->work); + } + return IRQ_HANDLED; + } + + return IRQ_NONE; +} +/******************************************************* +Function: + Synchronization. +Input: + ms: synchronization time in millisecond. +Output: + None. +*******************************************************/ +void gtp_int_sync(s32 ms) +{ + GTP_GPIO_OUTPUT(l_ts->irq_gpio, 0); + msleep(ms); + GTP_GPIO_AS_INPUT(l_ts->irq_gpio); + //GTP_GPIO_AS_INT(ts->irq_gpio); +} + +/******************************************************* +Function: + Reset chip. +Input: + ms: reset time in millisecond +Output: + None. +*******************************************************/ +void gtp_reset_guitar(struct i2c_client *client, s32 ms) +{ + GTP_DEBUG_FUNC(); + + GTP_GPIO_OUTPUT(l_ts->rst_gpio, 0); // begin select I2C slave addr + msleep(ms); // T2: > 10ms + // HIGH: 0x28/0x29, LOW: 0xBA/0xBB + GTP_GPIO_OUTPUT(l_ts->irq_gpio, client->addr == 0x14); + + msleep(2); // T3: > 100us + GTP_GPIO_OUTPUT(l_ts->rst_gpio, 1); + + msleep(6); // T4: > 5ms + + GTP_GPIO_AS_INPUT(l_ts->rst_gpio); // end select I2C slave addr + + gtp_int_sync(50); + +#if GTP_ESD_PROTECT + gtp_init_ext_watchdog(client); +#endif +} + +#if GTP_SLIDE_WAKEUP +/******************************************************* +Function: + Enter doze mode for sliding wakeup. +Input: + ts: goodix tp private data +Output: + 1: succeed, otherwise failed +*******************************************************/ +static s8 gtp_enter_doze(struct goodix_ts_data *ts) +{ + s8 ret = -1; + s8 retry = 0; + u8 i2c_control_buf[3] = {(u8)(GTP_REG_SLEEP >> 8), (u8)GTP_REG_SLEEP, 8}; + + GTP_DEBUG_FUNC(); + +#if GTP_DBL_CLK_WAKEUP + i2c_control_buf[2] = 0x09; +#endif + + gtp_irq_disable(ts); + + GTP_DEBUG("entering doze mode..."); + while(retry++ < 5) + { + i2c_control_buf[0] = 0x80; + i2c_control_buf[1] = 0x46; + ret = gtp_i2c_write(ts->client, i2c_control_buf, 3); + if (ret < 0) + { + GTP_DEBUG("failed to set doze flag into 0x8046, %d", retry); + continue; + } + i2c_control_buf[0] = 0x80; + i2c_control_buf[1] = 0x40; + ret = gtp_i2c_write(ts->client, i2c_control_buf, 3); + if (ret > 0) + { + doze_status = DOZE_ENABLED; + GTP_INFO("GTP has been working in doze mode!"); + gtp_irq_enable(ts); + return ret; + } + msleep(10); + } + GTP_ERROR("GTP send doze cmd failed."); + gtp_irq_enable(ts); + return ret; +} +#else +/******************************************************* +Function: + Enter sleep mode. +Input: + ts: private data. +Output: + Executive outcomes. + 1: succeed, otherwise failed. +*******************************************************/ +#if 0 +static s8 gtp_enter_sleep(struct goodix_ts_data * ts) +{ + s8 ret = -1; + s8 retry = 0; + u8 i2c_control_buf[3] = {(u8)(GTP_REG_SLEEP >> 8), (u8)GTP_REG_SLEEP, 5}; + + GTP_DEBUG_FUNC(); + + GTP_GPIO_OUTPUT(ts->irq_gpio, 0); + msleep(5); + + while(retry++ < 5) + { + ret = gtp_i2c_write(ts->client, i2c_control_buf, 3); + if (ret > 0) + { + GTP_INFO("GTP enter sleep!"); + + return ret; + } + msleep(10); + } + GTP_ERROR("GTP send sleep cmd failed."); + return ret; +} +#endif +#endif +/******************************************************* +Function: + Wakeup from sleep. +Input: + ts: private data. +Output: + Executive outcomes. + >0: succeed, otherwise: failed. +*******************************************************/ +#if 0 +static s8 gtp_wakeup_sleep(struct goodix_ts_data * ts) +{ + u8 retry = 0; + s8 ret = -1; + + GTP_DEBUG_FUNC(); + +#if GTP_POWER_CTRL_SLEEP + while(retry++ < 5) + { + gtp_reset_guitar(ts->client, 20); + + ret = gtp_send_cfg(ts); + if (ret < 0) + { + GTP_INFO("Wakeup sleep send config failed!"); + continue; + } + GTP_INFO("GTP wakeup sleep"); + return 1; + } +#else + while(retry++ < 10) + { + #if GTP_SLIDE_WAKEUP + if (DOZE_WAKEUP != doze_status) // wakeup not by slide + { + gtp_reset_guitar(ts->client, 10); + } + else // wakeup by slide + { + doze_status = DOZE_DISABLED; + } + #else + if (chip_gt9xxs == 1) + { + gtp_reset_guitar(ts->client, 10); + } + else + { + GTP_GPIO_OUTPUT(ts->irq_gpio, 1); + msleep(5); + } + #endif + ret = gtp_i2c_test(ts->client); + if (ret > 0) + { + GTP_INFO("GTP wakeup sleep."); + + #if (!GTP_SLIDE_WAKEUP) + if (chip_gt9xxs == 0) + { + gtp_int_sync(25); + msleep(20); + #if GTP_ESD_PROTECT + gtp_init_ext_watchdog(ts->client); + #endif + } + #endif + return ret; + } + gtp_reset_guitar(ts->client, 20); + } +#endif + + GTP_ERROR("GTP wakeup sleep failed."); + return ret; +} +#endif + +static int wmt_ts_load_firmware(char* firmwarename, unsigned char* firmdata) +{ + struct file *fp; + mm_segment_t fs; + loff_t pos; + long fsize; + int alloclen; + char filepath[64]; + + sprintf(filepath, "/system/etc/firmware/%s", firmwarename); + printk("ts firmware file:%s\n",filepath); + + fp = filp_open(filepath, O_RDONLY, 0); + if (IS_ERR(fp)) { + printk("create file error\n"); + return -1; + } + fs = get_fs(); + set_fs(KERNEL_DS); + alloclen = fp->f_op->llseek(fp, 0, SEEK_END); + printk("firmware file lengh:0x%x,\n", alloclen); + alloclen += alloclen%4; + + fp->f_op->llseek(fp,0,0); + pos = 0; + fsize = vfs_read(fp, firmdata, alloclen, &pos); + printk("filesize:0x%ld,alloclen:0x%d\n",fsize,alloclen); + if (fsize <= 0) + { + printk("alloc size is too small.\n"); + goto error_vfs_read; + } + filp_close(fp, NULL); + set_fs(fs); + printk("success to read firmware file!\n");; + + return 0; +error_vfs_read: + filp_close(fp, NULL); + set_fs(fs); + return -1; +} + +static int read_cfg(char* cfgname, u8* cfg, int len_max) +{ + char endflag[]="/* End flag */"; + unsigned char* p; + int val; + int i = 0; + unsigned char *rawdata; + + rawdata = kzalloc(1024, GFP_KERNEL); + if (rawdata == NULL) + { + printk("Error when alloc memory for firmware file!\n"); + return -ENOMEM; + } + + if (wmt_ts_load_firmware(cfgname, rawdata)) + return -1; + + p = rawdata; + while (*p!='{') p++; + p++; + + while (strncmp(p,endflag,strlen(endflag))) + { + if (!strncmp(p,"0x",strlen("0x"))) + { + sscanf(p,"%x,",&val); + *(cfg++) = val&0x00FF; + i++; + } + if (i == len_max) + break; + p++; + + }; + + kfree(rawdata); + + return i; +} + +/******************************************************* +Function: + Initialize gtp. +Input: + ts: goodix private data +Output: + Executive outcomes. + 0: succeed, otherwise: failed +*******************************************************/ +static s32 gtp_init_panel(struct goodix_ts_data *ts) +{ + s32 ret = -1; + +#if GTP_DRIVER_SEND_CFG + s32 i; + u8 check_sum = 0; + u8 opr_buf[16]; + u8 sensor_id = 0; + + u8 send_cfg_buf[256] = {0}; + char cfgname[32] = {0}; + + ret = gtp_i2c_read_dbl_check(ts->client, 0x41E4, opr_buf, 1); + if (SUCCESS == ret) + { + if (opr_buf[0] != 0xBE) + { + ts->fw_error = 1; + GTP_ERROR("Firmware error, no config sent!"); + return -1; + } + } + + ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_SENSOR_ID, &sensor_id, 1); + if (SUCCESS == ret) + { + if (sensor_id >= 0x06) + { + //GTP_ERROR("Invalid sensor_id(0x%02X), No Config Sent!", sensor_id); + //return -1; + GTP_ERROR("Invalid sensor_id(0x%02X), Force set id to 0!", sensor_id); + sensor_id = 0; + } + } + else + { + GTP_ERROR("Failed to get sensor_id, No config sent!"); + return -1; + } + GTP_DEBUG("Sensor_ID: %d", sensor_id); + + sprintf(cfgname, "%s_id%d.cfg", ts->fw_name, sensor_id); + GTP_INFO("config file name: %s.", cfgname); + ret = read_cfg(cfgname, send_cfg_buf, 256); + if (ret < 0) + return -1; + ts->gtp_cfg_len = ret; + + if (ts->gtp_cfg_len < GTP_CONFIG_MIN_LENGTH) + { + GTP_ERROR("INVALID CONFIG GROUP! NO Config Sent! You need to check you header file CFG_GROUP section!"); + return -1; + } + + ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA, &opr_buf[0], 1); + + if (ret == SUCCESS) + { + GTP_DEBUG("Config Version: %d, 0x%02X; IC Config Version: %d, 0x%02X", + send_cfg_buf[0], send_cfg_buf[0], opr_buf[0], opr_buf[0]); + + if (opr_buf[0] < 90) + { + grp_cfg_version = send_cfg_buf[0]; // backup group config version + send_cfg_buf[0] = 0x00; + ts->fixed_cfg = 0; + } + else // treated as fixed config, not send config + { + GTP_INFO("Ic fixed config with config version(%d, 0x%02X)", opr_buf[0], opr_buf[0]); + ts->fixed_cfg = 1; + } + } + else + { + GTP_ERROR("Failed to get ic config version!No config sent!"); + return -1; + } + + memset(&config[GTP_ADDR_LENGTH], 0, GTP_CONFIG_MAX_LENGTH); + memcpy(&config[GTP_ADDR_LENGTH], send_cfg_buf, ts->gtp_cfg_len); + +#if GTP_CUSTOM_CFG + config[RESOLUTION_LOC] = (u8)GTP_MAX_WIDTH; + config[RESOLUTION_LOC + 1] = (u8)(GTP_MAX_WIDTH>>8); + config[RESOLUTION_LOC + 2] = (u8)GTP_MAX_HEIGHT; + config[RESOLUTION_LOC + 3] = (u8)(GTP_MAX_HEIGHT>>8); + + if (GTP_INT_TRIGGER == 0) //RISING + { + config[TRIGGER_LOC] &= 0xfe; + } + else if (GTP_INT_TRIGGER == 1) //FALLING + { + config[TRIGGER_LOC] |= 0x01; + } +#endif // GTP_CUSTOM_CFG + + check_sum = 0; + for (i = GTP_ADDR_LENGTH; i < ts->gtp_cfg_len; i++) + { + check_sum += config[i]; + } + config[ts->gtp_cfg_len] = (~check_sum) + 1; + +#else // DRIVER NOT SEND CONFIG + ts->gtp_cfg_len = GTP_CONFIG_MAX_LENGTH; + ret = gtp_i2c_read(ts->client, config, ts->gtp_cfg_len + GTP_ADDR_LENGTH); + if (ret < 0) + { + GTP_ERROR("Read Config Failed, Using Default Resolution & INT Trigger!"); + ts->abs_x_max = GTP_MAX_WIDTH; + ts->abs_y_max = GTP_MAX_HEIGHT; + ts->int_trigger_type = GTP_INT_TRIGGER; + } +#endif // GTP_DRIVER_SEND_CFG + + GTP_DEBUG_FUNC(); + if ((ts->abs_x_max == 0) && (ts->abs_y_max == 0)) + { + ts->abs_x_max = (config[RESOLUTION_LOC + 1] << 8) + config[RESOLUTION_LOC]; + ts->abs_y_max = (config[RESOLUTION_LOC + 3] << 8) + config[RESOLUTION_LOC + 2]; + ts->int_trigger_type = (config[TRIGGER_LOC]) & 0x03; + } + + ret = gtp_send_cfg(ts); + if (ret < 0) + { + GTP_ERROR("Send config error."); + } + //GTP_DEBUG("X_MAX = %d, Y_MAX = %d, TRIGGER = 0x%02x", + //ts->abs_x_max,ts->abs_y_max,ts->int_trigger_type); + GTP_INFO("X_MAX = %d, Y_MAX = %d, TRIGGER = 0x%02x(%s).", + ts->abs_x_max,ts->abs_y_max,ts->int_trigger_type, ts->int_trigger_type?"Falling":"Rising"); + + msleep(10); + return 0; +} + +/******************************************************* +Function: + Read chip version. +Input: + client: i2c device + version: buffer to keep ic firmware version +Output: + read operation return. + 2: succeed, otherwise: failed +*******************************************************/ +s32 gtp_read_version(struct i2c_client *client, u16* version) +{ + s32 ret = -1; + u8 buf[8] = {GTP_REG_VERSION >> 8, GTP_REG_VERSION & 0xff}; + + GTP_DEBUG_FUNC(); + + ret = gtp_i2c_read(client, buf, sizeof(buf)); + if (ret < 0) + { + GTP_ERROR("GTP read version failed"); + return ret; + } + + if (version) + { + *version = (buf[7] << 8) | buf[6]; + } + + if (buf[5] == 0x00) + { + GTP_INFO("IC Version: %c%c%c_%02x%02x", buf[2], buf[3], buf[4], buf[7], buf[6]); + } + else + { + if (buf[5] == 'S' || buf[5] == 's') + { + chip_gt9xxs = 1; + } + GTP_INFO("IC Version: %c%c%c%c_%02x%02x", buf[2], buf[3], buf[4], buf[5], buf[7], buf[6]); + } + return ret; +} + +/******************************************************* +Function: + I2c test Function. +Input: + client:i2c client. +Output: + Executive outcomes. + 2: succeed, otherwise failed. +*******************************************************/ +static s8 gtp_i2c_test(struct i2c_client *client) +{ + u8 test[3] = {GTP_REG_CONFIG_DATA >> 8, GTP_REG_CONFIG_DATA & 0xff}; + u8 retry = 0; + s8 ret = -1; + + GTP_DEBUG_FUNC(); + + while(retry++ < 5) + { + ret = gtp_i2c_read(client, test, 3); + if (ret > 0) + { + return ret; + } + GTP_ERROR("GTP i2c test failed time %d.",retry); + msleep(10); + } + return ret; +} + +/******************************************************* +Function: + Request gpio(INT & RST) ports. +Input: + ts: private data. +Output: + Executive outcomes. + >= 0: succeed, < 0: failed +*******************************************************/ +static s8 gtp_request_io_port(struct goodix_ts_data *ts) +{ + s32 ret = 0; + + ret = GTP_GPIO_REQUEST(ts->irq_gpio, "GTP_INT_IRQ"); + if (ret < 0) + { + GTP_ERROR("Failed to request GPIO:%d, ERRNO:%d", (s32)ts->irq_gpio, ret); + ret = -ENODEV; + } + else + { + GTP_GPIO_AS_INPUT(ts->irq_gpio); + //GTP_GPIO_AS_INT(ts->irq_gpio); + //ts->client->irq = IRQ_GPIO; + } + + ret = GTP_GPIO_REQUEST(ts->rst_gpio, "GTP_RST_PORT"); + if (ret < 0) + { + GTP_ERROR("Failed to request GPIO:%d, ERRNO:%d",(s32)ts->rst_gpio,ret); + ret = -ENODEV; + } + + GTP_GPIO_AS_INPUT(ts->rst_gpio); + gtp_reset_guitar(ts->client, 20); + + + if(ret < 0) + { + GTP_GPIO_FREE(ts->rst_gpio); + GTP_GPIO_FREE(ts->irq_gpio); + } + + return ret; +} + +/******************************************************* +Function: + Request interrupt. +Input: + ts: private data. +Output: + Executive outcomes. + 0: succeed, -1: failed. +*******************************************************/ +static s8 gtp_request_irq(struct goodix_ts_data *ts) +{ + s32 ret = -1; + //const u8 irq_table[] = GTP_IRQ_TAB; + + GTP_DEBUG("INT trigger type:%x", ts->int_trigger_type); + + ret = request_irq(ts->client->irq, + goodix_ts_irq_handler, + IRQF_SHARED, + ts->client->name, + ts); + if (ret) + { + GTP_ERROR("Request IRQ failed!ERRNO:%d.", ret); + GTP_GPIO_AS_INPUT(ts->irq_gpio); + GTP_GPIO_FREE(ts->irq_gpio); + + hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + ts->timer.function = goodix_ts_timer_handler; + hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL); + return -1; + } + else + { + gtp_irq_disable(ts); + ts->use_irq = 1; + return 0; + } +} + +/******************************************************* +Function: + Request input device Function. +Input: + ts:private data. +Output: + Executive outcomes. + 0: succeed, otherwise: failed. +*******************************************************/ +static s8 gtp_request_input_dev(struct goodix_ts_data *ts) +{ + s8 ret = -1; + s8 phys[32]; +#if GTP_HAVE_TOUCH_KEY + u8 index = 0; +#endif + + GTP_DEBUG_FUNC(); + + ts->input_dev = input_allocate_device(); + if (ts->input_dev == NULL) + { + GTP_ERROR("Failed to allocate input device."); + return -ENOMEM; + } + + ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) ; + set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit); +#if GTP_ICS_SLOT_REPORT + __set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit); + input_mt_init_slots(ts->input_dev, 10); // in case of "out of memory" +#else + //ts->input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); +#endif + +#if GTP_HAVE_TOUCH_KEY + for (index = 0; index < GTP_MAX_KEY_NUM; index++) + { + input_set_capability(ts->input_dev, EV_KEY, touch_key_array[index]); + } +#endif + +#if GTP_SLIDE_WAKEUP + input_set_capability(ts->input_dev, EV_KEY, KEY_POWER); +#endif + +#if GTP_WITH_PEN + // pen support + __set_bit(BTN_TOOL_PEN, ts->input_dev->keybit); + __set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit); + __set_bit(INPUT_PROP_POINTER, ts->input_dev->propbit); +#endif + +#if GTP_CHANGE_X2Y + GTP_SWAP(ts->abs_x_max, ts->abs_y_max); +#endif + + if (ts->swap) { + s32 temp; + temp = ts->abs_x_max; + ts->abs_x_max = ts->abs_y_max; + ts->abs_y_max = temp; + } + + if (ts->lcd_exchg) { + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, ts->abs_y_max, 0, 0); + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, ts->abs_x_max, 0, 0); + } else { + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, ts->abs_x_max, 0, 0); + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, ts->abs_y_max, 0, 0); + } + //input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0); + //input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); + input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, 0, 255, 0, 0); + + sprintf(phys, "input/ts"); + ts->input_dev->name = goodix_ts_name; + ts->input_dev->phys = phys; + ts->input_dev->id.bustype = BUS_I2C; + ts->input_dev->id.vendor = 0xDEAD; + ts->input_dev->id.product = 0xBEEF; + ts->input_dev->id.version = 10427; + + ret = input_register_device(ts->input_dev); + if (ret) + { + GTP_ERROR("Register %s input device failed", ts->input_dev->name); + return -ENODEV; + } + +#ifdef CONFIG_HAS_EARLYSUSPEND + ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + ts->early_suspend.suspend = goodix_ts_early_suspend; + ts->early_suspend.resume = goodix_ts_late_resume; + register_early_suspend(&ts->early_suspend); +#endif + + return 0; +} + + +static int wmt_check_touch_env(struct goodix_ts_data *ts) +{ + int ret = 0; + int len = 127; + char retval[128] = {0},*p=NULL,*s=NULL; + int Enable=0; + int x,y; + + // Get u-boot parameter + ret = wmt_getsyspara("wmt.io.touch", retval, &len); + if(ret){ + GTP_ERROR("Read wmt.io.touch Failed.\n"); + return -EIO; + } + + //check touch enable + p = retval; + sscanf(p,"%d:", &Enable); + if(Enable == 0){ + GTP_ERROR("Touch Screen Is Disabled.\n"); + return -ENODEV; + } + + //check touch IC name + p = strchr(p,':');p++; + if (strncmp(p, "gt9xx", strlen("gt9xx"))) { + GTP_ERROR("Can't find gt9xx!\n"); + return -ENODEV; + } + + //get firmware file name + s = strchr(p,':'); + //p = p + strlen(fw_name) + 1; + if (s > (p + strlen("gt9xx") + 1)) { + memset(ts->fw_name,0x00,sizeof(ts->fw_name)); + strncpy(ts->fw_name, p, (s-p)); + GTP_DEBUG("ts_fwname=%s\n", ts->fw_name); + } else + GTP_DEBUG("needn't firmware\n"); + + //get other needed args + p = s + 1; + ret = sscanf(p,"%d:%d:%d:%d:%d:%d:%d:%d:%x", + &ts->irq_gpio,&x,&y,&ts->rst_gpio, + &ts->swap,&ts->xdir,&ts->ydir, + &ts->max_touch_num, + &ts->i2c_addr); + if (ret != 9) + { + GTP_ERROR("Wrong format ts u-boot param(%d)!\n",ret); + return -ENODEV; + } + + ret = wmt_getsyspara("wmt.display.fb0", retval, &len); + if (!ret) { + int tmp[6]; + p = retval; + sscanf(p, "%d:[%d:%d:%d:%d:%d", &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5]); + if (tmp[4] > tmp[5]) + ts->lcd_exchg = 1; + } + + return 0; +} + +/******************************************************* +Function: + I2c probe. +Input: + client: i2c device struct. + id: device id. +Output: + Executive outcomes. + 0: succeed. +*******************************************************/ +static int goodix_ts_probe(struct platform_device *pdev) +{ + s32 ret = -1; + struct goodix_ts_data *ts; + u16 version_info; + + GTP_DEBUG_FUNC(); + + //do NOT remove these logs + GTP_INFO("GTP Driver Version: %s", GTP_DRIVER_VERSION); + GTP_INFO("GTP Driver Built@%s, %s", __TIME__, __DATE__); + GTP_INFO("GTP I2C Address: 0x%02x", i2c_connect_client->addr); + + //i2c_connect_client = client; + + if (!i2c_check_functionality(i2c_connect_client->adapter, I2C_FUNC_I2C)) + { + GTP_ERROR("I2C check functionality failed."); + return -ENODEV; + } + ts = kzalloc(sizeof(*ts), GFP_KERNEL); + if (ts == NULL) + { + GTP_ERROR("Alloc GFP_KERNEL memory failed."); + return -ENOMEM; + } + memset(ts, 0, sizeof(*ts)); + l_ts = ts; + + ret = wmt_check_touch_env(ts); + if (ret < 0) + { + GTP_ERROR("GTP get touch env failed."); + kfree(ts); + return ret; + } + + i2c_connect_client->addr = ts->i2c_addr; + INIT_WORK(&ts->work, goodix_ts_work_func); + ts->client = i2c_connect_client; + //spin_lock_init(&ts->irq_lock); // 2.6.39 later + // ts->irq_lock = SPIN_LOCK_UNLOCKED; // 2.6.39 & before + platform_set_drvdata(pdev, ts); + + ts->gtp_rawdiff_mode = 0; + + ret = gtp_request_io_port(ts); + if (ret < 0) + { + GTP_ERROR("GTP request IO port failed."); + kfree(ts); + return ret; + } + + ret = gtp_i2c_test(ts->client); + if (ret < 0) + { + GTP_ERROR("I2C communication ERROR!"); + } + +#if GTP_AUTO_UPDATE + ret = gup_init_update_proc(ts); + if (ret < 0) + { + GTP_ERROR("Create update thread error."); + } +#endif + + ret = gtp_init_panel(ts); + if (ret < 0) + { + GTP_ERROR("GTP init panel failed."); + ts->abs_x_max = GTP_MAX_WIDTH; + ts->abs_y_max = GTP_MAX_HEIGHT; + ts->int_trigger_type = GTP_INT_TRIGGER; + } + + ret = gtp_request_input_dev(ts); + if (ret < 0) + { + GTP_ERROR("GTP request input dev failed"); + } + GTP_GPIO_AS_INT(ts->irq_gpio,IRQ_TYPE_EDGE_FALLING); + ts->client->irq = IRQ_GPIO; + ret = gtp_request_irq(ts); + if (ret < 0) + { + GTP_INFO("GTP works in polling mode."); + } + else + { + GTP_INFO("GTP works in interrupt mode."); + } + + ret = gtp_read_version(ts->client, &version_info); + if (ret < 0) + { + GTP_ERROR("Read version failed."); + } + if (ts->use_irq) + { + gtp_irq_enable(ts); + } + +#if GTP_CREATE_WR_NODE + init_wr_node(ts->client); +#endif + +#if GTP_ESD_PROTECT + gtp_esd_switch(ts, SWITCH_ON); +#endif + return 0; +} + + +/******************************************************* +Function: + Goodix touchscreen driver release function. +Input: + client: i2c device struct. +Output: + Executive outcomes. 0---succeed. +*******************************************************/ +static int goodix_ts_remove(struct platform_device *pdev) +{ + struct goodix_ts_data *ts = platform_get_drvdata(pdev); + + GTP_DEBUG_FUNC(); + +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&ts->early_suspend); +#endif + +#if GTP_CREATE_WR_NODE + uninit_wr_node(); +#endif + +#if GTP_ESD_PROTECT + destroy_workqueue(gtp_esd_check_workqueue); +#endif + + if (ts) + { + if (ts->use_irq) + { + GTP_GPIO_AS_INPUT(ts->irq_gpio); + GTP_GPIO_FREE(ts->irq_gpio); + free_irq(ts->client->irq, ts); + } + else + { + hrtimer_cancel(&ts->timer); + } + } + + GTP_GPIO_FREE(ts->rst_gpio); + GTP_INFO("GTP driver removing..."); + input_unregister_device(ts->input_dev); + kfree(ts); + + return 0; +} + +#ifdef CONFIG_HAS_EARLYSUSPEND +/******************************************************* +Function: + Early suspend function. +Input: + h: early_suspend struct. +Output: + None. +*******************************************************/ +static void goodix_ts_early_suspend(struct early_suspend *h) +{ + struct goodix_ts_data *ts; + s8 ret = -1; + ts = container_of(h, struct goodix_ts_data, early_suspend); + + GTP_DEBUG_FUNC(); + +#if GTP_ESD_PROTECT + ts->gtp_is_suspend = 1; + gtp_esd_switch(ts, SWITCH_OFF); +#endif + +#if GTP_SLIDE_WAKEUP + ret = gtp_enter_doze(ts); +#else + if (ts->use_irq) + { + gtp_irq_disable(ts); + } + else + { + hrtimer_cancel(&ts->timer); + } + ret = gtp_enter_sleep(ts); +#endif + if (ret < 0) + { + GTP_ERROR("GTP early suspend failed."); + } + // to avoid waking up while not sleeping + // delay 48 + 10ms to ensure reliability + msleep(58); +} + +/******************************************************* +Function: + Late resume function. +Input: + h: early_suspend struct. +Output: + None. +*******************************************************/ +static void goodix_ts_late_resume(struct early_suspend *h) +{ + struct goodix_ts_data *ts; + s8 ret = -1; + ts = container_of(h, struct goodix_ts_data, early_suspend); + + GTP_DEBUG_FUNC(); + + ret = gtp_wakeup_sleep(ts); + +#if GTP_SLIDE_WAKEUP + doze_status = DOZE_DISABLED; +#endif + + if (ret < 0) + { + GTP_ERROR("GTP later resume failed."); + } + + if (ts->use_irq) + { + gtp_irq_enable(ts); + } + else + { + hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL); + } + +#if GTP_ESD_PROTECT + ts->gtp_is_suspend = 0; + gtp_esd_switch(ts, SWITCH_ON); +#endif +} +#endif + +#if 1 +/******************************************************* +Function: + Suspend function. +Input: + client: i2c_client struct. + mesg: pm_message_t struct. +Output: + None. +*******************************************************/ +static int goodix_ts_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct goodix_ts_data *ts; + ts = dev_get_drvdata(&pdev->dev); + + GTP_DEBUG_FUNC(); + +#if GTP_ESD_PROTECT + ts->gtp_is_suspend = 1; + gtp_esd_switch(ts, SWITCH_OFF); +#endif + +#if GTP_SLIDE_WAKEUP + ret = gtp_enter_doze(ts); +#else + if (ts->use_irq) + { + gtp_irq_disable(ts); + } + else + { + hrtimer_cancel(&ts->timer); + } +#endif + // to avoid waking up while not sleeping + // delay 48 + 10ms to ensure reliability + l_suspend = 1; + return 0; +} + + +/******************************************************* +Function: + Late resume function. +Input: + client: i2c_client struct. +Output: + None. +*******************************************************/ +static int goodix_ts_resume(struct platform_device *pdev) +{ + struct goodix_ts_data *ts; + s8 ret = -1; + ts = dev_get_drvdata(&pdev->dev); + + GTP_DEBUG_FUNC(); + + GTP_GPIO_AS_INPUT(ts->irq_gpio); + GTP_GPIO_AS_INPUT(ts->rst_gpio); + gtp_reset_guitar(ts->client, 20); + + ret = gtp_i2c_test(ts->client); + if (ret < 0) + { + GTP_ERROR("I2C communication ERROR!"); + } + +#if GTP_SLIDE_WAKEUP + doze_status = DOZE_DISABLED; +#endif + + if (ts->use_irq) + { + GTP_GPIO_AS_INT(ts->irq_gpio,IRQ_TYPE_EDGE_FALLING); + gtp_irq_enable(ts); + } + else + { + hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL); + } + +#if GTP_ESD_PROTECT + ts->gtp_is_suspend = 0; + gtp_esd_switch(ts, SWITCH_ON); +#endif + l_suspend = 0; + return 0; +} +#endif + +#if GTP_ESD_PROTECT +/******************************************************* +Function: + switch on & off esd delayed work +Input: + client: i2c device + on: SWITCH_ON / SWITCH_OFF +Output: + void +*********************************************************/ +void gtp_esd_switch(struct goodix_ts_data * ts, s32 on) +{ + + if (SWITCH_ON == on) // switch on esd + { + if (!ts->esd_running) + { + ts->esd_running = 1; + GTP_INFO("Esd started"); + queue_delayed_work(gtp_esd_check_workqueue, >p_esd_check_work, GTP_ESD_CHECK_CIRCLE); + } + } + else // switch off esd + { + if (ts->esd_running) + { + ts->esd_running = 0; + GTP_INFO("Esd cancelled"); + cancel_delayed_work_sync(>p_esd_check_work); + } + } +} + +/******************************************************* +Function: + Initialize external watchdog for esd protect +Input: + client: i2c device. +Output: + result of i2c write operation. + 1: succeed, otherwise: failed +*********************************************************/ +static s32 gtp_init_ext_watchdog(struct i2c_client *client) +{ + u8 opr_buffer[4] = {0x80, 0x40, 0xAA, 0xAA}; + + struct i2c_msg msg; // in case of recursively reset by calling gtp_i2c_write + s32 ret = -1; + s32 retries = 0; + + GTP_DEBUG("Init external watchdog..."); + GTP_DEBUG_FUNC(); + + msg.flags = !I2C_M_RD; + msg.addr = client->addr; + msg.len = 4; + msg.buf = opr_buffer; + + while(retries < 5) + { + ret = i2c_transfer(client->adapter, &msg, 1); + if (ret == 1) + { + return 1; + } + retries++; + } + if (retries >= 5) + { + GTP_ERROR("init external watchdog failed!"); + } + return 0; +} + +/******************************************************* +Function: + Esd protect function. + Added external watchdog by meta, 2013/03/07 +Input: + work: delayed work +Output: + None. +*******************************************************/ +static void gtp_esd_check_func(struct work_struct *work) +{ + s32 i; + s32 ret = -1; + struct goodix_ts_data *ts = NULL; + u8 test[4] = {0x80, 0x40}; + + GTP_DEBUG_FUNC(); + + ts = container_of(work, struct goodix_ts_data, work); + + if (ts->gtp_is_suspend) + { + ts->esd_running = 0; + GTP_INFO("Esd terminated!"); + return; + } + + for (i = 0; i < 3; i++) + { + ret = gtp_i2c_read(ts->client, test, 4); + + GTP_DEBUG("0x8040 = 0x%02X, 0x8041 = 0x%02X", test[2], test[3]); + if ((ret < 0)) + { + // IIC communication problem + continue; + } + else + { + if ((test[2] == 0xAA) || (test[3] != 0xAA)) + { + // IC works abnormally.. + i = 3; + break; + } + else + { + // IC works normally, Write 0x8040 0xAA, feed the dog + test[2] = 0xAA; + gtp_i2c_write(ts->client, test, 3); + break; + } + } + } + if (i >= 3) + { + GTP_ERROR("IC Working ABNORMALLY, Resetting Guitar..."); + gtp_reset_guitar(ts->client, 50); + } + + if(!ts->gtp_is_suspend) + { + queue_delayed_work(gtp_esd_check_workqueue, >p_esd_check_work, GTP_ESD_CHECK_CIRCLE); + } + else + { + GTP_INFO("Esd terminated!"); + ts->esd_running = 0; + } + return; +} +#endif + +static void gt9xx_release(struct device *device) +{ + return; +} + + +static struct platform_device gt9xx_device = { + .name = GTP_I2C_NAME, + .id = 0, + .dev = {.release = gt9xx_release}, +}; + +static struct platform_driver gt9xx_driver = { + .driver = { + .name = GTP_I2C_NAME, + .owner = THIS_MODULE, + }, + .probe = goodix_ts_probe, + .remove = goodix_ts_remove, + .suspend = goodix_ts_suspend, + .resume = goodix_ts_resume, +}; + + +struct i2c_board_info ts_i2c_board_info = { + .type = GTP_I2C_NAME, + .flags = 0x00, + .addr = GTP_I2C_ADDR, + .platform_data = NULL, + .archdata = NULL, + .irq = -1, +}; + +static int ts_i2c_register_device (void) +{ + struct i2c_board_info *ts_i2c_bi; + struct i2c_adapter *adapter = NULL; + + ts_i2c_bi = &ts_i2c_board_info; + adapter = i2c_get_adapter(0x01);/*in bus 1*/ + if (NULL == adapter) { + GTP_ERROR("can not get i2c adapter, client address error."); + return -1; + } + i2c_connect_client = i2c_new_device(adapter, ts_i2c_bi); + if (i2c_connect_client == NULL) { + GTP_ERROR("allocate i2c client failed."); + return -1; + } + i2c_put_adapter(adapter); + return 0; +} + +static void ts_i2c_unregister_device(void) +{ + if (i2c_connect_client != NULL) + { + i2c_unregister_device(i2c_connect_client); + i2c_connect_client = NULL; + } +} + +/******************************************************* +Function: + Driver Install function. +Input: + None. +Output: + Executive Outcomes. 0---succeed. +********************************************************/ +static int __devinit goodix_ts_init(void) +{ + s32 ret; + + GTP_DEBUG_FUNC(); + GTP_INFO("GTP driver installing..."); + goodix_wq = create_singlethread_workqueue("goodix_wq"); + if (!goodix_wq) + { + GTP_ERROR("Creat workqueue failed."); + return -ENOMEM; + } +#if GTP_ESD_PROTECT + INIT_DELAYED_WORK(>p_esd_check_work, gtp_esd_check_func); + gtp_esd_check_workqueue = create_workqueue("gtp_esd_check"); +#endif + if (ts_i2c_register_device()<0) + { + destroy_workqueue(goodix_wq); + GTP_ERROR("Error to run ts_i2c_register_device()!\n"); + return -1; + } + + ret = platform_device_register(>9xx_device); + if(ret){ + GTP_ERROR("register platform drivver failed!\n"); + goto err_register_platdev; + } + + ret = platform_driver_register(>9xx_driver); + if(ret){ + GTP_ERROR("register platform device failed!\n"); + goto err_register_platdriver; + } + return 0; +err_register_platdriver: + platform_device_unregister(>9xx_device); +err_register_platdev: + destroy_workqueue(goodix_wq); + ts_i2c_unregister_device(); + + return ret; +} + +/******************************************************* +Function: + Driver uninstall function. +Input: + None. +Output: + Executive Outcomes. 0---succeed. +********************************************************/ +static void __exit goodix_ts_exit(void) +{ + GTP_DEBUG_FUNC(); + GTP_INFO("GTP driver exited."); + ts_i2c_unregister_device(); + platform_driver_unregister(>9xx_driver); + platform_device_unregister(>9xx_device); + if (goodix_wq) + { + destroy_workqueue(goodix_wq); + } +} + +late_initcall(goodix_ts_init); +module_exit(goodix_ts_exit); + +MODULE_DESCRIPTION("GTP Series Driver"); +MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/gt9xx.h b/ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/gt9xx.h new file mode 100755 index 00000000..c58b4800 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/gt9xx.h @@ -0,0 +1,278 @@ +/* drivers/input/touchscreen/gt9xx.h + * + * 2010 - 2013 Goodix Technology. + * + * 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 a reference + * to you, when you are integrating the GOODiX's CTP IC into your system, + * 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. + * + */ + +#ifndef _GOODIX_GT9XX_H_ +#define _GOODIX_GT9XX_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif + +struct goodix_ts_data { + //spinlock_t irq_lock; + struct i2c_client *client; + struct input_dev *input_dev; + struct hrtimer timer; + struct work_struct work; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif + char fw_name[20]; + s32 i2c_addr; + s32 irq_is_disable; + s32 use_irq; + s32 irq_gpio; + s32 rst_gpio; + s32 abs_x_max; + s32 abs_y_max; + s32 max_touch_num; + u8 int_trigger_type; + s32 swap; + s32 xdir; + s32 ydir; + s32 lcd_exchg; + u8 green_wake_mode; + u8 chip_type; + u8 enter_update; + u8 gtp_is_suspend; + u8 gtp_rawdiff_mode; + u8 gtp_cfg_len; + u8 fixed_cfg; + u8 esd_running; + u8 fw_error; +}; + +extern u16 show_len; +extern u16 total_len; +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); + +//***************************PART1:ON/OFF define******************************* +#define GTP_CUSTOM_CFG 0 +#define GTP_CHANGE_X2Y 0 +#define GTP_DRIVER_SEND_CFG 1 +#define GTP_HAVE_TOUCH_KEY 0 +#define GTP_POWER_CTRL_SLEEP 0 +#define GTP_ICS_SLOT_REPORT 0 + +#define GTP_AUTO_UPDATE 1 // auto updated by .bin file as default +#define GTP_HEADER_FW_UPDATE 0 // auto updated by head_fw_array in gt9xx_firmware.h, function together with GTP_AUTO_UPDATE + +#define GTP_CREATE_WR_NODE 1 +#define GTP_ESD_PROTECT 0 +#define GTP_WITH_PEN 0 + +#define GTP_SLIDE_WAKEUP 0 +#define GTP_DBL_CLK_WAKEUP 0 // double-click wakeup, function together with GTP_SLIDE_WAKEUP + +#define GTP_DEBUG_ON 0 +#define GTP_DEBUG_ARRAY_ON 0 +#define GTP_DEBUG_FUNC_ON 0 + +//*************************** PART2:TODO define ********************************** +// STEP_1(REQUIRED): Define Configuration Information Group(s) +// Sensor_ID Map: +/* sensor_opt1 sensor_opt2 Sensor_ID + GND GND 0 + VDDIO GND 1 + NC GND 2 + GND NC/300K 3 + VDDIO NC/300K 4 + NC NC/300K 5 +*/ +// TODO: define your own default or for Sensor_ID == 0 config here. +// The predefined one is just a sample config, which is not suitable for your tp in most cases. +#define CTP_CFG_GROUP1 {\ + 0x42,0x00,0x03,0x00,0x04,0x0A,0x34,0x00,0x01,0x3F,\ + 0x28,0x0F,0x50,0x3C,0x03,0x05,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x16,0x18,0x1C,0x14,0x8B,0x2A,0x0E,\ + 0x2D,0x3D,0x12,0x0C,0x00,0x00,0x00,0x01,0x03,0x1D,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x20,0x3D,0x94,0xC5,0x02,0x08,0x00,0x00,0x04,\ + 0x9A,0x22,0x00,0x8F,0x26,0x00,0x81,0x2C,0x00,0x77,\ + 0x32,0x00,0x6E,0x39,0x00,0x6E,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x0A,0x08,0x06,0x04,0x02,0x0C,0x0E,0x10,\ + 0x12,0x14,0x16,0x18,0x1A,0x1C,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x02,0x04,0x06,0x08,0x0A,0x0C,0x0F,\ + 0x10,0x12,0x13,0x16,0x18,0x1C,0x1D,0x1E,0x1F,0x20,\ + 0x21,0x22,0x24,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x9D,0x01\ + } + +/* +#define CTP_CFG_GROUP1 {\ + 0x00,0x00,0x03,0x00,0x04,0x0A,0x35,0x00,0x01,0x08,\ + 0x14,0x05,0x37,0x28,0x03,0x05,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x16,0x18,0x1A,0x14,0x8B,0x2A,0x0E,\ + 0x63,0x5E,0x31,0x0D,0x00,0x00,0x02,0xB9,0x02,0x2D,\ + 0x00,0x00,0x00,0x00,0x00,0x03,0x64,0x32,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x0A,0x08,0x06,0x04,0x02,0x0C,0x0E,0x10,\ + 0x12,0x14,0x16,0x18,0x1A,0x1C,0xFF,0xFF,0xFF,0xFF,\ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\ + 0xFF,0xFF,0x00,0x02,0x04,0x06,0x08,0x0A,0x0C,0x0F,\ + 0x10,0x12,0x13,0x16,0x18,0x1C,0x1D,0x1E,0x1F,0x20,\ + 0x21,0x22,0x24,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\ + 0xFF,0xFF,0xFF,0xFF,0x4A,0x01\ + } +*/ + +// TODO: define your config for Sensor_ID == 1 here, if needed +#define CTP_CFG_GROUP2 {\ + } +// TODO: define your config for Sensor_ID == 2 here, if needed +#define CTP_CFG_GROUP3 {\ + } + +// TODO: define your config for Sensor_ID == 3 here, if needed +#define CTP_CFG_GROUP4 {\ + } + +// TODO: define your config for Sensor_ID == 4 here, if needed +#define CTP_CFG_GROUP5 {\ + } + +// TODO: define your config for Sensor_ID == 5 here, if needed +#define CTP_CFG_GROUP6 {\ + } + +// STEP_2(REQUIRED): Customize your I/O ports & I/O operations +#define GTP_RST_PORT S5PV210_GPJ3(6) +#define GTP_INT_PORT S5PV210_GPH1(3) +#define GTP_INT_IRQ gpio_to_irq(GTP_INT_PORT) +#define GTP_INT_CFG S3C_GPIO_SFN(0xF) + +#define GTP_GPIO_AS_INPUT(pin) do{\ + gpio_direction_input(pin);\ + wmt_gpio_setpull(pin, WMT_GPIO_PULL_NONE);\ + }while(0) +#define GTP_GPIO_AS_INT(pin,type) do{\ + GTP_GPIO_AS_INPUT(pin);\ + wmt_gpio_set_irq_type(pin,type);\ + }while(0) +#define GTP_GPIO_GET_VALUE(pin) gpio_get_value(pin) +#define GTP_GPIO_OUTPUT(pin,level) gpio_direction_output(pin,level) +#define GTP_GPIO_REQUEST(pin, label) gpio_request(pin, label) +#define GTP_GPIO_FREE(pin) gpio_free(pin) +#define GTP_IRQ_TAB {IRQ_TYPE_EDGE_RISING, IRQ_TYPE_EDGE_FALLING, IRQ_TYPE_LEVEL_LOW, IRQ_TYPE_LEVEL_HIGH} + +// STEP_3(optional): Specify your special config info if needed +#if GTP_CUSTOM_CFG + #define GTP_MAX_HEIGHT 800 + #define GTP_MAX_WIDTH 480 + #define GTP_INT_TRIGGER 0 // 0: Rising 1: Falling +#else + #define GTP_MAX_HEIGHT 4096 + #define GTP_MAX_WIDTH 4096 + #define GTP_INT_TRIGGER 1 +#endif +#define GTP_MAX_TOUCH 5 +#define GTP_ESD_CHECK_CIRCLE 2000 // jiffy: ms + +// STEP_4(optional): If keys are available and reported as keys, config your key info here +#if GTP_HAVE_TOUCH_KEY + #define GTP_KEY_TAB {KEY_MENU, KEY_HOME, KEY_BACK} +#endif + +//***************************PART3:OTHER define********************************* +#define GTP_DRIVER_VERSION "V1.8<2013/06/08>" +#define GTP_I2C_NAME "Goodix-TS" +#define GTP_I2C_ADDR 0x5d +#define GTP_POLL_TIME 10 // jiffy: ms +#define GTP_ADDR_LENGTH 2 +#define GTP_CONFIG_MIN_LENGTH 186 +#define GTP_CONFIG_MAX_LENGTH 240 +#define FAIL 0 +#define SUCCESS 1 +#define SWITCH_OFF 0 +#define SWITCH_ON 1 + +// Registers define +#define GTP_READ_COOR_ADDR 0x814E +#define GTP_REG_SLEEP 0x8040 +#define GTP_REG_SENSOR_ID 0x814A +#define GTP_REG_CONFIG_DATA 0x8047 +#define GTP_REG_VERSION 0x8140 + +#define RESOLUTION_LOC 3 +#define TRIGGER_LOC 8 + +#define CFG_GROUP_LEN(p_cfg_grp) (sizeof(p_cfg_grp) / sizeof(p_cfg_grp[0])) +// Log define +#define GTP_INFO(fmt,arg...) printk("<<-GTP-INFO->> "fmt"\n",##arg) +#define GTP_ERROR(fmt,arg...) printk("<<-GTP-ERROR->> "fmt"\n",##arg) +#define GTP_DEBUG(fmt,arg...) do{\ + if(GTP_DEBUG_ON)\ + printk("<<-GTP-DEBUG->> [%d]"fmt"\n",__LINE__, ##arg);\ + }while(0) +#define GTP_DEBUG_ARRAY(array, num) do{\ + s32 i;\ + u8* a = array;\ + if(GTP_DEBUG_ARRAY_ON)\ + {\ + printk("<<-GTP-DEBUG-ARRAY->>\n");\ + for (i = 0; i < (num); i++)\ + {\ + printk("%02x ", (a)[i]);\ + if ((i + 1 ) %10 == 0)\ + {\ + printk("\n");\ + }\ + }\ + printk("\n");\ + }\ + }while(0) +#define GTP_DEBUG_FUNC() do{\ + if(GTP_DEBUG_FUNC_ON)\ + printk("<<-GTP-FUNC->> Func:%s@Line:%d\n",__func__,__LINE__);\ + }while(0) +#define GTP_SWAP(x, y) do{\ + typeof(x) z = x;\ + x = y;\ + y = z;\ + }while (0) + +//*****************************End of Part III******************************** + +#endif /* _GOODIX_GT9XX_H_ */ diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/gt9xx_firmware.h b/ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/gt9xx_firmware.h new file mode 100755 index 00000000..3998bf00 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/gt9xx_firmware.h @@ -0,0 +1,6 @@ +// make sense only when GTP_HEADER_FW_UPDATE & GTP_AUTO_UPDATE are enabled +// define your own firmware array here +const unsigned char header_fw_array[] = +{ + +}; \ No newline at end of file diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/gt9xx_update.c b/ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/gt9xx_update.c new file mode 100755 index 00000000..88daf209 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/gt9xx_update.c @@ -0,0 +1,1939 @@ +/* drivers/input/touchscreen/gt9xx_update.c + * + * 2010 - 2012 Goodix Technology. + * + * 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 a reference + * to you, when you are integrating the GOODiX's CTP IC into your system, + * 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. + * + * Latest Version:1.6 + * Author: andrew@goodix.com + * Revision Record: + * V1.0: + * first release. By Andrew, 2012/08/31 + * V1.2: + * add force update,GT9110P pid map. By Andrew, 2012/10/15 + * V1.4: + * 1. add config auto update function; + * 2. modify enter_update_mode; + * 3. add update file cal checksum. + * By Andrew, 2012/12/12 + * V1.6: + * 1. replace guitar_client with i2c_connect_client; + * 2. support firmware header array update. + * By Meta, 2013/03/11 + */ +#include +#include "gt9xx.h" + +#if GTP_HEADER_FW_UPDATE +#include +#include +#include "gt9xx_firmware.h" +#endif + +#define GUP_REG_HW_INFO 0x4220 +#define GUP_REG_FW_MSG 0x41E4 +#define GUP_REG_PID_VID 0x8140 + +#define GUP_SEARCH_FILE_TIMES 2 +#define UPDATE_FILE_PATH_2 "/system/etc/firmware/_goodix_update_.bin" +#define UPDATE_FILE_PATH_1 "/extsdcard/_goodix_update_.bin" + +#define CONFIG_FILE_PATH_1 "/extsdcard/_goodix_config_.cfg" +#define CONFIG_FILE_PATH_2 "/system/etc/firmware/_goodix_config_.cfg" + +#define FW_HEAD_LENGTH 14 +#define FW_SECTION_LENGTH 0x2000 +#define FW_DSP_ISP_LENGTH 0x1000 +#define FW_DSP_LENGTH 0x1000 +#define FW_BOOT_LENGTH 0x800 + +#define PACK_SIZE 256 +#define MAX_FRAME_CHECK_TIME 5 + +#define _bRW_MISCTL__SRAM_BANK 0x4048 +#define _bRW_MISCTL__MEM_CD_EN 0x4049 +#define _bRW_MISCTL__CACHE_EN 0x404B +#define _bRW_MISCTL__TMR0_EN 0x40B0 +#define _rRW_MISCTL__SWRST_B0_ 0x4180 +#define _bWO_MISCTL__CPU_SWRST_PULSE 0x4184 +#define _rRW_MISCTL__BOOTCTL_B0_ 0x4190 +#define _rRW_MISCTL__BOOT_OPT_B0_ 0x4218 +#define _rRW_MISCTL__BOOT_CTL_ 0x5094 + +#define FAIL 0 +#define SUCCESS 1 + +#pragma pack(1) +typedef struct +{ + u8 hw_info[4]; //hardware info// + u8 pid[8]; //product id // + u16 vid; //version id // +}st_fw_head; +#pragma pack() + +typedef struct +{ + u8 force_update; + u8 fw_flag; + struct file *file; + struct file *cfg_file; + st_fw_head ic_fw_msg; + mm_segment_t old_fs; +}st_update_msg; + +st_update_msg update_msg; +u16 show_len; +u16 total_len; +u8 got_file_flag = 0; +u8 searching_file = 0; +extern u8 config[GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH]; +extern void gtp_reset_guitar(struct i2c_client *client, s32 ms); +extern s32 gtp_send_cfg(struct goodix_ts_data * ts); +extern struct i2c_client * i2c_connect_client; +extern struct goodix_ts_data *l_ts; +extern void gtp_irq_enable(struct goodix_ts_data *ts); +extern void gtp_irq_disable(struct goodix_ts_data *ts); +extern s32 gtp_i2c_read_dbl_check(struct i2c_client *, u16, u8 *, int); +#if GTP_ESD_PROTECT +extern void gtp_esd_switch(struct i2c_client *, s32); +#endif +/******************************************************* +Function: + Read data from the i2c slave device. +Input: + client: i2c device. + buf[0~1]: read start address. + buf[2~len-1]: read data buffer. + len: GTP_ADDR_LENGTH + read bytes count +Output: + numbers of i2c_msgs to transfer: + 2: succeed, otherwise: failed +*********************************************************/ +s32 gup_i2c_read(struct i2c_client *client, u8 *buf, s32 len) +{ + struct i2c_msg msgs[2]; + s32 ret=-1; + s32 retries = 0; + + GTP_DEBUG_FUNC(); + + msgs[0].flags = !I2C_M_RD; + msgs[0].addr = client->addr; + msgs[0].len = GTP_ADDR_LENGTH; + msgs[0].buf = &buf[0]; + //msgs[0].scl_rate = 300 * 1000; // for Rockchip + + msgs[1].flags = I2C_M_RD; + msgs[1].addr = client->addr; + msgs[1].len = len - GTP_ADDR_LENGTH; + msgs[1].buf = &buf[GTP_ADDR_LENGTH]; + //msgs[1].scl_rate = 300 * 1000; + + while(retries < 5) + { + ret = i2c_transfer(client->adapter, msgs, 2); + if(ret == 2)break; + retries++; + } + + return ret; +} + +/******************************************************* +Function: + Write data to the i2c slave device. +Input: + client: i2c device. + buf[0~1]: write start address. + buf[2~len-1]: data buffer + len: GTP_ADDR_LENGTH + write bytes count +Output: + numbers of i2c_msgs to transfer: + 1: succeed, otherwise: failed +*********************************************************/ +s32 gup_i2c_write(struct i2c_client *client,u8 *buf,s32 len) +{ + struct i2c_msg msg; + s32 ret=-1; + s32 retries = 0; + + GTP_DEBUG_FUNC(); + + msg.flags = !I2C_M_RD; + msg.addr = client->addr; + msg.len = len; + msg.buf = buf; + //msg.scl_rate = 300 * 1000; // for Rockchip + + while(retries < 5) + { + ret = i2c_transfer(client->adapter, &msg, 1); + if (ret == 1)break; + retries++; + } + + return ret; +} + +static s32 gup_init_panel(struct goodix_ts_data *ts) +{ + s32 ret = 0; + s32 i = 0; + u8 check_sum = 0; + u8 opr_buf[16]; + u8 sensor_id = 0; + + u8 cfg_info_group1[] = CTP_CFG_GROUP1; + u8 cfg_info_group2[] = CTP_CFG_GROUP2; + u8 cfg_info_group3[] = CTP_CFG_GROUP3; + u8 cfg_info_group4[] = CTP_CFG_GROUP4; + u8 cfg_info_group5[] = CTP_CFG_GROUP5; + u8 cfg_info_group6[] = CTP_CFG_GROUP6; + u8 *send_cfg_buf[] = {cfg_info_group1, cfg_info_group2, cfg_info_group3, + cfg_info_group4, cfg_info_group5, cfg_info_group6}; + u8 cfg_info_len[] = { CFG_GROUP_LEN(cfg_info_group1), + CFG_GROUP_LEN(cfg_info_group2), + CFG_GROUP_LEN(cfg_info_group3), + CFG_GROUP_LEN(cfg_info_group4), + CFG_GROUP_LEN(cfg_info_group5), + CFG_GROUP_LEN(cfg_info_group6)}; + + if ((!cfg_info_len[1]) && (!cfg_info_len[2]) && + (!cfg_info_len[3]) && (!cfg_info_len[4]) && + (!cfg_info_len[5])) + { + sensor_id = 0; + } + else + { + ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_SENSOR_ID, &sensor_id, 1); + if (SUCCESS == ret) + { + if (sensor_id >= 0x06) + { + GTP_ERROR("Invalid sensor_id(0x%02X), No Config Sent!", sensor_id); + return -1; + } + } + else + { + GTP_ERROR("Failed to get sensor_id, No config sent!"); + return -1; + } + } + + GTP_DEBUG("Sensor_ID: %d", sensor_id); + + ts->gtp_cfg_len = cfg_info_len[sensor_id]; + + if (ts->gtp_cfg_len < GTP_CONFIG_MIN_LENGTH) + { + GTP_ERROR("Sensor_ID(%d) matches with NULL or INVALID CONFIG GROUP! NO Config Sent! You need to check you header file CFG_GROUP section!", sensor_id); + return -1; + } + + ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA, &opr_buf[0], 1); + + if (ret == SUCCESS) + { + GTP_DEBUG("CFG_GROUP%d Config Version: %d, IC Config Version: %d", sensor_id+1, + send_cfg_buf[sensor_id][0], opr_buf[0]); + + send_cfg_buf[sensor_id][0] = opr_buf[0]; + ts->fixed_cfg = 0; + /* + if (opr_buf[0] < 90) + { + grp_cfg_version = send_cfg_buf[sensor_id][0]; // backup group config version + send_cfg_buf[sensor_id][0] = 0x00; + ts->fixed_cfg = 0; + } + else // treated as fixed config, not send config + { + GTP_INFO("Ic fixed config with config version(%d)", opr_buf[0]); + ts->fixed_cfg = 1; + }*/ + } + else + { + GTP_ERROR("Failed to get ic config version!No config sent!"); + return -1; + } + + memset(&config[GTP_ADDR_LENGTH], 0, GTP_CONFIG_MAX_LENGTH); + memcpy(&config[GTP_ADDR_LENGTH], send_cfg_buf[sensor_id], ts->gtp_cfg_len); + + GTP_DEBUG("X_MAX = %d, Y_MAX = %d, TRIGGER = 0x%02x", + ts->abs_x_max, ts->abs_y_max, ts->int_trigger_type); + + config[RESOLUTION_LOC] = (u8)GTP_MAX_WIDTH; + config[RESOLUTION_LOC + 1] = (u8)(GTP_MAX_WIDTH>>8); + config[RESOLUTION_LOC + 2] = (u8)GTP_MAX_HEIGHT; + config[RESOLUTION_LOC + 3] = (u8)(GTP_MAX_HEIGHT>>8); + + if (GTP_INT_TRIGGER == 0) //RISING + { + config[TRIGGER_LOC] &= 0xfe; + } + else if (GTP_INT_TRIGGER == 1) //FALLING + { + config[TRIGGER_LOC] |= 0x01; + } + + check_sum = 0; + for (i = GTP_ADDR_LENGTH; i < ts->gtp_cfg_len; i++) + { + check_sum += config[i]; + } + config[ts->gtp_cfg_len] = (~check_sum) + 1; + + GTP_DEBUG_FUNC(); + ret = gtp_send_cfg(ts); + if (ret < 0) + { + GTP_ERROR("Send config error."); + } + + msleep(10); + return 0; +} + + +static u8 gup_get_ic_msg(struct i2c_client *client, u16 addr, u8* msg, s32 len) +{ + s32 i = 0; + + msg[0] = (addr >> 8) & 0xff; + msg[1] = addr & 0xff; + + for (i = 0; i < 5; i++) + { + if (gup_i2c_read(client, msg, GTP_ADDR_LENGTH + len) > 0) + { + break; + } + } + + if (i >= 5) + { + GTP_ERROR("Read data from 0x%02x%02x failed!", msg[0], msg[1]); + return FAIL; + } + + return SUCCESS; +} + +static u8 gup_set_ic_msg(struct i2c_client *client, u16 addr, u8 val) +{ + s32 i = 0; + u8 msg[3]; + + msg[0] = (addr >> 8) & 0xff; + msg[1] = addr & 0xff; + msg[2] = val; + + for (i = 0; i < 5; i++) + { + if (gup_i2c_write(client, msg, GTP_ADDR_LENGTH + 1) > 0) + { + break; + } + } + + if (i >= 5) + { + GTP_ERROR("Set data to 0x%02x%02x failed!", msg[0], msg[1]); + return FAIL; + } + + return SUCCESS; +} + +static u8 gup_get_ic_fw_msg(struct i2c_client *client) +{ + s32 ret = -1; + u8 retry = 0; + u8 buf[16]; + u8 i; + + // step1:get hardware info + ret = gtp_i2c_read_dbl_check(client, GUP_REG_HW_INFO, &buf[GTP_ADDR_LENGTH], 4); + if (FAIL == ret) + { + GTP_ERROR("[get_ic_fw_msg]get hw_info failed,exit"); + return FAIL; + } + + // buf[2~5]: 00 06 90 00 + // hw_info: 00 90 06 00 + for(i=0; i<4; i++) + { + update_msg.ic_fw_msg.hw_info[i] = buf[GTP_ADDR_LENGTH + 3 - i]; + } + GTP_DEBUG("IC Hardware info:%02x%02x%02x%02x", update_msg.ic_fw_msg.hw_info[0], update_msg.ic_fw_msg.hw_info[1], + update_msg.ic_fw_msg.hw_info[2], update_msg.ic_fw_msg.hw_info[3]); + // step2:get firmware message + for(retry=0; retry<2; retry++) + { + ret = gup_get_ic_msg(client, GUP_REG_FW_MSG, buf, 1); + if(FAIL == ret) + { + GTP_ERROR("Read firmware message fail."); + return ret; + } + + update_msg.force_update = buf[GTP_ADDR_LENGTH]; + if((0xBE != update_msg.force_update)&&(!retry)) + { + GTP_INFO("The check sum in ic is error."); + GTP_INFO("The IC will be updated by force."); + continue; + } + break; + } + GTP_DEBUG("IC force update flag:0x%x", update_msg.force_update); + + // step3:get pid & vid + ret = gtp_i2c_read_dbl_check(client, GUP_REG_PID_VID, &buf[GTP_ADDR_LENGTH], 6); + if (FAIL == ret) + { + GTP_ERROR("[get_ic_fw_msg]get pid & vid failed,exit"); + return FAIL; + } + + memset(update_msg.ic_fw_msg.pid, 0, sizeof(update_msg.ic_fw_msg.pid)); + memcpy(update_msg.ic_fw_msg.pid, &buf[GTP_ADDR_LENGTH], 4); + GTP_DEBUG("IC Product id:%s", update_msg.ic_fw_msg.pid); + + //GT9XX PID MAPPING + /*|-----FLASH-----RAM-----| + |------918------918-----| + |------968------968-----| + |------913------913-----| + |------913P-----913P----| + |------927------927-----| + |------927P-----927P----| + |------9110-----9110----| + |------9110P----9111----|*/ + if(update_msg.ic_fw_msg.pid[0] != 0) + { + if(!memcmp(update_msg.ic_fw_msg.pid, "9111", 4)) + { + GTP_DEBUG("IC Mapping Product id:%s", update_msg.ic_fw_msg.pid); + memcpy(update_msg.ic_fw_msg.pid, "9110P", 5); + } + } + + update_msg.ic_fw_msg.vid = buf[GTP_ADDR_LENGTH+4] + (buf[GTP_ADDR_LENGTH+5]<<8); + GTP_DEBUG("IC version id:%04x", update_msg.ic_fw_msg.vid); + + return SUCCESS; +} + +s32 gup_enter_update_mode(struct goodix_ts_data *ts) +{ + s32 ret = -1; + s32 retry = 0; + u8 rd_buf[3]; + + //step1:RST output low last at least 2ms + GTP_GPIO_OUTPUT(ts->rst_gpio, 0); + msleep(2); + + //step2:select I2C slave addr,INT:0--0xBA;1--0x28. + GTP_GPIO_OUTPUT(ts->irq_gpio, (ts->client->addr == 0x14)); + msleep(2); + + //step3:RST output high reset guitar + GTP_GPIO_OUTPUT(ts->rst_gpio, 1); + + //20121211 modify start + msleep(5); + while(retry++ < 200) + { + //step4:Hold ss51 & dsp + ret = gup_set_ic_msg(ts->client, _rRW_MISCTL__SWRST_B0_, 0x0C); + if(ret <= 0) + { + GTP_DEBUG("Hold ss51 & dsp I2C error,retry:%d", retry); + continue; + } + + //step5:Confirm hold + ret = gup_get_ic_msg(ts->client, _rRW_MISCTL__SWRST_B0_, rd_buf, 1); + if(ret <= 0) + { + GTP_DEBUG("Hold ss51 & dsp I2C error,retry:%d", retry); + continue; + } + if(0x0C == rd_buf[GTP_ADDR_LENGTH]) + { + GTP_DEBUG("Hold ss51 & dsp confirm SUCCESS"); + break; + } + GTP_DEBUG("Hold ss51 & dsp confirm 0x4180 failed,value:%d", rd_buf[GTP_ADDR_LENGTH]); + } + if(retry >= 200) + { + GTP_ERROR("Enter update Hold ss51 failed."); + return FAIL; + } + + //step6:DSP_CK and DSP_ALU_CK PowerOn + ret = gup_set_ic_msg(ts->client, 0x4010, 0x00); + + //20121211 modify end + return ret; +} + +void gup_leave_update_mode(struct goodix_ts_data *ts) +{ + //GTP_GPIO_AS_INT(ts->irq_gpio,IRQ_TYPE_EDGE_FALLING); + + GTP_DEBUG("[leave_update_mode]reset chip."); + gtp_reset_guitar(i2c_connect_client, 20); +} + +// Get the correct nvram data +// The correct conditions: +// 1. the hardware info is the same +// 2. the product id is the same +// 3. the firmware version in update file is greater than the firmware version in ic +// or the check sum in ic is wrong +/* Update Conditions: + 1. Same hardware info + 2. Same PID + 3. File PID > IC PID + Force Update Conditions: + 1. Wrong ic firmware checksum + 2. INVALID IC PID or VID + 3. IC PID == 91XX || File PID == 91XX +*/ + +static u8 gup_enter_update_judge(st_fw_head *fw_head) +{ + u16 u16_tmp; + s32 i = 0; + + u16_tmp = fw_head->vid; + fw_head->vid = (u16)(u16_tmp>>8) + (u16)(u16_tmp<<8); + + GTP_DEBUG("FILE HARDWARE INFO:%02x%02x%02x%02x", fw_head->hw_info[0], fw_head->hw_info[1], fw_head->hw_info[2], fw_head->hw_info[3]); + GTP_DEBUG("FILE PID:%s", fw_head->pid); + GTP_DEBUG("FILE VID:%04x", fw_head->vid); + + GTP_DEBUG("IC HARDWARE INFO:%02x%02x%02x%02x", update_msg.ic_fw_msg.hw_info[0], update_msg.ic_fw_msg.hw_info[1], + update_msg.ic_fw_msg.hw_info[2], update_msg.ic_fw_msg.hw_info[3]); + GTP_DEBUG("IC PID:%s", update_msg.ic_fw_msg.pid); + GTP_DEBUG("IC VID:%04x", update_msg.ic_fw_msg.vid); + + //First two conditions + if ( !memcmp(fw_head->hw_info, update_msg.ic_fw_msg.hw_info, sizeof(update_msg.ic_fw_msg.hw_info))) + { + GTP_DEBUG("Get the same hardware info."); + if( update_msg.force_update != 0xBE ) + { + GTP_INFO("FW chksum error,need enter update."); + return SUCCESS; + } + + // 20130523 start + if (strlen(update_msg.ic_fw_msg.pid) < 3) + { + GTP_INFO("Illegal IC pid, need enter update"); + return SUCCESS; + } + else + { + for (i = 0; i < 3; i++) + { + if ((update_msg.ic_fw_msg.pid[i] < 0x30) || (update_msg.ic_fw_msg.pid[i] > 0x39)) + { + GTP_INFO("Illegal IC pid, out of bound, need enter update"); + return SUCCESS; + } + } + } + // 20130523 end + + + if (( !memcmp(fw_head->pid, update_msg.ic_fw_msg.pid, (strlen(fw_head->pid)<3?3:strlen(fw_head->pid))))|| + (!memcmp(update_msg.ic_fw_msg.pid, "91XX", 4))|| + (!memcmp(fw_head->pid, "91XX", 4))) + { + if(!memcmp(fw_head->pid, "91XX", 4)) + { + GTP_DEBUG("Force none same pid update mode."); + } + else + { + GTP_DEBUG("Get the same pid."); + } + //The third condition + if (fw_head->vid > update_msg.ic_fw_msg.vid) + { + + GTP_INFO("Need enter update."); + return SUCCESS; + } + GTP_ERROR("Don't meet the third condition."); + GTP_ERROR("File VID <= Ic VID, update aborted!"); + } + else + { + GTP_ERROR("File PID != Ic PID, update aborted!"); + } + } + else + { + GTP_ERROR("Different Hardware, update aborted!"); + } + return FAIL; +} + +static u8 ascii2hex(u8 a) +{ + s8 value = 0; + + if(a >= '0' && a <= '9') + { + value = a - '0'; + } + else if(a >= 'A' && a <= 'F') + { + value = a - 'A' + 0x0A; + } + else if(a >= 'a' && a <= 'f') + { + value = a - 'a' + 0x0A; + } + else + { + value = 0xff; + } + + return value; +} + +static s8 gup_update_config(struct i2c_client *client) +{ + s32 file_len = 0; + s32 ret = 0; + s32 i = 0; + s32 file_cfg_len = 0; + s32 chip_cfg_len = 0; + s32 count = 0; + u8 *buf; + u8 *pre_buf; + u8 *file_config; + //u8 checksum = 0; + u8 pid[8]; + + if(NULL == update_msg.cfg_file) + { + GTP_ERROR("[update_cfg]No need to upgrade config!"); + return FAIL; + } + file_len = update_msg.cfg_file->f_op->llseek(update_msg.cfg_file, 0, SEEK_END); + + ret = gup_get_ic_msg(client, GUP_REG_PID_VID, pid, 6); + if(FAIL == ret) + { + GTP_ERROR("[update_cfg]Read product id & version id fail."); + return FAIL; + } + pid[5] = '\0'; + GTP_DEBUG("update cfg get pid:%s", &pid[GTP_ADDR_LENGTH]); + + chip_cfg_len = 186; + if(!memcmp(&pid[GTP_ADDR_LENGTH], "968", 3) || + !memcmp(&pid[GTP_ADDR_LENGTH], "910", 3) || + !memcmp(&pid[GTP_ADDR_LENGTH], "960", 3)) + { + chip_cfg_len = 228; + } + GTP_DEBUG("[update_cfg]config file len:%d", file_len); + GTP_DEBUG("[update_cfg]need config len:%d",chip_cfg_len); + if((file_len+5) < chip_cfg_len*5) + { + GTP_ERROR("Config length error"); + return -1; + } + + buf = (u8*)kzalloc(file_len, GFP_KERNEL); + pre_buf = (u8*)kzalloc(file_len, GFP_KERNEL); + file_config = (u8*)kzalloc(chip_cfg_len + GTP_ADDR_LENGTH, GFP_KERNEL); + update_msg.cfg_file->f_op->llseek(update_msg.cfg_file, 0, SEEK_SET); + + GTP_DEBUG("[update_cfg]Read config from file."); + ret = update_msg.cfg_file->f_op->read(update_msg.cfg_file, (char*)pre_buf, file_len, &update_msg.cfg_file->f_pos); + if(ret<0) + { + GTP_ERROR("[update_cfg]Read config file failed."); + goto update_cfg_file_failed; + } + + GTP_DEBUG("[update_cfg]Delete illgal charactor."); + for(i=0,count=0; i> 8; + file_config[1] = GTP_REG_CONFIG_DATA & 0xff; + for(i=0,file_cfg_len=GTP_ADDR_LENGTH; i 0) + { + GTP_INFO("[update_cfg]Send config SUCCESS."); + break; + } + GTP_ERROR("[update_cfg]Send config i2c error."); + } + +update_cfg_file_failed: + kfree(pre_buf); + kfree(buf); + kfree(file_config); + return ret; +} + +#if GTP_HEADER_FW_UPDATE +static u8 gup_check_fs_mounted(char *path_name) +{ + struct path root_path; + struct path path; + int err; + err = kern_path("/", LOOKUP_FOLLOW, &root_path); + + if (err) + { + GTP_DEBUG("\"/\" NOT Mounted: %d", err); + return FAIL; + } + err = kern_path(path_name, LOOKUP_FOLLOW, &path); + + if (err) + { + GTP_DEBUG("/data/ NOT Mounted: %d", err); + return FAIL; + } + + return SUCCESS; + + /* + if (path.mnt->mnt_sb == root_path.mnt->mnt_sb) + { + //-- not mounted + return FAIL; + } + else + { + return SUCCESS; + }*/ + +} +#endif +static u8 gup_check_update_file(struct i2c_client *client, st_fw_head* fw_head, u8* path) +{ + s32 ret = 0; + s32 i = 0; + s32 fw_checksum = 0; + u8 buf[FW_HEAD_LENGTH]; + + char fwname[64] = {0}; + struct goodix_ts_data *ts = l_ts; + sprintf(fwname, "/system/etc/firmware/%s.bin", ts->fw_name); + GTP_INFO("firmware file name: %s.", fwname); + if (path) + { + GTP_DEBUG("Update File path:%s, %d", path, strlen(path)); + update_msg.file = filp_open(path, O_RDONLY, 0); + + if (IS_ERR(update_msg.file)) + { + GTP_ERROR("Open update file(%s) error!", path); + return FAIL; + } + } + else + { +#if GTP_HEADER_FW_UPDATE + for (i = 0; i < (GUP_SEARCH_FILE_TIMES); i++) + { + GTP_DEBUG("Waiting for /data mounted [%d]", i); + + if (gup_check_fs_mounted("/data") == SUCCESS) + { + GTP_DEBUG("/data Mounted!"); + break; + } + msleep(3000); + } + if (i >= (GUP_SEARCH_FILE_TIMES)) + { + GTP_ERROR("Wait for /data mounted timeout!"); + return FAIL; + } + + // update config + update_msg.cfg_file = filp_open(CONFIG_FILE_PATH_1, O_RDONLY, 0); + if (IS_ERR(update_msg.cfg_file)) + { + GTP_DEBUG("%s is unavailable", CONFIG_FILE_PATH_1); + } + else + { + GTP_INFO("Update Config File: %s", CONFIG_FILE_PATH_1); + ret = gup_update_config(client); + if(ret <= 0) + { + GTP_ERROR("Update config failed."); + } + filp_close(update_msg.cfg_file, NULL); + } + + if (sizeof(header_fw_array) < (FW_HEAD_LENGTH+FW_SECTION_LENGTH*4+FW_DSP_ISP_LENGTH+FW_DSP_LENGTH+FW_BOOT_LENGTH)) + { + GTP_ERROR("INVALID header_fw_array, check your gt9xx_firmware.h file!"); + return FAIL; + } + update_msg.file = filp_open(UPDATE_FILE_PATH_2, O_CREAT | O_RDWR, 0666); + if ((IS_ERR(update_msg.file))) + { + GTP_ERROR("Failed to Create file: %s for fw_header!", UPDATE_FILE_PATH_2); + return FAIL; + } + update_msg.file->f_op->llseek(update_msg.file, 0, SEEK_SET); + update_msg.file->f_op->write(update_msg.file, (char *)header_fw_array, sizeof(header_fw_array), &update_msg.file->f_pos); + filp_close(update_msg.file, NULL); + update_msg.file = filp_open(UPDATE_FILE_PATH_2, O_RDONLY, 0); +#else + //u8 fp_len = max(sizeof(UPDATE_FILE_PATH_1), sizeof(UPDATE_FILE_PATH_2)); + u8 fp_len = max(sizeof(UPDATE_FILE_PATH_1), sizeof(fwname)); + u8 cfp_len = max(sizeof(CONFIG_FILE_PATH_1), sizeof(CONFIG_FILE_PATH_2)); + u8 *search_update_path = (u8*)kzalloc(fp_len, GFP_KERNEL); + u8 *search_cfg_path = (u8*)kzalloc(cfp_len, GFP_KERNEL); + //Begin to search update file,the config file & firmware file must be in the same path,single or double. + searching_file = 1; + for (i = 0; i < GUP_SEARCH_FILE_TIMES; i++) + { + if (searching_file == 0) + { + kfree(search_update_path); + kfree(search_cfg_path); + GTP_INFO(".bin/.cfg update file search forcely terminated!"); + return FAIL; + } + if(i%2) + { + memcpy(search_update_path, UPDATE_FILE_PATH_1, sizeof(UPDATE_FILE_PATH_1)); + memcpy(search_cfg_path, CONFIG_FILE_PATH_1, sizeof(CONFIG_FILE_PATH_1)); + } + else + { + //memcpy(search_update_path, UPDATE_FILE_PATH_2, sizeof(UPDATE_FILE_PATH_2)); + memcpy(search_update_path, fwname, sizeof(fwname)); + memcpy(search_cfg_path, CONFIG_FILE_PATH_2, sizeof(CONFIG_FILE_PATH_2)); + } + + if(!(got_file_flag&0x0F)) + { + update_msg.file = filp_open(search_update_path, O_RDONLY, 0); + if(!IS_ERR(update_msg.file)) + { + GTP_DEBUG("Find the bin file"); + got_file_flag |= 0x0F; + } + } + if(!(got_file_flag&0xF0)) + { + update_msg.cfg_file = filp_open(search_cfg_path, O_RDONLY, 0); + if(!IS_ERR(update_msg.cfg_file)) + { + GTP_DEBUG("Find the cfg file"); + got_file_flag |= 0xF0; + } + } + + if(got_file_flag) + { + if(got_file_flag == 0xFF) + { + break; + } + else + { + i += 4; + } + } + GTP_DEBUG("%3d:Searching %s %s file...", i, (got_file_flag&0x0F)?"":"bin", (got_file_flag&0xF0)?"":"cfg"); + //msleep(3000); + } + searching_file = 0; + kfree(search_update_path); + kfree(search_cfg_path); + + if(!got_file_flag) + { + GTP_ERROR("Can't find update file."); + goto load_failed; + } + + if(got_file_flag&0xF0) + { + GTP_DEBUG("Got the update config file."); + ret = gup_update_config(client); + if(ret <= 0) + { + GTP_ERROR("Update config failed."); + } + filp_close(update_msg.cfg_file, NULL); + msleep(500); //waiting config to be stored in FLASH. + } + if(got_file_flag&0x0F) + { + GTP_DEBUG("Got the update firmware file."); + } + else + { + GTP_ERROR("No need to upgrade firmware."); + goto load_failed; + } +#endif + } + + update_msg.old_fs = get_fs(); + set_fs(KERNEL_DS); + + update_msg.file->f_op->llseek(update_msg.file, 0, SEEK_SET); + //update_msg.file->f_pos = 0; + + ret = update_msg.file->f_op->read(update_msg.file, (char*)buf, FW_HEAD_LENGTH, &update_msg.file->f_pos); + if (ret < 0) + { + GTP_ERROR("Read firmware head in update file error."); + goto load_failed; + } + memcpy(fw_head, buf, FW_HEAD_LENGTH); + + //check firmware legality + fw_checksum = 0; + for(i=0; if_op->read(update_msg.file, (char*)buf, 2, &update_msg.file->f_pos); + if (ret < 0) + { + GTP_ERROR("Read firmware file error."); + goto load_failed; + } + //GTP_DEBUG("BUF[0]:%x", buf[0]); + temp = (buf[0]<<8) + buf[1]; + fw_checksum += temp; + } + + GTP_DEBUG("firmware checksum:%x", fw_checksum&0xFFFF); + if(fw_checksum&0xFFFF) + { + GTP_ERROR("Illegal firmware file."); + goto load_failed; + } + + return SUCCESS; + +load_failed: + set_fs(update_msg.old_fs); + return FAIL; +} + +#if 0 +static u8 gup_check_update_header(struct i2c_client *client, st_fw_head* fw_head) +{ + const u8* pos; + int i = 0; + u8 mask_num = 0; + s32 ret = 0; + + pos = HEADER_UPDATE_DATA; + + memcpy(fw_head, pos, FW_HEAD_LENGTH); + pos += FW_HEAD_LENGTH; + + ret = gup_enter_update_judge(fw_head); + if(SUCCESS == ret) + { + return SUCCESS; + } + return FAIL; +} +#endif + +static u8 gup_burn_proc(struct i2c_client *client, u8 *burn_buf, u16 start_addr, u16 total_length) +{ + s32 ret = 0; + u16 burn_addr = start_addr; + u16 frame_length = 0; + u16 burn_length = 0; + u8 wr_buf[PACK_SIZE + GTP_ADDR_LENGTH]; + u8 rd_buf[PACK_SIZE + GTP_ADDR_LENGTH]; + u8 retry = 0; + + GTP_DEBUG("Begin burn %dk data to addr 0x%x", (total_length/1024), start_addr); + while(burn_length < total_length) + { + GTP_DEBUG("B/T:%04d/%04d", burn_length, total_length); + frame_length = ((total_length - burn_length) > PACK_SIZE) ? PACK_SIZE : (total_length - burn_length); + wr_buf[0] = (u8)(burn_addr>>8); + rd_buf[0] = wr_buf[0]; + wr_buf[1] = (u8)burn_addr; + rd_buf[1] = wr_buf[1]; + memcpy(&wr_buf[GTP_ADDR_LENGTH], &burn_buf[burn_length], frame_length); + + for(retry = 0; retry < MAX_FRAME_CHECK_TIME; retry++) + { + ret = gup_i2c_write(client, wr_buf, GTP_ADDR_LENGTH + frame_length); + if(ret <= 0) + { + GTP_ERROR("Write frame data i2c error."); + continue; + } + ret = gup_i2c_read(client, rd_buf, GTP_ADDR_LENGTH + frame_length); + if(ret <= 0) + { + GTP_ERROR("Read back frame data i2c error."); + continue; + } + + if(memcmp(&wr_buf[GTP_ADDR_LENGTH], &rd_buf[GTP_ADDR_LENGTH], frame_length)) + { + GTP_ERROR("Check frame data fail,not equal."); + GTP_DEBUG("write array:"); + GTP_DEBUG_ARRAY(&wr_buf[GTP_ADDR_LENGTH], frame_length); + GTP_DEBUG("read array:"); + GTP_DEBUG_ARRAY(&rd_buf[GTP_ADDR_LENGTH], frame_length); + continue; + } + else + { + //GTP_DEBUG("Check frame data success."); + break; + } + } + if(retry >= MAX_FRAME_CHECK_TIME) + { + GTP_ERROR("Burn frame data time out,exit."); + return FAIL; + } + burn_length += frame_length; + burn_addr += frame_length; + } + return SUCCESS; +} + +static u8 gup_load_section_file(u8* buf, u16 offset, u16 length) +{ + s32 ret = 0; + + if(update_msg.file == NULL) + { + GTP_ERROR("cannot find update file,load section file fail."); + return FAIL; + } + update_msg.file->f_pos = FW_HEAD_LENGTH + offset; + + ret = update_msg.file->f_op->read(update_msg.file, (char*)buf, length, &update_msg.file->f_pos); + if(ret < 0) + { + GTP_ERROR("Read update file fail."); + return FAIL; + } + + return SUCCESS; +} + +static u8 gup_recall_check(struct i2c_client *client, u8* chk_src, u16 start_rd_addr, u16 chk_length) +{ + u8 rd_buf[PACK_SIZE + GTP_ADDR_LENGTH]; + s32 ret = 0; + u16 recall_addr = start_rd_addr; + u16 recall_length = 0; + u16 frame_length = 0; + + while(recall_length < chk_length) + { + frame_length = ((chk_length - recall_length) > PACK_SIZE) ? PACK_SIZE : (chk_length - recall_length); + ret = gup_get_ic_msg(client, recall_addr, rd_buf, frame_length); + if(ret <= 0) + { + GTP_ERROR("recall i2c error,exit"); + return FAIL; + } + + if(memcmp(&rd_buf[GTP_ADDR_LENGTH], &chk_src[recall_length], frame_length)) + { + GTP_ERROR("Recall frame data fail,not equal."); + GTP_DEBUG("chk_src array:"); + GTP_DEBUG_ARRAY(&chk_src[recall_length], frame_length); + GTP_DEBUG("recall array:"); + GTP_DEBUG_ARRAY(&rd_buf[GTP_ADDR_LENGTH], frame_length); + return FAIL; + } + + recall_length += frame_length; + recall_addr += frame_length; + } + GTP_DEBUG("Recall check %dk firmware success.", (chk_length/1024)); + + return SUCCESS; +} + +static u8 gup_burn_fw_section(struct i2c_client *client, u8 *fw_section, u16 start_addr, u8 bank_cmd ) +{ + s32 ret = 0; + u8 rd_buf[5]; + + //step1:hold ss51 & dsp + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C); + if(ret <= 0) + { + GTP_ERROR("[burn_fw_section]hold ss51 & dsp fail."); + return FAIL; + } + + //step2:set scramble + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00); + if(ret <= 0) + { + GTP_ERROR("[burn_fw_section]set scramble fail."); + return FAIL; + } + + //step3:select bank + ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, (bank_cmd >> 4)&0x0F); + if(ret <= 0) + { + GTP_ERROR("[burn_fw_section]select bank %d fail.", (bank_cmd >> 4)&0x0F); + return FAIL; + } + + //step4:enable accessing code + ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01); + if(ret <= 0) + { + GTP_ERROR("[burn_fw_section]enable accessing code fail."); + return FAIL; + } + + //step5:burn 8k fw section + ret = gup_burn_proc(client, fw_section, start_addr, FW_SECTION_LENGTH); + if(FAIL == ret) + { + GTP_ERROR("[burn_fw_section]burn fw_section fail."); + return FAIL; + } + + //step6:hold ss51 & release dsp + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04); + if(ret <= 0) + { + GTP_ERROR("[burn_fw_section]hold ss51 & release dsp fail."); + return FAIL; + } + //must delay + msleep(1); + + //step7:send burn cmd to move data to flash from sram + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, bank_cmd&0x0f); + if(ret <= 0) + { + GTP_ERROR("[burn_fw_section]send burn cmd fail."); + return FAIL; + } + GTP_DEBUG("[burn_fw_section]Wait for the burn is complete......"); + do{ + ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1); + if(ret <= 0) + { + GTP_ERROR("[burn_fw_section]Get burn state fail"); + return FAIL; + } + msleep(10); + //GTP_DEBUG("[burn_fw_section]Get burn state:%d.", rd_buf[GTP_ADDR_LENGTH]); + }while(rd_buf[GTP_ADDR_LENGTH]); + + //step8:select bank + ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, (bank_cmd >> 4)&0x0F); + if(ret <= 0) + { + GTP_ERROR("[burn_fw_section]select bank %d fail.", (bank_cmd >> 4)&0x0F); + return FAIL; + } + + //step9:enable accessing code + ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01); + if(ret <= 0) + { + GTP_ERROR("[burn_fw_section]enable accessing code fail."); + return FAIL; + } + + //step10:recall 8k fw section + ret = gup_recall_check(client, fw_section, start_addr, FW_SECTION_LENGTH); + if(FAIL == ret) + { + GTP_ERROR("[burn_fw_section]recall check 8k firmware fail."); + return FAIL; + } + + //step11:disable accessing code + ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x00); + if(ret <= 0) + { + GTP_ERROR("[burn_fw_section]disable accessing code fail."); + return FAIL; + } + + return SUCCESS; +} + +static u8 gup_burn_dsp_isp(struct i2c_client *client) +{ + s32 ret = 0; + u8* fw_dsp_isp = NULL; + u8 retry = 0; + + GTP_DEBUG("[burn_dsp_isp]Begin burn dsp isp---->>"); + + //step1:alloc memory + GTP_DEBUG("[burn_dsp_isp]step1:alloc memory"); + while(retry++ < 5) + { + fw_dsp_isp = (u8*)kzalloc(FW_DSP_ISP_LENGTH, GFP_KERNEL); + if(fw_dsp_isp == NULL) + { + continue; + } + else + { + GTP_INFO("[burn_dsp_isp]Alloc %dk byte memory success.", (FW_DSP_ISP_LENGTH/1024)); + break; + } + } + if(retry >= 5) + { + GTP_ERROR("[burn_dsp_isp]Alloc memory fail,exit."); + return FAIL; + } + + //step2:load dsp isp file data + GTP_DEBUG("[burn_dsp_isp]step2:load dsp isp file data"); + ret = gup_load_section_file(fw_dsp_isp, (4*FW_SECTION_LENGTH+FW_DSP_LENGTH+FW_BOOT_LENGTH), FW_DSP_ISP_LENGTH); + if(FAIL == ret) + { + GTP_ERROR("[burn_dsp_isp]load firmware dsp_isp fail."); + goto exit_burn_dsp_isp; + } + + //step3:disable wdt,clear cache enable + GTP_DEBUG("[burn_dsp_isp]step3:disable wdt,clear cache enable"); + ret = gup_set_ic_msg(client, _bRW_MISCTL__TMR0_EN, 0x00); + if(ret <= 0) + { + GTP_ERROR("[burn_dsp_isp]disable wdt fail."); + ret = FAIL; + goto exit_burn_dsp_isp; + } + ret = gup_set_ic_msg(client, _bRW_MISCTL__CACHE_EN, 0x00); + if(ret <= 0) + { + GTP_ERROR("[burn_dsp_isp]clear cache enable fail."); + ret = FAIL; + goto exit_burn_dsp_isp; + } + + //step4:hold ss51 & dsp + GTP_DEBUG("[burn_dsp_isp]step4:hold ss51 & dsp"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C); + if(ret <= 0) + { + GTP_ERROR("[burn_dsp_isp]hold ss51 & dsp fail."); + ret = FAIL; + goto exit_burn_dsp_isp; + } + + //step5:set boot from sram + GTP_DEBUG("[burn_dsp_isp]step5:set boot from sram"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOTCTL_B0_, 0x02); + if(ret <= 0) + { + GTP_ERROR("[burn_dsp_isp]set boot from sram fail."); + ret = FAIL; + goto exit_burn_dsp_isp; + } + + //step6:software reboot + GTP_DEBUG("[burn_dsp_isp]step6:software reboot"); + ret = gup_set_ic_msg(client, _bWO_MISCTL__CPU_SWRST_PULSE, 0x01); + if(ret <= 0) + { + GTP_ERROR("[burn_dsp_isp]software reboot fail."); + ret = FAIL; + goto exit_burn_dsp_isp; + } + + //step7:select bank2 + GTP_DEBUG("[burn_dsp_isp]step7:select bank2"); + ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x02); + if(ret <= 0) + { + GTP_ERROR("[burn_dsp_isp]select bank2 fail."); + ret = FAIL; + goto exit_burn_dsp_isp; + } + + //step8:enable accessing code + GTP_DEBUG("[burn_dsp_isp]step8:enable accessing code"); + ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01); + if(ret <= 0) + { + GTP_ERROR("[burn_dsp_isp]enable accessing code fail."); + ret = FAIL; + goto exit_burn_dsp_isp; + } + + //step9:burn 4k dsp_isp + GTP_DEBUG("[burn_dsp_isp]step9:burn 4k dsp_isp"); + ret = gup_burn_proc(client, fw_dsp_isp, 0xC000, FW_DSP_ISP_LENGTH); + if(FAIL == ret) + { + GTP_ERROR("[burn_dsp_isp]burn dsp_isp fail."); + goto exit_burn_dsp_isp; + } + + //step10:set scramble + GTP_DEBUG("[burn_dsp_isp]step10:set scramble"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00); + if(ret <= 0) + { + GTP_ERROR("[burn_dsp_isp]set scramble fail."); + ret = FAIL; + goto exit_burn_dsp_isp; + } + ret = SUCCESS; + +exit_burn_dsp_isp: + kfree(fw_dsp_isp); + return ret; +} + +static u8 gup_burn_fw_ss51(struct i2c_client *client) +{ + u8* fw_ss51 = NULL; + u8 retry = 0; + s32 ret = 0; + + GTP_DEBUG("[burn_fw_ss51]Begin burn ss51 firmware---->>"); + + //step1:alloc memory + GTP_DEBUG("[burn_fw_ss51]step1:alloc memory"); + while(retry++ < 5) + { + fw_ss51 = (u8*)kzalloc(FW_SECTION_LENGTH, GFP_KERNEL); + if(fw_ss51 == NULL) + { + continue; + } + else + { + GTP_INFO("[burn_fw_ss51]Alloc %dk byte memory success.", (FW_SECTION_LENGTH/1024)); + break; + } + } + if(retry >= 5) + { + GTP_ERROR("[burn_fw_ss51]Alloc memory fail,exit."); + return FAIL; + } + + //step2:load ss51 firmware section 1 file data + GTP_DEBUG("[burn_fw_ss51]step2:load ss51 firmware section 1 file data"); + ret = gup_load_section_file(fw_ss51, 0, FW_SECTION_LENGTH); + if(FAIL == ret) + { + GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 1 fail."); + goto exit_burn_fw_ss51; + } + + //step3:clear control flag + GTP_DEBUG("[burn_fw_ss51]step3:clear control flag"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x00); + if(ret <= 0) + { + GTP_ERROR("[burn_fw_ss51]clear control flag fail."); + ret = FAIL; + goto exit_burn_fw_ss51; + } + + //step4:burn ss51 firmware section 1 + GTP_DEBUG("[burn_fw_ss51]step4:burn ss51 firmware section 1"); + ret = gup_burn_fw_section(client, fw_ss51, 0xC000, 0x01); + if(FAIL == ret) + { + GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 1 fail."); + goto exit_burn_fw_ss51; + } + + //step5:load ss51 firmware section 2 file data + GTP_DEBUG("[burn_fw_ss51]step5:load ss51 firmware section 2 file data"); + ret = gup_load_section_file(fw_ss51, FW_SECTION_LENGTH, FW_SECTION_LENGTH); + if(FAIL == ret) + { + GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 2 fail."); + goto exit_burn_fw_ss51; + } + + //step6:burn ss51 firmware section 2 + GTP_DEBUG("[burn_fw_ss51]step6:burn ss51 firmware section 2"); + ret = gup_burn_fw_section(client, fw_ss51, 0xE000, 0x02); + if(FAIL == ret) + { + GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 2 fail."); + goto exit_burn_fw_ss51; + } + + //step7:load ss51 firmware section 3 file data + GTP_DEBUG("[burn_fw_ss51]step7:load ss51 firmware section 3 file data"); + ret = gup_load_section_file(fw_ss51, 2*FW_SECTION_LENGTH, FW_SECTION_LENGTH); + if(FAIL == ret) + { + GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 3 fail."); + goto exit_burn_fw_ss51; + } + + //step8:burn ss51 firmware section 3 + GTP_DEBUG("[burn_fw_ss51]step8:burn ss51 firmware section 3"); + ret = gup_burn_fw_section(client, fw_ss51, 0xC000, 0x13); + if(FAIL == ret) + { + GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 3 fail."); + goto exit_burn_fw_ss51; + } + + //step9:load ss51 firmware section 4 file data + GTP_DEBUG("[burn_fw_ss51]step9:load ss51 firmware section 4 file data"); + ret = gup_load_section_file(fw_ss51, 3*FW_SECTION_LENGTH, FW_SECTION_LENGTH); + if(FAIL == ret) + { + GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 4 fail."); + goto exit_burn_fw_ss51; + } + + //step10:burn ss51 firmware section 4 + GTP_DEBUG("[burn_fw_ss51]step10:burn ss51 firmware section 4"); + ret = gup_burn_fw_section(client, fw_ss51, 0xE000, 0x14); + if(FAIL == ret) + { + GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 4 fail."); + goto exit_burn_fw_ss51; + } + + ret = SUCCESS; + +exit_burn_fw_ss51: + kfree(fw_ss51); + return ret; +} + +static u8 gup_burn_fw_dsp(struct i2c_client *client) +{ + s32 ret = 0; + u8* fw_dsp = NULL; + u8 retry = 0; + u8 rd_buf[5]; + + GTP_DEBUG("[burn_fw_dsp]Begin burn dsp firmware---->>"); + //step1:alloc memory + GTP_DEBUG("[burn_fw_dsp]step1:alloc memory"); + while(retry++ < 5) + { + fw_dsp = (u8*)kzalloc(FW_DSP_LENGTH, GFP_KERNEL); + if(fw_dsp == NULL) + { + continue; + } + else + { + GTP_INFO("[burn_fw_dsp]Alloc %dk byte memory success.", (FW_SECTION_LENGTH/1024)); + break; + } + } + if(retry >= 5) + { + GTP_ERROR("[burn_fw_dsp]Alloc memory fail,exit."); + return FAIL; + } + + //step2:load firmware dsp + GTP_DEBUG("[burn_fw_dsp]step2:load firmware dsp"); + ret = gup_load_section_file(fw_dsp, 4*FW_SECTION_LENGTH, FW_DSP_LENGTH); + if(FAIL == ret) + { + GTP_ERROR("[burn_fw_dsp]load firmware dsp fail."); + goto exit_burn_fw_dsp; + } + + //step3:select bank3 + GTP_DEBUG("[burn_fw_dsp]step3:select bank3"); + ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x03); + if(ret <= 0) + { + GTP_ERROR("[burn_fw_dsp]select bank3 fail."); + ret = FAIL; + goto exit_burn_fw_dsp; + } + + //step4:hold ss51 & dsp + GTP_DEBUG("[burn_fw_dsp]step4:hold ss51 & dsp"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C); + if(ret <= 0) + { + GTP_ERROR("[burn_fw_dsp]hold ss51 & dsp fail."); + ret = FAIL; + goto exit_burn_fw_dsp; + } + + //step5:set scramble + GTP_DEBUG("[burn_fw_dsp]step5:set scramble"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00); + if(ret <= 0) + { + GTP_ERROR("[burn_fw_dsp]set scramble fail."); + ret = FAIL; + goto exit_burn_fw_dsp; + } + + //step6:release ss51 & dsp + GTP_DEBUG("[burn_fw_dsp]step6:release ss51 & dsp"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04); //20121211 + if(ret <= 0) + { + GTP_ERROR("[burn_fw_dsp]release ss51 & dsp fail."); + ret = FAIL; + goto exit_burn_fw_dsp; + } + //must delay + msleep(1); + + //step7:burn 4k dsp firmware + GTP_DEBUG("[burn_fw_dsp]step7:burn 4k dsp firmware"); + ret = gup_burn_proc(client, fw_dsp, 0x9000, FW_DSP_LENGTH); + if(FAIL == ret) + { + GTP_ERROR("[burn_fw_dsp]burn fw_section fail."); + goto exit_burn_fw_dsp; + } + + //step8:send burn cmd to move data to flash from sram + GTP_DEBUG("[burn_fw_dsp]step8:send burn cmd to move data to flash from sram"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x05); + if(ret <= 0) + { + GTP_ERROR("[burn_fw_dsp]send burn cmd fail."); + goto exit_burn_fw_dsp; + } + GTP_DEBUG("[burn_fw_dsp]Wait for the burn is complete......"); + do{ + ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1); + if(ret <= 0) + { + GTP_ERROR("[burn_fw_dsp]Get burn state fail"); + goto exit_burn_fw_dsp; + } + msleep(10); + //GTP_DEBUG("[burn_fw_dsp]Get burn state:%d.", rd_buf[GTP_ADDR_LENGTH]); + }while(rd_buf[GTP_ADDR_LENGTH]); + + //step9:recall check 4k dsp firmware + GTP_DEBUG("[burn_fw_dsp]step9:recall check 4k dsp firmware"); + ret = gup_recall_check(client, fw_dsp, 0x9000, FW_DSP_LENGTH); + if(FAIL == ret) + { + GTP_ERROR("[burn_fw_dsp]recall check 4k dsp firmware fail."); + goto exit_burn_fw_dsp; + } + + ret = SUCCESS; + +exit_burn_fw_dsp: + kfree(fw_dsp); + return ret; +} + +static u8 gup_burn_fw_boot(struct i2c_client *client) +{ + s32 ret = 0; + u8* fw_boot = NULL; + u8 retry = 0; + u8 rd_buf[5]; + + GTP_DEBUG("[burn_fw_boot]Begin burn bootloader firmware---->>"); + + //step1:Alloc memory + GTP_DEBUG("[burn_fw_boot]step1:Alloc memory"); + while(retry++ < 5) + { + fw_boot = (u8*)kzalloc(FW_BOOT_LENGTH, GFP_KERNEL); + if(fw_boot == NULL) + { + continue; + } + else + { + GTP_INFO("[burn_fw_boot]Alloc %dk byte memory success.", (FW_BOOT_LENGTH/1024)); + break; + } + } + if(retry >= 5) + { + GTP_ERROR("[burn_fw_boot]Alloc memory fail,exit."); + return FAIL; + } + + //step2:load firmware bootloader + GTP_DEBUG("[burn_fw_boot]step2:load firmware bootloader"); + ret = gup_load_section_file(fw_boot, (4*FW_SECTION_LENGTH+FW_DSP_LENGTH), FW_BOOT_LENGTH); + if(FAIL == ret) + { + GTP_ERROR("[burn_fw_boot]load firmware dsp fail."); + goto exit_burn_fw_boot; + } + + //step3:hold ss51 & dsp + GTP_DEBUG("[burn_fw_boot]step3:hold ss51 & dsp"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C); + if(ret <= 0) + { + GTP_ERROR("[burn_fw_boot]hold ss51 & dsp fail."); + ret = FAIL; + goto exit_burn_fw_boot; + } + + //step4:set scramble + GTP_DEBUG("[burn_fw_boot]step4:set scramble"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00); + if(ret <= 0) + { + GTP_ERROR("[burn_fw_boot]set scramble fail."); + ret = FAIL; + goto exit_burn_fw_boot; + } + + //step5:release ss51 & dsp + GTP_DEBUG("[burn_fw_boot]step5:release ss51 & dsp"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04); //20121211 + if(ret <= 0) + { + GTP_ERROR("[burn_fw_boot]release ss51 & dsp fail."); + ret = FAIL; + goto exit_burn_fw_boot; + } + //must delay + msleep(1); + + //step6:select bank3 + GTP_DEBUG("[burn_fw_boot]step6:select bank3"); + ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x03); + if(ret <= 0) + { + GTP_ERROR("[burn_fw_boot]select bank3 fail."); + ret = FAIL; + goto exit_burn_fw_boot; + } + + //step7:burn 2k bootloader firmware + GTP_DEBUG("[burn_fw_boot]step7:burn 2k bootloader firmware"); + ret = gup_burn_proc(client, fw_boot, 0x9000, FW_BOOT_LENGTH); + if(FAIL == ret) + { + GTP_ERROR("[burn_fw_boot]burn fw_section fail."); + goto exit_burn_fw_boot; + } + + //step7:send burn cmd to move data to flash from sram + GTP_DEBUG("[burn_fw_boot]step7:send burn cmd to move data to flash from sram"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x06); + if(ret <= 0) + { + GTP_ERROR("[burn_fw_boot]send burn cmd fail."); + goto exit_burn_fw_boot; + } + GTP_DEBUG("[burn_fw_boot]Wait for the burn is complete......"); + do{ + ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1); + if(ret <= 0) + { + GTP_ERROR("[burn_fw_boot]Get burn state fail"); + goto exit_burn_fw_boot; + } + msleep(10); + //GTP_DEBUG("[burn_fw_boot]Get burn state:%d.", rd_buf[GTP_ADDR_LENGTH]); + }while(rd_buf[GTP_ADDR_LENGTH]); + + //step8:recall check 2k bootloader firmware + GTP_DEBUG("[burn_fw_boot]step8:recall check 2k bootloader firmware"); + ret = gup_recall_check(client, fw_boot, 0x9000, FW_BOOT_LENGTH); + if(FAIL == ret) + { + GTP_ERROR("[burn_fw_boot]recall check 4k dsp firmware fail."); + goto exit_burn_fw_boot; + } + + //step9:enable download DSP code + GTP_DEBUG("[burn_fw_boot]step9:enable download DSP code "); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x99); + if(ret <= 0) + { + GTP_ERROR("[burn_fw_boot]enable download DSP code fail."); + ret = FAIL; + goto exit_burn_fw_boot; + } + + //step10:release ss51 & hold dsp + GTP_DEBUG("[burn_fw_boot]step10:release ss51 & hold dsp"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x08); + if(ret <= 0) + { + GTP_ERROR("[burn_fw_boot]release ss51 & hold dsp fail."); + ret = FAIL; + goto exit_burn_fw_boot; + } + + ret = SUCCESS; + +exit_burn_fw_boot: + kfree(fw_boot); + return ret; +} + +s32 gup_update_proc(void *dir) +{ + s32 ret = 0; + u8 retry = 0; + st_fw_head fw_head; + struct goodix_ts_data *ts = NULL; + + GTP_DEBUG("[update_proc]Begin update ......"); + + show_len = 1; + total_len = 100; + if(dir == NULL) + { + //msleep(3000); //wait main thread to be completed + } + + ts = l_ts; + + if (searching_file) + { + searching_file = 0; // exit .bin update file searching + GTP_INFO("Exiting searching .bin update file..."); + while ((show_len != 200) && (show_len != 100)) // wait for auto update quitted completely + { + msleep(100); + } + } + + update_msg.file = NULL; + ret = gup_check_update_file(i2c_connect_client, &fw_head, (u8*)dir); //20121211 + if(FAIL == ret) + { + GTP_ERROR("[update_proc]check update file fail."); + goto file_fail; + } + + //gtp_reset_guitar(i2c_connect_client, 20); + ret = gup_get_ic_fw_msg(i2c_connect_client); + if(FAIL == ret) + { + GTP_ERROR("[update_proc]get ic message fail."); + goto file_fail; + } + + ret = gup_enter_update_judge(&fw_head); + if(FAIL == ret) + { + GTP_ERROR("[update_proc]Check *.bin file fail."); + goto file_fail; + } + + ts->enter_update = 1; + gtp_irq_disable(ts); +#if GTP_ESD_PROTECT + gtp_esd_switch(ts->client, SWITCH_OFF); +#endif + ret = gup_enter_update_mode(ts); + if(FAIL == ret) + { + GTP_ERROR("[update_proc]enter update mode fail."); + goto update_fail; + } + + while(retry++ < 5) + { + show_len = 10; + total_len = 100; + ret = gup_burn_dsp_isp(i2c_connect_client); + if(FAIL == ret) + { + GTP_ERROR("[update_proc]burn dsp isp fail."); + continue; + } + + show_len += 10; + ret = gup_burn_fw_ss51(i2c_connect_client); + if(FAIL == ret) + { + GTP_ERROR("[update_proc]burn ss51 firmware fail."); + continue; + } + + show_len += 40; + ret = gup_burn_fw_dsp(i2c_connect_client); + if(FAIL == ret) + { + GTP_ERROR("[update_proc]burn dsp firmware fail."); + continue; + } + + show_len += 20; + ret = gup_burn_fw_boot(i2c_connect_client); + if(FAIL == ret) + { + GTP_ERROR("[update_proc]burn bootloader firmware fail."); + continue; + } + show_len += 10; + GTP_INFO("[update_proc]UPDATE SUCCESS."); + break; + } + if(retry >= 5) + { + GTP_ERROR("[update_proc]retry timeout,UPDATE FAIL."); + goto update_fail; + } + + GTP_DEBUG("[update_proc]leave update mode."); + gup_leave_update_mode(ts); + + msleep(100); +// GTP_DEBUG("[update_proc]send config."); +// ret = gtp_send_cfg(i2c_connect_client); +// if(ret < 0) +// { +// GTP_ERROR("[update_proc]send config fail."); +// } + if (ts->fw_error) + { + GTP_INFO("firmware error auto update, resent config!"); + gup_init_panel(ts); + } + show_len = 100; + total_len = 100; + ts->enter_update = 0; + gtp_irq_enable(ts); + +#if GTP_ESD_PROTECT + gtp_esd_switch(ts->client, SWITCH_ON); +#endif + filp_close(update_msg.file, NULL); + return SUCCESS; + +update_fail: + ts->enter_update = 0; + gtp_irq_enable(ts); + +#if GTP_ESD_PROTECT + gtp_esd_switch(ts->client, SWITCH_ON); +#endif + +file_fail: + if(update_msg.file && !IS_ERR(update_msg.file)) + { + filp_close(update_msg.file, NULL); + } + show_len = 200; + total_len = 100; + return FAIL; +} + +#if GTP_AUTO_UPDATE +u8 gup_init_update_proc(struct goodix_ts_data *ts) +{ + //struct task_struct *thread = NULL; + + GTP_INFO("Ready to run update thread."); + if(!gup_update_proc(NULL)) + GTP_ERROR("fail to update."); + /*thread = kthread_run(gup_update_proc, (void*)NULL, "guitar_update"); + if (IS_ERR(thread)) + { + GTP_ERROR("Failed to create update thread.\n"); + return -1; + }*/ + + return 0; +} +#endif diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/icn83xx_ts/Kconfig b/ANDROID_3.4.5/drivers/input/touchscreen/icn83xx_ts/Kconfig new file mode 100755 index 00000000..dbd6a729 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/icn83xx_ts/Kconfig @@ -0,0 +1,16 @@ +# +# ICN83XX capacity touch screen driver configuration +# +config TOUCHSCREEN_ICN83XX + tristate "ICN83XX I2C Capacitive Touchscreen Input Driver Support" + depends on ARCH_WMT + default y + help + Say Y here if you have an WMT based board with touchscreen + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called s_wmt_ts_icn83xx + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/icn83xx_ts/Makefile b/ANDROID_3.4.5/drivers/input/touchscreen/icn83xx_ts/Makefile new file mode 100755 index 00000000..e1070854 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/icn83xx_ts/Makefile @@ -0,0 +1,32 @@ +KERNELDIR=../../../../ +CROSS = arm_1103_le- +CC= $(CROSS)gcc +LD= $(CROSS)ld +STRIP = $(CROSS)strip + +DEBUG = n + +# Add your debugging flag (or not) to EXTRA_CFLAGS +ifeq ($(DEBUG),y) +# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines +DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines + +else + DEBFLAGS = -O2 -Wall +endif + +EXTRA_CFLAGS += $(DEBFLAGS) + + +MY_MODULE_NAME=s_wmt_ts_icn83xx + +obj-m := $(MY_MODULE_NAME).o +$(MY_MODULE_NAME)-objs := icn83xx.o flash.o + +default: + $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules + $(STRIP) --strip-debug $(MY_MODULE_NAME).ko + rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions *.order *.symvers modules.builtin + +clean: + rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers modules.builtin diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/icn83xx_ts/flash.c b/ANDROID_3.4.5/drivers/input/touchscreen/icn83xx_ts/flash.c new file mode 100755 index 00000000..595545d8 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/icn83xx_ts/flash.c @@ -0,0 +1,973 @@ +/*++ + + Copyright (c) 2012-2022 ChipOne Technology (Beijing) Co., Ltd. All Rights Reserved. + This PROPRIETARY SOFTWARE is the property of ChipOne Technology (Beijing) Co., Ltd. + and may contains trade secrets and/or other confidential information of ChipOne + Technology (Beijing) Co., Ltd. This file shall not be disclosed to any third party, + in whole or in part, without prior written consent of ChipOne. + THIS PROPRIETARY SOFTWARE & ANY RELATED DOCUMENTATION ARE PROVIDED AS IS, + WITH ALL FAULTS, & WITHOUT WARRANTY OF ANY KIND. CHIPONE DISCLAIMS ALL EXPRESS OR + IMPLIED WARRANTIES. + + File Name: flash.c + Abstract: + flash operation, read write etc. + Author: Zhimin Tian + Date : 10 30,2012 + Version: 0.1[.revision] + History : + Change logs. + --*/ +#include "icn83xx.h" + +struct file *fp; +int g_status = R_OK; +static char fw_mode = 0; +static int fw_size = 0; +static unsigned char *fw_buf; + +void icn83xx_rawdatadump(short *mem, int size, char br) +{ + int i; + for(i=0;if_dentry->d_inode; + file_size = inode->i_size; + flash_info("file size: %d\n", file_size); + + fs = get_fs(); + set_fs(KERNEL_DS); + + return file_size; + +} + +/*********************************************************************************************** +Name : icn83xx_read_fw +Input : offset + length, read length + buf, return buffer +Output : +function : read data to buffer +***********************************************************************************************/ +int icn83xx_read_fw(int offset, int length, char *buf) +{ + loff_t pos = offset; + if(fw_mode == 1) + { + memcpy(buf, fw_buf+offset, length); + } + else + { + vfs_read(fp, buf, length, &pos); + } +// icn83xx_memdump(buf, length); + return 0; +} + + +/*********************************************************************************************** +Name : icn83xx_close_fw +Input : +Output : +function : close file +***********************************************************************************************/ +int icn83xx_close_fw(void) +{ + if(fw_mode == 0) + { + filp_close(fp, NULL); + } + + return 0; +} +/*********************************************************************************************** +Name : icn83xx_readVersion +Input : void +Output : +function : return version +***********************************************************************************************/ +int icn83xx_readVersion(void) +{ + int err = 0; + char tmp[2]; + short CurVersion; + err = icn83xx_i2c_rxdata(12, tmp, 2); + if (err < 0) { + calib_error("%s failed: %d\n", __func__, err); + return err; + } + CurVersion = (tmp[0]<<8) | tmp[1]; + return CurVersion; +} + +/*********************************************************************************************** +Name : icn83xx_changemode +Input : normal/factory/config +Output : +function : change work mode +***********************************************************************************************/ +int icn83xx_changemode(char mode) +{ + char value = 0x0; + icn83xx_write_reg(0, mode); + mdelay(1); + icn83xx_read_reg(1, &value); + while(value != 0) + { + mdelay(1); + icn83xx_read_reg(1, &value); + } +// calib_info("icn83xx_changemode ok\n"); + return 0; +} + + +/*********************************************************************************************** +Name : icn83xx_readrawdata +Input : rownum and length +Output : +function : read one row rawdata +***********************************************************************************************/ + +int icn83xx_readrawdata(char *buffer, char row, char length) +{ + int err = 0; + int i; +// calib_info("readrawdata: %d, length: %d\n", row, length); + icn83xx_write_reg(3, row); + mdelay(1); + err = icn83xx_i2c_rxdata(160, buffer, length); + if (err < 0) { + calib_error("%s failed: %d\n", __func__, err); + return err; + } + + for(i=0; i 5000) + { + flash_error("op1 ucTemp: 0x%x\n", ucTemp); + return 1; + } + } + i = i+1024; + } + icn83xx_ll(); + return 0; +} + +/*********************************************************************************************** +Name : icn83xx_op2 +Input : +Output : +function : progm flash +***********************************************************************************************/ +int icn83xx_op2(char info, unsigned short offset, unsigned char * buffer, unsigned int size) +{ + int count = 0; + unsigned int flash_size; + unsigned char ucTemp; + unsigned short uiAddress; + ucTemp = 0x00; + uiAddress = 0x1000; + + icn83xx_prog_i2c_txdata(uiAddress, buffer, size); + + icn83xx_uu(); + + ucTemp = U16LOBYTE(offset); + icn83xx_prog_i2c_txdata(0x0502, &ucTemp, 1); + ucTemp = U16HIBYTE(offset); + icn83xx_prog_i2c_txdata(0x0503, &ucTemp, 1); + + icn83xx_prog_i2c_txdata(0x0504, (char *)&uiAddress, 2); + + +//ensure size is even + if(size%2 != 0) + { + flash_info("write op size: %d\n", size); + flash_size = size+1; + } + else + flash_size = size; + + ucTemp = U16LOBYTE(flash_size); + icn83xx_prog_i2c_txdata(0x0506, &ucTemp, 1); + ucTemp = U16HIBYTE(flash_size); + icn83xx_prog_i2c_txdata(0x0507, &ucTemp, 1); + ucTemp = 0x01; + + if(info > 0) + ucTemp = 0x01 | (1<<3); + + icn83xx_prog_i2c_txdata(0x0500, &ucTemp, 1); // + while(ucTemp) + { + icn83xx_prog_i2c_rxdata(0x0501, &ucTemp, 1); + count++; + if(count > 5000) + { + flash_error("op2 ucTemp: 0x%x\n", ucTemp); + return 1; + } + + } + icn83xx_ll(); + return 0; +} + +/*********************************************************************************************** +Name : icn83xx_op3 +Input : +Output : +function : read flash +***********************************************************************************************/ +int icn83xx_op3(char info, unsigned short offset, unsigned char * buffer, unsigned int size) +{ + int count = 0; + unsigned int flash_size; + unsigned char ucTemp; + unsigned short uiAddress; + ucTemp = 0x00; + uiAddress = 0x1000; + icn83xx_uu(); + ucTemp = U16LOBYTE(offset); + icn83xx_prog_i2c_txdata(0x0502, &ucTemp, 1); + ucTemp = U16HIBYTE(offset); + icn83xx_prog_i2c_txdata(0x0503, &ucTemp, 1); + + icn83xx_prog_i2c_txdata(0x0504, (unsigned char*)&uiAddress, 2); + +//ensure size is even + if(size%2 != 0) + { + flash_info("read op size: %d\n", size); + flash_size = size+1; + } + else + flash_size = size; + + ucTemp = U16LOBYTE(flash_size); + icn83xx_prog_i2c_txdata(0x0506, &ucTemp, 1); + + ucTemp = U16HIBYTE(flash_size); + icn83xx_prog_i2c_txdata(0x0507, &ucTemp, 1); + ucTemp = 0x40; + + if(info > 0) + ucTemp = 0x40 | (1<<3); + + icn83xx_prog_i2c_txdata(0x0500, &ucTemp, 1); + ucTemp = 0x01; + while(ucTemp) + { + icn83xx_prog_i2c_rxdata(0x0501, &ucTemp, 1); + count++; + if(count > 5000) + { + flash_error("op3 ucTemp: 0x%x\n", ucTemp); + return 1; + } + + } + icn83xx_ll(); + icn83xx_prog_i2c_rxdata(uiAddress, buffer, size); + return 0; +} + + +/*********************************************************************************************** +Name : icn83xx_goto_nomalmode +Input : +Output : +function : when prog flash ok, change flash info flag +***********************************************************************************************/ +int icn83xx_goto_nomalmode(void) +{ + int ret = -1; + //unsigned short addr = 0; + char temp_buf[3]; + + flash_info("icn83xx_goto_nomalmode\n"); + temp_buf[0] = 0x03; + icn83xx_prog_i2c_txdata(0x0f00, temp_buf, 1); + + msleep(100); +/* + addr = 0; + temp_buf[0] = U16HIBYTE(addr); + temp_buf[1] = U16LOBYTE(addr); + temp_buf[2] = 0; + ret = icn83xx_i2c_txdata(230, temp_buf, 2); + if (ret < 0) { + pr_err("write reg failed! ret: %d\n", ret); + return -1; + } + + icn83xx_i2c_rxdata(232, &temp_buf[2], 1); + flash_info("temp_buf[2]: 0x%x\n", temp_buf[2]); +*/ + ret = icn83xx_readInfo(0, &temp_buf[2]); + if(ret != 0) + return ret; + flash_info("temp_buf[2]: 0x%x\n", temp_buf[2]); + if(temp_buf[2] == 0xff) + { +/* + addr = 0; + temp_buf[0] = U16HIBYTE(addr); + temp_buf[1] = U16LOBYTE(addr); + ret = icn83xx_i2c_txdata(230, temp_buf, 2); + if (ret < 0) { + pr_err("write reg failed! ret: %d\n", ret); + return -1; + } + temp_buf[0] = 0x11; + ret = icn83xx_i2c_txdata(232, temp_buf, 1); + if (ret < 0) { + pr_err("write reg failed! ret: %d\n", ret); + return -1; + } +*/ + ret = icn83xx_writeInfo(0, 0x11); + if(ret != 0) + return ret; + + } + return 0; +} + +/*********************************************************************************************** +Name : icn83xx_read_fw_Ver +Input : fw +Output : +function : read fw version +***********************************************************************************************/ + +short icn83xx_read_fw_Ver(char *fw) +{ + short FWversion; + char tmp[2]; + int file_size; + file_size = icn83xx_open_fw(fw); + if(file_size < 0) + { + return -1; + } + icn83xx_read_fw(0x4000, 2, &tmp[0]); + + icn83xx_close_fw(); + FWversion = (tmp[0]<<8)|tmp[1]; +// flash_info("FWversion: 0x%x\n", FWversion); + return FWversion; +} + + + + +/*********************************************************************************************** +Name : icn83xx_fw_update +Input : fw +Output : +function : upgrade fw +***********************************************************************************************/ + +E_UPGRADE_ERR_TYPE icn83xx_fw_update(char *fw) +{ + int file_size, last_length; + int j, num; + int checksum_bak = 0; + int checksum = 0; + char temp_buf[B_SIZE]; +#ifdef ENABLE_BYTE_CHECK + char temp_buf1[B_SIZE]; +#endif + + file_size = icn83xx_open_fw(fw); + if(file_size < 0) + { + icn83xx_update_status(R_FILE_ERR); + return R_FILE_ERR; + } + + if(icn83xx_goto_progmode() != 0) + { + if(icn83xx_check_progmod() < 0) + { + icn83xx_update_status(R_STATE_ERR); + icn83xx_close_fw(); + return R_STATE_ERR; + } + } +// msleep(50); + + if(icn83xx_op1(0, 0, file_size) != 0) + { + flash_error("icn83xx_op1 error\n"); + icn83xx_update_status(R_ERASE_ERR); + icn83xx_close_fw(); + return R_ERASE_ERR; + } + icn83xx_update_status(5); + + num = file_size/B_SIZE; + for(j=0; j < num; j++) + { + icn83xx_read_fw(j*B_SIZE, B_SIZE, temp_buf); + +// icn83xx_op3(0, j*B_SIZE, temp_buf1, B_SIZE); +// icn83xx_memdump(temp_buf1, B_SIZE); + + if(icn83xx_op2(0, j*B_SIZE, temp_buf, B_SIZE) != 0) + { + icn83xx_update_status(R_PROGRAM_ERR); + icn83xx_close_fw(); + return R_PROGRAM_ERR; + } + checksum_bak = icn83xx_checksum(checksum_bak, temp_buf, B_SIZE); + + icn83xx_update_status(5+(int)(60*j/num)); + } + last_length = file_size - B_SIZE*j; + if(last_length > 0) + { + icn83xx_read_fw(j*B_SIZE, last_length, temp_buf); + +// icn83xx_op3(0, j*B_SIZE, temp_buf1, B_SIZE); +// icn83xx_memdump(temp_buf1, B_SIZE); + + if(icn83xx_op2(0, j*B_SIZE, temp_buf, last_length) != 0) + { + icn83xx_update_status(R_PROGRAM_ERR); + icn83xx_close_fw(); + return R_PROGRAM_ERR; + } + checksum_bak = icn83xx_checksum(checksum_bak, temp_buf, last_length); + } + + icn83xx_close_fw(); + icn83xx_update_status(65); + +#ifdef ENABLE_BYTE_CHECK + file_size = icn83xx_open_fw(fw); + num = file_size/B_SIZE; +#endif + + for(j=0; j < num; j++) + { + +#ifdef ENABLE_BYTE_CHECK + icn83xx_read_fw(j*B_SIZE, B_SIZE, temp_buf1); +#endif + icn83xx_op3(0, j*B_SIZE, temp_buf, B_SIZE); + checksum = icn83xx_checksum(checksum, temp_buf, B_SIZE); + +#ifdef ENABLE_BYTE_CHECK + if(memcmp(temp_buf1, temp_buf, B_SIZE) != 0) + { + flash_error("cmp error, %d\n", j); + icn83xx_memdump(temp_buf1, B_SIZE); + icn83xx_memdump(temp_buf, B_SIZE); + icn83xx_update_status(R_VERIFY_ERR); +#ifdef ENABLE_BYTE_CHECK + icn83xx_close_fw(); +#endif + return R_VERIFY_ERR; + //while(1); + } +#endif + icn83xx_update_status(65+(int)(30*j/num)); + } + +#ifdef ENABLE_BYTE_CHECK + last_length = file_size - B_SIZE*j; +#endif + if(last_length > 0) + { +#ifdef ENABLE_BYTE_CHECK + icn83xx_read_fw(j*B_SIZE, last_length, temp_buf1); +#endif + icn83xx_op3(0, j*B_SIZE, temp_buf, last_length); + checksum = icn83xx_checksum(checksum, temp_buf, last_length); + +#ifdef ENABLE_BYTE_CHECK + if(memcmp(temp_buf1, temp_buf, last_length) != 0) + { + flash_error("cmp error, %d\n", j); + icn83xx_memdump(temp_buf1, last_length); + icn83xx_memdump(temp_buf, last_length); + icn83xx_update_status(R_VERIFY_ERR); +#ifdef ENABLE_BYTE_CHECK + icn83xx_close_fw(); +#endif + return R_VERIFY_ERR; + //while(1); + } +#endif + + } + +#ifdef ENABLE_BYTE_CHECK + icn83xx_close_fw(); +#endif + + flash_info("checksum_bak: 0x%x, checksum: 0x%x\n", checksum_bak, checksum); + if(checksum_bak != checksum) + { + flash_error("upgrade checksum error\n"); + icn83xx_update_status(R_VERIFY_ERR); + return R_VERIFY_ERR; + } + + if(icn83xx_goto_nomalmode() != 0) + { + flash_error("icn83xx_goto_nomalmode error\n"); + icn83xx_update_status(R_STATE_ERR); + return R_STATE_ERR; + } + + icn83xx_update_status(R_OK); + flash_info("upgrade ok\n"); + return R_OK; +} diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/icn83xx_ts/icn83xx.c b/ANDROID_3.4.5/drivers/input/touchscreen/icn83xx_ts/icn83xx.c new file mode 100755 index 00000000..60e42e50 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/icn83xx_ts/icn83xx.c @@ -0,0 +1,2034 @@ +/*++ + + Copyright (c) 2012-2022 ChipOne Technology (Beijing) Co., Ltd. All Rights Reserved. + This PROPRIETARY SOFTWARE is the property of ChipOne Technology (Beijing) Co., Ltd. + and may contains trade secrets and/or other confidential information of ChipOne + Technology (Beijing) Co., Ltd. This file shall not be disclosed to any third party, + in whole or in part, without prior written consent of ChipOne. + THIS PROPRIETARY SOFTWARE & ANY RELATED DOCUMENTATION ARE PROVIDED AS IS, + WITH ALL FAULTS, & WITHOUT WARRANTY OF ANY KIND. CHIPONE DISCLAIMS ALL EXPRESS OR + IMPLIED WARRANTIES. + + File Name: icn83xx.c +Abstract: +input driver. +Author: Zhimin Tian +Date : 01,17,2013 +Version: 1.0 +History : +2012,10,30, V0.1 first version +--*/ + +#include "icn83xx.h" + +#if COMPILE_FW_WITH_DRIVER +#include "icn83xx_fw.h" +#endif + +static struct touch_param g_param; +static struct i2c_client *this_client; +short log_rawdata[28][16];// = {0,}; +short log_diffdata[28][16];// = {0,}; +static int l_suspend = 0; // 1:suspend, 0:normal state + +#if SUPPORT_ROCKCHIP +//if file system not ready,you can use inner array +//static char firmware[128] = "icn83xx_firmware"; +#endif +static char firmware[128] = {"/system/etc/firmware/fw.bin"}; + +//static void icn_delayedwork_fun(struct work_struct *work); +extern int register_bl_notifier(struct notifier_block *nb); +extern int unregister_bl_notifier(struct notifier_block *nb); +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); + +#define dbg(fmt, args...) do{if (g_param.dbg) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__ , ## args);}while(0) + +static ssize_t cat_dbg(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "echo 1 > dbg : print debug message.\necho 0 > dbg : Do not print debug message.\n"); +} +static ssize_t echo_dbg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + g_param.dbg = simple_strtoul(buf, NULL, 10) ? 1 : 0; + return count; +} +static DEVICE_ATTR(dbg, S_IRUGO | S_IWUSR, cat_dbg, echo_dbg); + +#if SUPPORT_SYSFS +static enum hrtimer_restart chipone_timer_func(struct hrtimer *timer); +static ssize_t icn83xx_show_update(struct device* cd,struct device_attribute *attr, char* buf); +static ssize_t icn83xx_store_update(struct device* cd, struct device_attribute *attr, const char* buf, size_t len); +static ssize_t icn83xx_show_process(struct device* cd,struct device_attribute *attr, char* buf); +static ssize_t icn83xx_store_process(struct device* cd, struct device_attribute *attr,const char* buf, size_t len); + +static DEVICE_ATTR(update, S_IRUGO | S_IWUSR, icn83xx_show_update, icn83xx_store_update); +static DEVICE_ATTR(process, S_IRUGO | S_IWUSR, icn83xx_show_process, icn83xx_store_process); + +static ssize_t icn83xx_show_process(struct device* cd,struct device_attribute *attr, char* buf) +{ + ssize_t ret = 0; + sprintf(buf, "icn83xx process\n"); + ret = strlen(buf) + 1; + return ret; +} + +static ssize_t icn83xx_store_process(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) +{ + struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client); + unsigned long on_off = simple_strtoul(buf, NULL, 10); + if(on_off == 0) + { + icn83xx_ts->work_mode = on_off; + } + else if((on_off == 1) || (on_off == 2)) + { + if((icn83xx_ts->work_mode == 0) && (icn83xx_ts->use_irq == 1)) + { + hrtimer_init(&icn83xx_ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + icn83xx_ts->timer.function = chipone_timer_func; + hrtimer_start(&icn83xx_ts->timer, ktime_set(CTP_START_TIMER/1000, (CTP_START_TIMER%1000)*1000000), HRTIMER_MODE_REL); + } + icn83xx_ts->work_mode = on_off; + } + return len; +} + +static ssize_t icn83xx_show_update(struct device* cd, + struct device_attribute *attr, char* buf) +{ + ssize_t ret = 0; + sprintf(buf, "icn83xx firmware\n"); + ret = strlen(buf) + 1; + return ret; +} + +static ssize_t icn83xx_store_update(struct device* cd, struct device_attribute *attr, const char* buf, size_t len) +{ + //int err=0; + //unsigned long on_off = simple_strtoul(buf, NULL, 10); + return len; +} + +static int icn83xx_create_sysfs(struct i2c_client *client) +{ + int err; + struct device *dev = &(client->dev); + icn83xx_trace("%s: \n",__func__); + err = device_create_file(dev, &dev_attr_update); + err = device_create_file(dev, &dev_attr_process); + return err; +} + +#endif + +#if SUPPORT_PROC_FS + +pack_head cmd_head; +static struct proc_dir_entry *icn83xx_proc_entry; +int DATA_LENGTH = 0; +static int icn83xx_tool_write(struct file *filp, const char __user *buff, unsigned long len, void *data) +{ + int ret = 0; + + struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client); + proc_info("%s \n",__func__); + if(down_interruptible(&icn83xx_ts->sem)) + { + return -1; + } + ret = copy_from_user(&cmd_head, buff, CMD_HEAD_LENGTH); + if(ret) + { + proc_error("copy_from_user failed.\n"); + goto write_out; + } + else + { + ret = CMD_HEAD_LENGTH; + } + + proc_info("wr :0x%02x.\n", cmd_head.wr); + proc_info("flag:0x%02x.\n", cmd_head.flag); + proc_info("circle :%d.\n", (int)cmd_head.circle); + proc_info("times :%d.\n", (int)cmd_head.times); + proc_info("retry :%d.\n", (int)cmd_head.retry); + proc_info("data len:%d.\n", (int)cmd_head.data_len); + proc_info("addr len:%d.\n", (int)cmd_head.addr_len); + proc_info("addr:0x%02x%02x.\n", cmd_head.addr[0], cmd_head.addr[1]); + proc_info("len:%d.\n", (int)len); + proc_info("data:0x%02x%02x.\n", buff[CMD_HEAD_LENGTH], buff[CMD_HEAD_LENGTH+1]); + if (1 == cmd_head.wr) // write iic + { + if(1 == cmd_head.addr_len) + { + ret = copy_from_user(&cmd_head.data[0], &buff[CMD_HEAD_LENGTH], cmd_head.data_len); + if(ret) + { + proc_error("copy_from_user failed.\n"); + goto write_out; + } + ret = icn83xx_i2c_txdata(cmd_head.addr[0], &cmd_head.data[0], cmd_head.data_len); + if (ret < 0) { + proc_error("write iic failed! ret: %d\n", ret); + goto write_out; + } + ret = cmd_head.data_len + CMD_HEAD_LENGTH; + goto write_out; + } + } + else if(3 == cmd_head.wr) + { + ret = copy_from_user(&cmd_head.data[0], &buff[CMD_HEAD_LENGTH], cmd_head.data_len); + if(ret) + { + proc_error("copy_from_user failed.\n"); + goto write_out; + } + ret = cmd_head.data_len + CMD_HEAD_LENGTH; + memset(firmware, 0, 128); + memcpy(firmware, &cmd_head.data[0], cmd_head.data_len); + proc_info("firmware : %s\n", firmware); + } + else if(5 == cmd_head.wr) + { + icn83xx_update_status(1); + ret = kernel_thread((int (*)(void *))icn83xx_fw_update,firmware,CLONE_KERNEL); + icn83xx_trace("the kernel_thread result is:%d\n", ret); + } + else if(7 == cmd_head.wr) //write reg + { + if(2 == cmd_head.addr_len) + { + ret = copy_from_user(&cmd_head.data[0], &buff[CMD_HEAD_LENGTH], cmd_head.data_len); + if(ret) + { + proc_error("copy_from_user failed.\n"); + goto write_out; + } + ret = icn83xx_writeReg((cmd_head.addr[0]<<8)|cmd_head.addr[1], cmd_head.data[0]); + if (ret < 0) { + proc_error("write reg failed! ret: %d\n", ret); + goto write_out; + } + ret = cmd_head.data_len + CMD_HEAD_LENGTH; + goto write_out; + + } + } + +write_out: + up(&icn83xx_ts->sem); + return len; + +} +static int icn83xx_tool_read( char *page, char **start, off_t off, int count, int *eof, void *data ) +{ + int i; + int ret = 0; + int data_len = 0; + int len = 0; + int loc = 0; + char retvalue; + struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client); + if(down_interruptible(&icn83xx_ts->sem)) + { + return -1; + } + proc_info("%s: count:%d, off:%d, cmd_head.data_len: %d\n",__func__, count, (int)off, cmd_head.data_len); + if (cmd_head.wr % 2) + { + ret = 0; + goto read_out; + } + else if (0 == cmd_head.wr) //read iic + { + if(1 == cmd_head.addr_len) + { + data_len = cmd_head.data_len; + if(cmd_head.addr[0] == 0xff) + { + page[0] = 83; + proc_info("read ic type: %d\n", page[0]); + } + else + { + while(data_len>0) + { + if (data_len > DATA_LENGTH) + { + len = DATA_LENGTH; + } + else + { + len = data_len; + } + data_len -= len; + memset(&cmd_head.data[0], 0, len+1); + ret = icn83xx_i2c_rxdata(cmd_head.addr[0]+loc, &cmd_head.data[0], len); + //proc_info("cmd_head.data[0]: 0x%02x\n", cmd_head.data[0]); + //proc_info("cmd_head.data[1]: 0x%02x\n", cmd_head.data[1]); + if(ret < 0) + { + icn83xx_error("read iic failed: %d\n", ret); + goto read_out; + } + else + { + //proc_info("iic read out %d bytes, loc: %d\n", len, loc); + memcpy(&page[loc], &cmd_head.data[0], len); + } + loc += len; + } + proc_info("page[0]: 0x%02x\n", page[0]); + proc_info("page[1]: 0x%02x\n", page[1]); + } + } + } + else if(2 == cmd_head.wr) //read rawdata + { + //scan tp rawdata + icn83xx_write_reg(4, 0x20); + mdelay(cmd_head.times); + icn83xx_read_reg(2, &retvalue); + while(retvalue != 1) + { + mdelay(cmd_head.times); + icn83xx_read_reg(2, &retvalue); + } + + if(2 == cmd_head.addr_len) + { + for(i=0; isem); + proc_info("%s out: %d, cmd_head.data_len: %d\n\n",__func__, count, cmd_head.data_len); + return cmd_head.data_len; +} + +int init_proc_node(void) +{ + int i; + memset(&cmd_head, 0, sizeof(cmd_head)); + cmd_head.data = NULL; + + i = 5; + while ((!cmd_head.data) && i) + { + cmd_head.data = kzalloc(i * DATA_LENGTH_UINT, GFP_KERNEL); + if (NULL != cmd_head.data) + { + break; + } + i--; + } + if (i) + { + //DATA_LENGTH = i * DATA_LENGTH_UINT + GTP_ADDR_LENGTH; + DATA_LENGTH = i * DATA_LENGTH_UINT; + icn83xx_trace("alloc memory size:%d.\n", DATA_LENGTH); + } + else + { + proc_error("alloc for memory failed.\n"); + return 0; + } + + icn83xx_proc_entry = create_proc_entry(ICN83XX_ENTRY_NAME, 0666, NULL); + if (icn83xx_proc_entry == NULL) + { + proc_error("Couldn't create proc entry!\n"); + return 0; + } + else + { + icn83xx_trace("Create proc entry success!\n"); + icn83xx_proc_entry->write_proc = icn83xx_tool_write; + icn83xx_proc_entry->read_proc = icn83xx_tool_read; + } + + return 1; +} + +void uninit_proc_node(void) +{ + kfree(cmd_head.data); + cmd_head.data = NULL; + remove_proc_entry(ICN83XX_ENTRY_NAME, NULL); +} + +#endif + + +#if TOUCH_VIRTUAL_KEYS +static ssize_t virtual_keys_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, + __stringify(EV_KEY) ":" __stringify(KEY_MENU) ":100:1030:50:60" + ":" __stringify(EV_KEY) ":" __stringify(KEY_HOME) ":280:1030:50:60" + ":" __stringify(EV_KEY) ":" __stringify(KEY_BACK) ":470:1030:50:60" + ":" __stringify(EV_KEY) ":" __stringify(KEY_SEARCH) ":900:1030:50:60" + "\n"); +} + +static struct kobj_attribute virtual_keys_attr = { + .attr = { + .name = "virtualkeys.chipone-ts", + .mode = S_IRUGO, + }, + .show = &virtual_keys_show, +}; + +static struct attribute *properties_attrs[] = { + &virtual_keys_attr.attr, + NULL +}; + +static struct attribute_group properties_attr_group = { + .attrs = properties_attrs, +}; + +static void icn83xx_ts_virtual_keys_init(void) +{ + int ret = 0; + struct kobject *properties_kobj; + properties_kobj = kobject_create_and_add("board_properties", NULL); + if (properties_kobj) + ret = sysfs_create_group(properties_kobj, + &properties_attr_group); + if (!properties_kobj || ret) + pr_err("failed to create board_properties\n"); +} +#endif + + +/* --------------------------------------------------------------------- + * + * Chipone panel related driver + * + * + ----------------------------------------------------------------------*/ +/*********************************************************************************************** +Name : icn83xx_ts_wakeup +Input : void +Output : ret +function : this function is used to wakeup tp + ***********************************************************************************************/ +void icn83xx_ts_wakeup(void) +{ + //#if def TOUCH_RESET_PIN + +} + +/*********************************************************************************************** +Name : icn83xx_ts_reset +Input : void +Output : ret +function : this function is used to reset tp, you should not delete it + ***********************************************************************************************/ +void icn83xx_ts_reset(void) +{ + int rst = g_param.rstgpio; + gpio_direction_output(rst, 0); + //mdelay(30); + msleep(50); + gpio_direction_output(rst, 1); + //mdelay(50); + msleep(50); + +} + +/*********************************************************************************************** +Name : icn83xx_irq_disable +Input : void +Output : ret +function : this function is used to disable irq + ***********************************************************************************************/ +void icn83xx_irq_disable(void) +{ + unsigned long irqflags; + struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client); + + spin_lock_irqsave(&icn83xx_ts->irq_lock, irqflags); + if (!icn83xx_ts->irq_is_disable) + { + icn83xx_ts->irq_is_disable = 1; + wmt_gpio_mask_irq(g_param.irqgpio); + //disable_irq_nosync(icn83xx_ts->irq); + //disable_irq(icn83xx_ts->irq); + } + spin_unlock_irqrestore(&icn83xx_ts->irq_lock, irqflags); +} + +/*********************************************************************************************** +Name : icn83xx_irq_enable +Input : void +Output : ret +function : this function is used to enable irq + ***********************************************************************************************/ +void icn83xx_irq_enable(void) +{ + unsigned long irqflags = 0; + struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client); + + spin_lock_irqsave(&icn83xx_ts->irq_lock, irqflags); + if (icn83xx_ts->irq_is_disable) + { + wmt_gpio_unmask_irq(g_param.irqgpio); + //enable_irq(icn83xx_ts->irq); + icn83xx_ts->irq_is_disable = 0; + } + spin_unlock_irqrestore(&icn83xx_ts->irq_lock, irqflags); + +} + +/*********************************************************************************************** +Name : icn83xx_prog_i2c_rxdata +Input : addr + *rxdata + length +Output : ret +function : read data from icn83xx, prog mode + ***********************************************************************************************/ +int icn83xx_prog_i2c_rxdata(unsigned short addr, char *rxdata, int length) +{ + int ret = -1; + int retries = 0; +#if 0 + struct i2c_msg msgs[] = { + { + .addr = ICN83XX_PROG_IIC_ADDR,//this_client->addr, + .flags = I2C_M_RD, + .len = length, + .buf = rxdata, +#if SUPPORT_ROCKCHIP + .scl_rate = ICN83XX_I2C_SCL, +#endif + }, + }; + + icn83xx_prog_i2c_txdata(addr, NULL, 0); + while(retries < IIC_RETRY_NUM) + { + ret = i2c_transfer(this_client->adapter, msgs, 1); + if(ret == 1)break; + retries++; + } + if (retries >= IIC_RETRY_NUM) + { + icn83xx_error("%s i2c read error: %d\n", __func__, ret); + // icn83xx_ts_reset(); + } +#else + unsigned char tmp_buf[2]; + struct i2c_msg msgs[] = { + { + .addr = ICN83XX_PROG_IIC_ADDR,//this_client->addr, + .flags = 0, + .len = 2, + .buf = tmp_buf, +#if SUPPORT_ROCKCHIP + .scl_rate = ICN83XX_I2C_SCL, +#endif + }, + { + .addr = ICN83XX_PROG_IIC_ADDR,//this_client->addr, + .flags = I2C_M_RD, + .len = length, + .buf = rxdata, +#if SUPPORT_ROCKCHIP + .scl_rate = ICN83XX_I2C_SCL, +#endif + }, + }; + tmp_buf[0] = U16HIBYTE(addr); + tmp_buf[1] = U16LOBYTE(addr); + + while(retries < IIC_RETRY_NUM) + { + ret = i2c_transfer(this_client->adapter, msgs, 2); + if(ret == 2)break; + retries++; + } + + if (retries >= IIC_RETRY_NUM) + { + icn83xx_error("%s i2c read error: %d\n", __func__, ret); + // icn83xx_ts_reset(); + } +#endif + return ret; +} +/*********************************************************************************************** +Name : icn83xx_prog_i2c_txdata +Input : addr + *rxdata + length +Output : ret +function : send data to icn83xx , prog mode + ***********************************************************************************************/ +int icn83xx_prog_i2c_txdata(unsigned short addr, char *txdata, int length) +{ + int ret = -1; + char tmp_buf[128]; + int retries = 0; + struct i2c_msg msg[] = { + { + .addr = ICN83XX_PROG_IIC_ADDR,//this_client->addr, + .flags = 0, + .len = length + 2, + .buf = tmp_buf, +#if SUPPORT_ROCKCHIP + .scl_rate = ICN83XX_I2C_SCL, +#endif + }, + }; + + if (length > 125) + { + icn83xx_error("%s too big datalen = %d!\n", __func__, length); + return -1; + } + + tmp_buf[0] = U16HIBYTE(addr); + tmp_buf[1] = U16LOBYTE(addr); + + if (length != 0 && txdata != NULL) + { + memcpy(&tmp_buf[2], txdata, length); + } + + while(retries < IIC_RETRY_NUM) + { + ret = i2c_transfer(this_client->adapter, msg, 1); + if(ret == 1)break; + retries++; + } + + if (retries >= IIC_RETRY_NUM) + { + icn83xx_error("%s i2c write error: %d\n", __func__, ret); + // icn83xx_ts_reset(); + } + return ret; +} +/*********************************************************************************************** +Name : icn83xx_prog_write_reg +Input : addr -- address +para -- parameter +Output : +function : write register of icn83xx, prog mode + ***********************************************************************************************/ +int icn83xx_prog_write_reg(unsigned short addr, char para) +{ + char buf[3]; + int ret = -1; + + buf[0] = para; + ret = icn83xx_prog_i2c_txdata(addr, buf, 1); + if (ret < 0) { + icn83xx_error("write reg failed! %#x ret: %d\n", buf[0], ret); + return -1; + } + + return ret; +} + + +/*********************************************************************************************** +Name : icn83xx_prog_read_reg +Input : addr +pdata +Output : +function : read register of icn83xx, prog mode + ***********************************************************************************************/ +int icn83xx_prog_read_reg(unsigned short addr, char *pdata) +{ + int ret = -1; + ret = icn83xx_prog_i2c_rxdata(addr, pdata, 1); + return ret; +} + +/*********************************************************************************************** +Name : icn83xx_i2c_rxdata +Input : addr + *rxdata + length +Output : ret +function : read data from icn83xx, normal mode + ***********************************************************************************************/ +int icn83xx_i2c_rxdata(unsigned char addr, char *rxdata, int length) +{ + int ret = -1; + int retries = 0; +#if 0 + struct i2c_msg msgs[] = { + { + .addr = this_client->addr, + .flags = I2C_M_RD, + .len = length, + .buf = rxdata, +#if SUPPORT_ROCKCHIP + .scl_rate = ICN83XX_I2C_SCL, +#endif + }, + }; + + icn83xx_i2c_txdata(addr, NULL, 0); + while(retries < IIC_RETRY_NUM) + { + + ret = i2c_transfer(this_client->adapter, msgs, 1); + if(ret == 1)break; + retries++; + } + + if (retries >= IIC_RETRY_NUM) + { + icn83xx_error("%s i2c read error: %d\n", __func__, ret); + // icn83xx_ts_reset(); + } + +#else + unsigned char tmp_buf[1]; + struct i2c_msg msgs[] = { + { + .addr = this_client->addr, + .flags = 0, + .len = 1, + .buf = tmp_buf, +#if SUPPORT_ROCKCHIP + .scl_rate = ICN83XX_I2C_SCL, +#endif + }, + { + .addr = this_client->addr, + .flags = I2C_M_RD, + .len = length, + .buf = rxdata, +#if SUPPORT_ROCKCHIP + .scl_rate = ICN83XX_I2C_SCL, +#endif + }, + }; + tmp_buf[0] = addr; + + while(retries < IIC_RETRY_NUM) + { + ret = i2c_transfer(this_client->adapter, msgs, 2); + if(ret == 2)break; + retries++; + } + + if (retries >= IIC_RETRY_NUM) + { + icn83xx_error("%s i2c read error: %d\n", __func__, ret); + icn83xx_ts_reset(); + } +#endif + + return ret; +} +/*********************************************************************************************** +Name : icn83xx_i2c_txdata +Input : addr + *rxdata + length +Output : ret +function : send data to icn83xx , normal mode + ***********************************************************************************************/ +int icn83xx_i2c_txdata(unsigned char addr, char *txdata, int length) +{ + int ret = -1; + unsigned char tmp_buf[128]; + int retries = 0; + + struct i2c_msg msg[] = { + { + .addr = this_client->addr, + .flags = 0, + .len = length + 1, + .buf = tmp_buf, +#if SUPPORT_ROCKCHIP + .scl_rate = ICN83XX_I2C_SCL, +#endif + }, + }; + + if (length > 125) + { + icn83xx_error("%s too big datalen = %d!\n", __func__, length); + return -1; + } + + tmp_buf[0] = addr; + + if (length != 0 && txdata != NULL) + { + memcpy(&tmp_buf[1], txdata, length); + } + + while(retries < IIC_RETRY_NUM) + { + ret = i2c_transfer(this_client->adapter, msg, 1); + if(ret == 1)break; + retries++; + } + + if (retries >= IIC_RETRY_NUM) + { + icn83xx_error("%s i2c write error: %d\n", __func__, ret); + icn83xx_ts_reset(); + } + + return ret; +} + +/*********************************************************************************************** +Name : icn83xx_write_reg +Input : addr -- address +para -- parameter +Output : +function : write register of icn83xx, normal mode + ***********************************************************************************************/ +int icn83xx_write_reg(unsigned char addr, char para) +{ + char buf[3]; + int ret = -1; + + buf[0] = para; + ret = icn83xx_i2c_txdata(addr, buf, 1); + if (ret < 0) { + icn83xx_error("write reg failed! %#x ret: %d\n", buf[0], ret); + return -1; + } + + return ret; +} + + +/*********************************************************************************************** +Name : icn83xx_read_reg +Input : addr +pdata +Output : +function : read register of icn83xx, normal mode + ***********************************************************************************************/ +int icn83xx_read_reg(unsigned char addr, char *pdata) +{ + int ret = -1; + ret = icn83xx_i2c_rxdata(addr, pdata, 1); + return ret; +} + +#if SUPPORT_FW_UPDATE +/*********************************************************************************************** +Name : icn83xx_log +Input : 0: rawdata, 1: diff data +Output : err type +function : calibrate param + ***********************************************************************************************/ +void icn83xx_log(char diff) +{ + char row = 0; + char column = 0; + int i, j; + icn83xx_read_reg(160, &row); + icn83xx_read_reg(161, &column); + + if(diff == 1) + { + icn83xx_readTP(row, column, (char *)&log_diffdata[0][0]); + + for(i=0; i 0) + { + return ret; + } + icn83xx_error("iic test error! %d\n", retry); + msleep(3); + } + return ret; +} + +/*********************************************************************************************** +Name : icn83xx_report_value_B +Input : void +Output : +function : reprot touch ponit + ***********************************************************************************************/ +#if CTP_REPORT_PROTOCOL +static int icn83xx_report_value_B(void) +{ + struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client); + char buf[POINT_NUM*POINT_SIZE+3]={0}; + static unsigned char finger_last[POINT_NUM + 1]={0}; + unsigned char finger_current[POINT_NUM + 1] = {0}; + unsigned int position = 0; + int temp = 0; + int ret = -1; + int x,y; + icn83xx_info("==icn83xx_report_value_B ==\n"); + // icn83xx_trace("==icn83xx_report_value_B ==\n"); + ret = icn83xx_i2c_rxdata(16, buf, POINT_NUM*POINT_SIZE+2); + if (ret < 0) { + icn83xx_error("%s read_data i2c_rxdata failed: %d\n", __func__, ret); + return ret; + } + + icn83xx_ts->point_num = buf[1]; + if (icn83xx_ts->point_num > 5) { + printk("error point_num : %d\n",icn83xx_ts->point_num); + return -1; + } + if(icn83xx_ts->point_num > 0) + { + for(position = 0; positionpoint_num; position++) + { + temp = buf[2 + POINT_SIZE*position] + 1; + finger_current[temp] = 1; + icn83xx_ts->point_info[temp].u8ID = buf[2 + POINT_SIZE*position]; + icn83xx_ts->point_info[temp].u16PosX = (buf[3 + POINT_SIZE*position]<<8) + buf[4 + POINT_SIZE*position]; + icn83xx_ts->point_info[temp].u16PosY = (buf[5 + POINT_SIZE*position]<<8) + buf[6 + POINT_SIZE*position]; + icn83xx_ts->point_info[temp].u8Pressure = buf[7 + POINT_SIZE*position]; + icn83xx_ts->point_info[temp].u8EventId = buf[8 + POINT_SIZE*position]; + + if(icn83xx_ts->point_info[temp].u8EventId == 4) + finger_current[temp] = 0; + + if(1 == icn83xx_ts->revert_x_flag) + { + icn83xx_ts->point_info[temp].u16PosX = icn83xx_ts->screen_max_x- icn83xx_ts->point_info[temp].u16PosX; + } + if(1 == icn83xx_ts->revert_y_flag) + { + icn83xx_ts->point_info[temp].u16PosY = icn83xx_ts->screen_max_y- icn83xx_ts->point_info[temp].u16PosY; + } + icn83xx_info("temp %d\n", temp); + icn83xx_info("u8ID %d\n", icn83xx_ts->point_info[temp].u8ID); + icn83xx_info("u16PosX %d\n", icn83xx_ts->point_info[temp].u16PosX); + icn83xx_info("u16PosY %d\n", icn83xx_ts->point_info[temp].u16PosY); + icn83xx_info("u8Pressure %d\n", icn83xx_ts->point_info[temp].u8Pressure); + icn83xx_info("u8EventId %d\n", icn83xx_ts->point_info[temp].u8EventId); + //icn83xx_info("u8Pressure %d\n", icn83xx_ts->point_info[temp].u8Pressure*16); + } + } + else + { + for(position = 1; position < POINT_NUM+1; position++) + { + finger_current[position] = 0; + } + icn83xx_info("no touch\n"); + } + + for(position = 1; position < POINT_NUM + 1; position++) + { + if((finger_current[position] == 0) && (finger_last[position] != 0)) + { + input_mt_slot(icn83xx_ts->input_dev, position-1); + input_mt_report_slot_state(icn83xx_ts->input_dev, MT_TOOL_FINGER, false); + icn83xx_point_info("one touch up: %d\n", position); + } + else if(finger_current[position]) + { + if (g_param.xyswap == 0) + { + x = icn83xx_ts->point_info[position].u16PosX; + y = icn83xx_ts->point_info[position].u16PosY; + } else { + y = icn83xx_ts->point_info[position].u16PosX; + x = icn83xx_ts->point_info[position].u16PosY; + } + if (g_param.xdir == -1) + { + x = g_param.panelres_x - x; + } + if (g_param.ydir == -1) + { + y = g_param.panelres_y - y; + } + + if (g_param.lcd_exchg) { + int tmp; + tmp = x; + x = y; + y = g_param.panelres_x - tmp; + } + + input_mt_slot(icn83xx_ts->input_dev, position-1); + input_mt_report_slot_state(icn83xx_ts->input_dev, MT_TOOL_FINGER, true); + input_report_abs(icn83xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, 1); + //input_report_abs(icn83xx_ts->input_dev, ABS_MT_PRESSURE, icn83xx_ts->point_info[position].u8Pressure); + input_report_abs(icn83xx_ts->input_dev, ABS_MT_PRESSURE, 200); + input_report_abs(icn83xx_ts->input_dev, ABS_MT_POSITION_X, x); + input_report_abs(icn83xx_ts->input_dev, ABS_MT_POSITION_Y, y); + icn83xx_point_info("===position: %d, x = %d,y = %d, press = %d ====\n", position, icn83xx_ts->point_info[position].u16PosX,icn83xx_ts->point_info[position].u16PosY, icn83xx_ts->point_info[position].u8Pressure); + // icn83xx_trace("===position: %d, x = %d,y = %d, press = %d ====\n", position, icn83xx_ts->point_info[position].u16PosX,icn83xx_ts->point_info[position].u16PosY, icn83xx_ts->point_info[position].u8Pressure); + dbg("raw%d(%d,%d), rpt%d(%d,%d)\n", position, icn83xx_ts->point_info[position].u16PosX, icn83xx_ts->point_info[position].u16PosY, position, x, y); + } + + } + input_sync(icn83xx_ts->input_dev); + + for(position = 1; position < POINT_NUM + 1; position++) + { + finger_last[position] = finger_current[position]; + } + return 0; +} + +#else + +/*********************************************************************************************** +Name : icn83xx_ts_release +Input : void +Output : +function : touch release + ***********************************************************************************************/ +static void icn83xx_ts_release(void) +{ + struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client); + icn83xx_info("==icn83xx_ts_release ==\n"); + input_report_abs(icn83xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, 0); + input_sync(icn83xx_ts->input_dev); +} + +/*********************************************************************************************** +Name : icn83xx_report_value_A +Input : void +Output : +function : reprot touch ponit + ***********************************************************************************************/ +static int icn83xx_report_value_A(void) +{ + struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client); + char buf[POINT_NUM*POINT_SIZE+3]={0}; + int ret = -1; + int i; +#if TOUCH_VIRTUAL_KEYS + unsigned char button; + static unsigned char button_last; +#endif + icn83xx_info("==icn83xx_report_value_A ==\n"); + + ret = icn83xx_i2c_rxdata(16, buf, POINT_NUM*POINT_SIZE+2); + if (ret < 0) { + icn83xx_error("%s read_data i2c_rxdata failed: %d\n", __func__, ret); + return ret; + } +#if TOUCH_VIRTUAL_KEYS + button = buf[0]; + icn83xx_info("%s: button=%d\n",__func__, button); + + if((button_last != 0) && (button == 0)) + { + icn83xx_ts_release(); + button_last = button; + return 1; + } + if(button != 0) + { + switch(button) + { + case ICN_VIRTUAL_BUTTON_HOME: + icn83xx_info("ICN_VIRTUAL_BUTTON_HOME down\n"); + input_report_abs(icn83xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, 200); + input_report_abs(icn83xx_ts->input_dev, ABS_MT_POSITION_X, 280); + input_report_abs(icn83xx_ts->input_dev, ABS_MT_POSITION_Y, 1030); + input_report_abs(icn83xx_ts->input_dev, ABS_MT_WIDTH_MAJOR, 1); + input_mt_sync(icn83xx_ts->input_dev); + input_sync(icn83xx_ts->input_dev); + break; + case ICN_VIRTUAL_BUTTON_BACK: + icn83xx_info("ICN_VIRTUAL_BUTTON_BACK down\n"); + input_report_abs(icn83xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, 200); + input_report_abs(icn83xx_ts->input_dev, ABS_MT_POSITION_X, 470); + input_report_abs(icn83xx_ts->input_dev, ABS_MT_POSITION_Y, 1030); + input_report_abs(icn83xx_ts->input_dev, ABS_MT_WIDTH_MAJOR, 1); + input_mt_sync(icn83xx_ts->input_dev); + input_sync(icn83xx_ts->input_dev); + break; + case ICN_VIRTUAL_BUTTON_MENU: + icn83xx_info("ICN_VIRTUAL_BUTTON_MENU down\n"); + input_report_abs(icn83xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, 200); + input_report_abs(icn83xx_ts->input_dev, ABS_MT_POSITION_X, 100); + input_report_abs(icn83xx_ts->input_dev, ABS_MT_POSITION_Y, 1030); + input_report_abs(icn83xx_ts->input_dev, ABS_MT_WIDTH_MAJOR, 1); + input_mt_sync(icn83xx_ts->input_dev); + input_sync(icn83xx_ts->input_dev); + break; + default: + icn83xx_info("other gesture\n"); + break; + } + button_last = button; + return 1; + } +#endif + + icn83xx_ts->point_num = buf[1]; + if (icn83xx_ts->point_num == 0) { + icn83xx_ts_release(); + return 1; + } + for(i=0;ipoint_num;i++){ + if(buf[8 + POINT_SIZE*i] != 4) break ; + } + + if(i == icn83xx_ts->point_num) { + icn83xx_ts_release(); + return 1; + } + + for(i=0; ipoint_num; i++) + { + icn83xx_ts->point_info[i].u8ID = buf[2 + POINT_SIZE*i]; + icn83xx_ts->point_info[i].u16PosX = (buf[3 + POINT_SIZE*i]<<8) + buf[4 + POINT_SIZE*i]; + icn83xx_ts->point_info[i].u16PosY = (buf[5 + POINT_SIZE*i]<<8) + buf[6 + POINT_SIZE*i]; + icn83xx_ts->point_info[i].u8Pressure = 200;//buf[7 + POINT_SIZE*i]; + icn83xx_ts->point_info[i].u8EventId = buf[8 + POINT_SIZE*i]; + + if(1 == icn83xx_ts->revert_x_flag) + { + icn83xx_ts->point_info[i].u16PosX = icn83xx_ts->screen_max_x- icn83xx_ts->point_info[i].u16PosX; + } + if(1 == icn83xx_ts->revert_y_flag) + { + icn83xx_ts->point_info[i].u16PosY = icn83xx_ts->screen_max_y- icn83xx_ts->point_info[i].u16PosY; + } + + icn83xx_info("u8ID %d\n", icn83xx_ts->point_info[i].u8ID); + icn83xx_info("u16PosX %d\n", icn83xx_ts->point_info[i].u16PosX); + icn83xx_info("u16PosY %d\n", icn83xx_ts->point_info[i].u16PosY); + icn83xx_info("u8Pressure %d\n", icn83xx_ts->point_info[i].u8Pressure); + icn83xx_info("u8EventId %d\n", icn83xx_ts->point_info[i].u8EventId); + + + input_report_abs(icn83xx_ts->input_dev, ABS_MT_TRACKING_ID, icn83xx_ts->point_info[i].u8ID); + input_report_abs(icn83xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, icn83xx_ts->point_info[i].u8Pressure); + input_report_abs(icn83xx_ts->input_dev, ABS_MT_POSITION_X, icn83xx_ts->point_info[i].u16PosX); + input_report_abs(icn83xx_ts->input_dev, ABS_MT_POSITION_Y, icn83xx_ts->point_info[i].u16PosY); + input_report_abs(icn83xx_ts->input_dev, ABS_MT_WIDTH_MAJOR, 1); + input_mt_sync(icn83xx_ts->input_dev); + icn83xx_point_info("point: %d ===x = %d,y = %d, press = %d ====\n",i, icn83xx_ts->point_info[i].u16PosX,icn83xx_ts->point_info[i].u16PosY, icn83xx_ts->point_info[i].u8Pressure); + } + + input_sync(icn83xx_ts->input_dev); + return 0; +} +#endif + +/*********************************************************************************************** +Name : icn83xx_ts_pen_irq_work +Input : void +Output : +function : work_struct + ***********************************************************************************************/ +static void icn83xx_ts_pen_irq_work(struct work_struct *work) +{ + struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client); +#if SUPPORT_PROC_FS + if(down_interruptible(&icn83xx_ts->sem)) + { + return; + } +#endif + + if(icn83xx_ts->work_mode == 0) + { +#if CTP_REPORT_PROTOCOL + icn83xx_report_value_B(); +#else + icn83xx_report_value_A(); +#endif + + } +#if SUPPORT_FW_UPDATE + else if(icn83xx_ts->work_mode == 1) + { + printk("log raw data\n"); + icn83xx_log(0); //raw data + } + else if(icn83xx_ts->work_mode == 2) + { + printk("log diff data\n"); + icn83xx_log(1); //diff data + } +#endif + +#if SUPPORT_PROC_FS + up(&icn83xx_ts->sem); +#endif + wmt_gpio_unmask_irq(g_param.irqgpio); + +} +/*********************************************************************************************** +Name : chipone_timer_func +Input : void +Output : +function : Timer interrupt service routine. + ***********************************************************************************************/ +static enum hrtimer_restart chipone_timer_func(struct hrtimer *timer) +{ + struct icn83xx_ts_data *icn83xx_ts = container_of(timer, struct icn83xx_ts_data, timer); + queue_work(icn83xx_ts->ts_workqueue, &icn83xx_ts->pen_event_work); + + if(icn83xx_ts->use_irq == 1) + { + if((icn83xx_ts->work_mode == 1) || (icn83xx_ts->work_mode == 2)) + { + hrtimer_start(&icn83xx_ts->timer, ktime_set(CTP_POLL_TIMER/1000, (CTP_POLL_TIMER%1000)*1000000), HRTIMER_MODE_REL); + } + } + else + { + hrtimer_start(&icn83xx_ts->timer, ktime_set(CTP_POLL_TIMER/1000, (CTP_POLL_TIMER%1000)*1000000), HRTIMER_MODE_REL); + } + return HRTIMER_NORESTART; +} +/*********************************************************************************************** +Name : icn83xx_ts_interrupt +Input : void +Output : +function : interrupt service routine + ***********************************************************************************************/ +static irqreturn_t icn83xx_ts_interrupt(int irq, void *dev_id) +{ + struct icn83xx_ts_data *icn83xx_ts = dev_id; + int irqindex = g_param.irqgpio; + + icn83xx_info("==========------icn83xx_ts TS Interrupt-----============\n"); + if (gpio_irqstatus(irqindex)) { + wmt_gpio_ack_irq(irqindex); + if (is_gpio_irqenable(irqindex) && l_suspend == 0) { + wmt_gpio_mask_irq(irqindex); + if(icn83xx_ts->work_mode != 0) { + wmt_gpio_unmask_irq(irqindex); + return IRQ_HANDLED; + } + //icn83xx_irq_disable(); + if (!work_pending(&icn83xx_ts->pen_event_work)) { + //icn83xx_info("Enter work\n"); + queue_work(icn83xx_ts->ts_workqueue, &icn83xx_ts->pen_event_work); + } + } + return IRQ_HANDLED; + } + return IRQ_NONE; +} + + +#ifdef CONFIG_HAS_EARLYSUSPEND +/*********************************************************************************************** +Name : icn83xx_ts_suspend +Input : void +Output : +function : tp enter sleep mode + ***********************************************************************************************/ +static void icn83xx_ts_early_suspend(struct early_suspend *handler) +{ + int retry = 0; + struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client); + icn83xx_trace("icn83xx_ts_suspend: write ICN83XX_REG_PMODE .\n"); + if (icn83xx_ts->use_irq) + { + icn83xx_irq_disable(); + icn83xx_trace("icn83xx_ts_suspend:disable irq .\n"); + } + else + { + hrtimer_cancel(&icn83xx_ts->timer); + } + for(retry = 0;retry <3; retry++ ) + { + icn83xx_write_reg(ICN83XX_REG_PMODE, PMODE_HIBERNATE); + } +} + +/*********************************************************************************************** +Name : icn83xx_ts_resume +Input : void +Output : +function : wakeup tp or reset tp + ***********************************************************************************************/ +static void icn83xx_ts_late_resume(struct early_suspend *handler) +{ + struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client); + int i; + printk("==icn83xx_ts_resume== \n"); + // icn83xx_ts_reset(); + //report touch release +#if CTP_REPORT_PROTOCOL + for(i = 0; i < POINT_NUM; i++) + { + input_mt_slot(icn83xx_ts->input_dev, i); + input_mt_report_slot_state(icn83xx_ts->input_dev, MT_TOOL_FINGER, false); + } +#else + icn83xx_ts_release(); +#endif + icn83xx_ts_wakeup(); + icn83xx_ts_reset(); + if (icn83xx_ts->use_irq) + { + printk("icn83xx_irq_enable\n"); + icn83xx_irq_enable(); + } + else + { printk("icn83xx_ts_resume hrtimer_start\n"); + hrtimer_start(&icn83xx_ts->timer, ktime_set(CTP_START_TIMER/1000, (CTP_START_TIMER%1000)*1000000), HRTIMER_MODE_REL); + } + +} +#endif + +#ifdef CONFIG_PM +/*********************************************************************************************** +Name : icn83xx_ts_suspend +Input : void +Output : +function : tp enter sleep mode + ***********************************************************************************************/ +static int icn83xx_ts_suspend(struct device *pdev) +{ + //int retry = 0; + struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client); + icn83xx_trace("icn83xx_ts_suspend: write ICN83XX_REG_PMODE .\n"); + if (icn83xx_ts->use_irq) + { + icn83xx_irq_disable(); + icn83xx_trace("icn83xx_ts_suspend:disable irq .\n"); + } + else + { + hrtimer_cancel(&icn83xx_ts->timer); + } + /*for(retry = 0;retry <3; retry++ ) + { + icn83xx_write_reg(ICN83XX_REG_PMODE, PMODE_HIBERNATE); + } */ + l_suspend = 1; + return 0; +} + +/*********************************************************************************************** +Name : icn83xx_ts_resume +Input : void +Output : +function : wakeup tp or reset tp + ***********************************************************************************************/ +static int icn83xx_ts_resume(struct device *pdev) +{ + struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client); + int i; + printk("==icn83xx_ts_resume== \n"); + // icn83xx_ts_reset(); + //report touch release +#if CTP_REPORT_PROTOCOL + for(i = 0; i < POINT_NUM; i++) + { + input_mt_slot(icn83xx_ts->input_dev, i); + input_mt_report_slot_state(icn83xx_ts->input_dev, MT_TOOL_FINGER, false); + } +#else + icn83xx_ts_release(); +#endif + //icn83xx_ts_wakeup(); + icn83xx_ts_reset(); + l_suspend = 0; + if (icn83xx_ts->use_irq) + { + printk("icn83xx_irq_enable\n"); + icn83xx_irq_enable(); + } + else + { printk("icn83xx_ts_resume hrtimer_start\n"); + hrtimer_start(&icn83xx_ts->timer, ktime_set(CTP_START_TIMER/1000, (CTP_START_TIMER%1000)*1000000), HRTIMER_MODE_REL); + } + return 0; +} +#else +#define icn83xx_ts_suspend NULL +#define icn83xx_ts_resume NULL +#endif + +/*********************************************************************************************** +Name : icn83xx_request_io_port +Input : void +Output : +function : 0 success, + ***********************************************************************************************/ +static int icn83xx_request_io_port(struct icn83xx_ts_data *icn83xx_ts) +{ +#if SUPPORT_ROCKCHIP + icn83xx_ts->screen_max_x = SCREEN_MAX_X; + icn83xx_ts->screen_max_y = SCREEN_MAX_Y; + icn83xx_ts->irq = CTP_IRQ_PORT; +#endif + icn83xx_ts->irq = IRQ_GPIO; + + if (gpio_request(g_param.rstgpio, "ts_rst") < 0) { + printk("gpio(%d) touchscreen reset request fail\n", g_param.rstgpio); + return -EIO; + } + gpio_direction_output(g_param.rstgpio, 1); + + if (gpio_request(g_param.irqgpio, "ts_irq") < 0) { + printk("gpio(%d) touchscreen interrupt request fail\n", g_param.irqgpio); + gpio_free(g_param.rstgpio); + return -EIO; + } + wmt_gpio_setpull(g_param.irqgpio, WMT_GPIO_PULL_UP); + gpio_direction_input(g_param.irqgpio); + + return 0; +} + +/*********************************************************************************************** +Name : icn83xx_free_io_port +Input : void +Output : +function : 0 success, + ***********************************************************************************************/ +static void icn83xx_free_io_port(void) +{ + gpio_free(g_param.rstgpio); + gpio_free(g_param.irqgpio); +} + +/*********************************************************************************************** +Name : icn83xx_request_irq +Input : void +Output : +function : 0 success, + ***********************************************************************************************/ +static int icn83xx_request_irq(struct icn83xx_ts_data *icn83xx_ts) +{ + int err = -1; + + /*err = gpio_request(icn83xx_ts->irq, "TS_INT"); //Request IO + if (err < 0) + { + icn83xx_error("Failed to request GPIO:%d, ERRNO:%d\n", (int)icn83xx_ts->irq, err); + return err; + } + gpio_direction_input(icn83xx_ts->irq);*/ + + wmt_gpio_set_irq_type(g_param.irqgpio, IRQ_TYPE_EDGE_FALLING); + err = request_irq(icn83xx_ts->irq, icn83xx_ts_interrupt, IRQF_SHARED, "icn83xx_ts", icn83xx_ts); + if (err < 0) + { + icn83xx_error("icn83xx_ts_probe: request irq failed\n"); + return err; + } + else + { + icn83xx_irq_disable(); + icn83xx_ts->use_irq = 1; + } + + return 0; +} + + +/*********************************************************************************************** +Name : icn83xx_free_irq +Input : void +Output : +function : 0 success, + ***********************************************************************************************/ +static void icn83xx_free_irq(struct icn83xx_ts_data *icn83xx_ts) +{ + if (icn83xx_ts) + { + if (icn83xx_ts->use_irq) + { + free_irq(icn83xx_ts->irq, icn83xx_ts); + } + else + { + hrtimer_cancel(&icn83xx_ts->timer); + } + } +} + +/*********************************************************************************************** +Name : icn83xx_request_input_dev +Input : void +Output : +function : 0 success, + ***********************************************************************************************/ +static int icn83xx_request_input_dev(struct icn83xx_ts_data *icn83xx_ts) +{ + int ret = -1; + struct input_dev *input_dev; + + input_dev = input_allocate_device(); + if (!input_dev) { + icn83xx_error("failed to allocate input device\n"); + return -ENOMEM; + } + icn83xx_ts->input_dev = input_dev; + + icn83xx_ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) ; +#if CTP_REPORT_PROTOCOL + __set_bit(INPUT_PROP_DIRECT, icn83xx_ts->input_dev->propbit); + input_mt_init_slots(icn83xx_ts->input_dev, 255); +#else + set_bit(ABS_MT_TOUCH_MAJOR, icn83xx_ts->input_dev->absbit); + set_bit(ABS_MT_POSITION_X, icn83xx_ts->input_dev->absbit); + set_bit(ABS_MT_POSITION_Y, icn83xx_ts->input_dev->absbit); + set_bit(ABS_MT_WIDTH_MAJOR, icn83xx_ts->input_dev->absbit); +#endif + if (g_param.lcd_exchg) { + input_set_abs_params(icn83xx_ts->input_dev, ABS_MT_POSITION_X, 0, g_param.panelres_y, 0, 0); + input_set_abs_params(icn83xx_ts->input_dev, ABS_MT_POSITION_Y, 0, g_param.panelres_x, 0, 0); + } else { + input_set_abs_params(icn83xx_ts->input_dev, ABS_MT_POSITION_X, 0, g_param.panelres_x, 0, 0); + input_set_abs_params(icn83xx_ts->input_dev, ABS_MT_POSITION_Y, 0, g_param.panelres_y, 0, 0); + } + input_set_abs_params(icn83xx_ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0); + input_set_abs_params(icn83xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); + input_set_abs_params(icn83xx_ts->input_dev, ABS_MT_TRACKING_ID, 0, 255, 0, 0); + + __set_bit(KEY_MENU, input_dev->keybit); + __set_bit(KEY_BACK, input_dev->keybit); + __set_bit(KEY_HOME, input_dev->keybit); + __set_bit(KEY_SEARCH, input_dev->keybit); + + input_dev->name = CTP_NAME; + ret = input_register_device(input_dev); + if (ret) { + icn83xx_error("Register %s input device failed\n", input_dev->name); + input_free_device(input_dev); + return -ENODEV; + } + +#ifdef CONFIG_HAS_EARLYSUSPEND + icn83xx_trace("==register_early_suspend =\n"); + icn83xx_ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + icn83xx_ts->early_suspend.suspend = icn83xx_ts_early_suspend; + icn83xx_ts->early_suspend.resume = icn83xx_ts_late_resume; + register_early_suspend(&icn83xx_ts->early_suspend); +#endif + + return 0; +} + +#if SUPPORT_DELAYED_WORK +static void icn_delayedwork_fun(struct work_struct *work) +{ + int retry; + short fwVersion = 0; + short curVersion = 0; + icn83xx_trace("====%s begin1111=====. \n", __func__); + +#if SUPPORT_FW_UPDATE + fwVersion = icn83xx_read_fw_Ver(firmware); + curVersion = icn83xx_readVersion(); + icn83xx_trace("fwVersion : 0x%x\n", fwVersion); + icn83xx_trace("current version: 0x%x\n", curVersion); + + +#if FORCE_UPDATA_FW + retry = 5; + while(retry > 0) + { + if(R_OK == icn83xx_fw_update(firmware)) + { + break; + } + retry--; + icn83xx_error("icn83xx_fw_update failed.\n"); + } +#else + if(fwVersion > curVersion) + { + retry = 5; + while(retry > 0) + { + if(R_OK == icn83xx_fw_update(firmware)) + { + break; + } + retry--; + icn83xx_error("icn83xx_fw_update failed.\n"); + } + } +#endif + +#endif + + + icn83xx_irq_enable(); + icn83xx_trace("====%s over1111=====. \n", __func__); +} +#endif + + +char FbCap[4][16]={ + {0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14}, + {0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12}, + {0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}, + {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08}, +}; + +static int wmt_wakeup_bl_notify(struct notifier_block *nb, unsigned long event, + void *dummy) +{ + //printk("get notify\n"); + switch (event) { + case BL_CLOSE: + l_suspend = 1; + //printk("\nclose backlight\n\n"); + //printk("disable irq\n\n"); + wmt_gpio_mask_irq(g_param.irqgpio); + break; + case BL_OPEN: + l_suspend = 0; + //printk("\nopen backlight\n\n"); + //printk("enable irq\n\n"); + wmt_gpio_unmask_irq(g_param.irqgpio); + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block wmt_bl_notify = { + .notifier_call = wmt_wakeup_bl_notify, +}; + +static int icn83xx_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct icn83xx_ts_data *icn83xx_ts; + short fwVersion = 0; + short curVersion = 0; + //int average; + int err = 0; + //char value; + int retry; + + icn83xx_trace("====%s begin=====. \n", __func__); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + { + icn83xx_error("I2C check functionality failed.\n"); + return -ENODEV; + } + + icn83xx_ts = kzalloc(sizeof(*icn83xx_ts), GFP_KERNEL); + if (!icn83xx_ts) + { + icn83xx_error("Alloc icn83xx_ts memory failed.\n"); + return -ENOMEM; + } + + this_client = client; + i2c_set_clientdata(client, icn83xx_ts); + + icn83xx_ts->work_mode = 0; + spin_lock_init(&icn83xx_ts->irq_lock); + // icn83xx_ts->irq_lock = SPIN_LOCK_UNLOCKED; + + err = icn83xx_request_io_port(icn83xx_ts); + if (err != 0) { + icn83xx_error("icn83xx_request_io_port failed.\n"); + goto fail1; + } + + memset(firmware, 0, 128); + sprintf(firmware,"/system/etc/firmware/%s.bin",g_param.fw_name); + + icn83xx_ts_reset(); + err = icn83xx_iic_test(); + if (err < 0) + { + icn83xx_error("icn83xx_iic_test failed.\n"); +#if SUPPORT_FW_UPDATE + +#if COMPILE_FW_WITH_DRIVER + icn83xx_set_fw(sizeof(icn83xx_fw), &icn83xx_fw[0]); +#endif + if(icn83xx_check_progmod() == 0) + { + + retry = 5; + icn83xx_trace("in prog mode\n"); + while(retry > 0) + { + if(R_OK == icn83xx_fw_update(firmware)) + { + break; + } + retry--; + icn83xx_error("icn83xx_fw_update failed.\n"); + } + } + else // + { + icn83xx_error("I2C communication failed.\n"); + err = -1; + goto fail2; + } + +#endif + } + else + { + icn83xx_trace("iic communication ok\n"); + } + +#if SUPPORT_FW_UPDATE + fwVersion = icn83xx_read_fw_Ver(firmware); + curVersion = icn83xx_readVersion(); + icn83xx_trace("fwVersion : 0x%x\n", fwVersion); + icn83xx_trace("current version: 0x%x\n", curVersion); + + if (g_param.force_download) { + retry = 5; + while(retry > 0) + { + if(R_OK == icn83xx_fw_update(firmware)) + { + break; + } + retry--; + icn83xx_error("icn83xx_fw_update failed.\n"); + } + } else { + if(fwVersion > curVersion) + { + retry = 5; + while(retry > 0) + { + if(R_OK == icn83xx_fw_update(firmware)) + { + break; + } + retry--; + icn83xx_error("icn83xx_fw_update failed.\n"); + } + } + } + +#endif + +#if SUPPORT_FW_CALIB + err = icn83xx_read_reg(0, &value); + if(err > 0) + { + //auto calib fw + average = icn83xx_calib(0, NULL); + //fix FbCap + // average = icn83xx_calib(0, FbCap[1]); + icn83xx_trace("average : %d\n", average); + icn83xx_setPeakGroup(250, 150); + icn83xx_setDownUp(400, 300); + } +#endif + + INIT_WORK(&icn83xx_ts->pen_event_work, icn83xx_ts_pen_irq_work); + icn83xx_ts->ts_workqueue = create_singlethread_workqueue(dev_name(&client->dev)); + if (!icn83xx_ts->ts_workqueue) { + icn83xx_error("create_singlethread_workqueue failed.\n"); + err = -ESRCH; + goto fail3; + } + + err= icn83xx_request_input_dev(icn83xx_ts); + if (err < 0) + { + icn83xx_error("request input dev failed\n"); + goto fail4; + } + +#if TOUCH_VIRTUAL_KEYS + icn83xx_ts_virtual_keys_init(); +#endif + err = icn83xx_request_irq(icn83xx_ts); + if (err != 0) + { + printk("request irq error, use timer\n"); + icn83xx_ts->use_irq = 0; + hrtimer_init(&icn83xx_ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + icn83xx_ts->timer.function = chipone_timer_func; + hrtimer_start(&icn83xx_ts->timer, ktime_set(CTP_START_TIMER/1000, (CTP_START_TIMER%1000)*1000000), HRTIMER_MODE_REL); + } +#if SUPPORT_SYSFS + icn83xx_create_sysfs(client); +#endif + +#if SUPPORT_PROC_FS + sema_init(&icn83xx_ts->sem, 1); + init_proc_node(); +#endif + + err = device_create_file(&(client->dev), &dev_attr_dbg); + if (err) { + printk("Can't create attr file"); + } + if (g_param.earlysus_en) + register_bl_notifier(&wmt_bl_notify); + +#if SUPPORT_DELAYED_WORK + INIT_DELAYED_WORK(&icn83xx_ts->icn_delayed_work, icn_delayedwork_fun); + schedule_delayed_work(&icn83xx_ts->icn_delayed_work, msecs_to_jiffies(8000)); +#else + + icn83xx_irq_enable(); +#endif + icn83xx_trace("==%s over =\n", __func__); + return 0; + +fail4: + input_unregister_device(icn83xx_ts->input_dev); + input_free_device(icn83xx_ts->input_dev); +fail3: + cancel_work_sync(&icn83xx_ts->pen_event_work); +fail2: + icn83xx_free_io_port(); +fail1: + kfree(icn83xx_ts); + return err; +} + +static int __devexit icn83xx_ts_remove(struct i2c_client *client) +{ + struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(client); + icn83xx_trace("==icn83xx_ts_remove=\n"); + icn83xx_irq_disable(); +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&icn83xx_ts->early_suspend); +#endif + + if (g_param.earlysus_en) + unregister_bl_notifier(&wmt_bl_notify); + +#if SUPPORT_PROC_FS + uninit_proc_node(); +#endif + + input_unregister_device(icn83xx_ts->input_dev); + input_free_device(icn83xx_ts->input_dev); + cancel_work_sync(&icn83xx_ts->pen_event_work); + destroy_workqueue(icn83xx_ts->ts_workqueue); + icn83xx_free_irq(icn83xx_ts); + icn83xx_free_io_port(); + kfree(icn83xx_ts); + i2c_set_clientdata(client, NULL); + return 0; +} + +static int wmt_check_touch_env(void) +{ + int ret = 0; + int len = 96; + char retval[200] = {0},*p=NULL,*s=NULL; + int Enable=0; + + // Get u-boot parameter + /*ret = wmt_getsyspara("wmt.io.zettouch", retval, &len); + if(ret){ + klog("Read wmt.io.zettouch Failed.\n"); + } else + goto paste;*/ + ret = wmt_getsyspara("wmt.io.touch", retval, &len); + if(ret){ + printk("Read wmt.io.touch Failed.\n"); + return -EIO; + } + +//paste: + p = retval; + Enable = (p[0] - '0' == 1) ? 1 : 0; + if(Enable == 0){ + printk("Touch Screen Is Disabled.\n"); + return -ENODEV; + } + + p = strchr(p,':');p++; + s = strchr(p,':'); + strncpy(g_param.fw_name,p, (s-p)); + printk("ts_name=%s\n", g_param.fw_name); + if (strncmp(g_param.fw_name, "ICN83", 5)) { + printk("Wrong firmware name.\n"); + return -ENODEV; + } + + p = s+1; + ret = sscanf(p,"%d:%d:%d:%d:%d:%d:%d:%d", + &(g_param.irqgpio),&(g_param.panelres_x),&(g_param.panelres_y),&(g_param.rstgpio), + &(g_param.xyswap),&(g_param.xdir),&(g_param.ydir),&(g_param.force_download)); + + if (ret < 8) { + printk("Wrong format ts u-boot param(%d)!\nwmt.io.touch=%s\n",ret,retval); + return -ENODEV; + } + + printk("p.x = %d, p.y = %d, irqgpio=%d, rstgpio=%d,xyswap=%d,xdir=%d,ydir=%d,force_download=%d\n", + g_param.panelres_x,g_param.panelres_y,g_param.irqgpio,g_param.rstgpio, + g_param.xyswap,g_param.xdir,g_param.ydir,g_param.force_download); + + memset(retval,0,sizeof(retval)); + ret = wmt_getsyspara("wmt.touch.earlysus", retval, &len); + if(!ret) + g_param.earlysus_en = (retval[0] - '0' == 1) ? 1 : 0; + + memset(retval,0,sizeof(retval)); + ret = wmt_getsyspara("wmt.display.fb0", retval, &len); + if (!ret) { + int tmp[6]; + p = retval; + sscanf(p, "%d:[%d:%d:%d:%d:%d", &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5]); + if (tmp[4] > tmp[5]) + g_param.lcd_exchg = 1; + } + + return 0; +} + +static const struct dev_pm_ops icn83xx_pm_ops = { + .suspend = icn83xx_ts_suspend, + .resume = icn83xx_ts_resume, +}; + +static const struct i2c_device_id icn83xx_ts_id[] = { + { CTP_NAME, 0 }, + {}, +}; +MODULE_DEVICE_TABLE(i2c, icn83xx_ts_id); + +static struct i2c_driver icn83xx_ts_driver = { + .driver = { + .name = CTP_NAME, + .pm = &icn83xx_pm_ops, + }, + .probe = icn83xx_ts_probe, + .remove = __devexit_p(icn83xx_ts_remove), + .id_table = icn83xx_ts_id, +}; + +static struct i2c_board_info i2c_board_info = { + I2C_BOARD_INFO(CTP_NAME, ICN83XX_IIC_ADDR), +}; + +static int __init icn83xx_ts_init(void) +{ + struct i2c_client *client; + struct i2c_adapter *adap; + //u8 ts_data[8]; + + icn83xx_trace("===========================%s=====================\n", __func__); + if(wmt_check_touch_env()) + return -ENODEV; + {//register i2c device + adap = i2c_get_adapter(1); //i2c Bus 1 + if (!adap) + return -ENODEV; + client = i2c_new_device(adap, &i2c_board_info); + i2c_put_adapter(adap); + if (!client) { + printk("i2c_new_device error\n"); + return -ENODEV; + } + } + /*{ //check if IC exists + if (i2c_read_tsdata(client, ts_data, 8) <= 0) { + errlog("Can't find IC!\n"); + i2c_unregister_device(client); + return -ENODEV; + } + }*/ + return i2c_add_driver(&icn83xx_ts_driver); +} + +static void __exit icn83xx_ts_exit(void) +{ + icn83xx_trace("==icn83xx_ts_exit==\n"); + i2c_unregister_device(this_client); + return i2c_del_driver(&icn83xx_ts_driver); +} + +late_initcall(icn83xx_ts_init); +module_exit(icn83xx_ts_exit); + +MODULE_AUTHOR(""); +MODULE_DESCRIPTION("Chipone icn83xx TouchScreen driver"); +MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/icn83xx_ts/icn83xx.h b/ANDROID_3.4.5/drivers/input/touchscreen/icn83xx_ts/icn83xx.h new file mode 100755 index 00000000..46a7cf21 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/icn83xx_ts/icn83xx.h @@ -0,0 +1,434 @@ +/*++ + + Copyright (c) 2012-2022 ChipOne Technology (Beijing) Co., Ltd. All Rights Reserved. + This PROPRIETARY SOFTWARE is the property of ChipOne Technology (Beijing) Co., Ltd. + and may contains trade secrets and/or other confidential information of ChipOne + Technology (Beijing) Co., Ltd. This file shall not be disclosed to any third party, + in whole or in part, without prior written consent of ChipOne. + THIS PROPRIETARY SOFTWARE & ANY RELATED DOCUMENTATION ARE PROVIDED AS IS, + WITH ALL FAULTS, & WITHOUT WARRANTY OF ANY KIND. CHIPONE DISCLAIMS ALL EXPRESS OR + IMPLIED WARRANTIES. + + File Name: icn83xx.h + Abstract: + input driver. +Author: Zhimin Tian +Date : 01,17,2013 +Version: 1.0 +History : + 2012,10,30, V0.1 first version + + --*/ + +#ifndef __LINUX_ICN83XX_H__ +#define __LINUX_ICN83XX_H__ + +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND + #include + #include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../../video/backlight/wmt_bl.h" + +//----------------------------------------------------------------------------- +// Pin Declarations +//----------------------------------------------------------------------------- + +#define SUPPORT_ROCKCHIP 0 + +#if SUPPORT_ROCKCHIP +#include +#include +//#include +#include +//#include +#include + +#define CTP_IRQ_PORT RK30_PIN1_PB7 +#define CTP_IRQ_MODE 0 +#define CTP_RST_PORT RK30_PIN1_PA7 +#define CTP_WAKEUP_PORT 0 + //1: B protocol +#define SCREEN_MAX_X (800) +#define SCREEN_MAX_Y (480) +#define ICN83XX_I2C_SCL 400*1000 + +#endif + +#define CTP_REPORT_PROTOCOL 1 //0: A protocol + +//----------------------------------------------------------------------------- +// Global CONSTANTS +//----------------------------------------------------------------------------- + +#define TOUCH_VIRTUAL_KEYS 0 +#define SUPPORT_PROC_FS 1 +#define SUPPORT_SYSFS 1 +#define SUPPORT_FW_UPDATE 1 +#define COMPILE_FW_WITH_DRIVER 0 +#define FORCE_UPDATA_FW 0 +#define SUPPORT_FW_CALIB 0 +#define SUPPORT_DELAYED_WORK 0 + +#define ICN83XX_NAME "chipone-ts" +#define ICN83XX_PROG_IIC_ADDR (0x60>>1) +#define ICN83XX_IIC_ADDR (0x80>>1) +#define CTP_NAME ICN83XX_NAME + +#define CTP_RESET_LOW_PERIOD (5) +#define CTP_RESET_HIGH_PERIOD (100) +#define CTP_WAKEUP_LOW_PERIOD (20) +#define CTP_WAKEUP_HIGH_PERIOD (50) +#define CTP_POLL_TIMER (16) /* ms delay between samples */ +#define CTP_START_TIMER (100) /* ms delay between samples */ + +#define POINT_NUM 5 +#define POINT_SIZE 7 + +#define TS_KEY_HOME 102 +#define TS_KEY_MENU 139 +#define TS_KEY_BACK 158 +#define TS_KEY_SEARCH 217 + +#define ICN_VIRTUAL_BUTTON_HOME 0x02 +#define ICN_VIRTUAL_BUTTON_MENU 0x01 +#define ICN_VIRTUAL_BUTTON_BACK 0x04 +#define ICN_VIRTUAL_BUTTON_SEARCH 0x08 + +#define IIC_RETRY_NUM 3 + +//ICN83XX_REG_PMODE +#define PMODE_ACTIVE 0x00 +#define PMODE_MONITOR 0x01 +#define PMODE_HIBERNATE 0x02 + +#define B_SIZE 32 +#define ENABLE_BYTE_CHECK +//#define WAKE_PIN 1 +//----------------------------------------------------------------------------- +// Macro DEFINITIONS +//----------------------------------------------------------------------------- +#define DBG_ICN83XX_TRACE +//#define DBG_ICN83XX_POINT +//#define DBG_ICN83XX_INFO +#define DBG_ICN83XX_ERROR +#define DBG_FLASH_INFO +#define DBG_FLASH_ERROR +#define DBG_OP_INFO +#define DBG_OP_ERROR +#define DBG_CALIB_INFO +#define DBG_CALIB_ERROR +//#define DBG_PROC_INFO +#define DBG_PROC_ERROR + + +#ifdef DBG_ICN83XX_TRACE +#define icn83xx_trace(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define icn83xx_trace(fmt, args...) // +#endif + + +#ifdef DBG_ICN83XX_POINT +#define icn83xx_point_info(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define icn83xx_point_info(fmt, args...) // +#endif + +#ifdef DBG_ICN83XX_INFO +#define icn83xx_info(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define icn83xx_info(fmt, args...) // +#endif + +#ifdef DBG_ICN83XX_ERROR +#define icn83xx_error(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define icn83xx_error(fmt, args...) // +#endif + +#ifdef DBG_FLASH_INFO +#define flash_info(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define flash_info(fmt, args...) // +#endif + +#ifdef DBG_FLASH_ERROR +#define flash_error(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define flash_error(fmt, args...) // +#endif + + +#ifdef DBG_OP_INFO +#define op_info(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define op_info(fmt, args...) // +#endif +#ifdef DBG_OP_ERROR +#define op_error(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define op_error(fmt, args...) // +#endif + + +#ifdef DBG_CALIB_INFO +#define calib_info(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define calib_info(fmt, args...) // +#endif + +#ifdef DBG_CALIB_ERROR +#define calib_error(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define calib_error(fmt, args...) // +#endif + + +#ifdef DBG_PROC_INFO +#define proc_info(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define proc_info(fmt, args...) // +#endif + +#ifdef DBG_PROC_ERROR +#define proc_error(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define proc_error(fmt, args...) // +#endif + +#define swap_ab(a,b) {char temp;temp=a;a=b;b=temp;} +#define U16LOBYTE(var) (*(unsigned char *) &var) +#define U16HIBYTE(var) (*(unsigned char *)((unsigned char *) &var + 1)) + + + +//----------------------------------------------------------------------------- +// Struct, Union and Enum DEFINITIONS +//----------------------------------------------------------------------------- +typedef struct _POINT_INFO +{ + unsigned char u8ID; + unsigned short u16PosX; // coordinate X, plus 4 LSBs for precision extension + unsigned short u16PosY; // coordinate Y, plus 4 LSBs for precision extension + unsigned char u8Pressure; + unsigned char u8EventId; +}POINT_INFO; + +struct icn83xx_ts_data { + struct i2c_client *client; + struct input_dev *input_dev; + struct work_struct pen_event_work; + struct delayed_work icn_delayed_work; + struct workqueue_struct *ts_workqueue; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif + struct hrtimer timer; + spinlock_t irq_lock; + struct semaphore sem; + + POINT_INFO point_info[POINT_NUM+1]; + int point_num; + int irq; + int irq_is_disable; + int use_irq; + int work_mode; + int screen_max_x; + int screen_max_y; + int revert_x_flag; + int revert_y_flag; + int exchange_x_y_flag; + int (*init_wakeup_hw)(void); +}; + +struct touch_param { + char fw_name[32]; + int irqgpio; + int rstgpio; + int panelres_x; + int panelres_y; + int xyswap; + int xdir; + int ydir; + int max_finger_num; + int force_download; + int earlysus_en; + int dbg; + int lcd_exchg; +}; + +#pragma pack(1) +typedef struct{ + unsigned char wr; //write read flag£¬0:R 1:W + unsigned char flag; //0: + unsigned char circle; //polling cycle + unsigned char times; //plling times + unsigned char retry; //I2C retry times + unsigned int data_len; //data length + unsigned char addr_len; //address length + unsigned char addr[2]; //address + unsigned char* data; //data pointer +}pack_head; +#pragma pack() + +#define DATA_LENGTH_UINT 512 +#define CMD_HEAD_LENGTH (sizeof(pack_head) - sizeof(unsigned char *)) +#define ICN83XX_ENTRY_NAME "icn83xx_tool" +enum icn83xx_ts_regs { + ICN83XX_REG_PMODE = 0x04, /* Power Consume Mode */ +}; + +typedef enum +{ + R_OK = 100, + R_FILE_ERR, + R_STATE_ERR, + R_ERASE_ERR, + R_PROGRAM_ERR, + R_VERIFY_ERR, +}E_UPGRADE_ERR_TYPE; + +//----------------------------------------------------------------------------- +// Global VARIABLES +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// Function PROTOTYPES +//----------------------------------------------------------------------------- + +void icn83xx_ts_reset(void); +int icn83xx_i2c_rxdata(unsigned char addr, char *rxdata, int length); +int icn83xx_i2c_txdata(unsigned char addr, char *txdata, int length); +int icn83xx_write_reg(unsigned char addr, char para); +int icn83xx_read_reg(unsigned char addr, char *pdata); +int icn83xx_prog_i2c_rxdata(unsigned short addr, char *rxdata, int length); +int icn83xx_prog_i2c_txdata(unsigned short addr, char *txdata, int length); +int icn83xx_prog_write_reg(unsigned short addr, char para); +int icn83xx_prog_read_reg(unsigned short addr, char *pdata); +#if SUPPORT_FW_UPDATE + +int icn83xx_writeInfo(unsigned short addr, char value); +int icn83xx_readInfo(unsigned short addr, char *value); +int icn83xx_writeReg(unsigned short addr, char value); +int icn83xx_readReg(unsigned short addr, char *value); +int icn83xx_readVersion(void); +int icn83xx_changemode(char mode); +int icn83xx_readrawdata(char *buffer, char row, char length); +int icn83xx_readTP(char row_num, char column_num, char *buffer); +int icn83xx_scanTP(void); +void icn83xx_rawdatadump(short *mem, int size, char br); +void icn83xx_set_fw(int size, unsigned char *buf); +void icn83xx_memdump(char *mem, int size); +int icn83xx_checksum(int sum, char *buf, unsigned int size); +int icn83xx_update_status(int status); +int icn83xx_get_status(void); +int icn83xx_open_fw( char *fw); +int icn83xx_read_fw(int offset, int length, char *buf); +int icn83xx_close_fw(void); +int icn83xx_goto_progmode(void); +int icn83xx_check_progmod(void); +int icn83xx_uu(void); +void icn83xx_ll(void); +int icn83xx_op1(char info, unsigned short offset, unsigned int size); +int icn83xx_op2(char info, unsigned short offset, unsigned char * buffer, unsigned int size); +int icn83xx_op3(char info, unsigned short offset, unsigned char * buffer, unsigned int size); +short icn83xx_read_fw_Ver(char *fw); +E_UPGRADE_ERR_TYPE icn83xx_fw_update(char *fw); +#endif + +#if SUPPORT_FW_CALIB + +int icn83xx_checkrawdata(short *data, char num); +int icn83xx_readpara(char *TxOrder, char row, char *RxOrder, char column); +int icn83xx_writepara(char *TxOrder, char row, char *RxOrder, char column); +int icn83xx_readFB(char *FB, char num); +int icn83xx_writeFB(char *FB, char num); +int icn83xx_readDC(char *DC, char num); +int icn83xx_writeDC(char *DC, char num); +int icn83xx_readPhaseDelay(char *PD, char row, char length); +int icn83xx_writePhaseDelay(char *PD, char row, char length); +int icn83xx_changeDCflag(char flag); +int icn83xx_readVkmode(char *vkmode, char *vknum); +int icn83xx_setTarget(short target); +int icn83xx_setPeakGroup(short peak, short group); +int icn83xx_setDownUp(short down, short up); +int icn83xx_average(short *data, char num); + +int icn83xx_calib(char index, char *FB); +#endif + +#endif diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/icn83xx_ts/icn83xx_fw.h b/ANDROID_3.4.5/drivers/input/touchscreen/icn83xx_ts/icn83xx_fw.h new file mode 100755 index 00000000..572bf1f3 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/icn83xx_ts/icn83xx_fw.h @@ -0,0 +1,3 @@ +static unsigned char icn83xx_fw[] = { + +}; \ No newline at end of file diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/icn85xx_ts/Kconfig b/ANDROID_3.4.5/drivers/input/touchscreen/icn85xx_ts/Kconfig new file mode 100755 index 00000000..593b379b --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/icn85xx_ts/Kconfig @@ -0,0 +1,16 @@ +# +# ICN85XX capacity touch screen driver configuration +# +config TOUCHSCREEN_ICN85XX + tristate "ICN85XX I2C Capacitive Touchscreen Input Driver Support" + depends on ARCH_WMT + default y + help + Say Y here if you have an WMT based board with touchscreen + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called s_wmt_ts_icn85xx + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/icn85xx_ts/Makefile b/ANDROID_3.4.5/drivers/input/touchscreen/icn85xx_ts/Makefile new file mode 100755 index 00000000..4f2c65ce --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/icn85xx_ts/Makefile @@ -0,0 +1,32 @@ +KERNELDIR=../../../../ +CROSS = arm_1103_le- +CC= $(CROSS)gcc +LD= $(CROSS)ld +STRIP = $(CROSS)strip + +DEBUG = n + +# Add your debugging flag (or not) to EXTRA_CFLAGS +ifeq ($(DEBUG),y) +# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines +DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines + +else + DEBFLAGS = -O2 -Wall +endif + +EXTRA_CFLAGS += $(DEBFLAGS) + + +MY_MODULE_NAME=s_wmt_ts_icn85xx + +obj-m := $(MY_MODULE_NAME).o +$(MY_MODULE_NAME)-objs := icn85xx.o icn85xx_flash.o + +default: + $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules + $(STRIP) --strip-debug $(MY_MODULE_NAME).ko + rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions *.order *.symvers modules.builtin + +clean: + rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers modules.builtin diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/icn85xx_ts/icn85xx.c b/ANDROID_3.4.5/drivers/input/touchscreen/icn85xx_ts/icn85xx.c new file mode 100755 index 00000000..371742fb --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/icn85xx_ts/icn85xx.c @@ -0,0 +1,2431 @@ +/*++ + + Copyright (c) 2012-2022 ChipOne Technology (Beijing) Co., Ltd. All Rights Reserved. + This PROPRIETARY SOFTWARE is the property of ChipOne Technology (Beijing) Co., Ltd. + and may contains trade secrets and/or other confidential information of ChipOne + Technology (Beijing) Co., Ltd. This file shall not be disclosed to any third party, + in whole or in part, without prior written consent of ChipOne. + THIS PROPRIETARY SOFTWARE & ANY RELATED DOCUMENTATION ARE PROVIDED AS IS, + WITH ALL FAULTS, & WITHOUT WARRANTY OF ANY KIND. CHIPONE DISCLAIMS ALL EXPRESS OR + IMPLIED WARRANTIES. + + File Name: icn85xx.c + Abstract: + input driver. + Author: Zhimin Tian + Date : 08,14,2013 + Version: 1.0 + History : + 2012,10,30, V0.1 first version + --*/ + +#include "icn85xx.h" +#include "icn85xx_fw.h" +//#include "icn85xx_00_ht_0528.h" +//#include "icn85xx_02_lh_0528.h" + +#if COMPILE_FW_WITH_DRIVER + static char firmware[128] = "icn85xx_firmware"; +#else + #if SUPPORT_SENSOR_ID + static char firmware[128] = {0}; + #else + //static char firmware[128] = {"/misc/modules/ICN8505.BIN"}; + //static char firmware[128] = {"/system/etc/firmware/ICN8505.bin"}; + static char firmware[128] = {"ICN8505.bin"}; + #endif +#endif + +#if SUPPORT_SENSOR_ID + char cursensor_id,tarsensor_id,id_match; + char invalid_id = 0; + + struct sensor_id { + char value; + const char bin_name[128]; + unsigned char *fw_name; + int size; + }; + +static struct sensor_id sensor_id_table[] = { + { 0x00, "/misc/modules/ICN8505_00_name1.BIN",fw_00_ht_0528,sizeof(fw_00_ht_0528)},//default bin or fw + { 0x02, "/misc/modules/ICN8505_02_name3.BIN",fw_02_lh_0528,sizeof(fw_02_lh_0528)}, + + // if you want support other sensor id value ,please add here + }; +#endif +struct i2c_client *this_client; +short log_basedata[COL_NUM][ROW_NUM] = {{0,0}}; +short log_rawdata[COL_NUM][ROW_NUM] = {{0,0}}; +short log_diffdata[COL_NUM][ROW_NUM] = {{0,0}}; +unsigned int log_on_off = 0; +static struct touch_param g_param; +static struct wake_lock downloadWakeLock; +static struct task_struct *resume_download_task; +static int bl_is_delay = 0; + +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); + //yank added + void icn85xx_charge_mode(void) + { + printk("yank---%s\n",__func__); + icn85xx_write_reg(ICN85xx_REG_PMODE, 0x55); + } + EXPORT_SYMBOL(icn85xx_charge_mode); + + void icn85xx_discharge_mode(void) + { + printk("yank---%s\n",__func__); + icn85xx_write_reg(ICN85xx_REG_PMODE, 0x66); + } + EXPORT_SYMBOL(icn85xx_discharge_mode); + + +static enum hrtimer_restart chipone_timer_func(struct hrtimer *timer); +#if SUPPORT_SYSFS +static ssize_t icn85xx_show_update(struct device* cd,struct device_attribute *attr, char* buf); +static ssize_t icn85xx_store_update(struct device* cd, struct device_attribute *attr, const char* buf, size_t len); +static ssize_t icn85xx_show_process(struct device* cd,struct device_attribute *attr, char* buf); +static ssize_t icn85xx_store_process(struct device* cd, struct device_attribute *attr,const char* buf, size_t len); + +static DEVICE_ATTR(update, S_IRUGO | S_IWUSR, icn85xx_show_update, icn85xx_store_update); +static DEVICE_ATTR(process, S_IRUGO | S_IWUSR, icn85xx_show_process, icn85xx_store_process); + +static ssize_t icn85xx_show_process(struct device* cd,struct device_attribute *attr, char* buf) +{ + ssize_t ret = 0; + sprintf(buf, "icn85xx process\n"); + ret = strlen(buf) + 1; + return ret; +} + +static ssize_t icn85xx_store_process(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) +{ + struct icn85xx_ts_data *icn85xx_ts = i2c_get_clientdata(this_client); + unsigned long on_off = simple_strtoul(buf, NULL, 10); + + log_on_off = on_off; + memset(&log_basedata[0][0], 0, COL_NUM*ROW_NUM*2); + if(on_off == 0) + { + icn85xx_ts->work_mode = 0; + } + else if((on_off == 1) || (on_off == 2) || (on_off == 3)) + { + if((icn85xx_ts->work_mode == 0) && (icn85xx_ts->use_irq == 1)) + { + hrtimer_init(&icn85xx_ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + icn85xx_ts->timer.function = chipone_timer_func; + hrtimer_start(&icn85xx_ts->timer, ktime_set(CTP_START_TIMER/1000, (CTP_START_TIMER%1000)*1000000), HRTIMER_MODE_REL); + } + icn85xx_ts->work_mode = on_off; + } + else if(on_off == 10) + { + icn85xx_ts->work_mode = 4; + mdelay(10); + printk("update baseline\n"); + icn85xx_write_reg(4, 0x30); + icn85xx_ts->work_mode = 0; + } + else + { + icn85xx_ts->work_mode = 0; + } + + + return len; +} + +static ssize_t icn85xx_show_update(struct device* cd, + struct device_attribute *attr, char* buf) +{ + ssize_t ret = 0; + sprintf(buf, firmware); + ret = strlen(buf) + 1; + printk("firmware: %s, ret: %d\n", firmware, ret); + + return ret; +} + +static ssize_t icn85xx_store_update(struct device* cd, struct device_attribute *attr, const char* buf, size_t len) +{ + printk("len: %d, update: %s\n", len, buf); + memset(firmware, 0, 128); + memcpy(firmware, buf, len-1); + if(R_OK == icn85xx_fw_update(firmware)) + { + printk("update ok\n"); + } + else + { + printk("update error\n"); + } + return len; +} + +static int icn85xx_create_sysfs(struct i2c_client *client) +{ + int err; + struct device *dev = &(client->dev); + icn85xx_trace("%s: \n",__func__); + err = device_create_file(dev, &dev_attr_update); + err = device_create_file(dev, &dev_attr_process); + return err; +} + +static void icn85xx_remove_sysfs(struct i2c_client *client) +{ + struct device *dev = &(client->dev); + icn85xx_trace("%s: \n",__func__); + device_remove_file(dev, &dev_attr_update); + device_remove_file(dev, &dev_attr_process); +} +#endif + +#if SUPPORT_PROC_FS + +pack_head cmd_head; +static struct proc_dir_entry *icn85xx_proc_entry; +int DATA_LENGTH = 0; + +STRUCT_PANEL_PARA_H g_structPanelPara; + +static int icn85xx_tool_write(struct file *filp, const char __user *buff, unsigned long len, void *data) +{ + int ret = 0; + int i; + unsigned short addr; + char retvalue; + struct icn85xx_ts_data *icn85xx_ts = i2c_get_clientdata(this_client); + proc_info("%s \n",__func__); + if(down_interruptible(&icn85xx_ts->sem)) + { + return -1; + } + ret = copy_from_user(&cmd_head, buff, CMD_HEAD_LENGTH); + if(ret) + { + proc_error("copy_from_user failed.\n"); + goto write_out; + } + else + { + ret = CMD_HEAD_LENGTH; + } + + proc_info("wr :0x%02x.\n", cmd_head.wr); + proc_info("flag:0x%02x.\n", cmd_head.flag); + proc_info("circle :%d.\n", (int)cmd_head.circle); + proc_info("times :%d.\n", (int)cmd_head.times); + proc_info("retry :%d.\n", (int)cmd_head.retry); + proc_info("data len:%d.\n", (int)cmd_head.data_len); + proc_info("addr len:%d.\n", (int)cmd_head.addr_len); + proc_info("addr:0x%02x%02x.\n", cmd_head.addr[0], cmd_head.addr[1]); + proc_info("len:%d.\n", (int)len); + proc_info("data:0x%02x%02x.\n", buff[CMD_HEAD_LENGTH], buff[CMD_HEAD_LENGTH+1]); + if (1 == cmd_head.wr) // write para + { + ret = copy_from_user(&cmd_head.data[0], &buff[CMD_HEAD_LENGTH], cmd_head.data_len); + if(ret) + { + proc_error("copy_from_user failed.\n"); + goto write_out; + } + //need copy to g_structPanelPara + + memcpy(&g_structPanelPara, &cmd_head.data[0], cmd_head.data_len); + //write para to tp + for(i=0; i cmd_head.data_len)?(cmd_head.data_len-i):64; + ret = icn85xx_i2c_txdata(0x8000+i, &cmd_head.data[i], size); + if (ret < 0) { + proc_error("write para failed!\n"); + goto write_out; + } + i = i + 64; + } + + ret = cmd_head.data_len + CMD_HEAD_LENGTH; + icn85xx_ts->work_mode = 5; //reinit + printk("reinit tp\n"); + icn85xx_write_reg(0, 1); + mdelay(100); + icn85xx_write_reg(0, 0); + icn85xx_ts->work_mode = 0; + goto write_out; + + } + else if(3 == cmd_head.wr) //set update file + { + proc_info("cmd_head_.wr == 3 \n"); + ret = copy_from_user(&cmd_head.data[0], &buff[CMD_HEAD_LENGTH], cmd_head.data_len); + if(ret) + { + proc_error("copy_from_user failed.\n"); + goto write_out; + } + ret = cmd_head.data_len + CMD_HEAD_LENGTH; + memset(firmware, 0, 128); + memcpy(firmware, &cmd_head.data[0], cmd_head.data_len); + proc_info("firmware : %s\n", firmware); + } + else if(5 == cmd_head.wr) //start update + { + proc_info("cmd_head_.wr == 5 \n"); + icn85xx_update_status(1); + ret = kernel_thread(icn85xx_fw_update,firmware,CLONE_KERNEL); + icn85xx_trace("the kernel_thread result is:%d\n", ret); + } + else if(11 == cmd_head.wr) //write hostcomm + { + ret = copy_from_user(&cmd_head.data[0], &buff[CMD_HEAD_LENGTH], cmd_head.data_len); + if(ret) + { + proc_error("copy_from_user failed.\n"); + goto write_out; + } + addr = (cmd_head.addr[1]<<8) | cmd_head.addr[0]; + icn85xx_write_reg(addr, cmd_head.data[0]); + } + else if(13 == cmd_head.wr) //adc enable + { + proc_info("cmd_head_.wr == 13 \n"); + icn85xx_ts->work_mode = 4; + mdelay(10); + //set col + icn85xx_write_reg(0x8000+STRUCT_OFFSET(STRUCT_PANEL_PARA_H, u8ColNum), 1); + //u8RXOrder[0] = u8RXOrder[cmd_head.addr[0]]; + icn85xx_write_reg(0x8000+STRUCT_OFFSET(STRUCT_PANEL_PARA_H, u8RXOrder[0]), g_structPanelPara.u8RXOrder[cmd_head.addr[0]]); + //set row + icn85xx_write_reg(0x8000+STRUCT_OFFSET(STRUCT_PANEL_PARA_H, u8RowNum), 1); + //u8TXOrder[0] = u8TXOrder[cmd_head.addr[1]]; + icn85xx_write_reg(0x8000+STRUCT_OFFSET(STRUCT_PANEL_PARA_H, u8TXOrder[0]), g_structPanelPara.u8TXOrder[cmd_head.addr[1]]); + //scan mode + icn85xx_write_reg(0x8000+STRUCT_OFFSET(STRUCT_PANEL_PARA_H, u8ScanMode), 0); + //bit + icn85xx_write_reg(0x8000+STRUCT_OFFSET(STRUCT_PANEL_PARA_H, u16BitFreq), 0xD0); + icn85xx_write_reg(0x8000+STRUCT_OFFSET(STRUCT_PANEL_PARA_H, u16BitFreq)+1, 0x07); + //freq + icn85xx_write_reg(0x8000+STRUCT_OFFSET(STRUCT_PANEL_PARA_H, u16FreqCycleNum[0]), 0x64); + icn85xx_write_reg(0x8000+STRUCT_OFFSET(STRUCT_PANEL_PARA_H, u16FreqCycleNum[0])+1, 0x00); + //pga + icn85xx_write_reg(0x8000+STRUCT_OFFSET(STRUCT_PANEL_PARA_H, u8PgaGain), 0x0); + + //config mode + icn85xx_write_reg(0, 0x2); + + mdelay(1); + icn85xx_read_reg(2, &retvalue); + printk("retvalue0: %d\n", retvalue); + while(retvalue != 1) + { + printk("retvalue: %d\n", retvalue); + mdelay(1); + icn85xx_read_reg(2, &retvalue); + } + + if(icn85xx_goto_progmode() != 0) + { + printk("icn85xx_goto_progmode() != 0 error\n"); + goto write_out; + } + + icn85xx_prog_write_reg(0x040870, 1); + + } + +write_out: + up(&icn85xx_ts->sem); + proc_info("icn85xx_tool_write write_out \n"); + return len; + +} + +static int icn85xx_tool_read( char *page, char **start, off_t off, int count, int *eof, void *data ) +{ + int i, j; + int ret = 0; + + char row, column, retvalue; + unsigned short addr; + struct icn85xx_ts_data *icn85xx_ts = i2c_get_clientdata(this_client); + if(down_interruptible(&icn85xx_ts->sem)) + { + return -1; + } + proc_info("%s: count:%d, off:%d, cmd_head.data_len: %d\n",__func__, count,(int)off,(int)cmd_head.data_len); + if (cmd_head.wr % 2) + { + ret = 0; + proc_info("cmd_head_.wr == 1111111 \n"); + goto read_out; + } + else if (0 == cmd_head.wr) //read para + { + //read para + proc_info("cmd_head_.wr == 0 \n"); + ret = icn85xx_i2c_rxdata(0x8000, &page[0], cmd_head.data_len); + if (ret < 0) { + icn85xx_error("%s read_data i2c_rxdata failed: %d\n", __func__, ret); + } + memcpy(&g_structPanelPara, &page[0], sizeof(g_structPanelPara)); + goto read_out; + + } + else if(2 == cmd_head.wr) //get update status + { + proc_info("cmd_head_.wr == 2 \n"); + page[0] = icn85xx_get_status(); + proc_info("status: %d\n", page[0]); + } + else if(4 == cmd_head.wr) //read rawdata + { + //icn85xx_read_reg(0x8004, &row); + //icn85xx_read_reg(0x8005, &column); + proc_info("cmd_head_.wr == 4 \n"); + row = cmd_head.addr[1]; + column = cmd_head.addr[0]; + //scan tp rawdata + icn85xx_write_reg(4, 0x20); + mdelay(1); + for(i=0; i<1000; i++) + { + mdelay(1); + icn85xx_read_reg(2, &retvalue); + if(retvalue == 1) + break; + } + + for(i=0; iictype == ICN85XX_WITHOUT_FLASH) + { + if(R_OK == icn85xx_fw_update(firmware)) + { + icn85xx_ts->code_loaded_flag = 1; + icn85xx_trace("ICN85XX_WITHOUT_FLASH, reload code ok\n"); + } + else + { + icn85xx_ts->code_loaded_flag = 0; + icn85xx_trace("ICN85XX_WITHOUT_FLASH, reload code error\n"); + } + } + else + { + icn85xx_bootfrom_flash(); + msleep(50); + } + icn85xx_ts->work_mode = 0; + } + } + else if(12 == cmd_head.wr) //read hostcomm + { + proc_info("cmd_head_.wr == 12 \n"); + addr = (cmd_head.addr[1]<<8) | cmd_head.addr[0]; + icn85xx_read_reg(addr, &retvalue); + page[0] = retvalue; + } + else if(14 == cmd_head.wr) //read adc status + { + proc_info("cmd_head_.wr == 14 \n"); + icn85xx_prog_read_reg(0x4085E, &retvalue); + page[0] = retvalue; + printk("0x4085E: 0x%x\n", retvalue); + } +read_out: + up(&icn85xx_ts->sem); + proc_info("%s out: %d, cmd_head.data_len: %d\n\n",__func__, count, cmd_head.data_len); + return cmd_head.data_len; +} + +void init_proc_node(void) +{ + int i; + memset(&cmd_head, 0, sizeof(cmd_head)); + cmd_head.data = NULL; + + i = 5; + while ((!cmd_head.data) && i) + { + cmd_head.data = kzalloc(i * DATA_LENGTH_UINT, GFP_KERNEL); + if (NULL != cmd_head.data) + { + break; + } + i--; + } + if (i) + { + //DATA_LENGTH = i * DATA_LENGTH_UINT + GTP_ADDR_LENGTH; + DATA_LENGTH = i * DATA_LENGTH_UINT; + icn85xx_trace("alloc memory size:%d.\n", DATA_LENGTH); + } + else + { + proc_error("alloc for memory failed.\n"); + return ; + } + + icn85xx_proc_entry = create_proc_entry(ICN85xx_ENTRY_NAME, 0666, NULL); + if (icn85xx_proc_entry == NULL) + { + proc_error("Couldn't create proc entry!\n"); + return ; + } + else + { + icn85xx_trace("Create proc entry success!\n"); + icn85xx_proc_entry->write_proc = icn85xx_tool_write; + icn85xx_proc_entry->read_proc = icn85xx_tool_read; + } + + return ; +} + +void uninit_proc_node(void) +{ + kfree(cmd_head.data); + cmd_head.data = NULL; + remove_proc_entry(ICN85xx_ENTRY_NAME, NULL); +} + +#endif + + +#if TOUCH_VIRTUAL_KEYS +static ssize_t virtual_keys_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, + __stringify(EV_KEY) ":" __stringify(KEY_MENU) ":100:1030:50:60" + ":" __stringify(EV_KEY) ":" __stringify(KEY_HOME) ":280:1030:50:60" + ":" __stringify(EV_KEY) ":" __stringify(KEY_BACK) ":470:1030:50:60" + ":" __stringify(EV_KEY) ":" __stringify(KEY_SEARCH) ":900:1030:50:60" + "\n"); +} + +static struct kobj_attribute virtual_keys_attr = { + .attr = { + .name = "virtualkeys.chipone-ts", + .mode = S_IRUGO, + }, + .show = &virtual_keys_show, +}; + +static struct attribute *properties_attrs[] = { + &virtual_keys_attr.attr, + NULL +}; + +static struct attribute_group properties_attr_group = { + .attrs = properties_attrs, +}; + +static void icn85xx_ts_virtual_keys_init(void) +{ + int ret; + struct kobject *properties_kobj; + properties_kobj = kobject_create_and_add("board_properties", NULL); + if (properties_kobj) + ret = sysfs_create_group(properties_kobj, + &properties_attr_group); + if (!properties_kobj || ret) + pr_err("failed to create board_properties\n"); +} +#endif + + + + +/* --------------------------------------------------------------------- +* +* Chipone panel related driver +* +* +----------------------------------------------------------------------*/ +/*********************************************************************************************** +Name : icn85xx_ts_wakeup +Input : void +Output : ret +function : this function is used to wakeup tp +***********************************************************************************************/ +void icn85xx_ts_wakeup(void) +{ + + + +} + +/*********************************************************************************************** +Name : icn85xx_ts_reset +Input : void +Output : ret +function : this function is used to reset tp, you should not delete it +***********************************************************************************************/ +void icn85xx_ts_reset(void) +{ + //set reset func + + int rst = g_param.rstgpio; + gpio_direction_output(rst,0); + msleep(50); + icn85xx_info("[%s]:>>>>>>>>>>>>>>>>>CTP_RST_PORT = %d;msleep(50);\n",__func__,gpio_get_value(rst)); + gpio_direction_output(rst,1); + msleep(70); + icn85xx_info("[%s]:>>>>>>>>>>>>>>>>>CTP_RST_PORT = %d;msleep(70);\n",__func__,gpio_get_value(rst)); + +} + +/*********************************************************************************************** +Name : icn85xx_irq_disable +Input : void +Output : ret +function : this function is used to disable irq +***********************************************************************************************/ +void icn85xx_irq_disable(void) +{ + unsigned long irqflags; + struct icn85xx_ts_data *icn85xx_ts = i2c_get_clientdata(this_client); + + spin_lock_irqsave(&icn85xx_ts->irq_lock, irqflags); + if (!icn85xx_ts->irq_is_disable) + { + icn85xx_ts->irq_is_disable = 1; + wmt_gpio_mask_irq(g_param.irqgpio); + //disable_irq_nosync(icn85xx_ts->irq); + //disable_irq(icn85xx_ts->irq); + } + spin_unlock_irqrestore(&icn85xx_ts->irq_lock, irqflags); + +} + +/*********************************************************************************************** +Name : icn85xx_irq_enable +Input : void +Output : ret +function : this function is used to enable irq +***********************************************************************************************/ +void icn85xx_irq_enable(void) +{ + unsigned long irqflags = 0; + struct icn85xx_ts_data *icn85xx_ts = i2c_get_clientdata(this_client); + + spin_lock_irqsave(&icn85xx_ts->irq_lock, irqflags); + if (icn85xx_ts->irq_is_disable) + { + wmt_gpio_unmask_irq(g_param.irqgpio); + //enable_irq(icn85xx_ts->irq); + icn85xx_ts->irq_is_disable = 0; + } + spin_unlock_irqrestore(&icn85xx_ts->irq_lock, irqflags); + +} + +/*********************************************************************************************** +Name : icn85xx_prog_i2c_rxdata +Input : addr + *rxdata + length +Output : ret +function : read data from icn85xx, prog mode +***********************************************************************************************/ +int icn85xx_prog_i2c_rxdata(unsigned int addr, char *rxdata, int length) +{ + int ret = -1; + int retries = 0; +#if 0 + struct i2c_msg msgs[] = { + { + .addr = ICN85XX_PROG_IIC_ADDR,//this_client->addr, + .flags = I2C_M_RD, + .len = length, + .buf = rxdata, +#if SUPPORT_ROCKCHIP + .scl_rate = ICN85XX_I2C_SCL, +#endif + }, + }; + + icn85xx_prog_i2c_txdata(addr, NULL, 0); + while(retries < IIC_RETRY_NUM) + { + ret = i2c_transfer(this_client->adapter, msgs, 1); + if(ret == 1)break; + retries++; + } + if (retries >= IIC_RETRY_NUM) + { + icn85xx_error("%s i2c read error: %d\n", __func__, ret); +// icn85xx_ts_reset(); + } +#else + unsigned char tmp_buf[3]; + struct i2c_msg msgs[] = { + { + .addr = ICN85XX_PROG_IIC_ADDR,//this_client->addr, + .flags = 0, + .len = 3, + .buf = tmp_buf, +#if SUPPORT_ROCKCHIP + .scl_rate = ICN85XX_I2C_SCL, +#endif + }, + { + .addr = ICN85XX_PROG_IIC_ADDR,//this_client->addr, + .flags = I2C_M_RD, + .len = length, + .buf = rxdata, +#if SUPPORT_ROCKCHIP + .scl_rate = ICN85XX_I2C_SCL, +#endif + }, + }; + + tmp_buf[0] = (unsigned char)(addr>>16); + tmp_buf[1] = (unsigned char)(addr>>8); + tmp_buf[2] = (unsigned char)(addr); + + + while(retries < IIC_RETRY_NUM) + { + ret = i2c_transfer(this_client->adapter, msgs, 2); + if(ret == 2)break; + retries++; + } + + if (retries >= IIC_RETRY_NUM) + { + icn85xx_error("%s i2c read error: %d\n", __func__, ret); +// icn85xx_ts_reset(); + } +#endif + return ret; +} +/*********************************************************************************************** +Name : icn85xx_prog_i2c_txdata +Input : addr + *rxdata + length +Output : ret +function : send data to icn85xx , prog mode +***********************************************************************************************/ +int icn85xx_prog_i2c_txdata(unsigned int addr, char *txdata, int length) +{ + int ret = -1; + char tmp_buf[128]; + int retries = 0; + struct i2c_msg msg[] = { + { + .addr = ICN85XX_PROG_IIC_ADDR,//this_client->addr, + .flags = 0, + .len = length + 3, + .buf = tmp_buf, +#if SUPPORT_ROCKCHIP + .scl_rate = ICN85XX_I2C_SCL, +#endif + }, + }; + + if (length > 125) + { + icn85xx_error("%s too big datalen = %d!\n", __func__, length); + return -1; + } + + tmp_buf[0] = (unsigned char)(addr>>16); + tmp_buf[1] = (unsigned char)(addr>>8); + tmp_buf[2] = (unsigned char)(addr); + + + if (length != 0 && txdata != NULL) + { + memcpy(&tmp_buf[3], txdata, length); + } + + while(retries < IIC_RETRY_NUM) + { + ret = i2c_transfer(this_client->adapter, msg, 1); + if(ret == 1)break; + retries++; + } + + if (retries >= IIC_RETRY_NUM) + { + icn85xx_error("%s i2c write error: %d\n", __func__, ret); +// icn85xx_ts_reset(); + } + return ret; +} +/*********************************************************************************************** +Name : icn85xx_prog_write_reg +Input : addr -- address + para -- parameter +Output : +function : write register of icn85xx, prog mode +***********************************************************************************************/ +int icn85xx_prog_write_reg(unsigned int addr, char para) +{ + char buf[3]; + int ret = -1; + + buf[0] = para; + ret = icn85xx_prog_i2c_txdata(addr, buf, 1); + if (ret < 0) { + icn85xx_error("%s write reg failed! %#x ret: %d\n", __func__, buf[0], ret); + return -1; + } + + return ret; +} + + +/*********************************************************************************************** +Name : icn85xx_prog_read_reg +Input : addr + pdata +Output : +function : read register of icn85xx, prog mode +***********************************************************************************************/ +int icn85xx_prog_read_reg(unsigned int addr, char *pdata) +{ + int ret = -1; + ret = icn85xx_prog_i2c_rxdata(addr, pdata, 1); + return ret; +} + +/*********************************************************************************************** +Name : icn85xx_i2c_rxdata +Input : addr + *rxdata + length +Output : ret +function : read data from icn85xx, normal mode +***********************************************************************************************/ +int icn85xx_i2c_rxdata(unsigned short addr, char *rxdata, int length) +{ + int ret = -1; + int retries = 0; + unsigned char tmp_buf[2]; +#if 0 + + struct i2c_msg msgs[] = { + { + .addr = this_client->addr, + .flags = 0, + .len = 2, + .buf = tmp_buf, +#if SUPPORT_ROCKCHIP + .scl_rate = ICN85XX_I2C_SCL, +#endif + }, + { + .addr = this_client->addr, + .flags = I2C_M_RD, + .len = length, + .buf = rxdata, +#if SUPPORT_ROCKCHIP + .scl_rate = ICN85XX_I2C_SCL, +#endif + }, + }; + + tmp_buf[0] = (unsigned char)(addr>>8); + tmp_buf[1] = (unsigned char)(addr); + + + while(retries < IIC_RETRY_NUM) + { + ret = i2c_transfer(this_client->adapter, msgs, 2); + if(ret == 2)break; + retries++; + } + + if (retries >= IIC_RETRY_NUM) + { + icn85xx_error("%s i2c read error: %d\n", __func__, ret); +// icn85xx_ts_reset(); + } +#else + + tmp_buf[0] = (unsigned char)(addr>>8); + tmp_buf[1] = (unsigned char)(addr); + + while(retries < IIC_RETRY_NUM) + { + // ret = i2c_transfer(this_client->adapter, msgs, 2); + ret = i2c_master_send(this_client, tmp_buf, 2); + if (ret < 0) + return ret; + ret = i2c_master_recv(this_client, rxdata, length); + if (ret < 0) + return ret; + if(ret == length)break; + retries++; + } + + if (retries >= IIC_RETRY_NUM) + { + icn85xx_error("%s i2c read error: %d\n", __func__, ret); +// icn85xx_ts_reset(); + } +#endif + + return ret; +} +/*********************************************************************************************** +Name : icn85xx_i2c_txdata +Input : addr + *rxdata + length +Output : ret +function : send data to icn85xx , normal mode +***********************************************************************************************/ +int icn85xx_i2c_txdata(unsigned short addr, char *txdata, int length) +{ + int ret = -1; + unsigned char tmp_buf[128]; + int retries = 0; + + struct i2c_msg msg[] = { + { + .addr = this_client->addr, + .flags = 0, + .len = length + 2, + .buf = tmp_buf, +#if SUPPORT_ROCKCHIP + .scl_rate = ICN85XX_I2C_SCL, +#endif + }, + }; + + if (length > 125) + { + icn85xx_error("%s too big datalen = %d!\n", __func__, length); + return -1; + } + + tmp_buf[0] = (unsigned char)(addr>>8); + tmp_buf[1] = (unsigned char)(addr); + + if (length != 0 && txdata != NULL) + { + memcpy(&tmp_buf[2], txdata, length); + } + + while(retries < IIC_RETRY_NUM) + { + ret = i2c_transfer(this_client->adapter, msg, 1); + if(ret == 1)break; + retries++; + } + + if (retries >= IIC_RETRY_NUM) + { + icn85xx_error("%s i2c write error: %d\n", __func__, ret); +// icn85xx_ts_reset(); + } + + return ret; +} + +/*********************************************************************************************** +Name : icn85xx_write_reg +Input : addr -- address + para -- parameter +Output : +function : write register of icn85xx, normal mode +***********************************************************************************************/ +int icn85xx_write_reg(unsigned short addr, char para) +{ + char buf[3]; + int ret = -1; + + buf[0] = para; + ret = icn85xx_i2c_txdata(addr, buf, 1); + if (ret < 0) { + icn85xx_error("write reg failed! %#x ret: %d\n", buf[0], ret); + return -1; + } + + return ret; +} + + +/*********************************************************************************************** +Name : icn85xx_read_reg +Input : addr + pdata +Output : +function : read register of icn85xx, normal mode +***********************************************************************************************/ +int icn85xx_read_reg(unsigned short addr, char *pdata) +{ + int ret = -1; + ret = icn85xx_i2c_rxdata(addr, pdata, 1); + if(ret < 0) + { + icn85xx_error("addr: 0x%x: 0x%x\n", addr, *pdata); + } + return ret; +} + + +/*********************************************************************************************** +Name : icn85xx_log +Input : 0: rawdata, 1: diff data +Output : err type +function : calibrate param +***********************************************************************************************/ +static void icn85xx_log(char diff) +{ + char row = 0; + char column = 0; + int i, j, ret; + char retvalue = 0; + + icn85xx_read_reg(0x8004, &row); + icn85xx_read_reg(0x8005, &column); + + //scan tp rawdata + icn85xx_write_reg(4, 0x20); + mdelay(1); + for(i=0; i<1000; i++) + { + mdelay(1); + icn85xx_read_reg(2, &retvalue); + if(retvalue == 1) + break; + } + if(diff == 0) + { + for(i=0; iictype = 0; + icn85xx_trace("====%s begin=====. \n", __func__); + + while(retry++ < 3) + { + ret = icn85xx_read_reg(0xa, &value); + if(ret > 0) + { + if(value == 0x85) + { + icn85xx_ts->ictype = ICN85XX_WITH_FLASH; + return ret; + } + } + + icn85xx_info("iic test error! retry = %d\n", retry); + msleep(3); + } + icn85xx_goto_progmode(); + msleep(10); + retry = 0; + while(retry++ < 3) + { + ret = icn85xx_prog_i2c_rxdata(0x040002, &value, 1); + icn85xx_info("icn85xx_check_progmod: 0x%x\n", value); + if(ret > 0) + { + if(value == 0x85) + { + flashid = icn85xx_read_flashid(); + if((MD25D40_ID1 == flashid) || (MD25D40_ID2 == flashid) + ||(MD25D20_ID1 == flashid) || (MD25D20_ID1 == flashid) + ||(GD25Q10_ID == flashid) || (MX25L512E_ID == flashid)) + { + icn85xx_ts->ictype = ICN85XX_WITH_FLASH; + } + else + { + icn85xx_ts->ictype = ICN85XX_WITHOUT_FLASH; + } + return ret; + } + } + icn85xx_error("iic2 test error! %d\n", retry); + msleep(3); + } + + return ret; +} + +#if !CTP_REPORT_PROTOCOL +/*********************************************************************************************** +Name : icn85xx_ts_release +Input : void +Output : +function : touch release +***********************************************************************************************/ +static void icn85xx_ts_release(void) +{ + struct icn85xx_ts_data *icn85xx_ts = i2c_get_clientdata(this_client); + icn85xx_info("==icn85xx_ts_release ==\n"); + input_report_abs(icn85xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, 0); + input_sync(icn85xx_ts->input_dev); +} + +/*********************************************************************************************** +Name : icn85xx_report_value_A +Input : void +Output : +function : reprot touch ponit +***********************************************************************************************/ +static void icn85xx_report_value_A(void) +{ + struct icn85xx_ts_data *icn85xx_ts = i2c_get_clientdata(this_client); + char buf[POINT_NUM*POINT_SIZE+3]={0}; + int ret = -1; + int i; +#if TOUCH_VIRTUAL_KEYS + unsigned char button; + static unsigned char button_last; +#endif + + icn85xx_info("==icn85xx_report_value_A ==\n"); + + ret = icn85xx_i2c_rxdata(0x1000, buf, POINT_NUM*POINT_SIZE+2); + if (ret < 0) { + icn85xx_error("%s read_data i2c_rxdata failed: %d\n", __func__, ret); + return ; + } +#if TOUCH_VIRTUAL_KEYS + button = buf[0]; + icn85xx_info("%s: button=%d\n",__func__, button); + + if((button_last != 0) && (button == 0)) + { + icn85xx_ts_release(); + button_last = button; + return ; + } + if(button != 0) + { + switch(button) + { + case ICN_VIRTUAL_BUTTON_HOME: + icn85xx_info("ICN_VIRTUAL_BUTTON_HOME down\n"); + input_report_abs(icn85xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, 200); + input_report_abs(icn85xx_ts->input_dev, ABS_MT_POSITION_X, 280); + input_report_abs(icn85xx_ts->input_dev, ABS_MT_POSITION_Y, 1030); + input_report_abs(icn85xx_ts->input_dev, ABS_MT_WIDTH_MAJOR, 1); + input_mt_sync(icn85xx_ts->input_dev); + input_sync(icn85xx_ts->input_dev); + break; + case ICN_VIRTUAL_BUTTON_BACK: + icn85xx_info("ICN_VIRTUAL_BUTTON_BACK down\n"); + input_report_abs(icn85xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, 200); + input_report_abs(icn85xx_ts->input_dev, ABS_MT_POSITION_X, 470); + input_report_abs(icn85xx_ts->input_dev, ABS_MT_POSITION_Y, 1030); + input_report_abs(icn85xx_ts->input_dev, ABS_MT_WIDTH_MAJOR, 1); + input_mt_sync(icn85xx_ts->input_dev); + input_sync(icn85xx_ts->input_dev); + break; + case ICN_VIRTUAL_BUTTON_MENU: + icn85xx_info("ICN_VIRTUAL_BUTTON_MENU down\n"); + input_report_abs(icn85xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, 200); + input_report_abs(icn85xx_ts->input_dev, ABS_MT_POSITION_X, 100); + input_report_abs(icn85xx_ts->input_dev, ABS_MT_POSITION_Y, 1030); + input_report_abs(icn85xx_ts->input_dev, ABS_MT_WIDTH_MAJOR, 1); + input_mt_sync(icn85xx_ts->input_dev); + input_sync(icn85xx_ts->input_dev); + break; + default: + icn85xx_info("other gesture\n"); + break; + } + button_last = button; + return ; + } +#endif + + icn85xx_ts->point_num = buf[1]; + if (icn85xx_ts->point_num == 0) { + icn85xx_ts_release(); + return ; + } + for(i=0;ipoint_num;i++){ + if(buf[8 + POINT_SIZE*i] != 4) + { + break ; + } + else + { + + } + } + + if(i == icn85xx_ts->point_num) { + icn85xx_ts_release(); + return ; + } + + for(i=0; ipoint_num; i++) + { + icn85xx_ts->point_info[i].u8ID = buf[2 + POINT_SIZE*i]; + icn85xx_ts->point_info[i].u16PosX = (buf[4 + POINT_SIZE*i]<<8) + buf[3 + POINT_SIZE*i]; + icn85xx_ts->point_info[i].u16PosY = (buf[6 + POINT_SIZE*i]<<8) + buf[5 + POINT_SIZE*i]; + icn85xx_ts->point_info[i].u8Pressure = 20;//buf[7 + POINT_SIZE*i]; + icn85xx_ts->point_info[i].u8EventId = buf[8 + POINT_SIZE*i]; + + if(1 == icn85xx_ts->revert_x_flag) + { + icn85xx_ts->point_info[i].u16PosX = icn85xx_ts->screen_max_x- icn85xx_ts->point_info[i].u16PosX; + } + if(1 == icn85xx_ts->revert_y_flag) + { + icn85xx_ts->point_info[i].u16PosY = icn85xx_ts->screen_max_y- icn85xx_ts->point_info[i].u16PosY; + } + + icn85xx_info("u8ID %d\n", icn85xx_ts->point_info[i].u8ID); + icn85xx_info("u16PosX %d\n", icn85xx_ts->point_info[i].u16PosX); + icn85xx_info("u16PosY %d\n", icn85xx_ts->point_info[i].u16PosY); + icn85xx_info("u8Pressure %d\n", icn85xx_ts->point_info[i].u8Pressure); + icn85xx_info("u8EventId %d\n", icn85xx_ts->point_info[i].u8EventId); + + + input_report_abs(icn85xx_ts->input_dev, ABS_MT_TRACKING_ID, icn85xx_ts->point_info[i].u8ID); + input_report_abs(icn85xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, icn85xx_ts->point_info[i].u8Pressure); + input_report_abs(icn85xx_ts->input_dev, ABS_MT_POSITION_X, icn85xx_ts->point_info[i].u16PosX); + input_report_abs(icn85xx_ts->input_dev, ABS_MT_POSITION_Y, icn85xx_ts->point_info[i].u16PosY); + input_report_abs(icn85xx_ts->input_dev, ABS_MT_WIDTH_MAJOR, 1); + input_mt_sync(icn85xx_ts->input_dev); + icn85xx_point_info("point: %d ===x = %d,y = %d, press = %d ====\n",i, icn85xx_ts->point_info[i].u16PosX,icn85xx_ts->point_info[i].u16PosY, icn85xx_ts->point_info[i].u8Pressure); + } + + input_sync(icn85xx_ts->input_dev); + +} +#endif +/*********************************************************************************************** +Name : icn85xx_report_value_B +Input : void +Output : +function : reprot touch ponit +***********************************************************************************************/ +#if CTP_REPORT_PROTOCOL +static void icn85xx_report_value_B(void) +{ + struct icn85xx_ts_data *icn85xx_ts = i2c_get_clientdata(this_client); + char buf[POINT_NUM*POINT_SIZE+3]={0}; + static unsigned char finger_last[POINT_NUM + 1]={0}; + unsigned char finger_current[POINT_NUM + 1] = {0}; + unsigned int position = 0; + int temp = 0; + int ret = -1; + int x,y; + icn85xx_info("==icn85xx_report_value_B ==\n"); + + + + ret = icn85xx_i2c_rxdata(0x1000, buf, POINT_NUM*POINT_SIZE+2); + if (ret < 0) { + icn85xx_error("%s read_data i2c_rxdata failed: %d\n", __func__, ret); + return ; + } + icn85xx_ts->point_num = buf[1]; + if (icn85xx_ts->point_num > POINT_NUM) + { + return ; + } + + if(icn85xx_ts->point_num > 0) + { + for(position = 0; positionpoint_num; position++) + { + temp = buf[2 + POINT_SIZE*position] + 1; + finger_current[temp] = 1; + icn85xx_ts->point_info[temp].u8ID = buf[2 + POINT_SIZE*position]; + icn85xx_ts->point_info[temp].u16PosX = (buf[4 + POINT_SIZE*position]<<8) + buf[3 + POINT_SIZE*position]; + icn85xx_ts->point_info[temp].u16PosY = (buf[6 + POINT_SIZE*position]<<8) + buf[5 + POINT_SIZE*position]; + icn85xx_ts->point_info[temp].u8Pressure = buf[7 + POINT_SIZE*position]; + icn85xx_ts->point_info[temp].u8EventId = buf[8 + POINT_SIZE*position]; + + if(icn85xx_ts->point_info[temp].u8EventId == 4) + finger_current[temp] = 0; + + if(1 == icn85xx_ts->revert_x_flag) + { + icn85xx_ts->point_info[temp].u16PosX = icn85xx_ts->screen_max_x- icn85xx_ts->point_info[temp].u16PosX; + } + if(1 == icn85xx_ts->revert_y_flag) + { + icn85xx_ts->point_info[temp].u16PosY = icn85xx_ts->screen_max_y- icn85xx_ts->point_info[temp].u16PosY; + } + icn85xx_info("temp %d\n", temp); + icn85xx_info("u8ID %d\n", icn85xx_ts->point_info[temp].u8ID); + icn85xx_info("u16PosX %d\n", icn85xx_ts->point_info[temp].u16PosX); + icn85xx_info("u16PosY %d\n", icn85xx_ts->point_info[temp].u16PosY); + icn85xx_info("u8Pressure %d\n", icn85xx_ts->point_info[temp].u8Pressure); + icn85xx_info("u8EventId %d\n", icn85xx_ts->point_info[temp].u8EventId); + //icn85xx_info("u8Pressure %d\n", icn85xx_ts->point_info[temp].u8Pressure*16); + } + } + else + { + for(position = 1; position < POINT_NUM+1; position++) + { + finger_current[position] = 0; + } + icn85xx_info("no touch\n"); + } + + for(position = 1; position < POINT_NUM + 1; position++) + { + if((finger_current[position] == 0) && (finger_last[position] != 0)) + { + input_mt_slot(icn85xx_ts->input_dev, position-1); + input_mt_report_slot_state(icn85xx_ts->input_dev, MT_TOOL_FINGER, false); + icn85xx_point_info("one touch up: %d\n", position); + } + else if(finger_current[position]) + { + if (g_param.xyswap == 0) + { + x = icn85xx_ts->point_info[position].u16PosX; + y = icn85xx_ts->point_info[position].u16PosY; + } else { + y = icn85xx_ts->point_info[position].u16PosX; + x = icn85xx_ts->point_info[position].u16PosY; + } + if (g_param.xdir == -1) + { + x = g_param.panelres_x - x; + } + if (g_param.ydir == -1) + { + y = g_param.panelres_y - y; + } + + if (g_param.lcd_exchg) { + int tmp; + tmp = x; + x = y; + y = g_param.panelres_x - tmp; + } + + input_mt_slot(icn85xx_ts->input_dev, position-1); + input_mt_report_slot_state(icn85xx_ts->input_dev, MT_TOOL_FINGER, true); + input_report_abs(icn85xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, 1); + //input_report_abs(icn85xx_ts->input_dev, ABS_MT_PRESSURE, icn85xx_ts->point_info[position].u8Pressure); + input_report_abs(icn85xx_ts->input_dev, ABS_MT_PRESSURE, 200); + input_report_abs(icn85xx_ts->input_dev, ABS_MT_POSITION_X, x); + input_report_abs(icn85xx_ts->input_dev, ABS_MT_POSITION_Y, y); + //icn85xx_point_info("===position: %d, x = %d,y = %d, press = %d ====\n", position, icn85xx_ts->point_info[position].u16PosX,icn85xx_ts->point_info[position].u16PosY, icn85xx_ts->point_info[position].u8Pressure); + icn85xx_point_info("raw%d(%d,%d), rpt%d(%d,%d)\n", position, icn85xx_ts->point_info[position].u16PosX, icn85xx_ts->point_info[position].u16PosY, position, x, y); + } + + } + input_sync(icn85xx_ts->input_dev); + + for(position = 1; position < POINT_NUM + 1; position++) + { + finger_last[position] = finger_current[position]; + } + +} +#endif + +/*********************************************************************************************** +Name : icn85xx_ts_pen_irq_work +Input : void +Output : +function : work_struct +***********************************************************************************************/ +static void icn85xx_ts_pen_irq_work(struct work_struct *work) +{ + struct icn85xx_ts_data *icn85xx_ts = i2c_get_clientdata(this_client); +#if SUPPORT_PROC_FS + if(down_interruptible(&icn85xx_ts->sem)) + { + return ; + } +#endif + + if(icn85xx_ts->work_mode == 0) + { +#if CTP_REPORT_PROTOCOL + icn85xx_report_value_B(); +#else + icn85xx_report_value_A(); +#endif + + + if(icn85xx_ts->use_irq) + { + icn85xx_irq_enable(); + } + if(log_on_off == 4) + { + printk("normal raw data\n"); + icn85xx_log(0); //raw data + } + else if(log_on_off == 5) + { + printk("normal diff data\n"); + icn85xx_log(1); //diff data + } + else if(log_on_off == 6) + { + printk("normal raw2diff\n"); + icn85xx_log(2); //diff data + } + + } + else if(icn85xx_ts->work_mode == 1) + { + printk("raw data\n"); + icn85xx_log(0); //raw data + } + else if(icn85xx_ts->work_mode == 2) + { + printk("diff data\n"); + icn85xx_log(1); //diff data + } + else if(icn85xx_ts->work_mode == 3) + { + printk("raw2diff data\n"); + icn85xx_log(2); //diff data + } + else if(icn85xx_ts->work_mode == 4) //idle + { + ; + } + else if(icn85xx_ts->work_mode == 5)//write para, reinit + { + printk("reinit tp\n"); + icn85xx_write_reg(0, 1); + mdelay(100); + icn85xx_write_reg(0, 0); + icn85xx_ts->work_mode = 0; + } + +#if SUPPORT_PROC_FS + up(&icn85xx_ts->sem); +#endif + + +} +/*********************************************************************************************** +Name : chipone_timer_func +Input : void +Output : +function : Timer interrupt service routine. +***********************************************************************************************/ +static enum hrtimer_restart chipone_timer_func(struct hrtimer *timer) +{ + struct icn85xx_ts_data *icn85xx_ts = container_of(timer, struct icn85xx_ts_data, timer); + queue_work(icn85xx_ts->ts_workqueue, &icn85xx_ts->pen_event_work); + //icn85xx_info("chipone_timer_func\n"); + if(icn85xx_ts->use_irq == 1) + { + if((icn85xx_ts->work_mode == 1) || (icn85xx_ts->work_mode == 2) || (icn85xx_ts->work_mode == 3)) + { + hrtimer_start(&icn85xx_ts->timer, ktime_set(CTP_POLL_TIMER/1000, (CTP_POLL_TIMER%1000)*1000000), HRTIMER_MODE_REL); + } + } + else + { + hrtimer_start(&icn85xx_ts->timer, ktime_set(CTP_POLL_TIMER/1000, (CTP_POLL_TIMER%1000)*1000000), HRTIMER_MODE_REL); + } + return HRTIMER_NORESTART; +} +/*********************************************************************************************** +Name : icn85xx_ts_interrupt +Input : void +Output : +function : interrupt service routine +***********************************************************************************************/ +static irqreturn_t icn85xx_ts_interrupt(int irq, void *dev_id) +{ + struct icn85xx_ts_data *icn85xx_ts = dev_id; + int irqindex = g_param.irqgpio; + + icn85xx_info("==========------icn85xx_ts TS Interrupt-----============\n"); + + if (gpio_irqstatus(irqindex)) { + wmt_gpio_ack_irq(irqindex); + if (is_gpio_irqenable(irqindex)) { + icn85xx_irq_disable(); + if(icn85xx_ts->work_mode != 0) { + icn85xx_irq_enable(); + return IRQ_HANDLED; + } + if (!work_pending(&icn85xx_ts->pen_event_work)) { + icn85xx_info("Enter work\n"); + queue_work(icn85xx_ts->ts_workqueue, &icn85xx_ts->pen_event_work); + } + } + return IRQ_HANDLED; + } + return IRQ_NONE; + + /*if(icn85xx_ts->use_irq) + icn85xx_irq_disable(); + if (!work_pending(&icn85xx_ts->pen_event_work)) + { + queue_work(icn85xx_ts->ts_workqueue, &icn85xx_ts->pen_event_work); + + } + + return IRQ_HANDLED;*/ +} + +/*********************************************************************************************** +Name : icn85xx_ts_suspend +Input : void +Output : +function : tp enter sleep mode +***********************************************************************************************/ +static int icn85xx_ts_suspend(struct i2c_client *client, pm_message_t mesg) +{ + struct icn85xx_ts_data *icn85xx_ts = i2c_get_clientdata(client); + icn85xx_trace("icn85xx_ts_suspend\n"); + if (icn85xx_ts->use_irq) { + icn85xx_irq_disable(); + } else { + hrtimer_cancel(&icn85xx_ts->timer); + } + cancel_work_sync(&icn85xx_ts->pen_event_work); + flush_workqueue(icn85xx_ts->ts_workqueue); + //} + + //reset flag if ic is flashless when power off + if(icn85xx_ts->ictype == ICN85XX_WITHOUT_FLASH) + { + //icn85xx_ts->code_loaded_flag = 0; + } +#if SUSPEND_POWER_OFF + +#else + icn85xx_write_reg(ICN85xx_REG_PMODE, PMODE_HIBERNATE); +#endif + + return 0; + +} + +int resume_download_thread(void *arg) +{ + int retry = 1; + int need_update_fw = false; + int ret = -1; + unsigned char value; + struct icn85xx_ts_data *icn85xx_ts = (struct icn85xx_ts_data*)arg; + wake_lock(&downloadWakeLock); + while (retry-- && !need_update_fw) { + icn85xx_ts_reset(); + icn85xx_bootfrom_sram(); + msleep(50); + ret = icn85xx_read_reg(0xa, &value); + if (ret > 0) { + need_update_fw = false; + break; + } + } + if (retry < 0) need_update_fw = true; + + if (need_update_fw) { + if(R_OK == icn85xx_fw_update(firmware)) { + icn85xx_ts->code_loaded_flag = 1; + icn85xx_trace("ICN85XX_WITHOUT_FLASH, reload code ok\n"); + } + else { + icn85xx_ts->code_loaded_flag = 0; + icn85xx_trace("ICN85XX_WITHOUT_FLASH, reload code error\n"); + } + } + + if (icn85xx_ts->use_irq) { + icn85xx_irq_enable(); + } else { + hrtimer_start(&icn85xx_ts->timer, ktime_set(CTP_START_TIMER/1000, \ + (CTP_START_TIMER%1000)*1000000), HRTIMER_MODE_REL); + } + wake_unlock(&downloadWakeLock); + return 0; +} + +/*********************************************************************************************** +Name : icn85xx_ts_resume +Input : void +Output : +function : wakeup tp or reset tp +***********************************************************************************************/ +static int icn85xx_ts_resume(struct i2c_client *client) +{ + struct icn85xx_ts_data *icn85xx_ts = i2c_get_clientdata(client); + int i; + icn85xx_trace("==icn85xx_ts_resume== \n"); + + //report touch release +#if CTP_REPORT_PROTOCOL + for(i = 0; i < POINT_NUM; i++) + { + input_mt_slot(icn85xx_ts->input_dev, i); + input_mt_report_slot_state(icn85xx_ts->input_dev, MT_TOOL_FINGER, false); + } +#else + icn85xx_ts_release(); +#endif + + + if(icn85xx_ts->ictype == ICN85XX_WITHOUT_FLASH) { + if (bl_is_delay) { + resume_download_task = kthread_create(resume_download_thread, icn85xx_ts, "resume_download"); + if(IS_ERR(resume_download_task)) { + icn85xx_error("cread thread failed\n"); + } + wake_up_process(resume_download_task); + } else + resume_download_thread(icn85xx_ts); + } else { + icn85xx_write_reg(ICN85xx_REG_PMODE, 0xff); + icn85xx_ts_reset(); + if (icn85xx_ts->use_irq) { + icn85xx_irq_enable(); + } else { + hrtimer_start(&icn85xx_ts->timer, ktime_set(CTP_START_TIMER/1000, \ + (CTP_START_TIMER%1000)*1000000), HRTIMER_MODE_REL); + } + } + + // icn85xx_write_reg(ICN85xx_REG_PMODE, 0x00); + return 0; +} + +/*********************************************************************************************** +Name : icn85xx_request_io_port +Input : void +Output : +function : 0 success, +***********************************************************************************************/ +static int icn85xx_request_io_port(struct icn85xx_ts_data *icn85xx_ts) +{ + +#if SUPPORT_ROCKCHIP + icn85xx_ts->screen_max_x = SCREEN_MAX_X; + icn85xx_ts->screen_max_y = SCREEN_MAX_Y; + icn85xx_ts->irq = CTP_IRQ_PORT; //maybe need changed +#endif + icn85xx_ts->irq = IRQ_GPIO; + + if (gpio_request(g_param.rstgpio, "ts_rst") < 0) { + printk("gpio(%d) touchscreen reset request fail\n", g_param.rstgpio); + return -EIO; + } + gpio_direction_output(g_param.rstgpio, 1); + + if (gpio_request(g_param.irqgpio, "ts_irq") < 0) { + printk("gpio(%d) touchscreen interrupt request fail\n", g_param.irqgpio); + gpio_free(g_param.rstgpio); + return -EIO; + } + wmt_gpio_setpull(g_param.irqgpio, WMT_GPIO_PULL_UP); + gpio_direction_input(g_param.irqgpio); + + + return 0; + +} + +/*********************************************************************************************** +Name : icn85xx_free_io_port +Input : void +Output : +function : 0 success, +***********************************************************************************************/ +static void icn85xx_free_io_port(void) +{ + gpio_free(g_param.rstgpio); + gpio_free(g_param.irqgpio); + return; +} + +/*********************************************************************************************** +Name : icn85xx_request_irq +Input : void +Output : +function : 0 success, +***********************************************************************************************/ +static int icn85xx_request_irq(struct icn85xx_ts_data *icn85xx_ts) +{ + int err = -1; + + + wmt_gpio_set_irq_type(g_param.irqgpio, IRQ_TYPE_EDGE_FALLING); + err = request_irq(icn85xx_ts->irq, icn85xx_ts_interrupt, IRQF_SHARED, "icn85xx_ts", icn85xx_ts); + if (err < 0) + { + icn85xx_error("icn85xx_ts_probe: request irq failed\n"); + return err; + } + else + { + icn85xx_irq_disable(); + icn85xx_ts->use_irq = 1; + } + +#if SUPPORT_ROCKCHIP + err = gpio_request(icn85xx_ts->irq, "TS_INT"); //Request IO + if (err < 0) + { + icn85xx_error("Failed to request GPIO:%d, ERRNO:%d\n", (int)icn85xx_ts->irq, err); + return err; + } + gpio_direction_input(icn85xx_ts->irq); + err = request_irq(icn85xx_ts->irq, icn85xx_ts_interrupt, IRQ_TYPE_EDGE_FALLING, "icn85xx_ts", icn85xx_ts); + if (err < 0) + { + icn85xx_ts->use_irq = 0; + icn85xx_error("icn85xx_ts_probe: request irq failed\n"); + return err; + } + else + { + icn85xx_irq_disable(); + icn85xx_ts->use_irq = 1; + } +#endif + + return 0; +} + + +/*********************************************************************************************** +Name : icn85xx_free_irq +Input : void +Output : +function : 0 success, +***********************************************************************************************/ +static void icn85xx_free_irq(struct icn85xx_ts_data *icn85xx_ts) +{ + if (icn85xx_ts) + { + if (icn85xx_ts->use_irq) + { + free_irq(icn85xx_ts->irq, icn85xx_ts); + } + else + { + hrtimer_cancel(&icn85xx_ts->timer); + } + } + +} + +/*********************************************************************************************** +Name : icn85xx_request_input_dev +Input : void +Output : +function : 0 success, +***********************************************************************************************/ +static int icn85xx_request_input_dev(struct icn85xx_ts_data *icn85xx_ts) +{ + int ret = -1; + struct input_dev *input_dev; + + input_dev = input_allocate_device(); + if (!input_dev) { + icn85xx_error("failed to allocate input device\n"); + return -ENOMEM; + } + icn85xx_ts->input_dev = input_dev; + + icn85xx_ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) ; +#if CTP_REPORT_PROTOCOL + __set_bit(INPUT_PROP_DIRECT, icn85xx_ts->input_dev->propbit); + input_mt_init_slots(icn85xx_ts->input_dev, POINT_NUM*2); +#else + set_bit(ABS_MT_TOUCH_MAJOR, icn85xx_ts->input_dev->absbit); + set_bit(ABS_MT_POSITION_X, icn85xx_ts->input_dev->absbit); + set_bit(ABS_MT_POSITION_Y, icn85xx_ts->input_dev->absbit); + set_bit(ABS_MT_WIDTH_MAJOR, icn85xx_ts->input_dev->absbit); +#endif + if (g_param.lcd_exchg) { + input_set_abs_params(icn85xx_ts->input_dev, ABS_MT_POSITION_X, 0, g_param.panelres_y, 0, 0); + input_set_abs_params(icn85xx_ts->input_dev, ABS_MT_POSITION_Y, 0, g_param.panelres_x, 0, 0); + } else { + input_set_abs_params(icn85xx_ts->input_dev, ABS_MT_POSITION_X, 0, g_param.panelres_x, 0, 0); + input_set_abs_params(icn85xx_ts->input_dev, ABS_MT_POSITION_Y, 0, g_param.panelres_y, 0, 0); + } + input_set_abs_params(icn85xx_ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0); + input_set_abs_params(icn85xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); + input_set_abs_params(icn85xx_ts->input_dev, ABS_MT_TRACKING_ID, 0, POINT_NUM*2, 0, 0); + + __set_bit(KEY_MENU, input_dev->keybit); + __set_bit(KEY_BACK, input_dev->keybit); + __set_bit(KEY_HOME, input_dev->keybit); + __set_bit(KEY_SEARCH, input_dev->keybit); + + input_dev->name = CTP_NAME; + ret = input_register_device(input_dev); + if (ret) { + icn85xx_error("Register %s input device failed\n", input_dev->name); + input_free_device(input_dev); + return -ENODEV; + } + +#ifdef CONFIG_HAS_EARLYSUSPEND + icn85xx_trace("==register_early_suspend =\n"); + icn85xx_ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + icn85xx_ts->early_suspend.suspend = icn85xx_ts_suspend; + icn85xx_ts->early_suspend.resume = icn85xx_ts_resume; + register_early_suspend(&icn85xx_ts->early_suspend); +#endif + + return 0; +} +#if SUPPORT_SENSOR_ID +static void read_sensor_id(void) +{ + int i,ret; + //icn85xx_trace("scan sensor id value begin sensor_id_num = %d\n",(sizeof(sensor_id_table)/sizeof(sensor_id_table[0]))); + ret = icn85xx_read_reg(0x10, &cursensor_id); + if(ret > 0) + { + icn85xx_trace("cursensor_id= 0x%x\n", cursensor_id); + } + else + { + icn85xx_error("icn85xx read cursensor_id failed.\n"); + cursensor_id = -1; + } + + ret = icn85xx_read_reg(0x1e, &tarsensor_id); + if(ret > 0) + { + icn85xx_trace("tarsensor_id= 0x%x\n", tarsensor_id); + tarsensor_id = -1; + } + else + { + icn85xx_error("icn85xx read tarsensor_id failed.\n"); + } + ret = icn85xx_read_reg(0x1f, &id_match); + if(ret > 0) + { + icn85xx_trace("match_flag= 0x%x\n", id_match); // 1: match; 0:not match + } + else + { + icn85xx_error("icn85xx read id_match failed.\n"); + id_match = -1; + } + // scan sensor id value + icn85xx_trace("begin to scan id table,find correct fw or bin. sensor_id_num = %d\n",(sizeof(sensor_id_table)/sizeof(sensor_id_table[0]))); + + for(i = 0;i < (sizeof(sensor_id_table)/sizeof(sensor_id_table[0])); i++) // not change tp + { + if (cursensor_id == sensor_id_table[i].value) + { + #if COMPILE_FW_WITH_DRIVER + icn85xx_set_fw(sensor_id_table[i].size, sensor_id_table[i].fw_name); + #else + strcpy(firmware,sensor_id_table[i].bin_name); + icn85xx_trace("icn85xx matched firmware = %s\n", firmware); + #endif + icn85xx_trace("icn85xx matched id = 0x%x\n", sensor_id_table[i].value); + invalid_id = 1; + break; + } + else + { + invalid_id = 0; + icn85xx_trace("icn85xx not matched id%d= 0x%x\n", i,sensor_id_table[i].value); + //icn85xx_trace("not match sensor_id_table[%d].value= 0x%x,bin_name = %s\n",i,sensor_id_table[i].value,sensor_id_table[i].bin_name); + } + } + +} +static void compare_sensor_id(void) +{ + int retry = 5; + + read_sensor_id(); // select sensor id + + if(0 == invalid_id) //not compare sensor id,update default fw or bin + { + icn85xx_trace("not compare sensor id table,update default: invalid_id= %d, cursensor_id= %d\n", invalid_id,cursensor_id); + #if COMPILE_FW_WITH_DRIVER + icn85xx_set_fw(sensor_id_table[0].size, sensor_id_table[0].fw_name); + #else + strcpy(firmware,sensor_id_table[0].bin_name); + icn85xx_trace("match default firmware = %s\n", firmware); + #endif + + while(retry > 0) + { + if(R_OK == icn85xx_fw_update(firmware)) + { + icn85xx_trace("icn85xx upgrade default firmware ok\n"); + break; + } + retry--; + icn85xx_error("icn85xx_fw_update default firmware failed.\n"); + } + } + + if ((1 == invalid_id)&&(0 == id_match)) // tp is changed,update current fw or bin + { + icn85xx_trace("icn85xx detect tp is changed!!! invalid_id= %d,id_match= %d,\n", invalid_id,id_match); + while(retry > 0) + { + if(R_OK == icn85xx_fw_update(firmware)) + { + icn85xx_trace("icn85xx upgrade cursensor id firmware ok\n"); + break; + } + retry--; + icn85xx_error("icn85xx_fw_update current id firmware failed.\n"); + } + } +} +#endif + +static void icn85xx_update(struct icn85xx_ts_data *icn85xx_ts) +{ + short fwVersion = 0; + short curVersion = 0; + int retry = 0; + + if(icn85xx_ts->ictype == ICN85XX_WITHOUT_FLASH) + { + #if (COMPILE_FW_WITH_DRIVER && !SUPPORT_SENSOR_ID) + icn85xx_set_fw(sizeof(icn85xx_fw), &icn85xx_fw[0]); + #endif + + #if SUPPORT_SENSOR_ID + while(0 == invalid_id ) //reselect sensor id + { + compare_sensor_id(); // select sensor id + icn85xx_trace("invalid_id= %d\n", invalid_id); + } + #else + if(R_OK == icn85xx_fw_update(firmware)) + { + icn85xx_ts->code_loaded_flag = 1; + icn85xx_trace("ICN85XX_WITHOUT_FLASH, update default fw ok\n"); + } + else + { + icn85xx_ts->code_loaded_flag = 0; + icn85xx_trace("ICN85XX_WITHOUT_FLASH, update error\n"); + } + #endif + + } + else if(icn85xx_ts->ictype == ICN85XX_WITH_FLASH) + { + #if (COMPILE_FW_WITH_DRIVER && !SUPPORT_SENSOR_ID) + icn85xx_set_fw(sizeof(icn85xx_fw), &icn85xx_fw[0]); + #endif + + #if SUPPORT_SENSOR_ID + while(0 == invalid_id ) //reselect sensor id + { + compare_sensor_id(); // select sensor id + if( 1 == invalid_id) + { + icn85xx_trace("select sensor id ok. begin compare fwVersion with curversion\n"); + } + } + #endif + + fwVersion = icn85xx_read_fw_Ver(firmware); + curVersion = icn85xx_readVersion(); + icn85xx_trace("fwVersion : 0x%x\n", fwVersion); + icn85xx_trace("current version: 0x%x\n", curVersion); + + #if FORCE_UPDATA_FW + retry = 5; + while(retry > 0) + { + if(icn85xx_goto_progmode() != 0) + { + printk("icn85xx_goto_progmode() != 0 error\n"); + return -1; + } + icn85xx_read_flashid(); + if(R_OK == icn85xx_fw_update(firmware)) + { + break; + } + retry--; + icn85xx_error("icn85xx_fw_update failed.\n"); + } + + #else + if(fwVersion > curVersion) + { + retry = 5; + while(retry > 0) + { + if(R_OK == icn85xx_fw_update(firmware)) + { + break; + } + retry--; + icn85xx_error("icn85xx_fw_update failed.\n"); + } + } + #endif + } +} +static int icn85xx_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct icn85xx_ts_data *icn85xx_ts; + int err = 0; + + icn85xx_trace("====%s begin=====. \n", __func__); + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + { + icn85xx_error("I2C check functionality failed.\n"); + return -ENODEV; + } + + icn85xx_ts = kzalloc(sizeof(*icn85xx_ts), GFP_KERNEL); + if (!icn85xx_ts) + { + icn85xx_error("Alloc icn85xx_ts memory failed.\n"); + return -ENOMEM; + } + memset(icn85xx_ts, 0, sizeof(*icn85xx_ts)); + + this_client = client; + this_client->addr = client->addr; + i2c_set_clientdata(client, icn85xx_ts); + + icn85xx_ts->work_mode = 0; + spin_lock_init(&icn85xx_ts->irq_lock); +// icn85xx_ts->irq_lock = SPIN_LOCK_UNLOCKED; + + icn85xx_request_io_port(icn85xx_ts); + if (err != 0) { + icn85xx_error("icn85xx_request_io_port failed.\n"); + goto fail1; + } + memset(firmware, 0, 128); + sprintf(firmware,"%s.bin",g_param.fw_name); + + icn85xx_ts_reset(); + + err = icn85xx_iic_test(); + if (err <= 0) + { + icn85xx_error("icn85xx_iic_test failed.\n"); + goto fail2; + + } + else + { + icn85xx_trace("iic communication ok: 0x%x\n", icn85xx_ts->ictype); + } + + icn85xx_update(icn85xx_ts); + + err= icn85xx_request_input_dev(icn85xx_ts); + if (err < 0) + { + icn85xx_error("request input dev failed\n"); + goto fail3; + } + + + +#if TOUCH_VIRTUAL_KEYS + icn85xx_ts_virtual_keys_init(); +#endif + err = icn85xx_request_irq(icn85xx_ts); + if (err != 0) + { + icn85xx_error("request irq error, use timer\n"); + icn85xx_ts->use_irq = 0; + hrtimer_init(&icn85xx_ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + icn85xx_ts->timer.function = chipone_timer_func; + hrtimer_start(&icn85xx_ts->timer, ktime_set(CTP_START_TIMER/1000, (CTP_START_TIMER%1000)*1000000), HRTIMER_MODE_REL); + } +#if SUPPORT_SYSFS + icn85xx_create_sysfs(client); +#endif + +#if SUPPORT_PROC_FS + sema_init(&icn85xx_ts->sem, 1); + init_proc_node(); +#endif + + INIT_WORK(&icn85xx_ts->pen_event_work, icn85xx_ts_pen_irq_work); + icn85xx_ts->ts_workqueue = create_singlethread_workqueue(dev_name(&client->dev)); + if (!icn85xx_ts->ts_workqueue) { + icn85xx_error("create_singlethread_workqueue failed.\n"); + err = -ESRCH; + goto fail4; + } + + if(icn85xx_ts->use_irq) + icn85xx_irq_enable(); + icn85xx_trace("==%s over =\n", __func__); + return 0; +fail4: + cancel_work_sync(&icn85xx_ts->pen_event_work); +fail3: + input_unregister_device(icn85xx_ts->input_dev); + input_free_device(icn85xx_ts->input_dev); +fail2: + icn85xx_free_io_port(); +fail1: + kfree(icn85xx_ts); + icn85xx_free_fw(); + return err; +} + +static int __devexit icn85xx_ts_remove(struct i2c_client *client) +{ + struct icn85xx_ts_data *icn85xx_ts = i2c_get_clientdata(client); + icn85xx_trace("==icn85xx_ts_remove=\n"); + if(icn85xx_ts->use_irq) + icn85xx_irq_disable(); +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&icn85xx_ts->early_suspend); +#endif + +#if SUPPORT_PROC_FS + uninit_proc_node(); +#endif + +#if SUPPORT_SYSFS + icn85xx_remove_sysfs(client); +#endif + input_unregister_device(icn85xx_ts->input_dev); + input_free_device(icn85xx_ts->input_dev); + cancel_work_sync(&icn85xx_ts->pen_event_work); + destroy_workqueue(icn85xx_ts->ts_workqueue); + icn85xx_free_irq(icn85xx_ts); + icn85xx_free_io_port(); + icn85xx_free_fw(); + kfree(icn85xx_ts); + i2c_set_clientdata(client, NULL); + return 0; +} + +static int wmt_check_touch_env(void) +{ + int ret = 0; + int len = 96; + char retval[200] = {0},*p=NULL,*s=NULL; + int Enable=0; + + ret = wmt_getsyspara("wmt.io.touch", retval, &len); + if(ret){ + printk("Read wmt.io.touch Failed.\n"); + return -EIO; + } + +//paste: + p = retval; + Enable = (p[0] - '0' == 1) ? 1 : 0; + if(Enable == 0){ + printk("Touch Screen Is Disabled.\n"); + return -ENODEV; + } + + p = strchr(p,':');p++; + s = strchr(p,':'); + strncpy(g_param.fw_name,p, (s-p)); + printk("ts_name=%s\n", g_param.fw_name); + if (strncmp(g_param.fw_name, "ICN85", 5)) { + printk("Wrong firmware name.\n"); + return -ENODEV; + } + + p = s+1; + ret = sscanf(p,"%d:%d:%d:%d:%d:%d:%d", + &(g_param.irqgpio),&(g_param.panelres_x),&(g_param.panelres_y),&(g_param.rstgpio), + &(g_param.xyswap),&(g_param.xdir),&(g_param.ydir)); + + if (ret < 7) { + printk("Wrong format ts u-boot param(%d)!\nwmt.io.touch=%s\n",ret,retval); + return -ENODEV; + } + + printk("p.x = %d, p.y = %d, irqgpio=%d, rstgpio=%d,xyswap=%d,xdir=%d,ydir=%d\n", + g_param.panelres_x,g_param.panelres_y,g_param.irqgpio,g_param.rstgpio, + g_param.xyswap,g_param.xdir,g_param.ydir); + + /*memset(retval,0,sizeof(retval)); + ret = wmt_getsyspara("wmt.touch.earlysus", retval, &len); + if(!ret) + g_param.earlysus_en = (retval[0] - '0' == 1) ? 1 : 0;*/ + + memset(retval,0,sizeof(retval)); + ret = wmt_getsyspara("wmt.display.fb0", retval, &len); + if (!ret) { + int tmp[6]; + p = retval; + sscanf(p, "%d:[%d:%d:%d:%d:%d", &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5]); + if (tmp[4] > tmp[5]) + g_param.lcd_exchg = 1; + } + + ret = wmt_getsyspara("wmt.backlight.delay", retval, &len); + if(ret) { + bl_is_delay = 0; + } else + bl_is_delay = 1; + + return 0; +} + +static const struct i2c_device_id icn85xx_ts_id[] = { + { CTP_NAME, 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, icn85xx_ts_id); + +static struct i2c_driver icn85xx_ts_driver = { + .probe = icn85xx_ts_probe, + .remove = __devexit_p(icn85xx_ts_remove), +#ifndef CONFIG_HAS_EARLYSUSPEND + .suspend = icn85xx_ts_suspend, + .resume = icn85xx_ts_resume, +#endif + .id_table = icn85xx_ts_id, + .driver = { + .name = CTP_NAME, + .owner = THIS_MODULE, + }, + +}; + + +static struct i2c_board_info i2c_board_info = { + I2C_BOARD_INFO(CTP_NAME, ICN85XX_IIC_ADDR), +}; + + +static int __init icn85xx_ts_init(void) +{ + struct i2c_client *client; + struct i2c_adapter *adap; + icn85xx_trace("===========================%s=====================\n", __func__); + + if(wmt_check_touch_env()) + return -ENODEV; + + {//register i2c device + adap = i2c_get_adapter(1); //i2c Bus 1 + if (!adap) + return -ENODEV; + client = i2c_new_device(adap, &i2c_board_info); + i2c_put_adapter(adap); + if (!client) { + printk("i2c_new_device error\n"); + return -ENODEV; + } + } + + return i2c_add_driver(&icn85xx_ts_driver); +} + +static void __exit icn85xx_ts_exit(void) +{ + icn85xx_trace("==icn85xx_ts_exit==\n"); + i2c_unregister_device(this_client); + i2c_del_driver(&icn85xx_ts_driver); +} +late_initcall(icn85xx_ts_init); +//module_init(icn85xx_ts_init); +module_exit(icn85xx_ts_exit); + +MODULE_AUTHOR(""); +MODULE_DESCRIPTION("Chipone icn85xx TouchScreen driver"); +MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/icn85xx_ts/icn85xx.h b/ANDROID_3.4.5/drivers/input/touchscreen/icn85xx_ts/icn85xx.h new file mode 100755 index 00000000..262b76fb --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/icn85xx_ts/icn85xx.h @@ -0,0 +1,500 @@ +/*++ + + Copyright (c) 2012-2022 ChipOne Technology (Beijing) Co., Ltd. All Rights Reserved. + This PROPRIETARY SOFTWARE is the property of ChipOne Technology (Beijing) Co., Ltd. + and may contains trade secrets and/or other confidential information of ChipOne + Technology (Beijing) Co., Ltd. This file shall not be disclosed to any third party, + in whole or in part, without prior written consent of ChipOne. + THIS PROPRIETARY SOFTWARE & ANY RELATED DOCUMENTATION ARE PROVIDED AS IS, + WITH ALL FAULTS, & WITHOUT WARRANTY OF ANY KIND. CHIPONE DISCLAIMS ALL EXPRESS OR + IMPLIED WARRANTIES. + + File Name: icn85xx.h + Abstract: + input driver. +Author: Zhimin Tian +Date : 08,14,2013 +Version: 1.0 +History : + 2012,10,30, V0.1 first version + + --*/ + +#ifndef __LINUX_ICN85XX_H__ +#define __LINUX_ICN85XX_H__ + +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND + #include + #include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +//----------------------------------------------------------------------------- +// Pin Declarations +//----------------------------------------------------------------------------- + +#define SUPPORT_ALLWINNER_A13 0 +#define SUPPORT_ROCKCHIP 0 +#define SUPPORT_SPREADTRUM 0 + + + + +#if SUPPORT_ROCKCHIP +#include +#include +#include +#include +#include +#include + + +#define CTP_IRQ_MODE 0 + + + #define CTP_RST_PORT RK30_PIN2_PB1//RK30_PIN1_PB1 + #define CTP_IRQ_PORT RK30_PIN1_PA1 + + + +#define CTP_WAKEUP_PORT 0 +#define CTP_REPORT_PROTOCOL 1 //0: A protocol + //1: B protocol +#define SCREEN_MAX_X (600) +#define SCREEN_MAX_Y (1024) +//#define SCREEN_MAX_X (480) +//#define SCREEN_MAX_Y (800) +#define ICN85XX_I2C_SCL 400*1000 + +#endif + + +#include +#include +#include +#include +#define CTP_RST_PORT 4//RK30_PIN1_PB1 +#define CTP_IRQ_PORT 7 +#define CTP_REPORT_PROTOCOL 1 //0: A protocol +#define SCREEN_MAX_X (1024) +#define SCREEN_MAX_Y (600) +#define ICN85XX_IIC_ADDR (0x90>>1) + +//----------------------------------------------------------------------------- +// Global CONSTANTS +//----------------------------------------------------------------------------- +#define COL_NUM 24 +#define ROW_NUM 36 + +#define MD25D40_ID1 0x514013 +#define MD25D40_ID2 0xC84013 +#define MD25D20_ID1 0x514012 +#define MD25D20_ID2 0xC84012 +#define GD25Q10_ID 0xC84011 +#define MX25L512E_ID 0xC22010 + +#define ICN85XX_WITHOUT_FLASH 0x11 +#define ICN85XX_WITH_FLASH 0x22 + +#define FLASH_TOTAL_SIZE 0x00010000 +#define FLASH_PAGE_SIZE 0x1000 +#define FLASH_AHB_BASE_ADDR 0x00100000 +#define FLASH_PATCH_PARA_BASE_ADDR (FLASH_TOTAL_SIZE - FLASH_PAGE_SIZE) // allocate 1 page for patch para, 0xff00 +#define FLASH_CODE_INFO_BASE_ADDR (FLASH_PATCH_PARA_BASE_ADDR - FLASH_PAGE_SIZE) // 0xfe00,allocate 1 page for system para +#define FLASH_CRC_ADDR (FLASH_AHB_BASE_ADDR + FLASH_CODE_INFO_BASE_ADDR + 0x00) // 0xfe00 +#define FLASH_CODE_LENGTH_ADDR (FLASH_AHB_BASE_ADDR + FLASH_CODE_INFO_BASE_ADDR + 0x04) // 0xfe04 + + +//tp config +#define TOUCH_VIRTUAL_KEYS 0 +#define SUPPORT_PROC_FS 1 +#define SUPPORT_SYSFS 1 +#define COMPILE_FW_WITH_DRIVER 0 +#define FORCE_UPDATA_FW 0 +#define SUSPEND_POWER_OFF 1 +#define SUPPORT_SENSOR_ID 0 + +#define ICN85XX_NAME "icn85xx" +#define ICN85XX_PROG_IIC_ADDR (0x30) +#define CTP_NAME ICN85XX_NAME + +#define CTP_RESET_LOW_PERIOD (5) +#define CTP_RESET_HIGH_PERIOD (100) +#define CTP_WAKEUP_LOW_PERIOD (20) +#define CTP_WAKEUP_HIGH_PERIOD (50) +#define CTP_POLL_TIMER (16) /* ms delay between samples */ +#define CTP_START_TIMER (100) /* ms delay between samples */ + +#define POINT_NUM 5 +#define POINT_SIZE 7 + +#define TS_KEY_HOME 102 +#define TS_KEY_MENU 139 +#define TS_KEY_BACK 158 +#define TS_KEY_SEARCH 217 + +#define ICN_VIRTUAL_BUTTON_HOME 0x02 +#define ICN_VIRTUAL_BUTTON_MENU 0x01 +#define ICN_VIRTUAL_BUTTON_BACK 0x04 +#define ICN_VIRTUAL_BUTTON_SEARCH 0x08 + +#define IIC_RETRY_NUM 3 + +//ICN85xx_REG_PMODE +#define PMODE_ACTIVE 0x00 +#define PMODE_MONITOR 0x01 +#define PMODE_HIBERNATE 0x02 + +#define B_SIZE 32 +//#define ENABLE_BYTE_CHECK + +//----------------------------------------------------------------------------- +// Macro DEFINITIONS +//----------------------------------------------------------------------------- +#define DBG_ICN85xx_TRACE +//#define DBG_ICN85xx_POINT +//#define DBG_ICN85xx_INFO +#define DBG_ICN85xx_ERROR +//#define DBG_FLASH_INFO +#define DBG_FLASH_ERROR +#define DBG_OP_INFO +#define DBG_OP_ERROR +#define DBG_CALIB_INFO +#define DBG_CALIB_ERROR +//#define DBG_PROC_INFO +#define DBG_PROC_ERROR + + +#ifdef DBG_ICN85xx_TRACE +#define icn85xx_trace(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define icn85xx_trace(fmt, args...) // +#endif + + +#ifdef DBG_ICN85xx_POINT +#define icn85xx_point_info(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define icn85xx_point_info(fmt, args...) // +#endif + +#ifdef DBG_ICN85xx_INFO +#define icn85xx_info(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define icn85xx_info(fmt, args...) // +#endif + +#ifdef DBG_ICN85xx_ERROR +#define icn85xx_error(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define icn85xx_error(fmt, args...) // +#endif + +#ifdef DBG_FLASH_INFO +#define flash_info(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define flash_info(fmt, args...) // +#endif + +#ifdef DBG_FLASH_ERROR +#define flash_error(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define flash_error(fmt, args...) // +#endif + + +#ifdef DBG_OP_INFO +#define op_info(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define op_info(fmt, args...) // +#endif +#ifdef DBG_OP_ERROR +#define op_error(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define op_error(fmt, args...) // +#endif + + +#ifdef DBG_CALIB_INFO +#define calib_info(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define calib_info(fmt, args...) // +#endif + +#ifdef DBG_CALIB_ERROR +#define calib_error(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define calib_error(fmt, args...) // +#endif + + +#ifdef DBG_PROC_INFO +#define proc_info(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define proc_info(fmt, args...) // +#endif + +#ifdef DBG_PROC_ERROR +#define proc_error(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define proc_error(fmt, args...) // +#endif + +#define swap_ab(a,b) {char temp;temp=a;a=b;b=temp;} +#define U16LOBYTE(var) (*(unsigned char *) &var) +#define U16HIBYTE(var) (*(unsigned char *)((unsigned char *) &var + 1)) + +#define STRUCT_OFFSET(StructName,MemberName) ((int)(&(((StructName*)0)->MemberName))) + + +//----------------------------------------------------------------------------- +// Struct, Union and Enum DEFINITIONS +//----------------------------------------------------------------------------- +typedef struct _POINT_INFO +{ + unsigned char u8ID; + unsigned short u16PosX; // coordinate X, plus 4 LSBs for precision extension + unsigned short u16PosY; // coordinate Y, plus 4 LSBs for precision extension + unsigned char u8Pressure; + unsigned char u8EventId; +}POINT_INFO; + +struct icn85xx_ts_data { + struct i2c_client *client; + struct input_dev *input_dev; + struct work_struct pen_event_work; + struct workqueue_struct *ts_workqueue; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif + struct hrtimer timer; + spinlock_t irq_lock; + struct semaphore sem; + int ictype; + int code_loaded_flag; + POINT_INFO point_info[POINT_NUM+1]; + int point_num; + int irq; + int irq_is_disable; + int use_irq; + int work_mode; + int screen_max_x; + int screen_max_y; + int revert_x_flag; + int revert_y_flag; + int exchange_x_y_flag; +}; + +struct touch_param { + char fw_name[32]; + int irqgpio; + int rstgpio; + int panelres_x; + int panelres_y; + int xyswap; + int xdir; + int ydir; + int max_finger_num; + int force_download; + int earlysus_en; + int dbg; + int lcd_exchg; +}; + +#pragma pack(1) +typedef struct{ + unsigned char wr; //write read flag£¬0:R 1:W + unsigned char flag; //0: + unsigned char circle; //polling cycle + unsigned char times; //plling times + unsigned char retry; //I2C retry times + unsigned int data_len; //data length + unsigned char addr_len; //address length + unsigned char addr[2]; //address + unsigned char* data; //data pointer +}pack_head; + +typedef struct _STRUCT_PANEL_PARA +{ + unsigned short u16ResX; // Row of resolution + unsigned short u16ResY; // Col of resolution + + unsigned char u8RowNum; // Row total number (Tp + vk) + unsigned char u8ColNum; // Column total number (Tp + vk) + unsigned char u8TXOrder[36]; // TX Order, start from zero + unsigned char u8RXOrder[24]; // TX Order, start from zero + + unsigned char u8NumVKey; // Virtual Key setting + unsigned char u8VKeyMode; + unsigned char u8TpVkOrder[4]; + unsigned char u8VKDownThreshold; + unsigned char u8VKUpThreshold; + + unsigned char u8MaxTouchNum; // max touch support + + unsigned char u8ScanMode; // scan mode + unsigned short u16BitFreq; + unsigned short u16FreqCycleNum[2]; + unsigned char u8MultiDrvNum; + unsigned char u8WindowType; + + unsigned char u8FreHopMode; // freq hopping + unsigned short u16FreHopBitFreq[5]; // Bit Freq + unsigned short u16FreqHopCycleNum[5]; // Cycle Num + unsigned short u16FreHopThreshold; // Threshold of Freq Hop + + unsigned char u8ShiftNum; // rawdata level + unsigned char u8DrvOutPutR; + unsigned char u8PgaC; + unsigned char u8RxVcmi; + unsigned char u8DacGain; + unsigned char u8PgaGain; + unsigned char u8PgaR; + unsigned char u8SpaceHolder[200]; +}STRUCT_PANEL_PARA_H; + +#pragma pack() + +#define DATA_LENGTH_UINT 512 +#define CMD_HEAD_LENGTH (sizeof(pack_head) - sizeof(unsigned char *)) +#define ICN85xx_ENTRY_NAME "icn85xx_tool" + + +enum icn85xx_ts_regs { + ICN85xx_REG_PMODE = 0x04, /* Power Consume Mode */ +}; + +typedef enum +{ + R_OK = 100, + R_FILE_ERR, + R_STATE_ERR, + R_ERASE_ERR, + R_PROGRAM_ERR, + R_VERIFY_ERR, +}E_UPGRADE_ERR_TYPE; + +//----------------------------------------------------------------------------- +// Global VARIABLES +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// Function PROTOTYPES +//----------------------------------------------------------------------------- + +void icn85xx_ts_reset(void); +int icn85xx_i2c_rxdata(unsigned short addr, char *rxdata, int length); +int icn85xx_i2c_txdata(unsigned short addr, char *txdata, int length); +int icn85xx_write_reg(unsigned short addr, char para); +int icn85xx_read_reg(unsigned short addr, char *pdata); +int icn85xx_prog_i2c_rxdata(unsigned int addr, char *rxdata, int length); +int icn85xx_prog_i2c_txdata(unsigned int addr, char *txdata, int length); +int icn85xx_prog_write_reg(unsigned int addr, char para); +int icn85xx_prog_read_reg(unsigned int addr, char *pdata); + +int icn85xx_readVersion(void); +void icn85xx_rawdatadump(short *mem, int size, char br); +void icn85xx_set_fw(int size, unsigned char *buf); +void icn85xx_memdump(char *mem, int size); +int icn85xx_checksum(int sum, char *buf, unsigned int size); +int icn85xx_update_status(int status); +int icn85xx_get_status(void); +int icn85xx_open_fw( char *fw); +void icn85xx_free_fw(void); +int icn85xx_read_fw(int offset, int length, char *buf); +int icn85xx_close_fw(void); +int icn85xx_goto_progmode(void); +int icn85xx_check_progmod(void); +int icn85xx_read_flashid(void); +int icn85xx_erase_flash(void); +int icn85xx_prog_buffer(unsigned int flash_addr,unsigned int sram_addr,unsigned int copy_length,unsigned char program_type); +int icn85xx_prog_data(unsigned int flash_addr, unsigned int data); +void icn85xx_read_flash(unsigned int sram_address,unsigned int flash_address,unsigned long copy_length,unsigned char i2c_wire_num); +int icn85xx_fw_download(unsigned int offset, unsigned char * buffer, unsigned int size); +int icn85xx_bootfrom_flash(void); +int icn85xx_bootfrom_sram(void); +int icn85xx_crc_enable(unsigned char enable); +unsigned int icn85xx_crc_calc(unsigned crc_in, char *buf, int len); + +short icn85xx_read_fw_Ver(char *fw); +//E_UPGRADE_ERR_TYPE icn85xx_fw_update(char *fw); +int icn85xx_fw_update(void *arg); +#endif + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/icn85xx_ts/icn85xx_flash.c b/ANDROID_3.4.5/drivers/input/touchscreen/icn85xx_ts/icn85xx_flash.c new file mode 100755 index 00000000..a17cf176 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/icn85xx_ts/icn85xx_flash.c @@ -0,0 +1,1050 @@ +/*++ + + Copyright (c) 2012-2022 ChipOne Technology (Beijing) Co., Ltd. All Rights Reserved. + This PROPRIETARY SOFTWARE is the property of ChipOne Technology (Beijing) Co., Ltd. + and may contains trade secrets and/or other confidential information of ChipOne + Technology (Beijing) Co., Ltd. This file shall not be disclosed to any third party, + in whole or in part, without prior written consent of ChipOne. + THIS PROPRIETARY SOFTWARE & ANY RELATED DOCUMENTATION ARE PROVIDED AS IS, + WITH ALL FAULTS, & WITHOUT WARRANTY OF ANY KIND. CHIPONE DISCLAIMS ALL EXPRESS OR + IMPLIED WARRANTIES. + + File Name: icn85xx_flash.c + Abstract: + flash operation, read write etc. + Author: Zhimin Tian + Date : 08 14,2013 + Version: 0.1[.revision] + History : + Change logs. + --*/ +#include "icn85xx.h" + +unsigned char* firmdata = NULL; +int g_status = R_OK; +static char fw_mode = 0; +static int fw_size = 0; +static unsigned char *fw_buf; +static char boot_mode = ICN85XX_WITH_FLASH; +void icn85xx_rawdatadump(short *mem, int size, char br) +{ + int i; + for(i=0;idev))!=0) { + flash_error(KERN_ERR "cat't request firmware\n"); + return -1; + } + if (fw_entry->size <= 0) { + flash_error(KERN_ERR "load firmware error\n"); + release_firmware(fw_entry); + return -1; + } + + firmdata = kzalloc(fw_entry->size + 1, GFP_KERNEL); + memcpy(firmdata, fw_entry->data, fw_entry->size); + file_size = fw_entry->size; + release_firmware(fw_entry); + return file_size; +} + +void icn85xx_free_fw(void) +{ + if (firmdata) { + kfree(firmdata); + firmdata = NULL; + } +} + +/*********************************************************************************************** +Name : icn85xx_read_fw +Input : offset + length, read length + buf, return buffer +Output : +function : read data to buffer +***********************************************************************************************/ +int icn85xx_read_fw(int offset, int length, char *buf) +{ + if(fw_mode == 1) + { + memcpy(buf, fw_buf+offset, length); + } + else + { + memcpy(buf, firmdata + offset, length); + } +// icn85xx_memdump(buf, length); + return 0; +} + + +/*********************************************************************************************** +Name : icn85xx_close_fw +Input : +Output : +function : close file +***********************************************************************************************/ +int icn85xx_close_fw(void) +{ + if(fw_mode == 0) + { + //filp_close(fp, NULL); + } + + return 0; +} +/*********************************************************************************************** +Name : icn85xx_readVersion +Input : void +Output : +function : return version +***********************************************************************************************/ +int icn85xx_readVersion(void) +{ + int err = 0; + char tmp[2]; + short CurVersion; + err = icn85xx_i2c_rxdata(0x000c, tmp, 2); + if (err < 0) { + flash_error("%s failed: %d\n", __func__, err); + return 0; + } + CurVersion = (tmp[0]<<8) | tmp[1]; + return CurVersion; +} + + +/*********************************************************************************************** +Name : icn85xx_goto_progmode +Input : +Output : +function : change MCU to progmod +***********************************************************************************************/ +int icn85xx_goto_progmode(void) +{ + int ret = -1; + int retry = 3; + unsigned char ucTemp; + +// flash_info("icn85xx_goto_progmode\n"); + while(retry > 0) + { + ucTemp = 0x5a; + ret = icn85xx_prog_i2c_txdata(0xcc3355, &ucTemp,1); + mdelay(2); + ucTemp = 01; + ret = icn85xx_prog_i2c_txdata(0x040400, &ucTemp,1); + mdelay(2); + ret = icn85xx_check_progmod(); + if(ret == 0) + return ret; + + retry--; + mdelay(2); + } + printk("icn85xx_goto_progmode over\n"); + if(retry == 0) + return -1; + + return 0; +} + +/*********************************************************************************************** +Name : icn85xx_check_progmod +Input : +Output : +function : check if MCU at progmode or not +***********************************************************************************************/ +int icn85xx_check_progmod(void) +{ + int ret; + unsigned char ucTemp = 0x0; + ret = icn85xx_prog_i2c_rxdata(0x040002, &ucTemp, 1); +// flash_info("icn85xx_check_progmod: 0x%x\n", ucTemp); + if(ret < 0) + { + flash_error("icn85xx_check_progmod error, ret: %d\n", ret); + return ret; + } + if(ucTemp == 0x85) + return 0; + else + return -1; + +} + +unsigned char FlashState(unsigned char State_Index) +{ + unsigned char ucTemp[4] = {0,0,0,0}; + + ucTemp[2]=0x08; + ucTemp[1]=0x10; + ucTemp[0]=0x00; + icn85xx_prog_i2c_txdata(0x4062c,ucTemp,3); + + if(State_Index==0) + { + ucTemp[0]=0x05; + } + else if(State_Index==1) + { + ucTemp[0]=0x35; + } + icn85xx_prog_i2c_txdata(0x40630,ucTemp,1); + + ucTemp[1]=0x00; + ucTemp[0]=0x01; + icn85xx_prog_i2c_txdata(0x40640,ucTemp,2); + + ucTemp[0]=1; + icn85xx_prog_i2c_txdata(0x40644,ucTemp,1); + while(ucTemp[0]) + { + icn85xx_prog_i2c_rxdata(0x40644,ucTemp,1); + } + + icn85xx_prog_i2c_rxdata(0x40648,ucTemp,1); + return (unsigned char)(ucTemp[0]); +} + +int icn85xx_read_flashid(void) +{ + unsigned char ucTemp[4] = {0,0,0,0}; + int flashid=0; + + ucTemp[2]=0x08; + ucTemp[1]=0x10; + ucTemp[0]=0x00; + icn85xx_prog_i2c_txdata(0x4062c,ucTemp,3); + + ucTemp[0]=0x9f; + + icn85xx_prog_i2c_txdata(0x40630,ucTemp,1); + + ucTemp[1]=0x00; + ucTemp[0]=0x03; + icn85xx_prog_i2c_txdata(0x40640,ucTemp,2); + + ucTemp[0]=1; + icn85xx_prog_i2c_txdata(0x40644,ucTemp,1); + while(ucTemp[0]) + { + icn85xx_prog_i2c_rxdata(0x40644,ucTemp,1); + } + + icn85xx_prog_i2c_rxdata(0x40648,(char *)&flashid,4); + flashid=flashid&0x00ffffff; + + if((MD25D40_ID1 == flashid) || (MD25D40_ID2 == flashid) + ||(MD25D20_ID1 == flashid) || (MD25D20_ID1 == flashid) + ||(GD25Q10_ID == flashid) || (MX25L512E_ID == flashid)) + { + boot_mode = ICN85XX_WITH_FLASH; + //printk("ICN85XX_WITH_FLASH\n"); + } + else + { + boot_mode = ICN85XX_WITHOUT_FLASH; + //printk("ICN85XX_WITHOUT_FLASH\n"); + } + + printk("flashid: 0x%x\n", flashid); + return flashid; +} + + +void FlashWriteEnable(void) +{ + unsigned char ucTemp[4] = {0,0,0,0}; + + ucTemp[2]=0x00; + ucTemp[1]=0x10; + ucTemp[0]=0x00; + icn85xx_prog_i2c_txdata(0x4062c,ucTemp,3); + + ucTemp[0]=0x06; + icn85xx_prog_i2c_txdata(0x40630,ucTemp,1); + + ucTemp[0]=0x00; + ucTemp[1]=0x00; + icn85xx_prog_i2c_txdata(0x40640,ucTemp,2); + + ucTemp[0]=1; + icn85xx_prog_i2c_txdata(0x40644,ucTemp,1); + while(ucTemp[0]) + { + icn85xx_prog_i2c_rxdata(0x40644,ucTemp,1); + } + + ucTemp[0]=FlashState(0); + while( (ucTemp[0]&0x02)!=0x02) + { + ucTemp[0]=FlashState(0); + } +} + +#ifndef QUAD_OUTPUT_ENABLE +void ClearFlashState(void) +{ + unsigned char ucTemp[4] = {0,0,0,0}; + icn85xx_prog_i2c_rxdata(0x40603,ucTemp,1); + ucTemp[0]=(ucTemp[0]|0x20); + icn85xx_prog_i2c_txdata(0x40603, ucTemp, 1 ); + + FlashWriteEnable(); + ////////////////////////////write comd to flash + ucTemp[2]=0x00; + ucTemp[1]=0x10; + ucTemp[0]=0x10; + icn85xx_prog_i2c_txdata(0x4062c,ucTemp,3); + + ucTemp[0]=0x01; + icn85xx_prog_i2c_txdata(0x40630,ucTemp,1); + + ucTemp[0]=0x00; + ucTemp[1]=0x00; + icn85xx_prog_i2c_txdata(0x40640,ucTemp,2); + + ucTemp[0]=0x00; + icn85xx_prog_i2c_txdata(0x40638,ucTemp,1); + + ucTemp[0]=1; + icn85xx_prog_i2c_txdata(0x40644,ucTemp,1); + while(ucTemp[0]) + { + icn85xx_prog_i2c_rxdata(0x40644,ucTemp,1); + } + while(FlashState(0)&0x01); + +} +#else +void ClearFlashState(void) +{ +} +#endif + + +void EarseFlash(unsigned char erase_index,ulong flash_addr) +{ + unsigned char ucTemp[4] = {0,0,0,0}; + FlashWriteEnable(); + if(erase_index==0) //erase the chip + { + ucTemp[0]=0xc7; + icn85xx_prog_i2c_txdata(0x40630, ucTemp, 1 ); + ucTemp[2]=0x00; + ucTemp[1]=0x10; + ucTemp[0]=0x00; + icn85xx_prog_i2c_txdata(0x4062c, ucTemp, 3 ); + } + else if(erase_index==1) //erase 32k space of the flash + { + ucTemp[0]=0x52; + icn85xx_prog_i2c_txdata(0x40630, ucTemp, 1); + ucTemp[2]=0x00; + ucTemp[1]=0x13; + ucTemp[0]=0x00; + icn85xx_prog_i2c_txdata(0x4062c, ucTemp, 3); + } + else if(erase_index==2) //erase 64k space of the flash + { + ucTemp[0]=0xd8; + icn85xx_prog_i2c_txdata(0x40630, ucTemp,1); + ucTemp[2]=0x00; + ucTemp[1]=0x13; + ucTemp[0]=0x00; + icn85xx_prog_i2c_txdata(0x4062c, ucTemp, 3); + } + else if(erase_index==3) + { + ucTemp[0]=0x20; + icn85xx_prog_i2c_txdata(0x40630, ucTemp, 1); + ucTemp[2]=0x00; + ucTemp[1]=0x13; + ucTemp[0]=0x00; + icn85xx_prog_i2c_txdata(0x4062c, ucTemp, 3); + } + ucTemp[2]=(unsigned char)(flash_addr>>16); + ucTemp[1]=(unsigned char)(flash_addr>>8); + ucTemp[0]=(unsigned char)(flash_addr); + icn85xx_prog_i2c_txdata(0x40634, ucTemp, 3); + + ucTemp[1]=0x00; + ucTemp[0]=0x00; + icn85xx_prog_i2c_txdata(0x40640, ucTemp, 2 ); + + ucTemp[0]=1; + icn85xx_prog_i2c_txdata(0x40644, ucTemp, 1); + while(ucTemp[0]) + { + icn85xx_prog_i2c_rxdata(0x40644,ucTemp,1); + } + +} + +/*********************************************************************************************** +Name : icn85xx_erase_flash +Input : +Output : +function : erase flash +***********************************************************************************************/ +int icn85xx_erase_flash(void) +{ + ClearFlashState(); + while(FlashState(0)&0x01); + FlashWriteEnable(); + EarseFlash(1,0); + while((FlashState(0)&0x01)); + FlashWriteEnable(); + EarseFlash(3,0x8000); //?which block + while((FlashState(0)&0x01)); + FlashWriteEnable(); + EarseFlash(3,0x9000); + while((FlashState(0)&0x01)); + FlashWriteEnable(); + EarseFlash(3,0xe000); + while((FlashState(0)&0x01)); + return 0; +} + + +/*********************************************************************************************** +Name : icn85xx_prog_buffer +Input : +Output : +function : progm flash +***********************************************************************************************/ +int icn85xx_prog_buffer(unsigned int flash_addr,unsigned int sram_addr,unsigned int copy_length,unsigned char program_type) +{ + unsigned char ucTemp[4] = {0,0,0,0}; + unsigned char prog_state=0; + + unsigned int i=0; + unsigned char program_commond=0; + if(program_type == 0) + { + program_commond = 0x02; + } + else if(program_type == 1) + { + program_commond = 0xf2; + } + else + { + program_commond = 0x02; + } + + + for(i=0; i>16); + ucTemp[1]=(unsigned char)(flash_addr>>8); + ucTemp[0]=(unsigned char)(flash_addr); + icn85xx_prog_i2c_txdata(0x40634, ucTemp, 3); + + ucTemp[2]=(unsigned char)(sram_addr>>16); + ucTemp[1]=(unsigned char)(sram_addr>>8); + ucTemp[0]=(unsigned char)(sram_addr); + icn85xx_prog_i2c_txdata(0x4063c, ucTemp, 3); + + if(i+256<=copy_length) + { + ucTemp[1]=0x01; + ucTemp[0]=0x00; + } + else + { + ucTemp[1]=(unsigned char)((copy_length-i)>>8); + ucTemp[0]=(unsigned char)(copy_length-i); + } + icn85xx_prog_i2c_txdata(0x40640, ucTemp,2); + + ucTemp[0]=program_commond; + icn85xx_prog_i2c_txdata(0x40630, ucTemp,1); + + ucTemp[0]=0x01; + icn85xx_prog_i2c_txdata(0x40644, ucTemp,1); + + flash_addr+=256; + sram_addr+=256; + i+=256; + while(ucTemp[0]) + { + icn85xx_prog_i2c_rxdata(0x40644,ucTemp,1); + } + + } + + prog_state=(FlashState(0)&0x01); + while(prog_state) + { + prog_state=(FlashState(0)&0x01); + } + return 0; +} + +/*********************************************************************************************** +Name : icn85xx_prog_data +Input : +Output : +function : write int data to flash +***********************************************************************************************/ +int icn85xx_prog_data(unsigned int flash_addr, unsigned int data) +{ + unsigned char ucTemp[4] = {0,0,0,0}; + + ucTemp[3]=(unsigned char)(data>>24); + ucTemp[2]=(unsigned char)(data>>16); + ucTemp[1]=(unsigned char)(data>>8); + ucTemp[0]=(unsigned char)(data); + + icn85xx_prog_i2c_txdata(0x7f00, ucTemp,4); + icn85xx_prog_buffer(flash_addr , 0x7f00, 0x04, 0); + return 0; +} + +/*********************************************************************************************** +Name : icn85xx_read_flash +Input : +Output : +function : read data from flash to sram +***********************************************************************************************/ +void icn85xx_read_flash(unsigned int sram_address,unsigned int flash_address,unsigned long copy_length,unsigned char i2c_wire_num) +{ + unsigned char ucTemp[4] = {0,0,0,0}; + + if(i2c_wire_num==1) + { + ucTemp[2]=0x18; + ucTemp[1]=0x13; + ucTemp[0]=0x00; + } + else if(i2c_wire_num==2) + { + ucTemp[2]=0x1a; + ucTemp[1]=0x13; + ucTemp[0]=0x01; + } + else if(i2c_wire_num==4) + { + ucTemp[2]=0x19; + ucTemp[1]=0x13; + ucTemp[0]=0x01; + } + else + { + ucTemp[2]=0x18; + ucTemp[1]=0x13; + ucTemp[0]=0x01; + } + icn85xx_prog_i2c_txdata(0x4062c, ucTemp,3); + + if(i2c_wire_num==1) + { + ucTemp[0]=0x03; + } + else if(i2c_wire_num==2) + { + ucTemp[0]=0x3b; + } + else if(i2c_wire_num==4) + { + ucTemp[0]=0x6b; + } + else + { + ucTemp[0]=0x0b; + } + icn85xx_prog_i2c_txdata(0x40630, ucTemp,1); + + ucTemp[2]=(unsigned char)(flash_address>>16); + ucTemp[1]=(unsigned char)(flash_address>>8); + ucTemp[0]=(unsigned char)(flash_address); + icn85xx_prog_i2c_txdata(0x40634, ucTemp,3); + + ucTemp[2]=(unsigned char)(sram_address>>16); + ucTemp[1]=(unsigned char)(sram_address>>8); + ucTemp[0]=(unsigned char)(sram_address); + icn85xx_prog_i2c_txdata(0x4063c, ucTemp,3); + + ucTemp[1]=(unsigned char)(copy_length>>8); + ucTemp[0]=(unsigned char)(copy_length); + icn85xx_prog_i2c_txdata(0x40640, ucTemp,2); + + ucTemp[0]=0x01; + + icn85xx_prog_i2c_txdata(0x40644, ucTemp,1); + while(ucTemp[0]) + { + icn85xx_prog_i2c_rxdata(0x40644,ucTemp,1); + } + +} + +/*********************************************************************************************** +Name : icn85xx_read_fw_Ver +Input : fw +Output : +function : read fw version +***********************************************************************************************/ + +short icn85xx_read_fw_Ver(char *fw) +{ + short FWversion; + char tmp[2]; + int file_size; + file_size = icn85xx_open_fw(fw); + if(file_size < 0) + { + return -1; + } + icn85xx_read_fw(0x100, 2, &tmp[0]); + + icn85xx_close_fw(); + FWversion = (tmp[1]<<8)|tmp[0]; +// flash_info("FWversion: 0x%x\n", FWversion); + return FWversion; + + +} + +/*********************************************************************************************** +Name : icn85xx_fw_download +Input : +Output : +function : download code to sram +***********************************************************************************************/ +int icn85xx_fw_download(unsigned int offset, unsigned char * buffer, unsigned int size) +{ +#ifdef ENABLE_BYTE_CHECK + int i; + char testb[B_SIZE]; +#endif + + icn85xx_prog_i2c_txdata(offset,buffer,size); +#ifdef ENABLE_BYTE_CHECK + icn85xx_prog_i2c_rxdata(offset,testb,size); + for(i = 0; i < size; i++) + { + if(buffer[i] != testb[i]) + { + flash_error("buffer[%d]:%x testb[%d]:%x\n",i,buffer[i],i,testb[i]); + return -1; + } + } +#endif + return 0; +} + +/*********************************************************************************************** +Name : icn85xx_bootfrom_flash +Input : +Output : +function : +***********************************************************************************************/ +int icn85xx_bootfrom_flash(void) +{ + int ret = -1; + unsigned char ucTemp = 0x00; + flash_info("icn85xx_bootfrom_flash\n"); + + ucTemp=0x00; + ret = icn85xx_prog_i2c_txdata(0x40004, &ucTemp, 1 ); //nend flash sfcontrol clear + if (ret < 0) { + flash_error("%s failed: %d\n", __func__, ret); + return ret; + } + + return ret; +} + +/*********************************************************************************************** +Name : icn85xx_bootfrom_sram +Input : +Output : +function : +***********************************************************************************************/ +int icn85xx_bootfrom_sram(void) +{ + int ret = -1; + unsigned char ucTemp = 0x03; + unsigned long addr = 0x40400; + flash_info("icn85xx_bootfrom_sram\n"); + ret = icn85xx_prog_i2c_txdata(addr, &ucTemp, 1 ); //change bootmode from sram + return ret; +} +/*********************************************************************************************** +Name : icn85xx_crc_calc +Input : +Output : +function : +***********************************************************************************************/ +/* +unsigned int icn85xx_crc_calc(unsigned crc_in, char *buf, int len) +{ + int pos; + unsigned int crc_result; + unsigned char in_data_8b; + unsigned int crc_reg_32b; + unsigned char i; + unsigned char xor_flag; + + crc_result = crc_in; + for(pos=0;pos>= 1; + crc_reg_32b |= 0x80000000; + } + else + { + crc_reg_32b >>= 1; + } + } + + for(i=0; i<40; i++) + { + xor_flag = (crc_reg_32b>>31); + crc_reg_32b = (crc_reg_32b<<1) + (in_data_8b>>7); + in_data_8b = (in_data_8b<<1); + if(xor_flag) + { + crc_reg_32b = crc_reg_32b ^ 0x04C11DB7; + } + } + crc_result = crc_reg_32b; + } + return crc_result; +} +*/ + + +/* + This polynomial (0x04c11db7) is used at: AUTODIN II, Ethernet, & FDDI +*/ +static unsigned int crc32table[256] = { + 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, + 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, + 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, + 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, + 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, + 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, + 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, + 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, + 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, + 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, + 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, + 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, + 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, + 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, + 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, + 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, + 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, + 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, + 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, + 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, + 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, + 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, + 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, + 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, + 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, + 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, + 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9, + 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, + 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, + 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, + 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, + 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, + 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, + 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, + 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, + 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, + 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, + 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, + 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, + 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, + 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, + 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, + 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 +}; + +unsigned int icn85xx_crc_calc(unsigned crc_in, char *buf, int len) +{ + int i; + unsigned int crc = crc_in; + for(i = 0; i < len; i++) + crc = (crc << 8) ^ crc32table[((crc >> 24) ^ *buf++) & 0xFF]; + return crc; +} + + +/*********************************************************************************************** +Name : icn85xx_crc_enable +Input : +Output : +function :control crc control +***********************************************************************************************/ +int icn85xx_crc_enable(unsigned char enable) +{ + unsigned char ucTemp; + int ret = 0; + if(enable==1) + { + ucTemp = 1; + ret = icn85xx_prog_i2c_txdata(0x40028, &ucTemp, 1 ); + } + else if(enable==0) + { + ucTemp = 0; + ret = icn85xx_prog_i2c_txdata(0x40028, &ucTemp, 1 ); + } + return ret; +} +/*********************************************************************************************** +Name : icn85xx_crc_check +Input : +Output : +function :chec crc right or not +***********************************************************************************************/ +int icn85xx_crc_check(unsigned int crc, unsigned int len) +{ + int ret; + unsigned int crc_len; + unsigned int crc_result; + unsigned char ucTemp[4] = {0,0,0,0}; + + ret= icn85xx_prog_i2c_rxdata(0x4002c, ucTemp, 4 ); + crc_result = ucTemp[3]<<24 | ucTemp[2]<<16 | ucTemp[1] << 8 | ucTemp[0]; +// flash_info("crc_result: 0x%x\n", crc_result); + + ret = icn85xx_prog_i2c_rxdata(0x40034, ucTemp, 2); + crc_len = ucTemp[1] << 8 | ucTemp[0]; +// flash_info("crc_len: %d\n", crc_len); + + if((crc_result == crc) && (crc_len == len)) + return 0; + else + { + flash_info("crc_fw: 0x%x\n", crc); + flash_info("crc_result: 0x%x\n", crc_result); + flash_info("crc_len: %d\n", crc_len); + return -1; + } + +} + + +/*********************************************************************************************** +Name : icn85xx_fw_update +Input : fw +Output : +function : upgrade fw +***********************************************************************************************/ +int icn85xx_fw_update(void *arg) +{ + int file_size, last_length; + int j, num; + char temp_buf[B_SIZE]; + unsigned int crc_fw; + char *fw = (char *)arg; + + file_size = icn85xx_open_fw(fw); + if(file_size < 0) + { + icn85xx_update_status(R_FILE_ERR); + return R_FILE_ERR; + } + if(icn85xx_goto_progmode() != 0) + { + flash_error("icn85xx_goto_progmode() != 0 error\n"); + return R_STATE_ERR; + } + msleep(1); + icn85xx_crc_enable(1); + + num = file_size/B_SIZE; + crc_fw = 0; + for(j=0; j < num; j++) + { + icn85xx_read_fw(j*B_SIZE, B_SIZE, temp_buf); + crc_fw = icn85xx_crc_calc(crc_fw, temp_buf, B_SIZE); + if(icn85xx_fw_download(j*B_SIZE, temp_buf, B_SIZE) != 0) + { + flash_error("error j:%d\n",j); + icn85xx_update_status(R_PROGRAM_ERR); + icn85xx_close_fw(); + return R_PROGRAM_ERR; + } + icn85xx_update_status(5+(int)(60*j/num)); + } + last_length = file_size - B_SIZE*j; + if(last_length > 0) + { + icn85xx_read_fw(j*B_SIZE, last_length, temp_buf); + crc_fw = icn85xx_crc_calc(crc_fw, temp_buf, last_length); + if(icn85xx_fw_download(j*B_SIZE, temp_buf, last_length) != 0) + { + flash_error("error last length\n"); + icn85xx_update_status(R_PROGRAM_ERR); + icn85xx_close_fw(); + return R_PROGRAM_ERR; + } + } + icn85xx_close_fw(); + icn85xx_update_status(65); +// flash_info("crc_fw: 0x%x\n", crc_fw); +// msleep(1); + icn85xx_crc_enable(0); + if(icn85xx_crc_check(crc_fw, file_size) != 0) + { + flash_info("down fw error, crc error\n"); + return R_PROGRAM_ERR; + } + else + { + //flash_info("downoad fw ok, crc ok\n"); + } + icn85xx_update_status(70); + + if(ICN85XX_WITH_FLASH == boot_mode) + { + icn85xx_erase_flash(); + // return R_PROGRAM_ERR; + icn85xx_update_status(75); + + FlashWriteEnable(); + + icn85xx_prog_buffer( 0, 0, file_size,0); + + icn85xx_update_status(85); + + while((FlashState(0)&0x01)); + FlashWriteEnable(); + + icn85xx_prog_data(FLASH_CRC_ADDR, crc_fw); + icn85xx_prog_data(FLASH_CRC_ADDR+4, file_size); + + icn85xx_update_status(90); + + + icn85xx_crc_enable(1); + icn85xx_read_flash( 0, 0, file_size, 2); + icn85xx_crc_enable(0); + if(icn85xx_crc_check(crc_fw, file_size) != 0) + { + flash_info("read flash data error, crc error\n"); + return R_PROGRAM_ERR; + } + else + { + flash_info("read flash data ok, crc ok\n"); + } + while((FlashState(0)&0x01)); + icn85xx_update_status(95); + + //if(icn85xx_bootfrom_flash() == 0) + if(icn85xx_bootfrom_sram() == 0) //code already in ram + { + flash_error("icn85xx_bootfrom_flash error\n"); + icn85xx_update_status(R_STATE_ERR); + return R_STATE_ERR; + } + } + else if(ICN85XX_WITHOUT_FLASH == boot_mode) + { + if(icn85xx_bootfrom_sram() == 0) + { + flash_error("icn85xx_bootfrom_sram error\n"); + icn85xx_update_status(R_STATE_ERR); + return R_STATE_ERR; + } + } + msleep(50); + icn85xx_update_status(R_OK); + flash_info("icn85xx upgrade ok\n"); + return R_OK; +} diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/icn85xx_ts/icn85xx_fw.h b/ANDROID_3.4.5/drivers/input/touchscreen/icn85xx_ts/icn85xx_fw.h new file mode 100755 index 00000000..757408c2 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/icn85xx_ts/icn85xx_fw.h @@ -0,0 +1,2517 @@ +const unsigned char icn85xx_fw[40235] = { + 0xb0,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00, + 0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00, + 0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00, + 0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00, + 0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00, + 0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00, + 0x36,0x16,0x00,0x00,0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00, + 0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00, + 0xda,0x15,0x00,0x00,0xf0,0x13,0x00,0x00,0x6e,0x13,0x00,0x00,0xc4,0x14,0x00,0x00, + 0xfc,0x13,0x00,0x00,0xb8,0x12,0x00,0x00,0x98,0x11,0x00,0x00,0x96,0x10,0x00,0x00, + 0xfc,0x14,0x00,0x00,0xd0,0x14,0x00,0x00,0x82,0x15,0x00,0x00,0x28,0x15,0x00,0x00, + 0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,0x38,0x16,0x00,0x00,0x3a,0x16,0x00,0x00, + 0x3e,0x16,0x00,0x00,0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00, + 0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00, + 0x3c,0x16,0x00,0x00,0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00, + 0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,0x40,0x16,0x00,0x00,0x56,0x16,0x00,0x00, + 0x00,0x27,0x00,0x00,0x22,0x00,0x00,0x00,0x01,0x00,0x05,0x00,0x08,0x00,0x0c,0x00, + 0x0f,0x00,0x13,0x00,0x17,0x00,0x1a,0x00,0x1e,0x00,0x22,0x00,0x26,0x00,0x2a,0x00, + 0x2e,0x00,0x32,0x00,0x37,0x00,0x3c,0x00,0x40,0x00,0x46,0x00,0x4b,0x00,0x50,0x00, + 0x56,0x00,0x5d,0x00,0x63,0x00,0x6b,0x00,0x73,0x00,0x7b,0x00,0x84,0x00,0x8e,0x00, + 0x99,0x00,0xa6,0x00,0xb4,0x00,0xc4,0x00,0xd6,0x00,0xeb,0x00,0x04,0x01,0x22,0x01, + 0x47,0x01,0x75,0x01,0xb1,0x01,0x02,0x02,0x77,0x02,0x2e,0x03,0x77,0x04,0x74,0x07, + 0x60,0x16,0x00,0x00,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7e,0x7e,0x7e,0x7e, + 0x7e,0x7d,0x7d,0x7d,0x7d,0x7c,0x7c,0x7c,0x7b,0x7b,0x7a,0x7a,0x79,0x79,0x78,0x78, + 0x77,0x77,0x76,0x76,0x75,0x75,0x74,0x73,0x73,0x72,0x71,0x71,0x70,0x6f,0x6e,0x6d, + 0x6d,0x6c,0x6b,0x6a,0x69,0x68,0x67,0x67,0x66,0x65,0x64,0x63,0x62,0x61,0x60,0x5f, + 0x5e,0x5d,0x5b,0x5a,0x59,0x58,0x57,0x56,0x55,0x53,0x52,0x51,0x50,0x4f,0x4d,0x4c, + 0x4b,0x4a,0x48,0x47,0x46,0x44,0x43,0x42,0x40,0x3f,0x3e,0x3c,0x3b,0x3a,0x38,0x37, + 0x35,0x34,0x32,0x31,0x30,0x2e,0x2d,0x2b,0x2a,0x28,0x27,0x25,0x24,0x22,0x21,0x1f, + 0x1e,0x1c,0x1b,0x19,0x17,0x16,0x14,0x13,0x11,0x10,0x0e,0x0d,0x0b,0x09,0x08,0x06, + 0x05,0x03,0x02,0x00,0xaa,0xa5,0x55,0x5a,0x5a,0xa5,0x66,0x6a,0x58,0x02,0x00,0x04, + 0x10,0x0a,0x1f,0x1d,0x1b,0x19,0x17,0x15,0x13,0x12,0x0f,0x0d,0x0b,0x09,0x07,0x05, + 0x03,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x16,0x14,0x0e,0x0c,0x0a,0x08,0x06,0x04,0x02,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, + 0x16,0x00,0x00,0x00,0x1e,0x14,0x05,0x01,0xa0,0x0f,0x28,0x00,0x96,0x00,0x09,0x01, + 0x00,0x34,0x21,0x40,0x1f,0x58,0x1b,0xa8,0x16,0x88,0x13,0x3a,0x00,0x32,0x00,0x2d, + 0x00,0x2a,0x00,0x14,0x00,0x58,0x02,0x03,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x14, + 0x28,0x3c,0x50,0xc8,0x00,0x03,0x01,0x00,0x01,0x01,0x10,0x01,0x14,0x00,0x28,0x00, + 0x58,0x02,0x00,0xea,0x00,0x01,0x06,0x1e,0x0a,0x00,0x10,0x27,0x00,0x00,0x00,0x80, + 0x01,0x50,0x50,0x50,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x02, + 0x00,0x02,0x01,0x00,0x02,0x80,0x01,0x06,0x00,0x02,0x00,0x01,0x01,0x0a,0x10,0x20, + 0x03,0xc4,0xff,0x3c,0x00,0x64,0x01,0x01,0x01,0x00,0x1e,0x00,0x64,0x01,0x00,0x01, + 0x00,0x00,0x64,0x0a,0x00,0x01,0x14,0x01,0x07,0x00,0xd0,0x07,0x14,0x14,0x14,0x14, + 0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14, + 0x14,0x14,0x14,0x14,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, + 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, + 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x32,0x00,0x05,0x01,0x00,0x00,0x01,0x03, + 0x05,0x07,0x46,0x46,0x0f,0x01,0x00,0x00,0x01,0x32,0xe8,0x03,0x00,0x03,0x00,0x00, + 0x00,0x40,0x00,0x20,0x00,0x20,0x00,0xe0,0x00,0xe0,0x00,0x00,0x00,0xf0,0x00,0xf0, + 0x00,0xf0,0x00,0x10,0x00,0x00,0x00,0xe0,0x00,0x00,0x00,0x00,0x00,0xe0,0x00,0xe8, + 0x00,0xf8,0x00,0x08,0x00,0xf8,0x00,0x08,0x00,0xf8,0x00,0xf0,0x00,0xf0,0x00,0x00, + 0x00,0x00,0x00,0xf0,0x00,0x00,0x00,0xf0,0xab,0xfa,0x00,0xf0,0xab,0xfa,0x55,0x05, + 0x55,0x05,0x00,0xf0,0x55,0x05,0xab,0xfa,0xd8,0xf0,0x94,0xf7,0x36,0xf4,0xe5,0xf5, + 0x0d,0x05,0x79,0xed,0x43,0xf9,0x5e,0x03,0x51,0xfe,0x74,0xf9,0x2f,0xf2,0x46,0xff, + 0xe9,0xfa,0x5d,0xfc,0x8c,0x06,0xd1,0xed,0xba,0x00,0x17,0x05,0xa3,0x03,0xde,0xf4, + 0x37,0xfd,0x4d,0xef,0xd3,0xfb,0xf4,0x06,0xbd,0xe9,0x6f,0xfa,0x9b,0xfe,0xa6,0xf7, + 0xe9,0x0d,0x7a,0xf3,0x9a,0xf9,0x33,0xf7,0x66,0xfa,0xcd,0xf4,0x9a,0x05,0x33,0xf7, + 0x66,0x06,0xcd,0x00,0x9a,0xfd,0x33,0xfb,0x66,0x02,0xcd,0x00,0x55,0xf5,0x55,0xf5, + 0x55,0xf5,0x55,0xf5,0x00,0x00,0xff,0xff,0x55,0xf5,0x00,0x00,0x00,0x00,0x00,0x00, + 0x55,0xf5,0x00,0x00,0x00,0x00,0x2a,0x05,0x81,0xfa,0x9e,0xf8,0x66,0xf8,0x97,0xf8, + 0xb7,0x03,0xe6,0xf9,0x8f,0x02,0x27,0xf7,0x74,0xfd,0x30,0x03,0xe4,0x01,0x64,0xfd, + 0x7b,0xff,0x00,0xf8,0x00,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0x00,0x00, + 0x00,0x00,0x00,0xf8,0x00,0xf8,0x00,0x00,0x00,0xf8,0x00,0x00,0x00,0xf8,0x00,0xf8, + 0x51,0x01,0xad,0xfc,0xaa,0xf9,0x2b,0xfb,0x6a,0xfa,0xcb,0xfa,0xf0,0xff,0xb3,0x02, + 0xa7,0xf6,0xad,0xfc,0x54,0x04,0x2b,0xfb,0x15,0x05,0xcb,0xfa,0xf0,0xff,0xb3,0x02, + 0x00,0x00,0x00,0xf8,0x00,0xf8,0x00,0x00,0x00,0xf8,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0xf8,0x00,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0x00,0x00,0x00,0xf8, + 0x00,0xf8,0x5b,0xff,0xf2,0xfa,0xbb,0xfb,0x07,0xf8,0x31,0xf9,0xc4,0x01,0x90,0xfa, + 0x59,0xfa,0x20,0x00,0xd1,0x02,0xcf,0xfb,0xf3,0x03,0x15,0xfe,0xb5,0x02,0x25,0xfc, + 0x28,0xfd,0xff,0x02,0x4a,0x02,0x9a,0xf9,0x9a,0xf9,0x00,0x00,0x9a,0xf9,0x00,0x00, + 0x9a,0xf9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x9a,0xf9,0x9a,0xf9,0x00,0x00, + 0x9a,0xf9,0x9a,0xf9,0x00,0x00,0x00,0x00,0x9a,0xf9,0x9a,0xf9,0x13,0xfe,0x0f,0xfc, + 0xd8,0xfa,0x7b,0xfb,0xb4,0xfc,0x50,0x02,0x2b,0xfb,0x14,0x02,0xc4,0xf9,0xf4,0x01, + 0x89,0x03,0x34,0x00,0xa9,0x00,0x41,0xfa,0x08,0xfd,0xe5,0x01,0xee,0xfc,0xb0,0xf9, + 0xf4,0x01,0x68,0x01,0x01,0x01,0x01,0xff,0xff,0x01,0xff,0xff,0xff,0x01,0xff,0xff, + 0x01,0x01,0xff,0xff,0xff,0x01,0xff,0x01,0xff,0xff,0xff,0x01,0x01,0xff,0x01,0xff, + 0xff,0xff,0xff,0x01,0x01,0xff,0x01,0xff,0xff,0xff,0xff,0xff,0x01,0xff,0x01,0x01, + 0x01,0xff,0xff,0xff,0xff,0xff,0x01,0xff,0x01,0x01,0x01,0x01,0xff,0xff,0xff,0x01, + 0xff,0xff,0x01,0x01,0x01,0xff,0xff,0xff,0xff,0xff,0x01,0xff,0x01,0x01,0xff,0xff, + 0x01,0x01,0xff,0xff,0xff,0xff,0x01,0x01,0xff,0x01,0xff,0x01,0xff,0x01,0x01,0x01, + 0xff,0xff,0xff,0xff,0x01,0xff,0x01,0xff,0xff,0x01,0x01,0xff,0x01,0xff,0xff,0x01, + 0x01,0x01,0xff,0x01,0x01,0xff,0xff,0x01,0xff,0x01,0xff,0xff,0x01,0xff,0xff,0xff, + 0xff,0xff,0x01,0x01,0xff,0xff,0x01,0xff,0x01,0xff,0x01,0x01,0xff,0xff,0xff,0x01, + 0xff,0x01,0x01,0x01,0xff,0xff,0x01,0x01,0x01,0xff,0x01,0xff,0xff,0x01,0xff,0xff, + 0xff,0xff,0x01,0xff,0xff,0x01,0x01,0xff,0x01,0xff,0x01,0xff,0xff,0x01,0x01,0xff, + 0xff,0x01,0xff,0x01,0xff,0x01,0x01,0x01,0x01,0xff,0xff,0x01,0xff,0xff,0x01,0x01, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0xff,0x01,0xff,0x01,0x01,0x01,0x01,0xff, + 0xff,0x01,0xff,0xff,0x01,0x01,0x00,0x00,0x01,0x02,0x04,0x08,0x00,0x01,0x02,0x02, + 0x03,0x03,0x03,0x03,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x05,0x05,0x05,0x05, + 0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x06,0x06,0x06,0x06, + 0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06, + 0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x07,0x07,0x07,0x07, + 0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, + 0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, + 0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, + 0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x08,0x08,0x08,0x08, + 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08, + 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08, + 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08, + 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08, + 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08, + 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08, + 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08, + 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x45,0x6e,0x74,0x65, + 0x72,0x20,0x44,0x75,0x6d,0x6d,0x79,0x20,0x45,0x78,0x63,0x65,0x70,0x74,0x69,0x6f, + 0x6e,0x20,0x48,0x61,0x6e,0x64,0x6c,0x65,0x72,0x21,0x20,0x00,0x6d,0x65,0x6d,0x6f, + 0x72,0x79,0x20,0x64,0x75,0x6d,0x70,0x3a,0x25,0x78,0x2c,0x25,0x64,0x0a,0x00,0x00, + 0x0a,0x00,0x00,0x00,0x25,0x78,0x20,0x00,0x25,0x32,0x64,0x3a,0x25,0x34,0x64,0x2c, + 0x25,0x34,0x64,0x2c,0x25,0x32,0x64,0x2c,0x25,0x32,0x64,0x7c,0x00,0x00,0x00,0x00, + 0x0a,0x00,0x00,0x00,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x41,0x42, + 0x43,0x44,0x45,0x46,0x00,0x00,0x00,0x00,0x41,0x64,0x64,0x72,0x3a,0x30,0x78,0x25, + 0x78,0x0a,0x00,0x00,0x25,0x35,0x64,0x2c,0x00,0x00,0x00,0x00,0x0a,0x00,0x00,0x00, + 0x52,0x61,0x77,0x3a,0x54,0x78,0x3a,0x25,0x32,0x64,0x2c,0x52,0x78,0x3a,0x25,0x32, + 0x64,0x0a,0x00,0x00,0x42,0x61,0x73,0x65,0x3a,0x54,0x78,0x3a,0x25,0x32,0x64,0x2c, + 0x52,0x78,0x3a,0x25,0x32,0x64,0x0a,0x00,0x62,0x65,0x66,0x6f,0x72,0x65,0x20,0x64, + 0x63,0x0a,0x00,0x00,0x44,0x69,0x66,0x3a,0x54,0x78,0x3a,0x25,0x32,0x64,0x2c,0x52, + 0x78,0x3a,0x25,0x32,0x64,0x0a,0x00,0x00,0x61,0x66,0x74,0x65,0x72,0x20,0x64,0x63, + 0x66,0x69,0x6c,0x74,0x65,0x72,0x0a,0x00,0x54,0x6f,0x74,0x61,0x6c,0x20,0x4e,0x75, + 0x6d,0x3a,0x25,0x32,0x64,0x0a,0x00,0x00,0x30,0x78,0x25,0x34,0x78,0x2c,0x30,0x78, + 0x25,0x34,0x78,0x2c,0x25,0x64,0x2c,0x25,0x64,0x7c,0x00,0x00,0x75,0x38,0x50,0x6c, + 0x61,0x6d,0x53,0x75,0x6d,0x3a,0x25,0x64,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xb0,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x0a,0x71,0x10,0x12,0x02,0x60,0x03,0x60,0x01,0x60,0x04,0x60,0x05,0x60,0x06,0x60, + 0x07,0x60,0x08,0x60,0x09,0x60,0x0a,0x60,0x0b,0x60,0x0c,0x60,0x0d,0x60,0x0e,0x60, + 0x0f,0x60,0x02,0x7f,0x03,0x7f,0xff,0xf7,0xfc,0xaf,0x00,0x00,0xf2,0x07,0x00,0x00, + 0xec,0x88,0x00,0x00,0x70,0x24,0x00,0x9f,0x0d,0x72,0x0d,0x7f,0x00,0x8f,0x70,0x20, + 0xcf,0x00,0x70,0x24,0x00,0x9f,0x0b,0x77,0x0c,0x73,0x37,0x0f,0x04,0xe8,0x72,0x12, + 0x0b,0x74,0x74,0x05,0x0b,0x7f,0x0b,0x74,0x0c,0x77,0x74,0x0f,0x04,0xe8,0x72,0x12, + 0x03,0x60,0x74,0x05,0x0a,0x7f,0x00,0x8f,0x70,0x20,0xcf,0x00,0x8c,0x06,0x00,0x00, + 0x7a,0x25,0x00,0x00,0x00,0x9e,0x00,0x00,0x60,0x89,0x00,0x00,0x04,0x9e,0x00,0x00, + 0x8c,0x82,0x00,0x00,0x52,0xaa,0x00,0x00,0x10,0x9e,0x00,0x00,0x22,0x83,0x00,0x00, + 0x70,0x24,0x00,0x9f,0x12,0x60,0x69,0x7f,0x6a,0x77,0x07,0xa7,0x07,0x2a,0x29,0xe0, + 0x69,0x76,0x06,0x84,0x69,0x76,0x06,0x83,0x69,0x75,0x05,0x86,0xc6,0x30,0xd6,0x30, + 0x05,0x96,0x67,0x75,0x68,0x76,0x06,0x95,0x36,0x60,0x67,0x75,0x05,0xb6,0x67,0x75, + 0x05,0x97,0x67,0x75,0x05,0x97,0x35,0x12,0x65,0x01,0x66,0x77,0x07,0xd5,0x66,0x77, + 0x07,0xb6,0x66,0x77,0x07,0x94,0x16,0x60,0x66,0x77,0x07,0xb6,0x66,0x77,0x07,0xb6, + 0x76,0x12,0x06,0xa7,0x07,0x2a,0xfd,0xe7,0x62,0x76,0x06,0xb7,0x36,0x60,0x54,0x77, + 0x07,0xb6,0x00,0x8f,0x70,0x20,0xcf,0x00,0xcf,0x00,0x46,0x60,0x5f,0x77,0x07,0x96, + 0x26,0x60,0x5e,0x77,0x07,0xb6,0xcf,0x00,0x70,0x24,0x00,0x9f,0x23,0x12,0x43,0x01, + 0x5c,0x77,0x07,0xa7,0x07,0x2a,0x0e,0xe0,0x03,0x2a,0x5a,0x77,0x05,0xe8,0x07,0xa3, + 0x32,0x60,0x03,0x2a,0x05,0xe0,0x05,0xf0,0x07,0xa7,0x32,0x60,0x07,0x2a,0x01,0xe0, + 0x13,0x60,0x55,0x7f,0x00,0x8f,0x70,0x20,0xcf,0x00,0x54,0x76,0x06,0x87,0x07,0x34, + 0x17,0x34,0x06,0x97,0x53,0x76,0x06,0x87,0xe7,0x35,0x06,0x97,0xcf,0x00,0x4f,0x76, + 0x06,0x87,0x07,0x30,0x17,0x30,0x06,0x97,0x4e,0x76,0x06,0x87,0xe7,0x31,0x06,0x97, + 0xcf,0x00,0x70,0x24,0x00,0x9f,0x4b,0x77,0x07,0xa2,0x4b,0x77,0x72,0x03,0x4b,0x73, + 0x4c,0x7f,0x4c,0x77,0x07,0x92,0x00,0x8f,0x70,0x20,0xcf,0x00,0x70,0x24,0x00,0x9f, + 0x23,0x12,0x43,0x01,0x36,0x12,0x36,0x25,0x46,0x01,0x47,0x77,0x67,0x0c,0x01,0xe0, + 0x03,0x65,0x42,0x72,0x46,0x7f,0x40,0x77,0x72,0x03,0x40,0x73,0x41,0x7f,0x44,0x77, + 0x07,0x92,0x00,0x8f,0x70,0x20,0xcf,0x00,0x43,0x76,0x06,0x87,0x07,0x34,0x17,0x34, + 0x06,0x97,0x37,0x76,0x06,0x87,0x40,0x75,0x57,0x1e,0x06,0x97,0x16,0x60,0x3f,0x77, + 0x37,0xb6,0xcf,0x00,0x3c,0x76,0x06,0x87,0x07,0x30,0x17,0x30,0x06,0x97,0x30,0x76, + 0x06,0x87,0xf7,0x31,0x06,0x97,0xcf,0x00,0x70,0x24,0x00,0x9f,0x39,0x77,0x07,0xa2, + 0x39,0x7f,0x00,0x8f,0x70,0x20,0xcf,0x00,0x70,0x24,0x00,0x9f,0x02,0x60,0x36,0x7f, + 0x32,0x60,0x36,0x7f,0x32,0x60,0x13,0x60,0x36,0x7f,0x02,0x60,0x36,0x7f,0x36,0x7f, + 0x37,0x7f,0x37,0x7f,0x06,0x60,0x37,0x77,0x07,0xd6,0x37,0x7f,0x38,0x7f,0x00,0x8f, + 0x70,0x20,0xcf,0x00,0x03,0x01,0x07,0x60,0x02,0xf0,0x06,0xb1,0x07,0x20,0x26,0x12, + 0x76,0x1c,0x47,0x0f,0xfa,0xe7,0xcf,0x00,0x63,0x01,0x07,0x60,0x03,0xf0,0x02,0xd3, + 0x07,0x20,0x12,0x20,0x47,0x0f,0xfb,0xe7,0xcf,0x00,0x00,0x00,0xbc,0x1d,0x00,0x00, + 0x00,0x04,0x04,0x00,0x00,0xe0,0x10,0x00,0x04,0xe0,0x10,0x00,0x00,0x06,0x04,0x00, + 0x00,0x13,0x18,0x00,0x2c,0x06,0x04,0x00,0x30,0x06,0x04,0x00,0x34,0x06,0x04,0x00, + 0x3c,0x06,0x04,0x00,0x40,0x06,0x04,0x00,0x2a,0x00,0x04,0x00,0x30,0x00,0x04,0x00, + 0x28,0x00,0x04,0x00,0x44,0x06,0x04,0x00,0x0c,0x00,0x04,0x00,0x60,0x01,0x04,0x00, + 0x3b,0xaa,0x00,0x00,0xc2,0x9c,0x00,0x00,0x0c,0x21,0x00,0x00,0x00,0x02,0x04,0x00, + 0x10,0x00,0x00,0xe0,0xc3,0x9c,0x00,0x00,0x80,0xc3,0xc9,0x01,0xe8,0x03,0x00,0x00, + 0xd0,0x83,0x00,0x00,0x04,0x02,0x04,0x00,0xb4,0x00,0x00,0x00,0x3e,0x84,0x00,0x00, + 0x14,0x02,0x04,0x00,0x10,0x02,0x04,0x00,0x00,0x00,0x00,0x80,0xb0,0xa8,0x00,0x00, + 0xc6,0x9c,0x00,0x00,0x2c,0x09,0x00,0x00,0xa8,0x20,0x00,0x00,0xc2,0x20,0x00,0x00, + 0xec,0x20,0x00,0x00,0xb8,0x08,0x00,0x00,0x2c,0x10,0x00,0x00,0x12,0x09,0x00,0x00, + 0x88,0x09,0x00,0x00,0x10,0x9e,0x00,0x00,0x34,0x16,0x00,0x00,0x7e,0x23,0x00,0x00, + 0x70,0x25,0x7a,0x00,0x2c,0x12,0x3b,0x12,0x4a,0x12,0x4a,0x01,0x6e,0x72,0xc3,0x12, + 0xb4,0x12,0x6d,0x7f,0x0d,0x60,0x0b,0xf0,0xd2,0x12,0xa3,0x12,0x6c,0x7f,0x02,0x2a, + 0x02,0xe0,0x6b,0x72,0x69,0x7f,0x6b,0x72,0x0e,0xa3,0x67,0x7f,0x0d,0x20,0xce,0x12, + 0xde,0x1c,0xbd,0x0f,0xf1,0xe7,0x66,0x72,0x64,0x7f,0x6a,0x00,0x70,0x21,0xcf,0x00, + 0x07,0x60,0x02,0xf0,0x00,0x12,0x07,0x20,0x27,0x0f,0xfc,0xe7,0xcf,0x00,0xf0,0x25, + 0x78,0x00,0x70,0x24,0x61,0x77,0x07,0xa6,0x61,0x75,0x55,0xa7,0x06,0x2a,0x05,0xe0, + 0x07,0x2a,0x4a,0xe8,0x55,0xb6,0x55,0xa7,0x47,0xf0,0x07,0x2a,0x16,0xe0,0x5c,0x75, + 0x05,0xa7,0x07,0x2a,0x5c,0x77,0x0f,0xe0,0x25,0xa5,0x05,0x2a,0x0c,0xe0,0x07,0xc5, + 0x05,0x20,0x65,0x01,0x07,0xd5,0x35,0x3e,0x56,0x0c,0x36,0xe0,0x17,0x60,0x53,0x76, + 0x56,0xb7,0x56,0xa7,0x31,0xf0,0x06,0x60,0x2e,0xf0,0x50,0x75,0x55,0xa7,0x17,0x2a, + 0x0e,0xe0,0x4f,0x77,0x07,0xa6,0x06,0x2a,0x03,0xe0,0x27,0xa7,0x07,0x2a,0x24,0xe8, + 0x06,0x60,0x4c,0x77,0x07,0xd6,0x49,0x77,0x57,0xb6,0x57,0xa7,0x1d,0xf0,0x47,0x76, + 0x56,0xa7,0x27,0x2a,0x19,0xe0,0x48,0x7e,0x0e,0xca,0x48,0x7d,0x0d,0xc9,0x48,0x7c, + 0x0c,0xc8,0x48,0x7b,0x0b,0xc7,0x00,0x97,0x02,0x60,0x47,0x7f,0x42,0x66,0x47,0x7f, + 0x0e,0xda,0x0d,0xd9,0x0c,0xd8,0x00,0x85,0x0b,0xd5,0x45,0x7f,0x07,0x60,0x3b,0x76, + 0x56,0xb7,0x06,0x60,0x3c,0x77,0x07,0xd6,0x70,0x20,0x68,0x00,0xf0,0x21,0xcf,0x00, + 0xe2,0x01,0x95,0x2c,0x52,0x16,0x3f,0x77,0x27,0x0c,0x3f,0x77,0x07,0xe0,0x72,0x14, + 0x97,0x32,0x72,0x1c,0x02,0xa2,0xf5,0x67,0x52,0x1c,0x17,0xf0,0x86,0x2c,0x26,0x0c, + 0x07,0xe0,0x72,0x1c,0x3a,0x77,0x72,0x1c,0x02,0xa7,0xf2,0x67,0x72,0x05,0x0d,0xf0, + 0xf6,0x67,0x26,0x0c,0x06,0xe0,0x27,0x05,0x85,0x32,0x57,0x1c,0x07,0xa2,0x62,0x14, + 0x04,0xf0,0x72,0x1c,0x02,0xa2,0xf7,0x67,0x72,0x1c,0x42,0x01,0xcf,0x00,0xf0,0x24, + 0x7d,0x00,0x2d,0x12,0x6d,0x01,0x63,0x01,0x0d,0x2a,0x3e,0x12,0x7e,0x01,0x26,0xe8, + 0xe7,0x12,0xe7,0x1c,0xe7,0x1c,0x72,0x12,0x52,0x3c,0x72,0x1c,0x7d,0x01,0xe2,0x1c, + 0xd3,0x12,0x27,0x7f,0x25,0x12,0xe5,0x01,0x27,0x77,0x02,0x60,0xd6,0x62,0x07,0xc4, + 0x45,0x0d,0x05,0xe0,0x02,0x20,0x42,0x01,0x17,0x20,0x62,0x0f,0xf8,0xe7,0x0d,0x22, + 0x04,0xe0,0x0e,0x22,0x13,0xe8,0x20,0x77,0x03,0xf0,0xa7,0x65,0x0e,0x22,0x03,0xe0, + 0x27,0x05,0x72,0x12,0x01,0xf0,0x72,0x1c,0x42,0x01,0x08,0xf0,0xd2,0x62,0x0e,0x22, + 0x05,0xe8,0x03,0x2a,0x02,0xe8,0x19,0x72,0x01,0xf0,0x32,0x12,0x6d,0x00,0xf0,0x20, + 0xcf,0x00,0x00,0x00,0xac,0x06,0x00,0x00,0x7a,0x25,0x00,0x00,0x08,0x84,0x00,0x00, + 0xc0,0x06,0x00,0x00,0xc4,0x06,0x00,0x00,0xc7,0x9c,0x00,0x00,0x20,0xaa,0x00,0x00, + 0x70,0xa8,0x00,0x00,0x10,0x9e,0x00,0x00,0x1c,0x04,0x04,0x00,0x20,0x04,0x04,0x00, + 0x40,0x04,0x04,0x00,0x44,0x04,0x04,0x00,0x68,0x23,0x00,0x00,0xe0,0x0a,0x00,0x00, + 0x60,0x26,0x00,0x00,0x7f,0x01,0x00,0x00,0x64,0x01,0x00,0x00,0x00,0xff,0xff,0xff, + 0x3e,0x84,0x00,0x00,0x08,0x01,0x00,0x00,0xb4,0xff,0xff,0xff,0x87,0x00,0x00,0x00, + 0x72,0x01,0x22,0x03,0x73,0x01,0x33,0x03,0x23,0x1c,0xf5,0x32,0x02,0x60,0xf6,0x60, + 0x04,0x2d,0x17,0x60,0x37,0x0c,0x03,0xe8,0x32,0x12,0x62,0x01,0x0e,0xf0,0x27,0x12, + 0x27,0x1c,0x57,0x1c,0x67,0x1b,0x06,0x24,0x66,0x01,0x73,0x0c,0x03,0xe8,0x52,0x1c, + 0x62,0x01,0x73,0x05,0x15,0x3e,0x46,0x0f,0xf2,0xe7,0xcf,0x00,0x70,0x24,0x00,0x9f, + 0x28,0x77,0x07,0xa6,0x16,0x2e,0x06,0x2a,0x2f,0xe8,0x07,0xa6,0x26,0x75,0x56,0x16, + 0x07,0xb6,0x32,0x60,0x25,0x73,0x25,0x7f,0x32,0x60,0x25,0x73,0x24,0x7f,0x25,0x7f, + 0x87,0x2c,0x27,0x16,0x25,0x76,0x06,0xa5,0x06,0xb7,0x12,0x01,0x24,0x77,0x07,0xa5, + 0x07,0xb1,0x22,0x01,0x23,0x73,0x03,0xa5,0x03,0xb1,0x82,0x3f,0x22,0x74,0x04,0xa5, + 0x04,0xb2,0x06,0xa6,0x07,0xa5,0x85,0x3c,0x65,0x1e,0x03,0xa7,0x07,0x3d,0x57,0x1e, + 0x04,0xa3,0x83,0x3d,0x17,0x72,0x73,0x1e,0x1c,0x74,0x05,0x60,0x1c,0x7f,0x12,0x72, + 0x1c,0x73,0x44,0x60,0x05,0x60,0x19,0x7f,0x0e,0x77,0x07,0xa6,0x16,0x36,0x14,0xe8, + 0x07,0xa6,0x18,0x75,0x56,0x16,0x07,0xb6,0x32,0x60,0x17,0x73,0x0c,0x7f,0x32,0x60, + 0x17,0x73,0x0a,0x7f,0x16,0x72,0x16,0x73,0x17,0x74,0x05,0x60,0x10,0x7f,0x12,0x72, + 0x16,0x73,0x44,0x60,0x05,0x60,0x0d,0x7f,0x00,0x8f,0x70,0x20,0xcf,0x00,0x00,0x00, + 0x3c,0xaa,0x00,0x00,0xfe,0x00,0x00,0x00,0x00,0xb0,0x00,0x00,0x3c,0x1f,0x00,0x00, + 0x00,0xa0,0x00,0x00,0x96,0x3b,0x00,0x00,0x33,0xaa,0x00,0x00,0x34,0xaa,0x00,0x00, + 0x35,0xaa,0x00,0x00,0x36,0xaa,0x00,0x00,0xc0,0x06,0x00,0x00,0x20,0x20,0x00,0x00, + 0xe4,0x01,0x00,0x00,0xfd,0x00,0x00,0x00,0x00,0xd0,0x00,0x00,0x00,0xc0,0x00,0x00, + 0x00,0x9c,0x00,0x00,0x23,0x01,0x00,0x00,0xe8,0x01,0x00,0x00,0x70,0x24,0x7e,0x00, + 0x0b,0x7e,0xe2,0x12,0x03,0x60,0x64,0x60,0x0a,0x7f,0x16,0x60,0x0e,0xb6,0xa7,0x60, + 0x2e,0xb7,0x07,0x60,0x1e,0xb7,0x3e,0xb6,0x5e,0xb7,0x06,0x72,0x03,0x60,0x04,0x64, + 0x04,0x7f,0x05,0x7f,0x06,0x7f,0x6e,0x00,0x70,0x20,0xcf,0x00,0xb0,0xa8,0x00,0x00, + 0xc4,0x09,0x00,0x00,0x70,0xa8,0x00,0x00,0xf8,0x16,0x00,0x00,0xf8,0x1a,0x00,0x00, + 0xf0,0x25,0x78,0x00,0x6d,0x75,0x55,0xa7,0x27,0x2a,0xd2,0xe8,0x85,0xa7,0x07,0x2a, + 0x0c,0xe8,0x6a,0x77,0x16,0x60,0x17,0xb6,0x06,0x60,0x07,0xb6,0x67,0xb6,0x77,0xb6, + 0x47,0xb6,0x57,0xb6,0x44,0x60,0x97,0xb4,0x85,0xb6,0x64,0x77,0x07,0xa6,0x06,0x2a, + 0x13,0xe0,0x17,0xa6,0x06,0x2a,0x10,0xe0,0x27,0xa6,0x06,0x2a,0x0d,0xe0,0x37,0xa2, + 0x02,0x2a,0x0a,0xe0,0x5f,0x7e,0x1e,0xb2,0x5f,0x7f,0x3e,0xa7,0x07,0x2a,0xfd,0xef, + 0x06,0x60,0x5b,0x77,0x37,0xb6,0xac,0xf0,0x5a,0x77,0x27,0xa6,0x07,0xa7,0xa6,0x2a, + 0x06,0xe0,0x17,0x2a,0x02,0xe0,0x58,0x7f,0x07,0xf0,0x58,0x7f,0x05,0xf0,0x17,0x2a, + 0x02,0xe0,0x57,0x7f,0x01,0xf0,0x57,0x7f,0x2b,0x12,0x51,0x77,0x07,0xa6,0x16,0x2a, + 0x02,0xe8,0x16,0x60,0x07,0xb6,0x07,0xa7,0x0a,0x60,0x17,0x2a,0x51,0xe0,0x4b,0x78, + 0x28,0xa7,0x0b,0xb7,0xbd,0x12,0x1d,0x20,0x50,0x7c,0xae,0x12,0xa9,0x12,0x0e,0x01, + 0x0c,0xa7,0x07,0x2a,0x38,0xe8,0x09,0x20,0x49,0x01,0xe6,0x12,0xe6,0x1c,0xe6,0x1c, + 0x66,0x1c,0x86,0x1c,0x65,0x12,0x0d,0xb1,0x46,0xa6,0x1d,0xb6,0x55,0xa6,0x2d,0xb6, + 0x65,0xa6,0x3d,0xb6,0x75,0xa6,0x4d,0xb6,0xc6,0x12,0x06,0x24,0x06,0xa6,0x5d,0xb6, + 0x6d,0xb7,0x6d,0x20,0x17,0x2a,0x03,0xe8,0x47,0x2a,0x04,0xe0,0x02,0xf0,0x7a,0x12, + 0x01,0xf0,0x1a,0x60,0x3e,0x75,0x55,0xa6,0x05,0x64,0x56,0x16,0x06,0x2a,0x13,0xe8, + 0xe6,0x12,0xe6,0x1c,0xe6,0x1c,0x66,0x1c,0x86,0x1c,0x46,0xaf,0x56,0xa4,0x84,0x3c, + 0x66,0xa1,0x76,0xa5,0x85,0x3c,0xc6,0x12,0x06,0x24,0x35,0x72,0xe3,0x12,0xf4,0x1e, + 0x15,0x1e,0x06,0xa6,0x34,0x7f,0x0e,0x20,0x5c,0x20,0x5e,0x2a,0xc0,0xe7,0x2f,0x77, + 0x57,0xa7,0x06,0x64,0x67,0x16,0x07,0x2a,0x02,0xe8,0x2f,0x72,0x2e,0x7f,0x1b,0xb9, + 0x23,0x77,0x27,0xa6,0x37,0xb6,0x22,0x77,0x22,0x7d,0x37,0xa6,0x06,0x2a,0xfc,0xef, + 0x07,0x60,0x3d,0xb7,0x4e,0x66,0x29,0x72,0x2a,0x7f,0x5d,0xa7,0x07,0x2a,0x04,0xe8, + 0x0e,0x24,0x4e,0x01,0x0e,0x2a,0xf7,0xe7,0x1a,0x77,0x27,0xa6,0xa6,0x2a,0x02,0xe0, + 0xb6,0x60,0x01,0xf0,0xa6,0x60,0x27,0xb6,0x16,0x7d,0x17,0x60,0x1d,0xb7,0x1a,0x2a, + 0x1c,0xe0,0x0d,0xa7,0x3e,0x60,0x0c,0x60,0x4d,0xbc,0x12,0x60,0x12,0x7f,0x1d,0x7f, + 0x03,0xf0,0x1d,0xa7,0x07,0x2a,0x0b,0xe8,0x4d,0xa7,0x07,0x2a,0xfa,0xef,0x02,0x60, + 0x0d,0x7f,0x16,0x72,0x17,0x7f,0x0e,0x24,0x4e,0x01,0x0e,0x2a,0xed,0xe7,0x02,0x60, + 0x09,0x7f,0x06,0x60,0x15,0x77,0x07,0x96,0x03,0xf0,0x12,0x60,0x06,0x7f,0x11,0x7f, + 0x68,0x00,0xf0,0x21,0xcf,0x00,0x00,0x00,0x20,0xaa,0x00,0x00,0x70,0xa8,0x00,0x00, + 0xb0,0xa8,0x00,0x00,0xb8,0x08,0x00,0x00,0xc2,0x17,0x00,0x00,0x06,0x1b,0x00,0x00, + 0xbe,0x17,0x00,0x00,0xfa,0x1a,0x00,0x00,0x79,0xa8,0x00,0x00,0x44,0xaa,0x00,0x00, + 0xc8,0x06,0x00,0x00,0x7a,0x25,0x00,0x00,0xe0,0x06,0x00,0x00,0xc8,0x00,0x00,0x00, + 0xe0,0x0a,0x00,0x00,0xea,0x08,0x00,0x00,0x18,0x02,0x04,0x00,0x89,0x76,0x06,0x87, + 0x57,0x30,0x07,0x31,0x06,0x97,0x36,0x60,0x87,0x77,0x07,0xb6,0x87,0x76,0x87,0x77, + 0x07,0xd6,0x87,0x76,0x88,0x77,0x07,0xd6,0x17,0x60,0x87,0x76,0x06,0xb7,0x87,0x76, + 0x06,0xb7,0x87,0x77,0x07,0xa6,0x35,0x60,0x56,0x1e,0x07,0xb6,0x54,0x60,0x85,0x76, + 0x06,0xb4,0x85,0x76,0x06,0xb5,0x07,0xa6,0x85,0x75,0x56,0x16,0x07,0xb6,0x84,0x76, + 0x85,0x77,0x07,0xd6,0x85,0x76,0x06,0x87,0x07,0x34,0x06,0x97,0x84,0x77,0x05,0x60, + 0x07,0xb5,0x17,0xb5,0x24,0x60,0x37,0xb4,0x27,0xb5,0x47,0xb5,0x06,0x87,0x80,0x75, + 0x57,0x1e,0x06,0x97,0xcf,0x00,0xf0,0x24,0x7c,0x00,0x7e,0x77,0x13,0x60,0x57,0xb3, + 0x7e,0x75,0x05,0xa5,0x05,0x2a,0x64,0xe8,0x7d,0x74,0x04,0xa6,0x16,0x2e,0x06,0x2a, + 0x03,0xe8,0x07,0xb3,0x26,0x60,0x05,0xf0,0x04,0xa4,0x14,0x36,0x04,0xe8,0x26,0x60, + 0x07,0xb6,0x72,0x77,0x37,0xb6,0x71,0x76,0x07,0x60,0x26,0xb7,0x36,0xa7,0x57,0x0f, + 0x4f,0xe0,0x04,0x60,0x73,0x7d,0x0d,0xa2,0x26,0xa3,0x53,0x0c,0x0f,0xe0,0x03,0x2a, + 0x03,0xe0,0x06,0xb2,0x07,0x60,0x09,0xf0,0x06,0xae,0x16,0xa7,0x87,0x3c,0xe7,0x1e, + 0x87,0x3c,0x27,0x1c,0x67,0x01,0x06,0xb7,0x87,0x3e,0x16,0xb7,0x64,0x7e,0x37,0x12, + 0x07,0x20,0x26,0xb7,0x04,0x20,0x44,0x01,0x54,0x0f,0xe5,0xe7,0x07,0x60,0x4e,0xb7, + 0x16,0x60,0x56,0x77,0x07,0xb6,0x5f,0x77,0x07,0xa7,0x8d,0x60,0x62,0x7c,0x17,0x2a, + 0x14,0xe0,0x0e,0xa2,0x1e,0xa7,0x87,0x3c,0x72,0x1e,0x5f,0x7f,0x0c,0xb2,0x0e,0xa6, + 0x1e,0xa7,0x87,0x3c,0x67,0x1e,0x07,0x20,0x67,0x01,0x0e,0xb7,0x87,0x3e,0x1e,0xb7, + 0x0d,0x24,0x4d,0x01,0x0d,0x2a,0xed,0xe7,0x13,0xf0,0x0e,0xa2,0x1e,0xa7,0x87,0x3c, + 0x72,0x1e,0x56,0x7f,0x0c,0xb2,0x0e,0xa6,0x1e,0xa7,0x87,0x3c,0x67,0x1e,0x07,0x20, + 0x67,0x01,0x0e,0xb7,0x87,0x3e,0x1e,0xb7,0x0d,0x24,0x4d,0x01,0x0d,0x2a,0xed,0xe7, + 0x47,0x77,0x47,0xa6,0x06,0x2a,0x04,0xe8,0x06,0x60,0x3c,0x75,0x05,0xb6,0x47,0xb6, + 0x0e,0x60,0x27,0xbe,0x02,0x60,0x4a,0x7f,0x43,0x77,0x17,0xa6,0x06,0x2a,0x01,0xe8, + 0x17,0xbe,0x6c,0x00,0xf0,0x20,0xcf,0x00,0x70,0x25,0x7b,0x00,0x3e,0x76,0x07,0x60, + 0x56,0xb7,0x3a,0x7e,0x17,0x60,0x4e,0xb7,0x06,0xb7,0x26,0x60,0x3e,0xb6,0x3a,0x7c, + 0x0c,0xac,0x0c,0x2a,0x28,0xe8,0x0d,0x60,0x3a,0x7b,0x0b,0xa3,0x2e,0xa7,0x3e,0xa6, + 0x67,0x0c,0x0b,0xe0,0x07,0x2a,0x02,0xe0,0x0e,0xb3,0x14,0xf0,0x0e,0xa6,0x1e,0xa7, + 0x87,0x3c,0x67,0x1e,0x87,0x3c,0x37,0x1c,0x0a,0xf0,0x0e,0xa2,0x1e,0xa7,0x87,0x3c, + 0x72,0x1e,0x34,0x7f,0x0e,0xa6,0x1e,0xa7,0x87,0x3c,0x67,0x1e,0x07,0x20,0x67,0x01, + 0x0e,0xb7,0x87,0x3e,0x1e,0xb7,0x2e,0xa7,0x07,0x20,0x2e,0xb7,0x0d,0x20,0x4d,0x01, + 0xcd,0x0f,0xdb,0xe7,0x02,0xf0,0x19,0x76,0x06,0xb7,0x20,0x7e,0x2e,0xa6,0x3e,0xa7, + 0x76,0x0f,0x1a,0xe0,0x07,0x60,0x4e,0xb7,0x16,0x60,0x14,0x77,0x07,0xb6,0x8d,0x60, + 0x21,0x7c,0x0e,0xa2,0x1e,0xa7,0x87,0x3c,0x72,0x1e,0x1f,0x7f,0x0c,0xb2,0x0e,0xa6, + 0x1e,0xa7,0x87,0x3c,0x67,0x1e,0x07,0x20,0x67,0x01,0x0e,0xb7,0x87,0x3e,0x1e,0xb7, + 0x0d,0x24,0x4d,0x01,0x0d,0x2a,0xed,0xe7,0x6b,0x00,0x70,0x21,0xcf,0x00,0x00,0x00, + 0x08,0x00,0x04,0x00,0x14,0x00,0x04,0x00,0x78,0x01,0x00,0x00,0x20,0x0e,0x04,0x00, + 0x48,0x01,0x00,0x00,0x24,0x0e,0x04,0x00,0x19,0x0e,0x04,0x00,0x1d,0x0e,0x04,0x00, + 0x00,0x0e,0x04,0x00,0x2c,0x0e,0x04,0x00,0x30,0x0e,0x04,0x00,0xfb,0x00,0x00,0x00, + 0x88,0x03,0x00,0x00,0x34,0x0e,0x04,0x00,0x10,0x00,0x00,0xe0,0x12,0x9e,0x00,0x00, + 0xfe,0x00,0x00,0x00,0xb0,0xa8,0x00,0x00,0x18,0x0e,0x04,0x00,0x0c,0x0e,0x04,0x00, + 0x14,0x0e,0x04,0x00,0x10,0x0e,0x04,0x00,0xc6,0x17,0x00,0x00,0x12,0x1b,0x00,0x00, + 0xb8,0x08,0x00,0x00,0x9a,0x18,0x00,0x00,0x70,0x25,0x7b,0x00,0x75,0x75,0x07,0x60, + 0x55,0xb7,0x74,0x7e,0x17,0x60,0x4e,0xb7,0x26,0x60,0x05,0xb6,0x3e,0xb6,0x72,0x7c, + 0x0c,0xac,0x0c,0x2a,0x28,0xe8,0x0d,0x60,0x71,0x7b,0x0b,0xa3,0x2e,0xa7,0x3e,0xa6, + 0x67,0x0c,0x0b,0xe0,0x07,0x2a,0x02,0xe0,0x0e,0xb3,0x14,0xf0,0x0e,0xa6,0x1e,0xa7, + 0x87,0x3c,0x67,0x1e,0x87,0x3c,0x37,0x1c,0x0a,0xf0,0x0e,0xa2,0x1e,0xa7,0x87,0x3c, + 0x72,0x1e,0x67,0x7f,0x0e,0xa6,0x1e,0xa7,0x87,0x3c,0x67,0x1e,0x07,0x20,0x67,0x01, + 0x0e,0xb7,0x87,0x3e,0x1e,0xb7,0x2e,0xa7,0x07,0x20,0x2e,0xb7,0x0d,0x20,0x4d,0x01, + 0xcd,0x0f,0xdb,0xe7,0x02,0xf0,0x5f,0x76,0x06,0xb7,0x5a,0x7e,0x2e,0xa6,0x3e,0xa7, + 0x76,0x0f,0x1a,0xe0,0x07,0x60,0x4e,0xb7,0x16,0x60,0x5a,0x77,0x07,0xb6,0x8d,0x60, + 0x5a,0x7c,0x0e,0xa2,0x1e,0xa7,0x87,0x3c,0x72,0x1e,0x58,0x7f,0x0c,0xb2,0x0e,0xa6, + 0x1e,0xa7,0x87,0x3c,0x67,0x1e,0x07,0x20,0x67,0x01,0x0e,0xb7,0x87,0x3e,0x1e,0xb7, + 0x0d,0x24,0x4d,0x01,0x0d,0x2a,0xed,0xe7,0x6b,0x00,0x70,0x21,0xcf,0x00,0x70,0x25, + 0x7b,0x00,0x4f,0x77,0x07,0xac,0x8c,0x28,0x4c,0x01,0x45,0x77,0x07,0xa6,0x16,0x2a, + 0x19,0xe0,0x12,0xf0,0x0e,0xa2,0x1e,0xa7,0x87,0x3c,0x72,0x1e,0x4a,0x7f,0x0b,0xb2, + 0x0d,0x20,0x4d,0x01,0x0e,0xa6,0x1e,0xa7,0x87,0x3c,0x67,0x1e,0x07,0x20,0x67,0x01, + 0x0e,0xb7,0x87,0x3e,0x1e,0xb7,0x03,0xf0,0x0d,0x60,0x3a,0x7e,0x3f,0x7b,0xcd,0x0f, + 0xe9,0xe7,0x1b,0xf0,0x07,0xa7,0x27,0x2a,0x18,0xe0,0x12,0xf0,0x0e,0xa2,0x1e,0xa7, + 0x87,0x3c,0x72,0x1e,0x3a,0x7f,0x0b,0xb2,0x0d,0x20,0x4d,0x01,0x0e,0xa6,0x1e,0xa7, + 0x87,0x3c,0x67,0x1e,0x07,0x20,0x67,0x01,0x0e,0xb7,0x87,0x3e,0x1e,0xb7,0x03,0xf0, + 0x0d,0x60,0x2c,0x7e,0x31,0x7b,0xcd,0x0f,0xe9,0xe7,0x6b,0x00,0x70,0x21,0xcf,0x00, + 0x70,0x24,0x00,0x9f,0x31,0x7f,0x00,0x8f,0x70,0x20,0xcf,0x00,0x70,0x25,0x7a,0x00, + 0x2f,0x76,0x06,0xa7,0x17,0x2e,0x07,0x2a,0x07,0xe8,0x16,0x60,0x21,0x77,0x07,0xb6, + 0x26,0x60,0x20,0x77,0x37,0xb6,0x08,0xf0,0x06,0xa6,0x16,0x36,0x05,0xe8,0x27,0x60, + 0x1c,0x76,0x06,0xb7,0x1c,0x76,0x36,0xb7,0x1c,0x7c,0x0c,0xac,0x0d,0x60,0x1b,0x7b, + 0x19,0x7e,0x17,0x7a,0x28,0xf0,0x0b,0xa3,0x2e,0xa7,0x3e,0xa6,0x67,0x0c,0x0b,0xe0, + 0x07,0x2a,0x02,0xe0,0x0e,0xb3,0x19,0xf0,0x0e,0xa6,0x1e,0xa7,0x87,0x3c,0x67,0x1e, + 0x87,0x3c,0x37,0x1c,0x0f,0xf0,0x0a,0xa7,0x17,0x2a,0x0e,0xa2,0x1e,0xa7,0x87,0x3c, + 0x72,0x1e,0x02,0xe0,0x17,0x7f,0x01,0xf0,0x0e,0x7f,0x0e,0xa6,0x1e,0xa7,0x87,0x3c, + 0x67,0x1e,0x07,0x20,0x67,0x01,0x0e,0xb7,0x87,0x3e,0x1e,0xb7,0x2e,0xa7,0x07,0x20, + 0x2e,0xb7,0x0d,0x20,0x4d,0x01,0xcd,0x0f,0xd6,0xe7,0x6a,0x00,0x70,0x21,0xcf,0x00, + 0xb0,0xa8,0x00,0x00,0x12,0x9e,0x00,0x00,0x18,0x0e,0x04,0x00,0x14,0x0e,0x04,0x00, + 0x20,0x1b,0x00,0x00,0x1d,0x0e,0x04,0x00,0x10,0x0e,0x04,0x00,0x12,0x1b,0x00,0x00, + 0x1c,0x0e,0x04,0x00,0xc6,0x17,0x00,0x00,0x6e,0x13,0x00,0x00,0x0c,0x0e,0x04,0x00, + 0x9a,0x18,0x00,0x00,0x70,0x24,0x00,0x9f,0x4f,0x7f,0x00,0x8f,0x70,0x20,0xcf,0x00, + 0x70,0x24,0x7e,0x00,0x4d,0x7e,0x0e,0xa2,0x1e,0xa7,0x87,0x3c,0x72,0x1e,0x4b,0x7f, + 0x4c,0x77,0x07,0xb2,0x0e,0xa6,0x1e,0xa7,0x87,0x3c,0x67,0x1e,0x07,0x20,0x67,0x01, + 0x0e,0xb7,0x87,0x3e,0x1e,0xb7,0x6e,0x00,0x70,0x20,0xcf,0x00,0x70,0x24,0x7e,0x00, + 0x42,0x7e,0x0e,0xa2,0x1e,0xa7,0x87,0x3c,0x72,0x1e,0x42,0x7f,0x41,0x77,0x07,0xb2, + 0x0e,0xa6,0x1e,0xa7,0x87,0x3c,0x67,0x1e,0x07,0x20,0x67,0x01,0x0e,0xb7,0x87,0x3e, + 0x1e,0xb7,0x6e,0x00,0x70,0x20,0xcf,0x00,0x70,0x24,0x7e,0x00,0x16,0x60,0x3a,0x77, + 0x07,0xb6,0x35,0x7e,0x27,0x60,0x3e,0xb7,0x39,0x73,0x03,0xa3,0x2e,0xa5,0x16,0x60, + 0x56,0x0c,0x0e,0xe8,0x05,0x2a,0x04,0xe0,0x2e,0xb6,0x0e,0xb3,0x07,0x60,0x15,0xf0, + 0x2e,0xb7,0x0e,0xa6,0x1e,0xa7,0x87,0x3c,0x67,0x1e,0x87,0x3c,0x37,0x1c,0x0a,0xf0, + 0x0e,0xa2,0x1e,0xa7,0x87,0x3c,0x72,0x1e,0x2e,0x7f,0x0e,0xa6,0x1e,0xa7,0x87,0x3c, + 0x67,0x1e,0x07,0x20,0x67,0x01,0x0e,0xb7,0x87,0x3e,0x1e,0xb7,0x6e,0x00,0x70,0x20, + 0xcf,0x00,0x70,0x24,0x7e,0x00,0x27,0x60,0x24,0x76,0x06,0xb7,0x1f,0x7e,0x3e,0xb7, + 0x23,0x73,0x03,0xa3,0x2e,0xa5,0x16,0x60,0x56,0x0c,0x0e,0xe8,0x05,0x2a,0x04,0xe0, + 0x2e,0xb6,0x0e,0xb3,0x07,0x60,0x15,0xf0,0x2e,0xb7,0x0e,0xa6,0x1e,0xa7,0x87,0x3c, + 0x67,0x1e,0x87,0x3c,0x37,0x1c,0x0a,0xf0,0x0e,0xa2,0x1e,0xa7,0x87,0x3c,0x72,0x1e, + 0x19,0x7f,0x0e,0xa6,0x1e,0xa7,0x87,0x3c,0x67,0x1e,0x07,0x20,0x67,0x01,0x0e,0xb7, + 0x87,0x3e,0x1e,0xb7,0x6e,0x00,0x70,0x20,0xcf,0x00,0x70,0x24,0x00,0x9f,0x12,0x77, + 0x07,0xa6,0x12,0x75,0x56,0x16,0x07,0xb6,0x07,0xa6,0x16,0x34,0x07,0xb6,0x10,0x7f, + 0x00,0x8f,0x70,0x20,0xcf,0x00,0x62,0x01,0x04,0x77,0x07,0xb2,0x82,0x3e,0x17,0xb2, + 0xcf,0x00,0x00,0x00,0xfc,0x13,0x00,0x00,0x12,0x9e,0x00,0x00,0xc6,0x17,0x00,0x00, + 0x10,0x0e,0x04,0x00,0x12,0x1b,0x00,0x00,0xb0,0xa8,0x00,0x00,0x14,0x0e,0x04,0x00, + 0x9a,0x18,0x00,0x00,0x20,0x1b,0x00,0x00,0x04,0x00,0x04,0x00,0xfd,0x00,0x00,0x00, + 0x2c,0x10,0x00,0x00,0xcf,0x00,0xcf,0x00,0xcf,0x00,0xcf,0x00,0xcf,0x00,0xcf,0x00, + 0x70,0x24,0x00,0x9f,0x22,0x7f,0x02,0x60,0x22,0x7f,0x16,0x60,0x22,0x77,0x47,0xb6, + 0x00,0x8f,0x70,0x20,0xcf,0x00,0x16,0x60,0x1f,0x77,0x37,0xb6,0x1f,0x77,0x07,0xa6, + 0x06,0x20,0x46,0x01,0x07,0xb6,0x1d,0x75,0x05,0xa5,0x56,0x0c,0x1e,0xe8,0x06,0x60, + 0x07,0xb6,0x1b,0x72,0x02,0xa6,0x1b,0x74,0x04,0xa7,0x87,0x3c,0x67,0x1e,0x1a,0x75, + 0x05,0xa3,0x03,0x3d,0x73,0x1e,0x19,0x76,0x06,0xa7,0x87,0x3d,0x37,0x1e,0x07,0x20, + 0x83,0x2c,0x73,0x16,0x02,0xa1,0x02,0xb3,0x17,0x01,0x04,0xa3,0x04,0xb1,0x27,0x01, + 0x05,0xa4,0x05,0xb1,0x87,0x3f,0x06,0xa5,0x06,0xb7,0x11,0x75,0x05,0xa4,0x11,0x76, + 0x06,0xa7,0x87,0x3c,0x47,0x1e,0x07,0x20,0x67,0x01,0x84,0x2c,0x74,0x16,0x05,0xa3, + 0x05,0xb4,0x87,0x3e,0x06,0xa5,0x06,0xb7,0xcf,0x00,0x00,0x00,0xfe,0x08,0x00,0x00, + 0xb8,0x08,0x00,0x00,0xb0,0xa8,0x00,0x00,0x17,0x9e,0x00,0x00,0xc6,0x9c,0x00,0x00, + 0x37,0xaa,0x00,0x00,0x38,0xaa,0x00,0x00,0x39,0xaa,0x00,0x00,0x3a,0xaa,0x00,0x00, + 0x40,0xaa,0x00,0x00,0x41,0xaa,0x00,0x00,0xf0,0x24,0x7d,0x00,0x91,0x7e,0xe2,0x12, + 0x03,0x60,0x24,0x62,0x90,0x7f,0x90,0x72,0x03,0x60,0x90,0x74,0x8e,0x7f,0x90,0x72, + 0x03,0x60,0x64,0x60,0x8c,0x7f,0x76,0x62,0x9e,0xb6,0x8e,0x77,0xae,0xb7,0x47,0x60, + 0xbe,0xb7,0xce,0xb6,0xee,0xb7,0x02,0x60,0x8c,0x7f,0x2e,0x12,0x42,0x60,0x8a,0x7f, + 0x2d,0x12,0x27,0x12,0x47,0x3c,0xe7,0x1e,0x47,0x01,0x88,0x76,0x06,0xb7,0x02,0x2a, + 0x05,0xe0,0x42,0x60,0x87,0x7f,0x42,0x60,0xd3,0x12,0x86,0x7f,0x7d,0x77,0x0e,0x60, + 0x67,0xbe,0x77,0xbe,0x1d,0x60,0x87,0xbd,0x84,0x7f,0x86,0x2c,0x26,0x16,0x83,0x77, + 0x07,0xa5,0x07,0xb6,0x12,0x01,0x82,0x77,0x07,0xa6,0x07,0xb1,0x22,0x01,0x81,0x77, + 0x07,0xa6,0x07,0xb1,0x82,0x3f,0x80,0x77,0x07,0xa6,0x07,0xb2,0x80,0x77,0x07,0xa6, + 0x07,0xbe,0x7f,0x77,0x07,0xa6,0x07,0xbe,0x7f,0x77,0x07,0xa6,0x07,0xbe,0x7e,0x77, + 0x07,0xa6,0x07,0xbe,0x7e,0x77,0x07,0xbe,0x7e,0x77,0x07,0xbe,0x6d,0x77,0x57,0xbe, + 0x26,0x62,0x7c,0x77,0x07,0xb6,0x6d,0x76,0x06,0xa6,0x27,0x62,0x76,0x0f,0x7a,0x77, + 0x02,0xe0,0x07,0xbd,0x01,0xf0,0x07,0xbe,0x6d,0x00,0xf0,0x20,0xcf,0x00,0x62,0x72, + 0xcf,0x00,0x76,0x72,0xcf,0x00,0x27,0x12,0x67,0x01,0xc6,0x2c,0x76,0x0c,0x06,0xe8, + 0x82,0x2c,0x16,0x62,0x76,0x0c,0x60,0xe8,0x5a,0x76,0x0f,0xf0,0xd6,0x2c,0x76,0x0c, + 0x14,0xe8,0x6f,0x75,0x57,0x1c,0x67,0x01,0x82,0x2c,0x6e,0x76,0x76,0x0c,0x54,0xe8, + 0x6e,0x76,0x26,0xa5,0xa5,0x2a,0x04,0xe0,0x54,0x76,0x76,0x1c,0x06,0xa2,0x4c,0xf0, + 0x26,0xa6,0xb6,0x2a,0x49,0xe0,0x65,0x76,0xf8,0xf7,0x68,0x76,0x76,0x0c,0x12,0xe8, + 0x57,0x75,0x05,0xa5,0x57,0x76,0x06,0xa6,0x86,0x3c,0x56,0x1e,0x56,0x75,0x05,0xa5, + 0x05,0x3d,0x65,0x1e,0x55,0x76,0x06,0xa6,0x86,0x3d,0x56,0x1e,0x61,0x75,0x57,0x1c, + 0x67,0x01,0xe3,0xf7,0xe6,0x2c,0x76,0x0c,0x06,0xe8,0x5e,0x76,0x67,0x1c,0x67,0x01, + 0x5e,0x75,0x57,0x1c,0x28,0xf0,0x76,0x12,0x76,0x01,0x82,0x2c,0xf6,0x37,0x24,0xe8, + 0x5b,0x76,0x76,0x0c,0x05,0xe8,0x5a,0x76,0x67,0x1c,0x67,0x01,0x5a,0x76,0x1a,0xf0, + 0x5a,0x76,0x76,0x0c,0x19,0xe0,0xc5,0x32,0x57,0x1c,0x67,0x01,0x47,0x2a,0x38,0x76, + 0x11,0xe0,0x06,0xa5,0x16,0xa7,0x87,0x3c,0x57,0x1e,0x26,0xa5,0x05,0x3d,0x75,0x1e, + 0x36,0xa7,0x87,0x3d,0x57,0x1e,0x51,0x76,0x67,0x0f,0x05,0xe0,0x15,0x60,0x50,0x76, + 0x06,0xb5,0x01,0xf0,0x67,0x1c,0x07,0xa2,0xcf,0x00,0x70,0x24,0x7e,0x00,0x62,0x01, + 0x3e,0x12,0x4e,0x01,0xc7,0x2c,0x27,0x0c,0xda,0xe8,0x17,0x62,0x27,0x0c,0xff,0xe8, + 0x22,0x2a,0x0b,0xe8,0x42,0x2a,0x0c,0xe8,0x02,0x2a,0xf9,0xe0,0x21,0x77,0x07,0xa6, + 0xe6,0x0f,0xf5,0xe8,0x16,0x60,0x17,0xb6,0xee,0xf0,0x1d,0x77,0x27,0xbe,0xef,0xf0, + 0x1e,0x2a,0x02,0xe0,0x40,0x7f,0xc1,0xf0,0x2e,0x2a,0x03,0xe0,0x19,0x77,0x57,0xbe, + 0xbc,0xf0,0x4e,0x2a,0x08,0xe0,0x3c,0x77,0x07,0xa7,0x37,0x2a,0xb6,0xe0,0x28,0x76, + 0x06,0xa7,0x17,0x34,0x86,0xf0,0xe6,0x12,0xf6,0x24,0x46,0x01,0x67,0x60,0x67,0x0c, + 0x03,0xe8,0xe2,0x12,0x36,0x7f,0xa9,0xf0,0x07,0x62,0x7e,0x0f,0x07,0xe0,0x16,0x60, + 0x34,0x77,0x07,0xb6,0x06,0x60,0x0a,0x77,0x27,0xb6,0x9f,0xf0,0x07,0x63,0x7e,0x0f, + 0x03,0xe0,0x16,0x60,0x2b,0x77,0x98,0xf0,0x57,0x65,0x16,0x60,0x7e,0x0f,0x04,0xe8, + 0x67,0x66,0x7e,0x0f,0x57,0xe0,0x06,0x60,0x02,0x77,0x77,0xb6,0x8e,0xf0,0x00,0x00, + 0x20,0xaa,0x00,0x00,0x22,0x83,0x00,0x00,0xc0,0xa8,0x00,0x00,0x60,0x01,0x00,0x00, + 0x44,0xaa,0x00,0x00,0x85,0xff,0xff,0xff,0xa4,0x21,0x00,0x00,0x30,0xaa,0x00,0x00, + 0xc2,0x20,0x00,0x00,0xec,0x20,0x00,0x00,0x96,0x3b,0x00,0x00,0x33,0xaa,0x00,0x00, + 0x34,0xaa,0x00,0x00,0x35,0xaa,0x00,0x00,0x36,0xaa,0x00,0x00,0x37,0xaa,0x00,0x00, + 0x38,0xaa,0x00,0x00,0x39,0xaa,0x00,0x00,0x3a,0xaa,0x00,0x00,0x3b,0xaa,0x00,0x00, + 0x3c,0xaa,0x00,0x00,0x3e,0xaa,0x00,0x00,0x3f,0xaa,0x00,0x00,0x30,0xa9,0x00,0x00, + 0x00,0xf0,0xff,0xff,0xb0,0x00,0x00,0x00,0xb0,0xa8,0x00,0x00,0xff,0x2f,0x00,0x00, + 0x00,0xe0,0xff,0xff,0x00,0xd0,0xff,0xff,0x00,0xe0,0x02,0x00,0xff,0x8f,0x00,0x00, + 0x00,0x80,0xff,0xff,0x00,0x9c,0x00,0x00,0xff,0xef,0x00,0x00,0xff,0xff,0x04,0x00, + 0x31,0xaa,0x00,0x00,0x60,0x26,0x00,0x00,0x18,0x9e,0x00,0x00,0x72,0x2d,0x00,0x00, + 0x32,0xaa,0x00,0x00,0x17,0x62,0x7e,0x0f,0x06,0xe0,0x07,0x60,0x32,0x76,0x06,0xb7, + 0x32,0x76,0x26,0xb7,0x32,0xf0,0x07,0x67,0x7e,0x0f,0x05,0xe0,0x30,0x76,0x06,0xa7, + 0x07,0x34,0x06,0xb7,0x2a,0xf0,0x2e,0x77,0x26,0x60,0x7e,0x0f,0x04,0xe8,0x2d,0x77, + 0x7e,0x0f,0x03,0xe0,0x06,0x60,0x2c,0x77,0x1f,0xf0,0x2c,0x77,0x16,0x60,0x7e,0x0f, + 0x04,0xe8,0x2b,0x77,0x7e,0x0f,0x03,0xe0,0x06,0x60,0x2a,0x77,0x15,0xf0,0x5e,0x2a, + 0x06,0xe0,0x16,0x60,0x29,0x77,0x07,0xb6,0x32,0x60,0x13,0x60,0x07,0xf0,0x6e,0x2a, + 0x07,0xe0,0x16,0x60,0x25,0x77,0x07,0xb6,0x32,0x60,0x03,0x60,0x24,0x7f,0x05,0xf0, + 0x7e,0x2a,0x03,0xe0,0x06,0x60,0x20,0x77,0x07,0xb6,0x21,0x77,0x24,0xf0,0xd7,0x2c, + 0x27,0x0c,0x25,0xe0,0xe7,0x2c,0x27,0x0c,0x22,0xe0,0x27,0x12,0xf7,0x36,0x1f,0xe8, + 0x1d,0x77,0x27,0x0c,0x05,0xe8,0x1c,0x77,0x72,0x1c,0x62,0x01,0x1c,0x77,0x15,0xf0, + 0x1c,0x77,0x27,0x0c,0x14,0xe0,0xc7,0x32,0x72,0x1c,0x62,0x01,0x42,0x2a,0x19,0x77, + 0x0c,0xe0,0x07,0xa6,0x17,0xa5,0x85,0x3c,0x65,0x1e,0x27,0xa6,0x06,0x3d,0x56,0x1e, + 0x37,0xa7,0x87,0x3d,0x67,0x1e,0x07,0xbe,0x02,0xf0,0x72,0x1c,0x02,0xbe,0x6e,0x00, + 0x70,0x20,0xcf,0x00,0x32,0xaa,0x00,0x00,0x20,0xaa,0x00,0x00,0x3c,0xaa,0x00,0x00, + 0x90,0x00,0x00,0x00,0x91,0x00,0x00,0x00,0x72,0x9c,0x00,0x00,0xa0,0x00,0x00,0x00, + 0xa1,0x00,0x00,0x00,0x11,0x9d,0x00,0x00,0x3b,0xaa,0x00,0x00,0x0c,0x21,0x00,0x00, + 0x18,0x9e,0x00,0x00,0xff,0x8f,0x00,0x00,0x00,0x80,0xff,0xff,0x00,0x9c,0x00,0x00, + 0xff,0xef,0x00,0x00,0x44,0xaa,0x00,0x00,0xcf,0x00,0x70,0x24,0x00,0x9f,0x0c,0x7f, + 0x00,0x8f,0x70,0x20,0xcf,0x00,0x70,0x24,0x00,0x9f,0x0a,0x7f,0x00,0x8f,0x70,0x20, + 0xcf,0x00,0x70,0x24,0x00,0x9f,0x62,0x01,0x08,0x7f,0x00,0x8f,0x70,0x20,0xcf,0x00, + 0x70,0x24,0x00,0x9f,0x62,0x01,0x43,0x01,0x05,0x7f,0x00,0x8f,0x70,0x20,0xcf,0x00, + 0xbe,0x17,0x00,0x00,0xc2,0x17,0x00,0x00,0xc6,0x17,0x00,0x00,0x9a,0x18,0x00,0x00, + 0x70,0x24,0x00,0x9f,0x09,0x77,0x07,0x86,0x09,0x77,0x09,0x72,0x76,0x0f,0x05,0xe0, + 0x09,0x73,0x09,0x74,0x15,0x60,0x09,0x7f,0x03,0xf0,0x09,0x73,0x07,0x74,0x09,0x7f, + 0x00,0x8f,0x70,0x20,0xcf,0x00,0x00,0x00,0x00,0xd0,0x10,0x00,0x5a,0xa5,0x66,0x6a, + 0x00,0x9c,0x00,0x00,0x00,0xc0,0x00,0x00,0x23,0x01,0x00,0x00,0xf6,0x1e,0x00,0x00, + 0xec,0x01,0x00,0x00,0x8c,0x82,0x00,0x00,0xf0,0x25,0x79,0x00,0x24,0x76,0x07,0x60, + 0x16,0xb7,0x56,0xb7,0x23,0x75,0x05,0xb7,0x26,0xb7,0x22,0x7f,0x23,0x72,0x23,0x7f, + 0x24,0x7f,0x24,0x7f,0x25,0x7f,0x25,0x7f,0x02,0x2a,0xfb,0xe7,0x25,0x7f,0x1b,0x7e, + 0x1c,0x79,0x24,0x7d,0x25,0x7c,0x25,0x7b,0x26,0x7a,0x26,0xf0,0x26,0x7f,0x26,0x7f, + 0x1d,0x7f,0x1d,0x7f,0x1e,0x7f,0x02,0x2a,0xfb,0xe7,0x24,0x7f,0x25,0x7f,0x09,0xa7, + 0x07,0x2a,0x13,0xe8,0x24,0x7f,0x87,0x2c,0x27,0x16,0x0d,0xa6,0x0d,0xb7,0x12,0x01, + 0x0c,0xa7,0x0c,0xb1,0x22,0x01,0x0b,0xa7,0x0b,0xb1,0x82,0x3f,0x0a,0xa7,0x0a,0xb2, + 0x17,0x60,0x2e,0xb7,0x2e,0xa7,0x07,0x2a,0xfd,0xe7,0x1b,0x7f,0x1c,0x7f,0x1c,0x7f, + 0x1d,0x72,0x1d,0x7f,0x1e,0x7f,0x1e,0x7f,0x0e,0xa7,0x07,0x2a,0xd7,0xef,0x1d,0x7f, + 0x16,0x60,0x02,0x77,0x17,0xb6,0x69,0x00,0xf0,0x21,0xcf,0x00,0x20,0xaa,0x00,0x00, + 0x32,0xaa,0x00,0x00,0x58,0x09,0x00,0x00,0x00,0x9c,0x00,0x00,0x8e,0x31,0x00,0x00, + 0x94,0x3b,0x00,0x00,0xd0,0x3c,0x00,0x00,0xea,0x3c,0x00,0x00,0x16,0x3c,0x00,0x00, + 0x7c,0x3c,0x00,0x00,0x33,0xaa,0x00,0x00,0x34,0xaa,0x00,0x00,0x35,0xaa,0x00,0x00, + 0x36,0xaa,0x00,0x00,0x8e,0x23,0x00,0x00,0x5e,0x31,0x00,0x00,0x70,0x3b,0x00,0x00, + 0xfc,0x0c,0x00,0x00,0x96,0x3b,0x00,0x00,0xf4,0x3c,0x00,0x00,0x5c,0x4f,0x00,0x00, + 0xf6,0x63,0x00,0x00,0x70,0xa8,0x00,0x00,0x3a,0x48,0x00,0x00,0x30,0x0e,0x00,0x00, + 0xee,0x0a,0x00,0x00,0x74,0x09,0x00,0x00,0xf0,0x25,0x79,0x00,0x02,0x60,0x34,0x7f, + 0x35,0x7e,0x0d,0x60,0x2e,0xbd,0x5e,0xbd,0x34,0x72,0x34,0x7f,0x1e,0xbd,0x34,0x7d, + 0x35,0x7c,0x35,0x7b,0x36,0x7a,0x19,0x60,0x20,0xf0,0x35,0x7f,0x36,0x7f,0x36,0x7f, + 0x37,0x7f,0x37,0x7f,0x02,0x2a,0xfb,0xe7,0x37,0x7f,0x37,0x7f,0x38,0x7f,0x87,0x2c, + 0x27,0x16,0x0d,0xa6,0x0d,0xb7,0x12,0x01,0x0c,0xa7,0x0c,0xb1,0x22,0x01,0x0b,0xa7, + 0x0b,0xb1,0x82,0x3f,0x0a,0xa7,0x0a,0xb2,0x2e,0xb9,0x04,0xf0,0x29,0x7f,0x0e,0xa7, + 0x17,0x2a,0x03,0xe0,0x2e,0xa7,0x07,0x2a,0xf9,0xe7,0x0e,0xa7,0x17,0x2a,0xdd,0xef, + 0x06,0x60,0x1c,0x77,0x27,0xb6,0x69,0x00,0xf0,0x21,0xcf,0x00,0xf0,0x25,0x78,0x00, + 0x02,0x60,0x17,0x7f,0x18,0x7e,0x0d,0x60,0x2e,0xbd,0x5e,0xbd,0x17,0x72,0x17,0x7f, + 0x1e,0xbd,0xed,0x12,0x23,0x7c,0x23,0x7b,0x24,0x7a,0x24,0x79,0x25,0x78,0x17,0xf0, + 0x18,0x7f,0x0c,0xbe,0x0b,0xa7,0x17,0x3e,0x47,0x34,0x0a,0xb7,0x09,0xbe,0x07,0x60, + 0x08,0xd7,0x20,0x76,0x21,0x77,0x07,0xd6,0x17,0x60,0x2d,0xb7,0x04,0xf0,0x10,0x7f, + 0x0d,0xa7,0x27,0x2a,0x03,0xe0,0x2d,0xa7,0x07,0x2a,0xf9,0xe7,0x13,0x7f,0x0d,0xae, + 0x2e,0x2a,0xe6,0xef,0x06,0x60,0x03,0x77,0x27,0xb6,0x68,0x00,0xf0,0x21,0xcf,0x00, + 0xa8,0x08,0x00,0x00,0x20,0xaa,0x00,0x00,0x00,0x9c,0x00,0x00,0x8e,0x31,0x00,0x00, + 0x33,0xaa,0x00,0x00,0x34,0xaa,0x00,0x00,0x35,0xaa,0x00,0x00,0x36,0xaa,0x00,0x00, + 0x8e,0x23,0x00,0x00,0x5e,0x31,0x00,0x00,0xd0,0x3c,0x00,0x00,0xea,0x3c,0x00,0x00, + 0x16,0x3c,0x00,0x00,0x70,0x3b,0x00,0x00,0xfc,0x0c,0x00,0x00,0x96,0x3b,0x00,0x00, + 0x5c,0x08,0x04,0x00,0x2a,0x9c,0x00,0x00,0x5d,0x08,0x04,0x00,0x74,0x08,0x04,0x00, + 0xa8,0x08,0x04,0x00,0xfc,0x7f,0x00,0x00,0xaa,0x08,0x04,0x00,0x02,0x01,0x78,0x76, + 0x06,0x87,0x78,0x74,0x47,0x1e,0x06,0x97,0x11,0x2a,0x77,0x77,0x07,0xa6,0x1a,0xe0, + 0x77,0x75,0x56,0x16,0x07,0xb6,0x76,0x76,0x06,0xa7,0x57,0x16,0x06,0xb7,0x75,0x76, + 0x06,0xa7,0x57,0x16,0x06,0xb7,0x74,0x77,0x07,0xb1,0x36,0x60,0x74,0x77,0x07,0xb6, + 0x74,0x75,0x05,0xa7,0x6e,0x74,0x47,0x16,0x05,0xb7,0x72,0x75,0x05,0xa7,0x47,0x16, + 0x05,0xb7,0x32,0xf0,0x21,0x2a,0x1a,0xe0,0x69,0x75,0x56,0x16,0x07,0xb6,0x68,0x76, + 0x06,0xa7,0x07,0x34,0x06,0xb7,0x67,0x76,0x06,0xa7,0x57,0x16,0x06,0xb7,0x16,0x60, + 0x66,0x77,0x07,0xb6,0x35,0x60,0x65,0x77,0x07,0xb5,0x65,0x75,0x05,0xa7,0x5f,0x74, + 0x47,0x16,0x05,0xb7,0x64,0x77,0x07,0xb6,0xb6,0x63,0x16,0xf0,0x41,0x2a,0x0d,0xe0, + 0x5b,0x75,0x56,0x16,0x07,0xb6,0x5a,0x77,0x07,0xa7,0x07,0x34,0x5a,0x76,0x06,0xb7, + 0x16,0x60,0x5c,0x77,0x07,0xb6,0xb6,0x66,0x07,0xf0,0x54,0x74,0x46,0x16,0x07,0xb6, + 0x16,0x60,0x58,0x77,0x07,0xb6,0xb6,0x60,0x58,0x77,0x07,0xb6,0x16,0x60,0x57,0x77, + 0x07,0x96,0xcf,0x00,0xc6,0x32,0x56,0x77,0x07,0x96,0x66,0x60,0x56,0x77,0x07,0xb6, + 0x06,0x60,0x55,0x77,0x07,0x96,0x55,0x77,0x16,0x60,0x07,0xb6,0x07,0xa6,0x06,0x2a, + 0xfd,0xe7,0xcf,0x00,0x02,0x01,0x52,0x76,0x4e,0x77,0x07,0x96,0x57,0x63,0x01,0x2a, + 0x01,0xe0,0x57,0x60,0x4c,0x76,0x06,0xb7,0x16,0x60,0x4b,0x77,0x07,0x96,0x4b,0x77, + 0x07,0xb6,0x07,0xa6,0x06,0x2a,0xfd,0xe7,0x4b,0x72,0x02,0xa2,0xcf,0x00,0x70,0x24, + 0x00,0x9f,0x49,0x7f,0x4a,0x76,0x42,0x77,0x07,0x96,0x16,0x60,0x42,0x77,0x07,0xb6, + 0x05,0x60,0x41,0x77,0x07,0x95,0x46,0x75,0x47,0x77,0x07,0xd5,0x40,0x77,0x07,0xb6, + 0x07,0xa6,0x06,0x2a,0xfd,0xe7,0x02,0x60,0x44,0x7f,0x12,0x2e,0x02,0x2a,0xfb,0xe7, + 0x00,0x8f,0x70,0x20,0xcf,0x00,0x05,0x01,0x11,0x2a,0x07,0xe8,0x21,0x2a,0x08,0xe8, + 0x41,0x2a,0x09,0xe0,0x3e,0x76,0xb7,0x66,0x08,0xf0,0x3d,0x76,0x37,0x60,0x05,0xf0, + 0x3d,0x76,0xb7,0x63,0x02,0xf0,0x3c,0x76,0xb7,0x60,0x2d,0x75,0x05,0x96,0x2d,0x76, + 0x06,0xb7,0x3a,0x77,0x07,0x93,0x3a,0x77,0x07,0x92,0x2b,0x77,0x07,0x94,0x2b,0x77, + 0x16,0x60,0x07,0xb6,0x07,0xa6,0x06,0x2a,0xfd,0xe7,0xcf,0x00,0xf0,0x24,0x7d,0x00, + 0x3d,0x12,0x2e,0x12,0x4e,0x01,0x28,0x7f,0x0e,0x2a,0x22,0x77,0x06,0xe0,0x31,0x76, + 0x07,0xb6,0xc6,0x32,0x1f,0x77,0x07,0x96,0x12,0xf0,0x1e,0x2a,0x06,0xe0,0x26,0x65, + 0x07,0xb6,0x2d,0x76,0x1b,0x77,0x07,0x96,0x08,0xf0,0x04,0x62,0x2e,0x2a,0x18,0x76, + 0x2a,0x75,0x01,0xe0,0x2a,0x74,0x07,0xb4,0x06,0x95,0x24,0x77,0x07,0x9d,0x06,0x60, + 0x16,0x77,0x07,0x96,0x16,0x77,0x16,0x60,0x07,0xb6,0x07,0xa6,0x06,0x2a,0xfd,0xe7, + 0x02,0x60,0x19,0x7f,0x12,0x2e,0x02,0x2a,0xfb,0xe7,0x6d,0x00,0xf0,0x20,0xcf,0x00, + 0x00,0x06,0x04,0x00,0x00,0x00,0x00,0x15,0x04,0x06,0x04,0x00,0xfe,0x00,0x00,0x00, + 0x08,0x06,0x04,0x00,0x0c,0x06,0x04,0x00,0x10,0x06,0x04,0x00,0x14,0x06,0x04,0x00, + 0x18,0x06,0x04,0x00,0x1c,0x06,0x04,0x00,0x20,0x06,0x04,0x00,0x28,0x06,0x04,0x00, + 0x2c,0x06,0x04,0x00,0x30,0x06,0x04,0x00,0x40,0x06,0x04,0x00,0x44,0x06,0x04,0x00, + 0x00,0x10,0x08,0x00,0x48,0x06,0x04,0x00,0x74,0x1e,0x00,0x00,0x20,0x10,0x00,0x00, + 0x02,0x02,0x00,0x00,0x38,0x06,0x04,0x00,0x94,0x1e,0x00,0x00,0x01,0x1d,0x18,0x00, + 0x00,0x13,0x18,0x00,0x01,0x1d,0x1a,0x00,0x01,0x13,0x18,0x00,0x34,0x06,0x04,0x00, + 0x3c,0x06,0x04,0x00,0xc7,0xff,0xff,0xff,0x00,0x13,0x00,0x00,0xd8,0xff,0xff,0xff, + 0xf0,0x25,0x78,0x00,0x70,0x24,0x38,0x12,0x4c,0x12,0x05,0x01,0x2a,0x60,0x01,0x2a, + 0x03,0xe8,0x11,0x2a,0x01,0xe0,0x74,0x7a,0x2b,0x12,0x0e,0x60,0x74,0x79,0x24,0xf0, + 0x02,0x60,0x73,0x7f,0x12,0x2e,0x02,0x2a,0xfb,0xe7,0x72,0x7f,0x73,0x77,0x73,0x76, + 0x06,0x97,0x73,0x76,0x06,0x9b,0x00,0x86,0x73,0x77,0x07,0x96,0x87,0x32,0xd7,0x1c, + 0x7c,0x0c,0x03,0xe8,0x87,0x32,0x09,0xd7,0x03,0xf0,0xcd,0x14,0x6d,0x01,0x09,0xdd, + 0x6e,0x77,0x07,0xba,0x6e,0x77,0x16,0x60,0x07,0xb6,0x86,0x32,0x6b,0x1c,0x07,0xa6, + 0x06,0x2a,0xfd,0xe7,0x87,0x32,0x7e,0x1c,0xe6,0x12,0x86,0x1c,0x00,0x96,0xed,0x12, + 0x6d,0x01,0xcd,0x0c,0xd5,0xef,0x02,0x60,0x5e,0x7f,0x12,0x2e,0x02,0x2a,0xfb,0xe7, + 0x70,0x20,0x68,0x00,0xf0,0x21,0xcf,0x00,0x02,0x01,0x01,0x2a,0x61,0x76,0x06,0xa7, + 0x04,0xe0,0x07,0x30,0x17,0x30,0x07,0x34,0x02,0xf0,0x5e,0x75,0x57,0x16,0x06,0xb7, + 0xcf,0x00,0x02,0x01,0x87,0x60,0x17,0x0c,0x06,0xe8,0x5b,0x77,0x07,0xc6,0x11,0x13, + 0x61,0x1e,0x61,0x01,0x07,0xd1,0xcf,0x00,0x02,0x01,0x87,0x60,0x17,0x0c,0x05,0xe8, + 0x56,0x76,0x06,0xc7,0x11,0x13,0x17,0x1f,0x06,0xd7,0xcf,0x00,0x02,0x01,0x43,0x01, + 0x87,0x60,0x17,0x0c,0x0a,0xe8,0x03,0x2a,0x51,0x77,0x11,0x13,0x07,0xc6,0x03,0xe8, + 0x16,0x1e,0x66,0x01,0x01,0xf0,0x16,0x1f,0x07,0xd6,0xcf,0x00,0x02,0x01,0x43,0x01, + 0x87,0x60,0x17,0x0c,0x0a,0xe8,0x03,0x2a,0x4a,0x77,0x11,0x13,0x07,0xc6,0x03,0xe8, + 0x16,0x1e,0x66,0x01,0x01,0xf0,0x16,0x1f,0x07,0xd6,0xcf,0x00,0x02,0x01,0x43,0x01, + 0x87,0x60,0x17,0x0c,0x0a,0xe8,0x03,0x2a,0x43,0x77,0x11,0x13,0x07,0xc6,0x03,0xe8, + 0x16,0x1e,0x66,0x01,0x01,0xf0,0x16,0x1f,0x07,0xd6,0xcf,0x00,0x02,0x01,0x82,0x2c, + 0x87,0x60,0x17,0x0c,0x08,0xe8,0x3c,0x76,0x06,0xc6,0x17,0x13,0x67,0x16,0x47,0x01, + 0x17,0x1a,0x72,0x12,0x42,0x01,0xcf,0x00,0x02,0x01,0x77,0x60,0x17,0x0c,0x0a,0xe8, + 0x37,0x76,0x06,0xc7,0x11,0x13,0x17,0x1f,0x06,0xd7,0x35,0x76,0x06,0xc7,0x17,0x1e, + 0x67,0x01,0x06,0xd7,0xcf,0x00,0x02,0x01,0x77,0x60,0x17,0x0c,0x0a,0xe8,0x30,0x76, + 0x06,0xc7,0x11,0x13,0x17,0x1f,0x06,0xd7,0x2d,0x76,0x06,0xc7,0x17,0x1e,0x67,0x01, + 0x06,0xd7,0xcf,0x00,0x70,0x25,0x7a,0x00,0x2e,0x12,0x4e,0x01,0x82,0x2c,0x77,0x60, + 0xe7,0x0c,0x26,0xe8,0x21,0x7d,0x0d,0xcd,0x21,0x7c,0x0c,0xcc,0x24,0x7b,0x0b,0xcb, + 0x24,0x7a,0x0a,0xca,0xe2,0x12,0x23,0x7f,0xe2,0x12,0x03,0x60,0x23,0x7f,0xe2,0x12, + 0x23,0x7f,0x42,0x66,0x23,0x7f,0xe2,0x12,0x23,0x7f,0x02,0x2a,0x09,0xe8,0xe2,0x12, + 0x22,0x7f,0x42,0x66,0x1f,0x7f,0xe2,0x12,0x1f,0x7f,0x02,0x2a,0x32,0x00,0x02,0x20, + 0x12,0x77,0x07,0xdd,0x12,0x77,0x07,0xdc,0x15,0x77,0x07,0xdb,0x15,0x77,0x07,0xda, + 0x6a,0x00,0x70,0x21,0xcf,0x00,0x00,0x00,0xf2,0x00,0x00,0x00,0x40,0x06,0x04,0x00, + 0x94,0x1e,0x00,0x00,0x74,0x1e,0x00,0x00,0x00,0x13,0x00,0x00,0x2c,0x06,0x04,0x00, + 0x34,0x06,0x04,0x00,0x3c,0x06,0x04,0x00,0x30,0x06,0x04,0x00,0x44,0x06,0x04,0x00, + 0x58,0x01,0x04,0x00,0xfc,0x00,0x00,0x00,0x1c,0x04,0x04,0x00,0x20,0x04,0x04,0x00, + 0x24,0x04,0x04,0x00,0x08,0x04,0x04,0x00,0x28,0x04,0x04,0x00,0x38,0x04,0x04,0x00, + 0x3c,0x04,0x04,0x00,0xc2,0x20,0x00,0x00,0xec,0x20,0x00,0x00,0x68,0x21,0x00,0x00, + 0xe0,0x0a,0x00,0x00,0x4c,0x21,0x00,0x00,0x86,0x21,0x00,0x00,0xf0,0x24,0x7d,0x00, + 0x2e,0x12,0x4e,0x01,0x3d,0x12,0x4d,0x01,0x87,0x60,0xe7,0x0c,0x12,0xe8,0xe2,0x12, + 0x03,0x60,0x5f,0x7f,0x60,0x76,0x06,0xc7,0xee,0x13,0xe5,0x12,0x65,0x01,0x57,0x1e, + 0x06,0xd7,0x0d,0x2a,0x5d,0x77,0x07,0xc6,0x02,0xe8,0x56,0x1e,0x01,0xf0,0xe6,0x1f, + 0x07,0xd6,0x6d,0x00,0xf0,0x20,0xcf,0x00,0x02,0x01,0x21,0x2a,0x08,0xe0,0x57,0x76, + 0x06,0xa7,0x17,0x34,0x06,0xb7,0x56,0x76,0x06,0xa7,0x17,0x34,0x06,0xb7,0x55,0x76, + 0x06,0xa7,0x55,0x75,0x57,0x1e,0x06,0xb7,0x55,0x76,0x06,0xa7,0x57,0x1e,0x06,0xb7, + 0x54,0x76,0x06,0xa7,0x57,0x1e,0x06,0xb7,0x66,0x60,0x52,0x77,0x07,0xb6,0x52,0x76, + 0x06,0x87,0xa7,0x34,0x06,0x97,0x16,0x60,0x51,0x77,0x07,0xb6,0x51,0x76,0x06,0xa7, + 0x07,0x34,0x06,0xb7,0x50,0x76,0x06,0x87,0x50,0x75,0x57,0x1e,0x06,0x97,0x4f,0x76, + 0x06,0x87,0x4f,0x75,0x57,0x1e,0x06,0x97,0x4f,0x77,0x07,0xa6,0x16,0x34,0x07,0xb6, + 0x07,0xa6,0x06,0x34,0x07,0xb6,0xcf,0x00,0x02,0x01,0x4a,0x77,0x07,0xa6,0x4a,0x75, + 0x56,0x16,0x07,0xb6,0x07,0xa6,0x49,0x75,0x56,0x16,0x07,0xb6,0x06,0x60,0x3f,0x77, + 0x07,0xb6,0x40,0x76,0x06,0x87,0x46,0x75,0x57,0x16,0x06,0x97,0x40,0x76,0x06,0x87, + 0x45,0x75,0x57,0x16,0x06,0x97,0x3a,0x76,0x06,0xa7,0x3f,0x75,0x57,0x16,0x06,0xb7, + 0x21,0x2a,0x09,0xe0,0x2e,0x76,0x06,0xa7,0x3d,0x75,0x57,0x16,0x06,0xb7,0x2c,0x76, + 0x06,0xa7,0x57,0x16,0x06,0xb7,0xcf,0x00,0x70,0x24,0x7e,0x00,0x2e,0x12,0x4e,0x01, + 0xe2,0x12,0x39,0x7f,0xe2,0x12,0x39,0x7f,0x6e,0x00,0x70,0x20,0xcf,0x00,0x38,0x76, + 0x39,0x77,0x07,0xd6,0xcf,0x00,0x06,0x60,0x37,0x77,0x07,0xd6,0xcf,0x00,0x36,0x77, + 0x16,0x60,0x07,0xb6,0x36,0x76,0x07,0xb6,0xcf,0x00,0xf0,0x24,0x7d,0x00,0x2d,0x12, + 0x3e,0x12,0x4e,0x01,0x32,0x60,0x0e,0x2a,0x0b,0xe8,0x52,0x60,0x4e,0x2a,0x08,0xe8, + 0x5e,0x2a,0x03,0xe0,0x12,0x60,0x23,0x12,0x04,0xf0,0x7e,0x2a,0x14,0xe0,0x22,0x60, + 0x13,0x60,0x2b,0x7f,0xe2,0x12,0x2b,0x7f,0xd2,0x12,0x2b,0x73,0x2c,0x7f,0x62,0x01, + 0x2c,0x77,0x07,0xd2,0x2c,0x77,0x07,0xd2,0x16,0x61,0x2b,0x77,0x07,0xb6,0x2b,0x76, + 0x06,0xa7,0x07,0x34,0x06,0xb7,0x6d,0x00,0xf0,0x20,0xcf,0x00,0x02,0x01,0x28,0x77, + 0x07,0xb1,0x28,0x76,0x06,0xa7,0x17,0x2e,0x07,0x2a,0xfc,0xe7,0xcf,0x00,0x00,0x00, + 0xec,0x20,0x00,0x00,0x40,0x04,0x04,0x00,0x44,0x04,0x04,0x00,0x21,0x0e,0x04,0x00, + 0x25,0x0e,0x04,0x00,0x1c,0x04,0x04,0x00,0xa7,0x00,0x00,0x00,0x20,0x04,0x04,0x00, + 0x38,0x04,0x04,0x00,0x61,0x01,0x04,0x00,0x04,0x00,0x04,0x00,0x40,0x01,0x04,0x00, + 0x0b,0x00,0x04,0x00,0x0c,0x01,0x04,0x00,0x00,0x00,0x0f,0x00,0x04,0x01,0x04,0x00, + 0x03,0x20,0x00,0x00,0x44,0x01,0x04,0x00,0xfe,0x00,0x00,0x00,0xfd,0x00,0x00,0x00, + 0xff,0xff,0xf0,0xff,0xfc,0xdf,0xff,0xff,0xa8,0x22,0x00,0x00,0x18,0x23,0x00,0x00, + 0x10,0x02,0x00,0x00,0x24,0x00,0x04,0x00,0x26,0x00,0x04,0x00,0xfe,0xff,0xff,0xff, + 0x2c,0x21,0x00,0x00,0xd8,0x20,0x00,0x00,0x00,0xc2,0x01,0x00,0xd0,0x83,0x00,0x00, + 0x22,0x02,0x04,0x00,0x32,0x02,0x04,0x00,0x30,0x02,0x04,0x00,0x20,0x02,0x04,0x00, + 0x24,0x02,0x04,0x00,0x28,0x02,0x04,0x00,0xf0,0x25,0x78,0x00,0x01,0x63,0x10,0x05, + 0x3c,0x12,0x4a,0x12,0x4a,0x01,0x59,0x12,0x49,0x01,0x09,0x2a,0x27,0x00,0xa0,0x97, + 0xa6,0x12,0x06,0x24,0x46,0x01,0xf7,0x60,0x67,0x0c,0x07,0xe0,0xa7,0x62,0x03,0xb7, + 0x07,0x60,0x13,0xb7,0x32,0x12,0x12,0x20,0x4d,0xf0,0x0b,0x60,0xf2,0x37,0x03,0xe8, + 0xaa,0x2a,0x4d,0xe8,0x2b,0x60,0x2d,0x12,0x2b,0x2a,0x4c,0xe0,0x5a,0x77,0x26,0x12, + 0xf6,0x2e,0x67,0x1c,0x07,0xa7,0x00,0xb7,0x4d,0x3e,0x1e,0x60,0x08,0x12,0xe8,0x1c, + 0x13,0xf0,0xd2,0x12,0xa3,0x12,0x54,0x7f,0x53,0x77,0x72,0x1c,0x02,0xa7,0x08,0xb7, + 0x08,0x20,0x0e,0x20,0x4e,0x01,0xd2,0x12,0xa3,0x12,0x50,0x7f,0x2d,0x12,0xa0,0x87, + 0x07,0x2a,0x02,0xe8,0x9e,0x0c,0x04,0xe0,0x0d,0x2a,0xeb,0xe7,0x08,0x0f,0xe9,0xef, + 0x1b,0x2a,0x05,0xe0,0xd7,0x62,0x08,0xb7,0x08,0x20,0x0e,0x20,0x4e,0x01,0xa0,0x87, + 0x07,0x2a,0x06,0xe8,0x08,0xf0,0x08,0xb7,0x08,0x20,0x0e,0x20,0x4e,0x01,0x04,0xf0, + 0x86,0x12,0xc7,0x12,0x08,0xf0,0x07,0x62,0x9e,0x0c,0xf5,0xef,0xf9,0xf7,0x06,0x24, + 0x06,0xa5,0x07,0xb5,0x07,0x20,0x06,0x0f,0xfa,0xe7,0x82,0x12,0x02,0x05,0xc2,0x1c, + 0x07,0x60,0x02,0xb7,0x01,0x63,0x10,0x1c,0x68,0x00,0xf0,0x21,0xcf,0x00,0x2d,0x12, + 0x0d,0x28,0x1b,0x60,0x0e,0x60,0x08,0x12,0xcf,0xf7,0x81,0x63,0x10,0x05,0xd0,0x97, + 0xc0,0x96,0xb0,0x95,0xa0,0x94,0x90,0x93,0x80,0x92,0x78,0x00,0xf0,0x25,0x07,0x64, + 0x07,0x1c,0x07,0x8e,0x4d,0x64,0x0d,0x1c,0x0c,0x60,0x59,0x62,0x4a,0x64,0x4a,0xf0, + 0x97,0x0f,0x0a,0xe8,0x0c,0x2a,0x08,0xe0,0xa7,0x2a,0x02,0xe0,0xd2,0x60,0x28,0x7f, + 0x0e,0xa2,0x0e,0x20,0x27,0x7f,0x3e,0xf0,0x1e,0xa2,0xa2,0x0f,0x18,0xe8,0x2a,0x0c, + 0x06,0xe8,0x24,0x76,0x26,0x1c,0x87,0x60,0x67,0x0c,0x2f,0xe8,0x0a,0xf0,0x47,0x66, + 0x72,0x0f,0x0d,0xe8,0x87,0x67,0x72,0x0f,0x19,0xe8,0x87,0x65,0x72,0x0f,0x25,0xe0, + 0x15,0xf0,0x0e,0x20,0x1d,0x77,0x72,0x1c,0x2c,0x12,0x4c,0x01,0x23,0xf0,0xdb,0x12, + 0x3b,0x20,0x0d,0x82,0x03,0x12,0xa4,0x60,0xc5,0x12,0x18,0x7f,0x08,0x12,0x02,0xf0, + 0x14,0x7f,0x08,0x20,0x08,0xa2,0x02,0x2a,0xfb,0xe7,0x11,0xf0,0xdb,0x12,0x3b,0x20, + 0x0d,0x82,0x03,0x12,0x04,0x61,0xc5,0x12,0x11,0x7f,0x08,0x12,0x02,0xf0,0x0c,0x7f, + 0x08,0x20,0x08,0xa2,0x02,0x2a,0xfb,0xe7,0x02,0xf0,0x09,0x7f,0xdb,0x12,0x1e,0x20, + 0xbd,0x12,0x0c,0x60,0x0e,0xa7,0x07,0x2a,0xb3,0xe7,0xf0,0x21,0x68,0x00,0x81,0x63, + 0x10,0x1c,0xcf,0x00,0xe4,0x06,0x00,0x00,0x08,0x84,0x00,0x00,0xd0,0x83,0x00,0x00, + 0xec,0x23,0x00,0x00,0xcf,0xff,0xff,0xff,0xd0,0xff,0xff,0xff,0x98,0x24,0x00,0x00, + 0x10,0x76,0x06,0xa7,0x10,0x75,0x57,0x16,0x06,0xb7,0xcf,0x00,0x0f,0x75,0x05,0xc5, + 0x45,0x01,0xf7,0x61,0x57,0x0c,0x12,0xe8,0x0d,0x77,0x07,0xc7,0xf7,0x01,0x47,0x01, + 0x75,0x0f,0x0c,0xe0,0x07,0xf0,0x07,0x84,0x47,0xa3,0x04,0xb3,0x06,0x20,0x46,0x01, + 0x77,0x20,0x02,0xf0,0x07,0x77,0x06,0x60,0x56,0x0c,0xf5,0xef,0xcf,0x00,0x00,0x00, + 0x04,0x00,0x04,0x00,0xfe,0x00,0x00,0x00,0x00,0xf0,0x10,0x00,0x02,0xf0,0x10,0x00, + 0x04,0xf0,0x10,0x00,0x70,0x24,0x7e,0x00,0xb2,0x71,0x01,0x8f,0xff,0x34,0x01,0x9f, + 0xb1,0x71,0x01,0x8f,0x1f,0x34,0x01,0x9f,0xb0,0x7e,0x0e,0xb2,0xb0,0x72,0x02,0xb3, + 0xb0,0x73,0x03,0x95,0xb0,0x75,0x05,0x96,0xb0,0x76,0x06,0x97,0xb0,0x77,0x20,0x86, + 0x07,0x96,0xaf,0x77,0x07,0xb4,0x01,0x87,0x07,0x34,0x01,0x97,0xae,0x76,0x06,0x87, + 0x17,0x2e,0x07,0x2a,0xfc,0xe7,0xa2,0x76,0x06,0x87,0xf7,0x34,0x06,0x97,0xa1,0x76, + 0x06,0x87,0x17,0x30,0x06,0x97,0x6e,0x00,0x70,0x20,0xcf,0x00,0x70,0x24,0x7e,0x00, + 0x2e,0x12,0x32,0x12,0xf2,0x3c,0x03,0x60,0x35,0x12,0xa3,0x7f,0xa4,0x74,0x05,0x60, + 0xa4,0x7f,0x62,0x01,0x0e,0x2a,0x02,0xe0,0xa3,0x77,0x13,0xf0,0x1e,0x2a,0x04,0xe8, + 0x2e,0x2a,0x04,0xe0,0xa0,0x77,0x07,0xd2,0xa0,0x77,0x0b,0xf0,0x3e,0x2a,0x02,0xe0, + 0x9f,0x77,0x07,0xf0,0x4e,0x2a,0x04,0xe8,0x5e,0x2a,0x04,0xe0,0x9c,0x77,0x07,0xd2, + 0x9c,0x77,0x07,0xd2,0x6e,0x00,0x70,0x20,0xcf,0x00,0x70,0x24,0x7e,0x00,0x2e,0x12, + 0x99,0x72,0x99,0x7f,0x0e,0x2a,0x03,0xe0,0x62,0x01,0x98,0x77,0x09,0xf0,0x1e,0x2a, + 0x03,0xe0,0x62,0x01,0x97,0x77,0x04,0xf0,0x2e,0x2a,0x03,0xe0,0x62,0x01,0x95,0x77, + 0x07,0xd2,0x6e,0x00,0x70,0x20,0xcf,0x00,0x94,0x75,0x95,0xa6,0x06,0x2a,0x93,0x77, + 0x01,0xe8,0x16,0x60,0x07,0xb6,0x05,0xa6,0x15,0xa7,0x87,0x3c,0x67,0x1e,0x25,0xa6, + 0x06,0x3d,0x76,0x1e,0x35,0xa7,0x87,0x3d,0x67,0x1e,0x8d,0x76,0x67,0x0f,0x02,0xe0, + 0x8d,0x76,0x04,0xf0,0x8d,0x76,0x67,0x0f,0x03,0xe0,0x8c,0x76,0x8d,0x77,0x07,0xd6, + 0x86,0x77,0xa7,0xa6,0xb7,0xa7,0x87,0x3c,0x67,0x1e,0x8a,0x76,0x06,0xd7,0x6c,0x76, + 0x06,0x87,0xf7,0x34,0x06,0x97,0x88,0x77,0x07,0x86,0x16,0x34,0x07,0x96,0x07,0x86, + 0x06,0x34,0x07,0x96,0x70,0x76,0x06,0x87,0x87,0x2e,0x07,0x2a,0xfc,0xe7,0x64,0x76, + 0x06,0x87,0xf7,0x34,0x06,0x97,0x80,0x76,0x06,0x87,0x17,0x30,0x06,0x97,0xcf,0x00, + 0x70,0x25,0x7a,0x00,0x75,0x77,0x0d,0x60,0x97,0xbd,0x7c,0x7e,0x07,0xbe,0x1e,0x01, + 0x17,0xb1,0x2e,0x01,0x27,0xb1,0xe6,0x12,0x86,0x3f,0x37,0xb6,0x79,0x76,0x26,0xac, + 0x8b,0x2c,0xcb,0x16,0xa7,0xbb,0x06,0x60,0xb7,0xb6,0x76,0x7f,0x77,0x74,0x04,0xa6, + 0x14,0xa7,0x87,0x3c,0x67,0x1e,0x75,0x76,0x06,0xb7,0x87,0x3e,0x16,0xb7,0x74,0x77, + 0x07,0xbd,0x74,0x77,0x07,0xbd,0x74,0x77,0x07,0xad,0x74,0x77,0x07,0xa3,0x02,0x60, + 0x25,0x12,0x6f,0x12,0xa1,0x61,0x19,0xf0,0x57,0x12,0x57,0x1c,0x46,0x12,0x76,0x1c, + 0x26,0xaa,0xf7,0x1c,0x27,0xba,0x36,0xaa,0x37,0xba,0x26,0xa7,0x36,0xaa,0xf1,0x11, + 0x17,0x03,0xf9,0x11,0xa7,0x1c,0x77,0x1c,0xe7,0x1c,0x07,0xc7,0x72,0x0c,0x03,0xe0, + 0x26,0xad,0x36,0xa3,0x72,0x12,0x05,0x20,0x65,0x01,0x04,0xa6,0x14,0xa7,0x87,0x3c, + 0x67,0x1e,0x75,0x0c,0xe1,0xef,0x87,0x2c,0x27,0x16,0x5d,0x76,0x06,0xb7,0x82,0x3e, + 0x5d,0x76,0x06,0xb2,0x5d,0x76,0x06,0xbd,0x5d,0x76,0x06,0xb3,0x42,0x01,0x82,0x3c, + 0x72,0x1e,0x5b,0x77,0x07,0x8e,0x5b,0x77,0xe7,0x1c,0x07,0xa7,0xf1,0x11,0x72,0x03, + 0xf9,0x11,0x43,0x66,0x41,0x7f,0x2c,0x0c,0x58,0x77,0x06,0xe0,0x62,0x01,0x07,0xb2, + 0x82,0x3e,0x56,0x77,0x07,0xb2,0x04,0xf0,0x07,0xbb,0x54,0x77,0x06,0x60,0x07,0xb6, + 0x3e,0x76,0x17,0x60,0x96,0xb7,0x52,0x77,0xe7,0x1c,0x07,0xa5,0x52,0x77,0x7e,0x1c, + 0x0e,0xa7,0x87,0x3c,0x57,0x1e,0x07,0x3d,0x07,0x3b,0xe7,0x01,0x67,0x01,0x0e,0x60, + 0xa6,0xb7,0x87,0x3e,0xb6,0xb7,0x3f,0x7f,0x40,0x74,0x04,0xa6,0x14,0xa7,0x87,0x3c, + 0x67,0x1e,0x49,0x76,0x06,0xb7,0x87,0x3e,0x49,0x76,0x06,0xb7,0x49,0x77,0x07,0xbe, + 0x49,0x77,0x07,0xbe,0xe6,0x12,0x39,0x7d,0x35,0x72,0xa3,0x61,0x1b,0xf0,0x65,0x12, + 0x65,0x1c,0x45,0x1c,0x25,0xaf,0x07,0x67,0x67,0x1c,0x77,0x1c,0xd7,0x1c,0x27,0xbf, + 0x35,0xaf,0x37,0xbf,0x25,0xa7,0x35,0xa5,0xf1,0x11,0x37,0x03,0xf9,0x11,0x57,0x1c, + 0x77,0x1c,0x27,0x1c,0x07,0xc7,0x77,0x01,0xe7,0x01,0x67,0x01,0x7e,0x0c,0x7e,0x0a, + 0x06,0x20,0x66,0x01,0x04,0xa5,0x14,0xa7,0x87,0x3c,0x57,0x1e,0x76,0x0c,0xdf,0xef, + 0x34,0x77,0x07,0xbe,0x8e,0x3e,0x33,0x77,0x07,0xbe,0x6a,0x00,0x70,0x21,0xcf,0x00, + 0x08,0x00,0x04,0x00,0x30,0x0a,0x04,0x00,0x00,0x0a,0x04,0x00,0x01,0x0a,0x04,0x00, + 0x24,0x0a,0x04,0x00,0x28,0x0a,0x04,0x00,0x20,0x0a,0x04,0x00,0x2c,0x0a,0x04,0x00, + 0x02,0x0a,0x04,0x00,0x3c,0x0a,0x04,0x00,0xd2,0x84,0x00,0x00,0x80,0xc3,0xc9,0x01, + 0x34,0x85,0x00,0x00,0x50,0x08,0x04,0x00,0x52,0x08,0x04,0x00,0x6c,0x08,0x04,0x00, + 0x6e,0x08,0x04,0x00,0xa0,0x25,0x26,0x00,0xd0,0x83,0x00,0x00,0x9a,0x08,0x04,0x00, + 0x9e,0x08,0x04,0x00,0x96,0x08,0x04,0x00,0x7a,0x9e,0x00,0x00,0x47,0x0a,0x04,0x00, + 0x00,0xe0,0x02,0x00,0x36,0x50,0x00,0x00,0x00,0x00,0x03,0x00,0x36,0x60,0x00,0x00, + 0x40,0x0a,0x04,0x00,0x48,0x0a,0x04,0x00,0x50,0x0a,0x04,0x00,0x00,0xe0,0x02,0x00, + 0x86,0x9e,0x00,0x00,0x88,0x27,0x00,0x00,0x00,0x08,0x03,0x00,0x8a,0x9e,0x00,0x00, + 0x3e,0xa4,0x00,0x00,0x3f,0xa4,0x00,0x00,0x40,0xa4,0x00,0x00,0x41,0xa4,0x00,0x00, + 0x1c,0x9e,0x00,0x00,0xc0,0x00,0x00,0x00,0x44,0xa4,0x00,0x00,0x45,0xa4,0x00,0x00, + 0xb5,0x00,0x00,0x00,0xb6,0x00,0x00,0x00,0x6a,0x9f,0x00,0x00,0x6b,0x9f,0x00,0x00, + 0x42,0xa4,0x00,0x00,0x43,0xa4,0x00,0x00,0xf0,0x25,0x78,0x00,0x81,0x62,0x10,0x05, + 0x29,0x12,0x3c,0x12,0x58,0x12,0x58,0x1c,0x4d,0x12,0x0b,0x60,0xa0,0xf0,0x02,0x12, + 0x03,0x60,0x04,0x61,0x52,0x7f,0x06,0x12,0xf6,0x20,0x07,0x60,0x73,0x12,0x04,0x61, + 0x1e,0xf0,0x75,0x12,0x75,0x1c,0xd5,0x1c,0x05,0xc5,0x75,0x01,0x4d,0x72,0x52,0x0d, + 0x02,0xe8,0x06,0xb4,0x0c,0xf0,0x4b,0x72,0x25,0x0d,0x02,0xe8,0x06,0xb3,0x07,0xf0, + 0xf5,0x37,0x02,0xe8,0xf2,0x63,0x25,0x1c,0x65,0x3a,0x75,0x20,0x06,0xb5,0x06,0xa5, + 0x55,0x01,0x05,0x1c,0x05,0xa2,0x02,0x20,0x05,0xb2,0x07,0x20,0x06,0x20,0x07,0x01, + 0xc1,0x0c,0xdf,0xef,0x07,0x60,0x76,0x12,0x75,0x12,0x07,0x01,0x04,0x12,0x74,0x1c, + 0x04,0xa4,0x45,0x0c,0x16,0x0a,0x45,0x0a,0x07,0x20,0x07,0x2b,0xf6,0xe7,0x07,0x60, + 0x7a,0x12,0x75,0x12,0x07,0x01,0x04,0x12,0x74,0x1c,0x04,0xa4,0x45,0x0c,0x03,0xe0, + 0x61,0x0f,0x1a,0x02,0x45,0x02,0x07,0x20,0x07,0x2b,0xf4,0xe7,0x07,0x60,0x72,0x12, + 0x73,0x12,0x10,0xf0,0x05,0x61,0x05,0x1c,0x75,0x1c,0x05,0xa5,0x55,0x01,0x65,0x0f, + 0x08,0xe0,0x75,0x12,0x75,0x1c,0xd5,0x1c,0x05,0xc5,0x75,0x01,0x52,0x1c,0x03,0x20, + 0x43,0x01,0x07,0x20,0x07,0x01,0xc1,0x0c,0xed,0xef,0x03,0x2a,0x03,0xe8,0x26,0x7f, + 0x2e,0x12,0x01,0xf0,0x3e,0x12,0x25,0x76,0x06,0x87,0x62,0x67,0x27,0x1c,0x07,0xa6, + 0x07,0x60,0x72,0x12,0x73,0x12,0xe6,0x0d,0x11,0xe0,0x18,0xf0,0x06,0x61,0x06,0x1c, + 0x76,0x1c,0x06,0xa6,0x56,0x01,0xa6,0x0f,0x08,0xe0,0x76,0x12,0x76,0x1c,0xd6,0x1c, + 0x06,0xc6,0x76,0x01,0x62,0x1c,0x03,0x20,0x43,0x01,0x07,0x20,0x07,0x01,0xc1,0x0c, + 0xed,0xef,0x03,0x2a,0x03,0xe8,0x14,0x7f,0x2e,0x0d,0x2e,0x0a,0xd7,0x12,0x06,0x60, + 0x63,0x12,0x10,0xf0,0x07,0xc5,0x54,0x12,0x74,0x01,0xf4,0x37,0x02,0xe0,0x4e,0x0d, + 0x01,0xf0,0xe4,0x0d,0x03,0xe8,0xe5,0x05,0x07,0xd5,0x01,0xf0,0x07,0xd3,0x06,0x20, + 0x46,0x01,0x17,0x20,0xc6,0x0f,0xee,0xe7,0x0b,0x20,0x4b,0x01,0x8d,0x1c,0x9b,0x0f, + 0x5e,0xe7,0x81,0x62,0x10,0x1c,0x68,0x00,0xf0,0x21,0xcf,0x00,0x22,0x83,0x00,0x00, + 0xc0,0x01,0x00,0x00,0x40,0xfe,0xff,0xff,0x3e,0x84,0x00,0x00,0x1c,0x9e,0x00,0x00, + 0xf0,0x25,0x79,0x00,0x2a,0x12,0x39,0x12,0x83,0x7f,0x83,0x72,0xa3,0x12,0x83,0x7f, + 0x0d,0x60,0x83,0x7c,0x17,0xf0,0x9e,0x12,0xf1,0x11,0xde,0x03,0xf9,0x11,0xee,0x1c, + 0xae,0x1c,0x0b,0x60,0x07,0xf0,0x0e,0xc3,0x1e,0x20,0x7e,0x72,0x73,0x01,0x7b,0x7f, + 0x0b,0x20,0x6b,0x01,0x0c,0x87,0x57,0xa7,0x7b,0x0c,0xf5,0xef,0x7b,0x72,0x77,0x7f, + 0x0d,0x20,0x6d,0x01,0x0c,0x87,0x47,0xa7,0x7d,0x0c,0xe5,0xef,0x69,0x00,0xf0,0x21, + 0xcf,0x00,0xf0,0x25,0x79,0x00,0x70,0x24,0xc6,0x60,0x74,0x77,0x07,0xb6,0x0e,0x60, + 0xed,0x12,0x73,0x7b,0x74,0x7a,0x74,0x79,0x6e,0x7c,0x19,0xf0,0xe6,0x12,0xe6,0x1c, + 0xe6,0x1c,0x46,0x3c,0x09,0xa2,0x0c,0x87,0x57,0xa3,0x70,0x77,0x67,0x1e,0x00,0x97, + 0xf4,0x60,0x6f,0x75,0x70,0x77,0x76,0x1e,0x07,0x60,0x6f,0x7f,0xb7,0x12,0xd7,0x1c, + 0x26,0x62,0x67,0x1c,0x07,0xa7,0x7e,0x1c,0x4e,0x01,0x0d,0x20,0x4d,0x01,0x0a,0xa7, + 0x7d,0x0c,0xe4,0xef,0x5f,0x7e,0x0e,0x87,0x47,0xa2,0x57,0xa3,0x64,0x7c,0x65,0x7d, + 0x00,0x9d,0x24,0x60,0xc5,0x12,0x06,0x60,0x67,0x12,0x63,0x7f,0xc6,0x60,0x63,0x77, + 0x07,0xb6,0x0e,0x8e,0x4e,0xa2,0x5e,0xa3,0x00,0x9c,0xe4,0x60,0xd5,0x12,0x60,0x76, + 0x07,0x60,0x5d,0x7f,0x4e,0xa2,0x5e,0xa3,0x00,0x9d,0x24,0x60,0xc5,0x12,0x06,0x60, + 0x67,0x12,0x59,0x7f,0x70,0x20,0x69,0x00,0xf0,0x21,0xcf,0x00,0xf0,0x24,0x20,0x9f, + 0x30,0x9e,0x4b,0x77,0x07,0x8e,0x4e,0xa2,0x5e,0xa3,0x56,0x77,0x00,0x97,0x24,0x60, + 0x51,0x75,0x06,0x60,0x67,0x12,0x50,0x7f,0x54,0x77,0x7e,0x1c,0x0e,0xa7,0x07,0x2a, + 0x13,0xe8,0x47,0x77,0x17,0xa6,0x07,0xa7,0x76,0x1c,0x07,0x60,0x50,0x73,0x50,0x74, + 0x09,0xf0,0x75,0x12,0x75,0x1c,0x32,0x12,0x52,0x1c,0x45,0x1c,0x05,0xc5,0x02,0xd5, + 0x07,0x20,0x47,0x01,0x67,0x0d,0xf5,0xe7,0x20,0x8f,0x30,0x8e,0xf0,0x20,0xcf,0x00, + 0x70,0x25,0x7a,0x00,0x2a,0x12,0x3c,0x12,0x0d,0x60,0xde,0x12,0x46,0x7b,0x23,0xf0, + 0xa7,0x12,0xe7,0x1c,0x07,0xa7,0x07,0x2a,0x1c,0xe0,0xe6,0x12,0xe6,0x1c,0xc6,0x1c, + 0x26,0xa5,0x87,0x65,0xd7,0x1c,0x77,0x1c,0xb7,0x1c,0x87,0xb5,0x36,0xa6,0x97,0xb6, + 0xed,0x0f,0x0d,0xe8,0xd2,0x12,0x32,0x3c,0xd2,0x05,0xb2,0x1c,0xe3,0x12,0x33,0x3c, + 0xe3,0x05,0xb3,0x1c,0xa7,0x62,0x72,0x1c,0x73,0x1c,0x74,0x60,0x37,0x7f,0x0d,0x20, + 0x4d,0x01,0x0e,0x20,0x4e,0x01,0x0c,0xa6,0x1c,0xa7,0x87,0x3c,0x67,0x1e,0x7e,0x0c, + 0xd7,0xef,0x32,0x77,0x07,0xbd,0x32,0x77,0x06,0x60,0x07,0xb6,0x6a,0x00,0x70,0x21, + 0xcf,0x00,0x02,0x01,0x01,0x2b,0x0e,0xe0,0x1a,0x77,0x07,0x84,0x2e,0x77,0x2e,0x75, + 0x46,0x12,0x76,0x1c,0x2e,0x73,0x36,0x1c,0x06,0xa6,0x07,0xb6,0x07,0x20,0x57,0x0f, + 0xf7,0xe7,0x13,0xf0,0xf1,0x2e,0x27,0x77,0x14,0x60,0x27,0x75,0x07,0xa6,0x06,0x2a, + 0x03,0xe8,0x61,0x0c,0x06,0xe0,0x01,0xf0,0x06,0x62,0x16,0x05,0x46,0x01,0x07,0xb6, + 0x01,0xf0,0x07,0xb4,0x07,0x20,0x57,0x0f,0xf1,0xe7,0x07,0x60,0x1f,0x76,0x06,0xb7, + 0x20,0x76,0x06,0xb7,0x07,0x77,0x07,0x87,0x1f,0x76,0x67,0x1c,0x07,0xa6,0x1e,0x77, + 0x07,0xb6,0xcf,0x00,0x8e,0x23,0x00,0x00,0xf8,0x06,0x00,0x00,0x7a,0x25,0x00,0x00, + 0x1c,0x9e,0x00,0x00,0x04,0x07,0x00,0x00,0x0c,0x07,0x00,0x00,0x07,0x0a,0x04,0x00, + 0x20,0x9e,0x00,0x00,0x41,0x9e,0x00,0x00,0x42,0x9e,0x00,0x00,0x00,0x00,0x03,0x18, + 0x00,0x00,0x01,0x24,0x00,0x00,0x02,0x18,0xb4,0x26,0x00,0x00,0x06,0x0a,0x04,0x00, + 0x00,0x00,0x07,0x18,0x36,0x00,0x04,0x1a,0xc8,0x00,0x00,0x00,0x5e,0xa5,0x00,0x00, + 0xec,0xa4,0x00,0x00,0x8a,0x9e,0x00,0x00,0x8c,0x82,0x00,0x00,0x40,0x9f,0x00,0x00, + 0x41,0x9f,0x00,0x00,0x40,0x09,0x04,0x00,0x64,0x09,0x04,0x00,0xa8,0xf7,0xfb,0xff, + 0x65,0x09,0x04,0x00,0xcc,0x00,0x00,0x00,0x66,0x09,0x04,0x00,0x42,0x01,0x03,0x01, + 0x44,0x01,0x15,0x12,0x35,0x2e,0x55,0x1c,0x27,0x12,0x37,0x3c,0x27,0x1c,0x16,0x33, + 0x67,0x1c,0x21,0x3e,0x17,0x1c,0x07,0xa6,0x33,0x60,0x53,0x1b,0x36,0x1f,0x54,0x1b, + 0x46,0x1e,0x46,0x01,0x07,0xb6,0xcf,0x00,0xf0,0x25,0x78,0x00,0xf0,0x24,0x2d,0x12, + 0x4d,0x01,0x12,0x33,0x83,0x2c,0x80,0x74,0x81,0x7f,0x81,0x76,0x06,0x8e,0x4e,0xa1, + 0x00,0x91,0x0d,0x2a,0x14,0xe0,0x7f,0x75,0x05,0xa7,0x7f,0x74,0x47,0x16,0x05,0xb7, + 0xde,0x12,0x6d,0x12,0x07,0xf0,0xe7,0x1c,0xe2,0x12,0x67,0xa3,0x14,0x60,0x7b,0x7f, + 0x0e,0x20,0x4e,0x01,0x0d,0x87,0x47,0xa6,0x6e,0x0c,0xf5,0xef,0xc8,0xf0,0x2d,0x2a, + 0x3f,0xe0,0x74,0x76,0x06,0xa7,0x07,0x30,0x17,0x30,0x17,0x34,0x06,0xb7,0x6e,0xa5, + 0x16,0x61,0x07,0x60,0x56,0x0c,0x4e,0xa5,0x07,0xe8,0x11,0xf0,0x07,0x20,0xe4,0x12, + 0x74,0x1c,0x54,0xa4,0x46,0x0c,0x10,0xe0,0x7c,0x12,0x4c,0x01,0x5c,0x0c,0xf6,0xef, + 0x0a,0xf0,0x07,0x20,0xe4,0x12,0x74,0x1c,0x54,0xa4,0x46,0x0c,0x05,0xe8,0x7c,0x12, + 0x4c,0x01,0x5c,0x0c,0xf6,0xef,0x0c,0x60,0x0d,0x60,0x07,0xf0,0xe7,0x12,0xd7,0x1c, + 0xd2,0x12,0x67,0xa3,0x14,0x60,0x61,0x7f,0x0d,0x20,0x0d,0x01,0xc1,0x0c,0xf6,0xef, + 0x0d,0x60,0x07,0xf0,0xe7,0x1c,0xd2,0x12,0x67,0xa3,0x14,0x60,0x5c,0x7f,0x0d,0x20, + 0x4d,0x01,0xd7,0x12,0xc7,0x1c,0x47,0x01,0x4e,0xa6,0x67,0x0c,0xf3,0xef,0x87,0xf0, + 0x1d,0x2a,0x85,0xe0,0x54,0x76,0x06,0xa7,0x07,0x30,0x17,0x30,0x07,0x34,0x06,0xb7, + 0x4e,0xad,0x53,0x7b,0x07,0x60,0x0b,0xb7,0x05,0x60,0x00,0x95,0x26,0x65,0xe6,0x1c, + 0x10,0x96,0xe9,0x12,0x44,0xf0,0x78,0x1c,0x07,0x20,0x07,0x01,0x61,0x0c,0xfb,0xef, + 0x6d,0x0c,0xd6,0x0a,0x30,0x96,0x00,0x8c,0x0a,0x60,0xc7,0x12,0x97,0x1c,0x20,0x97, + 0x1a,0xf0,0xe2,0x12,0xa2,0x1c,0x10,0x81,0x01,0xa3,0x46,0x7f,0x82,0x1c,0x02,0xa4, + 0x20,0x87,0xe7,0x1c,0xc2,0x12,0x67,0xa3,0x14,0x2a,0x01,0xe8,0x24,0x60,0x3f,0x7f, + 0x0e,0x20,0x01,0xf0,0x0e,0x60,0x0e,0x01,0x30,0x84,0x41,0x0c,0xea,0xef,0x0a,0x20, + 0x4a,0x01,0x0c,0x20,0x4c,0x01,0x10,0x85,0x05,0xa7,0x7a,0x0c,0xf3,0xef,0x0b,0xa6, + 0xd7,0x0c,0x08,0xe0,0x39,0x71,0x16,0x1c,0x24,0x62,0x46,0x1c,0x06,0xb7,0x7d,0x05, + 0x4d,0x01,0x06,0xf0,0x35,0x75,0x56,0x1c,0x21,0x62,0x16,0x1c,0x06,0xbd,0x0d,0x60, + 0x00,0x84,0x47,0x1c,0x07,0x01,0x00,0x91,0x0b,0xa7,0x07,0x20,0x0b,0xb7,0x0d,0x2a, + 0x04,0xe0,0x2e,0x77,0x07,0xab,0x2e,0x79,0x09,0xf0,0x10,0x84,0x04,0xa6,0x07,0x60, + 0x2d,0x78,0xb3,0xf7,0xd7,0x12,0xd7,0x1c,0x79,0x1c,0x0d,0x20,0x0d,0x01,0xb1,0x0c, + 0xf9,0xef,0x0d,0x60,0x29,0x78,0x19,0xf0,0xea,0x12,0xea,0x1c,0xca,0x1c,0xe2,0x12, + 0xd2,0x1c,0xb3,0x12,0x20,0x7f,0x22,0x1c,0x92,0x1c,0x02,0xc7,0x0a,0xd7,0x0e,0x20, + 0x07,0xf0,0x0e,0x60,0xdc,0x12,0x3c,0x3c,0xd7,0x12,0x67,0x3c,0x7c,0x1c,0x8c,0x1c, + 0x0e,0x01,0xb1,0x0c,0xe9,0xef,0x0d,0x20,0x4d,0x01,0xbd,0x0f,0xf2,0xe7,0x10,0x77, + 0x07,0x85,0x45,0xa3,0x07,0x60,0x76,0x12,0x14,0x61,0x08,0xf0,0x52,0x12,0x72,0x1c, + 0x62,0xa2,0x24,0x0c,0x02,0xe8,0x06,0x20,0x46,0x01,0x07,0x20,0x07,0x01,0x31,0x0c, + 0xf5,0xef,0x12,0x77,0x07,0xb6,0x00,0x85,0x56,0x14,0x46,0x01,0x11,0x77,0x07,0xb6, + 0xf0,0x20,0x68,0x00,0xf0,0x21,0xcf,0x00,0x44,0x01,0x00,0x00,0xc4,0x09,0x00,0x00, + 0x1c,0x9e,0x00,0x00,0x54,0x08,0x04,0x00,0xfc,0x00,0x00,0x00,0x4c,0x2e,0x00,0x00, + 0x41,0x9e,0x00,0x00,0x74,0x84,0x00,0x00,0x20,0x9e,0x00,0x00,0x42,0x9e,0x00,0x00, + 0x10,0x03,0x00,0x00,0xb4,0x04,0x00,0x00,0x00,0x60,0x02,0x00,0x5a,0x08,0x04,0x00, + 0x5b,0x08,0x04,0x00,0x70,0x25,0x7b,0x00,0x23,0x12,0x63,0x01,0xb7,0x72,0xb7,0x7f, + 0x2d,0x12,0x6d,0x01,0xdc,0x12,0x0c,0x20,0x1c,0x3e,0x0e,0x60,0xb5,0x7b,0x0b,0xf0, + 0xe2,0x12,0x92,0x3c,0xd3,0x12,0xb1,0x7f,0xb3,0x7f,0xb2,0x14,0x42,0x01,0xb2,0x77, + 0xe7,0x1c,0x07,0xb2,0x0e,0x20,0xe7,0x12,0x67,0x01,0xc7,0x0c,0xf1,0xef,0x6b,0x00, + 0x70,0x21,0xcf,0x00,0x70,0x24,0x7e,0x00,0xad,0x7e,0xe2,0x12,0x03,0x60,0x44,0x61, + 0xac,0x7f,0x07,0x60,0x0e,0xb7,0x2e,0xb7,0x3e,0xb7,0xfe,0xb7,0xae,0xb7,0x07,0x2c, + 0xbe,0xb7,0xf7,0x67,0xce,0xb7,0x6e,0x00,0x70,0x20,0xcf,0x00,0x70,0x24,0x00,0x9f, + 0xa5,0x77,0x07,0xa7,0xa5,0x76,0x06,0x85,0xa5,0x76,0x65,0x0f,0x0a,0xe0,0x74,0x12, + 0x74,0x1c,0x74,0x1c,0xa3,0x72,0xa3,0x73,0x44,0x3c,0x15,0x60,0xa3,0x7f,0x16,0x60, + 0x01,0xf0,0x06,0x60,0x9a,0x77,0x27,0xb6,0x00,0x8f,0x70,0x20,0xcf,0x00,0x70,0x24, + 0x00,0x9f,0x06,0x60,0x9e,0x77,0x07,0xb6,0x9e,0x76,0x06,0x87,0x9e,0x75,0x57,0x16, + 0x06,0x97,0x9d,0x76,0x06,0x87,0xd7,0x30,0x06,0x97,0x9c,0x76,0x06,0x87,0xe7,0x31, + 0xf7,0x31,0x06,0x97,0xa2,0x60,0x9a,0x7f,0x00,0x8f,0x70,0x20,0xcf,0x00,0xf0,0x25, + 0x78,0x00,0xf0,0x24,0x98,0x7e,0x0e,0x92,0x98,0x77,0x00,0x97,0x42,0x62,0x83,0x61, + 0x94,0x60,0x05,0x60,0x56,0x12,0x57,0x12,0x95,0x7f,0x95,0x77,0x00,0x97,0x42,0x62, + 0x83,0x61,0x94,0x60,0x05,0x60,0x56,0x12,0x57,0x12,0x90,0x7f,0x92,0x77,0x00,0x97, + 0x42,0x62,0xa3,0x61,0x94,0x60,0x05,0x60,0x56,0x12,0x57,0x12,0x8c,0x7f,0x8e,0x77, + 0x00,0x97,0x42,0x62,0xa3,0x61,0x94,0x60,0x05,0x60,0x56,0x12,0x57,0x12,0x87,0x7f, + 0x8b,0x77,0x00,0x97,0x42,0x62,0xa3,0x61,0x94,0x60,0x05,0x60,0x56,0x12,0x57,0x12, + 0x83,0x7f,0x87,0x77,0x00,0x97,0x42,0x62,0x23,0x12,0x94,0x60,0x05,0x60,0x56,0x12, + 0x57,0x12,0x7e,0x7f,0x70,0x7d,0xd2,0x12,0x03,0x60,0x64,0x64,0x6d,0x7f,0x0e,0x8e, + 0x27,0x64,0xe7,0x1c,0x07,0xa7,0x07,0x2a,0x05,0xe0,0x4e,0xa7,0x0d,0xb7,0x5e,0xa7, + 0x1d,0xb7,0x99,0xf0,0x36,0x64,0xe6,0x1c,0x06,0xa4,0x14,0x2a,0x4e,0xa5,0x5e,0xa6, + 0x19,0xe0,0x54,0x12,0x04,0x24,0x0d,0xb4,0x64,0x12,0x74,0x05,0x1d,0xb4,0x03,0x60, + 0x34,0x12,0x72,0x12,0xd2,0x1c,0x09,0xf0,0x4c,0x12,0xdc,0x1c,0x2c,0xb5,0x2c,0x12, + 0x3c,0x1c,0x6c,0xb6,0x04,0x20,0x06,0x24,0x46,0x01,0x03,0x24,0x04,0x01,0x71,0x0c, + 0xf3,0xef,0x79,0xf0,0x24,0x2a,0x19,0xe0,0x54,0x12,0x74,0x05,0x0d,0xb4,0x64,0x12, + 0x04,0x24,0x1d,0xb4,0x03,0x60,0x34,0x12,0x72,0x12,0xd2,0x1c,0x09,0xf0,0x4c,0x12, + 0xdc,0x1c,0x6c,0xb6,0x2c,0x12,0x3c,0x1c,0x2c,0xb5,0x04,0x20,0x05,0x24,0x45,0x01, + 0x03,0x24,0x04,0x01,0x71,0x0c,0xf3,0xef,0x5e,0xf0,0x34,0x2a,0x25,0xe0,0x54,0x12, + 0x04,0x24,0x0d,0xb4,0x1d,0xb6,0x5b,0x73,0x04,0x60,0x1a,0xf0,0x32,0x12,0x32,0x24, + 0x02,0xb5,0x02,0x60,0xed,0x12,0x4d,0x1c,0x48,0x64,0x8d,0x1c,0x0c,0xf0,0x02,0x20, + 0xec,0x12,0x2c,0x1c,0x9b,0x62,0xbc,0x1c,0x0d,0xab,0x0c,0xac,0xcb,0x0f,0x03,0xe0, + 0x01,0x20,0x03,0xb1,0x03,0xf0,0x02,0x01,0x61,0x0c,0xf1,0xef,0x04,0x20,0x03,0x20, + 0x04,0x01,0x71,0x0c,0xe3,0xef,0x37,0xf0,0x44,0x2a,0x21,0xe0,0x0d,0xb5,0x64,0x12, + 0x04,0x24,0x1d,0xb4,0x49,0x73,0x04,0x60,0x16,0xf0,0x43,0xb6,0x02,0x60,0xed,0x12, + 0x4d,0x1c,0x4f,0x64,0xfd,0x1c,0x0a,0xf0,0x02,0x20,0xec,0x12,0x2c,0x1c,0x0d,0xab, + 0x5c,0xac,0xcb,0x0f,0x03,0xe0,0x01,0x20,0x03,0xb1,0x03,0xf0,0x02,0x01,0x51,0x0c, + 0xf3,0xef,0x04,0x20,0x03,0x20,0x04,0x01,0x71,0x0c,0xe7,0xef,0x14,0xf0,0x54,0x12, + 0x74,0x05,0x0d,0xb4,0x64,0x12,0x74,0x05,0x1d,0xb4,0x7d,0x1c,0x0d,0x20,0x04,0x60, + 0x53,0x12,0x43,0x05,0x0d,0xb3,0x63,0x12,0x43,0x05,0x4d,0xb3,0x04,0x20,0x44,0x01, + 0x0d,0x24,0x74,0x0f,0xf5,0xe7,0x1b,0x77,0x17,0xad,0x8d,0x3c,0x86,0x2c,0xd6,0x16, + 0xa7,0xb6,0xd6,0x12,0x86,0x3e,0xb7,0xb6,0x2d,0x76,0xe6,0x1c,0x06,0xa6,0x26,0x2a, + 0x07,0xa6,0x96,0x00,0x86,0x3c,0x66,0x01,0x85,0x2c,0x65,0x16,0xc7,0xb5,0x86,0x3e, + 0xd7,0xb6,0x27,0x77,0xe7,0x1c,0x07,0xa9,0x27,0x77,0xe7,0x1c,0x07,0xa8,0x98,0x1c, + 0x26,0x72,0x28,0x1c,0x26,0x77,0xe7,0x1c,0x07,0xa7,0x20,0x97,0x0a,0x7a,0xca,0xa7, + 0xda,0xac,0x8c,0x3c,0x7c,0x1e,0x44,0xf0,0xa0,0x25,0x26,0x00,0xd0,0x83,0x00,0x00, + 0xfe,0xff,0xff,0xff,0xa0,0x0b,0x00,0x00,0x00,0x80,0x01,0x00,0x66,0x9e,0x00,0x00, + 0xc4,0x09,0x00,0x00,0x20,0x9e,0x00,0x00,0x00,0xb0,0x10,0x00,0xaa,0xa5,0x55,0x5a, + 0x00,0x00,0x03,0x00,0x00,0xa0,0x00,0x00,0xf6,0x1e,0x00,0x00,0x40,0x01,0x04,0x00, + 0x0c,0x01,0x04,0x00,0xff,0xff,0xf0,0xff,0x04,0x01,0x04,0x00,0x08,0x01,0x04,0x00, + 0xe0,0x0a,0x00,0x00,0x1c,0x9e,0x00,0x00,0x00,0x00,0x02,0x18,0xb4,0x26,0x00,0x00, + 0x00,0x00,0x03,0x18,0x00,0x00,0x04,0x1a,0x00,0x00,0x05,0x1a,0x00,0x00,0x06,0x1a, + 0x00,0x00,0x01,0x24,0x26,0x9e,0x00,0x00,0x22,0x9e,0x00,0x00,0x20,0x01,0x00,0x00, + 0x95,0x00,0x00,0x00,0x96,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0x97,0x00,0x00,0x00, + 0x27,0x12,0xc7,0x1c,0x20,0x8b,0xb7,0x1c,0xca,0x76,0xe6,0x1c,0x06,0xa6,0x67,0x1c, + 0x67,0x01,0x30,0x97,0x7f,0x32,0xf9,0x1c,0x0e,0xa7,0x1e,0xab,0x8b,0x3c,0x7b,0x1e, + 0xd8,0x1c,0x68,0x01,0x92,0x12,0xf1,0x11,0xb2,0x03,0xf9,0x11,0x83,0x12,0xc1,0x7f, + 0x62,0x01,0xea,0xb2,0x82,0x3e,0xfa,0xb2,0x92,0x12,0xd2,0x1c,0xbf,0x73,0x32,0x1c, + 0xf1,0x11,0xb2,0x03,0xf9,0x11,0x83,0x12,0xbb,0x7f,0x62,0x01,0xbc,0x77,0x07,0xb2, + 0x82,0x3e,0xbb,0x77,0x07,0xb2,0x20,0x8a,0x74,0x32,0x4a,0x1c,0x2e,0xa7,0x3e,0xab, + 0x8b,0x3c,0x7b,0x1e,0xa2,0x12,0xf1,0x11,0xb2,0x03,0xf9,0x11,0x30,0x83,0xb1,0x7f, + 0x62,0x01,0xb4,0x77,0x07,0xb2,0x82,0x3e,0xb4,0x77,0x07,0xb2,0xa2,0x12,0xc2,0x1c, + 0xae,0x75,0x52,0x1c,0xf1,0x11,0xb2,0x03,0xf9,0x11,0x30,0x83,0xaa,0x7f,0x62,0x01, + 0xaf,0x77,0x07,0xb2,0x82,0x3e,0xae,0x77,0x07,0xb2,0xae,0x77,0xe7,0x1c,0x07,0xa6, + 0xae,0x77,0xe7,0x1c,0x07,0xa7,0x87,0x3c,0x67,0x1e,0x85,0x2c,0x75,0x16,0xab,0x76, + 0x06,0xb5,0x76,0x12,0x86,0x3e,0xaa,0x74,0x04,0xb6,0xaa,0x74,0x04,0xb5,0xaa,0x75, + 0x05,0xb6,0x7d,0x05,0x6d,0x01,0xa9,0x76,0x06,0xbd,0x8d,0x3e,0xa9,0x76,0x06,0xbd, + 0xc7,0x14,0x67,0x01,0xa8,0x76,0x06,0xb7,0x87,0x3e,0xa7,0x76,0x06,0xb7,0xa7,0x77, + 0x66,0x67,0xe6,0x1c,0x06,0xa6,0x07,0xb6,0x56,0x67,0xe6,0x1c,0x06,0xa6,0x17,0xb6, + 0x46,0x67,0xe6,0x1c,0x06,0xa6,0x27,0xb6,0x06,0x60,0x37,0xb6,0xb7,0x64,0xe7,0x1c, + 0x07,0xa7,0x27,0x2a,0xcd,0x64,0xed,0x1c,0xdc,0x64,0xec,0x1c,0x0d,0xa3,0x0c,0xa6, + 0x86,0x3c,0xe7,0x64,0xe7,0x1c,0x07,0xa4,0xf7,0x64,0xe7,0x1c,0x07,0xa7,0x87,0x3c, + 0x10,0xe0,0x02,0x60,0x63,0x1e,0x74,0x1e,0x96,0x7f,0x0d,0xa3,0x0c,0xa6,0x86,0x3c, + 0x07,0x65,0xe7,0x1c,0x07,0xa4,0x17,0x65,0xe7,0x1c,0x07,0xa7,0x87,0x3c,0x12,0x60, + 0x01,0xf0,0x22,0x60,0x63,0x1e,0x74,0x1e,0x8e,0x7f,0xc7,0x64,0xe7,0x1c,0x07,0xa3, + 0xd7,0x64,0xe7,0x1c,0x07,0xa7,0x87,0x3c,0x02,0x60,0x73,0x1e,0x8a,0x7f,0xb7,0x64, + 0x7e,0x1c,0x0e,0xa2,0x89,0x7f,0x89,0x77,0xc6,0x60,0x07,0xb6,0x07,0xb6,0x88,0x72, + 0xf3,0x63,0x84,0x61,0x88,0x7f,0x88,0x77,0x07,0x83,0x07,0x60,0x75,0x12,0x76,0x12, + 0x18,0xf0,0x34,0x12,0x64,0x1c,0xa8,0x62,0x84,0x1c,0x04,0xa2,0x14,0x60,0x42,0x0e, + 0x12,0x3e,0x64,0x12,0x54,0x34,0x05,0xe8,0x05,0x20,0x45,0x01,0x80,0x7b,0xb2,0x1c, + 0x04,0xf0,0x07,0x20,0x47,0x01,0x7a,0x7d,0xd2,0x1c,0x44,0x01,0x02,0xb4,0x06,0x20, + 0x66,0x01,0x53,0xa4,0x46,0x0c,0xe5,0xef,0x7a,0x76,0x06,0xb7,0x7a,0x77,0x07,0xb5, + 0x86,0x60,0x79,0x77,0x07,0x96,0x74,0x77,0x07,0x87,0x36,0x65,0x76,0x1c,0x06,0xa6, + 0x06,0x2a,0x09,0xe0,0x76,0x77,0x07,0xa6,0x76,0x7e,0xe6,0x16,0x07,0xb6,0x07,0xa6, + 0x75,0x72,0x26,0x16,0x0f,0xf0,0xc6,0x64,0x76,0x1c,0x06,0xa2,0xd3,0x64,0x37,0x1c, + 0x07,0xa7,0x87,0x3c,0x72,0x1e,0x70,0x7f,0x6d,0x77,0x07,0xa6,0x06,0x34,0x07,0xb6, + 0x07,0xa6,0x46,0x34,0x07,0xb6,0x69,0x76,0x06,0xa7,0x17,0x34,0x06,0xb7,0x6b,0x75, + 0x05,0xa7,0x6b,0x74,0x47,0x16,0x60,0x76,0x06,0x86,0xb4,0x66,0x64,0x1c,0x04,0xa4, + 0x47,0x1e,0x05,0xb7,0x68,0x75,0x05,0xa7,0x07,0x34,0x05,0xb7,0x15,0x60,0x66,0x77, + 0x07,0xb5,0x05,0x60,0x66,0x77,0x07,0xb5,0x05,0x60,0x65,0x77,0x07,0xd5,0x85,0x32, + 0x65,0x77,0x07,0xd5,0x65,0x75,0x65,0x77,0x07,0xd5,0x05,0x62,0x65,0x77,0x07,0xb5, + 0x07,0x60,0x12,0xf0,0x64,0x12,0x74,0x1c,0xa3,0x62,0x43,0x1c,0x03,0xa5,0x61,0x78, + 0x85,0x1c,0x61,0x7b,0xb4,0x1c,0x04,0xa2,0x05,0xb2,0x03,0xa5,0x60,0x7d,0xd5,0x1c, + 0x04,0xa4,0x05,0xb4,0x07,0x20,0x67,0x01,0x56,0xa5,0x57,0x0c,0xeb,0xef,0x5c,0x72, + 0x03,0x60,0x44,0x62,0x44,0x7f,0x44,0x77,0x07,0x87,0xbe,0x64,0xe7,0x1c,0x07,0xa7, + 0x17,0x2a,0x46,0x77,0x07,0xa6,0x02,0xe8,0x26,0x34,0x02,0xf0,0x56,0x72,0x26,0x16, + 0x07,0xb6,0x3d,0x7e,0x0e,0x87,0xf3,0x66,0x37,0x1c,0x07,0xa3,0x53,0x72,0x83,0x3c, + 0x53,0x74,0x53,0x7f,0x0e,0x87,0x04,0x67,0x47,0x1c,0x07,0xa7,0x73,0x12,0x43,0x3c, + 0x73,0x1e,0x50,0x72,0x43,0x01,0x50,0x74,0x33,0x7f,0x0e,0x87,0x50,0x75,0x57,0x1c, + 0x07,0xa7,0x73,0x12,0x43,0x3c,0x73,0x1e,0x4e,0x72,0x43,0x01,0x54,0x62,0x2d,0x7f, + 0x0e,0x87,0x4c,0x76,0x76,0x1c,0x06,0xa6,0x06,0x2a,0xd2,0xe8,0xe6,0x64,0x76,0x1c, + 0x06,0xa6,0xf5,0x64,0x75,0x1c,0x05,0xa2,0x82,0x3c,0x62,0x1e,0xc6,0x64,0x76,0x1c, + 0x06,0xa5,0xd6,0x64,0x76,0x1c,0x06,0xa6,0x86,0x3c,0x56,0x1e,0x43,0x78,0x87,0x1c, + 0xf1,0x11,0x62,0x03,0xf9,0x11,0x07,0xa3,0x07,0x7f,0x23,0x12,0x63,0x01,0x12,0x60, + 0x19,0x7f,0x15,0x60,0x3e,0x77,0x07,0xb5,0x0e,0x87,0x3d,0x7b,0x7b,0xf0,0x00,0x00, + 0x98,0x00,0x00,0x00,0xd0,0x83,0x00,0x00,0x00,0xfe,0xff,0xff,0x30,0x9e,0x00,0x00, + 0x31,0x9e,0x00,0x00,0x32,0x9e,0x00,0x00,0x33,0x9e,0x00,0x00,0x34,0x9e,0x00,0x00, + 0x35,0x9e,0x00,0x00,0xa7,0x00,0x00,0x00,0xa8,0x00,0x00,0x00,0x36,0x9e,0x00,0x00, + 0x37,0x9e,0x00,0x00,0x38,0x9e,0x00,0x00,0x39,0x9e,0x00,0x00,0x3a,0x9e,0x00,0x00, + 0x3b,0x9e,0x00,0x00,0x3c,0x9e,0x00,0x00,0x3d,0x9e,0x00,0x00,0x86,0x9e,0x00,0x00, + 0x0c,0x27,0x00,0x00,0x5a,0x27,0x00,0x00,0x78,0x2e,0x00,0x00,0x62,0x08,0x04,0x00, + 0x00,0x08,0x04,0x00,0xc4,0x09,0x00,0x00,0x1c,0x9e,0x00,0x00,0x0c,0x08,0x04,0x00, + 0x58,0x08,0x04,0x00,0x59,0x08,0x04,0x00,0x2c,0x08,0x04,0x00,0x40,0x08,0x04,0x00, + 0xfe,0x00,0x00,0x00,0xef,0x00,0x00,0x00,0xc4,0x30,0x00,0x00,0x41,0x08,0x04,0x00, + 0xf8,0xff,0xff,0xff,0x68,0x08,0x04,0x00,0x69,0x08,0x04,0x00,0x84,0x08,0x04,0x00, + 0x8c,0x08,0x04,0x00,0x8e,0x08,0x04,0x00,0x96,0x00,0x00,0x00,0x90,0x08,0x04,0x00, + 0x98,0x08,0x04,0x00,0xd0,0x08,0x04,0x00,0xd0,0x00,0x00,0x00,0xe8,0x08,0x04,0x00, + 0x14,0x09,0x04,0x00,0xfb,0x00,0x00,0x00,0x00,0x40,0x02,0x00,0x60,0x03,0x00,0x00, + 0xd8,0x09,0x00,0x00,0x00,0x20,0x02,0x00,0xbc,0x01,0x00,0x00,0xcb,0x00,0x00,0x00, + 0xbc,0x21,0x02,0x00,0xc8,0x00,0x00,0x00,0xca,0x00,0x00,0x00,0x9c,0x08,0x04,0x00, + 0xc9,0x00,0x00,0x00,0xb7,0x1c,0x07,0xa6,0x06,0x2a,0x96,0x77,0x06,0xe0,0x07,0x85, + 0x35,0x31,0x07,0x95,0x95,0x77,0x07,0xb6,0x0a,0xf0,0x16,0x2a,0x07,0x86,0x03,0xe0, + 0x36,0x35,0x07,0x96,0x04,0xf0,0x36,0x31,0x07,0x96,0x8f,0x77,0x07,0xb5,0x8f,0x76, + 0x06,0xa7,0x57,0x34,0x06,0xb7,0x8e,0x75,0x05,0xa6,0x8e,0x77,0x07,0x87,0xbd,0x66, + 0xd7,0x1c,0x07,0xa7,0x47,0x3c,0x8c,0x7e,0xe6,0x16,0x67,0x1e,0x47,0x01,0x05,0xb7, + 0x86,0x2d,0x8a,0x77,0x07,0x96,0x06,0x2c,0x8a,0x77,0x07,0x96,0x06,0x60,0x89,0x77, + 0x07,0xb6,0xf6,0x61,0x89,0x77,0x07,0xb6,0x89,0x76,0x06,0xa7,0x17,0x34,0x04,0xf0, + 0x87,0x76,0x06,0xa7,0x87,0x72,0x27,0x16,0x06,0xb7,0x86,0x7f,0x02,0x61,0x86,0x7f, + 0x02,0x60,0x86,0x77,0x07,0xb2,0x86,0x77,0x07,0x84,0x7a,0x73,0x03,0x85,0x16,0x67, + 0x56,0x1c,0x06,0xa6,0x66,0x3d,0x64,0x31,0x74,0x31,0x46,0x1e,0x07,0x96,0x07,0x84, + 0xe6,0x66,0x56,0x1c,0x06,0xa6,0x16,0x3d,0x14,0x31,0x24,0x31,0x46,0x1e,0x07,0x96, + 0x07,0x84,0xd6,0x66,0x56,0x1c,0x06,0xa6,0x06,0x3d,0x04,0x31,0x46,0x1e,0x07,0x96, + 0x79,0x74,0x04,0x86,0xc7,0x66,0x75,0x1c,0x05,0xa7,0xd7,0x3c,0xd6,0x30,0xe6,0x30, + 0x67,0x1e,0x04,0x97,0x75,0x75,0x05,0xb2,0x07,0x60,0xf2,0x61,0x34,0x60,0x0f,0xf0, + 0x76,0x1c,0x66,0xa6,0x62,0x0c,0x09,0xe0,0x05,0xae,0xf6,0x25,0x06,0x30,0x48,0x12, + 0x68,0x1b,0x86,0x12,0xe6,0x1e,0x46,0x01,0x05,0xb6,0x07,0x20,0x47,0x01,0x03,0x86, + 0x46,0xae,0xe7,0x0c,0xed,0xef,0x69,0x72,0x03,0x60,0x69,0x74,0x6a,0x7f,0x07,0x60, + 0x6a,0x76,0x06,0xb7,0x15,0x60,0x69,0x76,0x06,0xb5,0x69,0x76,0x06,0xb7,0x63,0x73, + 0x3e,0x12,0x06,0x60,0x62,0x12,0x3a,0x12,0x6b,0x64,0x0c,0x2c,0xfd,0x67,0x1b,0xf0, + 0xe7,0x12,0x47,0x1c,0x64,0x78,0x87,0x1c,0x07,0xb2,0x57,0x12,0x37,0x3c,0x57,0x05, + 0x97,0x1c,0xa7,0x1c,0x61,0x78,0x87,0x1c,0x37,0xbc,0x47,0xbd,0x57,0xbc,0x67,0xbd, + 0x77,0xb2,0x87,0xb2,0x05,0x20,0x64,0x20,0xa5,0x2a,0xea,0xe7,0x06,0x20,0x6f,0x64, + 0xfe,0x1c,0x46,0x2a,0x24,0xe8,0x04,0x60,0x45,0x12,0x69,0x12,0xf1,0x11,0xb9,0x03, + 0xf9,0x11,0xde,0xf7,0x47,0x12,0x37,0x3c,0x37,0x1c,0x54,0x78,0x87,0x1c,0x0d,0x60, + 0x07,0xb5,0x27,0x12,0x47,0x1c,0x52,0x7b,0xb7,0x1c,0x37,0x3c,0xe7,0x1c,0x0b,0x60, + 0x37,0xbc,0x47,0xb5,0x57,0xb5,0x67,0xb5,0x77,0xb5,0x87,0xb5,0x04,0x20,0xa4,0x2a, + 0xe9,0xe7,0x06,0x20,0x0f,0x65,0xf3,0x1c,0x46,0x2a,0x05,0xe0,0x0b,0xf0,0x06,0x60, + 0x6c,0x12,0x65,0x12,0x3e,0x7e,0x04,0x60,0x62,0x12,0x62,0x1c,0x67,0x12,0x37,0x3c, + 0x72,0x1c,0xd8,0xf7,0x44,0x72,0xb3,0x12,0x3b,0x7f,0x43,0x7e,0x44,0x77,0x0e,0xb7, + 0x17,0x01,0x1e,0xb1,0x27,0x01,0x2e,0xb1,0x87,0x3f,0x3e,0xb7,0x47,0x61,0x4e,0xb7, + 0x40,0x7c,0x0c,0xa7,0x5e,0xb7,0x1c,0xa7,0x6e,0xb7,0x9e,0xbb,0x22,0x7a,0x0a,0x87, + 0x42,0x67,0x27,0x1c,0x07,0xa7,0xae,0xb7,0x07,0x60,0xbe,0xb7,0x3a,0x77,0x07,0xa6, + 0x07,0xbd,0x17,0xa6,0x17,0xbd,0x38,0x77,0x27,0xbd,0x37,0xbd,0x07,0xbd,0x17,0xbd, + 0x47,0xbd,0x57,0xbd,0x36,0x7f,0x36,0x76,0x06,0x87,0x47,0x30,0x57,0x30,0x06,0x97, + 0x35,0x76,0x35,0x77,0x07,0xd6,0x35,0x76,0x36,0x77,0x07,0xd6,0x1c,0xa7,0x87,0x3c, + 0x0c,0xa6,0x67,0x1e,0x34,0x76,0x06,0xd7,0xa6,0x61,0x33,0x77,0x07,0xb6,0x33,0x77, + 0x07,0xbd,0x0a,0x87,0x43,0x67,0x37,0x1c,0x07,0xa6,0x31,0x77,0x07,0xd6,0x4e,0xa6, + 0x31,0x77,0x07,0xb6,0x31,0x7f,0x31,0x77,0x07,0x9b,0xf0,0x20,0x68,0x00,0xf0,0x21, + 0xcf,0x00,0x00,0x00,0x08,0x01,0x04,0x00,0x9d,0x08,0x04,0x00,0x40,0x08,0x04,0x00, + 0x41,0x08,0x04,0x00,0x1c,0x9e,0x00,0x00,0x8f,0xff,0xff,0xff,0xa0,0x08,0x04,0x00, + 0xa4,0x08,0x04,0x00,0xcc,0x08,0x04,0x00,0x66,0x09,0x04,0x00,0x68,0x08,0x04,0x00, + 0xfd,0x00,0x00,0x00,0x5e,0x31,0x00,0x00,0x72,0x2d,0x00,0x00,0x3c,0x01,0x04,0x00, + 0x04,0x01,0x04,0x00,0x0c,0x01,0x04,0x00,0x48,0x01,0x04,0x00,0x8a,0x9e,0x00,0x00, + 0xe9,0x05,0x00,0x00,0xc4,0x09,0x00,0x00,0x63,0xa4,0x00,0x00,0x64,0xa4,0x00,0x00, + 0xe5,0xa3,0x00,0x00,0x02,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x1a,0x04,0x00,0x00, + 0x83,0x00,0x00,0x00,0xfa,0xa3,0x00,0x00,0x7a,0x9e,0x00,0x00,0x00,0xe0,0x02,0x00, + 0x20,0x9e,0x00,0x00,0x00,0x08,0x03,0x00,0x73,0xa4,0x00,0x00,0x04,0x31,0x00,0x00, + 0x04,0x0a,0x04,0x00,0x36,0x50,0x00,0x00,0x40,0x0a,0x04,0x00,0x00,0x68,0x00,0x00, + 0x42,0x0a,0x04,0x00,0x44,0x0a,0x04,0x00,0x46,0x0a,0x04,0x00,0x47,0x0a,0x04,0x00, + 0x48,0x0a,0x04,0x00,0x4a,0x0a,0x04,0x00,0x2c,0x31,0x00,0x00,0x4c,0x06,0x04,0x00, + 0x16,0x60,0x82,0x77,0x07,0xb6,0x82,0x76,0x06,0x87,0x82,0x75,0x57,0x1e,0x06,0x97, + 0x82,0x76,0x06,0x87,0xd7,0x34,0x06,0x97,0x81,0x76,0x06,0x87,0xe7,0x35,0xf7,0x35, + 0x06,0x97,0xcf,0x00,0xcf,0x00,0x7e,0x72,0xcf,0x00,0xf0,0x24,0x7d,0x00,0x7d,0x77, + 0x07,0x83,0x7d,0x77,0x37,0x1c,0x07,0xa7,0x07,0x2a,0x32,0xe8,0x7c,0x77,0x17,0xa6, + 0x7c,0x74,0x05,0x60,0x7c,0x72,0x0b,0xf0,0x37,0x12,0x57,0x1c,0xaf,0x62,0xf7,0x1c, + 0x07,0xa7,0x77,0x1c,0x27,0x1c,0x07,0xc7,0x04,0xd7,0x05,0x20,0x14,0x20,0x05,0x01, + 0x61,0x0c,0xf2,0xef,0x72,0x77,0x07,0xad,0x05,0x60,0x54,0x12,0xff,0x61,0x70,0x7e, + 0x71,0x71,0x66,0x1c,0x11,0xf0,0x37,0x12,0x47,0x1c,0x67,0xa7,0x52,0x12,0x62,0x1c, + 0xe2,0x1c,0x7f,0x0c,0x02,0xe8,0x77,0x21,0x01,0xf0,0xb7,0x24,0x77,0x1c,0x17,0x1c, + 0x07,0xc7,0x02,0xd7,0x04,0x20,0x15,0x20,0x47,0x12,0x47,0x01,0xd7,0x0c,0xeb,0xef, + 0x6d,0x00,0xf0,0x20,0xcf,0x00,0x70,0x24,0x7e,0x00,0x63,0x77,0x07,0xa6,0x06,0x20, + 0x46,0x01,0x07,0xb6,0x62,0x77,0x07,0xa7,0x07,0x2a,0x07,0xe0,0x5a,0x77,0x07,0x87, + 0x85,0x67,0x75,0x1c,0x05,0xa5,0x05,0x2a,0x0d,0xe0,0x06,0x60,0x5b,0x77,0x07,0xb6, + 0x55,0x77,0x07,0x87,0xb6,0x64,0x67,0x1c,0x07,0xa7,0x0e,0x60,0x17,0x2a,0x12,0xe0, + 0x58,0x7f,0x10,0xf0,0x95,0x67,0x75,0x1c,0x05,0xa5,0x1e,0x60,0x56,0x0c,0x0a,0xe8, + 0xb6,0x64,0x67,0x1c,0x07,0xa7,0x17,0x2a,0x01,0xe0,0x51,0x7f,0x06,0x60,0x4e,0x77, + 0x07,0xb6,0x0e,0x60,0xe2,0x12,0x6e,0x00,0x70,0x20,0xcf,0x00,0xf0,0x24,0x20,0x9f, + 0x30,0x9e,0x44,0x77,0x07,0x8e,0x4e,0xa2,0x5e,0xa3,0x4a,0x77,0x00,0x97,0x24,0x60, + 0x4a,0x75,0x06,0x60,0x67,0x12,0x49,0x7f,0x40,0x77,0x7e,0x1c,0x0e,0xa7,0x07,0x2a, + 0x13,0xe8,0x3e,0x77,0x17,0xa6,0x07,0xa7,0x76,0x1c,0x07,0x60,0x45,0x73,0x3c,0x74, + 0x09,0xf0,0x75,0x12,0x75,0x1c,0x32,0x12,0x52,0x1c,0x45,0x1c,0x05,0xc5,0x02,0xd5, + 0x07,0x20,0x47,0x01,0x67,0x0d,0xf5,0xe7,0x20,0x8f,0x30,0x8e,0xf0,0x20,0xcf,0x00, + 0x70,0x24,0x00,0x9f,0x06,0x60,0x3b,0x77,0x07,0xb6,0x16,0x60,0x3b,0x77,0x07,0xb6, + 0xa2,0x60,0x3a,0x7f,0x00,0x8f,0x70,0x20,0xcf,0x00,0x37,0x77,0x07,0xa6,0x16,0x36, + 0xfd,0xef,0xcf,0x00,0xcf,0x00,0xcf,0x00,0x42,0x01,0x03,0x01,0x35,0x76,0xa7,0x61, + 0xf1,0x11,0x27,0x03,0xf9,0x11,0x17,0x1c,0x77,0x1c,0x76,0x1c,0x06,0xc5,0x54,0x12, + 0x74,0x01,0x30,0x77,0x07,0xa6,0x30,0x77,0x07,0xa7,0x87,0x3c,0x67,0x1e,0x74,0x0d, + 0x17,0xe0,0x2e,0x77,0x27,0xa3,0x37,0xa6,0x86,0x3c,0x36,0x1e,0x06,0x20,0x66,0x01, + 0x27,0xb6,0x86,0x3e,0x37,0xb6,0x47,0xa3,0x57,0xa6,0x86,0x3c,0x36,0x1e,0x46,0x0d, + 0x07,0xe8,0x56,0x12,0x66,0x01,0x47,0xb6,0x86,0x3e,0x57,0xb6,0x67,0xb2,0x77,0xb1, + 0x23,0x77,0x87,0xa6,0x62,0x0c,0x01,0xe0,0x87,0xb2,0x97,0xa7,0x71,0x0c,0x02,0xe0, + 0x1f,0x77,0x97,0xb1,0x1e,0x77,0xa7,0xa6,0x26,0x0c,0x01,0xe0,0xa7,0xb2,0xb7,0xa7, + 0x17,0x0c,0x02,0xe0,0x1a,0x77,0xb7,0xb1,0xcf,0x00,0x00,0x00,0x40,0x01,0x04,0x00, + 0x0c,0x01,0x04,0x00,0x00,0x00,0x0f,0x00,0x04,0x01,0x04,0x00,0x08,0x01,0x04,0x00, + 0x00,0x80,0x02,0x00,0x1c,0x9e,0x00,0x00,0xc8,0x00,0x00,0x00,0x20,0x9e,0x00,0x00, + 0xec,0xa4,0x00,0x00,0xc0,0x86,0x02,0x00,0x5c,0xa5,0x00,0x00,0x20,0xaa,0x00,0x00, + 0x12,0x2c,0x00,0x00,0x36,0x00,0x04,0x1a,0x00,0x00,0x02,0x18,0xb4,0x26,0x00,0x00, + 0x5e,0xa5,0x00,0x00,0x74,0x08,0x04,0x00,0x70,0x08,0x04,0x00,0xe0,0x0a,0x00,0x00, + 0x00,0xe0,0x02,0x00,0x44,0xa4,0x00,0x00,0x45,0xa4,0x00,0x00,0x73,0xa4,0x00,0x00, + 0x70,0x25,0x7a,0x00,0x42,0x01,0x43,0x01,0x04,0x01,0xad,0x77,0x07,0xa7,0xad,0x76, + 0x06,0xaf,0x8f,0x3c,0x7f,0x1e,0x86,0x2c,0x5e,0x60,0xec,0x12,0x05,0x60,0xaa,0x7a, + 0x1a,0xf0,0x52,0x0f,0x16,0xe8,0x87,0x65,0x57,0x1c,0x77,0x1c,0xa7,0x1c,0x87,0xad, + 0x3d,0x14,0x5d,0x01,0xed,0x01,0x4d,0x01,0x97,0xa7,0x17,0x14,0x57,0x01,0xe7,0x01, + 0x47,0x01,0x7b,0x12,0xdb,0x1c,0x4b,0x01,0x6b,0x0c,0x03,0xe0,0xb6,0x12,0x7e,0x12, + 0xdc,0x12,0x05,0x20,0x45,0x01,0xf5,0x0c,0xe4,0xef,0x22,0x60,0x62,0x0c,0x09,0xe8, + 0x02,0x60,0x26,0x2a,0x06,0xe0,0x62,0x12,0x0c,0x2a,0x03,0xe8,0x0e,0x2a,0x22,0x00, + 0x22,0x28,0x6a,0x00,0x70,0x21,0xcf,0x00,0xf0,0x25,0x79,0x00,0x27,0x12,0x47,0x01, + 0x03,0x01,0x45,0x01,0x5b,0x12,0x5b,0x1c,0x02,0x60,0x2f,0x12,0x07,0x24,0x01,0x24, + 0x4c,0x61,0x1b,0xf0,0xe3,0x12,0xa3,0x1c,0x33,0x1c,0x43,0x1c,0x3d,0x12,0xbd,0x1c, + 0x03,0xc6,0x76,0x01,0x1d,0xc9,0x79,0x01,0x96,0x1c,0x13,0xc3,0x73,0x01,0x36,0x05, + 0x0d,0xc3,0x73,0x01,0x36,0x05,0xe6,0x01,0x6c,0x0c,0x01,0xe0,0x62,0x1c,0x0e,0x20, + 0x4e,0x01,0x1e,0x0d,0xe7,0xe7,0x0f,0x20,0x4f,0x01,0x7f,0x0d,0x06,0xe8,0xfa,0x12, + 0xf1,0x11,0x5a,0x03,0xf9,0x11,0x0e,0x60,0xf4,0xf7,0x69,0x00,0xf0,0x21,0xcf,0x00, + 0xf0,0x24,0x7d,0x00,0x7a,0x77,0x07,0xa2,0x17,0xa3,0x79,0x74,0x85,0x61,0x79,0x7f, + 0x7a,0x7d,0x0d,0xa5,0x05,0x2a,0x79,0x77,0x7a,0x7e,0x03,0xe0,0x07,0x92,0x0e,0x92, + 0x2d,0xf0,0x0e,0x86,0x26,0x1c,0x0e,0x96,0x07,0x87,0x72,0x05,0xe2,0x01,0x75,0x77, + 0x07,0x87,0x75,0x74,0x74,0x1c,0x04,0xa4,0x75,0x73,0x37,0x1c,0x07,0xa7,0x87,0x3c, + 0x47,0x1e,0x27,0x0d,0x04,0xe8,0x06,0x60,0x72,0x77,0x07,0xb6,0x15,0xf0,0x87,0x60, + 0x57,0x0c,0x14,0xe0,0x15,0x60,0x6e,0x77,0x07,0xb5,0x62,0x12,0xa3,0x60,0x6d,0x7f, + 0x0e,0x92,0x6d,0x77,0x07,0xb2,0x12,0x01,0x6d,0x77,0x07,0xb1,0x22,0x01,0x6c,0x77, + 0x07,0xb1,0x82,0x3f,0x6c,0x77,0x07,0xb2,0x07,0x2c,0x0d,0xb7,0x5f,0x77,0x07,0xa6, + 0x06,0x20,0x07,0xb6,0x65,0x77,0x07,0xa6,0x65,0x77,0x07,0xa7,0x87,0x3c,0x67,0x1e, + 0x64,0x76,0x06,0xa6,0x06,0x3d,0x76,0x1e,0x63,0x77,0x07,0xa7,0x87,0x3d,0x67,0x1e, + 0x62,0x7e,0x0e,0xa5,0x62,0x74,0x04,0xa6,0x86,0x3c,0x56,0x1e,0x61,0x75,0x05,0xa2, + 0x02,0x3d,0x62,0x1e,0x60,0x76,0x06,0xa3,0x83,0x3d,0x23,0x1e,0x37,0x0c,0x07,0xe0, + 0x0e,0xb7,0x17,0x01,0x04,0xb1,0x27,0x01,0x05,0xb1,0x87,0x3f,0x06,0xb7,0x6d,0x00, + 0xf0,0x20,0xcf,0x00,0x70,0x24,0x7e,0x00,0x58,0x7e,0x0e,0xa7,0x17,0x2a,0x03,0xe0, + 0x27,0x60,0x0e,0xb7,0xff,0xf0,0x27,0x2a,0xfd,0xe0,0x54,0x7f,0x55,0x77,0x07,0xa7, + 0x07,0x2a,0xd0,0xe8,0xfe,0xa7,0x07,0x2a,0x20,0xe8,0x52,0x77,0x07,0xa7,0x52,0x76, + 0x06,0xa6,0x86,0x3c,0x76,0x1e,0x51,0x77,0x07,0xa7,0x07,0x3d,0x67,0x1e,0x50,0x76, + 0x06,0xa6,0x86,0x3d,0x76,0x1e,0x4f,0x77,0x07,0xa5,0x4f,0x77,0x07,0xa7,0x87,0x3c, + 0x57,0x1e,0x4e,0x75,0x05,0xa5,0x05,0x3d,0x75,0x1e,0x4d,0x77,0x07,0xa7,0x87,0x3d, + 0x57,0x1e,0x67,0x0c,0x02,0xe0,0x07,0x60,0xfe,0xb7,0x4a,0x77,0x07,0xa7,0x07,0x2a, + 0x3e,0x77,0x26,0xe8,0x06,0x60,0xa7,0xb6,0x34,0x76,0x06,0xa6,0x34,0x75,0x05,0xa5, + 0x85,0x3c,0x65,0x1e,0x33,0x76,0x06,0xa6,0x06,0x3d,0x56,0x1e,0x32,0x75,0x05,0xa5, + 0x85,0x3d,0x65,0x1e,0x41,0x76,0x06,0xa4,0x41,0x76,0x06,0xa6,0x86,0x3c,0x46,0x1e, + 0x40,0x74,0x04,0xa4,0x04,0x3d,0x64,0x1e,0x3f,0x76,0x06,0xa6,0x86,0x3d,0x46,0x1e, + 0x16,0x3e,0x65,0x0c,0xaf,0xe0,0x16,0x60,0x3c,0x75,0x05,0xb6,0xf7,0xb6,0xaa,0xf0, + 0x16,0x60,0xa7,0xb6,0xf7,0xa6,0x06,0x2a,0x1b,0x76,0x06,0x85,0x0e,0xe8,0x37,0x76, + 0x56,0x1c,0x06,0xa4,0x37,0x76,0x56,0x1c,0x06,0xa6,0x86,0x3c,0x46,0x1e,0xb7,0xb6, + 0x86,0x3e,0xc7,0xb6,0x34,0x74,0x45,0x1c,0x0d,0xf0,0x33,0x76,0x56,0x1c,0x06,0xa4, + 0x33,0x76,0x56,0x1c,0x06,0xa6,0x86,0x3c,0x46,0x1e,0xb7,0xb6,0x86,0x3e,0xc7,0xb6, + 0x30,0x76,0x65,0x1c,0x05,0xa6,0xd7,0xb6,0x06,0x60,0xe7,0xb6,0x83,0xf0,0x00,0x00, + 0x40,0x9f,0x00,0x00,0x41,0x9f,0x00,0x00,0x8a,0x9e,0x00,0x00,0x20,0x9e,0x00,0x00, + 0x00,0x80,0x02,0x00,0x58,0x3e,0x00,0x00,0xce,0xa5,0x00,0x00,0xd0,0xa5,0x00,0x00, + 0xd4,0xa5,0x00,0x00,0x1c,0x9e,0x00,0x00,0x1e,0x01,0x00,0x00,0x1f,0x01,0x00,0x00, + 0x71,0xa4,0x00,0x00,0xd0,0x83,0x00,0x00,0x6d,0xa4,0x00,0x00,0x6e,0xa4,0x00,0x00, + 0x6f,0xa4,0x00,0x00,0x70,0xa4,0x00,0x00,0x69,0xa4,0x00,0x00,0x6a,0xa4,0x00,0x00, + 0x6b,0xa4,0x00,0x00,0x6c,0xa4,0x00,0x00,0x66,0x9e,0x00,0x00,0xc0,0x3e,0x00,0x00, + 0x64,0xa4,0x00,0x00,0x37,0xaa,0x00,0x00,0x38,0xaa,0x00,0x00,0x39,0xaa,0x00,0x00, + 0x3a,0xaa,0x00,0x00,0x76,0x9e,0x00,0x00,0x77,0x9e,0x00,0x00,0x78,0x9e,0x00,0x00, + 0x79,0x9e,0x00,0x00,0xa5,0xa0,0x00,0x00,0x65,0xa4,0x00,0x00,0x66,0xa4,0x00,0x00, + 0x67,0xa4,0x00,0x00,0x68,0xa4,0x00,0x00,0x31,0xaa,0x00,0x00,0x0f,0x01,0x00,0x00, + 0x10,0x01,0x00,0x00,0x0e,0x01,0x00,0x00,0x0c,0x01,0x00,0x00,0x0d,0x01,0x00,0x00, + 0xba,0x00,0x00,0x00,0x17,0x60,0xad,0x76,0x06,0xb7,0xfe,0xb7,0xad,0x77,0x07,0xa7, + 0xad,0x76,0x06,0xa6,0x86,0x3c,0x76,0x1e,0xac,0x77,0x07,0xa7,0x07,0x3d,0x67,0x1e, + 0xab,0x76,0x06,0xa6,0x86,0x3d,0x76,0x1e,0xaa,0x77,0x07,0x87,0xaa,0x75,0x75,0x1c, + 0x05,0xa5,0xa9,0x74,0x47,0x1c,0x07,0xa7,0x87,0x3c,0x57,0x1e,0x67,0x1c,0xa7,0x76, + 0x06,0xb7,0x17,0x01,0xa7,0x76,0x06,0xb1,0x27,0x01,0xa6,0x76,0x06,0xb1,0x87,0x3f, + 0xa6,0x76,0x06,0xb7,0x6e,0x00,0x70,0x20,0xcf,0x00,0xa4,0x77,0x37,0xa6,0x06,0x2a, + 0xa4,0xe0,0xa3,0x75,0x05,0xa6,0x06,0x2a,0x40,0xe0,0xa2,0x76,0x06,0xa4,0xa2,0x76, + 0x06,0xa6,0x86,0x3c,0x46,0x1e,0xa1,0x74,0x04,0xa4,0x04,0x3d,0x64,0x1e,0xa0,0x76, + 0x06,0xa6,0x86,0x3d,0x46,0x1e,0x06,0x2a,0xbd,0xe1,0x9e,0x76,0x06,0xa4,0x9e,0x76, + 0x06,0xa6,0x86,0x3c,0x46,0x1e,0x9d,0x74,0x04,0xa4,0x04,0x3d,0x64,0x1e,0x9c,0x76, + 0x06,0xa6,0x86,0x3d,0x46,0x1e,0x06,0x2a,0x02,0xe8,0x16,0x60,0xa6,0xf0,0x17,0xa6, + 0x06,0x20,0x46,0x01,0x17,0xb6,0x55,0x60,0x65,0x0c,0xba,0xe1,0x16,0x60,0x17,0xb6, + 0xa7,0xb6,0x83,0x76,0x06,0x85,0x93,0x76,0x56,0x1c,0x06,0xa4,0x93,0x76,0x56,0x1c, + 0x06,0xa6,0x86,0x3c,0x46,0x1e,0xb7,0xb6,0x86,0x3e,0xc7,0xb6,0x90,0x72,0x25,0x1c, + 0x05,0xa6,0xd7,0xb6,0x06,0x60,0xe7,0xb6,0xa3,0xf1,0x16,0x2a,0x2b,0xe0,0x81,0x74, + 0x04,0xa3,0x81,0x74,0x04,0xa4,0x84,0x3c,0x34,0x1e,0x80,0x73,0x03,0xa3,0x03,0x3d, + 0x43,0x1e,0x7f,0x74,0x04,0xa4,0x84,0x3d,0x34,0x1e,0x04,0x2a,0x09,0xe8,0x17,0xa5, + 0x05,0x20,0x45,0x01,0x17,0xb5,0x34,0x60,0x54,0x0c,0x8a,0xe1,0x17,0xb6,0x41,0xf0, + 0x79,0x74,0x04,0xa3,0x79,0x74,0x04,0xa4,0x84,0x3c,0x34,0x1e,0x78,0x73,0x03,0xa3, + 0x03,0x3d,0x43,0x1e,0x77,0x74,0x04,0xa4,0x84,0x3d,0x34,0x1e,0x17,0xb6,0x04,0x2a, + 0x4d,0xe9,0x5c,0xf0,0x26,0x2a,0x74,0xe1,0x6b,0x74,0x04,0xa3,0x6b,0x74,0x04,0xa4, + 0x84,0x3c,0x34,0x1e,0x6a,0x73,0x03,0xa3,0x03,0x3d,0x43,0x1e,0x69,0x74,0x04,0xa4, + 0x84,0x3d,0x34,0x1e,0x04,0x2a,0x4e,0xe1,0x67,0x74,0x04,0xa3,0x67,0x74,0x04,0xa4, + 0x84,0x3c,0x34,0x1e,0x66,0x73,0x03,0xa3,0x03,0x3d,0x43,0x1e,0x65,0x74,0x04,0xa4, + 0x84,0x3d,0x34,0x1e,0x04,0x2a,0x0f,0xe8,0x17,0xa4,0x04,0x20,0x44,0x01,0x17,0xb4, + 0x50,0x75,0x05,0x85,0x63,0x73,0x35,0x1c,0x05,0xa5,0x45,0x0c,0x49,0xe1,0x15,0x60, + 0x17,0xb5,0x37,0xb6,0x45,0xf1,0x16,0x60,0xbd,0xf0,0x16,0x2a,0xbd,0xe0,0x05,0x60, + 0xa7,0xb5,0x4f,0x75,0x05,0xa3,0x03,0x2a,0x30,0xe0,0x4e,0x74,0x04,0xa3,0x4e,0x74, + 0x04,0xa4,0x84,0x3c,0x34,0x1e,0x4d,0x73,0x03,0xa3,0x03,0x3d,0x43,0x1e,0x4c,0x74, + 0x04,0xa4,0x84,0x3d,0x34,0x1e,0x04,0x2a,0x16,0xe1,0x4a,0x74,0x04,0xa3,0x4a,0x74, + 0x04,0xa4,0x84,0x3c,0x34,0x1e,0x49,0x73,0x03,0xa3,0x03,0x3d,0x43,0x1e,0x48,0x74, + 0x04,0xa4,0x84,0x3d,0x34,0x1e,0x04,0x2a,0x04,0xe8,0x17,0xb6,0x27,0x60,0x05,0xb7, + 0x17,0xf1,0x17,0xa3,0x03,0x20,0x43,0x01,0x17,0xb3,0x31,0x75,0x05,0x85,0x44,0x72, + 0x25,0x1c,0x05,0xa5,0x35,0x0c,0x0c,0xe1,0xbb,0xf0,0x13,0x2a,0x22,0xe0,0x35,0x76, + 0x06,0xa4,0x35,0x76,0x06,0xa6,0x86,0x3c,0x46,0x1e,0x34,0x74,0x04,0xa4,0x04,0x3d, + 0x64,0x1e,0x33,0x76,0x06,0xa6,0x86,0x3d,0x46,0x1e,0x06,0x2a,0xf9,0xe0,0x31,0x76, + 0x06,0xa4,0x31,0x76,0x06,0xa6,0x86,0x3c,0x46,0x1e,0x30,0x74,0x04,0xa4,0x04,0x3d, + 0x64,0x1e,0x2f,0x76,0x06,0xa6,0x86,0x3d,0x46,0x1e,0x17,0xb3,0x06,0x2a,0xe7,0xe8, + 0xcd,0xf7,0x23,0x2a,0xe5,0xe0,0x23,0x74,0x04,0xa2,0x23,0x74,0x04,0xa4,0x84,0x3c, + 0x24,0x1e,0x22,0x72,0x02,0xa2,0x02,0x3d,0x42,0x1e,0x21,0x74,0x04,0xa4,0x84,0x3d, + 0x24,0x1e,0x04,0x2a,0xc0,0xe0,0x1f,0x74,0x04,0xa2,0x1f,0x74,0x04,0xa4,0x84,0x3c, + 0x24,0x1e,0x1e,0x72,0x02,0xa2,0x02,0x3d,0x42,0x1e,0x1d,0x74,0x04,0xa4,0x84,0x3d, + 0x24,0x1e,0x04,0x2a,0x3f,0xe8,0x0a,0x75,0x05,0x85,0x1d,0x74,0x45,0x1c,0x17,0xa4, + 0x05,0xa5,0x45,0x0c,0xbd,0xe0,0x17,0xb6,0x37,0xb3,0xba,0xf0,0x31,0xaa,0x00,0x00, + 0x37,0xaa,0x00,0x00,0x38,0xaa,0x00,0x00,0x39,0xaa,0x00,0x00,0x3a,0xaa,0x00,0x00, + 0x1c,0x9e,0x00,0x00,0xb7,0x00,0x00,0x00,0xb8,0x00,0x00,0x00,0x76,0x9e,0x00,0x00, + 0x77,0x9e,0x00,0x00,0x78,0x9e,0x00,0x00,0x79,0x9e,0x00,0x00,0x66,0x9e,0x00,0x00, + 0xd8,0xa5,0x00,0x00,0x46,0xa4,0x00,0x00,0x47,0xa4,0x00,0x00,0x48,0xa4,0x00,0x00, + 0x49,0xa4,0x00,0x00,0x4a,0xa4,0x00,0x00,0x4b,0xa4,0x00,0x00,0x4c,0xa4,0x00,0x00, + 0x4d,0xa4,0x00,0x00,0x0c,0x01,0x00,0x00,0x0d,0x01,0x00,0x00,0xba,0x00,0x00,0x00, + 0xb9,0x00,0x00,0x00,0x17,0xb6,0x5a,0xf0,0x26,0x2a,0x82,0xe0,0x05,0x60,0xa7,0xb5, + 0x92,0x75,0x05,0xa3,0x03,0x2a,0x2f,0xe0,0x91,0x74,0x04,0xa3,0x91,0x74,0x04,0xa4, + 0x84,0x3c,0x34,0x1e,0x90,0x73,0x03,0xa3,0x03,0x3d,0x43,0x1e,0x8f,0x74,0x04,0xa4, + 0x84,0x3d,0x34,0x1e,0x04,0x2a,0x56,0xe0,0x8d,0x74,0x04,0xa3,0x8d,0x74,0x04,0xa4, + 0x84,0x3c,0x34,0x1e,0x8c,0x73,0x03,0xa3,0x03,0x3d,0x43,0x1e,0x8b,0x74,0x04,0xa4, + 0x84,0x3d,0x34,0x1e,0x04,0x2a,0x59,0xe0,0x17,0xa5,0x05,0x20,0x45,0x01,0x17,0xb5, + 0x87,0x76,0x06,0x86,0x87,0x72,0x26,0x1c,0x06,0xa6,0x56,0x0c,0x51,0xe0,0x16,0x60, + 0x17,0xb6,0x37,0xb4,0x4d,0xf0,0x13,0x2a,0x23,0xe0,0x78,0x74,0x04,0xa2,0x78,0x74, + 0x04,0xa4,0x84,0x3c,0x24,0x1e,0x77,0x72,0x02,0xa2,0x02,0x3d,0x42,0x1e,0x76,0x74, + 0x04,0xa4,0x84,0x3d,0x24,0x1e,0x04,0x2a,0x3b,0xe0,0x74,0x74,0x04,0xa2,0x74,0x74, + 0x04,0xa4,0x84,0x3c,0x24,0x1e,0x73,0x72,0x02,0xa2,0x02,0x3d,0x42,0x1e,0x72,0x74, + 0x04,0xa4,0x84,0x3d,0x24,0x1e,0x17,0xb3,0x04,0x2a,0x29,0xe0,0x05,0xb4,0x28,0xf0, + 0x23,0x2a,0x26,0xe0,0x66,0x76,0x06,0xa4,0x66,0x76,0x06,0xa6,0x86,0x3c,0x46,0x1e, + 0x65,0x74,0x04,0xa4,0x04,0x3d,0x64,0x1e,0x64,0x76,0x06,0xa6,0x86,0x3d,0x46,0x1e, + 0x06,0x2a,0x03,0xe8,0x16,0x60,0x17,0xb6,0x12,0xf0,0x60,0x76,0x06,0xa4,0x60,0x76, + 0x06,0xa6,0x86,0x3c,0x46,0x1e,0x5f,0x74,0x04,0xa4,0x04,0x3d,0x64,0x1e,0x5e,0x76, + 0x06,0xa6,0x86,0x3d,0x46,0x1e,0x06,0x2a,0x03,0xe0,0x14,0x60,0x17,0xb4,0x05,0xb6, + 0xcf,0x00,0xf0,0x24,0x7c,0x00,0x5b,0x77,0x77,0xa7,0x07,0x2a,0x05,0xe8,0x57,0x77, + 0x07,0x87,0x76,0x67,0x67,0x1c,0x07,0xf0,0x58,0x77,0x07,0xa7,0x07,0x2a,0x57,0x77, + 0x02,0xe8,0x17,0xa7,0x01,0xf0,0x07,0xa7,0x56,0x73,0x03,0xa6,0x13,0xa4,0x84,0x3c, + 0x64,0x1e,0x06,0x60,0x65,0x12,0x53,0x7d,0xae,0x61,0x7f,0x12,0x7f,0x01,0x1d,0xf0, + 0x57,0x12,0x57,0x1c,0x37,0x1c,0x27,0xa1,0x37,0xa2,0x2c,0x12,0x5c,0x01,0x17,0x12, + 0x57,0x01,0xf1,0x11,0xe7,0x03,0xf9,0x11,0xc7,0x1c,0x77,0x1c,0xd7,0x1c,0x07,0xc7, + 0x77,0x01,0x7f,0x0d,0x08,0xe8,0x87,0x65,0x67,0x1c,0x77,0x1c,0x37,0x1c,0x87,0xb1, + 0x97,0xb2,0x06,0x20,0x46,0x01,0x05,0x20,0x45,0x01,0x45,0x0c,0xe1,0xef,0x42,0x77, + 0x07,0xb6,0x42,0x77,0x06,0x60,0x07,0xb6,0x6c,0x00,0xf0,0x20,0xcf,0x00,0xf0,0x25, + 0x60,0x9f,0x70,0x9e,0x36,0x77,0x07,0x87,0x3e,0x76,0x76,0x1c,0x06,0xa6,0x06,0x2a, + 0x4f,0xe8,0x3c,0x76,0x06,0xa4,0x3c,0x76,0x06,0xa6,0x86,0x3c,0x3c,0x75,0x75,0x1c, + 0x05,0xa5,0x3b,0x72,0x27,0x1c,0x07,0xa7,0x87,0x3c,0x46,0x1e,0x57,0x1e,0x67,0x0c, + 0x39,0x75,0x39,0x77,0x04,0xe0,0x16,0x60,0x05,0xb6,0x56,0x60,0x05,0xf0,0x07,0xa6, + 0x06,0x2a,0x86,0x00,0x01,0xe0,0x05,0xb6,0x07,0xb6,0x32,0x77,0x07,0xa7,0x07,0x2a, + 0x2f,0xe8,0x2c,0x77,0x07,0xa6,0x2c,0x77,0x07,0xa7,0x87,0x3c,0x67,0x1e,0x7e,0x12, + 0x7e,0x1c,0x7e,0x1c,0x2e,0x3e,0x02,0x12,0x03,0x60,0x44,0x61,0x2c,0x7f,0x22,0x77, + 0x07,0xa7,0x22,0x76,0x06,0xa5,0x85,0x3c,0x75,0x1e,0x06,0x60,0x1d,0x73,0x7e,0x01, + 0x14,0x60,0x11,0xf0,0x67,0x12,0x37,0x3c,0x67,0x05,0x37,0x1c,0x82,0x62,0x27,0x1c, + 0x77,0xa2,0x87,0xa7,0x87,0x3c,0x27,0x1e,0xe7,0x0d,0x03,0xe8,0x07,0x12,0x67,0x1c, + 0x07,0xb4,0x06,0x20,0x46,0x01,0x56,0x0c,0xed,0xef,0x02,0x12,0x13,0x73,0x1c,0x7f, + 0x60,0x8f,0x70,0x8e,0xf0,0x21,0xcf,0x00,0xd8,0xa5,0x00,0x00,0x46,0xa4,0x00,0x00, + 0x47,0xa4,0x00,0x00,0x48,0xa4,0x00,0x00,0x49,0xa4,0x00,0x00,0x4a,0xa4,0x00,0x00, + 0x4b,0xa4,0x00,0x00,0x4c,0xa4,0x00,0x00,0x4d,0xa4,0x00,0x00,0x1c,0x9e,0x00,0x00, + 0xb9,0x00,0x00,0x00,0x20,0xaa,0x00,0x00,0x4a,0xa0,0x00,0x00,0x86,0x9e,0x00,0x00, + 0x8a,0x9e,0x00,0x00,0x00,0xe0,0x02,0x00,0x40,0x9f,0x00,0x00,0x41,0x9f,0x00,0x00, + 0x83,0x00,0x00,0x00,0x3e,0xa4,0x00,0x00,0x3f,0xa4,0x00,0x00,0x84,0x00,0x00,0x00, + 0x85,0x00,0x00,0x00,0xd9,0xa5,0x00,0x00,0x00,0x9e,0x00,0x00,0x22,0x83,0x00,0x00, + 0x00,0x2d,0x00,0x00,0x70,0x25,0x7a,0x00,0xbd,0x77,0x07,0x8f,0xbd,0x77,0xf7,0x1c, + 0x07,0xa7,0x07,0x2a,0x77,0xe8,0xbb,0x77,0x07,0xa6,0xbb,0x77,0x07,0xa7,0xbb,0x71, + 0x7c,0x12,0x4c,0x3c,0x75,0x12,0x65,0x3c,0x5c,0x1c,0xb9,0x74,0xc4,0x1c,0x03,0x60, + 0x7d,0x12,0x7d,0x1c,0x37,0x3c,0x7d,0x1c,0x0c,0x28,0x6e,0x12,0x4e,0x3c,0x67,0x12, + 0x67,0x3c,0x7e,0x1c,0x01,0xa7,0x27,0x2a,0x58,0xe0,0x04,0xa7,0x07,0x2a,0x55,0xe8, + 0xb1,0x7b,0xd7,0x12,0x37,0x1c,0xb0,0x75,0x57,0x1c,0x37,0x3c,0xb7,0x1c,0x77,0xa5, + 0x87,0xa2,0x82,0x3c,0x52,0x1e,0xad,0x77,0xf7,0x1c,0x07,0xa7,0xad,0x75,0xf5,0x1c, + 0x05,0xa5,0x85,0x3c,0x75,0x1e,0x25,0x0c,0x12,0xe0,0x67,0x12,0x67,0x1c,0x6a,0x12, + 0x3a,0x3c,0xa7,0x1c,0x37,0x1c,0xa4,0x7a,0xa7,0x1c,0x37,0x3c,0xb7,0x1c,0x77,0xab, + 0x87,0xa7,0x87,0x3c,0xb7,0x1e,0x5b,0x12,0x2b,0x3e,0x7b,0x0c,0x14,0xe8,0x9d,0x7b, + 0x67,0x12,0x67,0x1c,0x6a,0x12,0x3a,0x3c,0xa7,0x1c,0x37,0x1c,0x9b,0x7a,0xa7,0x1c, + 0x37,0x3c,0x7b,0x1c,0x7b,0xaa,0x8b,0xa7,0x87,0x3c,0xa7,0x1e,0x75,0x0c,0x1d,0xe0, + 0x25,0x3e,0x25,0x0c,0x1a,0xe0,0x74,0xa7,0xc5,0x12,0x45,0x1c,0xe5,0x1c,0x75,0xa5, + 0x57,0x05,0xe7,0x01,0x67,0x01,0x72,0x12,0x72,0x01,0xa5,0x65,0x25,0x0d,0x04,0xe8, + 0x91,0x75,0x75,0x05,0x57,0x12,0x67,0x01,0x77,0x01,0x8f,0x75,0xf5,0x1c,0x05,0xa5, + 0x15,0x3e,0x75,0x0d,0x02,0xe8,0x47,0x60,0x01,0xb7,0x03,0x20,0x01,0x20,0x74,0x20, + 0xa3,0x2a,0xa0,0xe7,0x6a,0x00,0x70,0x21,0xcf,0x00,0xf0,0x25,0x78,0x00,0x01,0x65, + 0x10,0x05,0x2a,0x12,0x86,0x77,0x07,0xa7,0x07,0x2a,0x17,0xe8,0x06,0x60,0x84,0x77, + 0x07,0xb6,0x7a,0x77,0x84,0x72,0x13,0x60,0x44,0x60,0x07,0xa5,0x15,0x2a,0x02,0xe0, + 0x07,0xb6,0x05,0xf0,0x15,0x24,0x45,0x01,0x53,0x0c,0x01,0xe8,0x07,0xb4,0x07,0x20, + 0x27,0x0f,0xf3,0xe7,0x06,0x60,0x79,0x77,0x07,0xb6,0x79,0x77,0x07,0xa7,0x0a,0xb7, + 0x7a,0x77,0x07,0xa7,0x1a,0xb7,0x79,0x77,0x07,0xa7,0x2a,0xb7,0xa6,0x12,0x07,0x60, + 0x6d,0x74,0x75,0x12,0x45,0x1c,0x76,0x73,0x35,0x1c,0x05,0xa5,0x96,0xb5,0x07,0x20, + 0x56,0x20,0xa7,0x2a,0xf6,0xe7,0x61,0x77,0x07,0x8e,0x72,0x77,0xe7,0x1c,0x07,0xa7, + 0x74,0x32,0x47,0x1c,0x00,0x97,0x70,0x77,0xe7,0x1c,0x07,0xa7,0x47,0x1c,0x10,0x97, + 0x6f,0x77,0xa7,0xa6,0xb7,0xa5,0x85,0x3c,0x65,0x1e,0x40,0x95,0x56,0x12,0x6c,0x73, + 0x36,0x1c,0x66,0x01,0x60,0x96,0xc7,0xa6,0xd7,0xa4,0x84,0x3c,0x64,0x1e,0x50,0x94, + 0x46,0x12,0x36,0x1c,0x66,0x01,0x70,0x96,0xe7,0xa6,0xf7,0xa8,0x88,0x3c,0x68,0x1e, + 0x65,0x77,0x07,0xa7,0x65,0x76,0x06,0xa9,0x89,0x3c,0x79,0x1e,0x95,0x12,0x85,0x05, + 0xc0,0x95,0x62,0x77,0x07,0xa7,0x62,0x76,0x06,0xa6,0x86,0x3c,0x76,0x1e,0x20,0x96, + 0x61,0x77,0x07,0xa7,0x61,0x76,0x06,0xa6,0x86,0x3c,0x76,0x1e,0x30,0x96,0x20,0x87, + 0x76,0x05,0xd0,0x96,0x0d,0x60,0x5d,0x73,0xe3,0x1c,0x90,0x93,0x5d,0x74,0xe4,0x1c, + 0xa0,0x94,0x5c,0x75,0xe5,0x1c,0xe0,0x95,0x5c,0x76,0xe6,0x1c,0xb0,0x96,0x10,0x87, + 0x83,0x2c,0x37,0x16,0xf0,0x97,0x10,0x85,0x85,0x3e,0x04,0x64,0x04,0x1c,0x04,0x95, + 0x00,0x87,0x37,0x16,0x46,0x64,0x06,0x1c,0x06,0x97,0x00,0x84,0x84,0x3e,0x83,0x64, + 0x03,0x1c,0x03,0x94,0x87,0xf1,0xd6,0x12,0x36,0x3c,0xd6,0x1c,0x76,0x1c,0x4f,0x75, + 0x65,0x1c,0x05,0xab,0xb7,0x1c,0x3e,0x75,0x57,0x1c,0x07,0xa7,0x47,0x2a,0x78,0xe9, + 0x07,0x2a,0x76,0xe9,0x4b,0x77,0x76,0x1c,0x56,0xa7,0x66,0xa2,0x82,0x3c,0x72,0x1e, + 0x87,0x32,0x27,0x0c,0x22,0xe8,0x00,0x83,0x32,0x0c,0x08,0xe0,0x44,0x64,0x04,0x1c, + 0x04,0xa4,0x56,0xb4,0x85,0x64,0x05,0x1c,0x05,0xa5,0x66,0xb5,0xd7,0x12,0x37,0x3c, + 0xd7,0x1c,0x40,0x76,0x67,0x1c,0x57,0xa6,0x67,0xa7,0x87,0x3c,0x67,0x1e,0x00,0x86, + 0x67,0x05,0x90,0x83,0x03,0xac,0x82,0x12,0xc2,0x05,0xf1,0x11,0x72,0x03,0xf9,0x11, + 0x83,0x32,0x63,0x05,0x39,0x7f,0x2c,0x1c,0x8b,0xf0,0x60,0x84,0x24,0x0c,0x7d,0xe0, + 0x37,0x77,0xe7,0x1c,0x07,0xa7,0x45,0x12,0x73,0x32,0x35,0x1c,0x75,0x05,0x25,0x0d, + 0x08,0xe8,0x40,0x85,0x33,0x74,0x45,0x1c,0x75,0x05,0x65,0x01,0x56,0xb5,0x85,0x3e, + 0x66,0xb5,0xd5,0x12,0x35,0x3c,0xd5,0x1c,0x2b,0x76,0x65,0x1c,0x55,0xa6,0x65,0xa2, + 0x82,0x3c,0x62,0x1e,0x60,0x85,0x52,0x05,0x0e,0xa5,0x1e,0xa6,0x86,0x3c,0x56,0x1e, + 0x29,0x75,0xe5,0x1c,0x05,0xa5,0x56,0x05,0x4f,0xf0,0x00,0x00,0x1c,0x9e,0x00,0x00, + 0x1a,0x01,0x00,0x00,0xe4,0xa3,0x00,0x00,0xe5,0xa3,0x00,0x00,0xfa,0xa3,0x00,0x00, + 0xa4,0xa2,0x00,0x00,0x8a,0x9e,0x00,0x00,0x83,0x00,0x00,0x00,0x1b,0x01,0x00,0x00, + 0x1c,0x01,0x00,0x00,0xb4,0x00,0x00,0x00,0x1d,0x01,0x00,0x00,0x62,0xa4,0x00,0x00, + 0xa5,0xa0,0x00,0x00,0x04,0xa4,0x00,0x00,0x4a,0xa0,0x00,0x00,0x2c,0xa4,0x00,0x00, + 0x70,0x05,0x00,0x00,0x9d,0x00,0x00,0x00,0x9f,0x00,0x00,0x00,0x20,0x9e,0x00,0x00, + 0x00,0xff,0xff,0xff,0x30,0x9e,0x00,0x00,0x31,0x9e,0x00,0x00,0x32,0x9e,0x00,0x00, + 0x33,0x9e,0x00,0x00,0x34,0x9e,0x00,0x00,0x35,0x9e,0x00,0x00,0x99,0x00,0x00,0x00, + 0x9b,0x00,0x00,0x00,0xc1,0x00,0x00,0x00,0x9c,0x00,0x00,0x00,0x1c,0x02,0x00,0x00, + 0x18,0x02,0x00,0x00,0xa2,0xa0,0x00,0x00,0xd0,0x83,0x00,0x00,0x9e,0x00,0x00,0x00, + 0x80,0xff,0xff,0xff,0x9a,0x00,0x00,0x00,0x96,0x05,0xf1,0x11,0x62,0x03,0xf9,0x11, + 0x73,0x32,0x73,0x05,0x7e,0x7f,0x92,0x1c,0x0a,0xf0,0x7d,0x76,0x62,0x1c,0xc0,0x87, + 0xf1,0x11,0x72,0x03,0xf9,0x11,0x60,0x83,0x63,0x1c,0x78,0x7f,0x82,0x1c,0x2c,0x12, + 0x6c,0x01,0xd6,0x12,0x36,0x3c,0xd6,0x1c,0x77,0x77,0x76,0x1c,0x76,0xa7,0x86,0xa2, + 0x82,0x3c,0x72,0x1e,0x87,0x2c,0x27,0x0c,0x24,0xe8,0x10,0x83,0x32,0x0c,0x08,0xe0, + 0xc4,0x63,0x04,0x1c,0x04,0xa4,0x76,0xb4,0x05,0x64,0x05,0x1c,0x05,0xa5,0x86,0xb5, + 0xd7,0x12,0x37,0x3c,0xd7,0x1c,0x6b,0x76,0x67,0x1c,0x77,0xa6,0x87,0xa7,0x87,0x3c, + 0x67,0x1e,0x10,0x86,0x67,0x05,0xa0,0x83,0x03,0xa3,0x80,0x93,0x20,0x82,0x32,0x05, + 0xf1,0x11,0x72,0x03,0xf9,0x11,0x83,0x32,0x63,0x05,0x60,0x7f,0x80,0x84,0x42,0x1c, + 0x3b,0xf0,0x70,0x85,0x25,0x0c,0x2d,0xe0,0x60,0x77,0xe7,0x1c,0x07,0xa7,0x73,0x32, + 0x35,0x1c,0x75,0x05,0x25,0x0d,0x08,0xe8,0x50,0x85,0x5c,0x74,0x45,0x1c,0x75,0x05, + 0x65,0x01,0x76,0xb5,0x85,0x3e,0x86,0xb5,0xd5,0x12,0x35,0x3c,0xd5,0x1c,0x55,0x76, + 0x65,0x1c,0x75,0xa6,0x85,0xa2,0x82,0x3c,0x62,0x1e,0x70,0x85,0x52,0x05,0x2e,0xa5, + 0x3e,0xa6,0x86,0x3c,0x56,0x1e,0xb0,0x83,0x03,0xa5,0x56,0x05,0x30,0x84,0x46,0x05, + 0xf1,0x11,0x62,0x03,0xf9,0x11,0x73,0x32,0x73,0x05,0x48,0x7f,0x30,0x85,0x52,0x1c, + 0x0b,0xf0,0x47,0x76,0x62,0x1c,0xd0,0x87,0xf1,0x11,0x72,0x03,0xf9,0x11,0x70,0x83, + 0x63,0x1c,0x42,0x7f,0x20,0x83,0x32,0x1c,0x62,0x01,0x90,0x84,0x04,0xa7,0x7c,0x0c, + 0x10,0xe8,0x0e,0xa6,0x1e,0xa7,0x87,0x3c,0x67,0x1e,0x41,0x76,0xe6,0x1c,0x06,0xa6, + 0x75,0x12,0x65,0x05,0x5c,0x0d,0x06,0xe0,0x07,0x24,0x67,0x05,0x7c,0x12,0x6c,0x01, + 0x01,0xf0,0x7c,0x12,0xa0,0x85,0x05,0xa7,0x72,0x0c,0x0f,0xe8,0x2e,0xa6,0x3e,0xa7, + 0x87,0x3c,0x67,0x1e,0xb0,0x83,0x03,0xa6,0x75,0x12,0x65,0x05,0x52,0x0d,0x06,0xe0, + 0x07,0x24,0x67,0x05,0x72,0x12,0x62,0x01,0x01,0xf0,0x72,0x12,0xe0,0x84,0x04,0xa7, + 0x07,0x2a,0xb7,0x12,0xb7,0x1c,0x86,0x2c,0x26,0x16,0x85,0x2c,0xc5,0x16,0xb7,0x1c, + 0x77,0x1c,0xa7,0x1c,0x07,0xe8,0x47,0xb6,0x82,0x3e,0x57,0xb2,0x67,0xb5,0x8c,0x3e, + 0x77,0xbc,0x06,0xf0,0x47,0xb5,0x8c,0x3e,0x57,0xbc,0x67,0xb6,0x82,0x3e,0x77,0xb2, + 0xb7,0x12,0xb7,0x1c,0xb7,0x1c,0x77,0x1c,0xa7,0x1c,0xd6,0x12,0x36,0x3c,0xd6,0x1c, + 0x1d,0x75,0x56,0x1c,0x96,0xa5,0xa6,0xa6,0x86,0x3c,0x56,0x1e,0x46,0x3e,0x87,0xb6, + 0x0d,0x20,0x4d,0x01,0x1c,0x77,0x1c,0x76,0x06,0xa6,0x6d,0x0c,0x74,0xee,0x05,0x60, + 0x1b,0x72,0x53,0x12,0x12,0xf0,0x56,0x12,0x36,0x3c,0x56,0x1c,0x76,0x1c,0x18,0x74, + 0x46,0x1c,0x06,0xa4,0x46,0x12,0x46,0x1c,0x46,0x1c,0x66,0x1c,0xa6,0x1c,0x96,0xa4, + 0x44,0x2a,0x01,0xe0,0x86,0xb3,0x05,0x20,0x45,0x01,0x02,0xa6,0x65,0x0c,0xeb,0xef, + 0x0e,0x73,0x03,0xa7,0x74,0x12,0x34,0x3c,0x74,0x1c,0x0c,0x72,0x04,0x20,0x0d,0x7f, + 0x01,0x65,0x10,0x1c,0x68,0x00,0xf0,0x21,0xcf,0x00,0x00,0x00,0xd0,0x83,0x00,0x00, + 0x00,0xff,0xff,0xff,0xa2,0xa0,0x00,0x00,0xa0,0x00,0x00,0x00,0x80,0xff,0xff,0xff, + 0x9a,0x00,0x00,0x00,0x8a,0x9e,0x00,0x00,0xa5,0xa0,0x00,0x00,0x4a,0xa0,0x00,0x00, + 0xc1,0x01,0x00,0x00,0x8c,0x82,0x00,0x00,0x70,0x25,0x7a,0x00,0x86,0x7e,0x86,0x77, + 0x07,0xa7,0x07,0x2a,0x56,0xe8,0x0e,0xa7,0x1e,0xa5,0x85,0x3c,0x75,0x1e,0x1b,0x60, + 0x5b,0x0c,0x4f,0xe0,0x82,0x77,0x07,0xa7,0x82,0x76,0x06,0xaa,0x8a,0x3c,0x7a,0x1e, + 0x81,0x77,0x07,0x8d,0x67,0x67,0xd7,0x1c,0x07,0xa7,0x77,0x1c,0x7a,0x0d,0x48,0xe8, + 0x57,0x67,0xd7,0x1c,0x07,0xa7,0x7a,0x0c,0x0e,0xe8,0xba,0x0b,0x7b,0x7c,0x2c,0xba, + 0x7b,0x7f,0x0e,0xa6,0x1e,0xa7,0x87,0x3c,0x67,0x1e,0x7b,0x0c,0x39,0xe8,0x3c,0xbb, + 0x0c,0xba,0x1c,0xba,0x2e,0xf0,0x76,0x77,0x07,0xac,0x76,0x77,0x07,0xad,0x03,0x60, + 0xf2,0x67,0x36,0x12,0x5c,0x01,0x5d,0x01,0x16,0xf0,0x67,0x12,0x67,0x1c,0xe7,0x1c, + 0x27,0xa4,0x54,0x01,0xc4,0x05,0xe4,0x01,0x37,0xa7,0x57,0x01,0xd7,0x05,0xe7,0x01, + 0x47,0x1c,0x47,0x01,0x74,0x12,0x54,0x01,0x24,0x0d,0x27,0x0a,0x01,0xe8,0x63,0x12, + 0x06,0x20,0x46,0x01,0x72,0x12,0x56,0x0c,0x5f,0x77,0xe7,0xef,0x16,0x60,0x07,0xb6, + 0x06,0x60,0x17,0xb6,0x36,0x12,0x36,0x1c,0x76,0x1c,0x26,0xa5,0x27,0xb5,0x36,0xa6, + 0x37,0xb6,0x59,0x77,0x07,0xa6,0x60,0x77,0x07,0xb6,0x6a,0x00,0x70,0x21,0xcf,0x00, + 0x5a,0x77,0x66,0x67,0xd6,0x1c,0x06,0xa6,0x07,0xb6,0x56,0x67,0xd6,0x1c,0x06,0xa6, + 0x17,0xb6,0x46,0x67,0x6d,0x1c,0x0d,0xa6,0x27,0xb6,0x06,0x60,0x4f,0x77,0x07,0xb6, + 0xe8,0xf7,0xf0,0x25,0x78,0x00,0xf0,0x24,0x42,0x01,0x03,0x01,0x26,0x12,0x06,0x24, + 0x46,0x01,0x4c,0x77,0x07,0x87,0x0f,0x60,0x1a,0x12,0x0a,0x24,0x4a,0x01,0x4f,0x7b, + 0xac,0x61,0x6d,0x67,0x7d,0x1c,0x5e,0x67,0x7e,0x1c,0x43,0x67,0x73,0x1c,0x4c,0x75, + 0x75,0x1c,0x00,0x95,0x4c,0x75,0x75,0x1c,0x10,0x95,0x29,0xf0,0xa5,0x12,0x69,0x12, + 0xf1,0x11,0xc9,0x03,0xf9,0x11,0x20,0x96,0x1d,0xf0,0x97,0x12,0x57,0x1c,0x77,0x1c, + 0xb7,0x1c,0x07,0xc4,0x74,0x01,0x0d,0xa7,0x47,0x0d,0x12,0xe0,0x0e,0xa7,0x47,0x0d, + 0x0f,0xe0,0x03,0xa7,0x47,0x0d,0x0c,0xe0,0x00,0x86,0x06,0xa8,0x10,0x86,0x06,0xa7, + 0x87,0x3c,0x87,0x1e,0x07,0x3d,0x07,0x3b,0x74,0x0d,0x02,0xe8,0x0f,0x20,0x4f,0x01, + 0x05,0x20,0x45,0x01,0x51,0x0d,0xe1,0xef,0x20,0x86,0x06,0x20,0x46,0x01,0x62,0x0d, + 0xd5,0xef,0x27,0x60,0xf7,0x0c,0x22,0x00,0xf0,0x20,0x68,0x00,0xf0,0x21,0xcf,0x00, + 0xf0,0x24,0x7c,0x00,0x24,0x7c,0x30,0x77,0x07,0xa6,0x30,0x77,0x07,0xa7,0x87,0x3c, + 0x67,0x1e,0x1e,0x60,0x07,0x2a,0x16,0xe8,0x0c,0xa7,0x1c,0xae,0x8e,0x3c,0x7e,0x1e, + 0x0d,0x60,0x0e,0x2a,0x0b,0xe0,0x0e,0xf0,0xd7,0x12,0xd7,0x1c,0xc7,0x1c,0x27,0xa2, + 0x37,0xa3,0x27,0x7f,0x02,0x2a,0x04,0xe0,0x0d,0x20,0x4d,0x01,0xed,0x0c,0xf4,0xef, + 0xed,0x0c,0x3e,0x00,0x24,0x77,0x07,0xa7,0x07,0x2a,0x23,0x77,0x0f,0xe8,0x06,0x60, + 0x0e,0x2a,0x02,0xe0,0x07,0xa6,0x06,0x20,0x07,0xb6,0x1f,0x77,0x07,0xa5,0xa6,0x60, + 0x56,0x0c,0x15,0xe0,0x06,0x60,0x1b,0x75,0x05,0xb6,0x10,0xf0,0x0e,0x2a,0x04,0xe8, + 0x07,0xa6,0x06,0x20,0x07,0xb6,0x01,0xf0,0x07,0xbe,0x17,0x77,0x07,0xa5,0xa6,0x60, + 0x56,0x0c,0x05,0xe0,0x15,0x60,0x13,0x76,0x06,0xb5,0x06,0x60,0x07,0xb6,0x6c,0x00, + 0xf0,0x20,0xcf,0x00,0x8a,0x9e,0x00,0x00,0x63,0xa4,0x00,0x00,0x3e,0xa4,0x00,0x00, + 0x3f,0xa4,0x00,0x00,0x1c,0x9e,0x00,0x00,0x86,0x9e,0x00,0x00,0x00,0x28,0x00,0x00, + 0x4f,0xa0,0x00,0x00,0x4d,0xa0,0x00,0x00,0x3d,0xaa,0x00,0x00,0x00,0xe0,0x02,0x00, + 0xb5,0x00,0x00,0x00,0xb6,0x00,0x00,0x00,0x6a,0x9f,0x00,0x00,0x6b,0x9f,0x00,0x00, + 0xe2,0x4d,0x00,0x00,0x64,0xa4,0x00,0x00,0xda,0xa5,0x00,0x00,0xf0,0x25,0x78,0x00, + 0xa4,0x71,0x10,0x05,0xa4,0x77,0x07,0x8e,0x4e,0xa2,0x5e,0xa3,0xa3,0x77,0x00,0x97, + 0x34,0x60,0xa2,0x75,0xa3,0x76,0x07,0x60,0xa3,0x7f,0xa3,0x77,0xe7,0x1c,0x07,0xa7, + 0x07,0x2a,0x18,0xe8,0xa2,0x77,0x17,0xa6,0x07,0xa7,0x76,0x1c,0x07,0x60,0xa0,0x72, + 0xa1,0x73,0xa1,0x74,0x0d,0xf0,0x75,0x12,0x75,0x1c,0x2f,0x12,0x5f,0x1c,0x3d,0x12, + 0x5d,0x1c,0x45,0x1c,0x0d,0xcd,0x05,0xc5,0xd5,0x14,0x0f,0xd5,0x07,0x20,0x47,0x01, + 0x67,0x0d,0xf1,0xe7,0x9a,0x77,0x57,0xa7,0x17,0x2e,0x07,0x2a,0x07,0xe8,0x98,0x72, + 0x4e,0xa3,0x5e,0xa4,0x98,0x7f,0x98,0x72,0x83,0x61,0x98,0x7f,0x94,0x77,0x57,0xa7, + 0x47,0x2e,0x07,0x2a,0x09,0xe8,0x87,0x77,0x07,0x87,0x95,0x72,0x47,0xa3,0x57,0xa4, + 0x91,0x7f,0x94,0x72,0xa3,0x61,0x91,0x7f,0x8d,0x77,0x57,0xa7,0x27,0x2e,0x07,0x2a, + 0x0b,0xe8,0x91,0x72,0x8c,0x7f,0x7f,0x77,0x07,0x87,0x90,0x72,0x47,0xa3,0x57,0xa4, + 0x89,0x7f,0x8f,0x72,0xa3,0x61,0x89,0x7f,0x7b,0x77,0x07,0x8e,0xa7,0x67,0xe7,0x1c, + 0x07,0xa7,0x07,0x2a,0x06,0xe8,0x7d,0x77,0x07,0xa2,0x17,0xa3,0x89,0x74,0xa5,0x61, + 0x89,0x7f,0xd1,0x67,0x1e,0x1c,0x0e,0xa7,0x07,0x2a,0x49,0xe9,0x78,0x77,0x07,0xa3, + 0x86,0x72,0x02,0x1c,0x02,0x93,0x17,0xa5,0x85,0x74,0x04,0x1c,0x04,0x95,0x0e,0x60, + 0xed,0x12,0x6c,0x78,0x37,0xf1,0x08,0x87,0x26,0x65,0x67,0x1c,0x07,0xae,0xde,0x1c, + 0x4e,0x01,0x7d,0x77,0x07,0x1c,0x07,0x87,0x7e,0x0c,0x7e,0x02,0xd2,0x12,0x12,0x28, + 0xe2,0x1c,0x42,0x01,0x22,0x1c,0x33,0x60,0x7a,0x7f,0x7a,0x73,0x03,0x1c,0x03,0x92, + 0x0c,0x60,0xa9,0x61,0x14,0xf1,0x02,0x12,0x72,0x20,0x03,0x60,0x04,0x61,0x76,0x7f, + 0xd7,0x12,0x04,0x60,0x05,0x61,0x31,0xf0,0x76,0x12,0xf1,0x11,0x96,0x03,0xf9,0x11, + 0xc6,0x1c,0x66,0x1c,0x6b,0x71,0x16,0x1c,0x06,0xc6,0x76,0x01,0x70,0x72,0x62,0x0d, + 0x05,0xe8,0xc6,0x61,0x06,0x1c,0x76,0x1c,0x06,0xb5,0x12,0xf0,0x6d,0x73,0x36,0x0d, + 0x05,0xe8,0xc6,0x61,0x06,0x1c,0x76,0x1c,0x06,0xb4,0x0a,0xf0,0xc3,0x61,0x03,0x1c, + 0x73,0x1c,0xf6,0x37,0x02,0xe8,0xff,0x63,0xf6,0x1c,0x66,0x3a,0x76,0x20,0x03,0xb6, + 0xc6,0x61,0x06,0x1c,0x76,0x1c,0x06,0xa6,0x56,0x01,0x81,0x60,0x01,0x1c,0x16,0x1c, + 0x06,0xa3,0x03,0x20,0x06,0xb3,0x07,0x20,0x47,0x01,0xe7,0x0c,0xcd,0xef,0x07,0x60, + 0x75,0x12,0x76,0x12,0x07,0x01,0x84,0x60,0x04,0x1c,0x74,0x1c,0x04,0xa4,0x46,0x0c, + 0x15,0x0a,0x46,0x0a,0x07,0x20,0x07,0x2b,0xf5,0xe7,0x07,0x60,0x56,0x72,0x02,0x1c, + 0x02,0x97,0x76,0x12,0x07,0x01,0x84,0x60,0x04,0x1c,0x74,0x1c,0x04,0xa4,0x46,0x0c, + 0x06,0xe0,0x51,0x0f,0x04,0xe8,0x4f,0x73,0x03,0x1c,0x03,0x91,0x46,0x12,0x07,0x20, + 0x07,0x2b,0xf0,0xe7,0xd6,0x12,0x02,0x60,0x2b,0x12,0x16,0xf0,0xc7,0x61,0x07,0x1c, + 0x67,0x1c,0x07,0xa7,0x57,0x01,0x57,0x0f,0x0d,0xe0,0x67,0x12,0xf1,0x11,0x97,0x03, + 0xf9,0x11,0xc7,0x1c,0x77,0x1c,0x3a,0x74,0x47,0x1c,0x07,0xc7,0x77,0x01,0x72,0x1c, + 0x0b,0x20,0x4b,0x01,0x06,0x20,0x46,0x01,0xe6,0x0c,0xe8,0xef,0x0b,0x2a,0x04,0xe8, + 0xb3,0x12,0x37,0x7f,0x2a,0x12,0x01,0xf0,0xba,0x12,0x36,0x75,0x05,0x1c,0x05,0x85, + 0x5b,0x0d,0x2b,0xe8,0x08,0x87,0x66,0x67,0x67,0x1c,0x07,0xa7,0xa7,0x0d,0x1b,0xe0, + 0x24,0xf0,0xc7,0x61,0x07,0x1c,0x67,0x1c,0x07,0xa7,0x57,0x01,0x32,0x71,0x01,0x1c, + 0x01,0x81,0x17,0x0f,0x0d,0xe0,0x67,0x12,0xf1,0x11,0x97,0x03,0xf9,0x11,0xc7,0x1c, + 0x77,0x1c,0x23,0x74,0x47,0x1c,0x07,0xc7,0x77,0x01,0x72,0x1c,0x03,0x20,0x43,0x01, + 0x06,0x20,0x46,0x01,0x03,0xf0,0xd6,0x12,0x02,0x60,0x23,0x12,0xe6,0x0c,0xe1,0xef, + 0x03,0x2a,0x03,0xe8,0x1f,0x7f,0x2a,0x0d,0x2a,0x0a,0x08,0x87,0xe5,0x67,0x57,0x1c, + 0x07,0xa6,0xf1,0x11,0xa6,0x03,0xf9,0x11,0x46,0x3a,0xd5,0x12,0x02,0x60,0x53,0xf0, + 0xd0,0x00,0x00,0x00,0x1c,0x9e,0x00,0x00,0x36,0x00,0x05,0x1a,0x36,0x00,0x04,0x1a, + 0x00,0x00,0x02,0x18,0xb4,0x26,0x00,0x00,0xc8,0x00,0x00,0x00,0x20,0x9e,0x00,0x00, + 0xdc,0xa5,0x00,0x00,0x5e,0xa5,0x00,0x00,0xec,0xa4,0x00,0x00,0x44,0xaa,0x00,0x00, + 0x10,0x07,0x00,0x00,0x7a,0x25,0x00,0x00,0x00,0x80,0x02,0x00,0xc0,0x2b,0x00,0x00, + 0x24,0x07,0x00,0x00,0x36,0xc0,0x02,0x00,0x38,0x07,0x00,0x00,0x44,0x07,0x00,0x00, + 0x36,0xe0,0x02,0x00,0x48,0x2a,0x00,0x00,0xb0,0x00,0x00,0x00,0xb4,0x00,0x00,0x00, + 0x3e,0x84,0x00,0x00,0xbc,0x00,0x00,0x00,0x22,0x83,0x00,0x00,0xc0,0x01,0x00,0x00, + 0x40,0xfe,0xff,0xff,0xb8,0x00,0x00,0x00,0x57,0x12,0xf1,0x11,0x97,0x03,0xf9,0x11, + 0xc7,0x1c,0x77,0x1c,0xad,0x71,0x17,0x1c,0x07,0xc4,0x43,0x12,0x73,0x01,0xf3,0x37, + 0x02,0xe0,0x36,0x0d,0x01,0xf0,0x63,0x0d,0x03,0xe8,0x64,0x05,0x07,0xd4,0x01,0xf0, + 0x07,0xd2,0x05,0x20,0x45,0x01,0xe5,0x0c,0xe7,0xef,0x0c,0x20,0x4c,0x01,0xa3,0x72, + 0x02,0x1c,0x02,0x82,0x2c,0x0f,0xe7,0xe6,0x08,0x87,0x23,0x65,0x37,0x1c,0x07,0xa7, + 0x7d,0x1c,0x4d,0x01,0x9f,0x74,0x04,0x1c,0x04,0x84,0x4e,0x0c,0xc4,0xee,0x9d,0x77, + 0x57,0xa7,0x27,0x2e,0x07,0x2a,0x05,0xe8,0x9c,0x72,0x9c,0x7f,0x97,0x72,0xa3,0x61, + 0x9c,0x7f,0x9c,0x77,0x07,0x8e,0x4e,0xa2,0x5e,0xa3,0x57,0x67,0xe7,0x1c,0x07,0xa7, + 0x0d,0x60,0x00,0x9d,0xc4,0x60,0x98,0x75,0xd6,0x12,0x98,0x7f,0x99,0x7c,0x0c,0x87, + 0x99,0x76,0x06,0xb7,0x17,0x01,0x98,0x76,0x06,0xb1,0x27,0x01,0x98,0x76,0x06,0xb1, + 0x87,0x3f,0x97,0x76,0x06,0xb7,0x4e,0xa2,0x5e,0xa3,0x96,0x7b,0xeb,0x1c,0x0b,0xa6, + 0x96,0x7a,0xea,0x1c,0x0a,0xa7,0x87,0x3c,0x67,0x1e,0x07,0x3d,0x00,0x9d,0xd4,0x60, + 0x8a,0x75,0xd6,0x12,0x07,0x3b,0x89,0x7f,0x0c,0x87,0x90,0x76,0x06,0xb7,0x17,0x01, + 0x90,0x76,0x06,0xb1,0x27,0x01,0x8f,0x76,0x06,0xb1,0x87,0x3f,0x8f,0x76,0x06,0xb7, + 0x4e,0xa2,0x5e,0xa3,0x47,0x67,0xe7,0x1c,0x07,0xa7,0x00,0x9d,0xa4,0x60,0x7e,0x75, + 0xd6,0x12,0x7e,0x7f,0x0c,0x87,0x89,0x75,0x05,0xb7,0x17,0x01,0x89,0x76,0x06,0xb1, + 0x27,0x01,0x88,0x78,0x08,0xb1,0x87,0x3f,0x88,0x71,0x01,0xb7,0x4e,0xa2,0x5e,0xa3, + 0x0b,0xa6,0x0a,0xa7,0x87,0x3c,0x67,0x1e,0x07,0x3d,0x00,0x9d,0xb4,0x60,0x72,0x75, + 0xd6,0x12,0x07,0x3b,0x72,0x7f,0x0c,0x87,0xe7,0x01,0x80,0x7b,0x0b,0xb7,0x17,0x01, + 0x80,0x7a,0x0a,0xb1,0x27,0x01,0x7f,0x79,0x09,0xb1,0x87,0x3f,0x7f,0x78,0x08,0xb7, + 0x4e,0xa2,0x5e,0xa3,0x37,0x67,0xe7,0x1c,0x07,0xa7,0x00,0x9d,0xc4,0x60,0x66,0x75, + 0xd6,0x12,0x66,0x7f,0x0c,0x87,0x79,0x76,0x06,0xb7,0x17,0x01,0x79,0x76,0x06,0xb1, + 0x27,0x01,0x78,0x76,0x06,0xb1,0x87,0x3f,0x78,0x76,0x06,0xb7,0x6c,0x72,0x02,0xa6, + 0x6c,0x73,0x03,0xa7,0x87,0x3c,0x67,0x1e,0x6b,0x74,0x04,0xa6,0x06,0x3d,0x76,0x1e, + 0x6a,0x75,0x05,0xa7,0x87,0x3d,0x67,0x1e,0x71,0x76,0x06,0x86,0x76,0x05,0x70,0x73, + 0x36,0x0d,0x20,0xe0,0x70,0x74,0x64,0x0d,0x1d,0xe0,0x0b,0xa5,0x0a,0xa6,0x86,0x3c, + 0x56,0x1e,0x09,0xa5,0x05,0x3d,0x65,0x1e,0x08,0xa6,0x86,0x3d,0x56,0x1e,0x6a,0x75, + 0x05,0x85,0x65,0x05,0x35,0x0d,0x0e,0xe0,0x54,0x0d,0x0c,0xe0,0x68,0x76,0x06,0xa7, + 0x45,0x61,0x75,0x0c,0x04,0xe0,0x16,0x60,0x66,0x77,0x07,0xb6,0x1a,0xf0,0x07,0x20, + 0x06,0xb7,0x17,0xf0,0x06,0x60,0x61,0x75,0x05,0xb6,0x61,0x75,0x05,0xb6,0x5b,0x76, + 0x06,0x97,0x52,0x77,0x07,0xa6,0x52,0x77,0x07,0xa7,0x87,0x3c,0x67,0x1e,0x51,0x76, + 0x06,0xa6,0x06,0x3d,0x76,0x1e,0x50,0x77,0x07,0xa7,0x87,0x3d,0x67,0x1e,0x56,0x76, + 0x06,0x97,0x27,0x67,0xe7,0x1c,0x07,0xac,0x0c,0x2a,0x09,0xe0,0x56,0x77,0x07,0xa6, + 0x06,0x2a,0xd2,0xe8,0x15,0x60,0x54,0x76,0x36,0xb5,0x07,0xbc,0xcd,0xf0,0x1c,0x2a, + 0x09,0xe0,0x50,0x77,0x07,0xa6,0x26,0x2a,0xc7,0xe8,0x4f,0x76,0x36,0xbc,0x26,0x60, + 0x07,0xb6,0xc2,0xf0,0x2c,0x2a,0xc0,0xe0,0x4b,0x7b,0x0b,0xad,0x0d,0x2a,0x15,0xe0, + 0x4b,0x76,0x06,0xa7,0x27,0x2a,0x4a,0x77,0x0e,0xe0,0x36,0xa6,0x26,0x2a,0x0b,0xe8, + 0x07,0xc6,0x06,0x20,0x66,0x01,0x07,0xd6,0x55,0x60,0x65,0x0c,0xad,0xe0,0x07,0xdd, + 0x17,0x60,0x0b,0xb7,0xa9,0xf0,0x07,0xdd,0xa7,0xf0,0x1d,0x2a,0x94,0xe0,0x40,0x76, + 0x06,0xc7,0x07,0x20,0x67,0x01,0x06,0xd7,0x46,0x66,0x76,0x0c,0x85,0xe8,0x3d,0x77, + 0x06,0x60,0x97,0xb6,0x3d,0x76,0x07,0xb6,0x16,0x01,0x17,0xb1,0x26,0x01,0x27,0xb1, + 0x86,0x3f,0x37,0xb6,0x36,0x67,0x6e,0x1c,0x0e,0xa6,0x06,0x24,0x66,0x01,0xa7,0xb6, + 0x86,0x3e,0xb7,0xb6,0x36,0x7f,0x36,0x77,0x07,0xa6,0x17,0xa7,0x87,0x3c,0x67,0x1e, + 0x07,0x2a,0x34,0x77,0x6d,0xe0,0x07,0xc6,0x06,0x20,0x66,0x01,0x07,0xd6,0x57,0x60, + 0x67,0x0c,0x7a,0xe0,0x61,0xf0,0x00,0x00,0x36,0xe0,0x02,0x00,0xb4,0x00,0x00,0x00, + 0xb0,0x00,0x00,0x00,0x44,0xaa,0x00,0x00,0x58,0x07,0x00,0x00,0x7a,0x25,0x00,0x00, + 0xc0,0x2b,0x00,0x00,0x1c,0x9e,0x00,0x00,0x36,0x00,0x05,0x1a,0xb4,0x26,0x00,0x00, + 0x34,0x0a,0x04,0x00,0x46,0xa4,0x00,0x00,0x47,0xa4,0x00,0x00,0x48,0xa4,0x00,0x00, + 0x49,0xa4,0x00,0x00,0xb5,0x00,0x00,0x00,0xb6,0x00,0x00,0x00,0x4a,0xa4,0x00,0x00, + 0x4b,0xa4,0x00,0x00,0x4c,0xa4,0x00,0x00,0x4d,0xa4,0x00,0x00,0x52,0xa4,0x00,0x00, + 0x53,0xa4,0x00,0x00,0x54,0xa4,0x00,0x00,0x55,0xa4,0x00,0x00,0x56,0xa4,0x00,0x00, + 0x57,0xa4,0x00,0x00,0x58,0xa4,0x00,0x00,0x59,0xa4,0x00,0x00,0x4e,0xa4,0x00,0x00, + 0x4f,0xa4,0x00,0x00,0x50,0xa4,0x00,0x00,0x51,0xa4,0x00,0x00,0x4c,0xa6,0x00,0x00, + 0x39,0xff,0xff,0xff,0xc7,0x00,0x00,0x00,0x50,0xa6,0x00,0x00,0x54,0xa6,0x00,0x00, + 0x72,0xa4,0x00,0x00,0x63,0xa4,0x00,0x00,0x86,0x9e,0x00,0x00,0x66,0x9e,0x00,0x00, + 0x56,0xa6,0x00,0x00,0x7a,0x9e,0x00,0x00,0x00,0xe0,0x02,0x00,0x88,0x27,0x00,0x00, + 0x00,0x08,0x03,0x00,0x58,0xa6,0x00,0x00,0xad,0x77,0x37,0xbd,0x0b,0xbc,0x14,0xf0, + 0x06,0x60,0x07,0xd6,0x11,0xf0,0x2d,0x2a,0x0f,0xe0,0xa9,0x77,0x07,0xa6,0x37,0xa7, + 0x27,0x2a,0x02,0xe8,0x26,0x2a,0x08,0xe8,0x07,0x60,0xa6,0x76,0x06,0xd7,0x15,0x60, + 0xa3,0x76,0x36,0xb5,0xa5,0x76,0x06,0xb7,0xa1,0x77,0x37,0xa6,0x06,0x2a,0x1a,0xe8, + 0x06,0x60,0x37,0xb6,0xa1,0x76,0x06,0xa6,0x26,0x2a,0xa0,0x76,0x06,0x86,0x06,0xe0, + 0x38,0x67,0x86,0x1c,0x06,0xa6,0x07,0xb6,0x17,0xb6,0x0b,0xf0,0x65,0x67,0x65,0x1c, + 0x05,0xa5,0x07,0xb5,0x55,0x67,0x65,0x1c,0x05,0xa5,0x17,0xb5,0x4d,0x67,0xd6,0x1c, + 0x06,0xa6,0x27,0xb6,0x97,0x77,0x07,0xa5,0x97,0x76,0x06,0xb5,0x97,0x71,0x15,0x16, + 0x07,0xb5,0x92,0x75,0x05,0x85,0x29,0x64,0x59,0x1c,0x09,0xa4,0x04,0x2a,0x8e,0xe8, + 0x06,0xa8,0x06,0x60,0x92,0x7a,0x8b,0x64,0x5b,0x1c,0x9c,0x64,0x5c,0x1c,0x90,0x73, + 0x53,0x1c,0x90,0x72,0x02,0x1c,0x02,0x93,0x90,0x74,0x7f,0x12,0x41,0xf0,0xa7,0x12, + 0x67,0x1c,0x07,0xa2,0x27,0x12,0x87,0x16,0x07,0x2a,0x02,0xe8,0x0c,0xad,0x01,0xf0, + 0x0b,0xad,0x8a,0x73,0x63,0x1c,0x23,0xa7,0x63,0xa3,0xae,0x61,0xf1,0x11,0xe7,0x03, + 0xf9,0x11,0x37,0x1c,0x77,0x1c,0x86,0x73,0x73,0x1c,0x03,0xce,0xe3,0x12,0x73,0x01, + 0x3d,0x0d,0x04,0xe8,0x0f,0xa7,0x72,0x1e,0x0f,0xb2,0x20,0xf0,0x82,0x72,0x62,0x1c, + 0x02,0xad,0x0d,0x20,0x4d,0x01,0x02,0xbd,0x51,0x60,0xd1,0x0c,0x17,0xe0,0x0d,0x60, + 0x02,0xbd,0x78,0x7d,0x0d,0x1c,0x0d,0x8d,0x0d,0xa2,0x32,0x0d,0x04,0xe8,0x47,0x1c, + 0x07,0xc3,0x32,0x14,0x07,0xf0,0x2d,0x12,0x0d,0x28,0x47,0x1c,0xd3,0x0d,0x07,0xc3, + 0x03,0xe8,0x32,0x1c,0x07,0xd2,0x02,0xf0,0x3e,0x14,0x07,0xde,0x06,0x20,0x46,0x01, + 0x09,0xa7,0x76,0x0c,0xbc,0xef,0x3f,0x64,0xf5,0x1c,0x05,0xa7,0x37,0x2a,0x6b,0x7e, + 0x0e,0xe0,0x2e,0xa6,0x65,0x12,0x65,0x1c,0x65,0x1c,0x57,0x12,0x47,0x3c,0x57,0x1c, + 0x67,0x1c,0x69,0x71,0x17,0x1e,0x00,0x97,0x12,0x60,0x83,0x61,0x22,0xf0,0x47,0x2a, + 0x06,0xe0,0x6e,0xa7,0x97,0x21,0x77,0x1c,0x64,0x72,0x27,0x1e,0x17,0xf0,0x2e,0xa6, + 0x65,0x12,0x65,0x1c,0x65,0x1c,0x57,0x12,0x47,0x3c,0x57,0x1c,0x67,0x1c,0x5e,0x73, + 0x37,0x1e,0x00,0x97,0x12,0x60,0x83,0x61,0x84,0x60,0x05,0x60,0x56,0x12,0x57,0x12, + 0x5b,0x7f,0x6e,0xa7,0x97,0x21,0x77,0x1c,0x58,0x74,0x47,0x1e,0x00,0x97,0x42,0x62, + 0x13,0x60,0x84,0x60,0x05,0x60,0x56,0x12,0x57,0x12,0x54,0x7f,0x55,0x7f,0x55,0x7f, + 0x56,0x7f,0x09,0x60,0x56,0x7d,0x4e,0x7b,0x10,0xf2,0x97,0x12,0x97,0x1c,0x54,0x75, + 0x57,0x1c,0x27,0xae,0x54,0x76,0x76,0xbe,0x37,0xac,0x86,0xbc,0x56,0xa8,0x52,0x77, + 0x07,0x1c,0x07,0x98,0x8d,0xb8,0x66,0xa2,0x43,0x71,0x01,0x1c,0x01,0x92,0x9d,0xb2, + 0x17,0x60,0xad,0xb7,0xbd,0xb7,0x07,0x60,0x0d,0xb7,0x1d,0xb7,0x2d,0xb7,0x3d,0xb7, + 0xa8,0x61,0xf1,0x11,0xe8,0x03,0xf9,0x11,0x87,0x12,0xc7,0x1c,0x77,0x1c,0xb7,0x1c, + 0x07,0xa6,0x4d,0xb6,0x17,0xa7,0x5d,0xb7,0x6d,0xbe,0x7d,0xbc,0xe2,0x12,0xc3,0x12, + 0x43,0x7f,0xca,0x12,0x05,0xf0,0x0a,0x20,0x4a,0x01,0xe2,0x12,0xa3,0x12,0x3f,0x7f, + 0x87,0x12,0xa7,0x1c,0x07,0x20,0x77,0x1c,0xb7,0x1c,0x07,0xc6,0x76,0x01,0x3c,0x73, + 0x03,0xa5,0x3c,0x74,0x04,0xa7,0x87,0x3c,0x57,0x1e,0x76,0x0d,0x05,0xe0,0x29,0x75, + 0x05,0x1c,0x05,0x85,0xa5,0x0c,0xe7,0xe7,0x0d,0xa6,0x1d,0xa7,0x87,0x3c,0x67,0x1e, + 0xd7,0x1c,0x46,0x65,0x67,0x1c,0x07,0xba,0xca,0x12,0xa8,0x61,0xf1,0x11,0xe8,0x03, + 0xf9,0x11,0x05,0xf0,0x0a,0x24,0x4a,0x01,0xe2,0x12,0xa3,0x12,0x2c,0x7f,0x87,0x12, + 0xa7,0x1c,0x07,0x24,0x77,0x1c,0xb7,0x1c,0x07,0xc6,0x76,0x01,0x29,0x77,0x07,0xa5, + 0x29,0x71,0x01,0xa7,0x87,0x3c,0x57,0x1e,0x76,0x0d,0x02,0xe0,0x0a,0x2a,0xea,0xe7, + 0x0d,0xa6,0x1d,0xa7,0x87,0x3c,0x67,0x1e,0xd6,0x12,0x76,0x1c,0x05,0x63,0x65,0x1c, + 0x05,0xba,0xc6,0xbe,0x07,0x20,0x67,0x01,0x0d,0xb7,0x87,0x3e,0x1d,0xb7,0xc8,0x12, + 0xea,0x12,0x1d,0x72,0x02,0x1c,0x02,0x99,0xe9,0x12,0xbf,0xf0,0x86,0x9e,0x00,0x00, + 0x66,0x9e,0x00,0x00,0x56,0xa6,0x00,0x00,0x63,0xa4,0x00,0x00,0x1c,0x9e,0x00,0x00, + 0x2c,0xa4,0x00,0x00,0x2d,0xa4,0x00,0x00,0xf0,0xff,0xff,0xff,0x88,0x05,0x00,0x00, + 0xbb,0x00,0x00,0x00,0xb0,0x00,0x00,0x00,0x00,0xc0,0x02,0x00,0x20,0x9e,0x00,0x00, + 0x00,0xe0,0x02,0x00,0x5c,0xa6,0x00,0x00,0x00,0x00,0x05,0x1a,0xb4,0x26,0x00,0x00, + 0x00,0x28,0x00,0x00,0xf8,0x4c,0x00,0x00,0x80,0x4e,0x00,0x00,0x73,0xa4,0x00,0x00, + 0x8a,0x9e,0x00,0x00,0x7a,0x9e,0x00,0x00,0xb8,0x00,0x00,0x00,0xf8,0x3c,0x00,0x00, + 0x44,0xa4,0x00,0x00,0x45,0xa4,0x00,0x00,0xb4,0x00,0x00,0x00,0xa7,0x12,0x07,0x24, + 0xb7,0x73,0x03,0xa5,0xb7,0x74,0x04,0xa6,0x86,0x3c,0x56,0x1e,0xa5,0x61,0xf1,0x11, + 0x57,0x03,0xf9,0x11,0x87,0x1c,0x75,0x12,0x75,0x1c,0xb5,0x1c,0x05,0xc5,0x75,0x01, + 0x65,0x0d,0x12,0xe8,0x75,0x12,0x05,0x24,0x55,0x1c,0xb5,0x1c,0x05,0xc5,0x75,0x01, + 0x65,0x0d,0x98,0x00,0x08,0xe8,0x07,0x20,0x77,0x1c,0xb7,0x1c,0x07,0xc7,0x77,0x01, + 0x67,0x0d,0xef,0xe0,0x08,0x20,0x48,0x01,0x0a,0x24,0x4a,0x01,0xa2,0x12,0x83,0x12, + 0xa5,0x7f,0x8e,0x12,0xa7,0x61,0xf1,0x11,0xa7,0x03,0xf9,0x11,0xa3,0x76,0x06,0x1c, + 0x06,0x97,0x05,0xf0,0x0e,0x20,0x4e,0x01,0xa2,0x12,0xe3,0x12,0x9e,0x7f,0x9e,0x71, + 0x01,0x1c,0x01,0x87,0xe7,0x1c,0x07,0x20,0x77,0x1c,0xb7,0x1c,0x07,0xc6,0x76,0x01, + 0x97,0x72,0x02,0xa5,0x97,0x73,0x03,0xa7,0x87,0x3c,0x57,0x1e,0x76,0x0d,0x05,0xe0, + 0x97,0x74,0x04,0x1c,0x04,0x84,0xe4,0x0c,0xe5,0xe7,0x0d,0xa6,0x1d,0xa7,0x87,0x3c, + 0x67,0x1e,0xd7,0x1c,0x45,0x65,0x57,0x1c,0x07,0xbe,0x8e,0x12,0xa7,0x61,0xf1,0x11, + 0xa7,0x03,0xf9,0x11,0x8d,0x76,0x06,0x1c,0x06,0x97,0x05,0xf0,0x0e,0x24,0x4e,0x01, + 0xa2,0x12,0xe3,0x12,0x88,0x7f,0x88,0x71,0x01,0x1c,0x01,0x87,0xe7,0x1c,0x07,0x24, + 0x77,0x1c,0xb7,0x1c,0x07,0xc6,0x76,0x01,0x81,0x72,0x02,0xa5,0x81,0x73,0x03,0xa7, + 0x87,0x3c,0x57,0x1e,0x76,0x0d,0x02,0xe0,0x0e,0x2a,0xe8,0xe7,0x0d,0xa6,0x1d,0xa7, + 0x87,0x3c,0x67,0x1e,0xd6,0x12,0x76,0x1c,0x05,0x63,0x65,0x1c,0x05,0xbe,0xc6,0xba, + 0x07,0x20,0x67,0x01,0x0d,0xb7,0x87,0x3e,0x1d,0xb7,0x0a,0x2a,0x77,0xe7,0x9e,0x12, + 0x78,0x74,0x04,0x1c,0x04,0x89,0x89,0xf0,0xe7,0x12,0x07,0x20,0x70,0x76,0x06,0xa5, + 0x08,0xa6,0x86,0x3c,0x56,0x1e,0xaf,0x61,0xf1,0x11,0xf7,0x03,0xf9,0x11,0xc7,0x1c, + 0x75,0x12,0x75,0x1c,0xb5,0x1c,0x05,0xc5,0x75,0x01,0x65,0x0d,0x12,0xe8,0x75,0x12, + 0x05,0x24,0x55,0x1c,0xb5,0x1c,0x05,0xc5,0x75,0x01,0x65,0x0d,0x9c,0x00,0x08,0xe8, + 0x07,0x20,0x77,0x1c,0xb7,0x1c,0x07,0xc7,0x77,0x01,0x67,0x0d,0x6c,0xe0,0x0c,0x20, + 0x4c,0x01,0x0e,0x20,0x4e,0x01,0xe2,0x12,0xc3,0x12,0x5e,0x7f,0xca,0x12,0xa2,0x61, + 0xf1,0x11,0xe2,0x03,0xf9,0x11,0x5e,0x71,0x01,0x1c,0x01,0x92,0x05,0xf0,0x0a,0x20, + 0x4a,0x01,0xe2,0x12,0xa3,0x12,0x57,0x7f,0x5a,0x73,0x03,0x1c,0x03,0x87,0xa7,0x1c, + 0x07,0x20,0x77,0x1c,0xb7,0x1c,0x07,0xc6,0x76,0x01,0x50,0x74,0x04,0xa5,0x08,0xa7, + 0x87,0x3c,0x57,0x1e,0x76,0x0d,0x05,0xe0,0x51,0x75,0x05,0x1c,0x05,0x85,0xa5,0x0c, + 0xe6,0xe7,0x0d,0xa6,0x1d,0xa7,0x87,0x3c,0x67,0x1e,0xd7,0x1c,0x46,0x65,0x67,0x1c, + 0x07,0xba,0xca,0x12,0xaf,0x61,0xf1,0x11,0xef,0x03,0xf9,0x11,0x49,0x77,0x07,0x1c, + 0x07,0x9f,0x05,0xf0,0x0a,0x24,0x4a,0x01,0xe2,0x12,0xa3,0x12,0x42,0x7f,0x44,0x71, + 0x01,0x1c,0x01,0x87,0xa7,0x1c,0x07,0x24,0x77,0x1c,0xb7,0x1c,0x07,0xc6,0x76,0x01, + 0x3b,0x72,0x02,0xa5,0x08,0xa7,0x87,0x3c,0x57,0x1e,0x76,0x0d,0x02,0xe0,0x0a,0x2a, + 0xe9,0xe7,0x0d,0xa6,0x1d,0xa7,0x87,0x3c,0x67,0x1e,0xd6,0x12,0x76,0x1c,0x05,0x63, + 0x65,0x1c,0x05,0xba,0xc6,0xbe,0x07,0x20,0x67,0x01,0x0d,0xb7,0x87,0x3e,0x1d,0xb7, + 0x05,0xf0,0x9e,0x12,0x33,0x73,0x03,0x1c,0x03,0x89,0x2d,0x78,0x32,0x74,0x04,0x1c, + 0x04,0x84,0xe4,0x0c,0x71,0xe7,0x8d,0xa2,0x97,0x12,0x37,0x3c,0x97,0x05,0x2e,0x75, + 0x57,0x1c,0xa6,0x62,0x76,0x1c,0x06,0xb2,0x9d,0xa4,0xb6,0x62,0x76,0x1c,0x06,0xb4, + 0xad,0xaf,0xc6,0x62,0x76,0x1c,0x06,0xbf,0xbd,0xa3,0xd6,0x62,0x76,0x1c,0x06,0xb3, + 0xe6,0x62,0x76,0x1c,0x2d,0xa5,0x06,0xb5,0x86,0x62,0x67,0x1c,0x4d,0xa5,0x5d,0xa6, + 0x86,0x3c,0x56,0x1e,0x77,0xb6,0x86,0x3e,0x87,0xb6,0xf7,0x12,0x27,0x05,0x57,0x01, + 0x17,0x22,0x05,0xe8,0x37,0x12,0x47,0x05,0x57,0x01,0x17,0x22,0x0c,0xe0,0x95,0x12, + 0x95,0x1c,0x19,0x77,0x75,0x1c,0xf6,0x12,0x26,0x1c,0x16,0x3a,0x25,0xb6,0x37,0x12, + 0x47,0x1c,0x17,0x3a,0x35,0xb7,0x09,0x20,0x49,0x01,0x13,0x7c,0x0c,0xa7,0x1c,0xae, + 0x8e,0x3c,0x7e,0x1e,0xe9,0x0c,0xe9,0xed,0x02,0x12,0x72,0x20,0x03,0x60,0x44,0x61, + 0x0f,0x7f,0x1f,0x60,0xef,0x0c,0x68,0xe0,0x0c,0xa7,0x1c,0xa4,0x84,0x3c,0x74,0x1e, + 0x05,0x60,0x0b,0x7b,0xad,0x61,0x2e,0x60,0x5d,0xf0,0x00,0x00,0x44,0xa4,0x00,0x00, + 0x45,0xa4,0x00,0x00,0xf8,0x3c,0x00,0x00,0xbc,0x00,0x00,0x00,0xb0,0x00,0x00,0x00, + 0xb4,0x00,0x00,0x00,0xb8,0x00,0x00,0x00,0x8a,0x9e,0x00,0x00,0x22,0x83,0x00,0x00, + 0x00,0xe0,0x02,0x00,0x87,0x60,0x07,0x1c,0x57,0x1c,0x07,0xa7,0x07,0x2a,0x40,0xe0, + 0x56,0x12,0x56,0x1c,0xc6,0x1c,0x26,0xa7,0x36,0xaa,0x53,0x12,0x03,0x20,0x43,0x01, + 0x79,0x12,0x09,0x20,0xa6,0x12,0x56,0x01,0x57,0x01,0xf1,0x11,0xd7,0x03,0xf9,0x11, + 0x67,0x1c,0x77,0x1c,0xb7,0x1c,0x2a,0xf0,0x32,0x12,0x32,0x1c,0xc2,0x1c,0x22,0xa6, + 0x32,0xa8,0x92,0x12,0x62,0x05,0x42,0x01,0x2e,0x0c,0x1e,0xe8,0xa2,0x12,0x02,0x20, + 0x82,0x05,0x42,0x01,0x2e,0x0c,0x18,0xe8,0x58,0x01,0x56,0x01,0xf1,0x11,0xd6,0x03, + 0xf9,0x11,0x86,0x1c,0x66,0x1c,0xb6,0x1c,0x07,0xc2,0x72,0x01,0x06,0xc6,0x76,0x01, + 0x26,0x0d,0x05,0xe8,0x86,0x60,0x06,0x1c,0x36,0x1c,0x06,0xbf,0x05,0xf0,0x87,0x60, + 0x07,0x1c,0x57,0x1c,0x07,0xbf,0x04,0xf0,0x03,0x20,0x43,0x01,0x43,0x0c,0xd4,0xef, + 0x05,0x20,0x45,0x01,0x45,0x0c,0xb6,0xef,0x02,0x12,0x72,0x20,0xb0,0x73,0xb0,0x7f, + 0xb1,0x77,0x77,0xa7,0x07,0x2a,0x05,0xe8,0xb0,0x77,0x07,0x87,0x78,0x67,0x87,0x1c, + 0x11,0xf0,0xae,0x77,0x07,0xa7,0x07,0x2a,0x0c,0xe8,0xad,0x77,0x07,0xa7,0xad,0x76, + 0x06,0xae,0x8e,0x3c,0x7e,0x1e,0x2e,0x3e,0xac,0x77,0x17,0xa7,0x7e,0x0d,0x7e,0x02, + 0x02,0xf0,0xa9,0x77,0x07,0xae,0x02,0x12,0x72,0x20,0x03,0x60,0x44,0x61,0xa7,0x7f, + 0xa8,0x77,0x07,0xa7,0xa8,0x76,0x06,0xa5,0x85,0x3c,0x75,0x1e,0x06,0x60,0x9b,0x73, + 0x7e,0x01,0x14,0x60,0x12,0xf0,0x67,0x12,0x37,0x3c,0x67,0x05,0x37,0x1c,0x8d,0x62, + 0xd7,0x1c,0x77,0xa2,0x87,0xa7,0x87,0x3c,0x27,0x1e,0xe7,0x0d,0x04,0xe8,0x87,0x60, + 0x07,0x1c,0x67,0x1c,0x07,0xb4,0x06,0x20,0x46,0x01,0x56,0x0c,0xec,0xef,0x98,0x7c, + 0x02,0x12,0x72,0x20,0xc3,0x12,0x8e,0x7f,0x90,0x77,0x07,0x87,0x97,0x71,0x01,0x1c, + 0x01,0x97,0xf2,0x67,0x27,0x1c,0x07,0xa7,0x07,0x2a,0xf1,0xe8,0x02,0x12,0x72,0x20, + 0x03,0x60,0x44,0x61,0x8e,0x7f,0x8e,0x67,0x0e,0x1c,0xe2,0x12,0x03,0x60,0x44,0x63, + 0x8b,0x7f,0x4d,0x64,0x0d,0x1c,0xd2,0x12,0x03,0x60,0x44,0x63,0x88,0x7f,0x0c,0xa7, + 0x89,0x76,0x06,0xa4,0x84,0x3c,0x74,0x1e,0x07,0x60,0x7c,0x7a,0xeb,0x12,0xdc,0x12, + 0x7c,0xf0,0x86,0x65,0x76,0x1c,0x66,0x1c,0xa6,0x1c,0x86,0xa9,0x96,0xa6,0x93,0x12, + 0x03,0x24,0x43,0x01,0x05,0x60,0x09,0x20,0x62,0x12,0x02,0x24,0x02,0x01,0x7f,0x78, + 0x08,0x1c,0x08,0x91,0x12,0x20,0x7e,0x71,0x01,0x1c,0x01,0x92,0x1d,0xf0,0x7b,0x78, + 0x08,0x1c,0x08,0x82,0xa8,0x61,0xf1,0x11,0x38,0x03,0xf9,0x11,0x0e,0xf0,0x8f,0x12, + 0x2f,0x1c,0xff,0x1c,0x78,0x71,0x1f,0x1c,0x0f,0xcf,0xf1,0x12,0x71,0x01,0x01,0x22, + 0x02,0xe0,0xf5,0x1c,0x65,0x01,0x02,0x20,0x42,0x01,0x71,0x71,0x01,0x1c,0x01,0x81, + 0x21,0x0d,0xed,0xef,0x03,0x20,0x43,0x01,0x39,0x0d,0xe1,0xef,0x73,0x12,0x73,0x1c, + 0xc2,0x61,0x02,0x1c,0x23,0x1c,0x03,0xd5,0x63,0x12,0x63,0x1c,0xb3,0x1c,0x03,0xc2, + 0x72,0x01,0x59,0x12,0x79,0x01,0x92,0x0d,0x01,0xe8,0x03,0xd5,0x62,0x12,0x02,0x24, + 0x23,0x12,0x23,0x1c,0xe3,0x1c,0x03,0xcf,0x7f,0x01,0x9f,0x0d,0x01,0xe8,0x03,0xd5, + 0x63,0x12,0x03,0x20,0x3f,0x12,0x3f,0x1c,0xbf,0x1c,0x0f,0xc8,0x78,0x01,0x98,0x0d, + 0x01,0xe8,0x0f,0xd5,0x75,0x12,0x35,0x3c,0x75,0x05,0xa5,0x1c,0x88,0x62,0x85,0x1c, + 0x75,0xaf,0x85,0xa5,0x85,0x3c,0xf5,0x1e,0x66,0x1c,0xc6,0x1c,0x06,0xcf,0x7f,0x01, + 0x5f,0x0d,0x01,0xe8,0x06,0xd5,0x26,0x12,0x26,0x1c,0xd6,0x1c,0x06,0xc2,0x72,0x01, + 0x52,0x0d,0x01,0xe8,0x06,0xd5,0x36,0x12,0x36,0x1c,0xc6,0x1c,0x06,0xc3,0x73,0x01, + 0x53,0x0d,0x01,0xe8,0x06,0xd5,0x07,0x20,0x47,0x01,0x47,0x0c,0x82,0xef,0x4a,0x77, + 0x17,0xac,0x0c,0x20,0x0d,0x60,0x44,0x71,0x01,0x1c,0x01,0x8b,0x72,0x32,0x2b,0x1c, + 0x10,0xf0,0xde,0x12,0xde,0x1c,0x83,0x67,0x03,0x1c,0x3e,0x1c,0x0e,0xc2,0x72,0x01, + 0x0b,0xa7,0xf1,0x11,0x72,0x03,0xf9,0x11,0x43,0x66,0x40,0x7f,0x0e,0xd2,0x0d,0x20, + 0x4d,0x01,0xdc,0x0d,0xee,0xef,0x36,0x77,0x07,0xa7,0x36,0x76,0x06,0xa5,0x85,0x3c, + 0x75,0x1e,0x07,0x60,0x2a,0x72,0x1f,0x60,0x2c,0xf0,0x86,0x65,0x76,0x1c,0x66,0x1c, + 0x26,0x1c,0x96,0xa4,0x76,0x12,0x36,0x3c,0x76,0x05,0x26,0x1c,0x88,0x62,0x86,0x1c, + 0x76,0xa3,0x86,0xa6,0x86,0x3c,0x36,0x1e,0x44,0x1c,0x43,0x64,0x03,0x1c,0x43,0x1c, + 0x03,0xc3,0x73,0x01,0x13,0x3a,0x63,0x0d,0x12,0xe0,0x76,0x12,0x76,0x1c,0xcd,0x61, + 0x0d,0x1c,0xd6,0x1c,0x81,0x67,0x01,0x1c,0x14,0x1c,0x06,0xc3,0x73,0x01,0x04,0xc6, + 0x76,0x01,0x63,0x0d,0x04,0xe8,0x86,0x60,0x06,0x1c,0x76,0x1c,0x06,0xbf,0x07,0x20, + 0x47,0x01,0x57,0x0c,0xd2,0xef,0x02,0x12,0x72,0x20,0x19,0x73,0x11,0x7f,0x20,0x7f, + 0x12,0x77,0x07,0x87,0x20,0x72,0x27,0x1c,0x07,0xa7,0x07,0x2a,0x57,0xe8,0x1e,0x77, + 0x37,0xa7,0x27,0x2a,0x53,0xe0,0x10,0x77,0x07,0xae,0xee,0x1c,0x02,0x12,0x72,0x20, + 0x03,0x60,0x44,0x61,0x0e,0x7f,0x0e,0x77,0x07,0xa7,0x0e,0x76,0x06,0xa5,0x85,0x3c, + 0x75,0x1e,0x06,0x60,0x02,0x73,0x7e,0x01,0x14,0x60,0x3a,0xf0,0x8a,0x9e,0x00,0x00, + 0x00,0x2d,0x00,0x00,0x20,0xaa,0x00,0x00,0x1c,0x9e,0x00,0x00,0x4a,0xa0,0x00,0x00, + 0x3e,0xa4,0x00,0x00,0x3f,0xa4,0x00,0x00,0x86,0x9e,0x00,0x00,0x22,0x83,0x00,0x00, + 0x40,0x9f,0x00,0x00,0x41,0x9f,0x00,0x00,0xb0,0x00,0x00,0x00,0xb8,0x00,0x00,0x00, + 0xb4,0x00,0x00,0x00,0x00,0xe0,0x02,0x00,0x20,0x9e,0x00,0x00,0x3e,0x84,0x00,0x00, + 0x0e,0x46,0x00,0x00,0x86,0x00,0x00,0x00,0x66,0x9e,0x00,0x00,0x67,0x12,0x37,0x3c, + 0x67,0x05,0x37,0x1c,0x88,0x62,0x87,0x1c,0x77,0xa2,0x87,0xa7,0x87,0x3c,0x27,0x1e, + 0xe7,0x0d,0x04,0xe8,0x87,0x60,0x07,0x1c,0x67,0x1c,0x07,0xb4,0x06,0x20,0x46,0x01, + 0x56,0x0c,0xec,0xef,0x02,0x12,0x72,0x20,0xbd,0x73,0xbd,0x7f,0xbc,0x77,0x07,0xa7, + 0xbd,0x76,0x06,0xaf,0xbd,0x7d,0x0d,0x1c,0x8f,0x3c,0x7f,0x1e,0x0d,0x9f,0x0d,0xa2, + 0xbb,0x71,0x01,0x1c,0x01,0x92,0xba,0x77,0x07,0xb2,0x0d,0x60,0x0b,0xf1,0xd7,0x12, + 0x37,0x3c,0xd7,0x05,0xb8,0x73,0x37,0x1c,0xc6,0x62,0x76,0x1c,0x06,0xa5,0xa6,0x62, + 0x76,0x1c,0x06,0xa4,0xd6,0x62,0x76,0x1c,0x06,0xa6,0xb8,0x62,0x87,0x1c,0x07,0xa7, + 0x53,0x12,0x43,0x05,0x43,0x01,0x1f,0x60,0x3f,0x0c,0x35,0xe8,0x63,0x12,0x73,0x05, + 0x43,0x01,0x3f,0x0c,0x30,0xe8,0x87,0x65,0xd7,0x1c,0x77,0x1c,0xaa,0x71,0x17,0x1c, + 0x87,0xa7,0xfc,0x12,0x22,0x60,0x72,0x0c,0x03,0xe0,0x7c,0x12,0x0c,0x24,0x4c,0x01, + 0xa6,0x73,0x03,0xaa,0xa6,0x12,0x06,0x24,0x67,0x0d,0x03,0xe8,0x07,0x20,0x7a,0x12, + 0x4a,0x01,0x87,0x65,0xd7,0x1c,0x77,0x1c,0x9f,0x74,0x47,0x1c,0x97,0xa7,0x16,0x60, + 0x9f,0x75,0x05,0x1c,0x05,0x96,0x28,0x60,0x78,0x0c,0x04,0xe0,0x76,0x12,0x06,0x24, + 0x06,0x01,0x05,0x91,0x99,0x72,0x12,0xa9,0x96,0x12,0x06,0x24,0x67,0x0d,0x26,0xe8, + 0x07,0x20,0x79,0x12,0x22,0xf0,0x1c,0x60,0x23,0x60,0x43,0x0c,0x03,0xe0,0x04,0x24, + 0x4c,0x12,0x4c,0x01,0x91,0x74,0x04,0xaa,0xa4,0x12,0x04,0x24,0x45,0x0d,0x03,0xe8, + 0x05,0x20,0x5a,0x12,0x4a,0x01,0x18,0x60,0x8d,0x75,0x05,0x1c,0x05,0x98,0x2f,0x60, + 0x7f,0x0c,0x03,0xe0,0x07,0x24,0x07,0x01,0x05,0x91,0x87,0x72,0x12,0xa9,0x97,0x12, + 0x07,0x24,0x76,0x0d,0x03,0xe8,0x06,0x20,0x69,0x12,0x49,0x01,0x08,0x60,0x84,0x73, + 0x03,0x1c,0x03,0x98,0x84,0x74,0x04,0x1c,0x04,0x98,0xdb,0x12,0x35,0xf0,0x82,0x75, + 0x05,0x1c,0x05,0x87,0xd7,0x1c,0x77,0x1c,0x81,0x76,0x67,0x1c,0x07,0xce,0x7e,0x01, + 0x0e,0x22,0x24,0xe0,0xb2,0x12,0xc3,0x12,0xd4,0x12,0x7d,0x7f,0x72,0x01,0x2e,0x1b, + 0x7e,0x01,0x2e,0x3a,0x7c,0x71,0x01,0x1c,0x01,0x87,0xf1,0x11,0xe7,0x03,0xf9,0x11, + 0x74,0x72,0x02,0x1c,0x02,0x83,0x73,0x1c,0x72,0x72,0x02,0x1c,0x02,0x93,0xd7,0x12, + 0x17,0x3c,0x07,0x24,0x67,0x01,0xf1,0x11,0xe7,0x03,0xf9,0x11,0x6e,0x74,0x04,0x1c, + 0x04,0x85,0x75,0x1c,0x6c,0x74,0x04,0x1c,0x04,0x95,0xe8,0x1c,0x0d,0x20,0x4d,0x01, + 0xd9,0x0c,0xcd,0xe7,0x0c,0x20,0x4c,0x01,0xca,0x0c,0x12,0xe8,0xc7,0x12,0x17,0x3c, + 0x07,0x24,0x67,0x01,0x68,0x76,0x06,0x1c,0x06,0x97,0x60,0x77,0x07,0x1c,0x07,0x8d, + 0xa2,0x61,0xf1,0x11,0xc2,0x03,0xf9,0x11,0x60,0x71,0x01,0x1c,0x01,0x92,0xe8,0xf7, + 0xbd,0x12,0xbe,0x12,0x3e,0x3c,0xbe,0x1c,0x57,0x73,0x3e,0x1c,0x5f,0x74,0x4e,0x1c, + 0x59,0x75,0x05,0x1c,0x05,0x82,0x72,0x3c,0x83,0x12,0x5c,0x7f,0x62,0x01,0x4e,0xb2, + 0x82,0x3e,0x5e,0xb2,0x53,0x76,0x06,0x1c,0x06,0x82,0x72,0x3c,0x83,0x12,0x57,0x7f, + 0x62,0x01,0x6e,0xb2,0x27,0x12,0x87,0x3e,0x7e,0xb7,0x55,0x78,0x08,0x87,0x55,0x71, + 0x17,0x1c,0x07,0xa7,0x27,0x2a,0x06,0xe0,0x54,0x73,0x32,0x1c,0x62,0x01,0x6e,0xb2, + 0x82,0x3e,0x7e,0xb2,0xd5,0x12,0x35,0x3c,0x56,0x12,0xd6,0x1c,0x42,0x74,0x46,0x1c, + 0x4f,0x77,0x67,0x1c,0x04,0x2c,0x07,0xb4,0x48,0x77,0x76,0x1c,0xd5,0x05,0x3d,0x78, + 0x85,0x1c,0x87,0x62,0x57,0x1c,0x77,0xa4,0x87,0xa7,0x87,0x3c,0x47,0x1e,0x86,0xb7, + 0x87,0x3e,0x96,0xb7,0xef,0x62,0xf5,0x1c,0x05,0xa7,0xa6,0xb7,0x07,0x60,0xb6,0xb7, + 0x0d,0x20,0x4d,0x01,0x31,0x71,0x01,0x1c,0x01,0x81,0x1d,0x0c,0xf0,0xee,0x40,0x77, + 0x57,0xa7,0x07,0x2f,0x07,0x2a,0x31,0xe8,0x2d,0x72,0x02,0x1c,0x02,0x82,0x02,0x2a, + 0x05,0xe8,0x3c,0x72,0x2a,0x74,0x04,0x1c,0x04,0x83,0x3b,0x7f,0x0e,0x60,0x29,0x7d, + 0x28,0x7c,0x1c,0xf0,0xe7,0x12,0x37,0x3c,0xe7,0x1c,0xd7,0x1c,0x2f,0x75,0x57,0x1c, + 0x47,0xab,0x57,0xa3,0x83,0x3c,0x67,0xaf,0x77,0xa4,0x84,0x3c,0x87,0xa6,0x97,0xa5, + 0x85,0x3c,0x65,0x1e,0x05,0x3d,0xa7,0xa6,0xb7,0xa7,0x87,0x3c,0x30,0x72,0xb3,0x1e, + 0xf4,0x1e,0x05,0x3b,0x76,0x1e,0x2c,0x7f,0x0e,0x20,0x4e,0x01,0x0c,0xa7,0x7e,0x0c, + 0xe1,0xef,0x07,0x2a,0x02,0xe8,0x2a,0x72,0x28,0x7f,0x21,0x77,0x07,0x87,0x29,0x76, + 0x67,0x1c,0x07,0xa7,0x07,0x2a,0xa2,0xe8,0x22,0x77,0x57,0xa7,0x77,0x36,0x10,0xe8, + 0x26,0x77,0x07,0xa7,0x26,0x76,0x06,0xa6,0x86,0x3c,0x76,0x1e,0x25,0x77,0x07,0xa7, + 0x07,0x3d,0x67,0x1e,0x24,0x76,0x06,0xa3,0x83,0x3d,0x23,0x72,0x73,0x1e,0x1a,0x7f, + 0x14,0x77,0x07,0x87,0x1d,0x76,0x06,0xa6,0x1d,0x75,0x40,0xf0,0x40,0x9f,0x00,0x00, + 0x00,0x2d,0x00,0x00,0x41,0x9f,0x00,0x00,0xb0,0x00,0x00,0x00,0xb4,0x00,0x00,0x00, + 0x94,0x9f,0x00,0x00,0x8a,0x9e,0x00,0x00,0x20,0x9e,0x00,0x00,0xb8,0x00,0x00,0x00, + 0xbc,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0xc8,0x00,0x00,0x00,0x00,0xe0,0x02,0x00, + 0xe0,0x3d,0x00,0x00,0xc4,0x00,0x00,0x00,0x08,0x01,0x00,0x00,0xd0,0x83,0x00,0x00, + 0x1c,0x9e,0x00,0x00,0x20,0x01,0x00,0x00,0x80,0xff,0xff,0xff,0x0b,0x01,0x00,0x00, + 0x44,0xaa,0x00,0x00,0x68,0x07,0x00,0x00,0x7a,0x25,0x00,0x00,0x78,0x07,0x00,0x00, + 0x0c,0x07,0x00,0x00,0x8d,0x00,0x00,0x00,0x52,0xa4,0x00,0x00,0x53,0xa4,0x00,0x00, + 0x54,0xa4,0x00,0x00,0x55,0xa4,0x00,0x00,0x8c,0x07,0x00,0x00,0x05,0xa5,0x85,0x3c, + 0x65,0x1e,0xa6,0x76,0x06,0xa6,0x06,0x3d,0x56,0x1e,0xa5,0x75,0x05,0xa5,0x85,0x3d, + 0x65,0x1e,0xa4,0x76,0x76,0x1c,0x06,0xa4,0xa4,0x76,0x76,0x1c,0x06,0xa6,0x86,0x3c, + 0x46,0x1e,0xa2,0x74,0x74,0x1c,0x04,0xa4,0x04,0x3d,0x64,0x1e,0xa1,0x76,0x76,0x1c, + 0x06,0xa6,0x86,0x3d,0x46,0x1e,0x56,0x0c,0x9f,0x76,0x24,0xe8,0x07,0x60,0x06,0xb7, + 0x9e,0x76,0x0c,0xf0,0x9d,0x74,0x04,0xa5,0x05,0x20,0x45,0x01,0x04,0xb5,0x9b,0x78, + 0x87,0x1c,0x07,0xa7,0x27,0x3e,0x57,0x0c,0x02,0xe0,0x17,0x60,0x06,0xb7,0x95,0x77, + 0x07,0xa7,0x07,0x2a,0x97,0x77,0x02,0xe8,0xa6,0x60,0x04,0xf0,0x07,0xa6,0x06,0x2a, + 0x02,0xe8,0x06,0x24,0x07,0xb6,0x07,0xa7,0x07,0x2a,0x08,0xe8,0x16,0x60,0x91,0x77, + 0x07,0xb6,0x04,0xf0,0x06,0xa5,0x05,0x2a,0xdd,0xef,0xe9,0xf7,0x8f,0x71,0x10,0x1c, + 0x68,0x00,0xf0,0x21,0xcf,0x00,0xf0,0x25,0x78,0x00,0x01,0x64,0x10,0x05,0x8b,0x77, + 0x07,0xae,0x3c,0x60,0x0e,0x2a,0x03,0xe8,0xec,0x12,0x0c,0x24,0x4c,0x01,0x88,0x77, + 0x07,0xa5,0xa6,0x60,0x56,0x0c,0x01,0xe0,0x07,0xb6,0x0a,0x12,0x1a,0x21,0xa6,0x12, + 0x07,0x60,0x04,0x2c,0x75,0x12,0x06,0xd4,0x83,0x60,0x03,0x1c,0x73,0x1c,0x03,0xb5, + 0x07,0x20,0x16,0x20,0xa7,0x2a,0xf7,0xe7,0x6d,0x64,0xf1,0x11,0xde,0x03,0xf9,0x11, + 0x7d,0x72,0x7d,0x73,0xe3,0x1c,0xd4,0x12,0x7d,0x7f,0x7d,0x76,0xa6,0xa5,0xb6,0xa7, + 0x87,0x3c,0x57,0x1e,0x7c,0x71,0x71,0x1c,0x1f,0x12,0x7b,0x72,0x27,0x1c,0x7b,0x12, + 0x6b,0x01,0xc6,0xa5,0xd6,0xa7,0x87,0x3c,0x57,0x1e,0x76,0x72,0x72,0x1c,0x76,0x73, + 0x37,0x1c,0x79,0x12,0x69,0x01,0x05,0x60,0x75,0x73,0xf1,0x11,0xcd,0x03,0xf9,0x11, + 0xf8,0x67,0x57,0x12,0x37,0x1c,0x72,0x74,0x47,0x1c,0x07,0xa7,0x27,0x2a,0x45,0xe0, + 0x54,0x12,0x34,0x3c,0x54,0x05,0x47,0x12,0xe7,0x1c,0x37,0x1c,0x6e,0x76,0x67,0x1c, + 0x37,0xac,0x47,0xa6,0x86,0x3c,0xc6,0x1e,0x57,0xac,0x67,0xa7,0x87,0x3c,0xc7,0x1e, + 0x66,0x1c,0xd4,0x1c,0x34,0x1c,0x67,0x7c,0xc4,0x1c,0x34,0xa1,0x44,0xac,0x8c,0x3c, + 0x1c,0x1e,0xc6,0x05,0x66,0x01,0x77,0x1c,0x54,0xac,0x64,0xa4,0x84,0x3c,0xc4,0x1e, + 0x47,0x05,0x74,0x12,0x64,0x01,0x67,0x12,0x77,0x01,0x78,0x0d,0x03,0xe8,0xf7,0x0d, + 0x03,0xe8,0x03,0xf0,0x76,0x32,0x01,0xf0,0xb6,0x12,0x47,0x12,0x77,0x01,0x78,0x0d, + 0x03,0xe8,0x27,0x0d,0x03,0xe8,0x03,0xf0,0x74,0x32,0x01,0xf0,0x94,0x12,0x57,0x12, + 0x37,0x3c,0x57,0x05,0x37,0x1c,0x54,0x71,0x17,0x1c,0x66,0x01,0x57,0xb6,0x86,0x3e, + 0x67,0xb6,0x64,0x01,0x77,0xb4,0x84,0x3e,0x87,0xb4,0x05,0x20,0xa5,0x2a,0xb1,0xe7, + 0x0e,0x60,0x4a,0x78,0xa9,0x12,0x3f,0xf0,0xe7,0x12,0x37,0x3c,0xe7,0x1c,0x87,0x1c, + 0x4b,0x76,0x76,0x1c,0x46,0xa5,0x56,0xac,0x8c,0x3c,0x5c,0x1e,0x66,0xa5,0x76,0xab, + 0x8b,0x3c,0x5b,0x1e,0x3c,0x7a,0x0d,0x60,0x46,0x72,0x72,0x1c,0xb0,0x92,0x0d,0x01, + 0xa0,0x91,0x0a,0xa7,0x07,0x2a,0x21,0xe8,0xd7,0x12,0x37,0x3c,0xd7,0x05,0x87,0x1c, + 0x3e,0x72,0x27,0x1c,0x57,0xa6,0x67,0xa2,0x82,0x3c,0x62,0x1e,0xc2,0x14,0x77,0xa6, + 0x87,0xa3,0x83,0x3c,0x63,0x1e,0xb3,0x14,0x72,0x01,0x73,0x01,0x3a,0x7f,0xe7,0x12, + 0xe7,0x1c,0x23,0x61,0x03,0x1c,0x37,0x1c,0x07,0xc6,0x62,0x0c,0x06,0xe0,0x07,0xd2, + 0x84,0x62,0x04,0x1c,0x04,0xa5,0xb0,0x84,0x04,0xb5,0x0d,0x20,0x6a,0x20,0xad,0x2a, + 0xd6,0xe7,0x0e,0x20,0x4e,0x01,0x22,0x76,0x06,0xa2,0x2e,0x0c,0xbd,0xef,0x9a,0x12, + 0x2e,0x7d,0xd3,0x12,0x05,0x60,0x54,0x12,0x8b,0x2c,0x24,0x7e,0x0c,0x2c,0xe8,0x12, + 0x19,0x60,0x6a,0xf0,0x04,0x20,0x44,0x01,0x46,0x12,0x5a,0xf0,0x03,0xaf,0xbf,0x0f, + 0x59,0xe8,0x67,0x12,0x37,0x3c,0x67,0x1c,0xe7,0x1c,0x21,0x71,0x17,0x1c,0x07,0xa1, + 0xf1,0x0f,0x4c,0xe0,0x6f,0x12,0x6f,0x1c,0x21,0x61,0x01,0x1c,0x1f,0x1c,0x0a,0xc1, + 0x0f,0xcf,0x1f,0x0c,0x3b,0xe8,0x07,0xbc,0x41,0xf0,0x00,0x00,0x54,0xa4,0x00,0x00, + 0x55,0xa4,0x00,0x00,0x8e,0x00,0x00,0x00,0x8f,0x00,0x00,0x00,0x90,0x00,0x00,0x00, + 0x91,0x00,0x00,0x00,0x3c,0xa4,0x00,0x00,0x3d,0xa4,0x00,0x00,0xc6,0x00,0x00,0x00, + 0x60,0xa6,0x00,0x00,0x62,0xa4,0x00,0x00,0xd0,0x00,0x00,0x00,0xe5,0xa3,0x00,0x00, + 0x94,0x9f,0x00,0x00,0x46,0xa1,0x00,0x00,0x8c,0xa1,0x00,0x00,0x8c,0x82,0x00,0x00, + 0x20,0x9e,0x00,0x00,0x81,0xff,0xff,0xff,0x80,0xff,0xff,0xff,0x8a,0x9e,0x00,0x00, + 0x8e,0x05,0x00,0x00,0x00,0x03,0x00,0x00,0xb8,0x02,0x00,0x00,0x08,0x01,0x00,0x00, + 0x0b,0x01,0x00,0x00,0xc0,0x0c,0x00,0x00,0x95,0x9f,0x00,0x00,0x57,0x12,0x37,0x3c, + 0x57,0x1c,0x87,0x1c,0xbe,0x76,0x67,0x1c,0x07,0xbc,0x04,0xf0,0x06,0x20,0x46,0x01, + 0x26,0x0f,0xa4,0xe7,0x03,0xa7,0xb7,0x0f,0x04,0xe8,0x81,0x60,0x01,0x1c,0x17,0x1c, + 0x07,0xb9,0x05,0x20,0x83,0x20,0x1a,0x20,0x24,0x0f,0x94,0xe7,0xb5,0x77,0x07,0xac, + 0xb5,0x77,0x07,0xab,0xb5,0x74,0x05,0x60,0x56,0x12,0x8f,0x2c,0xb4,0x7e,0x12,0x60, + 0x24,0xf0,0x04,0xa7,0xf7,0x0f,0x1f,0xe0,0x57,0x12,0x37,0x3c,0x57,0x1c,0xe7,0x1c, + 0xb0,0x73,0x37,0x1c,0x87,0xa3,0x97,0xa7,0x87,0x3c,0x37,0x1e,0x07,0x3d,0x07,0x3b, + 0xb7,0x0d,0x11,0xe0,0x0e,0xf0,0x67,0x12,0x07,0x20,0x47,0x01,0x83,0x60,0x03,0x1c, + 0x63,0x1c,0x03,0xaa,0x0a,0x2a,0x04,0xe0,0x04,0xb6,0x03,0xb2,0x76,0x12,0x03,0xf0, + 0x76,0x12,0xc6,0x0c,0xf0,0xef,0x05,0x20,0x84,0x20,0x05,0x01,0xc1,0x0c,0xd9,0xef, + 0x0e,0x60,0xeb,0x12,0x8a,0x2c,0x9d,0x79,0x11,0xf0,0x0d,0xa7,0xa7,0x0f,0x0b,0xe8, + 0xe2,0x12,0x32,0x3c,0xe2,0x1c,0x92,0x1c,0x9b,0x74,0x42,0x1c,0xd3,0x12,0x94,0x60, + 0x9a,0x7f,0x0e,0x20,0x4e,0x01,0x0b,0x20,0x4b,0x01,0x8d,0x20,0xcb,0x0f,0xed,0xe7, + 0x97,0x77,0x07,0xbe,0x97,0x77,0x07,0xa8,0x97,0x76,0x06,0xb8,0x86,0x12,0x06,0x20, + 0x46,0x01,0x07,0xb6,0x35,0x60,0x65,0x0c,0x02,0xe0,0x06,0x60,0x07,0xb6,0x07,0xac, + 0x02,0x12,0x72,0x20,0x03,0x60,0xa4,0x60,0x90,0x7f,0x8c,0x77,0x07,0xab,0x8f,0x72, + 0x04,0x60,0x86,0x7d,0x63,0x64,0xf1,0x11,0xc3,0x03,0xf9,0x11,0x1e,0x60,0x2c,0xf0, + 0x02,0xaf,0xf7,0x12,0x37,0x3c,0xf7,0x05,0x37,0x1c,0xd7,0x1c,0x89,0x76,0x76,0x1c, + 0x06,0xbe,0x88,0x76,0x76,0x1c,0x47,0x12,0x37,0x3c,0x47,0x1c,0xd7,0x1c,0x86,0x79, + 0x97,0x1c,0x77,0xaa,0x87,0xa5,0x85,0x3c,0xa5,0x1e,0x36,0xb5,0x85,0x3e,0x46,0xb5, + 0x97,0xaa,0xa7,0xa5,0x85,0x3c,0xa5,0x1e,0x56,0xb5,0x85,0x3e,0x66,0xb5,0xb7,0xa5, + 0xc7,0xa7,0x87,0x3c,0x57,0x1e,0x76,0xb7,0x87,0x3e,0x86,0xb7,0x81,0x60,0x01,0x1c, + 0x1f,0x1c,0x0f,0xbe,0x04,0x20,0x82,0x20,0x04,0x01,0xb1,0x0c,0xd1,0xef,0x04,0x60, + 0x46,0x12,0x65,0x64,0xf1,0x11,0xc5,0x03,0xf9,0x11,0x68,0x7d,0x5f,0x12,0xdf,0x1c, + 0x0e,0x2c,0xf2,0x67,0x87,0x60,0x07,0x1c,0x67,0x1c,0x07,0xa3,0x03,0x2a,0x12,0xe0, + 0xf7,0x12,0x47,0x1c,0x6b,0x79,0x97,0x1c,0x07,0xb3,0x67,0x12,0x37,0x3c,0x67,0x05, + 0x57,0x1c,0xd7,0x1c,0x68,0x7b,0xb7,0x1c,0x37,0xbe,0x47,0xb2,0x57,0xbe,0x67,0xb2, + 0x77,0xb3,0x87,0xb3,0x06,0x20,0x64,0x20,0xa6,0x2a,0xe4,0xe7,0xcd,0x12,0x4d,0x3c, + 0xc7,0x12,0x67,0x3c,0x7d,0x1c,0x55,0x79,0x9d,0x1c,0x60,0x71,0x1d,0x1c,0x0b,0x60, + 0xba,0x12,0x62,0x64,0xf1,0x11,0xc2,0x03,0xf9,0x11,0xa0,0x92,0x92,0x1c,0xb0,0x92, + 0x63,0x64,0xf1,0x11,0x38,0x03,0xf9,0x11,0x94,0x12,0x84,0x1c,0xc0,0x94,0xb0,0x87, + 0xb7,0x1c,0x53,0x75,0x57,0x1c,0x07,0xa7,0x07,0x2a,0x52,0xe8,0xc0,0x87,0xb7,0x1c, + 0x57,0x1c,0x07,0xa7,0x07,0x2a,0x4c,0xe8,0x17,0x60,0x0d,0xb7,0xce,0x12,0xce,0x1c, + 0xc7,0x12,0x37,0x3c,0x7e,0x1c,0xae,0x1c,0x4e,0x76,0x6e,0x1c,0x3e,0x3c,0x9e,0x1c, + 0xa7,0x12,0x37,0x3c,0xa7,0x05,0xa0,0x86,0x76,0x1c,0x96,0x1c,0x46,0x71,0x16,0x1c, + 0x36,0xa4,0x46,0xa5,0x85,0x3c,0x45,0x1e,0x87,0x1c,0x97,0x1c,0x17,0x1c,0x37,0xa3, + 0x47,0xa4,0x84,0x3c,0x34,0x1e,0x45,0x05,0x65,0x01,0x3e,0xb5,0x85,0x3e,0x4e,0xb5, + 0x56,0xa5,0x66,0xa3,0x83,0x3c,0x53,0x1e,0x57,0xa6,0x67,0xa7,0x87,0x3c,0x67,0x1e, + 0x73,0x05,0x63,0x01,0x5e,0xb3,0x37,0x12,0x87,0x3e,0x6e,0xb7,0x3e,0xa7,0x4e,0xa2, + 0x82,0x3c,0x72,0x1e,0x02,0x3d,0x02,0x3b,0x73,0x01,0x36,0x7f,0x7e,0xb2,0x82,0x3e, + 0x8e,0xb2,0x3e,0xa7,0x4e,0xa2,0x82,0x3c,0x72,0x1e,0x02,0x3d,0x5e,0xa7,0x6e,0xa3, + 0x83,0x3c,0x73,0x1e,0x03,0x3d,0x02,0x3b,0x03,0x3b,0x2f,0x7f,0x7d,0xb2,0x12,0xf0, + 0x06,0x60,0x0d,0xb6,0xc7,0x12,0xc7,0x1c,0xc5,0x12,0x35,0x3c,0x57,0x1c,0xa7,0x1c, + 0x28,0x72,0x27,0x1c,0x37,0x3c,0x97,0x1c,0x37,0xb6,0x47,0xb6,0x57,0xb6,0x67,0xb6, + 0x77,0xb6,0x87,0xb6,0x0a,0x20,0x6b,0x20,0x7d,0x20,0x63,0x64,0x3b,0x0f,0x8f,0xe7, + 0x18,0x77,0x07,0xae,0x22,0x77,0x07,0x8c,0x22,0x78,0xa0,0x98,0x22,0x76,0x87,0x12, + 0x05,0x60,0x0e,0x73,0x29,0x60,0x6f,0x64,0xe4,0x12,0xf1,0x11,0xf4,0x03,0xf9,0x11, + 0x43,0x1c,0x1d,0x7a,0xca,0x1c,0x4b,0x60,0x54,0x12,0x1c,0x71,0x1c,0x1c,0x1d,0x60, + 0x07,0xa2,0x42,0x2a,0x35,0xe0,0x07,0xb4,0x56,0xf0,0x00,0x00,0x0b,0x01,0x00,0x00, + 0x94,0x9f,0x00,0x00,0x86,0x9e,0x00,0x00,0x95,0x9f,0x00,0x00,0x8a,0x9e,0x00,0x00, + 0x08,0x01,0x00,0x00,0x66,0x01,0x00,0x00,0x8c,0x82,0x00,0x00,0xef,0x9f,0x00,0x00, + 0xe5,0xa3,0x00,0x00,0xe4,0xa3,0x00,0x00,0xc4,0x09,0x00,0x00,0xf0,0x9f,0x00,0x00, + 0x02,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x60,0x01,0x00,0x00,0x1a,0x04,0x00,0x00, + 0x83,0x00,0x00,0x00,0xc0,0x0c,0x00,0x00,0xee,0x0b,0x00,0x00,0x1c,0x9e,0x00,0x00, + 0xfa,0xa3,0x00,0x00,0x0e,0xa4,0x00,0x00,0xa1,0x00,0x00,0x00,0xa2,0x00,0x00,0x00, + 0x02,0x2a,0x19,0xe0,0x32,0x12,0x52,0x1c,0xb8,0x78,0x82,0x1c,0x02,0xa2,0x02,0x2a, + 0x0e,0xe8,0x06,0xa2,0x02,0x2a,0x03,0xe0,0x78,0x12,0x98,0x24,0x08,0xbe,0x02,0x20, + 0x42,0x01,0x06,0xb2,0x0c,0xa8,0x28,0x0c,0x19,0xe0,0x07,0xbd,0x17,0xf0,0x07,0xb2, + 0x06,0xb2,0xa7,0xb2,0x13,0xf0,0x07,0xb9,0x32,0x12,0x52,0x1c,0xab,0x71,0x12,0x1c, + 0x02,0xa2,0x02,0x2a,0x03,0xe8,0x06,0xb4,0xa7,0xb4,0x08,0xf0,0xa7,0xa2,0x02,0x20, + 0x42,0x01,0xa7,0xb2,0x0a,0xa8,0x28,0x0c,0x01,0xe0,0x07,0xbb,0x07,0x20,0x06,0x20, + 0x65,0x20,0xf5,0x0f,0x95,0xe7,0xa1,0x76,0x06,0x87,0xa2,0x64,0x27,0x1c,0x07,0xac, + 0x0e,0x60,0x9f,0x7b,0x87,0xf0,0xb7,0x12,0xe7,0x1c,0x9e,0x73,0x37,0x1c,0x07,0xa7, + 0x07,0x2a,0x05,0xe8,0x0e,0x20,0x4e,0x01,0x6e,0x0c,0xf5,0xef,0x7b,0xf0,0x26,0x60, + 0x98,0x7d,0xb7,0x12,0xc7,0x1c,0x97,0x74,0x47,0x1c,0x07,0xa5,0x05,0x24,0x45,0x01, + 0x56,0x0c,0x6c,0xe8,0xd6,0x12,0xe6,0x1c,0x46,0x1c,0x15,0x60,0x06,0xb5,0x46,0x60, + 0x07,0xb6,0xe8,0x12,0x38,0x3c,0xb0,0x98,0x82,0x12,0xe2,0x05,0xd2,0x1c,0xc8,0x12, + 0x38,0x3c,0x89,0x12,0xc9,0x05,0xd3,0x12,0x93,0x1c,0x8b,0x71,0x12,0x1c,0x13,0x1c, + 0x74,0x60,0x8a,0x7f,0x9d,0x1c,0x84,0x72,0x2d,0x1c,0x0a,0x60,0xc0,0x98,0x09,0x28, + 0xd0,0x99,0xb0,0x89,0xb8,0x12,0x98,0x1c,0xb0,0x98,0xd0,0x82,0xd2,0x1c,0x97,0x12, + 0xe7,0x05,0x72,0x1c,0xd3,0x12,0x74,0x60,0x81,0x7f,0x7d,0x78,0xb0,0x82,0xa2,0x1c, + 0xc0,0x83,0xb3,0x1c,0xa3,0x1c,0x7e,0x71,0x12,0x1c,0x13,0x1c,0x84,0x60,0x7b,0x7f, + 0x07,0x60,0x0d,0xb7,0x62,0x64,0x2d,0x1c,0x03,0x65,0x3a,0x1c,0x7a,0x74,0x4a,0x0f, + 0xe4,0xe7,0x87,0x12,0xc7,0x1c,0x78,0x76,0x76,0x1c,0x06,0xa5,0xe8,0x1c,0x76,0x76, + 0x86,0x1c,0x06,0xb5,0x76,0x76,0x76,0x1c,0x06,0xa5,0x74,0x76,0x86,0x1c,0x06,0xb5, + 0x74,0x76,0x76,0x1c,0x06,0xa5,0x72,0x76,0x86,0x1c,0x06,0xb5,0x72,0x76,0x76,0x1c, + 0x06,0xa5,0x70,0x76,0x86,0x1c,0x06,0xb5,0x70,0x76,0x76,0x1c,0x06,0xa5,0x6e,0x76, + 0x86,0x1c,0x06,0xb5,0x6e,0x76,0x76,0x1c,0x06,0xa5,0x6c,0x76,0x86,0x1c,0x06,0xb5, + 0x6c,0x75,0x57,0x1c,0x07,0xa7,0x58,0x1c,0x08,0xb7,0x04,0xf0,0x0c,0x20,0x4c,0x01, + 0xac,0x2a,0x86,0xe7,0x5a,0x76,0x06,0x87,0xa8,0x64,0x87,0x1c,0x07,0xa6,0x6e,0x0c, + 0x03,0xe0,0x97,0x60,0xc7,0x0c,0x6f,0xe7,0x56,0x76,0x62,0x77,0x07,0xa3,0x62,0x77, + 0x07,0xa7,0x69,0x64,0x71,0x12,0xf1,0x11,0x91,0x03,0xf9,0x11,0x62,0x12,0x12,0x1c, + 0x4e,0x7b,0xb2,0x1c,0x7a,0x12,0x4a,0x3c,0x75,0x12,0x65,0x3c,0x5a,0x1c,0xa6,0x1c, + 0x50,0x7c,0xc6,0x1c,0x05,0x60,0xf1,0x11,0x39,0x03,0xf9,0x11,0x0a,0x28,0x3d,0x12, + 0x4d,0x3c,0x34,0x12,0x64,0x3c,0x4d,0x1c,0x46,0x7e,0x54,0x12,0xe4,0x1c,0x45,0x78, + 0x84,0x1c,0x04,0xa4,0x14,0x24,0x44,0x01,0x1b,0x60,0x4b,0x0c,0x5c,0xe8,0x02,0xa4, + 0x04,0x2a,0x59,0xe0,0x24,0x60,0x02,0xb4,0x5c,0x12,0x3c,0x3c,0x5c,0x05,0xc4,0x12, + 0x94,0x1c,0xe4,0x1c,0x4a,0x78,0x84,0x1c,0x34,0xa8,0x44,0xaf,0x8f,0x3c,0x8f,0x1e, + 0x1c,0x1c,0xec,0x1c,0x46,0x78,0x8c,0x1c,0x3c,0xbf,0x8f,0x3e,0x4c,0xbf,0x54,0xaf, + 0x64,0xa4,0x84,0x3c,0xf4,0x1e,0x5c,0xb4,0x84,0x3e,0x6c,0xb4,0x04,0x67,0x7c,0xb4, + 0x34,0x60,0x8c,0xb4,0x34,0x12,0x34,0x1c,0x3f,0x12,0x3f,0x3c,0xf4,0x1c,0x54,0x1c, + 0x3c,0x7c,0xc4,0x1c,0x34,0x3c,0xe4,0x1c,0x74,0xac,0x84,0xaf,0x8f,0x3c,0xcf,0x1e, + 0xfc,0x63,0x06,0xbb,0xfc,0x0c,0x34,0xaf,0x44,0xac,0x8c,0x3c,0xfc,0x1e,0x7f,0x12, + 0x7f,0x1c,0x7b,0x12,0x3b,0x3c,0xbf,0x1c,0x5f,0x1c,0x03,0xe8,0x31,0x78,0x8f,0x1c, + 0x02,0xf0,0x2f,0x7b,0xbf,0x1c,0x3f,0x3c,0xef,0x1c,0x3f,0xbc,0x8c,0x3e,0x4f,0xbc, + 0x54,0xac,0x64,0xae,0x8e,0x3c,0xce,0x1e,0x5f,0xbe,0x8e,0x3e,0x6f,0xbe,0x74,0xae, + 0x84,0xa4,0x84,0x3c,0xe4,0x1e,0x7f,0xb4,0x84,0x3e,0x8f,0xb4,0xa4,0x12,0x64,0x1c, + 0xd4,0x1c,0x74,0xa4,0x76,0xb4,0x05,0x20,0x62,0x20,0x76,0x20,0xa5,0x2a,0x94,0xe7, + 0x04,0x60,0x0f,0x7e,0x6c,0x64,0x7a,0x12,0xf1,0x11,0xca,0x03,0xf9,0x11,0x42,0x12, + 0x3b,0x60,0x46,0x12,0xe6,0x1c,0x0b,0x75,0x65,0x1c,0x05,0xa5,0x15,0x2a,0x5f,0xe0, + 0x0f,0x71,0x16,0x1c,0x06,0xa5,0x4d,0x12,0x3d,0x3c,0x4d,0x05,0xd3,0x12,0xa3,0x1c, + 0xe3,0x1c,0x12,0x76,0x63,0x1c,0x51,0xf0,0x02,0x03,0x00,0x00,0x1c,0x9e,0x00,0x00, + 0x8a,0x9e,0x00,0x00,0x70,0x05,0x00,0x00,0x76,0x02,0x00,0x00,0x8c,0x82,0x00,0x00, + 0x1a,0x04,0x00,0x00,0x40,0x01,0x00,0x00,0x5c,0x05,0x00,0x00,0x66,0x05,0x00,0x00, + 0x7a,0x05,0x00,0x00,0x84,0x05,0x00,0x00,0x8e,0x05,0x00,0x00,0x98,0x05,0x00,0x00, + 0xa7,0x05,0x00,0x00,0xe4,0xa3,0x00,0x00,0xe5,0xa3,0x00,0x00,0x00,0x03,0x00,0x00, + 0x83,0x00,0x00,0x00,0x33,0xa6,0x43,0xaf,0x8f,0x3c,0x6f,0x1e,0x56,0x12,0xf1,0x11, + 0xc6,0x03,0xf9,0x11,0xd6,0x1c,0xe6,0x1c,0xc0,0x78,0x86,0x1c,0x36,0xbf,0x8f,0x3e, + 0x46,0xbf,0x53,0xa9,0x63,0xaf,0x8f,0x3c,0x9f,0x1e,0x56,0xbf,0x8f,0x3e,0x66,0xbf, + 0x56,0x12,0x56,0x1c,0x5f,0x12,0x3f,0x3c,0xf6,0x1c,0x46,0x1c,0xb8,0x79,0x96,0x1c, + 0x36,0x3c,0xe6,0x1c,0x36,0xb2,0x46,0xb2,0x56,0xb2,0x66,0xb2,0x76,0xb2,0x86,0xb2, + 0x96,0xb2,0x05,0x20,0x45,0x01,0x5b,0x0c,0xd5,0x01,0x75,0x0f,0xd3,0xe7,0x04,0x20, + 0xa4,0x2a,0x97,0xe7,0xaf,0x75,0x06,0x60,0x64,0x12,0x2b,0x60,0xae,0x7e,0x3c,0x60, + 0x6d,0x12,0x6f,0x64,0xf1,0x11,0x7f,0x03,0xf9,0x11,0x06,0x01,0x57,0x12,0x37,0x21, + 0x07,0xa7,0x73,0x12,0x03,0x24,0x43,0x01,0x3b,0x0c,0x3b,0xe8,0x17,0x2a,0x43,0x12, + 0x33,0x3c,0x43,0x1c,0xe3,0x1c,0xa4,0x77,0x37,0x1c,0x07,0xb1,0x0a,0xe0,0xa3,0x71, + 0x13,0x1c,0x67,0x12,0x37,0x3c,0x67,0x05,0xf7,0x1c,0xe7,0x1c,0x9b,0x72,0x27,0x1c, + 0x09,0xf0,0x9e,0x77,0x73,0x1c,0x67,0x12,0x37,0x3c,0x67,0x05,0xf7,0x1c,0xe7,0x1c, + 0x96,0x78,0x87,0x1c,0x37,0xaa,0x47,0xa2,0x82,0x3c,0xa2,0x1e,0x53,0xb2,0x82,0x3e, + 0x63,0xb2,0x57,0xaa,0x67,0xa2,0x82,0x3c,0xa2,0x1e,0x73,0xb2,0x82,0x3e,0x83,0xb2, + 0x77,0xa2,0x87,0xa7,0x87,0x3c,0x27,0x1e,0x93,0xb7,0x87,0x3e,0xa3,0xb7,0xa5,0xa7, + 0x05,0xb7,0x07,0x20,0x47,0x01,0xa5,0xb7,0x7c,0x0c,0x01,0xe0,0xa5,0xbd,0x04,0x20, + 0x44,0x01,0x06,0x20,0x05,0x20,0xa6,0x2a,0xb8,0xe7,0x89,0x77,0x07,0xb4,0x89,0x7d, + 0x0e,0x60,0x84,0x7c,0x6b,0x64,0xe7,0x12,0xc7,0x1c,0x87,0x76,0x76,0x1c,0x06,0xa6, + 0x16,0x2a,0x10,0xe0,0x86,0x79,0x97,0x1c,0x07,0xa7,0xe3,0x12,0x33,0x3c,0xe3,0x05, + 0xf1,0x11,0xb7,0x03,0xf9,0x11,0x73,0x1c,0xc3,0x1c,0xd2,0x12,0x81,0x71,0x13,0x1c, + 0x74,0x60,0x80,0x7f,0x0e,0x20,0x6d,0x20,0xae,0x2a,0xe5,0xe7,0x7f,0x7e,0x0d,0x60, + 0x19,0x60,0xd8,0x12,0x74,0x7c,0x7d,0x7b,0xe7,0x12,0xd7,0x25,0x07,0xa7,0x76,0x12, + 0x16,0x24,0x46,0x01,0x69,0x0c,0x73,0xe8,0x7a,0x72,0x02,0xaa,0x7a,0x73,0x03,0xa7, + 0xd5,0x12,0x35,0x3c,0xd5,0x05,0x64,0x64,0xa6,0x12,0xf1,0x11,0x46,0x03,0xf9,0x11, + 0x56,0x1c,0xc6,0x1c,0x65,0x71,0x16,0x1c,0x36,0xa3,0x46,0xa2,0x82,0x3c,0x32,0x1e, + 0xf1,0x11,0x47,0x03,0xf9,0x11,0x57,0x1c,0xc7,0x1c,0x17,0x1c,0x37,0xa4,0x47,0xa5, + 0x85,0x3c,0x45,0x1e,0x52,0x05,0x56,0xa5,0x66,0xa3,0x83,0x3c,0x53,0x1e,0x57,0xa6, + 0x67,0xa7,0x87,0x3c,0x67,0x1e,0x73,0x05,0x72,0x01,0x73,0x01,0x67,0x7f,0x72,0x01, + 0x0b,0x87,0x66,0x76,0x76,0x1c,0x06,0xa6,0x66,0x73,0x37,0x1c,0x07,0xa7,0x87,0x3c, + 0x67,0x1e,0x27,0x0d,0x03,0xe8,0x27,0x60,0x0e,0xb7,0x04,0xf0,0x0e,0xa7,0x27,0x2a, + 0x01,0xe0,0x0e,0xb9,0x0e,0xa7,0x07,0x2a,0x37,0xe0,0xd6,0x12,0x36,0x3c,0xd6,0x05, + 0x67,0x64,0xf1,0x11,0xa7,0x03,0xf9,0x11,0x67,0x1c,0xc7,0x1c,0x47,0x74,0x47,0x1c, + 0x37,0xa5,0x47,0xa2,0x82,0x3c,0x52,0x1e,0xc6,0x1c,0x56,0x75,0x56,0x1c,0x76,0xa4, + 0x86,0xa5,0x85,0x3c,0x45,0x1e,0x52,0x05,0x57,0xa5,0x67,0xa3,0x83,0x3c,0x53,0x1e, + 0x96,0xa5,0xa6,0xa7,0x87,0x3c,0x57,0x1e,0x73,0x05,0x72,0x01,0x73,0x01,0x4a,0x7f, + 0x72,0x01,0x0b,0x87,0x4a,0x76,0x76,0x1c,0x06,0xa6,0x49,0x71,0x17,0x1c,0x07,0xa7, + 0x87,0x3c,0x67,0x1e,0x27,0x0d,0x08,0xe8,0x17,0x60,0x0e,0xb7,0x05,0xf0,0x17,0x2a, + 0x02,0xe8,0x47,0x2a,0x01,0xe0,0x0e,0xb8,0x0d,0x20,0x0e,0x20,0xad,0x2a,0x7c,0xe7, + 0x42,0x7f,0x3a,0x77,0x07,0x87,0xb0,0x97,0x41,0x72,0x27,0x1c,0x07,0xa7,0x07,0x2a, + 0x06,0xe9,0x38,0x77,0x07,0xac,0x36,0x77,0x07,0xa7,0x76,0x12,0x46,0x3c,0x75,0x12, + 0x65,0x3c,0x56,0x1c,0x3b,0x7b,0x6b,0x1c,0x3b,0x7a,0x09,0x60,0x78,0x12,0x78,0x1c, + 0x37,0x3c,0x78,0x1c,0xc0,0x98,0x06,0x28,0xe0,0x96,0xc8,0x12,0x48,0x3c,0xc7,0x12, + 0x67,0x3c,0x78,0x1c,0xd0,0x98,0xa0,0x88,0x08,0xa7,0x17,0x24,0x47,0x01,0x1d,0x60, + 0x7d,0x0c,0xcb,0xe8,0x0a,0xa7,0x07,0x2a,0x76,0xe0,0x0b,0xa7,0x07,0x2a,0xc5,0xe8, + 0x19,0x7e,0xc0,0x87,0x97,0x1c,0x15,0x71,0x17,0x1c,0x37,0x3c,0xe7,0x1c,0x77,0xa6, + 0x87,0xa2,0x82,0x3c,0x62,0x1e,0xb0,0x87,0x28,0x73,0x37,0x1c,0x07,0xa6,0xb0,0x87, + 0x27,0x74,0x47,0x1c,0x07,0xa7,0x87,0x3c,0x67,0x1e,0x27,0x0c,0xae,0xe0,0xe0,0x87, + 0xb7,0x1c,0xd0,0x88,0x87,0x1c,0x07,0xa7,0x07,0x2a,0xa7,0xe8,0xb0,0x87,0x20,0x71, + 0x17,0x1c,0x07,0xa3,0x20,0x7f,0x62,0x01,0xc7,0x12,0xc7,0x1c,0xc6,0x12,0x36,0x3c, + 0x67,0x1c,0x97,0x1c,0x02,0x73,0x38,0xf0,0x00,0x03,0x00,0x00,0x83,0x00,0x00,0x00, + 0xe6,0xa3,0x00,0x00,0x8a,0x9e,0x00,0x00,0x1c,0x02,0x00,0x00,0x18,0x02,0x00,0x00, + 0xa5,0xa0,0x00,0x00,0x00,0xa1,0x00,0x00,0x70,0x05,0x00,0x00,0x5c,0x05,0x00,0x00, + 0x02,0x03,0x00,0x00,0x8c,0x82,0x00,0x00,0x18,0xa4,0x00,0x00,0x1c,0x9e,0x00,0x00, + 0xe5,0xa3,0x00,0x00,0xe4,0xa3,0x00,0x00,0xc0,0x0c,0x00,0x00,0xae,0x00,0x00,0x00, + 0xaf,0x00,0x00,0x00,0x70,0x02,0x00,0x00,0x34,0x47,0x00,0x00,0xaa,0x00,0x00,0x00, + 0xa4,0xa2,0x00,0x00,0x22,0xa4,0x00,0x00,0xac,0x00,0x00,0x00,0xad,0x00,0x00,0x00, + 0xab,0x00,0x00,0x00,0x3e,0x84,0x00,0x00,0x37,0x1c,0x37,0x3c,0xe7,0x1c,0x77,0xa6, + 0x87,0xa7,0x87,0x3c,0x67,0x1e,0x26,0x12,0xd6,0x0b,0x67,0x0c,0x53,0xe8,0x27,0x0c, + 0x4e,0xe0,0x0a,0xbd,0x52,0xf0,0x17,0x2a,0x50,0xe0,0x0b,0xa7,0x07,0x2a,0x4d,0xe8, + 0xae,0x77,0xc0,0x8d,0x9d,0x1c,0xad,0x71,0x1d,0x1c,0x3d,0x3c,0x7d,0x1c,0x7d,0xa6, + 0x8d,0xa8,0x88,0x3c,0x68,0x1e,0xce,0x12,0xce,0x1c,0xc6,0x12,0x36,0x3c,0x6e,0x1c, + 0x9e,0x1c,0x1e,0x1c,0x3e,0x3c,0x7e,0x1c,0x7e,0xa2,0x8e,0xa6,0x86,0x3c,0xb0,0x87, + 0xa4,0x73,0x37,0x1c,0x62,0x1e,0x07,0xa3,0xa3,0x7f,0x62,0x01,0x28,0x0c,0x2a,0xe8, + 0x3e,0xa7,0x4e,0xa5,0x85,0x3c,0x75,0x1e,0x05,0x3d,0x05,0x3b,0x5e,0xa7,0x6e,0xa6, + 0x86,0x3c,0x76,0x1e,0x06,0x3d,0x06,0x3b,0x54,0x12,0xe4,0x01,0x67,0x12,0xe7,0x01, + 0x47,0x0d,0x0a,0xe8,0x3d,0xa6,0x4d,0xa7,0x87,0x3c,0x67,0x1e,0x07,0x3d,0x07,0x3b, + 0xf1,0x11,0x57,0x03,0xf9,0x11,0x09,0xf0,0x5d,0xa5,0x6d,0xa7,0x87,0x3c,0x57,0x1e, + 0x07,0x3d,0x07,0x3b,0xf1,0x11,0x67,0x03,0xf9,0x11,0x07,0x22,0x03,0xe0,0x27,0x60, + 0x0a,0xb7,0x03,0xf0,0x47,0x60,0xa0,0x88,0x08,0xb7,0x09,0x20,0xa0,0x88,0x08,0x20, + 0xa0,0x98,0x7b,0x20,0x0a,0x20,0xa9,0x2a,0x26,0xe7,0x07,0x60,0x83,0x73,0x74,0x12, + 0x76,0x12,0x36,0x1c,0x85,0x75,0x65,0x1c,0x05,0xa5,0x15,0x2a,0x02,0xe8,0x45,0x2a, + 0x03,0xe0,0x82,0x79,0x96,0x1c,0x06,0xb4,0x07,0x20,0xa7,0x2a,0xf1,0xe7,0x80,0x77, + 0x07,0x87,0x80,0x7b,0xb7,0x1c,0x07,0xa7,0x0d,0x60,0x07,0x2a,0x18,0xe1,0x1b,0xf1, + 0xd7,0x12,0x37,0x3c,0xd7,0x1c,0x74,0x7c,0xc7,0x1c,0x7b,0x71,0x17,0x1c,0x07,0xae, + 0xc7,0x12,0xe7,0x1c,0x75,0x72,0x27,0x1c,0x07,0xa7,0x17,0x2a,0x07,0xe8,0x47,0x2a, + 0x05,0xe8,0x76,0x73,0x03,0xa5,0x76,0x76,0x07,0x60,0xfc,0xf0,0xee,0x1c,0x75,0x76, + 0xe6,0x1c,0x07,0x60,0x06,0xd7,0x74,0x74,0x4e,0x1c,0x0e,0xd7,0xf6,0xf0,0x74,0x12, + 0x06,0xa3,0x07,0x20,0x86,0x20,0x3e,0x0f,0xed,0xe0,0xd7,0x12,0x37,0x3c,0xd7,0x1c, + 0x62,0x75,0x57,0x1c,0x6e,0x76,0x67,0x1c,0x57,0xa6,0x67,0xa5,0x85,0x3c,0x65,0x1e, + 0x77,0xa3,0x87,0xa6,0x86,0x3c,0x36,0x1e,0x47,0x12,0x37,0x3c,0x47,0x1c,0x5a,0x78, + 0x87,0x1c,0x67,0x79,0x97,0x1c,0x27,0xa4,0x37,0xab,0x8b,0x3c,0x4b,0x1e,0xbc,0x12, + 0x6c,0x01,0xa0,0x9c,0x47,0xa4,0x57,0xa9,0x89,0x3c,0x49,0x1e,0x98,0x12,0x68,0x01, + 0xb0,0x98,0x75,0x01,0xc0,0x95,0x8c,0x62,0x0c,0x1c,0x0c,0xc8,0x78,0x01,0xd0,0x98, + 0x5a,0x12,0x8a,0x05,0xea,0x01,0x6a,0x01,0x76,0x01,0xe0,0x96,0xcc,0x62,0x0c,0x1c, + 0x0c,0xc8,0x78,0x01,0xf0,0x98,0x86,0x05,0x68,0x12,0xe8,0x01,0x68,0x01,0xa2,0x12, + 0x72,0x01,0x83,0x12,0x73,0x01,0x53,0x7f,0x2c,0x12,0x49,0x77,0x07,0x87,0x49,0x76, + 0x76,0x1c,0x06,0xa6,0x26,0x2a,0x33,0xe0,0x50,0x76,0x76,0x1c,0x06,0xa6,0x4f,0x71, + 0x17,0x1c,0x07,0xa3,0x83,0x3c,0x63,0x1e,0x82,0x32,0x3c,0x0c,0x08,0xe0,0xc2,0x12, + 0x82,0x3c,0x4b,0x7f,0x62,0x01,0xf7,0x60,0x27,0x0c,0x01,0xe8,0x02,0x61,0xe7,0x12, + 0xe7,0x1c,0x41,0x76,0x76,0x1c,0x06,0xc6,0x6c,0x0c,0x04,0xe0,0x3e,0x72,0x27,0x1c, + 0x07,0xc2,0x03,0xf0,0x3c,0x73,0x37,0x1c,0x07,0xd2,0xe7,0x12,0xe7,0x1c,0x3a,0x74, + 0x47,0x1c,0x07,0xdc,0x87,0x32,0x72,0x0c,0x72,0x02,0xf1,0x11,0x2a,0x03,0xf9,0x11, + 0x8a,0x3e,0x6a,0x01,0xf1,0x11,0x28,0x03,0xf9,0x11,0x88,0x3e,0x1e,0xf0,0x16,0x2a, + 0x1d,0xe0,0x35,0x76,0x76,0x1c,0x06,0xa6,0x35,0x75,0x57,0x1c,0x07,0xa7,0x87,0x3c, + 0x67,0x1e,0x75,0x12,0x35,0x3e,0x46,0x60,0x52,0x0c,0x0c,0xe8,0x75,0x12,0x25,0x3e, + 0x36,0x60,0x52,0x0c,0x07,0xe8,0x75,0x12,0x15,0x3e,0x26,0x60,0x52,0x0c,0x02,0xe8, + 0x72,0x0c,0x36,0x00,0x6a,0x1a,0x6a,0x01,0x68,0x1a,0x68,0x01,0x17,0x76,0x6e,0x1c, + 0x1b,0x77,0x7e,0x1c,0x0e,0xa7,0x17,0x2a,0x12,0xe8,0xc0,0x8c,0xd0,0x81,0xc1,0x0d, + 0x02,0xe8,0xab,0x1c,0x01,0xf0,0xab,0x05,0x6b,0x01,0xa0,0x9b,0xe0,0x8b,0xf0,0x8c, + 0xbc,0x0d,0x02,0xe8,0x89,0x1c,0x01,0xf0,0x89,0x05,0x69,0x01,0xb0,0x99,0xd7,0x12, + 0x37,0x3c,0xd7,0x1c,0x09,0x71,0x17,0x1c,0x15,0x72,0x27,0x1c,0x83,0x62,0x03,0x1c, + 0x03,0xcb,0x57,0xbb,0x8b,0x3e,0x67,0xbb,0xc4,0x62,0x04,0x1c,0x04,0xc9,0x77,0xb9, + 0x89,0x3e,0x87,0xb9,0x2a,0xf0,0x00,0x00,0x8a,0x9e,0x00,0x00,0x83,0x00,0x00,0x00, + 0xab,0x00,0x00,0x00,0x3e,0x84,0x00,0x00,0x70,0x05,0x00,0x00,0x98,0x05,0x00,0x00, + 0x1c,0x9e,0x00,0x00,0xa3,0x00,0x00,0x00,0x1c,0x02,0x00,0x00,0x4a,0xa0,0x00,0x00, + 0x4b,0xa0,0x00,0x00,0x62,0xa6,0x00,0x00,0x76,0xa6,0x00,0x00,0x18,0x02,0x00,0x00, + 0xc0,0x01,0x00,0x00,0xc0,0x0c,0x00,0x00,0xa4,0x00,0x00,0x00,0xa5,0x00,0x00,0x00, + 0xd0,0x83,0x00,0x00,0x07,0x01,0x51,0x0c,0x0a,0xef,0x0d,0x20,0x4d,0x01,0xa9,0x75, + 0x05,0xa7,0x7d,0x0c,0xe5,0xee,0xa8,0x77,0x07,0x87,0xa8,0x76,0x67,0x1c,0x07,0xa5, + 0x16,0x60,0x56,0x0c,0x92,0xe0,0x56,0x60,0x56,0x0c,0x01,0xe0,0x07,0xb6,0x0c,0x60, + 0xa4,0x78,0xa4,0x7a,0xa5,0x79,0x85,0xf0,0xc3,0x12,0x33,0x3c,0xc3,0x1c,0x83,0x1c, + 0xa3,0x77,0x37,0x1c,0x07,0xad,0x87,0x12,0xd7,0x1c,0xa1,0x76,0x76,0x1c,0x06,0xa6, + 0x16,0x2a,0x21,0xe0,0xa7,0x12,0xd7,0x1c,0x06,0x60,0x07,0xb6,0x0e,0x60,0x3b,0x12, + 0x9b,0x77,0x7b,0x1c,0x10,0xf0,0xe2,0x12,0x32,0x3c,0xe2,0x1c,0xd7,0x12,0xd7,0x1c, + 0xd7,0x1c,0x76,0x12,0x46,0x3c,0x76,0x05,0x62,0x1c,0x92,0x1c,0xb3,0x12,0x94,0x60, + 0x95,0x7f,0x0e,0x20,0x4e,0x01,0x8c,0x71,0x01,0x87,0x8c,0x72,0x27,0x1c,0x07,0xa7, + 0x7e,0x0c,0xe9,0xef,0x54,0xf0,0x46,0x2a,0x52,0xe8,0x8f,0x74,0x47,0x1c,0x07,0xa7, + 0x17,0x2a,0x4d,0xe8,0xa7,0x12,0xd7,0x1c,0x07,0xa7,0xa0,0x97,0x72,0x12,0x32,0x3c, + 0x72,0x1c,0xd7,0x12,0xd7,0x1c,0xd7,0x1c,0x7e,0x12,0x4e,0x3c,0x7e,0x05,0xe2,0x1c, + 0x92,0x1c,0x82,0x75,0x53,0x1c,0x94,0x60,0x83,0x7f,0x7b,0x76,0x06,0x87,0x7b,0x7b, + 0xb7,0x1c,0x07,0xab,0x06,0x60,0xb0,0x96,0x62,0x12,0x64,0x12,0x10,0xf0,0x67,0x12, + 0x37,0x3c,0x67,0x1c,0xe7,0x1c,0x97,0x1c,0x17,0xa3,0x27,0xa5,0x85,0x3c,0x35,0x1e, + 0x52,0x1c,0x37,0xa5,0x47,0xa7,0x87,0x3c,0x57,0x1e,0x74,0x1c,0x06,0x20,0x06,0x01, + 0xb1,0x0c,0xed,0xef,0xb0,0x94,0xce,0x12,0x3e,0x3c,0xce,0x1c,0x8e,0x1c,0x73,0x71, + 0x1e,0x1c,0xb3,0x12,0x73,0x7f,0x62,0x01,0x5e,0xb2,0x82,0x3e,0x6e,0xb2,0xb0,0x82, + 0xb3,0x12,0x6f,0x7f,0x62,0x01,0x7e,0xb2,0x82,0x3e,0x8e,0xb2,0xa0,0x87,0x07,0x20, + 0x47,0x01,0xad,0x1c,0x0d,0xb7,0xb7,0x0c,0x02,0xe8,0x02,0x60,0x0d,0xb2,0x0c,0x20, + 0x4c,0x01,0x5c,0x73,0x03,0xa7,0x7c,0x0c,0x77,0xef,0x5b,0x77,0x07,0x87,0x65,0x74, + 0x47,0x1c,0x07,0xa7,0x07,0x2a,0x02,0xe9,0x5a,0x7a,0x56,0x77,0x07,0xa1,0x11,0x2a, + 0xfd,0xe0,0x61,0x77,0x07,0xa9,0x61,0x76,0x62,0x77,0x07,0xa7,0x62,0x75,0x05,0xab, + 0x8b,0x3c,0x7b,0x1e,0x61,0x77,0x07,0xa7,0x61,0x75,0x05,0xac,0x8c,0x3c,0x7c,0x1e, + 0x60,0x77,0x07,0xa7,0x60,0x75,0x05,0xad,0x8d,0x3c,0x7d,0x1e,0x5f,0x77,0x07,0xa7, + 0x5f,0x75,0x05,0xae,0x8e,0x3c,0x7e,0x1e,0xa6,0xa5,0xb6,0xa7,0x87,0x3c,0x57,0x1e, + 0x5c,0x75,0x75,0x1c,0xa0,0x95,0x5b,0x78,0x87,0x1c,0x67,0x01,0xb0,0x97,0xc6,0xa5, + 0xd6,0xa7,0x87,0x3c,0x57,0x1e,0x56,0x72,0x72,0x1c,0xc0,0x92,0x87,0x1c,0x67,0x01, + 0xd0,0x97,0x55,0x77,0x07,0xa7,0x55,0x76,0x06,0xa3,0x83,0x3c,0x73,0x1e,0x54,0x77, + 0x07,0xa7,0x54,0x76,0x06,0xa4,0x84,0x3c,0x74,0x1e,0x53,0x77,0x07,0xa8,0x67,0x64, + 0xf1,0x11,0x78,0x03,0xf9,0x11,0xa2,0x12,0x82,0x1c,0x50,0x75,0x52,0x1c,0x06,0x60, + 0xf1,0x11,0x79,0x03,0xf9,0x11,0x02,0xa7,0x27,0x2a,0xa2,0xe0,0x67,0x12,0xa7,0x1c, + 0x34,0x75,0x75,0x1c,0x05,0xa5,0x15,0x24,0x45,0x01,0x51,0x0c,0x99,0xe8,0x48,0x75, + 0x57,0x1c,0x07,0xa7,0x07,0x24,0x47,0x01,0x71,0x0c,0x92,0xe8,0x67,0x12,0x37,0x3c, + 0x67,0x05,0x87,0x1c,0xa7,0x1c,0x43,0x75,0x57,0x1c,0x37,0xaf,0x47,0xa5,0x85,0x3c, + 0xf5,0x1e,0xb5,0x0c,0x0a,0xe8,0x5c,0x0c,0x08,0xe8,0x57,0xaf,0x67,0xa7,0x87,0x3c, + 0xf7,0x1e,0xd7,0x0c,0x02,0xe8,0x7e,0x0c,0x7b,0xe0,0x55,0x1c,0x6f,0x12,0x3f,0x3c, + 0x6f,0x05,0xf7,0x12,0x97,0x1c,0xa7,0x1c,0x37,0x73,0x37,0x1c,0x37,0xa3,0x47,0xa4, + 0x84,0x3c,0x34,0x1e,0x45,0x05,0x65,0x01,0x8f,0x1c,0xaf,0x1c,0x32,0x74,0x4f,0x1c, + 0x5f,0xa3,0x6f,0xa4,0x84,0x3c,0x34,0x1e,0x44,0x1c,0x57,0xa3,0x67,0xa7,0x87,0x3c, + 0x37,0x1e,0x74,0x05,0x64,0x01,0x57,0x12,0x77,0x01,0xf3,0x67,0x73,0x0d,0x04,0xe8, + 0xa0,0x83,0x37,0x0d,0x03,0xe8,0x03,0xf0,0x75,0x32,0x01,0xf0,0xb0,0x85,0x47,0x12, + 0x77,0x01,0xf3,0x67,0x73,0x0d,0x04,0xe8,0xc0,0x83,0x37,0x0d,0x45,0xe8,0x45,0xf0, + 0x74,0x32,0x43,0xf0,0xa5,0xa0,0x00,0x00,0x1c,0x9e,0x00,0x00,0x21,0x01,0x00,0x00, + 0x8a,0x9e,0x00,0x00,0x8c,0xa6,0x00,0x00,0x96,0xa6,0x00,0x00,0x1c,0x02,0x00,0x00, + 0x70,0x05,0x00,0x00,0x8c,0x82,0x00,0x00,0x98,0x05,0x00,0x00,0x18,0x02,0x00,0x00, + 0x3e,0x84,0x00,0x00,0xa6,0x00,0x00,0x00,0xe4,0xa3,0x00,0x00,0x20,0x9e,0x00,0x00, + 0x36,0x9e,0x00,0x00,0x37,0x9e,0x00,0x00,0x3a,0x9e,0x00,0x00,0x3b,0x9e,0x00,0x00, + 0x38,0x9e,0x00,0x00,0x39,0x9e,0x00,0x00,0x3c,0x9e,0x00,0x00,0x3d,0x9e,0x00,0x00, + 0x81,0xff,0xff,0xff,0x80,0xff,0xff,0xff,0xa7,0xa0,0x00,0x00,0xa8,0xa0,0x00,0x00, + 0xa9,0xa0,0x00,0x00,0xaa,0xa0,0x00,0x00,0xe5,0xa3,0x00,0x00,0x02,0x03,0x00,0x00, + 0x8e,0x05,0x00,0x00,0x00,0x03,0x00,0x00,0xd0,0x84,0x53,0x12,0x63,0x01,0x64,0x01, + 0x06,0x20,0x62,0x20,0xa6,0x2a,0x57,0xe7,0x9f,0x77,0x07,0xb3,0x83,0x3e,0x9e,0x77, + 0x07,0xb3,0x9e,0x77,0x07,0xb4,0x84,0x3e,0x9e,0x77,0x07,0xb4,0x9e,0x77,0x07,0xa6, + 0x9e,0x77,0x07,0xa5,0x17,0x60,0x57,0x0c,0x9d,0x77,0x07,0x87,0x03,0xe0,0x9c,0x74, + 0x47,0x1c,0x02,0xf0,0x9c,0x75,0x57,0x1c,0x07,0xab,0x1b,0x3c,0x0a,0x60,0xac,0x12, + 0x9a,0x7d,0x68,0x64,0xf1,0x11,0x68,0x03,0xf9,0x11,0xb9,0x12,0x8a,0xf0,0xc7,0x12, + 0x37,0x3c,0xc7,0x1c,0xd7,0x1c,0x95,0x76,0x67,0x1c,0x07,0xab,0xd7,0x12,0xb7,0x1c, + 0x94,0x76,0x76,0x1c,0x06,0xa6,0x26,0x2a,0x74,0xe0,0x92,0x77,0x07,0xa5,0x92,0x77, + 0x06,0x60,0x2e,0xf0,0x74,0x12,0x87,0x20,0x04,0xa4,0xb4,0x0f,0x27,0xe0,0xb7,0x12, + 0x37,0x3c,0xb7,0x05,0x87,0x1c,0xd7,0x1c,0x8d,0x71,0x17,0x1c,0x37,0xa5,0x47,0xa2, + 0x82,0x3c,0x52,0x1e,0x6e,0x12,0x3e,0x3c,0x6e,0x1c,0xde,0x1c,0x89,0x73,0x3e,0x1c, + 0x2e,0xa5,0x3e,0xa6,0x86,0x3c,0x56,0x1e,0x62,0x05,0x57,0xa6,0x67,0xa3,0x83,0x3c, + 0x63,0x1e,0x4e,0xa6,0x5e,0xa7,0x87,0x3c,0x67,0x1e,0x73,0x05,0x72,0x01,0x73,0x01, + 0x81,0x7f,0x92,0x0c,0xc7,0x12,0x37,0x3c,0x06,0xe8,0x3a,0xf0,0x06,0x20,0x46,0x01, + 0x56,0x0f,0xd0,0xe7,0x44,0xf0,0xc7,0x1c,0xd7,0x1c,0x74,0x76,0x76,0x1c,0x06,0xa6, + 0xd6,0x1c,0x79,0x74,0x46,0x1c,0x06,0xa4,0x6d,0x75,0x05,0x85,0x78,0x73,0x53,0x1c, + 0x03,0xa3,0x34,0x0c,0x77,0x71,0x15,0x1c,0x08,0xe0,0x04,0x20,0x06,0xb4,0x05,0xa6, + 0x26,0x2a,0x2d,0xe0,0x74,0x72,0x27,0x1c,0x0c,0xf0,0x0a,0x20,0x4a,0x01,0xdb,0x1c, + 0x68,0x73,0x3b,0x1c,0x36,0x60,0x0b,0xb6,0x05,0xa6,0x06,0x2a,0x20,0xe8,0x6d,0x74, + 0x47,0x1c,0x2e,0xa5,0x3e,0xa6,0x86,0x3c,0x56,0x1e,0x57,0xb6,0x86,0x3e,0x67,0xb6, + 0x4e,0xa5,0x5e,0xa6,0x86,0x3c,0x56,0x1e,0x77,0xb6,0x86,0x3e,0x87,0xb6,0x0f,0xf0, + 0xc7,0x1c,0xd7,0x1c,0x5a,0x75,0x57,0x1c,0x07,0xa7,0xd7,0x1c,0x5f,0x76,0x67,0x1c, + 0x04,0xf0,0x16,0x2a,0x04,0xe0,0x5c,0x7b,0xb7,0x1c,0x06,0x60,0x07,0xb6,0x0c,0x20, + 0x4c,0x01,0x4d,0x71,0x01,0xa7,0x7c,0x0c,0x72,0xef,0x0a,0x2a,0x08,0xe8,0x5a,0x77, + 0x07,0xa6,0x5a,0x77,0x07,0xa7,0x87,0x3c,0x67,0x1e,0x7a,0x0c,0x2a,0x00,0x58,0x77, + 0x07,0xba,0x46,0x77,0x07,0x87,0x57,0x76,0x76,0x1c,0x06,0xa6,0x06,0x2a,0x05,0xe0, + 0x56,0x77,0x07,0xa6,0xf2,0x67,0x26,0x16,0xd4,0xf0,0x4f,0x76,0x06,0xa6,0x4f,0x75, + 0x05,0xa5,0x85,0x3c,0x65,0x1e,0x05,0x01,0x04,0x60,0x3f,0x7c,0x50,0x7d,0x7d,0x1c, + 0x50,0x7e,0x7e,0x1c,0x50,0x73,0x73,0x1c,0x3f,0x12,0x4f,0x72,0x72,0x1c,0x16,0xf0, + 0x86,0x65,0x46,0x1c,0x66,0x1c,0xc6,0x1c,0x86,0xa3,0x96,0xa6,0x0d,0xab,0xb3,0x0c, + 0x0b,0xe8,0x0e,0xab,0x3b,0x0c,0x08,0xe8,0x0f,0xa3,0x36,0x0c,0x05,0xe8,0x02,0xa3, + 0x63,0x0c,0x02,0xe8,0x01,0x24,0x41,0x01,0x04,0x20,0x44,0x01,0x54,0x0c,0xe8,0xef, + 0x15,0x60,0x15,0x0c,0x33,0xe8,0x3d,0x76,0x76,0x1c,0x06,0xa4,0x3d,0x76,0x76,0x1c, + 0x06,0xac,0x05,0x60,0x3c,0x7d,0x7d,0x1c,0x3c,0x76,0x76,0x1c,0x6f,0x12,0x3b,0x7e, + 0xa2,0x61,0x16,0xf0,0x0d,0xa3,0x0f,0xaa,0x4b,0x12,0xf1,0x11,0x2b,0x03,0xf9,0x11, + 0x0b,0xf0,0xb6,0x12,0x36,0x1c,0x66,0x1c,0xe6,0x1c,0x06,0xc6,0x76,0x01,0x06,0x22, + 0x01,0xe0,0x65,0x1c,0x03,0x20,0x43,0x01,0x3a,0x0c,0xf3,0xe7,0x04,0x20,0x44,0x01, + 0x4c,0x0c,0xe8,0xe7,0x11,0x2a,0x05,0xe0,0x66,0x67,0x76,0x1c,0x06,0xa6,0x66,0x1c, + 0x03,0xf0,0x2b,0x76,0x76,0x1c,0x06,0xa6,0x56,0x0c,0x35,0x00,0x2a,0x76,0x06,0xa6, + 0x76,0x36,0x29,0x76,0x59,0xe8,0x05,0x2a,0x02,0xe8,0x07,0x60,0x53,0xf0,0x06,0xa5, + 0x27,0x78,0x87,0x1c,0x07,0xa7,0x57,0x0c,0x4b,0xe0,0x1b,0x77,0x07,0xa6,0xf9,0x67, + 0x96,0x16,0x56,0xf0,0xa7,0xa0,0x00,0x00,0xa8,0xa0,0x00,0x00,0xa9,0xa0,0x00,0x00, + 0xaa,0xa0,0x00,0x00,0xe5,0xa3,0x00,0x00,0xa5,0xa0,0x00,0x00,0x1c,0x9e,0x00,0x00, + 0xb3,0x00,0x00,0x00,0xb2,0x00,0x00,0x00,0x8a,0x9e,0x00,0x00,0x1c,0x02,0x00,0x00, + 0x70,0x05,0x00,0x00,0x4a,0xa0,0x00,0x00,0x4b,0xa0,0x00,0x00,0x00,0x03,0x00,0x00, + 0xc0,0x01,0x00,0x00,0xc0,0x0c,0x00,0x00,0xa7,0x05,0x00,0x00,0xb1,0x00,0x00,0x00, + 0xb0,0x00,0x00,0x00,0x18,0x02,0x00,0x00,0x40,0x9f,0x00,0x00,0x41,0x9f,0x00,0x00, + 0x3b,0xa4,0x00,0x00,0x11,0x01,0x00,0x00,0x2c,0xa4,0x00,0x00,0x12,0x01,0x00,0x00, + 0x13,0x01,0x00,0x00,0x14,0x01,0x00,0x00,0x15,0x01,0x00,0x00,0x00,0xe0,0x02,0x00, + 0x17,0x01,0x00,0x00,0x2d,0xa4,0x00,0x00,0x58,0xa8,0x00,0x00,0x18,0x01,0x00,0x00, + 0x57,0x12,0x07,0x20,0x06,0xb7,0x0f,0xf0,0x05,0x2a,0x0c,0xe8,0x06,0xa5,0xa4,0x7b, + 0xb7,0x1c,0x07,0xa7,0x57,0x0c,0xf4,0xe7,0xa3,0x77,0x07,0xa6,0xa3,0x7c,0xc6,0x1e, + 0x07,0xb6,0x01,0xf0,0x06,0xb5,0x9f,0x77,0x07,0xa7,0x77,0x36,0x03,0xe8,0x16,0x60, + 0x9f,0x77,0x07,0xb6,0x9f,0x7e,0x0e,0xa7,0x07,0x2a,0x42,0xe8,0x9e,0x7f,0x9e,0x77, + 0x07,0xa2,0x17,0xa3,0x9e,0x74,0x85,0x61,0x9e,0x7f,0x9e,0x77,0x07,0xb2,0x12,0x01, + 0x9e,0x77,0x07,0xb1,0x22,0x01,0x9d,0x77,0x07,0xb1,0x82,0x3f,0x9d,0x77,0x07,0xb2, + 0x9d,0x77,0x07,0xa6,0x9d,0x77,0x07,0xa7,0x87,0x3c,0x67,0x1e,0x9c,0x76,0x06,0xa6, + 0x06,0x3d,0x76,0x1e,0x9b,0x77,0x07,0xa7,0x87,0x3d,0x67,0x1e,0x07,0x2a,0x1a,0xe0, + 0x99,0x77,0x07,0xa6,0x99,0x77,0x07,0xa7,0x87,0x3c,0x67,0x1e,0x98,0x76,0x06,0xa6, + 0x06,0x3d,0x76,0x1e,0x97,0x77,0x07,0xa7,0x87,0x3d,0x67,0x1e,0x07,0x2a,0x0a,0xe0, + 0x95,0x75,0x05,0xa6,0x06,0x20,0x46,0x01,0x05,0xb6,0x25,0x60,0x65,0x0c,0x05,0xe0, + 0x0e,0xb7,0x03,0xf0,0x06,0x60,0x8f,0x77,0x07,0xb6,0x16,0x60,0x7c,0x77,0x07,0xb6, + 0x8e,0x76,0x06,0x87,0x07,0x20,0x06,0x97,0x8d,0x7e,0x0e,0xa7,0x07,0x2a,0x7f,0xe0, + 0x81,0x77,0x07,0xa6,0x81,0x77,0x07,0xa7,0x87,0x3c,0x67,0x1e,0x80,0x76,0x06,0xa6, + 0x06,0x3d,0x76,0x1e,0x7f,0x77,0x07,0xa7,0x87,0x3d,0x67,0x1e,0x07,0x2a,0x10,0xe0, + 0x7d,0x77,0x07,0xa7,0x7d,0x76,0x06,0xa6,0x86,0x3c,0x76,0x1e,0x7c,0x77,0x07,0xa7, + 0x07,0x3d,0x67,0x1e,0x7b,0x76,0x06,0xad,0x8d,0x3d,0x7d,0x1e,0x0d,0x2a,0x05,0xe8, + 0x69,0x7f,0x06,0x60,0x7a,0x77,0x17,0xb6,0x23,0xf3,0x1e,0xa7,0x26,0x60,0x76,0x0c, + 0x04,0xe8,0x07,0x20,0x1e,0xb7,0x63,0x7f,0x1b,0xf3,0x56,0x60,0x76,0x0c,0x0f,0xe8, + 0x07,0x20,0x1e,0xb7,0x17,0x60,0xae,0xb7,0xbe,0xbd,0xce,0xbd,0x71,0x77,0x07,0x87, + 0x71,0x71,0x17,0x1c,0x07,0xa7,0xde,0xb7,0x07,0x60,0xee,0xb7,0x09,0xf3,0x5a,0x77, + 0x07,0xa2,0x17,0xa3,0x5a,0x74,0x85,0x61,0x5a,0x7f,0x86,0x2c,0x26,0x16,0x59,0x77, + 0x07,0xb6,0x12,0x01,0x17,0x12,0x58,0x75,0x05,0xb1,0x22,0x01,0x58,0x75,0x05,0xb1, + 0x82,0x3f,0x57,0x75,0x05,0xb2,0x64,0x75,0x05,0xb6,0x64,0x75,0x05,0xb7,0x64,0x75, + 0x05,0xb1,0x64,0x75,0x05,0xb2,0x64,0x75,0x05,0xb6,0x64,0x76,0x06,0xb7,0x64,0x77, + 0x07,0xb1,0x64,0x77,0x07,0xb2,0xae,0xbd,0x64,0x76,0x06,0xa6,0x64,0x77,0x07,0xa7, + 0x87,0x3c,0x67,0x1e,0x63,0x76,0x06,0xa6,0x06,0x3d,0x76,0x1e,0x62,0x77,0x07,0xa7, + 0x87,0x3d,0x67,0x1e,0x4e,0xb7,0x17,0x01,0x5e,0xb1,0x27,0x01,0x6e,0xb1,0x87,0x3f, + 0x7e,0xb7,0x1e,0xbd,0x17,0x60,0x0e,0xb7,0x5c,0x77,0x67,0xbd,0xc9,0xf2,0x4c,0x76, + 0x06,0x8d,0x5a,0x76,0xd6,0x1c,0x06,0xa6,0x06,0x2a,0x03,0xe0,0x27,0x60,0x0e,0xb7, + 0x31,0xf3,0x16,0x2a,0xdd,0xe1,0x17,0x2a,0xb4,0xe2,0x07,0x60,0xae,0xb7,0x54,0x77, + 0xd7,0x1c,0x07,0xa6,0x06,0x2a,0x50,0x77,0x03,0xe0,0x26,0x60,0x67,0xb6,0xb1,0xf1, + 0x16,0x2a,0x0a,0xe1,0x67,0xa6,0x06,0x2a,0xec,0xe0,0x4e,0x77,0x07,0xa7,0x07,0x2a, + 0x07,0xe0,0x4d,0x77,0x07,0xa7,0x17,0x2a,0x3c,0xe0,0x4c,0x76,0x06,0xb7,0x3c,0xf0, + 0x17,0x2a,0x37,0xe0,0x49,0x77,0x07,0xa7,0x17,0x2a,0x36,0xe8,0x49,0x77,0x07,0xa6, + 0x06,0x2a,0x2f,0xe0,0x46,0x77,0x07,0xa5,0x15,0x2a,0x2d,0xe0,0x46,0x77,0x07,0xa7, + 0x66,0x64,0xf1,0x11,0x67,0x03,0xf9,0x11,0x44,0x76,0x67,0x1c,0x44,0x72,0x27,0x1c, + 0x37,0xa6,0x47,0xa2,0x82,0x3c,0x62,0x1e,0x42,0x76,0x06,0xa5,0x42,0x76,0x06,0xa6, + 0x86,0x3c,0x56,0x1e,0x62,0x05,0x57,0xa6,0x67,0xa3,0x83,0x3c,0x63,0x1e,0x3e,0x77, + 0x07,0xa6,0x3e,0x77,0x07,0xa7,0x87,0x3c,0x67,0x1e,0x73,0x05,0x72,0x01,0x73,0x01, + 0x3c,0x7f,0x72,0x01,0x97,0x32,0x27,0x0d,0x07,0xe8,0x26,0x60,0x2b,0x77,0x67,0xb6, + 0x03,0xf0,0x06,0x60,0x2e,0x77,0x07,0xb6,0x1a,0x77,0x07,0x85,0x36,0x77,0x6c,0xf0, + 0x18,0x01,0x00,0x00,0x2c,0xa4,0x00,0x00,0x80,0xff,0xff,0xff,0x62,0xa4,0x00,0x00, + 0x31,0xaa,0x00,0x00,0xac,0x2c,0x00,0x00,0x20,0x9e,0x00,0x00,0x00,0x80,0x02,0x00, + 0x58,0x3e,0x00,0x00,0x65,0xa4,0x00,0x00,0x66,0xa4,0x00,0x00,0x67,0xa4,0x00,0x00, + 0x68,0xa4,0x00,0x00,0x46,0xa4,0x00,0x00,0x47,0xa4,0x00,0x00,0x48,0xa4,0x00,0x00, + 0x49,0xa4,0x00,0x00,0x4a,0xa4,0x00,0x00,0x4b,0xa4,0x00,0x00,0x4c,0xa4,0x00,0x00, + 0x4d,0xa4,0x00,0x00,0x59,0xa8,0x00,0x00,0x5c,0xa8,0x00,0x00,0x66,0x9e,0x00,0x00, + 0x1c,0x9e,0x00,0x00,0xba,0x00,0x00,0x00,0x69,0xa4,0x00,0x00,0x6a,0xa4,0x00,0x00, + 0x6b,0xa4,0x00,0x00,0x6c,0xa4,0x00,0x00,0x6d,0xa4,0x00,0x00,0x6e,0xa4,0x00,0x00, + 0x6f,0xa4,0x00,0x00,0x70,0xa4,0x00,0x00,0x37,0xaa,0x00,0x00,0x38,0xaa,0x00,0x00, + 0x39,0xaa,0x00,0x00,0x3a,0xaa,0x00,0x00,0x20,0xaa,0x00,0x00,0xb4,0x00,0x00,0x00, + 0xbc,0x00,0x00,0x00,0x4a,0xa0,0x00,0x00,0xa5,0xa0,0x00,0x00,0x60,0xa8,0x00,0x00, + 0xef,0x9f,0x00,0x00,0xe4,0xa3,0x00,0x00,0x8a,0x9e,0x00,0x00,0x00,0x03,0x00,0x00, + 0x01,0xa1,0x00,0x00,0x02,0xa1,0x00,0x00,0x03,0xa1,0x00,0x00,0x04,0xa1,0x00,0x00, + 0xc0,0x0c,0x00,0x00,0x42,0xa4,0x00,0x00,0x07,0xa6,0xb7,0x77,0x07,0xa7,0x87,0x3c, + 0x67,0x1e,0x56,0x67,0x56,0x1c,0x06,0xa6,0xb5,0x73,0x35,0x1c,0x05,0xa5,0x56,0x1b, + 0x76,0x0d,0xe7,0xe8,0xb3,0x77,0x07,0xa7,0xb3,0x76,0x06,0xa6,0x86,0x3c,0x76,0x1e, + 0xb2,0x77,0x07,0xa7,0x07,0x3d,0x67,0x1e,0xb1,0x76,0x06,0xa6,0x86,0x3d,0x76,0x1e, + 0xb0,0x77,0x07,0xa5,0xb0,0x77,0x07,0xa7,0x87,0x3c,0x57,0x1e,0xaf,0x75,0x05,0xa5, + 0x05,0x3d,0x75,0x1e,0xae,0x77,0x07,0xa7,0x87,0x3d,0x57,0x1e,0x67,0x0c,0x06,0xe0, + 0x06,0x60,0xab,0x77,0x17,0xb6,0x16,0x60,0xab,0x77,0x67,0xb6,0x06,0x60,0xaa,0x77, + 0x19,0xf0,0x67,0xa7,0x17,0x2a,0xbd,0xe0,0x1e,0xa6,0x06,0x20,0x46,0x01,0x1e,0xb6, + 0xa7,0x74,0x4d,0x1c,0x0d,0xa7,0x17,0x3e,0x67,0x0c,0x04,0xe8,0xa5,0x77,0x07,0xa7, + 0x07,0x2a,0x06,0xe8,0x16,0x60,0xa3,0x77,0x07,0xb6,0x06,0x60,0x9e,0x77,0x67,0xb6, + 0x16,0x60,0xa1,0x77,0x07,0xb6,0xa5,0xf0,0x26,0x2a,0xa3,0xe0,0x67,0xa6,0x06,0x2a, + 0x34,0xe0,0x9e,0x77,0x07,0xa6,0x8c,0x77,0x07,0xa7,0x87,0x3c,0x67,0x1e,0x56,0x67, + 0xd6,0x1c,0x06,0xa6,0x8a,0x75,0x5d,0x1c,0x0d,0xa5,0x56,0x1b,0x76,0x0d,0x65,0xe8, + 0x88,0x77,0x07,0xa7,0x88,0x76,0x06,0xa6,0x86,0x3c,0x76,0x1e,0x87,0x77,0x07,0xa7, + 0x07,0x3d,0x67,0x1e,0x86,0x76,0x06,0xa6,0x86,0x3d,0x76,0x1e,0x85,0x77,0x07,0xa5, + 0x85,0x77,0x07,0xa7,0x87,0x3c,0x57,0x1e,0x84,0x75,0x05,0xa5,0x05,0x3d,0x75,0x1e, + 0x83,0x77,0x07,0xa7,0x87,0x3d,0x57,0x1e,0x67,0x0c,0x47,0xe0,0x06,0x60,0x80,0x77, + 0x17,0xb6,0x16,0x60,0x80,0x77,0x67,0xb6,0x40,0xf0,0x67,0xa7,0x17,0x2a,0x3d,0xe0, + 0x1e,0xa6,0x06,0x20,0x46,0x01,0x1e,0xb6,0x7d,0x77,0xd7,0x1c,0x07,0xa7,0x17,0x3e, + 0x67,0x0c,0x04,0xe8,0x7b,0x77,0x07,0xa7,0x07,0x2a,0x2c,0xe8,0x76,0x73,0x16,0x60, + 0x79,0x77,0x07,0xb6,0x7b,0x76,0x06,0xa6,0x7b,0x77,0x07,0xa7,0x87,0x3c,0x67,0x1e, + 0x7a,0x76,0x06,0xa6,0x06,0x3d,0x76,0x1e,0x79,0x77,0x07,0xa7,0x87,0x3d,0x67,0x1e, + 0x6c,0x74,0x44,0xa5,0x54,0xa6,0x86,0x3c,0x56,0x1e,0x64,0xa5,0x05,0x3d,0x65,0x1e, + 0x74,0xa6,0x86,0x3d,0x56,0x1e,0x67,0x05,0x72,0x76,0xd6,0x1c,0x06,0xa5,0x71,0x76, + 0x6d,0x1c,0x0d,0xa6,0x86,0x3c,0x56,0x1e,0x76,0x0c,0x02,0xe0,0x27,0x60,0x01,0xf0, + 0x07,0x60,0x63,0xb7,0x06,0x60,0x60,0x77,0x07,0xb6,0x5e,0x73,0x63,0xa7,0x07,0x2a, + 0x28,0xe0,0x63,0x76,0x06,0xa6,0x63,0x77,0x07,0xa7,0x87,0x3c,0x67,0x1e,0x62,0x76, + 0x06,0xa6,0x06,0x3d,0x76,0x1e,0x61,0x77,0x07,0xa7,0x87,0x3d,0x67,0x1e,0x54,0x74, + 0x44,0xa5,0x54,0xa6,0x86,0x3c,0x56,0x1e,0x64,0xa5,0x05,0x3d,0x65,0x1e,0x74,0xa6, + 0x86,0x3d,0x56,0x1e,0x67,0x05,0x5c,0x76,0x06,0x86,0x59,0x75,0x65,0x1c,0x05,0xa5, + 0x59,0x78,0x86,0x1c,0x06,0xa6,0x86,0x3c,0x56,0x1e,0x76,0x0c,0x02,0xe0,0x27,0x60, + 0x63,0xb7,0x48,0x75,0x65,0xa5,0x25,0x2a,0xfb,0xe0,0x45,0x76,0x07,0x60,0x16,0xb7, + 0x36,0xb7,0x4b,0x74,0x04,0xa4,0x4b,0x77,0x07,0xa7,0x87,0x3c,0x47,0x1e,0x4a,0x74, + 0x04,0xa4,0x04,0x3d,0x74,0x1e,0x49,0x77,0x07,0xa7,0x87,0x3d,0x47,0x1e,0x46,0xb7, + 0x17,0x01,0x56,0xb1,0x27,0x01,0x66,0xb1,0x87,0x3f,0x76,0xb7,0x06,0xb5,0xe0,0xf0, + 0x26,0x2a,0xdb,0xe0,0x2e,0xa6,0x06,0x2a,0xda,0xe8,0x17,0x2a,0xd2,0xe0,0x43,0x7c, + 0x0c,0xa2,0x5d,0xa3,0x43,0x7b,0x00,0x9b,0x34,0x60,0x42,0x75,0x43,0x76,0x07,0x60, + 0x43,0x7f,0x0c,0xa2,0x5d,0xa3,0x49,0x67,0xd9,0x1c,0x09,0xa7,0x0e,0x60,0x00,0x9e, + 0xc4,0x60,0xb5,0x12,0xe6,0x12,0x3d,0x7f,0x3e,0x7a,0x0a,0x88,0xb0,0x98,0x0c,0xa2, + 0x5d,0xa3,0x3c,0x78,0xd8,0x1c,0x08,0xa6,0x3c,0x71,0xd1,0x1c,0xa0,0x91,0x01,0xa7, + 0x87,0x3c,0x67,0x1e,0x07,0x3d,0x00,0x9e,0xd4,0x60,0xb5,0x12,0xe6,0x12,0x07,0x3b, + 0x33,0x7f,0x0a,0x82,0xc0,0x92,0x0c,0xa2,0x1c,0xa3,0x34,0x74,0x85,0x61,0x34,0x7f, + 0x0c,0xa2,0x5d,0xa3,0x09,0xa7,0x00,0x9e,0xc4,0x60,0xb5,0x12,0xe6,0x12,0x2b,0x7f, + 0x0a,0x89,0x0c,0xa2,0x5d,0xa3,0x08,0xa6,0xa0,0x88,0x08,0xa7,0x87,0x3c,0x67,0x1e, + 0x07,0x3d,0x00,0x9e,0xd4,0x60,0xb5,0x12,0xe6,0x12,0x07,0x3b,0x24,0x7f,0x0a,0x87, + 0xb0,0x8b,0x0b,0x2a,0x03,0xe0,0xc0,0x8c,0x0c,0x2a,0x04,0xe8,0x09,0x2a,0xd3,0xe0, + 0x07,0x2a,0xd1,0xe0,0x0b,0x7e,0x46,0xf0,0x43,0xa4,0x00,0x00,0xbd,0x00,0x00,0x00, + 0x56,0xa4,0x00,0x00,0x57,0xa4,0x00,0x00,0x58,0xa4,0x00,0x00,0x59,0xa4,0x00,0x00, + 0x52,0xa4,0x00,0x00,0x53,0xa4,0x00,0x00,0x54,0xa4,0x00,0x00,0x55,0xa4,0x00,0x00, + 0x66,0x9e,0x00,0x00,0x20,0xaa,0x00,0x00,0xa5,0xa0,0x00,0x00,0xb9,0x00,0x00,0x00, + 0x72,0xa4,0x00,0x00,0x31,0xaa,0x00,0x00,0x62,0xa4,0x00,0x00,0x42,0xa4,0x00,0x00, + 0x37,0xaa,0x00,0x00,0x38,0xaa,0x00,0x00,0x39,0xaa,0x00,0x00,0x3a,0xaa,0x00,0x00, + 0xbe,0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x1c,0x9e,0x00,0x00,0x20,0x9e,0x00,0x00, + 0x00,0x00,0x03,0x18,0x00,0x00,0x06,0x18,0x00,0x00,0x02,0x18,0xb4,0x26,0x00,0x00, + 0x34,0x0a,0x04,0x00,0xb5,0x00,0x00,0x00,0xb6,0x00,0x00,0x00,0x00,0xa0,0x02,0x00, + 0x48,0x2a,0x00,0x00,0x1e,0xa7,0x07,0x20,0x47,0x01,0x1e,0xb7,0x2d,0x60,0x7d,0x0c, + 0x37,0xe0,0x07,0x60,0x3e,0xb7,0x1e,0xb7,0x56,0x7f,0x56,0x76,0x06,0xa6,0x56,0x77, + 0x07,0xa7,0x87,0x3c,0x67,0x1e,0x55,0x76,0x06,0xa6,0x06,0x3d,0x76,0x1e,0x54,0x77, + 0x07,0xa7,0x87,0x3d,0x67,0x1e,0x4e,0xb7,0x17,0x01,0x5e,0xb1,0x27,0x01,0x6e,0xb1, + 0x87,0x3f,0x7e,0xb7,0x0e,0xbd,0x1c,0xf0,0x37,0xbf,0x0c,0xac,0x0e,0xa6,0x86,0x3c, + 0xc6,0x1e,0x02,0xa5,0x05,0x3d,0x65,0x1e,0x03,0xa6,0x86,0x3d,0x56,0x1e,0x47,0xb6, + 0x16,0x01,0x57,0xb1,0x26,0x01,0x67,0xb1,0x86,0x3f,0x77,0xb6,0x26,0x60,0x07,0xb6, + 0x07,0xf0,0x27,0x2a,0x05,0xe0,0x43,0x7f,0x03,0xf0,0x36,0x2a,0x01,0xe0,0x42,0x7f, + 0x43,0x76,0xd6,0xa5,0xe6,0xa7,0x87,0x3c,0x57,0x1e,0x7f,0x12,0x6f,0x01,0xa6,0xa5, + 0x05,0x2a,0x68,0xe8,0x3f,0x75,0x05,0x82,0x3f,0x75,0x25,0x1c,0x05,0xa4,0x04,0x2a, + 0x61,0xe0,0x3d,0x75,0x05,0xc3,0x03,0x20,0x63,0x01,0x05,0xd3,0xb6,0xae,0xc6,0xa6, + 0x86,0x3c,0xe6,0x1e,0x63,0x0c,0x56,0xe8,0x05,0xd4,0x42,0xaa,0x15,0x60,0x37,0x7b, + 0xac,0x61,0x7f,0x01,0x37,0x73,0xfd,0x12,0x0d,0x28,0x1c,0xf0,0x96,0x12,0x46,0x1c, + 0x66,0x1c,0xbe,0x12,0x6e,0x1c,0x0e,0xce,0xe1,0x12,0x71,0x01,0x36,0x1c,0x1f,0x0d, + 0x03,0xe8,0x06,0xce,0x7e,0x05,0x07,0xf0,0xd1,0x0d,0x03,0xe8,0x06,0xce,0x7e,0x1c, + 0x02,0xf0,0x06,0xc1,0x1e,0x14,0x06,0xde,0x04,0x20,0x44,0x01,0x48,0x0c,0xe6,0xe7, + 0x05,0x20,0x45,0x01,0x5a,0x0c,0x2e,0xe8,0x52,0xa8,0x14,0x60,0x59,0x12,0xf1,0x11, + 0xc9,0x03,0xf9,0x11,0xf3,0xf7,0x1d,0x77,0x0f,0x60,0x17,0xbf,0x16,0x7c,0x0c,0xa5, + 0x16,0x7e,0x0e,0xa6,0x86,0x3c,0x56,0x1e,0x15,0x72,0x02,0xa5,0x05,0x3d,0x65,0x1e, + 0x14,0x73,0x03,0xa6,0x86,0x3d,0x56,0x1e,0x47,0xa4,0x57,0xa5,0x85,0x3c,0x45,0x1e, + 0x67,0xa4,0x04,0x3d,0x54,0x1e,0x77,0xa5,0x85,0x3d,0x45,0x1e,0x56,0x05,0x15,0x75, + 0xd5,0x1c,0x05,0xa4,0x15,0x71,0x1d,0x1c,0x0d,0xa5,0x85,0x3c,0x45,0x1e,0x65,0x0c, + 0x73,0xef,0x8e,0xf7,0x01,0x64,0x10,0x1c,0x68,0x00,0xf0,0x21,0xcf,0x00,0x00,0x00, + 0xac,0x2c,0x00,0x00,0x37,0xaa,0x00,0x00,0x38,0xaa,0x00,0x00,0x39,0xaa,0x00,0x00, + 0x3a,0xaa,0x00,0x00,0xaa,0x41,0x00,0x00,0x94,0x3f,0x00,0x00,0x66,0x9e,0x00,0x00, + 0x1c,0x9e,0x00,0x00,0x11,0x01,0x00,0x00,0x62,0xa8,0x00,0x00,0x00,0xe0,0x02,0x00, + 0x00,0xc0,0x02,0x00,0xb7,0x00,0x00,0x00,0xb8,0x00,0x00,0x00,0x70,0x24,0x7e,0x00, + 0xf1,0x60,0x41,0x0c,0x38,0xe0,0x37,0x12,0x27,0x1e,0x37,0x2e,0x07,0x2a,0x3f,0xe0, + 0x36,0x12,0x27,0x12,0x45,0x12,0x06,0x8f,0x07,0x9f,0x16,0x8f,0x17,0x9f,0x26,0x8f, + 0x27,0x9f,0x36,0x8f,0x37,0x9f,0xf7,0x20,0xf6,0x20,0xf5,0x24,0x51,0x0c,0xf3,0xef, + 0x46,0x12,0xf6,0x24,0x46,0x3e,0x06,0x20,0x46,0x3c,0x27,0x12,0x67,0x1c,0x63,0x1c, + 0xf4,0x2e,0x3e,0x60,0x4e,0x0c,0x1e,0xe0,0x31,0x12,0x75,0x12,0x46,0x12,0x01,0x8f, + 0x05,0x9f,0x35,0x20,0x31,0x20,0x36,0x24,0x6e,0x0c,0xf9,0xef,0x45,0x12,0x35,0x24, + 0x25,0x3e,0x05,0x20,0x25,0x3c,0x34,0x2e,0x53,0x1c,0x57,0x1c,0x04,0x2a,0x05,0xe0, + 0x6e,0x00,0x70,0x20,0xcf,0x00,0x27,0x12,0x05,0xf0,0x03,0xa6,0x07,0xb6,0x07,0x20, + 0x03,0x20,0x04,0x24,0x04,0x2a,0xf9,0xe7,0x6e,0x00,0x70,0x20,0xcf,0x00,0x27,0x12, + 0xf4,0xf7,0x70,0x24,0x00,0x9f,0x37,0x60,0x72,0x0e,0x4c,0xe8,0x04,0x2a,0x47,0xe8, + 0x04,0x24,0x03,0x01,0x27,0x12,0x05,0xf0,0x46,0x12,0x06,0x24,0x04,0x2a,0x3f,0xe8, + 0x64,0x12,0x07,0xb1,0x07,0x20,0x36,0x60,0x67,0x0e,0xf6,0xe7,0x36,0x60,0x46,0x0c, + 0x2e,0xe0,0x85,0x2c,0x35,0x16,0x56,0x12,0x86,0x3c,0x56,0x1e,0x65,0x12,0x05,0x3d, + 0x65,0x1e,0xff,0x60,0x4f,0x0c,0x30,0xe0,0x76,0x12,0x41,0x12,0x06,0x95,0x16,0x95, + 0x26,0x95,0x36,0x95,0xf6,0x20,0xf1,0x24,0x1f,0x0c,0xf8,0xef,0x41,0x12,0xf1,0x24, + 0x41,0x3e,0x01,0x20,0x41,0x3c,0x71,0x1c,0xf4,0x2e,0x37,0x60,0x47,0x0c,0x1e,0xe0, + 0x16,0x12,0x47,0x12,0x3f,0x60,0x06,0x95,0x36,0x20,0x37,0x24,0x7f,0x0c,0xfb,0xef, + 0x47,0x12,0x37,0x24,0x27,0x3e,0x07,0x20,0x27,0x3c,0x34,0x2e,0x17,0x1c,0x04,0x2a, + 0x06,0xe8,0x43,0x01,0x07,0xb3,0x07,0x20,0x04,0x24,0x04,0x2a,0xfb,0xe7,0x00,0x8f, + 0x70,0x20,0xcf,0x00,0x27,0x12,0xc2,0xf7,0x71,0x12,0xe2,0xf7,0x17,0x12,0xef,0xf7, + 0x02,0x2a,0x19,0xe8,0x03,0x2a,0x02,0xe0,0x0b,0x00,0x15,0xf0,0x07,0x60,0x21,0x12, + 0x34,0x12,0xf1,0x37,0x03,0xe8,0xf1,0x33,0x01,0xf0,0x14,0x3c,0x41,0x0f,0x02,0xe8, + 0x41,0x0c,0xfb,0xe7,0x01,0xf0,0x14,0x3e,0x42,0x0c,0x01,0xe8,0x42,0x05,0x77,0x06, + 0x43,0x0c,0xf9,0xef,0x72,0x12,0xcf,0x00,0x02,0x2a,0x18,0xe8,0x03,0x2a,0x02,0xe0, + 0x0b,0x00,0x14,0xf0,0x07,0x60,0x21,0x12,0x34,0x12,0xf1,0x37,0x03,0xe8,0xf1,0x33, + 0x01,0xf0,0x14,0x3c,0x41,0x0f,0x02,0xe8,0x41,0x0c,0xfb,0xe7,0x01,0xf0,0x14,0x3e, + 0x42,0x0c,0x01,0xe8,0x42,0x05,0x77,0x06,0x43,0x0c,0xf9,0xef,0xcf,0x00,0x03,0x2a, + 0x02,0xe0,0x0b,0x00,0x16,0xf0,0x07,0x60,0x31,0x12,0x21,0x17,0xe2,0x01,0xe3,0x01, + 0x34,0x12,0x01,0xf0,0x14,0x3c,0x42,0x0c,0xfd,0xe7,0x01,0xf0,0x14,0x3e,0x42,0x0c, + 0x01,0xe8,0x42,0x05,0x77,0x06,0x43,0x0c,0xf9,0xef,0xf1,0x37,0x01,0xe8,0x07,0x28, + 0x72,0x12,0xcf,0x00,0x25,0x12,0xe2,0x01,0xe3,0x01,0x01,0x60,0x14,0x60,0x03,0x2a, + 0x01,0xe0,0x0b,0x00,0x27,0x12,0x07,0x2a,0x02,0xe0,0x02,0x60,0xcf,0x00,0x30,0x24, + 0x00,0x91,0xf6,0x61,0x71,0x12,0x61,0x0b,0x01,0x2a,0x03,0xe8,0xf6,0x29,0x67,0x12, + 0x08,0xf0,0x06,0x24,0x71,0x12,0x61,0x0b,0x01,0x2a,0xf8,0xe7,0x06,0x2a,0xf2,0xe7, + 0x07,0x62,0x00,0x81,0x30,0x20,0x74,0x1b,0x72,0x1b,0x02,0x3c,0x11,0x06,0x31,0x0c, + 0x01,0xe8,0x31,0x05,0x44,0x06,0xf9,0xef,0x12,0x12,0xf5,0x37,0x01,0xe8,0x02,0x28, + 0xcf,0x00,0xf0,0x25,0x60,0x92,0x70,0x93,0x40,0x94,0x50,0x95,0x07,0x2d,0x27,0x16, + 0x25,0x12,0x05,0x3f,0x06,0x2d,0x46,0x16,0x41,0x12,0x01,0x3f,0x63,0x12,0x73,0x03, + 0x17,0x03,0x56,0x03,0x15,0x03,0x67,0x1c,0x31,0x12,0x01,0x3f,0x17,0x1c,0x67,0x0c, + 0x02,0xe0,0x06,0x33,0x65,0x1c,0x76,0x12,0x06,0x3f,0x56,0x1c,0x10,0x96,0x07,0x3d, + 0x06,0x2d,0x63,0x16,0x37,0x1c,0x00,0x97,0x00,0x86,0x10,0x87,0x20,0x96,0x30,0x97, + 0x50,0x87,0x27,0x03,0x70,0x86,0x46,0x03,0x67,0x1c,0x20,0x82,0x30,0x83,0x73,0x1c, + 0xf0,0x21,0xcf,0x00,0xf0,0x25,0x78,0x00,0x81,0x62,0x10,0x05,0x40,0x92,0x50,0x93, + 0x20,0x94,0x30,0x95,0x4d,0x12,0x57,0x12,0x2b,0x12,0x3e,0x12,0x05,0x2a,0x58,0xe0, + 0x43,0x0c,0x76,0xe0,0x06,0x2d,0x46,0x0c,0xd4,0xe0,0x87,0x2d,0x47,0x0c,0x8b,0xe9, + 0x07,0x61,0x75,0x12,0x9f,0x76,0xd3,0x12,0x73,0x0b,0x36,0x1c,0x06,0xa6,0x56,0x1c, + 0x07,0x62,0x67,0x05,0x07,0x2a,0x06,0xe8,0x7d,0x1b,0x7e,0x1b,0xb4,0x12,0x64,0x0b, + 0x4e,0x1e,0x7b,0x1b,0xdc,0x12,0x0c,0x3f,0x09,0x2d,0xd9,0x16,0xe2,0x12,0xc3,0x12, + 0x95,0x7f,0x28,0x12,0xe2,0x12,0xc3,0x12,0x94,0x7f,0x2a,0x12,0x2e,0x12,0x9e,0x03, + 0x08,0x3d,0xb7,0x12,0x07,0x3f,0x78,0x1e,0xe8,0x0c,0x08,0xe0,0x27,0x12,0x07,0x24, + 0xd8,0x1c,0xd8,0x0c,0x02,0xe8,0xe8,0x0c,0x8d,0xe9,0x7a,0x12,0x8e,0x14,0xe2,0x12, + 0xc3,0x12,0x88,0x7f,0x28,0x12,0xe2,0x12,0xc3,0x12,0x87,0x7f,0x27,0x12,0x29,0x03, + 0x08,0x3d,0x05,0x2d,0x5b,0x16,0xb8,0x1e,0x98,0x0c,0x08,0xe0,0x26,0x12,0x06,0x24, + 0xd8,0x1c,0xd8,0x0c,0x4b,0xe9,0x98,0x0c,0x49,0xe1,0x17,0x24,0xa2,0x12,0x02,0x3d, + 0x72,0x1e,0x0c,0x60,0xc3,0x12,0x81,0x62,0x10,0x1c,0x68,0x00,0xf0,0x21,0xcf,0x00, + 0x53,0x0c,0x77,0xe8,0x06,0x2d,0x56,0x0c,0x76,0xe0,0x86,0x2d,0x56,0x0c,0x45,0xe9, + 0x05,0x61,0x54,0x12,0x73,0x76,0x73,0x12,0x53,0x0b,0x36,0x1c,0x06,0xa6,0x46,0x1c, + 0x0c,0x62,0x6c,0x05,0x0c,0x2a,0x79,0xe0,0x12,0x60,0xe7,0x0c,0x03,0xe8,0xdb,0x0c, + 0x01,0xe0,0xc2,0x12,0xc3,0x12,0x81,0x62,0x10,0x1c,0x68,0x00,0xf0,0x21,0xcf,0x00, + 0x04,0x2a,0x04,0xe0,0x12,0x60,0x43,0x12,0x68,0x7f,0x2d,0x12,0x07,0x2d,0xd7,0x0c, + 0x5e,0xe0,0x87,0x2d,0xd7,0x0c,0x27,0xe9,0x06,0x61,0x65,0x12,0x61,0x77,0xd3,0x12, + 0x63,0x0b,0x37,0x1c,0x07,0xa6,0x56,0x1c,0x07,0x62,0x67,0x05,0x07,0x2a,0xbe,0xe0, + 0xde,0x05,0xda,0x12,0x0a,0x3f,0x08,0x2d,0xd8,0x16,0x1c,0x60,0xe2,0x12,0xa3,0x12, + 0x59,0x7f,0x60,0x92,0xe2,0x12,0xa3,0x12,0x58,0x7f,0x29,0x12,0x27,0x12,0x87,0x03, + 0x60,0x8e,0x0e,0x3d,0xb6,0x12,0x06,0x3f,0x6e,0x1e,0x7e,0x0c,0x08,0xe0,0x26,0x12, + 0x06,0x24,0xde,0x1c,0xde,0x0c,0x02,0xe8,0x7e,0x0c,0x11,0xe9,0x69,0x12,0x7e,0x05, + 0xe2,0x12,0xa3,0x12,0x4c,0x7f,0x60,0x92,0xe2,0x12,0xa3,0x12,0x4b,0x7f,0x26,0x12, + 0x28,0x03,0x60,0x87,0x07,0x3d,0x03,0x2d,0x3b,0x16,0xb7,0x1e,0x87,0x0c,0x08,0xe0, + 0x25,0x12,0x05,0x24,0xd7,0x1c,0xd7,0x0c,0xd3,0xe8,0x87,0x0c,0xd1,0xe0,0x16,0x24, + 0x92,0x12,0x02,0x3d,0x62,0x1e,0xc3,0x12,0x81,0x62,0x10,0x1c,0x68,0x00,0xf0,0x21, + 0xcf,0x00,0x0c,0x60,0x9e,0xf7,0x86,0x2c,0x56,0x0c,0xd2,0xe8,0x05,0x60,0x54,0x12, + 0x89,0xf7,0x86,0x2c,0x46,0x0c,0xb8,0xe0,0x87,0x60,0x75,0x12,0x2b,0xf7,0x87,0x2c, + 0xd7,0x0c,0xcc,0xe8,0x06,0x60,0x65,0x12,0xa1,0xf7,0x7a,0x12,0xca,0x1b,0xd7,0x12, + 0x67,0x0b,0x7a,0x1e,0xcd,0x1b,0x60,0x9d,0xe8,0x12,0x68,0x0b,0xe9,0x12,0xc9,0x1b, + 0xb7,0x12,0x67,0x0b,0x79,0x1e,0xad,0x12,0x0d,0x3f,0x04,0x2d,0xa4,0x16,0x70,0x94, + 0x82,0x12,0xd3,0x12,0x28,0x7f,0x2e,0x12,0x82,0x12,0xd3,0x12,0x27,0x7f,0x28,0x12, + 0x70,0x87,0x27,0x03,0x0e,0x3d,0x96,0x12,0x06,0x3f,0x6e,0x1e,0x7e,0x0c,0x06,0xe0, + 0x26,0x12,0x06,0x24,0xae,0x1c,0xae,0x0c,0xa9,0xe0,0x68,0x12,0x7e,0x05,0xe2,0x12, + 0xd3,0x12,0x1c,0x7f,0x80,0x92,0xe2,0x12,0xd3,0x12,0x1b,0x7f,0x70,0x86,0x26,0x03, + 0x80,0x87,0x07,0x3d,0x05,0x2d,0x59,0x16,0x97,0x1e,0x67,0x0c,0x06,0xe0,0x25,0x12, + 0x05,0x24,0xa7,0x1c,0xa7,0x0c,0x8d,0xe0,0x52,0x12,0x76,0x14,0x08,0x3d,0x28,0x1e, + 0x07,0x2d,0x87,0x16,0x84,0x12,0x04,0x3f,0x60,0x85,0x03,0x2d,0x35,0x16,0x60,0x8d, + 0x0d,0x3f,0x73,0x12,0x53,0x03,0xd7,0x03,0x45,0x03,0x4d,0x03,0x57,0x1c,0x34,0x12, + 0x04,0x3f,0x47,0x1c,0x57,0x0c,0x02,0xe0,0x04,0x33,0x4d,0x1c,0x75,0x12,0x05,0x3f, + 0xd5,0x1c,0x56,0x0c,0x5e,0xe8,0x56,0x0f,0x55,0xe8,0x82,0x12,0x0c,0x60,0x2a,0xf7, + 0x8c,0x05,0x00,0x00,0x08,0x84,0x00,0x00,0xd0,0x83,0x00,0x00,0x7d,0x1b,0xe9,0x12, + 0x69,0x0b,0xec,0x12,0x7c,0x1b,0xb4,0x12,0x64,0x0b,0x4c,0x1e,0x7b,0x1b,0xda,0x12, + 0x0a,0x3f,0x08,0x2d,0xd8,0x16,0x92,0x12,0xa3,0x12,0x34,0x7f,0x2e,0x12,0x92,0x12, + 0xa3,0x12,0x33,0x7f,0x29,0x12,0x27,0x12,0x87,0x03,0x0e,0x3d,0xc6,0x12,0x06,0x3f, + 0x6e,0x1e,0x7e,0x0c,0x09,0xe0,0x26,0x12,0x06,0x24,0xde,0x1c,0xde,0x0c,0x4d,0xe8, + 0x7e,0x0c,0x4b,0xe0,0x19,0x24,0xde,0x1c,0x7e,0x05,0xe2,0x12,0xa3,0x12,0x27,0x7f, + 0x60,0x92,0xe2,0x12,0xa3,0x12,0x26,0x7f,0x27,0x12,0x87,0x03,0x60,0x8e,0x0e,0x3d, + 0x05,0x2d,0x5c,0x16,0xce,0x1e,0x7e,0x0c,0x09,0xe0,0x26,0x12,0x06,0x24,0xde,0x1c, + 0xde,0x0c,0x31,0xe8,0x7e,0x0c,0x2f,0xe0,0x12,0x24,0xde,0x1c,0x7e,0x05,0x9c,0x12, + 0x0c,0x3d,0x2c,0x1e,0x03,0xf7,0x87,0x61,0x75,0x12,0x74,0xf6,0x67,0x12,0xb6,0xf6, + 0x56,0x12,0x2e,0xf7,0xcb,0x1b,0x07,0x3d,0x05,0x2d,0x53,0x16,0x37,0x1c,0x7b,0x0c, + 0xa4,0xe7,0x82,0x12,0x02,0x24,0x0c,0x60,0xcd,0xf6,0x85,0x61,0x54,0x12,0xba,0xf6, + 0x85,0x60,0x54,0x12,0xb7,0xf6,0x86,0x61,0x65,0x12,0xd8,0xf6,0x86,0x60,0x65,0x12, + 0xd5,0xf6,0x67,0x0c,0x71,0xe7,0x12,0x24,0xa7,0x1c,0x6f,0xf7,0x7e,0x0c,0x55,0xe7, + 0x18,0x24,0xae,0x1c,0x53,0xf7,0x62,0x12,0xd1,0xf7,0x69,0x12,0xb5,0xf7,0x19,0x24, + 0xde,0x1c,0xed,0xf6,0x1a,0x24,0xd8,0x1c,0x71,0xf6,0x00,0x00,0x08,0x84,0x00,0x00, + 0xd0,0x83,0x00,0x00,0xbe,0xbe,0xbe,0xbe,0xbe,0xbe,0xbe,0xbe,0x70,0x24,0x7e,0x00, + 0x0e,0x7f,0x06,0x66,0x0e,0x77,0x07,0xb6,0x0e,0x7f,0x0e,0x7f,0x0f,0x72,0x43,0x60, + 0x0f,0x7f,0x0f,0x7f,0x10,0x7f,0x10,0x7f,0x11,0x7e,0x0e,0xa7,0x17,0x2a,0x07,0xe8, + 0x07,0x2a,0x03,0xe8,0x27,0x2a,0xf9,0xe7,0x04,0xf0,0x0d,0x7f,0xf6,0xf7,0x0d,0x7f, + 0xf4,0xf7,0x0d,0x7f,0xf2,0xf7,0x00,0x00,0x40,0x08,0x00,0x00,0x20,0x01,0x04,0x00, + 0xaa,0x08,0x00,0x00,0x6c,0x26,0x00,0x00,0x80,0xc3,0xc9,0x01,0x9a,0x23,0x00,0x00, + 0x40,0x1b,0x00,0x00,0xec,0x0d,0x00,0x00,0x98,0x09,0x00,0x00,0x20,0xaa,0x00,0x00, + 0x88,0x1b,0x00,0x00,0x88,0x1c,0x00,0x00,0xfc,0x1c,0x00,0x00,0xbe,0xbe,0xbe,0xbe, + 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; \ No newline at end of file diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/lw86x0_ts/Kconfig b/ANDROID_3.4.5/drivers/input/touchscreen/lw86x0_ts/Kconfig new file mode 100755 index 00000000..34cf42cb --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/lw86x0_ts/Kconfig @@ -0,0 +1,11 @@ +config TOUCHSCREEN_LW86X0 + tristate "LW86X0 Touchscreen Driver" + default y + depends on ARCH_WMT + ---help--- + Say Y here if you have an WMT based board with touchscreen + attached to it. + If unsure, say N. + To compile this driver as a module, choose M here: the + module will be called lw86x0_ts. + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/lw86x0_ts/Makefile b/ANDROID_3.4.5/drivers/input/touchscreen/lw86x0_ts/Makefile new file mode 100755 index 00000000..a7cbba75 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/lw86x0_ts/Makefile @@ -0,0 +1,34 @@ +#KERNELDIR=/home/hangyan/android8850/kernel/ANDROID_3.0.8 +KERNELDIR=../../../../ +CROSS = arm_1103_le- +CC= $(CROSS)gcc +LD= $(CROSS)ld +STRIP = $(CROSS)strip + +DEBUG = n + +# Add your debugging flag (or not) to EXTRA_CFLAGS +ifeq ($(DEBUG),y) +# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines +DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines + +else + DEBFLAGS = -O2 -Wall +endif + +EXTRA_CFLAGS += $(DEBFLAGS) + + +MY_MODULE_NAME=s_wmt_ts_lw86x0 + +obj-m := $(MY_MODULE_NAME).o +$(MY_MODULE_NAME)-objs := lw86x0_ts.o wmt_ts.o + +default: + $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules + $(STRIP) --strip-debug $(MY_MODULE_NAME).ko + rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions *.order *.symvers + +clean: + rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/lw86x0_ts/lw86x0_ts.c b/ANDROID_3.4.5/drivers/input/touchscreen/lw86x0_ts/lw86x0_ts.c new file mode 100755 index 00000000..ce741c9c --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/lw86x0_ts/lw86x0_ts.c @@ -0,0 +1,1321 @@ +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_HAS_EARLYSUSPEND) +#include +#endif +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../../video/backlight/wmt_bl.h" +#include "lw86x0_ts.h" +#include "wmt_ts.h" +//#include "wmt_custom_lw86x0.h" + +#define TIME_CHECK_CHARGE 3000 + +#define MAX_MULTI_DATA_SIZE 256 + +#define HDMI_BASE_ADDR (HDMI_TRANSMITTE_BASE_ADDR + 0xC000) +#define REG_HDMI_HOTPLUG_DETECT (HDMI_BASE_ADDR + 0x3ec) + +struct i2c_client *lw_i2c_client = NULL; +struct i2c_client *client;//add by jackie +extern char g_dbgmode; +extern int COL_NUM; +extern int ROW_NUM; +extern int SKIP_ZERO_POINT; + +struct wmtts_device lw86x0_tsdev; +static int tsirq_gpio; + +static int skip_zero_num = 0; + +u16 mcu_status_old = 0xffff; +u16 mcu_status = 0xffff; + +typedef struct Fw_Version{ //add by jackie + u8 magic_num1; + u8 magic_num2; + u8 mj_ver; + u8 mn_ver; +}Fw_Ver;//add by jackie + +//struct for report touch info +struct ts_event { + u16 x[SUPPORT_POINT_NUM_MAX];//point x + u16 y[SUPPORT_POINT_NUM_MAX];//point y + u16 pressure[SUPPORT_POINT_NUM_MAX];//point pressure + u8 touch_point;//touch point number +}; + +struct lw86x0_ts_data { + struct input_dev *input_dev; + struct ts_event event; + struct work_struct touch_event_work; + struct workqueue_struct *ts_workqueue; +#if defined(CONFIG_HAS_EARLYSUSPEND) + struct early_suspend early_suspend; +#endif +}l_tsdata; + +static struct mutex ts_data_mutex; +static int l_powermode = -1; +static int l_hdmimode = -1; + +static int l_keylen = 4; +static int l_baseaxis = 1; //0:x-axis,1:y-axis +int l_keypos[TS_KEY_NUM+1][2]; + +unsigned int l_tskey[TS_KEY_NUM][2] = { + {0,KEY_MENU}, + {0,KEY_HOME}, + {0,KEY_BACK}, + {0,KEY_SEARCH}, +}; +static int l_early_suspend = 0; // 1:the early suspend function has been excuted + +static int stop_timer = 0; +struct work_struct phone_status_work; +struct timer_list polling_phone_status_timer; +static int check_chip_status(void); +static int first_init_reg = 1; +static u16 auto_coff_value[20] = {0}; +//static finger_up_status = 1; + +u8 get_fw_file_check_sum(void); +u16 get_fw_check_sum(void); + +extern int register_bl_notifier(struct notifier_block *nb); + +extern int unregister_bl_notifier(struct notifier_block *nb); +//static struct ts_event old_event; + +void swap_byte_in_buffer(u16* buf, int count ) +{ + int i; + for(i = 0; i < count; i++ ) + { + buf[i] = swap16(buf[i]); + } +} + +/** +** for read register +** rxbuf:read value +** txdata:read register address +** rxlength:read value length +**/ + +static int lw86x0_i2c_rxdata(char *rxbuf, char*txdata, int rxlength) +{ + int ret; + //int reg;//add jackie + + struct i2c_msg msgs[] = { + { + .addr = lw_i2c_client->addr, + .flags = 0, + .len = 2, + .buf = txdata, + }, + { + .addr = lw_i2c_client->addr, + .flags = I2C_M_RD, + .len = rxlength, + .buf = rxbuf, + }, + }; + + //ret = wmt_i2c_xfer_continue_if_4(msgs, 2, 1); + + ret = i2c_transfer(lw_i2c_client->adapter, &msgs[0], 2);//add by jackie + if (ret != 2) + { + dbg("msg i2c rxdata error: %d\n", ret); + return -1; + } + else + { + return 0; + } + +#if 0 + struct i2c_msg xfer_msg[2]; + if (reg < 0x80) { + i2c_transfer(client->adapter, xfer_msg, ARRAY_SIZE(xfer_msg)); + msleep(5); + } + return i2c_transfer(client->adapter, xfer_msg, ARRAY_SIZE(xfer_msg)) == ARRAY_SIZE(xfer_msg) ? 0 : -EFAULT; +#endif + +} + +/** +** for write register +** txdata:register address and value u8 +** length:txdata length +**/ + +static int lw86x0_i2c_txdata(char *txdata, int length) +{ + int ret; + + struct i2c_msg msg[] = { + { + .addr = lw_i2c_client->addr, + .flags = 0, + .len = length, + .buf = txdata, + }, + }; + + + ret = i2c_transfer(lw_i2c_client->adapter, &msg[0], 1);//1 + + //ret = wmt_i2c_xfer_continue_if_4(msg, 1, 1); + if (ret != 1) + { + dbg("i2c txdata error: %d\n", ret); + return -1; + } + else + { + return 0; + } + +} + +/** +** Interface write register for other functions +** addr:write register address +** value:write register value +**/ + +int lw86x0_write_reg(u16 addr, u16 value) +{ + u8 buf[4]; + int ret = -1; + unsigned char * pVal = (unsigned char *) &value; + unsigned char * pOffset = (unsigned char *) &addr; + buf[0] = pOffset[1]; + buf[1] = pOffset[0]; + buf[2] = pVal[1]; + buf[3] = pVal[0]; + ret = lw86x0_i2c_txdata(buf, 4); + if (ret < 0) + { + dbg("lw86x0_write_reg error: %d\n", ret); + return -1; + } + return 0; +} + +/*int lw86x0_write_reg_multi(u16 start_addr, u16 value[], u16 num) +{ + u8 buf[MAX_MULTI_DATA_SIZE]; + int ret = -1; + int i = 0; + unsigned char * pVal = (unsigned char *) &value[0]; + unsigned char * pOffset = (unsigned char *) &addr; + buf[0] = pOffset[1]; + buf[1] = pOffset[0]; + //buf[2] = pVal[1]; + //buf[3] = pVal[0]; + for(i = 0; i < num; i++) + { + pVal = (unsigned char *) &value[i]; + buf[2*i + 2] = pVal[1]; + buf[2*i + 3] = pVal[0]; + } + + ret = lw86x0_i2c_txdata(buf, num*2+2); + + if (ret < 0) + { + dbg("lw86x0_write_reg error: %d\n", ret); + return -1; + } + return 0; +}*/ +/** +** Interface read register for other functions +** addr:read register address +** pdata:read register value +** regcnt:read register count +**/ + +int lw86x0_read_reg(u16 addr, u16 *pdata, int regcnt) +{ + int ret; + + u16 offset_reverse = swap16(addr); + ret = lw86x0_i2c_rxdata((char*)pdata, (char*)&offset_reverse, 2*regcnt); + + if (ret < 0) + { + dbg("lw86x0_read_reg error: %d\n", ret); + return -1; + } + else + { + swap_byte_in_buffer(pdata, regcnt); + return 0; + } +} + +int wmt_ts_load_firmware(char* firmwarename, unsigned char** firmdata, int* fwlen) +{ + int i; + const struct firmware *fw_entry; + for (i = 0; i < 3; i++) { + if(request_firmware(&fw_entry, firmwarename, &lw_i2c_client->dev)!=0) + printk(KERN_ERR "cat't request firmware #%d\n", i); + else + break; + } + if (i == 3) + return -EINVAL; + + if (fw_entry->size <= 0) { + printk(KERN_ERR "load firmware error\n"); + release_firmware(fw_entry); + return -1; + } + + *firmdata = kzalloc(fw_entry->size + 1, GFP_KERNEL); + memcpy(*firmdata, fw_entry->data, fw_entry->size); + *fwlen = fw_entry->size; + release_firmware(fw_entry); + + return 0; +} + +static u16 *default_setting_table; +static int cfg_len; + +static int load_cfgfile(void) +{ + u32 val[2]; + u16 temp[200]; + int i = 0; + char cfgname[32] = {0}; + u8 *pData; + int fileLen; + char *p; + char *s; + + wmt_ts_get_configfilename(cfgname); + if (wmt_ts_load_firmware(cfgname, &pData, &fileLen)) { + errlog("Load config file failed~ \n"); + return -1; + } + s = pData; + p = strstr(s, "COL_NUM"); + sscanf(p, "COL_NUM=%d;", &COL_NUM); + p = strstr(s, "ROW_NUM"); + sscanf(p, "ROW_NUM=%d;", &ROW_NUM); + p = strstr(s, "SKIP_ZERO_POINT"); + sscanf(p, "SKIP_ZERO_POINT=%d;", &SKIP_ZERO_POINT); + dbg("COL_NUM=%d;ROW_NUM=%d;SKIP_ZERO_POINT=%d;",COL_NUM,ROW_NUM,SKIP_ZERO_POINT); + + p = pData; + while (*p != '{') { + p++; + if(*p == '\0') { + errlog("Bad config file\n"); + i = -1; + goto end; + } + } + while (*p != '}') { + if (!strncmp(p, "0x", 2)) { + i++; + if ((i & 0x0001) != 0) { + sscanf(p, "0x%x,0x%x,", val, val+1); + temp[i-1] = val[0] & 0x0000FFFF; + temp[i] = val[1] & 0x0000FFFF; + } + } + p++; + if(*p == '\0') { + i = -1; + errlog("Bad config file\n"); + goto end; + } + }; + + dbg("the number of data:0x%x\n", i); + default_setting_table = kzalloc(i*2, GFP_KERNEL); + memcpy(default_setting_table, temp, i*2); + cfg_len = i; + + dbg("paring config file end.\n"); +end: + kfree(pData); + return i; +} + +void lw86x0_stop_timer(int flags) +{ + stop_timer = flags; +} + + +static u16 get_trim_info(void) +{ + u16 trim_info = 0; + u8 buf[2] = {0}; + lw86x0_write_reg(0x00e4, 0x0000); + lw86x0_write_reg(0x00e2, 0x0302); + lw86x0_write_reg(0x00e3, 0x0000); + lw86x0_write_reg(0x00e2, 0x034e); + lw86x0_write_reg(0x00e2, 0x0302); + lw86x0_read_reg(0x00e4, buf, 1); + lw86x0_write_reg(0x00e2, 0x0000); + trim_info = buf[1]; + dbg("trim info is %04x",trim_info); + return trim_info; +} + +/** +** load default register setting +**/ + +void lw86x0_load_def_setting(void) +{ + int i = 0; + u16 trim_value = 0; + u16 trim_info = 0; + + lw86x0_write_reg(0x00e6, 0x3311); + trim_info = get_trim_info(); + for(i = 0; i < cfg_len / 2; i++) + { + if(default_setting_table[2*i] == 0xffff) + { + msleep(default_setting_table[2*i+1]); + } + else + { + if(default_setting_table[2*i] == 0x00ee) + { + lw86x0_read_reg(0x00ee, &trim_value, 1); + if(trim_value == 0x00a0) + { + trim_value = 0x00c0 + trim_info; + } + else + { + trim_value = 0x100 + trim_value; + } + lw86x0_write_reg(0x00ee, trim_value); + } + else + { + lw86x0_write_reg(default_setting_table[2*i], default_setting_table[2*i+1]); + } + //lw86x0_write_reg(default_setting_table[2*i], default_setting_table[2*i+1]); + } + /*if(i == 0) + { + msleep(100); + }*/ + } + if(first_init_reg == 1) + { + for(i = 0; i < 19; i++) + { + lw86x0_read_reg(0x0092+i, &auto_coff_value[i], 1); + } + first_init_reg = 0; + } + else + { + lw86x0_write_reg(0x0035, 0x0070); + lw86x0_write_reg(0x0060, 0x0307); + lw86x0_write_reg(0x0091, 0x0200); + for(i = 0; i < 19; i++) + { + lw86x0_write_reg(0x0092+i, auto_coff_value[i]); + } + lw86x0_write_reg(0x0035, 0x2070); + msleep(100); + lw86x0_write_reg(0x0060, 0x0306); + } +} + +/** +** set reset pin for lw86x0 +**/ + +static void lw86x0_hw_reset(void) +{ + wmt_rst_output(0); + //msleep(500); + msleep(30); + wmt_rst_output(1); +} + +static void lw86x0_ts_release(void) +{ + int i = 0; + struct lw86x0_ts_data *data = &l_tsdata; + int down = 0; + + // dbg("lw86x0_ts_release"); + + for (i = 0; i < l_keylen; i++) + { + down |= l_tskey[i][0]; + } + if (down != 0) + { + // if down clear the flag + for ( i = 0; i < l_keylen; i++) + { + l_tskey[i][0] = 0; + }; + //dbg("key up!\n"); + if (wmt_ts_enable_keyled()) + wmt_ts_turnoff_light(); + } + else + { + if (!lw86x0_tsdev.penup) + { + input_mt_sync(data->input_dev); + input_sync(data->input_dev); + //dbg("rpt pen\n"); + } + lw86x0_tsdev.penup = 1; + //dbg("pen up\n"); + //wake_up(&ts_penup_wait_queue); + } +} + +/** +**set wmt touch key count +**/ + +void wmt_ts_set_keylen(int keylen) +{ + l_keylen = keylen; +} + +/** +**set wmt touch baseaxis +**axis:0--x axis,1--y axis. +**/ + +void wmt_ts_set_baseaxis(int axis) +{ + l_baseaxis = axis; +} + +/** +** set wmt touch key info struct keypos +** index:set key number +** min:key min point value +** max:key max point value +**/ + +void wmt_ts_set_keypos(int index, int min,int max) +{ + l_keypos[index][0] = min; + l_keypos[index][1] = max; +} + +/** +** report key info to wmt android +**/ +#if 0 + +static int lw86x0_report_key_info(void) +{ + struct lw86x0_ts_data *data = &l_tsdata; + u16 x, y; + u16 key_stpos,key_vrpos; // the stable and variable position for touch key + int i =0; + lw86x0_read_reg(0x0161, &x, 1); + lw86x0_read_reg(0x016B, &y, 1); + if (wmt_ts_enable_tskey() != 0) + { + switch (l_baseaxis) + { + case 0: + key_stpos = y; + key_vrpos = x; + break; + case 1: + default: + key_stpos = x; + key_vrpos = y; + break; + } + } + for (i=0;i < l_keylen;i++) + { + if ((key_vrpos>=l_keypos[i][0]) && (key_vrpos<=l_keypos[i][1])) + { + // report the key + if (0 == l_tskey[i][0]) + { + input_report_key(data->input_dev, l_tskey[i][1], 1); + input_report_key(data->input_dev, l_tskey[i][1], 0); + input_sync(data->input_dev); + l_tskey[i][0] = 1; + dbg("report tskey:%d\n",i); + if (wmt_ts_enable_keyled()) + wmt_ts_turnon_light(); + } + return 1;//key + } + } + return 0;//no key + +} +#endif + +static void check_mode(void) +{ + int dcin = wmt_charger_is_dc_plugin(); + int hdmiin = (REG32_VAL(REG_HDMI_HOTPLUG_DETECT) & BIT31) >> 31; + + if (dcin == l_powermode && hdmiin == l_hdmimode) + return; + if (!dcin && !hdmiin) { + klog("DC and HDMI removed\n"); + lw86x0_write_reg(0x01e9, 0x0000); + } else { + klog("DC or HDMI in\n"); + lw86x0_write_reg(0x01e9, 0x0001); + } + l_powermode = dcin; + l_hdmimode = hdmiin; +} + +/** +** report touch info to wmt android +** touch_number: touch count +**/ + +static void lw86x0_report_touch_info(u16 touch_number) +{ + struct lw86x0_ts_data *data = &l_tsdata; + struct ts_event *event = &data->event; + u16 i; + + //old_event = *event; + //dbg("Enter into lw86x0_report_touch_info"); + check_mode(); + if(touch_number == 0) + { + input_mt_sync(data->input_dev); + input_sync(data->input_dev); + return; + } + if(touch_number> wmt_ts_get_fingernum()){ + //dbg("Invalid Touch point count is found %d",touch_number); + return; + } + event->touch_point = touch_number; + + //memset(event->x, 0, SUPPORT_POINT_NUM*sizeof(u16) ); + //memset(event->y, 0, SUPPORT_POINT_NUM*sizeof(u16) ); + //memset(event->pressure, 0, SUPPORT_POINT_NUM*sizeof(u16) ); + for( i = 0; i x[i], 1); + lw86x0_read_reg(0x016B+i, &event->y[i], 1); + lw86x0_read_reg(0x0175+i, &event->pressure[i], 1); + } + + for (i = 0; i < touch_number; i++) + { + int x = (event->x[i]) & 0x03ff; + int y = (event->y[i]) & 0x03ff; + int id = ((event->x[i])>>12)&0x000f; + int tmp; + + if(x>wmt_ts_get_resolvX()) + { + x = wmt_ts_get_resolvX(); + } + + if(y>wmt_ts_get_resolvY()) + { + y= wmt_ts_get_resolvY(); + } + + if (wmt_ts_get_xaxis()) { + tmp = x; + x = y; + y = tmp; + } + if (wmt_ts_get_xdir()) + x = wmt_ts_get_resolvX() - x; + if (wmt_ts_get_ydir()) + y = wmt_ts_get_resolvY() - y; + + if (wmt_ts_get_lcdexchg()) { + int tmp; + tmp = x; + x = y; + y = wmt_ts_get_resolvX() - tmp; + } + + dbg("id %d [%d, %d] p %d",id, x, y, event->pressure[i]); + //input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR,event->pressure[i]); + input_report_abs(data->input_dev, ABS_MT_POSITION_X, x); + input_report_abs(data->input_dev, ABS_MT_POSITION_Y, y); + input_report_abs(data->input_dev, ABS_MT_TRACKING_ID, id); + input_mt_sync(data->input_dev); + } + /* SYN_REPORT */ + input_sync(data->input_dev); +} + +/** +**lw86x0 touch irq work function +**/ + +static void lw86x0_ts_touch_irq_work(struct work_struct *work) +{ + + u16 int_touch_status=0; + mutex_lock(&ts_data_mutex); + + //dbg("Enter into lw86x0_ts_touch_irq_work"); + + //finger_up_status = 0; + lw86x0_read_reg(0x01f5, &int_touch_status, 1); + + //dbg("Read 0x1f5 = %d",int_touch_status); + if( int_touch_status & 0x0001) + { + u16 touch_number=0; + lw86x0_read_reg(0x0160, &touch_number, 1); + //dbg("tn=%d\n",touch_number); + if(touch_number==0) + { + skip_zero_num++; + if(SKIP_ZERO_POINT==skip_zero_num) + { + dbg("tn=%d\n",touch_number); + lw86x0_write_reg(0x01f2, 0x0010); + lw86x0_report_touch_info(touch_number); + lw86x0_ts_release(); + //finger_up_status = 1; + } + else if(SKIP_ZERO_POINTmagic_num1,pfwVerInFile->magic_num2,pfwVerInFile->mj_ver,pfwVerInFile->mn_ver);//add by jackie + lw86x0_write_reg(0x00e6,0x3311); + lw86x0_flash_read((u8*)&fwVer,0x2000,4); + printk("lw86x0_flash:%c%c%d%d\n",fwVer.magic_num1,fwVer.magic_num2,fwVer.mj_ver,fwVer.mn_ver);//add by jackie + //printk("lw86x0_flash:%d%d\n",fwVer.magic_num1,fwVer.magic_num2);//add by jackie + if((fwVer.magic_num1!='L'||fwVer.magic_num2!='W') + ||((fwVer.magic_num1=='L'&&fwVer.magic_num2=='W') + &&(pfwVerInFile->magic_num1=='L'&&pfwVerInFile->magic_num2=='W') + &&(fwVer.mj_ver!=pfwVerInFile->mj_ver || fwVer.mn_ver!=pfwVerInFile->mn_ver)) + )*/ + lw86x0_write_reg(0x00e6, 0x3311); + lw86x0_write_reg(0x0020, 0x9000); + lw86x0_write_reg(0x0002, 0x8900); + lw86x0_write_reg(0x0115, 0x0100); + lw86x0_write_reg(0x0020, 0x1000); + msleep(200); + fw_check_sum = get_fw_check_sum(); + fw_file_check_sum = get_fw_file_check_sum(); + printk("**********fw_check_sum = %04x, fw_file_check_sum = %04x\n",fw_check_sum,fw_file_check_sum); + if(((fw_check_sum&0xff00)!=0x8000)||((fw_check_sum&0x00ff)!=fw_file_check_sum)) + { + lw86x0_write_reg(0x0002, 0x8800); + printk("firmware crc check is not equal, update firmware......\n"); + return 1;//return 1 means needing upgrade + } + else + { + printk("firmware is not updated......\n"); + lw86x0_write_reg(0x0002, 0x8800); + return 0; + } +} + +void fw_download(void) +{ + int pkt_num = (fileLen+BYTES_PER_PACKET-1)/BYTES_PER_PACKET; + int i; + int last_pkt_size = ((int)fileLen) % BYTES_PER_PACKET; + printk("pkt_num is:%d\n",pkt_num);//add + if(last_pkt_size==0) + { + last_pkt_size = BYTES_PER_PACKET; + } + lw86x0_flash_write_prepare(); + for(i=0;i0) + { + lw86x0_read_reg(0x0182, &check_sum, 1); + printk("**********check_sum = %04x\n",check_sum); + if((check_sum&0xff00)==0x8000) + { + break; + } + cnt--; + msleep(100); + } + return check_sum; +} + +static void fw_upgrader(void) +{ + u16 fw_check_sum; + u16 fw_file_check_sum = 0; + + if(check_fw_version()==0) + { + return; + } + + lw86x0_write_reg(0x00e6, 0x3311); + fw_download(); + lw86x0_write_reg(0x0020, 0x9000); + lw86x0_write_reg(0x0002, 0x8900); + lw86x0_write_reg(0x0115, 0x0100); + lw86x0_write_reg(0x0020, 0x1000); + msleep(200); + fw_check_sum = get_fw_check_sum(); + fw_file_check_sum = get_fw_file_check_sum(); + printk("**********fw_check_sum = %04x, fw_file_check_sum = %04x\n",fw_check_sum,fw_file_check_sum); + if(((fw_check_sum&0xff00)!=0x8000)||((fw_check_sum&0x00ff)!=fw_file_check_sum)) + { + printk("*********redownload fw\n"); + fw_download(); + lw86x0_write_reg(0x00e6, 0x3311); + lw86x0_write_reg(0x0020, 0x9000); + lw86x0_write_reg(0x0002, 0x8900); + lw86x0_write_reg(0x0115, 0x0100); + lw86x0_write_reg(0x0020, 0x1000); + msleep(200); + fw_check_sum = get_fw_check_sum(); + fw_file_check_sum = get_fw_file_check_sum(); + printk("**********re-check fw_check_sum = %04x, fw_file_check_sum = %04x\n",fw_check_sum,fw_file_check_sum); + if(((fw_check_sum&0xff00)!=0x8000)||((fw_check_sum&0x00ff)!=fw_file_check_sum)) + { + lw86x0_flash_write_prepare(); + } + } + else + { + } + lw86x0_write_reg(0x0002, 0x8800); + kfree(pData); + lw86x0_hw_reset(); + +} + +#endif + + +static int wmt_wakeup_bl_notify(struct notifier_block *nb, unsigned long event, + void *dummy) +{ + //printk("get notify\n"); + switch (event) { + case BL_CLOSE: + l_early_suspend = 1; + wmt_disable_gpirq(tsirq_gpio); + stop_timer = 1; + cancel_work_sync(&l_tsdata.touch_event_work); + cancel_work_sync(&phone_status_work); + printk("\nclose backlight\n\n"); + break; + case BL_OPEN: + l_early_suspend = 0; + wmt_enable_gpirq(tsirq_gpio); + lw86x0_write_reg(0x01f5,0xffff);//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + stop_timer = 0; + printk("\nopen backlight\n\n"); + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block wmt_bl_notify = { + .notifier_call = wmt_wakeup_bl_notify, +}; + +static int lw86x0_ts_probe(struct platform_device *pdev) +{ + int err = 0; + int i = 0; + u16 read_from_e6 = 0; + lw_i2c_client = ts_get_i2c_client();//get i2c_client + + memset(&l_tsdata, 0 ,sizeof(l_tsdata)); + INIT_WORK(&l_tsdata.touch_event_work, lw86x0_ts_touch_irq_work); + mutex_init(&ts_data_mutex); + + l_tsdata.ts_workqueue = create_singlethread_workqueue("lw86x0-ts-queue"); + if (!l_tsdata.ts_workqueue) { + err = -ESRCH; + goto exit_create_singlethread; + } + + l_tsdata.input_dev = input_allocate_device(); + if (!l_tsdata.input_dev) { + err = -ENOMEM; + dbg("failed to allocate input device\n"); + goto exit_input_dev_alloc_failed; + } + + l_tsdata.input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + l_tsdata.input_dev->propbit[0] = BIT_MASK(INPUT_PROP_DIRECT); + + if (wmt_ts_get_lcdexchg()) { + input_set_abs_params(l_tsdata.input_dev, + ABS_MT_POSITION_X, 0, wmt_ts_get_resolvY(), 0, 0); + input_set_abs_params(l_tsdata.input_dev, + ABS_MT_POSITION_Y, 0, wmt_ts_get_resolvX(), 0, 0); + } else { + input_set_abs_params(l_tsdata.input_dev, + ABS_MT_POSITION_X, 0, wmt_ts_get_resolvX(), 0, 0); + input_set_abs_params(l_tsdata.input_dev, + ABS_MT_POSITION_Y, 0, wmt_ts_get_resolvY(), 0, 0); + } + input_set_abs_params(l_tsdata.input_dev, + ABS_MT_TRACKING_ID, 0, 15, 0, 0); + + l_tsdata.input_dev->name = LW86X0_NAME; + for (i = 0; i < TS_KEY_NUM; i++) + { + set_bit(l_tskey[i][1], l_tsdata.input_dev->keybit); + }; + err = input_register_device(l_tsdata.input_dev); + if (err) { + errlog("lw86x0_ts_probe: failed to register input device."); + goto exit_input_register_device_failed; + } + +#ifdef SUPPORT_FW_UPGRADE + fw_upgrader(); + mdelay(500); +#endif + + err = load_cfgfile(); + if (err < 0) + goto exit_load_cfgfile_failed; + lw86x0_load_def_setting(); + +#ifdef CONFIG_HAS_EARLYSUSPEND + l_tsdata.early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB+ 1; + l_tsdata.early_suspend.suspend = lw86x0_ts_early_suspend; + l_tsdata.early_suspend.resume = lw86x0_ts_late_resume; + register_early_suspend(&l_tsdata.early_suspend); +#endif + + // init interrupt gpio + tsirq_gpio = wmt_ts_get_gpionum(); + wmt_set_gpirq(tsirq_gpio, GIRQ_FALLING);//GIRQ_FALLING); + wmt_disable_gpirq(tsirq_gpio); + + if(request_irq(wmt_get_tsirqnum(), lw86x0_ts_interrupt, IRQF_SHARED, "ts_lw86x0", l_tsdata.input_dev) < 0){ + errlog("Could not allocate intrrupt for ts_lw86x0 !\n"); + err = -1; + goto exit_register_irq; + } + lw86x0_ts_touch_irq_work(&l_tsdata.touch_event_work); + if(g_dbgmode==0) + { + wmt_enable_gpirq(tsirq_gpio); + } + msleep(5); + dbg("irqgpio=%d,irq=%d,resetgpio=%d\n", tsirq_gpio, wmt_get_tsirqnum(),wmt_ts_get_resetgpnum()); + + lw86x0_read_reg(0x00e6, &read_from_e6, 1); + if(read_from_e6 == 0x3311 || read_from_e6 == 0xa311) + { + INIT_WORK(&phone_status_work, phone_status_listener); + init_timer(&polling_phone_status_timer); + setup_timer(&polling_phone_status_timer, lw86x0_ts_polling_phone_status, (long unsigned int) pdev); + lw86x0_ts_polling_phone_status((long unsigned int) pdev); + } + + register_bl_notifier(&wmt_bl_notify); + + return 0; +exit_register_irq: +#ifdef CONFIG_HAS_EARLYSUSPEND//add by jackie + unregister_early_suspend(&l_tsdata.early_suspend); +#endif + kfree(default_setting_table); +exit_load_cfgfile_failed: + +exit_input_register_device_failed: + input_free_device(l_tsdata.input_dev); +exit_input_dev_alloc_failed: + cancel_work_sync(&l_tsdata.touch_event_work); + destroy_workqueue(l_tsdata.ts_workqueue); +exit_create_singlethread: + return err; +} + +static int lw86x0_ts_remove(struct platform_device *pdev) +{ + kfree(default_setting_table); +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&l_tsdata.early_suspend); +#endif + free_irq(wmt_get_tsirqnum(), l_tsdata.input_dev); + input_unregister_device(l_tsdata.input_dev); + flush_workqueue(l_tsdata.ts_workqueue); + cancel_work_sync(&l_tsdata.touch_event_work); + destroy_workqueue(l_tsdata.ts_workqueue); + mutex_destroy(&ts_data_mutex); + del_timer(&polling_phone_status_timer); + unregister_bl_notifier(&wmt_bl_notify); + dbg("remove...\n"); + return 0; +} + + +static int lw86x0_ts_init(void) +{ + dbg("lw86x0_ts_init\n"); + lw86x0_hw_reset(); + return 0; +} + +static void lw86x0_ts_exit(void) +{ + dbg("lw86x0_ts_exit\n"); +} + +struct wmtts_device lw86x0_tsdev = { + .driver_name = "s_lw86x0_ts", + .ts_id = "lw86x0", + .init = lw86x0_ts_init, + .exit = lw86x0_ts_exit, + .probe = lw86x0_ts_probe, + .remove = lw86x0_ts_remove, + .suspend = lw86x0_suspend, + .resume = lw86x0_resume, + .penup = 1, +}; + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/lw86x0_ts/lw86x0_ts.h b/ANDROID_3.4.5/drivers/input/touchscreen/lw86x0_ts/lw86x0_ts.h new file mode 100755 index 00000000..cc2d9e26 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/lw86x0_ts/lw86x0_ts.h @@ -0,0 +1,53 @@ +#ifndef _LW86X0_TS_H_ +#define _LW86X0_TS_H_ + +//#include "wmt_custom_lw86x0.h" + +// define byte swap of a WORD +#define swap16(a) ((((a)&0xff)<<8)|(((a)>>8)&0xff)) + +//struct _reg_word for ioctl read or write register +#define LW86X0_NAME "touch_lw86x0" + +#define SUPPORT_FW_UPGRADE +#define TS_KEY_NUM 4 +#define COL_NUM_MAX 28 +#define ROW_NUM_MAX 16 +#define SUPPORT_POINT_NUM_MAX 10 +#define MULTI_DATA_MAX_SIZE 49 + +typedef struct _reg_word +{ + u16 uOffset; + u16 uValue; + u16 multi_data[MULTI_DATA_MAX_SIZE]; + int data_size; +}reg_word; + +//struct _flash_op for ioctl write or read frimware +#define FLASH_XFER_PKT_SIZE 256 +typedef struct _flash_op +{ + u16 startaddr; //=0 if the first pkt + u16 lastpkt; // =1 if last pkt; =0, otherwise + u16 pktlen; //data length in this pkt + char data[FLASH_XFER_PKT_SIZE]; +}flash_op; + +//struct _raw_data for ioctl read cdc/amb/diff data +typedef struct _raw_data +{ + u8 row; + u8 col; + u16 data[COL_NUM_MAX*ROW_NUM_MAX]; +}rawdata; + +extern void wmt_ts_set_keylen(int keylen); +extern void wmt_ts_set_baseaxis(int axis); +extern void wmt_ts_set_keypos(int index, int min,int max); +extern int lw86x0_write_reg(u16 addr, u16 value); +extern int lw86x0_read_reg(u16 addr, u16 *pdata, int regcnt); +extern void getversion(void); +extern void lw86x0_stop_timer(int flags); + +#endif diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/lw86x0_ts/wmt_ts.c b/ANDROID_3.4.5/drivers/input/touchscreen/lw86x0_ts/wmt_ts.c new file mode 100755 index 00000000..505dedfd --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/lw86x0_ts/wmt_ts.c @@ -0,0 +1,1165 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include //add +#include "wmt_ts.h" +#include "lw86x0_ts.h" +//#include "wmt_custom_lw86x0.h" + + +struct i2c_client *l_client = NULL; + + + +///////////////////////////////////////////////////////////////// + +// commands for ui +#define TS_IOC_MAGIC 't' +#define LW86X0_READ_REG _IOWR(TS_IOC_MAGIC, 1, int*) +#define LW86X0_WRITE_REG _IOW(TS_IOC_MAGIC, 2, int*) +#define LW86X0_FLASH_DOWNLOAD _IOW(TS_IOC_MAGIC, 3, int *) +#define LW86X0_FLASH_UPLOAD _IOWR(TS_IOC_MAGIC, 4, int *) +#define LW86X0_CTRL_DEBUG_MODE _IOW(TS_IOC_MAGIC, 5, int *) +#define LW86X0_CTRL_RD_DIFF _IOR(TS_IOC_MAGIC, 6, int *) +#define LW86X0_CTRL_RD_CDC _IOR(TS_IOC_MAGIC, 7, int *) +#define LW86X0_CTRL_RD_AMB _IOR(TS_IOC_MAGIC, 8, int *) +#define LW86X0_CTRL_STOP_TIMER _IOR(TS_IOC_MAGIC, 15, int *) +#define TS_IOC_MAXNR 15 + +// +#define TS_MAJOR 11 +#define TS_DRIVER_NAME "wmtts_touch" +#define TS_NAME "wmtts" +#define WMTTS_PROC_NAME "wmtts_config" + +#define LIGHT_ON_WAIT_TIME 5000 // 5s + +#define EXT_GPIO0 0 +#define EXT_GPIO1 1 +#define EXT_GPIO2 2 +#define EXT_GPIO3 3 +#define EXT_GPIO4 4 +#define EXT_GPIO5 5 +#define EXT_GPIO6 6 +#define EXT_GPIO7 7 + +struct touch_tp_info { + char name[64]; + unsigned int i2caddr; + int xaxis; // 0:x,1:x swap with y + int xdir; // 1:positive,-1:revert + int ydir; // 1:positive,-1:revert + int finger_num; +}; + + +static struct touch_tp_info l_tp[] = { + {"LW86X0",(0x30>>1), 0, 1, 1}, +}; + +static int irq_gpio; +static int rst_gpio; +static int keyled_gpio = -1; +static int light_level; +static int light_time = 5000; // unit: ms +static int panelres_x; +static int panelres_y; +static int lcd_exchg = 0; +static DECLARE_WAIT_QUEUE_HEAD(queue); +static TS_EVENT g_evLast; +static struct mutex cal_mutex; + +static struct class* l_dev_class = NULL; +static struct device *l_clsdevice = NULL; +extern struct wmtts_device lw86x0_tsdev; +static struct wmtts_device* l_tsdev = &lw86x0_tsdev; +static unsigned char ts_i2c_addr = 0; + +static struct proc_dir_entry* l_tsproc = NULL; +static struct timer_list l_lighttimer; // for shaking +static int l_tskey_btn = 0; // zero to disable touch key, positive to support touch key + +#if 0 +//add +struct tp_infor{ + +char name[64]; +int i2caddr; +int xaxis; +int xdir; +int ydir; +int finger_num; +}; + +//add by jackie +//static int l_tpindex = -1; +static struct tp_infor l_tpinfor[1]; +#endif +///////////////////////////////////////////////////// +// extrenal function +///////////////////////////////////////////////////// +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); +extern int wmt_setsyspara(char *varname, unsigned char *varval); +///////////////////////////////////////////////////// +static int ts_writeproc( struct file *file, + const char *buffer, + unsigned long count, + void *data ); +static int ts_readproc(char *page, char **start, off_t off, + int count, int *eof, void *data); + + +char g_dbgmode = 0; +int COL_NUM; +int ROW_NUM; +int SKIP_ZERO_POINT; + +int wmt_ts_get_configfilename(char* fname) +{ + sprintf(fname,"%s.cfg",l_tp[0].name); + return 0; +} + +int wmt_ts_get_firmwfilename(char* fname) +{ + sprintf(fname,"%s_fw.bin",l_tp[0].name); + return 0; +} + +int wmt_ts_get_xaxis(void) +{ + return l_tp[0].xaxis; +} + +int wmt_ts_get_xdir(void) +{ + return l_tp[0].xdir; +} + +int wmt_ts_get_ydir(void) +{ + return l_tp[0].ydir; +} + +int wmt_ts_get_fingernum(void) +{ + return l_tp[0].finger_num; +} + + int wmt_ts_get_gpionum(void) +{ + return irq_gpio; +} + +int wmt_ts_get_resetgpnum(void) +{ + return rst_gpio; +} + +int wmt_ts_get_lcdexchg(void) +{ + return lcd_exchg; +} + +int wmt_ts_get_resolvX(void) +{ + return panelres_x; +} + +int wmt_ts_get_resolvY(void) +{ + return panelres_y; +} + +int wmt_ts_enable_tskey(void) +{ + return l_tskey_btn; +} + +int wmt_ts_enable_keyled(void) +{ + return (keyled_gpio>=0 ? 1:0); +} + + +static void ts_lighttimer_timeout(unsigned long timeout) +{ + // turn off the light + if (20 == keyled_gpio) + { + if (light_level>=0) + { + REG32_VAL(__GPIO_BASE+0x00F0) &= ~BIT4; // output low + dbg("turn off the light!\n"); + } else { + REG32_VAL(__GPIO_BASE+0x00F0) |= BIT4; // output high + dbg("turn off the light!\n"); + } + } +} + + +static void wmt_ts_init_light(void) +{ + if (20 == keyled_gpio) + { + setup_timer(&l_lighttimer, ts_lighttimer_timeout, 0); + // init gpio20 and turn off light + REG32_VAL(__GPIO_BASE+0x00F0) &= ~BIT4; // output low + REG32_VAL(__GPIO_BASE+0x00B0) |= BIT4; // output enable + REG32_VAL(__GPIO_BASE+0x0070) |= BIT4; // enable gpio + REG32_VAL(__GPIO_BASE+0x04F0) |= BIT4; // pull up + REG32_VAL(__GPIO_BASE+0x04B0) |= BIT4; // enable pull up/down + } +} + +void wmt_ts_turnoff_light(void) +{ + if (20 == keyled_gpio) + { + mod_timer(&l_lighttimer, jiffies + msecs_to_jiffies(light_time)); + } +} + +void wmt_ts_turnon_light(void) +{ + if (20 == keyled_gpio) + { + del_timer(&l_lighttimer); + if (light_level >= 0) + { + REG32_VAL(__GPIO_BASE+0x00F0) |= BIT4; // output high + dbg("turn on the light!\n"); + } else { + REG32_VAL(__GPIO_BASE+0x00F0) &= ~BIT4; // output low + dbg("turn on the light!\n"); + } + } +} + +static void wmt_ts_remove_light(void) +{ + if (20 == keyled_gpio) + { + if (light_level >= 0) + { + REG32_VAL(__GPIO_BASE+0x00F0) &= ~BIT4; // output low + } else { + REG32_VAL(__GPIO_BASE+0x00F0) |= BIT4; // output high + } + del_timer(&l_lighttimer); + } +} + +int wmt_is_tsirq_enable(int num) +{ + int val = 0; + + if(num > 11) + return 0; + + if(num<4) + val = REG32_VAL(__GPIO_BASE+0x0300) & (1<<(num*8+7)); + else if(num >= 4 && num < 8) + val = REG32_VAL(__GPIO_BASE+0x0304) & (1<<((num-4)*8+7)); + else + val = REG32_VAL(__GPIO_BASE+0x0308) & (1<<((num-8)*8+7)); + + return val?1:0; +} + +int wmt_is_tsint(int num) +{ + if (num > 11) + { + return 0; + } + return (REG32_VAL(__GPIO_BASE+0x0360) & (1< 11) + { + return; + } + REG32_VAL(__GPIO_BASE+0x0360) = 1<11) + return -1; + REG32_VAL(__GPIO_BASE+0x0040) &= ~(1<11) + return -1; + //if (num > 9) + //GPIO_PIN_SHARING_SEL_4BYTE_VAL &= ~BIT4; // gpio10,11 as gpio + REG32_VAL(__GPIO_BASE+0x0040) &= ~(1<= 4 && num < 8){//[4,7] + shift = num-4; + offset = 0x0304; + }else{// [8,11] + shift = num-8; + offset = 0x0308; + } + + reg = REG32_VAL(__GPIO_BASE + offset); + + switch(type){ + case GIRQ_LOW: + reg &= ~(1<<(shift*8+2)); + reg &= ~(1<<(shift*8+1)); + reg &= ~(1<<(shift*8)); + break; + case GIRQ_HIGH: + reg &= ~(1<<(shift*8+2)); + reg &= ~(1<<(shift*8+1)); + reg |= (1<<(shift*8)); + break; + case GIRQ_FALLING: + reg &= ~(1<<(shift*8+2)); + reg |= (1<<(shift*8+1)); + reg &= ~(1<<(shift*8)); + break; + case GIRQ_RISING: + reg &= ~(1<<(shift*8+2)); + reg |= (1<<(shift*8+1)); + reg |= (1<<(shift*8)); + break; + default://both edge + reg |= (1<<(shift*8+2)); + reg &= ~(1<<(shift*8+1)); + reg &= ~(1<<(shift*8)); + break; + + } + //reg |= 1<<(shift*8+7);//enable interrupt + reg &= ~(1<<(shift*8+7)); //disable int + REG32_VAL(__GPIO_BASE + offset) = reg; + REG32_VAL(__GPIO_BASE+0x0360) = 1< 11) + return -1; + if(num<4) + REG32_VAL(__GPIO_BASE+0x0300) |= 1<<(num*8+7); //enable interrupt + else if(num >= 4 && num < 8) + REG32_VAL(__GPIO_BASE+0x0304) |= 1<<((num-4)*8+7); //enable interrupt + else + REG32_VAL(__GPIO_BASE+0x0308) |= 1<<((num-8)*8+7); //enable interrupt + + return 0; +} + +int wmt_disable_gpirq(unsigned int num) +{ + if(num > 11) + return -1; + + if(num<4) + REG32_VAL(__GPIO_BASE+0x0300) &= ~(1<<(num*8+7)); //enable interrupt + else if(num >= 4 && num < 8) + REG32_VAL(__GPIO_BASE+0x0304) &= ~(1<<((num-4)*8+7)); //enable interrupt + else + REG32_VAL(__GPIO_BASE+0x0308) &= ~(1<<((num-8)*8+7)); //enable interrupt + + return 0; +} + + +int wmt_get_tsirqnum(void) +{ + return IRQ_GPIO; +} + +int wmt_ts_set_rawcoord(unsigned short x, unsigned short y) +{ + g_evLast.x = x; + g_evLast.y = y; + //dbg("raw(%d,%d)*\n", x, y); + return 0; +} + +static void wmt_ts_platform_release(struct device *device) +{ + return; +} + +static struct platform_device wmt_ts_plt_device = { + .name = TS_DRIVER_NAME, + .id = 0, + .dev = { + .release = wmt_ts_platform_release, + }, +// .num_resources = ARRAY_SIZE(wm9715_ts_resources), +// .resource = wm9715_ts_resources, +}; + +static int wmt_ts_suspend(struct platform_device *pdev, pm_message_t state) +{ + dbg("ts suspend....\n"); + if (wmt_ts_enable_keyled()) + wmt_ts_remove_light(); + if (l_tsdev->suspend !=NULL) + { + return l_tsdev->suspend(pdev, state); + } + return 0; +} +static int wmt_ts_resume(struct platform_device *pdev) +{ + klog("ts resume....\n"); + if (wmt_ts_enable_keyled()) + wmt_ts_init_light(); + if (l_tsdev->resume != NULL) + { + return l_tsdev->resume(pdev); + } + return 0; +} + +static int wmt_ts_probe(struct platform_device *pdev) +{ + l_tsproc= create_proc_entry(WMTTS_PROC_NAME, 0666, NULL/*&proc_root*/); + if (l_tsproc != NULL) + { + l_tsproc->read_proc = ts_readproc; + l_tsproc->write_proc = ts_writeproc; + } + if (l_tsdev->probe != NULL) + { + return l_tsdev->probe(pdev); + } + else + { + return 0; + } +} + +static int wmt_ts_remove(struct platform_device *pdev) +{ + if (l_tsproc != NULL) + { + remove_proc_entry(WMTTS_PROC_NAME, NULL); + l_tsproc = NULL; + } + + if (l_tsdev->remove != NULL) + return l_tsdev->remove(pdev); + else + return 0; +} + +static struct platform_driver wmt_ts_plt_driver = { + .driver = { + .name = TS_DRIVER_NAME, + .owner = THIS_MODULE, + }, + .probe = wmt_ts_probe, + .remove = wmt_ts_remove, + .suspend = wmt_ts_suspend, + .resume = wmt_ts_resume, +}; + +static int wmt_ts_open(struct inode *inode, struct file *filp) +{ + int ret = 0; + return ret; +} + +static int wmt_ts_close(struct inode *inode, struct file *filp) +{ + return 0; +} + +static unsigned int wmt_ts_poll(struct file *filp, struct poll_table_struct *wait) +{ + return 0; +} + + +void read_diff(rawdata* pdata) +{ + //u16 Buffer[COL_NUM_MAX*ROW_NUM_MAX*2]; + u16 *Buffer; + u16 idx = 0; + int i,j; + u16 addr =0; + pdata->col = COL_NUM; + pdata->row = ROW_NUM; + Buffer = kzalloc(COL_NUM_MAX*ROW_NUM_MAX*2*2, GFP_KERNEL); + if (!Buffer) { + errlog("mem alloc fail.\n"); + return; + } + for(i=0;irow;i++) + { + addr = 0x42f2+i*60; + printk("read_diff: addr=0x%04x\n",addr); + for(j=0;jcol*2;j++) + { + if(lw86x0_read_reg(addr+j, &Buffer[idx],1)!=0) + { + lw86x0_read_reg(addr+j, &Buffer[idx],1); + } + printk("read_diff: Buffer[%d]=0x%04x\n",idx,Buffer[idx]); + idx++; + } + } + for(i=0; icol * pdata->row; i++) + { + pdata->data[i] = ((Buffer[i*2]<<8)&0xff00)|(Buffer[i*2+1]&0x00ff); + printk("read_diff: pdata->data[%d]=0x%04x\n",i,pdata->data[i]); + } + kfree(Buffer); +} + +void read_cdc(rawdata* pdata) +{ + int i,j; + u16 addr = 0x2fc8; + u16 idx = 0; + + pdata->col = COL_NUM; + pdata->row = ROW_NUM; + + for(i=0;icol;i++) + { + for(j=0;jrow;j++) + { + printk("read_cdc: addr=0x%04x\n",addr+idx); + if(lw86x0_read_reg(addr+idx, &pdata->data[j*pdata->col+i],1)!=0) + { + lw86x0_read_reg(addr+idx, &pdata->data[j*pdata->col+i],1); + } + printk("read_cdc: pdata->data[%d]=0x%04x\n",j*pdata->col+i,pdata->data[j*pdata->col+i]); + idx++; + } + } +} + +void read_amb(rawdata* pdata) +{ + int i,j; + u16 addr = 0x2E04; + u16 idx = 0; + + pdata->col = COL_NUM; + pdata->row = ROW_NUM; + + for(i=0;icol;i++) + { + for(j=0;jrow;j++) + { + printk("read_amb: addr=0x%04x\n",addr+idx); + if(lw86x0_read_reg(addr+idx, &pdata->data[j*pdata->col+i],1)!=0) + { + lw86x0_read_reg(addr+idx, &pdata->data[j*pdata->col+i],1); + } + printk("read_amb: pdata->data[%d]=0x%04x\n",j*pdata->col+i,pdata->data[j*pdata->col+i]); + idx++; + } + } + + +} + +void lw86x0_flash_write_prepare(void) +{ + lw86x0_stop_timer(1); + lw86x0_write_reg(0x00e2, 0x0300);//#write_en=1 tmr=1 + udelay(1); + //mass erase + lw86x0_write_reg(0x00e2, 0x0305);//#xe=1 mas1=1 + lw86x0_write_reg(0x00e2, 0x0315);//#erase=1 + udelay(5); + lw86x0_write_reg(0x00e2, 0x0395);//#nvstr=1 + mdelay(20); + lw86x0_write_reg(0x00e2, 0x0385);//#erase=0 + udelay(100); + lw86x0_write_reg(0x00e2, 0x0305);//#nvstr=0 + lw86x0_write_reg(0x00e2, 0x0300);//#xe=0 mas1=0 +} + +void lw86x0_flash_write(u8* pbData,u16 start_addr, u16 num) +{ + u16 yaddr = start_addr; + u16 xaddr = (start_addr)&0xFF80;//x addr is a 8bit address + u16 cnt = 0; + while(cnt TS_IOC_MAXNR){ + dbg("NO SUCH IO CMD!\n"); + return -ENOTTY; + } + + switch (cmd) { + case LW86X0_WRITE_REG: + copy_from_user(®word, (reg_word*)arg, sizeof(regword)); + dbg("write reg[%d] word value 0x%x", regword.uOffset, regword.uValue ); + ret = lw86x0_write_reg(regword.uOffset, regword.uValue); + if (ret != 0) + { + dbg("Faied to write reg. ret 0x%x\n",ret); + } + return 0; + case LW86X0_READ_REG: + copy_from_user(®word, (reg_word*)arg, sizeof(regword)); + ret = lw86x0_read_reg(regword.uOffset, ®word.uValue, 1); + if (ret != 0) + { + dbg("Faied to read reg. ret 0x%x\n",ret); + } + else + { + + dbg("read reg[%d]=0x%04x",regword.uOffset, regword.uValue); + } + copy_to_user((unsigned int*)arg, ®word, sizeof(regword)); + return 0; + case LW86X0_CTRL_DEBUG_MODE: + copy_from_user(&ch, (char*)arg, sizeof(char)); + printk("LW86X0_CTRL_DEBUG_MODE,%c", ch); + if(ch=='1') + { + g_dbgmode = 1; + wmt_disable_gpirq(irq_gpio); + } + else + { + g_dbgmode = 0; + wmt_enable_gpirq(irq_gpio); + } + return 0; + /* + case LW86X0_CTRL_RD_DIFF: + copy_from_user(&rdata, (rawdata*)arg, sizeof(rdata)); + printk("tpd-ioctrl: LW86X0_CTRL_RD_DIFF\n"); + read_diff(&rdata); + copy_to_user((unsigned int*)arg, &rdata, sizeof(rdata)); + return 0; + case LW86X0_CTRL_RD_CDC: + copy_from_user(&rdata, (rawdata*)arg, sizeof(rdata)); + printk("tpd-ioctrl: LW86X0_CTRL_RD_CDC\n"); + read_cdc(&rdata); + copy_to_user((unsigned int*)arg, &rdata, sizeof(rdata)); + return 0; + case LW86X0_CTRL_RD_AMB: + copy_from_user(&rdata, (rawdata*)arg, sizeof(rdata)); + printk("tpd-ioctrl: LW86X0_CTRL_RD_AMB\n"); + read_amb(&rdata); + copy_to_user((unsigned int*)arg, &rdata, sizeof(rdata)); + return 0; + */ + case LW86X0_CTRL_RD_DIFF: + copy_from_user(rdata, (rawdata*)arg, sizeof(*rdata)); + printk("tpd-ioctrl: LW86X0_CTRL_RD_DIFF\n"); + read_diff(rdata); + copy_to_user((unsigned int*)arg, rdata, sizeof(*rdata)); + return 0; + case LW86X0_CTRL_RD_CDC: + copy_from_user(rdata, (rawdata*)arg, sizeof(*rdata)); + printk("tpd-ioctrl: LW86X0_CTRL_RD_CDC\n"); + read_cdc(rdata); + copy_to_user((unsigned int*)arg, rdata, sizeof(*rdata)); + return 0; + case LW86X0_CTRL_RD_AMB: + copy_from_user(rdata, (rawdata*)arg, sizeof(*rdata)); + printk("tpd-ioctrl: LW86X0_CTRL_RD_AMB\n"); + read_amb(rdata); + copy_to_user((unsigned int*)arg, rdata, sizeof(*rdata)); + return 0; + case LW86X0_FLASH_DOWNLOAD: + copy_from_user(&f_pkt, (flash_op*)arg, sizeof(f_pkt)); + if(f_pkt.startaddr==0) + { + lw86x0_flash_write_prepare(); + } + lw86x0_flash_write(f_pkt.data, + f_pkt.startaddr, + f_pkt.pktlen); + printk("dnload: start addr = %04x\n",f_pkt.startaddr); + if(f_pkt.lastpkt==1) + { + u16 write_len = f_pkt.startaddr + f_pkt.pktlen; + lw86x0_flash_write_finish(write_len); + } + return 0; + case LW86X0_FLASH_UPLOAD: + copy_from_user(&f_pkt, (flash_op*)arg, sizeof(f_pkt)); + lw86x0_flash_read(f_pkt.data, f_pkt.startaddr, f_pkt.pktlen); + printk("upload: start addr = %04x\n",f_pkt.startaddr); + printk("\n"); + copy_to_user((int*)arg, &f_pkt, sizeof(f_pkt)); + return 0; + case LW86X0_CTRL_STOP_TIMER: + copy_from_user(&ch, (char*)arg, sizeof(char)); + if(ch == '1') + lw86x0_stop_timer(1); + else + lw86x0_stop_timer(0); + return 0; + } + kfree(rdata); + return -EINVAL; +} + +static ssize_t wmt_ts_read(struct file *filp, char *buf, size_t count, loff_t *l) +{ + return 0; +} + + +static struct file_operations wmt_ts_fops = { + .read = wmt_ts_read, + .poll = wmt_ts_poll, + .unlocked_ioctl = wmt_ts_ioctl, + .open = wmt_ts_open, + .release = wmt_ts_close, +}; + +static int ts_writeproc( struct file *file, + const char *buffer, + unsigned long count, + void *data ) +{ + int calibrate = 0; + int val = 0; + + if (sscanf(buffer, "calibrate=%d\n", &calibrate)) + { + if (1 == calibrate) + { + if((l_tsdev->capacitance_calibrate != NULL) && + (0 == l_tsdev->capacitance_calibrate())) + { + printk(KERN_ALERT "%s calibration successfully!\n", l_tsdev->ts_id); + } else { + printk(KERN_ALERT "%s calibration failed!\n", l_tsdev->ts_id); + } + } + } else if (sscanf(buffer, "out=%d\n", &val)) + { + switch(val) + { + case 1: // reset1 + REG32_VAL(__GPIO_BASE+0x0040) |= (1< /proc/wmtts_config to calibrate ts.\n"); + return len; +} + +unsigned char wmt_ts_get_i2caddr(void) +{ + return ts_i2c_addr; +} + +static int wmt_check_touch_env(void) +{ + int ret = 0; + int len = 127; + char retval[128] = {0},*p=NULL,*s=NULL; + int Enable=0; + + // Get u-boot parameter + ret = wmt_getsyspara("wmt.io.touch", retval, &len); + if(ret){ + errlog("Read wmt.io.touch Failed.\n"); + return -EIO; + } + + //check touch enable + p = retval; + sscanf(p,"%d:", &Enable); + if(Enable == 0){ + errlog("Touch Screen Is Disabled.\n"); + return -ENODEV; + } + + //check touch IC name + p = strchr(p,':');p++; + if (strncmp(p, l_tp[0].name, strlen(l_tp[0].name))) { + errlog("Can't find %s!\n", l_tp[0].name); + return -ENODEV; + } + + //get firmware file name + s = strchr(p,':'); + memset(l_tp[0].name,0x00,sizeof(l_tp[0].name)); + strncpy(l_tp[0].name, p, (s-p)); + dbg("ts_fwname=%s\n", l_tp[0].name); + + p = s + 1; + ret = sscanf(p,"%d:%d:%d:%d:%d:%d:%d:%d:%x", + &irq_gpio,&panelres_x,&panelres_y,&rst_gpio, + &(l_tp[0].xaxis),&(l_tp[0].xdir),&(l_tp[0].ydir), + &(l_tp[0].finger_num),&(l_tp[0].i2caddr)); + + dbg("%d;%d;%d;%d;%d;%d;%d;%d;%x;",irq_gpio,panelres_x,panelres_y,rst_gpio, + (l_tp[0].xaxis),(l_tp[0].xdir),(l_tp[0].ydir), + (l_tp[0].finger_num),(l_tp[0].i2caddr)); + + ret = wmt_getsyspara("wmt.display.fb0", retval, &len); + if (!ret) { + int tmp[6]; + p = retval; + sscanf(p, "%d:[%d:%d:%d:%d:%d", &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5]); + if (tmp[4] > tmp[5]) + lcd_exchg = 1; + } + + return 0; +} +//#if 0 +//add by jackie i2c_board_info +struct i2c_board_info ts_i2c_board_info = { + .type = WMT_TS_I2C_NAME, + .flags = 0x00, + //.addr = 0x18, //WMT_TS_I2C_ADDR,//why error? + .platform_data = NULL, + .archdata = NULL, + .irq = -1, +}; +//add jackie static + int ts_i2c_register_device (void) +{ + struct i2c_board_info *ts_i2c_bi; + struct i2c_adapter *adapter = NULL; + //struct i2c_client *client = NULL; + + ts_i2c_board_info.addr = l_tp[0].i2caddr; + ts_i2c_bi = &ts_i2c_board_info; + adapter = i2c_get_adapter(1);/*in bus 1*/ + + if (NULL == adapter) { + printk("can not get i2c adapter, client address error\n"); + return -1; + } + l_client = i2c_new_device(adapter, ts_i2c_bi); + if (l_client == NULL) { + printk("allocate i2c client failed\n"); + return -1; + } + i2c_put_adapter(adapter); + return 0; +} +//add by jackie +struct i2c_client* ts_get_i2c_client(void) +{ + return l_client; +} +//add +static int __init wmt_ts_init(void) +{ + int ret = 0; + + if(wmt_check_touch_env()) + return -ENODEV; + +//add by jackie + if (ts_i2c_register_device()<0) + { + dbg("Error to run ts_i2c_register_device()!\n"); + return -1; + } + + mutex_init(&cal_mutex); + + if (l_tsdev->init() < 0){ + printk(KERN_ERR "Errors to init %s ts IC!!!\n", l_tsdev->ts_id); + return -1; + } + if (wmt_ts_enable_keyled()) + wmt_ts_init_light(); + // Create device node + if (register_chrdev (TS_MAJOR, TS_NAME, &wmt_ts_fops)) { + printk (KERN_ERR "wmt touch: unable to get major %d\n", TS_MAJOR); + return -EIO; + } + + l_dev_class = class_create(THIS_MODULE, TS_NAME); + if (IS_ERR(l_dev_class)){ + ret = PTR_ERR(l_dev_class); + printk(KERN_ERR "Can't class_create touch device !!\n"); + return ret; + } + l_clsdevice = device_create(l_dev_class, NULL, MKDEV(TS_MAJOR, 0), NULL, TS_NAME); + if (IS_ERR(l_clsdevice)){ + ret = PTR_ERR(l_clsdevice); + printk(KERN_ERR "Failed to create device %s !!!",TS_NAME); + return ret; + } + + // register device and driver of platform + ret = platform_device_register(&wmt_ts_plt_device); + if(ret){ + errlog("wmt ts plat device register failed!\n"); + return ret; + } + ret = platform_driver_register(&wmt_ts_plt_driver); + if(ret){ + errlog("can not register platform_driver_register\n"); + platform_device_unregister(&wmt_ts_plt_device); + return ret; + } + + klog("wmt ts driver init ok!\n"); + return ret; +} + +//add by jackie +static void ts_i2c_unregister_device(void) +{ + if (l_client != NULL) + { + i2c_unregister_device(l_client); + l_client = NULL; + } +} +//add end + +static void __exit wmt_ts_exit(void) +{ + dbg("%s\n",__FUNCTION__); + + if (wmt_ts_enable_keyled()) + wmt_ts_remove_light(); + l_tsdev->exit(); + mutex_destroy(&cal_mutex); + platform_driver_unregister(&wmt_ts_plt_driver); + platform_device_unregister(&wmt_ts_plt_device); + device_destroy(l_dev_class, MKDEV(TS_MAJOR, 0)); + unregister_chrdev(TS_MAJOR, TS_NAME); + class_destroy(l_dev_class); + ts_i2c_unregister_device(); +} + + +module_init(wmt_ts_init); +module_exit(wmt_ts_exit); + +MODULE_LICENSE("GPL"); + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/lw86x0_ts/wmt_ts.h b/ANDROID_3.4.5/drivers/input/touchscreen/lw86x0_ts/wmt_ts.h new file mode 100755 index 00000000..ff1218ac --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/lw86x0_ts/wmt_ts.h @@ -0,0 +1,98 @@ + +#ifndef WMT_TSH_201010191758 +#define WMT_TSH_201010191758 + +#include +#include +#include +#include + +//#define DEBUG_WMT_TS +#ifdef DEBUG_WMT_TS +#undef dbg +#define dbg(fmt, args...) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__ , ## args) + +//#define dbg(fmt, args...) if (wmt_ts_isrundbg()) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__, ## args) + +#else +#define dbg(fmt, args...) +#endif + +#undef errlog +#undef klog +#define errlog(fmt, args...) printk("[%s]: " fmt, __FUNCTION__, ## args) +#define klog(fmt, args...) printk("[%s]: " fmt, __FUNCTION__, ## args) + +#define DONOTHING 0xff + +#define WMT_TS_I2C_NAME "lw86x0-ts" +//////////////////////////////data type/////////////////////////// +typedef struct { + short pressure; + short x; + short y; + //short millisecs; +} TS_EVENT; + +struct wmtts_device +{ + //data + char* driver_name; + char* ts_id; + //function + int (*init)(void); + int (*probe)(struct platform_device *platdev); + int (*remove)(struct platform_device *pdev); + void (*exit)(void); + int (*suspend)(struct platform_device *pdev, pm_message_t state); + int (*resume)(struct platform_device *pdev); + int (*capacitance_calibrate)(void); + int (*wait_penup)(struct wmtts_device*tsdev); // waiting untill penup + int penup; // 0--pendown;1--penup + +}; + +//////////////////////////function interface///////////////////////// +extern int wmt_ts_get_gpionum(void); +extern int wmt_ts_get_resolvX(void); +extern int wmt_ts_get_resolvY(void); +extern int wmt_ts_set_rawcoord(unsigned short x, unsigned short y); +extern int wmt_set_gpirq(unsigned int num, int type); +extern int wmt_get_tsirqnum(void); +extern int wmt_disable_gpirq(unsigned int num); +extern int wmt_enable_gpirq(unsigned int num); +extern int wmt_is_tsirq_enable(int num); +extern void wmt_enable_rst_pull(int enable); +extern void wmt_set_rst_pull(int up); +extern void wmt_rst_output(int high); +void wmt_rst_input(void); +extern int wmt_is_tsint(int num); +extern void wmt_clr_int(int num); +extern void wmt_tsreset_init(int num); +extern int wmt_ts_get_resetgpnum(void); +extern int wmt_ts_get_lcdexchg(void); +extern unsigned char wmt_ts_get_i2caddr(void); +extern void wmt_ts_turnoff_light(void); +extern void wmt_ts_turnon_light(void); +extern int wmt_ts_enable_tskey(void); +extern int wmt_ts_get_configfilename(char* fname); +extern int wmt_ts_get_firmwfilename(char* fname); +extern int wmt_ts_get_xaxis(void); +extern int wmt_ts_get_xdir(void); +extern int wmt_ts_get_ydir(void); +extern int wmt_ts_get_fingernum(void); +extern int wmt_ts_enable_keyled(void); +extern int wmt_set_irq_mode(unsigned int num, int mode); +extern int wmt_disable_gpirq(unsigned int num); +extern int wmt_enable_gpirq(unsigned int num); +extern int ts_i2c_register_device (void); +extern struct i2c_client* ts_get_i2c_client(void); + +extern void lw86x0_flash_write_prepare(void); +extern void lw86x0_flash_read(u8* pbData, u16 start_addr, u16 num); +extern void lw86x0_flash_write(u8* pbData,u16 start_addr, u16 num); +extern void lw86x0_flash_write_finish(u16 total_len); +#endif + + + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/metusb/Makefile b/ANDROID_3.4.5/drivers/input/touchscreen/metusb/Makefile new file mode 100755 index 00000000..f806933e --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/metusb/Makefile @@ -0,0 +1,33 @@ +KERNELDIR=../../../../ +CROSS = arm_1103_le- +CC= $(CROSS)gcc +LD= $(CROSS)ld +STRIP = $(CROSS)strip + +DEBUG = n + +# Add your debugging flag (or not) to EXTRA_CFLAGS +ifeq ($(DEBUG),y) +# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines +DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines + +else + DEBFLAGS = -O2 -Wall +endif + +EXTRA_CFLAGS += $(DEBFLAGS) + + +MY_MODULE_NAME=metusb + +obj-m := $(MY_MODULE_NAME).o + +default: + $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules + $(STRIP) --strip-debug $(MY_MODULE_NAME).ko + rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions *.order *.symvers modules.builtin +clean: + rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers modules.builtin + + + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/metusb/metusb.c b/ANDROID_3.4.5/drivers/input/touchscreen/metusb/metusb.c new file mode 100755 index 00000000..e86bf03c --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/metusb/metusb.c @@ -0,0 +1,856 @@ + +//#define DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define DRIVER_VERSION "v1.0" +#define DRIVER_AUTHOR "Xiaoyijian" +#define DRIVER_DESC "Metouch USB Touchscreen Driver" + +static int swap_xy = 0; +static int swapx=0; +static int swapy=0; + +static int v_shift=0; +static int v_flag=0; + +static int h_shift=0; +static int h_flag=0; + + +#define TP_TIMEOUT 30 +#define TP_TIMEROUT_MAX 3 + +/* device specifc data/functions */ +struct usbtouch_usb; +struct usbtouch_device_info { + int min_xc, max_xc; + int min_yc, max_yc; + int min_press, max_press; + int rept_size; + + /* + * Always service the USB devices irq not just when the input device is + * open. This is useful when devices have a watchdog which prevents us + * from periodically polling the device. Leave this unset unless your + * touchscreen device requires it, as it does consume more of the USB + * bandwidth. + */ + bool irq_always; + + void (*process_pkt) (struct usbtouch_usb *usbtouch, unsigned char *pkt, int len); + + /* + * used to get the packet len. possible return values: + * > 0: packet len + * = 0: skip one byte + * < 0: -return value more bytes needed + */ + int (*get_pkt_len) (unsigned char *pkt, int len); + + int (*read_data) (struct usbtouch_usb *usbtouch, unsigned char *pkt); + int (*alloc) (struct usbtouch_usb *usbtouch); + int (*init) (struct usbtouch_usb *usbtouch); + void (*exit) (struct usbtouch_usb *usbtouch); +}; + +/* a usbtouch device */ +struct usbtouch_usb { + unsigned char *data; + dma_addr_t data_dma; + unsigned char *buffer; + int buf_len; + struct urb *irq; + struct usb_interface *interface; + struct input_dev *input; + + struct workqueue_struct *tp_queue; + struct delayed_work tp_work; + struct mutex tp_timeout_mutex; + int tp_timer_count; + + struct usbtouch_device_info *type; + char name[128]; + char phys[64]; + void *priv; + int x, y; + int touch, press; +}; + +#define DEVTYPE_METOUCH 0 + +#define USB_DEVICE_HID_CLASS(vend, prod) \ + .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS \ + | USB_DEVICE_ID_MATCH_DEVICE, \ + .idVendor = (vend), \ + .idProduct = (prod), \ + .bInterfaceClass = USB_INTERFACE_CLASS_HID, \ + .bInterfaceProtocol = USB_INTERFACE_PROTOCOL_MOUSE + +/* Define these values to match your devices */ +#define METOUCH_VENDOR_ID 0x5A53 +#define METOUCH_PRODUCT_ID 0x0001 +#define METUSB_MINOR_BASE 0x0 + +static int metouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt); +static void usbtouch_process_pkt(struct usbtouch_usb *usbtouch,unsigned char *pkt, int len); +static void usbtouch_irq(struct urb *urb); +static int usbtouch_open(struct input_dev *input); +static void usbtouch_close(struct input_dev *input); +static int usbtouch_suspend(struct usb_interface *intf, pm_message_t message); +static int usbtouch_resume(struct usb_interface *intf); +static int usbtouch_reset_resume(struct usb_interface *intf); +static void usbtouch_free_buffers(struct usb_device *udev,struct usbtouch_usb *usbtouch); +static struct usb_endpoint_descriptor *usbtouch_get_input_endpoint(struct usb_host_interface *interface); +static int usbtouch_probe(struct usb_interface *intf,const struct usb_device_id *id); +static void usbtouch_disconnect(struct usb_interface *intf); +static int __init usbtouch_init(void); +static void __exit usbtouch_cleanup(void); +static void GetUserCfg(void); +static void AnlysCmd(char *cmd); +static int myatoi(char *str); +static void DeleteAllSpace(char *cmd); +int mypow(int t); + + +static struct usbtouch_device_info usbtouch_dev_info[] = { + [DEVTYPE_METOUCH] = { + .min_xc = 0x0, + .max_xc = 0x0fff, + .min_yc = 0x0, + .max_yc = 0x0fff, + .rept_size = 8, + .read_data = metouch_read_data, + }, +}; + +static struct usb_device_id metusb_table [] = { + { USB_DEVICE(METOUCH_VENDOR_ID, METOUCH_PRODUCT_ID) }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, metusb_table); + +/***************************************************************************** + * METOUCH Part + */ +/* +AA 55 XL XH YL YH BTN CRC +****************************************************************************/ +static int metouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt) +{ + dev->x = (pkt[3] << 8) | pkt[2]; + dev->y = (pkt[5] << 8) | pkt[4]; + dev->touch = (pkt[6] & 0x03) ? 1 : 0; + + if (h_flag == 0) dev->x = dev->x + h_shift; + if (v_flag == 0) dev->y = dev->y + v_shift; + + if (h_flag>0) + { + if (dev->x > h_shift) dev->x = dev->x - h_shift; + else dev->x=0; + } + + if (v_flag>0) + { + if (dev->y > v_shift) dev->y = dev->y - v_shift; + else dev->y=0; + } + + if (dev->x > 4095) dev->x=4095; + if (dev->y > 4095) dev->y=4095; + + if (dev->x <0) dev->x=0; + if (dev->y <0) dev->y=0; + + if (swapx>0) dev->x = 4095 - dev->x; + if (swapy>0) dev->y = 4095 - dev->y; + + return 1; +} + + +/***************************************************************************** + * Generic Part + */ +static void usbtouch_process_pkt(struct usbtouch_usb *usbtouch, + unsigned char *pkt, int len) +{ + struct usbtouch_device_info *type = usbtouch->type; + + if (!type->read_data(usbtouch, pkt)) + return; + + mutex_lock(&usbtouch->tp_timeout_mutex); + if( usbtouch->tp_timer_count < 0 ){ + queue_delayed_work(usbtouch->tp_queue, &usbtouch->tp_work, msecs_to_jiffies(TP_TIMEOUT)); + } + usbtouch->tp_timer_count = TP_TIMEROUT_MAX; + mutex_unlock(&usbtouch->tp_timeout_mutex); + + //input_report_key(usbtouch->input, BTN_TOUCH, usbtouch->touch); + input_report_abs(usbtouch->input, ABS_MT_TRACKING_ID, 0); + if (swap_xy) { + //input_report_abs(usbtouch->input, ABS_X, usbtouch->y); + //input_report_abs(usbtouch->input, ABS_Y, usbtouch->x); + input_report_abs(usbtouch->input, ABS_MT_POSITION_X, usbtouch->y ); + input_report_abs(usbtouch->input, ABS_MT_POSITION_Y, usbtouch->x ); + } else { + //input_report_abs(usbtouch->input, ABS_X, usbtouch->x); + //input_report_abs(usbtouch->input, ABS_Y, usbtouch->y); + input_report_abs(usbtouch->input, ABS_MT_POSITION_X, usbtouch->x ); + input_report_abs(usbtouch->input, ABS_MT_POSITION_Y, usbtouch->y ); + } + //if (type->max_press) + // input_report_abs(usbtouch->input, ABS_PRESSURE, usbtouch->press); + //input_sync(usbtouch->input); + input_mt_sync(usbtouch->input); + input_sync(usbtouch->input); + + + +} + + +static void usbtouch_irq(struct urb *urb) +{ + struct usbtouch_usb *usbtouch = urb->context; + int retval; + + switch (urb->status) { + case 0: + /* success */ + break; + case -ETIME: + /* this urb is timing out */ + dbg("%s - urb timed out - was the device unplugged?", + __func__); + return; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + case -EPIPE: + /* this urb is terminated, clean up */ + dbg("%s - urb shutting down with status: %d", + __func__, urb->status); + return; + default: + dbg("%s - nonzero urb status received: %d", + __func__, urb->status); + goto exit; + } + + usbtouch->type->process_pkt(usbtouch, usbtouch->data, urb->actual_length); + +exit: + usb_mark_last_busy(interface_to_usbdev(usbtouch->interface)); + retval = usb_submit_urb(urb, GFP_ATOMIC); + if (retval) + err("%s - usb_submit_urb failed with result: %d", + __func__, retval); +} + +static int usbtouch_open(struct input_dev *input) +{ + struct usbtouch_usb *usbtouch = input_get_drvdata(input); + int r; + + usbtouch->irq->dev = interface_to_usbdev(usbtouch->interface); + + r = usb_autopm_get_interface(usbtouch->interface) ? -EIO : 0; + if (r < 0) + goto out; + + if (!usbtouch->type->irq_always) { + if (usb_submit_urb(usbtouch->irq, GFP_KERNEL)) { + r = -EIO; + goto out_put; + } + } + + usbtouch->interface->needs_remote_wakeup = 1; +out_put: + usb_autopm_put_interface(usbtouch->interface); +out: + return r; +} + +static void usbtouch_close(struct input_dev *input) +{ + struct usbtouch_usb *usbtouch = input_get_drvdata(input); + int r; + + if (!usbtouch->type->irq_always) + usb_kill_urb(usbtouch->irq); + r = usb_autopm_get_interface(usbtouch->interface); + usbtouch->interface->needs_remote_wakeup = 0; + if (!r) + usb_autopm_put_interface(usbtouch->interface); +} + +static int usbtouch_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct usbtouch_usb *usbtouch = usb_get_intfdata(intf); + + usb_kill_urb(usbtouch->irq); + + return 0; +} + +static int usbtouch_resume(struct usb_interface *intf) +{ + struct usbtouch_usb *usbtouch = usb_get_intfdata(intf); + struct input_dev *input = usbtouch->input; + int result = 0; + + mutex_lock(&input->mutex); + if (input->users || usbtouch->type->irq_always) + result = usb_submit_urb(usbtouch->irq, GFP_NOIO); + mutex_unlock(&input->mutex); + + return result; +} + +static int usbtouch_reset_resume(struct usb_interface *intf) +{ + struct usbtouch_usb *usbtouch = usb_get_intfdata(intf); + struct input_dev *input = usbtouch->input; + int err = 0; + + /* reinit the device */ + if (usbtouch->type->init) { + err = usbtouch->type->init(usbtouch); + if (err) { + dbg("%s - type->init() failed, err: %d", + __func__, err); + return err; + } + } + + /* restart IO if needed */ + mutex_lock(&input->mutex); + if (input->users) + err = usb_submit_urb(usbtouch->irq, GFP_NOIO); + mutex_unlock(&input->mutex); + + return err; +} + +static void usbtouch_free_buffers(struct usb_device *udev, + struct usbtouch_usb *usbtouch) +{ + usb_free_coherent(udev, usbtouch->type->rept_size, + usbtouch->data, usbtouch->data_dma); + kfree(usbtouch->buffer); +} + +static struct usb_endpoint_descriptor *usbtouch_get_input_endpoint(struct usb_host_interface *interface) +{ + int i; + + for (i = 0; i < interface->desc.bNumEndpoints; i++) + if (usb_endpoint_dir_in(&interface->endpoint[i].desc)) + return &interface->endpoint[i].desc; + + return NULL; +} + + +static void tp_timeout_func(struct work_struct *work){ + struct usbtouch_usb *usbtouch = + container_of(work, struct usbtouch_usb, tp_work.work); + int button_up = -1; + + mutex_lock(&usbtouch->tp_timeout_mutex); + button_up = --usbtouch->tp_timer_count; + mutex_unlock(&usbtouch->tp_timeout_mutex); + + if( button_up < 0){ + input_mt_sync(usbtouch->input); + input_sync(usbtouch->input); + }else{ + queue_delayed_work(usbtouch->tp_queue, &usbtouch->tp_work, msecs_to_jiffies(TP_TIMEOUT)); + } + +} + +static int usbtouch_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usbtouch_usb *usbtouch; + struct input_dev *input_dev; + struct usb_endpoint_descriptor *endpoint; + struct usb_device *udev = interface_to_usbdev(intf); + struct usbtouch_device_info *type; + int err = -ENOMEM; + + GetUserCfg(); + + /* some devices are ignored */ + if (id->driver_info == -1) + return -ENODEV; + + endpoint = usbtouch_get_input_endpoint(intf->cur_altsetting); + if (!endpoint) + return -ENXIO; + + usbtouch = kzalloc(sizeof(struct usbtouch_usb), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!usbtouch || !input_dev) + goto out_free; + + type = &usbtouch_dev_info[id->driver_info]; + usbtouch->type = type; + if (!type->process_pkt) + type->process_pkt = usbtouch_process_pkt; + + usbtouch->data = usb_alloc_coherent(udev, type->rept_size, + GFP_KERNEL, &usbtouch->data_dma); + if (!usbtouch->data) + goto out_free; + + if (type->get_pkt_len) { + usbtouch->buffer = kmalloc(type->rept_size, GFP_KERNEL); + if (!usbtouch->buffer) + goto out_free_buffers; + } + + usbtouch->irq = usb_alloc_urb(0, GFP_KERNEL); + if (!usbtouch->irq) { + dbg("%s - usb_alloc_urb failed: usbtouch->irq", __func__); + goto out_free_buffers; + } + + usbtouch->interface = intf; + usbtouch->input = input_dev; + + if (udev->manufacturer) + strlcpy(usbtouch->name, udev->manufacturer, sizeof(usbtouch->name)); + + if (udev->product) { + if (udev->manufacturer) + strlcat(usbtouch->name, " ", sizeof(usbtouch->name)); + strlcat(usbtouch->name, udev->product, sizeof(usbtouch->name)); + } + + if (!strlen(usbtouch->name)) + snprintf(usbtouch->name, sizeof(usbtouch->name), + "USB Touchscreen %04x:%04x", + le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct)); + + usb_make_path(udev, usbtouch->phys, sizeof(usbtouch->phys)); + strlcat(usbtouch->phys, "/input0", sizeof(usbtouch->phys)); + + input_dev->name = usbtouch->name; + input_dev->phys = usbtouch->phys; + usb_to_input_id(udev, &input_dev->id); + input_dev->dev.parent = &intf->dev; + + + input_set_drvdata(input_dev, usbtouch); + + input_dev->open = usbtouch_open; + input_dev->close = usbtouch_close; + + input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + + + set_bit(INPUT_PROP_DIRECT, input_dev->propbit); + + set_bit(ABS_MT_POSITION_X, input_dev->absbit); + set_bit(ABS_MT_POSITION_Y, input_dev->absbit); + input_set_abs_params(input_dev, ABS_MT_POSITION_X, type->min_xc, type->max_xc, 0, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_Y, type->min_yc, type->max_yc, 0, 0); + + mutex_init(&usbtouch->tp_timeout_mutex); + usbtouch->tp_timer_count = -1; + usbtouch->tp_queue= create_singlethread_workqueue("tp_queue"); + INIT_DELAYED_WORK(&usbtouch->tp_work, tp_timeout_func); + //queue_delayed_work(tp_queue, &tp_work, msecs_to_jiffies(TP_TIMEOUT)); + + //input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + //input_set_abs_params(input_dev, ABS_X, type->min_xc, type->max_xc, 0, 0); + //input_set_abs_params(input_dev, ABS_Y, type->min_yc, type->max_yc, 0, 0); + + //if (type->max_press) + // input_set_abs_params(input_dev, ABS_PRESSURE, type->min_press, + // type->max_press, 0, 0); + + + if (usb_endpoint_type(endpoint) == USB_ENDPOINT_XFER_INT) + usb_fill_int_urb(usbtouch->irq, udev, + usb_rcvintpipe(udev, endpoint->bEndpointAddress), + usbtouch->data, type->rept_size, + usbtouch_irq, usbtouch, endpoint->bInterval); + else + usb_fill_bulk_urb(usbtouch->irq, udev, + usb_rcvbulkpipe(udev, endpoint->bEndpointAddress), + usbtouch->data, type->rept_size, + usbtouch_irq, usbtouch); + + usbtouch->irq->dev = udev; + usbtouch->irq->transfer_dma = usbtouch->data_dma; + usbtouch->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + /* device specific allocations */ + if (type->alloc) { + err = type->alloc(usbtouch); + if (err) { + dbg("%s - type->alloc() failed, err: %d", __func__, err); + goto out_free_urb; + } + } + + /* device specific initialisation*/ + if (type->init) { + err = type->init(usbtouch); + if (err) { + dbg("%s - type->init() failed, err: %d", __func__, err); + goto out_do_exit; + } + } + + err = input_register_device(usbtouch->input); + if (err) { + dbg("%s - input_register_device failed, err: %d", __func__, err); + goto out_do_exit; + } + + usb_set_intfdata(intf, usbtouch); + + if (usbtouch->type->irq_always) { + /* this can't fail */ + usb_autopm_get_interface(intf); + err = usb_submit_urb(usbtouch->irq, GFP_KERNEL); + if (err) { + usb_autopm_put_interface(intf); + err("%s - usb_submit_urb failed with result: %d", + __func__, err); + goto out_unregister_input; + } + } + + return 0; + +out_unregister_input: + input_unregister_device(input_dev); + input_dev = NULL; +out_do_exit: + if (type->exit) + type->exit(usbtouch); +out_free_urb: + usb_free_urb(usbtouch->irq); +out_free_buffers: + usbtouch_free_buffers(udev, usbtouch); +out_free: + input_free_device(input_dev); + kfree(usbtouch); + return err; +} + +static void usbtouch_disconnect(struct usb_interface *intf) +{ + struct usbtouch_usb *usbtouch = usb_get_intfdata(intf); + + dbg("%s - called", __func__); + + if (!usbtouch) + return; + + dbg("%s - usbtouch is initialized, cleaning up", __func__); + mutex_destroy(&usbtouch->tp_timeout_mutex); + usb_set_intfdata(intf, NULL); + /* this will stop IO via close */ + input_unregister_device(usbtouch->input); + usb_free_urb(usbtouch->irq); + if (usbtouch->type->exit) + usbtouch->type->exit(usbtouch); + usbtouch_free_buffers(interface_to_usbdev(intf), usbtouch); + kfree(usbtouch); +} + + +static void GetUserCfg(void) +{ +struct file *fd; +char buffer[256]; +loff_t pos; + +mm_segment_t old_fs = get_fs(); +set_fs(KERNEL_DS); + +memset((char *)&buffer[0],0,256); + +fd= filp_open("/etc/metouch.cfg",O_RDONLY,0); + +if (IS_ERR(fd)) + { + printk("Unable to open metouch config information.\n"); + goto exithere; + } +else + { + printk("open metouch config file ok.\n"); + + pos=0; + vfs_read(fd,buffer,256,&pos); + + if (pos < 0) + { + printk("reach the end of file\n"); + } + else + { + AnlysCmd(buffer); + } + filp_close(fd,NULL); + } +exithere:; +set_fs(old_fs); +} + +static void AnlysCmd(char *cmd) +{ +//static int swapx=0; +//static int swapy=0; +//static int v_shift=0; +//static int h_shift=0; +char *pstr=NULL; +char upx[10]; +char upy[10]; +char vsh[10]; +char hsh[10]; +int i=0; + +//clear all invisible char +DeleteAllSpace(cmd); + +//find UPSIDEX +pstr=NULL; +pstr=strstr((const char*)cmd,(const char*)"UPSIDEX="); +if (pstr!=NULL) +{ +strncpy(upx,(char *)(pstr+strlen("UPSIDEX=")),4); + +i=0; +while (i<4) + { + if (upx[i]<0x20) + { + upx[i]=0; + swapx = myatoi(upx); + break; + } + i++; + } +} + +//find UPSIDEY +pstr=NULL; +pstr=strstr((const char*)cmd,(const char*)"UPSIDEY="); +if (pstr!=NULL) +{ +strncpy(upy,(char *)(pstr+strlen("UPSIDEY=")),4); + +i=0; +while (i<4) + { + if (upy[i]<0x20) + { + upy[i]=0; + swapy = myatoi(upy); + break; + } + i++; + } +} + +//find V_SHIFT +pstr=NULL; +pstr=strstr((const char*)cmd,(const char*)"V_SHIFT="); +if (pstr!=NULL) +{ +strncpy(vsh,(char *)(pstr+strlen("V_SHIFT=")),4); +i=0; +while (i<4) + { + if (vsh[i]<0x20) + { + vsh[i]=0; + v_shift = myatoi(vsh); + break; + } + i++; + } +} + +//find H_SHIFT +pstr=NULL; +pstr=strstr((const char*)cmd,(const char*)"H_SHIFT="); +if (pstr!=NULL) +{ +strncpy(hsh,(char *)(pstr+strlen("H_SHIFT=")),4); +i=0; +while (i<4) + { + if (hsh[i]<0x20) + { + hsh[i]=0; + h_shift = myatoi(hsh); + break; + } + i++; + } +} +//v_flag +pstr=NULL; +pstr=strstr((const char*)cmd,(const char*)"V_FLAG="); +if (pstr!=NULL) +{ +strncpy(hsh,(char *)(pstr+strlen("V_FLAG=")),4); + +i=0; +while (i<4) + { + if (hsh[i]<0x20) + { + hsh[i]=0; + v_flag = myatoi(hsh); + break; + } + i++; + } +} + +//H_flag +pstr=NULL; +pstr=strstr((const char*)cmd,(const char*)"H_FLAG="); +if (pstr!=NULL) +{ +strncpy(hsh,(char *)(pstr+strlen("H_FLAG=")),4); +i=0; +while (i<4) + { + if (hsh[i]<0x20) + { + hsh[i]=0; + h_flag = myatoi(hsh); + break; + } + i++; + } +} + +printk("%d\n",v_flag); +printk("%d\n",h_flag); +printk("%d\n",swapx); +printk("%d\n",swapy); +printk("%d\n",v_shift); +printk("%d\n",h_shift); +} + +static void DeleteAllSpace(char *cmd) +{ +char tmp[256]; +int i=0; +int j=0; +memset((char *)&tmp,0,256); +for (i=0;i<250;i++) + { + //printk("%02x ",cmd[i]&0xff); + + if ((cmd[i]!=0x09) && (cmd[i]!=0x20)) + { + tmp[j]=cmd[i]; + j++; + } + } +//printk("%s\n",cmd); + +//printk("\n"); +tmp[j]=0; +//for (i=0;i<250;i++) +// { + //printk("%02x ",tmp[i]&0xff); +// } +//printk("%s\n",tmp); + +strncpy(cmd,tmp,250); +} + +static int myatoi(char *str) +{ +int i; +int num=0; +int len = strlen(str); + + +for (i=0;i +#endif + +#include + +#ifndef errlog +#define errlog(fmt, args...) printk(KERN_ERR "[%s:%d]: " fmt, __FUNCTION__, __LINE__ ,## args) +#endif + + +//#define DEBUG_TOUCH + +#undef dbg +#ifdef DEBUG_TOUCH +#define dbg(fmt, args...) printk(KERN_ERR "[%s:%d]: " fmt, __FUNCTION__, __LINE__ ,## args) +#else +#define dbg(fmt, args...) +#endif + +#undef MSM_GPIO_TO_INT +#define MSM_GPIO_TO_INT(a) (a) + + + + +#define I2C_TOUCH_NAME "SN310M" +#define I2C_SEND_MAX_SIZE 512 // I2C Send/Receive data max size + +//-------------------------------------------- +// Button struct (1 = press, 0 = release) +//-------------------------------------------- +typedef struct button__t { + unsigned char bt0_press :1; // lsb + unsigned char bt1_press :1; + unsigned char bt2_press :1; + unsigned char bt3_press :1; + unsigned char bt4_press :1; + unsigned char bt5_press :1; + unsigned char bt6_press :1; + unsigned char bt7_press :1; // msb +} __attribute__ ((packed)) button_t; + +typedef union button__u { + unsigned char ubyte; + button_t bits; +} __attribute__ ((packed)) button_u; + +//-------------------------------------------- +// Touch Event type define +//-------------------------------------------- +#define TS_EVENT_UNKNOWN 0x00 +#define TS_EVENT_PRESS 0x01 +#define TS_EVENT_MOVE 0x02 +#define TS_EVENT_RELEASE 0x03 + +typedef struct finger__t { + unsigned int status; // true : ts data updated, false : no update data + unsigned int event; // ts event type + unsigned int id; // ts received id + unsigned int x; // ts data x + unsigned int y; // ts data y + unsigned int area; // ts finger area + unsigned int pressure; // ts finger pressure +} __attribute__ ((packed)) finger_t; + +struct touch { + int irq; + struct i2c_client *client; + struct touch_pdata *pdata; + struct input_dev *input; + char phys[32]; + + finger_t *finger; // finger data + struct mutex mutex; + + // sysfs control flags + unsigned char disabled; // interrupt status + unsigned char fw_version; + + unsigned char *fw_buf; + unsigned int fw_size; + int fw_status; + + // irq func used + struct workqueue_struct *work_queue; + struct work_struct work; + + // noise filter work + struct delayed_work filter_dwork; + +#if defined(CONFIG_HAS_EARLYSUSPEND) + struct early_suspend power; +#endif +}; + +struct i2c_client; +struct input_dev; +struct device; + +#define IRQ_MODE_THREAD 0 +#define IRQ_MODE_NORMAL 1 +#define IRQ_MODE_POLLING 2 + +//-------------------------------------------- +// IRQ type & trigger action +//-------------------------------------------- +// +// IRQF_TRIGGER_RISING, IRQF_TRIGGER_FALLING, IRQF_TRIGGER_HIGH, IRQF_TRIGGER_LOW +// IRQF_DISABLED, IRQF_SHARED, IRQF_IRQPOLL, IRQF_ONESHOT, IRQF_NO_THREAD +// +//-------------------------------------------- +struct touch_pdata { + char *name; // input drv name + + int irq_gpio; // irq gpio define + int reset_gpio; // reset gpio define + int reset_level; // reset level setting (1 = High reset, 0 = Low reset) + + int irq_mode; // IRQ_MODE_THREAD, IRQ_MODE_NORMAL, IRQ_MODE_POLLING + int irq_flags; // irq flags setup : Therad irq mode(IRQF_TRIGGER_HIGH | IRQF_ONESHOT) + + int abs_max_x, abs_max_y; + int abs_min_x, abs_min_y; + + int area_max, area_min; + int press_max, press_min; + int id_max, id_min; + + int vendor, product, version; + + int max_fingers; + + int *keycode, keycnt; + int lcd_exchg; + + //-------------------------------------------- + // Control function + //-------------------------------------------- + void (*gpio_init) (void); // gpio early-init function + + irqreturn_t (*irq_func) (int irq, void *handle); + void (*touch_work) (struct touch *ts); + + void (*report) (struct touch *ts); + void (*key_report) (struct touch *ts, unsigned char button_data); + + int (*early_probe) (struct touch *ts); + int (*probe) (struct touch *ts); + void (*enable) (struct touch *ts); + void (*disable) (struct touch *ts); + int (*input_open) (struct input_dev *input); + void (*input_close) (struct input_dev *input); + + void (*event_clear) (struct touch *ts); + +#ifdef CONFIG_HAS_EARLYSUSPEND + void (*resume) (struct early_suspend *h); + void (*suspend) (struct early_suspend *h); +#endif + + /* by limst, added to control power for touch IC */ + int (*power) (int on); + + //-------------------------------------------- + // I2C control function + //-------------------------------------------- + int (*i2c_write) (struct i2c_client *client, unsigned char *cmd, unsigned int cmd_len, unsigned char *data, unsigned int len); + int (*i2c_read) (struct i2c_client *client, unsigned char *cmd, unsigned int cmd_len, unsigned char *data, unsigned int len); + + //-------------------------------------------- + // Firmware update control function + //-------------------------------------------- + char *fw_filename; + int fw_filesize; + + int (*i2c_boot_write) (struct i2c_client *client, unsigned char *cmd, unsigned int cmd_len, unsigned char *data, unsigned int len); + int (*i2c_boot_read) (struct i2c_client *client, unsigned char *cmd, unsigned int cmd_len, unsigned char *data, unsigned int len); + int (*fw_control) (struct touch *ts, unsigned int fw_status); + int (*flash_firmware) (struct device *dev, const char *fw_name); + + //-------------------------------------------- + // Calibration control function + //-------------------------------------------- + int (*calibration) (struct touch *ts); +}; + +#endif // __TOUCH_PDATA_H + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/semisens/sn310m-touch.c b/ANDROID_3.4.5/drivers/input/touchscreen/semisens/sn310m-touch.c new file mode 100755 index 00000000..81275baf --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/semisens/sn310m-touch.c @@ -0,0 +1,332 @@ +/**************************************************************** + * + * sn310m-touch.c : I2C Touchscreen driver (platform data struct) + * + * Copyright (c) 2013 SEMISENS Co.,Ltd + * http://www.semisens.com + * + ****************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +//---------------------------------------------- +#include "sn310m-touch-pdata.h" +#include "sn310m-touch.h" +#include "touch.h" + + +//---------------------------------------------- +unsigned char sn310m_id_tracking(struct touch *ts, unsigned char find_id); + +//---------------------------------------------- +// Touch i2c control function +//---------------------------------------------- +int sn310m_i2c_read(struct i2c_client *client, unsigned char *cmd, unsigned int cmd_len, unsigned char *data, unsigned int len) +{ + struct i2c_msg msg[2]; + int ret = 0; + unsigned char i = 0; + unsigned char cmd_tmp[10] = {0, }; + + if((len == 0) || (data == NULL)) { + dev_err(&client->dev, "I2C read error: Null pointer or length == 0\n"); + return -1; + } + + memset(cmd_tmp, 0x00, sizeof(cmd_tmp)); + + if(cmd_len) { + for(i = 0; i < cmd_len; i++) { + cmd_tmp[i] = cmd[cmd_len -1 -i]; + } + } + + memset(msg, 0x00, sizeof(msg)); + msg[0].addr = client->addr; + msg[0].flags = client->flags & I2C_M_TEN; + msg[0].len = cmd_len; + msg[0].buf = cmd_tmp; + + msg[1].addr = client->addr; + msg[1].flags = client->flags & I2C_M_TEN; + msg[1].flags |= I2C_M_RD; + msg[1].len = len; + msg[1].buf = data; + + if((ret = i2c_transfer(client->adapter, msg, 2)) != 2) { + dev_err(&client->dev, "I2C read error: (%d) reg: 0x%X len: %d\n", ret, cmd_tmp[0], len); + return -EIO; + } + + return len; +} + +int sn310m_i2c_write(struct i2c_client *client, unsigned char *cmd, unsigned int cmd_len, unsigned char *data, unsigned int len) +{ + int ret = 0; + unsigned char block_data[10] = {0, }; + unsigned char i = 0; + unsigned char cmd_tmp[10] = {0, }; + + if((cmd_len + len) >= sizeof(block_data)) { + dev_err(&client->dev, "I2C write error: wdata overflow reg: 0x%X len: %d\n", cmd[0], cmd_len + len); + return -1; + } + + memset(block_data, 0x00, sizeof(block_data)); + memset(cmd_tmp, 0x00, sizeof(cmd_tmp)); + + if(cmd_len) { + for(i = 0; i < cmd_len; i++) { + cmd_tmp[i] = cmd[cmd_len -1 -i]; + } + } + + if(cmd_len) + memcpy(&block_data[0], &cmd_tmp[0], cmd_len); + + if(len) + memcpy(&block_data[cmd_len], &data[0], len); + + if((ret = i2c_master_send(client, block_data, (cmd_len + len))) < 0) { + dev_err(&client->dev, "I2C write error: (%d) reg: 0x%X len: %d\n", ret, cmd[0], len); + return ret; + } + + return len; +} + +//---------------------------------------------- +// Touch initialize & finalize function +//---------------------------------------------- +int sn310m_input_open(struct input_dev *input) +{ + struct touch *ts = input_get_drvdata(input); + + dbg("%s\n", __func__); + + ts->pdata->enable(ts); + + return 0; +} + +void sn310m_enable(struct touch *ts) +{ + unsigned short cmd = REG_TS_STATUS; + unsigned int rdata = 0; + dbg("sn310m_enable++\n"); + if(ts->disabled) { + while(!gpio_get_value(ts->pdata->irq_gpio)) + ts->pdata->i2c_read(ts->client, (unsigned char *)&cmd, sizeof(cmd), (unsigned char *)&rdata, sizeof(rdata)); + wmt_gpio_set_irq_type(ts->pdata->irq_gpio, IRQ_TYPE_EDGE_FALLING); + wmt_gpio_unmask_irq(ts->pdata->irq_gpio); + dbg("enable_irq (%d)\n",ts->irq); + ts->disabled = false; + } + dbg("sn310m_enable--\n"); +} + +void sn310m_disable(struct touch *ts) +{ + dbg("sn310m_disable++\n"); + if(!ts->disabled) { + //disable_irq(ts->irq);//wmt_gpio_mask_irq(ts->pdata->irq_gpio);// + wmt_gpio_mask_irq(ts->pdata->irq_gpio); + dbg("disable_irq(ts->irq);\n"); + ts->disabled = true; + if(ts->pdata->event_clear){ + ts->pdata->event_clear(ts); + } + } + dbg("sn310m_disable--"); +} + +int sn310m_early_probe(struct touch *ts) +{ + // nothing to do... + + return 0; +} + +int sn310m_probe(struct touch *ts) +{ + unsigned short cmd = REG_FIRMWARE_VERSION; + unsigned short rdata = 0; + + if(ts->pdata->i2c_read(ts->client, (unsigned char *)&cmd, sizeof(cmd), (unsigned char *)&rdata, sizeof(rdata)) < 0) { + errlog("fail to get touch ic firmware version.\n"); + return -1; + } + + ts->fw_version = rdata; + + dbg("touch ic firmware version : %d \n", rdata); + + return 0; +} + +//---------------------------------------------- +// calibration function +//---------------------------------------------- +int sn310m_calibration(struct touch *ts) +{ + // nothing to do... + + return 0; +} + +#define SN310M_NATIVE_INTERFACE +#if defined(SN310M_NATIVE_INTERFACE) +#include +extern int g_MiscInitialize; +#endif + +//---------------------------------------------- +// Touch data processing function +//---------------------------------------------- +void sn310m_work(struct touch *ts) +{ + unsigned char find_slot = 0; + unsigned short cmd = 0; + status_reg_u status; + data_reg_t data; + button_u button; + unsigned int ids = 0; + int i = 0; + + mutex_lock(&ts->mutex); + + cmd = REG_TS_STATUS; + ts->pdata->i2c_read(ts->client, (unsigned char *)&cmd, sizeof(cmd), (unsigned char *)&status.uint, sizeof(status_reg_u)); + + if(status.bits.ts_cnt <= ts->pdata->max_fingers) { + unsigned char cnt = 0; + + if(ts->pdata->keycode && (status.bits.ts_cnt == 0)) { + button.bits.bt0_press = (status.bits.button & 0x01) ? 1 : 0; + button.bits.bt1_press = (status.bits.button & 0x02) ? 1 : 0; + button.bits.bt2_press = (status.bits.button & 0x04) ? 1 : 0; + button.bits.bt3_press = (status.bits.button & 0x08) ? 1 : 0; + + ts->pdata->key_report(ts, button.ubyte); + } + + for(cnt = 0; cnt < status.bits.ts_cnt; cnt++) { + unsigned int id; + unsigned int x; + unsigned int y; + unsigned int area; + unsigned int pressure; + + cmd = REG_TS_DATA(cnt); + ts->pdata->i2c_read(ts->client, (unsigned char *)&cmd, sizeof(cmd), (unsigned char *)&data.packet0, sizeof(data_reg_t)); + + id = data.packet0 >> 12; + x = data.packet0 & 0xfff; + y = data.packet1 & 0xfff; + area = data.packet2 & 0xfff; + pressure = ((data.packet1 >> 8) & 0x00f0) + (data.packet2 >> 12); + + dbg("DEBUG(%s) : cmd=%d, id=%d, x=%d, y=%d, area=%d, pressure=%d \n", __func__, cmd, id, x, y, area, pressure); + dbg("DEBUG(%s) : pkt0=%x pkt1=%x pkt2=%x \n", __func__, data.packet0, data.packet1, data.packet2); + + if((x >= ts->pdata->abs_max_x) || (y >= ts->pdata->abs_max_y)) { + if(ts->pdata->event_clear) + ts->pdata->event_clear(ts); + + dbg("ERROR(%s) : x(%d) or y(%d) value overflow!\n", __func__, x, y); + continue; + } + + if(ts->pdata->id_max) { + if((id >= ts->pdata->id_max) || (id < ts->pdata->id_min)) { + if(ts->pdata->event_clear) + ts->pdata->event_clear(ts); + + dbg("ERROR(%s) : id(%d) value overflow!\n", __func__, id); + continue; + } + if((find_slot = sn310m_id_tracking(ts, id)) == 0xFF) { + dbg("ERROR(%s) : Empty slot not found\n", __func__); + continue; + } + } + else { + if(id == 0) + continue; + + find_slot = cnt; + } + + if(ts->finger[find_slot].event == TS_EVENT_UNKNOWN) + ts->finger[find_slot].event = TS_EVENT_PRESS; + else if((ts->finger[find_slot].event == TS_EVENT_PRESS) || (ts->finger[find_slot].event == TS_EVENT_MOVE)) + ts->finger[find_slot].event = TS_EVENT_MOVE; + + if (ts->pdata->lcd_exchg) { + int tmp; + tmp = x; + x = y; + y = ts->pdata->abs_max_x - tmp; + } + + ts->finger[find_slot].status = true; + ts->finger[find_slot].id = id; + ts->finger[find_slot].x = x; + ts->finger[find_slot].y = y; + ts->finger[find_slot].area = (ts->pdata->area_max < area) ? ts->pdata->area_max : area; + ts->finger[find_slot].pressure = (ts->pdata->press_max < pressure) ? ts->pdata->press_max : pressure; + ids |= 1 << find_slot; + } + } + + for(i = 0; i < ts->pdata->max_fingers; i++) { + if(!(ids & (1 << i))) { + if(ts->finger[i].event != TS_EVENT_UNKNOWN) { + ts->finger[i].status = true; + ts->finger[i].event = TS_EVENT_RELEASE; + } + } + } + + ts->pdata->report(ts); + mutex_unlock(&ts->mutex); + wmt_gpio_unmask_irq(ts->pdata->irq_gpio); +} + +unsigned char sn310m_id_tracking(struct touch *ts, unsigned char find_id) +{ + unsigned char find_slot = 0xFF; + int i = 0; + + for(i = 0; i < ts->pdata->max_fingers; i++) { + if(ts->finger[i].id == find_id) + find_slot = i; + + if((ts->finger[i].event == TS_EVENT_UNKNOWN) && (find_slot == 0xFF)) + find_slot = i; + } + return find_slot; +} + +//---------------------------------------------- +// Firmware update Control function +//---------------------------------------------- +int sn310m_flash_firmware(struct device *dev, const char *fw_name) +{ + // nothing to do... + return 0; +} diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/semisens/sn310m-touch.h b/ANDROID_3.4.5/drivers/input/touchscreen/semisens/sn310m-touch.h new file mode 100755 index 00000000..0469bf19 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/semisens/sn310m-touch.h @@ -0,0 +1,97 @@ +/**************************************************************** + * + * sn310m-touch.c : i2c Touchscreen driver (platform data struct) + * + * Copyright (c) 2013 SEMISENS Co.,Ltd + * http://www.semisens.com + * + ****************************************************************/ +#ifndef __SN310M_TOUCH_H +#define __SN310M_TOUCH_H + +//---------------------------------------------- +// register address for firmware update +//---------------------------------------------- +#define REG_CMD_ISP_MODE 0x02F1 // 0x0200 : prepare eFlash, 0x0100 : finish eFalsh +#define REG_CMD_FLASH_BUS 0x04F1 // 0x0000 : set eFlash bus functions +#define REG_CMD_FLASH_ENABLE 0x08F1 // 0xFFFF : enable eFlash functions +#define REG_CMD_FLASH_AUTH 0x00F4 // 0x0100 : get eFlash approach authority +#define REG_CMD_FLASH_CON_EN 0x02F4 // 0x0000 : enable eFlash controller +#define REG_CMD_FLASH_COMMAND 0x04F4 // 0x0200 : erase eFlash, 0x0000 : write eFlash +#define REG_CMD_FLASH_BUSY 0x08F4 // [15] bit is busy flag for eflash eperating. + +//---------------------------------------------- +// register setting value for firmware update +//---------------------------------------------- +#define REG_SET_PREPARE_FLASH_ACCESS 0x0200 +#define REG_SET_FINISH_FLASH_ACCESS 0x0100 +#define REG_SET_ENABLE_FLASH_ERASE 0x0200 +#define REG_SET_ENABLE_FLASH_WRITE 0x0000 + +#define SN310M_MAX_FW_SIZE (10*1024) // 10 Kbytes +#define REG_FIRMWARE_VERSION (0x3EE0) + +//---------------------------------------------- +// Touch status & data register address +//---------------------------------------------- +#define REG_TS_STATUS 0x00E0 + +typedef struct status_reg__t { + unsigned int ts_cnt :4; // lsb + unsigned int reserved1 :4; + unsigned int button :5; + unsigned int reserved2 :3; // msb +} __attribute__ ((packed)) status_reg_t; + +typedef union status_reg__u { + unsigned short uint; + status_reg_t bits; +} __attribute__ ((packed)) status_reg_u; + +#define REG_TS_DATA_BASE 0x02E0 +#define REG_TS_DATA(x) (((x * 6) << 8) + REG_TS_DATA_BASE) + +typedef struct data_reg__t { + unsigned short packet0; + unsigned short packet1; + unsigned short packet2; +} __attribute__ ((packed)) data_reg_t; + +typedef union data_reg__u { + unsigned int uint; + data_reg_t bits; +} __attribute__ ((packed)) data_reg_u; + + +//---------------------------------------------- +// i2c Control function +//---------------------------------------------- +extern int sn310m_i2c_read(struct i2c_client *client, unsigned char *cmd, unsigned int cmd_len, unsigned char *data, unsigned int len); +extern int sn310m_i2c_write(struct i2c_client *client, unsigned char *cmd, unsigned int cmd_len, unsigned char *data, unsigned int len); + +//---------------------------------------------- +// Touch initialize & finalize function +//---------------------------------------------- +extern int sn310m_input_open(struct input_dev *input); +extern void sn310m_enable(struct touch *ts); +extern void sn310m_disable(struct touch *ts); +extern int sn310m_early_probe(struct touch *ts); +extern int sn310m_probe(struct touch *ts); + +//---------------------------------------------- +// Calibration function +//---------------------------------------------- +extern int sn310m_calibration(struct touch *ts); + +//---------------------------------------------- +// Touch data processing function +//---------------------------------------------- +extern void sn310m_work(struct touch *ts); + +//---------------------------------------------- +// Firmware update Control function +//---------------------------------------------- +extern int sn310m_flash_firmware(struct device *dev, const char *fw_name); + +#endif // __SN310M_TOUCH_H + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/semisens/touch.c b/ANDROID_3.4.5/drivers/input/touchscreen/semisens/touch.c new file mode 100755 index 00000000..39d6ce15 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/semisens/touch.c @@ -0,0 +1,1121 @@ +/**************************************************************** + * + * touch.c : I2C Touchscreen driver + * + * Copyright (c) 2013 SEMISENS Co.,Ltd + * http://www.semisens.com + * + ****************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//---------------------------------------------- +#if defined(CONFIG_HAS_EARLYSUSPEND) + #include + #include + #include +#endif + +//---------------------------------------------- +#include +#include "sn310m-touch-pdata.h" +#include "sn310m-touch.h" + +//---------------------------------------------- +#include "touch.h" +#include +#include + + +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); +extern int wmt_setsyspara(char *varname, unsigned char *varval); + +#define SN310M_NATIVE_INTERFACE /* This is to debug semisens TSC */ + +#if defined(SN310M_NATIVE_INTERFACE) +#include +#include +struct touch* g_ts; +int g_MiscInitialize = 0; +static int P_SN310M_Dist_Probe(struct touch* ts); +static int P_SN310M_Dist_Open(struct inode *inode, struct file *file); +static long P_SN310M_Dist_Ioctl(struct file *file, unsigned int cmd, unsigned long arg); +static void P_SN310M_Dist_Remove(void); +#endif + +// function prototype define +//---------------------------------------------- +#ifdef CONFIG_HAS_EARLYSUSPEND + static void touch_suspend(struct early_suspend *h); + static void touch_resume(struct early_suspend *h); +#endif + +irqreturn_t touch_irq(int irq, void *handle); +#if 0 /* unused */ + static void touch_work(struct touch *ts); +#endif +static void touch_work_q(struct work_struct *work); +static void touch_key_report(struct touch *ts, unsigned char button_data); +static void touch_report_protocol_a(struct touch *ts); +static void touch_report_protocol_b(struct touch *ts); +static void touch_event_clear(struct touch *ts); +#if 0 /* unused */ + static void touch_enable(struct touch *ts); + static void touch_disable(struct touch *ts); +#endif +static void touch_input_close(struct input_dev *input); +static int touch_input_open(struct input_dev *input); +static int touch_check_functionality (struct touch_pdata *pdata); +void touch_hw_reset(struct touch *ts); +int touch_info_display(struct touch *ts); +int touch_probe(struct i2c_client *client, const struct i2c_device_id *client_id); +int touch_remove(struct i2c_client *client); + + +// Kinsey: +#define WMT_TS_I2C_NAME "wmt-ts" +static struct i2c_client *l_client; + + + + +//---------------------------------------------- +irqreturn_t touch_irq(int irq, void *handle) +{ + struct touch *ts = handle; + if (gpio_irqstatus(ts->pdata->irq_gpio)){ + wmt_gpio_ack_irq(ts->pdata->irq_gpio); + if (is_gpio_irqenable(ts->pdata->irq_gpio)){ + wmt_gpio_mask_irq(ts->pdata->irq_gpio); + #ifdef CONFIG_HAS_EARLYSUSPEND + if(!ts->earlysus) + queue_work(ts->work_queue, &ts->work); + #else + queue_work(ts->work_queue, &ts->work); + #endif + } + return IRQ_HANDLED; + } + return IRQ_NONE; + +} + +//---------------------------------------------- +static void touch_work_q(struct work_struct *work) +{ + struct touch *ts = container_of(work, struct touch, work); + ts->pdata->touch_work(ts); +} + +//---------------------------------------------- +static void touch_key_report(struct touch *ts, unsigned char button_data) +{ + static button_u button_old; + button_u button_new; + + button_new.ubyte = button_data; + if(button_old.ubyte != button_new.ubyte) { + if((button_old.bits.bt0_press != button_new.bits.bt0_press) && (ts->pdata->keycnt > 0)) { + if(button_new.bits.bt0_press) input_report_key(ts->input, ts->pdata->keycode[0], true); + else input_report_key(ts->input, ts->pdata->keycode[0], false); + #if defined(DEBUG_TOUCH_KEY) + dbg("keycode[0](0x%04X) %s\n", ts->pdata->keycode[0], button_new.bits.bt0_press ? "press":"release"); + #endif + } + if((button_old.bits.bt1_press != button_new.bits.bt1_press) && (ts->pdata->keycnt > 1)) { + if(button_new.bits.bt1_press) input_report_key(ts->input, ts->pdata->keycode[1], true); + else input_report_key(ts->input, ts->pdata->keycode[1], false); + #if defined(DEBUG_TOUCH_KEY) + dbg("keycode[1](0x%04X) %s\n", ts->pdata->keycode[1], button_new.bits.bt1_press ? "press":"release"); + #endif + } + if((button_old.bits.bt2_press != button_new.bits.bt2_press) && (ts->pdata->keycnt > 2)) { + if(button_new.bits.bt2_press) input_report_key(ts->input, ts->pdata->keycode[2], true); + else input_report_key(ts->input, ts->pdata->keycode[2], false); + #if defined(DEBUG_TOUCH_KEY) + dbg("keycode[2](0x%04X) %s\n", ts->pdata->keycode[2], button_new.bits.bt2_press ? "press":"release"); + #endif + } + if((button_old.bits.bt3_press != button_new.bits.bt3_press) && (ts->pdata->keycnt > 3)) { + if(button_new.bits.bt3_press) input_report_key(ts->input, ts->pdata->keycode[3], true); + else input_report_key(ts->input, ts->pdata->keycode[3], false); + #if defined(DEBUG_TOUCH_KEY) + dbg("keycode[3](0x%04X) %s\n", ts->pdata->keycode[3], button_new.bits.bt3_press ? "press":"release"); + #endif + } + if((button_old.bits.bt4_press != button_new.bits.bt4_press) && (ts->pdata->keycnt > 4)) { + if(button_new.bits.bt4_press) input_report_key(ts->input, ts->pdata->keycode[4], true); + else input_report_key(ts->input, ts->pdata->keycode[4], false); + #if defined(DEBUG_TOUCH_KEY) + dbg("keycode[4](0x%04X) %s\n", ts->pdata->keycode[4], button_new.bits.bt4_press ? "press":"release"); + #endif + } + if((button_old.bits.bt5_press != button_new.bits.bt5_press) && (ts->pdata->keycnt > 5)) { + if(button_new.bits.bt5_press) input_report_key(ts->input, ts->pdata->keycode[5], true); + else input_report_key(ts->input, ts->pdata->keycode[5], false); + #if defined(DEBUG_TOUCH_KEY) + dbg("keycode[5](0x%04X) %s\n", ts->pdata->keycode[5], button_new.bits.bt5_press ? "press":"release"); + #endif + } + if((button_old.bits.bt6_press != button_new.bits.bt6_press) && (ts->pdata->keycnt > 6)) { + if(button_new.bits.bt6_press) input_report_key(ts->input, ts->pdata->keycode[6], true); + else input_report_key(ts->input, ts->pdata->keycode[6], false); + #if defined(DEBUG_TOUCH_KEY) + dbg("keycode[6](0x%04X) %s\n", ts->pdata->keycode[6], button_new.bits.bt6_press ? "press":"release"); + #endif + } + if((button_old.bits.bt7_press != button_new.bits.bt7_press) && (ts->pdata->keycnt > 7)) { + if(button_new.bits.bt7_press) input_report_key(ts->input, ts->pdata->keycode[7], true); + else input_report_key(ts->input, ts->pdata->keycode[7], false); + #if defined(DEBUG_TOUCH_KEY) + dbg("keycode[7](0x%04X) %s\n", ts->pdata->keycode[7], button_new.bits.bt7_press ? "press":"release"); + #endif + } + button_old.ubyte = button_new.ubyte; + } +} + +//---------------------------------------------- +static void touch_report_protocol_a(struct touch *ts) +{ + int id; + + for(id = 0; id < ts->pdata->max_fingers; id++) { + + if(ts->finger[id].event == TS_EVENT_UNKNOWN) continue; + + if(ts->finger[id].event != TS_EVENT_RELEASE) { + if(ts->pdata->id_max) input_report_abs(ts->input, ABS_MT_TRACKING_ID, ts->finger[id].id); + if(ts->pdata->area_max) input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, ts->finger[id].area ? ts->finger[id].area : 10); + if(ts->pdata->press_max) input_report_abs(ts->input, ABS_MT_PRESSURE, ts->finger[id].pressure); + + input_report_abs(ts->input, ABS_MT_POSITION_X, ts->finger[id].x); + input_report_abs(ts->input, ABS_MT_POSITION_Y, ts->finger[id].y); + dbg("%s : id = %d, x = %d, y = %d\n", __func__, ts->finger[id].id, ts->finger[id].x, ts->finger[id].y); + } + else { + ts->finger[id].event = TS_EVENT_UNKNOWN; + dbg("%s : release id = %d\n", __func__, ts->finger[id].id); + } + + input_mt_sync(ts->input); + } + + input_sync(ts->input); +} + +//---------------------------------------------- +static void touch_report_protocol_b(struct touch *ts) +{ + int id; +#if defined(DEBUG_TOUCH) + char *event_str[] = {"unknown", "press", "move", "release"}; +#endif + + for(id = 0; id < ts->pdata->max_fingers; id++) { + if((ts->finger[id].event == TS_EVENT_UNKNOWN) || (ts->finger[id].status == false)) + continue; + + input_mt_slot(ts->input, id); + ts->finger[id].status = false; + + if(ts->finger[id].event != TS_EVENT_RELEASE) { + input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, true); + + input_report_abs(ts->input, ABS_MT_TRACKING_ID, ts->finger[id].id); + input_report_abs(ts->input, ABS_MT_POSITION_X, ts->finger[id].x); + input_report_abs(ts->input, ABS_MT_POSITION_Y, ts->finger[id].y); + + if(ts->pdata->area_max) input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, ts->finger[id].area ? ts->finger[id].area : 10); + if(ts->pdata->press_max) input_report_abs(ts->input, ABS_MT_PRESSURE, ts->finger[id].pressure); + +#if defined(DEBUG_TOUCH) + dbg("%s : event = %s, slot = %d, id = %d, x = %d, y = %d\n", __func__, event_str[ts->finger[id].event], id, ts->finger[id].id, ts->finger[id].x, ts->finger[id].y); +#endif + } + else { +#if defined(DEBUG_TOUCH) + dbg("%s : event = %s, slot = %d, id = %d\n", __func__, event_str[ts->finger[id].event], id, ts->finger[id].id); +#endif + ts->finger[id].event = TS_EVENT_UNKNOWN; + input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, false); + } + } + input_sync(ts->input); +} + +//---------------------------------------------- +static void touch_event_clear(struct touch *ts) +{ + unsigned char id; + + for(id = 0; id < ts->pdata->max_fingers; id++) { + if(ts->finger[id].event == TS_EVENT_MOVE) { + ts->finger[id].status = true; + ts->finger[id].event = TS_EVENT_RELEASE; + } + } + ts->pdata->report(ts); + if(ts->pdata->keycode) + ts->pdata->key_report(ts, 0x00); +} + +//---------------------------------------------- +static int touch_input_open(struct input_dev *input) +{ + struct touch *ts = input_get_drvdata(input); + + ts->pdata->enable(ts); + + dbg("%s\n", __func__); + + return 0; +} + +//---------------------------------------------- +static void touch_input_close(struct input_dev *input) +{ + struct touch *ts = input_get_drvdata(input); + + ts->pdata->disable(ts); + + dbg("%s\n", __func__); +} + +//---------------------------------------------- +static int touch_check_functionality(struct touch_pdata *pdata) +{ + if(!pdata) { + errlog("Error : Platform data is NULL pointer!\n"); return -1; + } + + pdata->i2c_read = sn310m_i2c_read; + pdata->i2c_write = sn310m_i2c_write; + + pdata->i2c_boot_read = sn310m_i2c_read; + pdata->i2c_boot_write = sn310m_i2c_write; + + pdata->enable = sn310m_enable; + pdata->disable = sn310m_disable; + pdata->probe = sn310m_probe; + + if(!pdata->report) { + if(pdata->id_max) pdata->report = touch_report_protocol_b; + else pdata->report = touch_report_protocol_a; + } + if(!pdata->key_report) pdata->key_report = touch_key_report; + + pdata->touch_work = sn310m_work; + + if(!pdata->irq_func) pdata->irq_func = touch_irq; + + if(!pdata->event_clear) pdata->event_clear = touch_event_clear; + +#ifdef CONFIG_HAS_EARLYSUSPEND + if(!pdata->resume) pdata->resume = touch_resume; + if(!pdata->suspend) pdata->suspend = touch_suspend; +#endif + + //pdata->irq_gpio = 7; + + return 0; +} + +//---------------------------------------------- +void touch_hw_reset(struct touch *ts) +{ + if(ts->pdata->reset_gpio) { + if(gpio_request(ts->pdata->reset_gpio, "touch reset")) { + errlog("--------------------------------------------------------\n"); + errlog("%s : request port error!\n", "touch reset"); + errlog("--------------------------------------------------------\n"); + } + else { + if(ts->pdata->power) { + /* power sequence: reset low -> power on -> reset high */ + gpio_direction_output(ts->pdata->reset_gpio, 0); + gpio_set_value(ts->pdata->reset_gpio, 0); + mdelay(15); + ts->pdata->power(1); + mdelay(50); + gpio_set_value(ts->pdata->reset_gpio, 1); + mdelay(15); + } + else { + /* if there is no power control for touch, then just do reset (high -> low -> high) */ + gpio_direction_output(ts->pdata->reset_gpio, 1); + gpio_set_value(ts->pdata->reset_gpio, 1); + mdelay(15); + gpio_set_value(ts->pdata->reset_gpio, 0); + mdelay(20); + gpio_set_value(ts->pdata->reset_gpio, 1); + mdelay(15); + } + } + } +} + +//---------------------------------------------- +int touch_info_display(struct touch *ts) +{ + errlog("--------------------------------------------------------\n"); + errlog(" TOUCH SCREEN INFORMATION\n"); + errlog("--------------------------------------------------------\n"); + if(ts->pdata->irq_gpio) { + errlog("TOUCH INPUT Name = %s\n", ts->pdata->name); + + switch(ts->pdata->irq_mode) { + default : + case IRQ_MODE_THREAD: errlog("TOUCH IRQ Mode = %s\n", "IRQ_MODE_THREAD"); break; + case IRQ_MODE_NORMAL: errlog("TOUCH IRQ Mode = %s\n", "IRQ_MODE_NORMAL"); break; + case IRQ_MODE_POLLING: errlog("TOUCH IRQ Mode = %s\n", "IRQ_MODE_POLLING"); break; + } + errlog("TOUCH F/W Version = %d.%02d\n", ts->fw_version / 100, ts->fw_version % 100); + errlog("TOUCH FINGRES MAX = %d\n", ts->pdata->max_fingers); + errlog("TOUCH ABS X MAX = %d, TOUCH ABS X MIN = %d\n", ts->pdata->abs_max_x, ts->pdata->abs_min_x); + errlog("TOUCH ABS Y MAX = %d, TOUCH ABS Y MIN = %d\n", ts->pdata->abs_max_y, ts->pdata->abs_min_y); + + if(ts->pdata->area_max) + errlog("TOUCH MAJOR MAX = %d, TOUCH MAJOR MIN = %d\n", ts->pdata->area_max, ts->pdata->area_min); + + if(ts->pdata->press_max) + errlog("TOUCH PRESS MAX = %d, TOUCH PRESS MIN = %d\n", ts->pdata->press_max, ts->pdata->press_min); + + if(ts->pdata->id_max) { + errlog("TOUCH ID MAX = %d, TOUCH ID MIN = %d\n", ts->pdata->id_max, ts->pdata->id_min); + errlog("Mulit-Touch Protocol-B Used.\n"); + } + else + errlog("Mulit-Touch Protocol-A Used.\n"); + + if(ts->pdata->gpio_init) + errlog("GPIO early-init function implemented\n"); + + if(ts->pdata->reset_gpio) + errlog("H/W Reset function implemented\n"); + + #ifdef CONFIG_HAS_EARLYSUSPEND + errlog("Early-suspend function implemented\n"); + #endif + if(ts->pdata->fw_control) + errlog("Firmware update function(sysfs control) implemented\n"); + + /* flashing sample is not implemented yet */ + if(ts->pdata->flash_firmware) + errlog("Firmware update function(udev control) implemented\n"); + + if(ts->pdata->calibration) + errlog("Calibration function implemented\n"); + } + else { + errlog("TOUCH INPUT Name = %s\n", ts->pdata->name); + errlog("Dummy Touchscreen driver!\n"); + } + errlog("--------------------------------------------------------\n"); + return 0; +} + +//---------------------------------------------- +int touch_probe(struct i2c_client *client, const struct i2c_device_id *client_id) +{ + return -1; +} + +//---------------------------------------------- +// +// Power Management function +// +//---------------------------------------------- +#ifdef CONFIG_HAS_EARLYSUSPEND +static void touch_suspend(struct early_suspend *h) +{ + struct touch *ts = container_of(h, struct touch, power); + + dbg("%s++\n", __func__); + + /* TSC enters deep sleep mode */ + dbg("[%s] touch reset goes low!\n", __func__); + gpio_direction_output(ts->pdata->reset_gpio, 0); + gpio_set_value(ts->pdata->reset_gpio, 0); + + ts->pdata->disable(ts); +} + +//---------------------------------------------- +static void touch_resume(struct early_suspend *h) +{ + struct touch *ts = container_of(h, struct touch, power); + + dbg("%s++\n", __func__); + + /* TSC enters active mode */ + dbg("[%s] touch reset goes high!\n", __func__); + gpio_direction_output(ts->pdata->reset_gpio, 1); + gpio_set_value(ts->pdata->reset_gpio, 1); + + ts->pdata->enable(ts); +} +#endif + +//---------------------------------------------- +int touch_remove(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct touch *ts = dev_get_drvdata(dev); + + dbg("touch_remove++"); + + if(ts->irq) free_irq(ts->irq, ts); + + if(ts->pdata->reset_gpio) gpio_free(ts->pdata->reset_gpio); + + if(ts->pdata->irq_gpio) gpio_free(ts->pdata->irq_gpio); + + input_unregister_device(ts->input); + + dev_set_drvdata(dev, NULL); + +#if defined(SN310M_NATIVE_INTERFACE) + P_SN310M_Dist_Remove(); +#endif + + kfree(ts->finger); ts->finger = NULL; + kfree(ts); ts = NULL; + + return 0; +} + +#if defined(SN310M_NATIVE_INTERFACE) +#define SN310M_DIST_MINOR 250 + +typedef struct { + unsigned int addr; + short *buf; + unsigned int size; +} packet_t; + +static const struct file_operations SN310M_Dist_Fops = +{ + .owner = THIS_MODULE, + .open = P_SN310M_Dist_Open, + .unlocked_ioctl = P_SN310M_Dist_Ioctl, +}; + + +static struct miscdevice SN310M_Dist_MiscDev = +{ + .minor = SN310M_DIST_MINOR, + .name = "sn310m_dist", + .fops = &SN310M_Dist_Fops, + .mode = 0x666, +}; + + +static long P_SN310M_Dist_Ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + packet_t* packet = (packet_t*)arg; + int i; + + mutex_lock(&g_ts->mutex); + switch(cmd) { + case 0: // write data + if(packet->size) { + unsigned short addr = (packet->addr >> 8) | (packet->addr & 0x00ff) << 8; + g_ts->pdata->i2c_write(g_ts->client, (unsigned char *)&addr, sizeof(addr), (unsigned char *)packet->buf, packet->size*2); + dbg("Request I2C Write\n"); + } + break; + + case 1: // read data + if(packet->size) { + unsigned short addr = (packet->addr >> 8) | (packet->addr & 0x00ff) << 8; + short buffer[500] = {0, }; + + g_ts->pdata->i2c_read(g_ts->client, (unsigned char *)&addr, sizeof(addr), (unsigned char *)buffer, packet->size*2); + for(i = 0; (i < packet->size) && (i < 500); i++) { + packet->buf[i] = buffer[i]; + } + dbg("Request I2C Read\n"); + } + break; + + default: + mutex_unlock(&g_ts->mutex); + return -ENOIOCTLCMD; + } + + mutex_unlock(&g_ts->mutex); + return 0; +} + +static int P_SN310M_Dist_Open(struct inode *inode, struct file *file) +{ + return 0; +} + +static int P_SN310M_Dist_Probe(struct touch* ts) +{ + int result = 0; + + g_ts = ts; + result = misc_register(&SN310M_Dist_MiscDev); + if(result == 0) { + dbg("succeeded to register sn310m_misc_device \n"); + } + else { + errlog("failed to register sn310m_misc_device \n"); + } + + return result; +} + +static void P_SN310M_Dist_Remove(void) +{ + misc_deregister(&SN310M_Dist_MiscDev); + g_ts = NULL; +} +#endif +static const struct i2c_device_id sample_ts_id[] = { + { I2C_TOUCH_NAME, 0 }, + {}, +}; + + + +#define TS_DRIVER_NAME "wmt-touch" + +static void wmt_ts_platform_release(struct device *device) +{ + dbg("wmt_ts_platform_release\n"); + return; +} + +static struct platform_device wmt_ts_plt_device = { + .name = TS_DRIVER_NAME, + .id = 0, + .dev = { + .release = wmt_ts_platform_release, + }, +}; + +static int sn310m_keycode[] = { + KEY_HOME, KEY_MENU, KEY_BACK, KEY_SEARCH +}; + +struct touch_pdata sn310m_touch_pdata = { + + .name = "sn310m", // input drv name + .irq_gpio = 7,//SAMPLE_GPIO_0, // irq gpio define + .reset_gpio = 4,//SAMPLE_GPIO_1, // reset gpio define + .reset_level = 0, // reset level setting (1 = High reset, 0 = Low reset) + + .irq_mode = IRQ_MODE_NORMAL, // IRQ_MODE_THREAD, IRQ_MODE_NORMAL, IRQ_MODE_POLLING + .irq_flags = IRQF_SHARED ,//IRQF_TRIGGER_FALLING | IRQF_DISABLED, + + .abs_max_x = 600, + .abs_max_y = 1024, + + .area_max = 10, + .press_max = 255, + + .id_max = 10 + 1, + .id_min = 0, + + .vendor = 0x16B4, + .product = 0x0310, + .version = 0x0001, + + .max_fingers = 5, + + .keycnt = 4, + .keycode = sn310m_keycode, + .lcd_exchg = 0, + + //-------------------------------------------- + // Control function + //-------------------------------------------- + .touch_work = sn310m_work, + .enable = sn310m_enable, + .disable = sn310m_disable, + .early_probe = sn310m_early_probe, + .probe = sn310m_probe, + + //-------------------------------------------- + // I2C control function + //-------------------------------------------- + .i2c_write = sn310m_i2c_write, + .i2c_read = sn310m_i2c_read, + + //-------------------------------------------- + // Calibration function + //-------------------------------------------- + .calibration = sn310m_calibration, + + //-------------------------------------------- + // Firmware update control function + //-------------------------------------------- + .fw_filename = "sn310m_fw.bin", + .fw_filesize = (10 * 1024), // 10K bytes + .input_open = sn310m_input_open, + .flash_firmware = sn310m_flash_firmware, +}; + + +int temp; +static int wmt_ts_probe(struct platform_device *pdev) +{ + int rc = -1; + struct i2c_client *client = l_client; + struct device *dev = &client->dev; + struct touch *ts; + + + dbg("wmt_ts_probe\n"); + + if(!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_err(&client->dev, "i2c byte data not supported\n"); + return -EIO; + } + + + client->dev.platform_data = &sn310m_touch_pdata; + + if(touch_check_functionality(client->dev.platform_data) < 0) { + dev_err(&client->dev, "Platform data is not available!\n"); + return -EINVAL; + } + + if(!(ts = kzalloc(sizeof(struct touch), GFP_KERNEL))) { + errlog("touch struct malloc error!\n"); + return -ENOMEM; + } + ts->client = client; + ts->pdata = client->dev.platform_data; + + + /* by limst, setting gpio for IRQ */ + if(ts->pdata->irq_gpio) { + int ret; + + ts->irq = IRQ_GPIO;//MSM_GPIO_TO_INT(ts->pdata->irq_gpio); + dbg("IRQ_GPIO(%d) IRQ(%d) REG\n", ts->pdata->irq_gpio, ts->irq); + + ret = gpio_request(ts->pdata->irq_gpio, "touch_int"); + if(ret < 0) + errlog("FAIL: touch_int gpio_request\n"); + else + dbg("OK: touch_int gpio_request value(%d)\n", gpio_get_value(ts->pdata->irq_gpio)); + + wmt_gpio_setpull(ts->pdata->irq_gpio,WMT_GPIO_PULL_UP); + gpio_direction_input(ts->pdata->irq_gpio); + wmt_gpio_set_irq_type(ts->pdata->irq_gpio, IRQ_TYPE_EDGE_FALLING); + } + + i2c_set_clientdata(client, ts); + + if(ts->pdata->max_fingers) { + if(!(ts->finger = kzalloc(sizeof(finger_t) * ts->pdata->max_fingers, GFP_KERNEL))) { + kfree(ts); + errlog("touch data struct malloc error!\n"); + return -ENOMEM; + } + } + + if(ts->pdata->gpio_init) ts->pdata->gpio_init(); + + if(ts->pdata->early_probe) { + if((rc = ts->pdata->early_probe(ts)) < 0) + goto err_free_mem; + } + + + dev_set_drvdata(dev, ts); + + if(!(ts->input = input_allocate_device())) + goto err_free_mem; + + snprintf(ts->phys, sizeof(ts->phys), "%s/input0", ts->pdata->name); + + if(!ts->pdata->input_open) ts->input->open = touch_input_open; + else ts->input->open = ts->pdata->input_open; + if(!ts->pdata->input_close) ts->input->close = touch_input_close; + else ts->input->close = ts->pdata->input_close; + + /* + * by limst, for the test purpose, + * input device's name is forcedly set to the name of android idc file + */ + ts->input->name = "qwerty";//idc's filename //"touch_dev"; + //ts->input->name = ts->pdata->name; + ts->input->phys = ts->phys; + ts->input->dev.parent = dev; + ts->input->id.bustype = BUS_I2C; + + ts->input->id.vendor = ts->pdata->vendor; + ts->input->id.product = ts->pdata->product; + ts->input->id.version = ts->pdata->version; + + set_bit(EV_SYN, ts->input->evbit); + set_bit(EV_ABS, ts->input->evbit); + + /* Register Touch Key Event */ + if(ts->pdata->keycode) { + int key; + + set_bit(EV_KEY, ts->input->evbit); + + for(key = 0; key < ts->pdata->keycnt; key++) { + if(ts->pdata->keycode[key] <= 0) continue; + set_bit(ts->pdata->keycode[key] & KEY_MAX, ts->input->keybit); + } + } + + input_set_drvdata(ts->input, ts); + + if (sn310m_touch_pdata.lcd_exchg) { + input_set_abs_params(ts->input, ABS_MT_POSITION_X, ts->pdata->abs_min_y, ts->pdata->abs_max_y, 0, 0); + input_set_abs_params(ts->input, ABS_MT_POSITION_Y, ts->pdata->abs_min_x, ts->pdata->abs_max_x, 0, 0); + } else { + input_set_abs_params(ts->input, ABS_MT_POSITION_X, ts->pdata->abs_min_x, ts->pdata->abs_max_x, 0, 0); + input_set_abs_params(ts->input, ABS_MT_POSITION_Y, ts->pdata->abs_min_y, ts->pdata->abs_max_y, 0, 0); + } + + if(ts->pdata->area_max) + input_set_abs_params(ts->input, ABS_MT_TOUCH_MAJOR, ts->pdata->area_min, ts->pdata->area_max, 0, 0); + + if(ts->pdata->press_max) + input_set_abs_params(ts->input, ABS_MT_PRESSURE, ts->pdata->press_min, ts->pdata->press_max, 0, 0); + + if(ts->pdata->id_max) { + input_set_abs_params(ts->input, ABS_MT_TRACKING_ID, ts->pdata->id_min, ts->pdata->id_max, 0, 0); + input_mt_init_slots(ts->input, ts->pdata->max_fingers); + } + + + mutex_init(&ts->mutex); + if(ts->irq) { + switch(ts->pdata->irq_mode) { + default : + case IRQ_MODE_THREAD: + INIT_WORK(&ts->work, touch_work_q); + if((ts->work_queue = create_singlethread_workqueue("work_queue")) == NULL) + goto err_free_input_mem; + + if((rc = request_threaded_irq(ts->irq, NULL, ts->pdata->irq_func, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, ts->pdata->name, ts))) { + dev_err(dev, "threaded irq %d request fail!\n", ts->irq); + goto err_free_input_mem; + } + break; + case IRQ_MODE_NORMAL: + INIT_WORK(&ts->work, touch_work_q); + if((ts->work_queue = create_singlethread_workqueue("work_queue")) == NULL) + goto err_free_input_mem; + + if((rc = request_irq(ts->irq, ts->pdata->irq_func, ts->pdata->irq_flags, ts->pdata->name, ts))) { + errlog("irq %d request fail!\n", ts->irq); + goto err_free_input_mem; + } + dbg("irq %d request ok!\n", ts->irq); + break; + case IRQ_MODE_POLLING: + errlog("Error IRQ_MODE POLLING!! but defined irq_gpio\n"); + break; + } /* end of switch */ + } + ts->disabled = true; + + if((rc = input_register_device(ts->input))) { + dev_err(dev, "(%s) input register fail!\n", ts->input->name); + goto err_free_input_mem; + } + + /* by limst, added to turn on the power and reset of Touch IC */ + touch_hw_reset(ts); + +#if defined(CONFIG_HAS_EARLYSUSPEND) + if(ts->pdata->suspend) ts->power.suspend = ts->pdata->suspend; + if(ts->pdata->resume) ts->power.resume = ts->pdata->resume; + + ts->power.level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 1; + + register_early_suspend(&ts->power); +#endif + + if(ts->pdata->probe) { + ts->pdata->probe(ts); + } + + touch_info_display(ts); + +#if defined(SN310M_NATIVE_INTERFACE) + if(P_SN310M_Dist_Probe(ts) < 0) { + errlog("P_SN310M_Dist_Probe(), fail\n"); + } +#endif + + return 0; + + free_irq(ts->irq, ts); + input_unregister_device(ts->input); + err_free_input_mem: + input_free_device(ts->input); + ts->input = NULL; + err_free_mem: + kfree(ts->finger); + ts->finger = NULL; + kfree(ts); + ts = NULL; + return rc; +} + +static int wmt_ts_remove(struct platform_device *pdev) +{ + struct i2c_client *client = l_client; + struct device *dev = &client->dev; + struct touch *ts = dev_get_drvdata(dev); + + dbg("wmt_ts_remove\n"); + + if(ts->irq) free_irq(ts->irq, ts); + + if(ts->pdata->reset_gpio) gpio_free(ts->pdata->reset_gpio); + + if(ts->pdata->irq_gpio) gpio_free(ts->pdata->irq_gpio); + + input_unregister_device(ts->input); + + dev_set_drvdata(dev, NULL); + + #if defined(SN310M_NATIVE_INTERFACE) + P_SN310M_Dist_Remove(); + #endif + + kfree(ts->finger); ts->finger = NULL; + kfree(ts); ts = NULL; + + return 0; +} + +static int wmt_ts_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct i2c_client *client = l_client; + struct device *dev = &client->dev; + struct touch *ts = dev_get_drvdata(dev); + + dbg("%s++\n", __func__); + + /* TSC enters deep sleep mode */ + dbg("[%s] touch reset goes low!\n", __func__); + gpio_direction_output(ts->pdata->reset_gpio, 0); + gpio_set_value(ts->pdata->reset_gpio, 0); + + + ts->pdata->disable(ts); + + return 0; +} +static int wmt_ts_resume(struct platform_device *pdev) +{ + struct i2c_client *client = l_client; + struct device *dev = &client->dev; + struct touch *ts = dev_get_drvdata(dev); + + dbg("%s++\n", __func__); + + /* TSC enters active mode */ + dbg("[%s] touch reset goes high!\n", __func__); + gpio_direction_output(ts->pdata->reset_gpio, 1); + gpio_set_value(ts->pdata->reset_gpio, 1); + + ts->pdata->enable(ts); + //touch_hw_reset(ts); + + return 0; +} + + +static struct platform_driver wmt_ts_plt_driver = { + .driver = { + .name = TS_DRIVER_NAME, + .owner = THIS_MODULE, + }, + .probe = wmt_ts_probe, + .remove = wmt_ts_remove, + .suspend = wmt_ts_suspend, + .resume = wmt_ts_resume, +}; + + + +struct i2c_board_info ts_i2c_board_info = { + .type = WMT_TS_I2C_NAME, + .flags = 0x00, + .platform_data = NULL, + .archdata = NULL, + .irq = -1, +}; + +static int ts_i2c_register_device (void) +{ + struct i2c_board_info *ts_i2c_bi; + struct i2c_adapter *adapter = NULL; + + ts_i2c_board_info.addr =(unsigned short) 0x3c; + ts_i2c_bi = &ts_i2c_board_info; + adapter = i2c_get_adapter(1);/*in bus 1*/ + + if (NULL == adapter) { + errlog("can not get i2c adapter, client address error\n"); + return -1; + } + l_client = i2c_new_device(adapter, ts_i2c_bi); + if (l_client == NULL) { + errlog("allocate i2c client failed\n"); + return -1; + } + i2c_put_adapter(adapter); + return 0; +} + +static void ts_i2c_unregister_device(void) +{ + if (l_client != NULL) + { + i2c_unregister_device(l_client); + l_client = NULL; + } +} + +static struct tp_info l_tpinfo; +static int wmt_check_touch_env(void) +{ + int ret = 0; + int len = 127; + char retval[200] = {0}; + char *p=NULL; + char *s=NULL; + int Enable=0; + + // Get u-boot parameter + ret = wmt_getsyspara("wmt.io.touch", retval, &len); + if(ret){ + errlog("Read wmt.io.touch Failed.\n"); + return -EIO; + } + memset(&l_tpinfo,0,sizeof(l_tpinfo)); + + p = retval; + sscanf(p,"%d:", &Enable); + p = strchr(p,':'); + p++; + s = strchr(p,':'); + strncpy(l_tpinfo.name,p, (s-p)); + p = s+1; + //dbg("ts_name=%s\n", l_tpinfo.name); + + ret = sscanf(p,"%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", + &l_tpinfo.irq_gpio,&l_tpinfo.panelres_x,&l_tpinfo.panelres_y,&l_tpinfo.rst_gpio, + &(l_tpinfo.xaxis),&(l_tpinfo.xdir),&(l_tpinfo.ydir), + &(l_tpinfo.max_finger_num),&l_tpinfo.i2caddr,&l_tpinfo.low_Impendence_mode,&l_tpinfo.download_option); + + if (ret < 8){ + errlog("Wrong format ts u-boot param(%d)!\nwmt.io.touch=%s\n",ret,retval); + return -ENODEV; + } + + //check touch enable + if(Enable == 0){ + errlog("Touch Screen Is Disabled.\n"); + return -ENODEV; + } + if (strstr(l_tpinfo.name, sn310m_touch_pdata.name) == NULL){ + errlog("Can't find %s in the wmt.io.touch\n", sn310m_touch_pdata.name); + return -ENODEV; + } + + errlog("p.x = %d, p.y = %d, gpio=%d, resetgpio=%d,xaxis=%d,xdir=%d,ydri=%d,maxfingernum=%d,,i2c_addr=0x%X,low_Impendence_mode=%d,s_download_option=%d\n", + l_tpinfo.panelres_x, l_tpinfo.panelres_y, l_tpinfo.irq_gpio, l_tpinfo.rst_gpio, + l_tpinfo.xaxis,l_tpinfo.xdir,l_tpinfo.ydir, + l_tpinfo.max_finger_num,l_tpinfo.i2caddr,l_tpinfo.low_Impendence_mode,l_tpinfo.download_option); + + sn310m_touch_pdata.irq_gpio = l_tpinfo.irq_gpio; + sn310m_touch_pdata.reset_gpio = l_tpinfo.rst_gpio; + sn310m_touch_pdata.abs_max_x = l_tpinfo.panelres_x; + sn310m_touch_pdata.abs_max_y = l_tpinfo.panelres_y; + + memset(retval,0,sizeof(retval)); + ret = wmt_getsyspara("wmt.display.fb0", retval, &len); + if (!ret) { + int tmp[6]; + p = retval; + sscanf(p, "%d:[%d:%d:%d:%d:%d", &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5]); + if (tmp[4] > tmp[5]) + sn310m_touch_pdata.lcd_exchg = 1; + } + + return 0; +} + + +static int __init sample_touch_init(void) +{ + int ret = 0; + + if(wmt_check_touch_env()) + return -ENODEV; + + + if (ts_i2c_register_device()<0){ + errlog("Error to run ts_i2c_register_device()!\n"); + return -1; + } + + ret = platform_device_register(&wmt_ts_plt_device); + if(ret){ + errlog("wmt ts plat device register failed!\n"); + return ret; + } + ret = platform_driver_register(&wmt_ts_plt_driver); + if(ret){ + errlog("can not register platform_driver_register\n"); + platform_device_unregister(&wmt_ts_plt_device); + return ret; + } + return 0; +} + +static void sample_touch_exit(void) +{ + platform_driver_unregister(&wmt_ts_plt_driver); + platform_device_unregister(&wmt_ts_plt_device); + ts_i2c_unregister_device(); + + return; +} + + +module_init(sample_touch_init); +module_exit(sample_touch_exit); + +#ifndef MODULE +__initcall(sample_touch_init); +#endif + + + +MODULE_AUTHOR("SEMISENS Co., Ltd."); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Touchscreen Driver for SN310M"); diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/semisens/touch.h b/ANDROID_3.4.5/drivers/input/touchscreen/semisens/touch.h new file mode 100755 index 00000000..750112ea --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/semisens/touch.h @@ -0,0 +1,54 @@ +/**************************************************************** + * + * touch.c : I2C Touchscreen driver + * + * Copyright (c) 2013 SEMISENS Co.,Ltd + * http://www.semisens.com + * + ****************************************************************/ +#ifndef _TOUCH_H_ +#define _TOUCH_H_ + +//---------------------------------------------- +// extern function define +//---------------------------------------------- +extern void touch_hw_reset(struct touch *ts); +extern int touch_info_display(struct touch *ts); +#if 0 /* depends on kernel version */ +extern int touch_probe(struct i2c_client *client); +extern int touch_remove(struct device *dev); +#else +extern int touch_probe(struct i2c_client *client, const struct i2c_device_id *client_id); +extern int touch_remove(struct i2c_client *client); +#endif + +struct tp_info +{ + char name[64]; + unsigned int xaxis; //0: x, 1: x swap with y + unsigned int xdir; // 1: positive,-1: revert + unsigned int ydir; // 1: positive,-1: revert + unsigned int max_finger_num; + unsigned int download_option; // 0: disable 1:force download 2:force cancel download + unsigned int low_Impendence_mode; // 0: High Impendence Mode 1: Low Impendence Mode + unsigned int irq_gpio; + unsigned int rst_gpio; + unsigned int panelres_x; + unsigned int panelres_y; + unsigned int i2caddr; + unsigned int lcd_exchg; +#if 0 + struct input_dev *inputdev; + struct work_struct int_work; + struct i2c_client *i2cclient; + struct workqueue_struct *wq; +#if SUPPORT_TS_KEY + int key_num; +#endif +#endif + +}; + + + +#endif /* _TOUCH_H_ */ diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/sis_usbhid_ts/Kconfig b/ANDROID_3.4.5/drivers/input/touchscreen/sis_usbhid_ts/Kconfig new file mode 100755 index 00000000..21574ec3 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/sis_usbhid_ts/Kconfig @@ -0,0 +1,16 @@ +# +# SIS USB capacity touch screen driver configuration +# +config TOUCHSCREEN_SIS + tristate "SIS USB Capacitive Touchscreen Input Driver Support" + depends on ARCH_WMT + default y + help + Say Y here if you have an WMT based board with touchscreen + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called s_wmt_ts_sis + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/sis_usbhid_ts/Makefile b/ANDROID_3.4.5/drivers/input/touchscreen/sis_usbhid_ts/Makefile new file mode 100755 index 00000000..045ea698 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/sis_usbhid_ts/Makefile @@ -0,0 +1,32 @@ +KERNELDIR=../../../../ +CROSS = arm_1103_le- +CC= $(CROSS)gcc +LD= $(CROSS)ld +STRIP = $(CROSS)strip + +DEBUG = n + +# Add your debugging flag (or not) to EXTRA_CFLAGS +ifeq ($(DEBUG),y) +# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines +DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines + +else + DEBFLAGS = -O2 -Wall +endif + +EXTRA_CFLAGS += $(DEBFLAGS) + + +MY_MODULE_NAME=s_wmt_ts_sis + +obj-m := $(MY_MODULE_NAME).o +$(MY_MODULE_NAME)-objs := hid-sis.o + +default: + $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules + $(STRIP) --strip-debug $(MY_MODULE_NAME).ko + rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions *.order *.symvers modules.builtin + +clean: + rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers modules.builtin diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/sis_usbhid_ts/hid-sis.c b/ANDROID_3.4.5/drivers/input/touchscreen/sis_usbhid_ts/hid-sis.c new file mode 100755 index 00000000..0b9cee3d --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/sis_usbhid_ts/hid-sis.c @@ -0,0 +1,1104 @@ +/* + * HID driver for sis 9237/9257 test touchscreens + * + * Copyright (c) 2008 Rafi Rubin + * Copyright (c) 2009 Stephane Chatty + * + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include +#include +#include +#include +//for i2c-bridge +#include +#include "../../../hid/usbhid/usbhid.h" +#include +#include + +#ifdef CONFIG_HID_SIS_UPDATE_FW +//for ioctl +#include +#include +#include + +#define INTERNAL_DEVICE_NAME "sis_zeus_hid_touch_device" +#define BRIDGE_DEVICE_NAME "sis_zeus_hid_bridge_touch_device" +#define SIS817_DEVICE_NAME "sis_aegis_hid_touch_device" +#define SISF817_DEVICE_NAME "sis_aegis_hid_bridge_touch_device" + +static int sis_char_devs_count = 1; /* device count */ +static int sis_char_major = 0; +static struct cdev sis_char_cdev; +static struct class *sis_char_class = NULL; +//20110111 Tammy system call for tool +static struct hid_device *hid_dev_backup = NULL; //backup address +static struct urb *backup_urb = NULL; +#endif //CONFIG_HID_SIS_UPDATE_FW + +///////////////// SIS START ///////////////// +#define USB_VENDOR_ID_SIS_TOUCH 0x1039 +#define USB_VENDOR_ID_SIS2_TOUCH 0x0457 +#define USB_PRODUCT_ID_SIS_TOUCH 0x0810 +#define USB_PRODUCT_ID_SIS2_TOUCH 0x0151 +#define USB_PRODUCT_ID_NEW_SIS2_TOUCH 0x0816 +#define USB_PRODUCT_ID_SIS9200_TOUCH 0x9200 +#define USB_PRODUCT_ID_SIS817_TOUCH 0x0817 +#define USB_PRODUCT_ID_SISF817_TOUCH 0xF817 + +//waltop id-table +#define USB_VENUS_ID_WALTOP 0x0503 +#define USB_VENUS_ID_WALTOP2 0x1040 +///////////////// SIS END ///////////////// +//#define CONFIG_HID_SIS_UPDATE_FW +//#define CONFIG_DEBUG_HID_SIS_INIT +//#define CONFIG_DEBUG_HID_SIS_SENDPOINT + +#define MAX_X 4095 +#define MAX_Y 4095 +//#define MAX_PRESSURE 2047 +#define MAX_SCANTIME 65535 +#define MAX_CONTACTID 31 + +#define MAX_POINT 10 +#define HID_DG_SCANTIME 0x000d0056 //new usage not defined in hid.h +#define REPORTID_10 0x10 +#define REPORTID_TYPE1 0x30 + +#define CTRL 0 +#define DIR_IN 0x1 + +struct Point { + u16 x, y, id, pressure, width, height; +}; + +struct sis_data { + int id, total, ReportID, scantime; + struct Point pt[MAX_POINT]; +}; + + +static int pkg_num=0; +static int idx=-1; + +/* + * this driver is aimed at two firmware versions in circulation: + * - dual pen/fingedrivers/hid/hid-sis.c:83:r single touch + * - finger multitouch, pen not working + */ + +static int sis_input_mapping(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + // No special mappings needed for the pen and single touch + if (field->physical == HID_GD_POINTER) + return -1; + + else if (field->physical && (field->physical != HID_GD_POINTER)) + return 0; + +#ifdef CONFIG_DEBUG_HID_SIS_INIT + printk (KERN_INFO "sis_input_mapping : usage->hid = %x\n", usage->hid); +#endif //CONFIG_DEBUG_HID_SIS_INIT + + switch (usage->hid & HID_USAGE_PAGE) { + case HID_UP_GENDESK: + switch (usage->hid) { + case HID_GD_X: + hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_POSITION_X); + input_set_abs_params(hi->input, ABS_X, + field->logical_minimum, field->logical_maximum, 0, 0); + return 1; + + case HID_GD_Y: + hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_POSITION_Y); + input_set_abs_params(hi->input, ABS_Y, + field->logical_minimum, field->logical_maximum, 0, 0); + return 1; + } + return 0; + + case HID_UP_DIGITIZER: + switch (usage->hid) { + /* we do not want to map these for now */ + case HID_DG_CONFIDENCE: + case HID_DG_INPUTMODE: + case HID_DG_DEVICEINDEX: + case HID_DG_CONTACTCOUNT: + case HID_DG_CONTACTMAX: + case HID_DG_INRANGE: + + //new usage for SiS817 Device(for later use) + case HID_DG_WIDTH: + //hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_TOUCH_MINOR); + //input_set_abs_params(hi->input, ABS_MT_TOUCH_MINOR, 0, 255, 0, 0); + //return 1; + case HID_DG_HEIGHT: + //hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_TOUCH_MAJOR); + //input_set_abs_params(hi->input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); + //return 1; + case HID_DG_TIPPRESSURE: + //hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_PRESSURE); + //input_set_abs_params(hi->input, ABS_MT_PRESSURE, 0, 2047, 0, 0); + //return 1; + case HID_DG_SCANTIME: + return -1; + + case HID_DG_TIPSWITCH: + hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_PRESSURE); + input_set_abs_params(hi->input, ABS_MT_PRESSURE, 0, 1, 0, 0); + return 1; + + case HID_DG_CONTACTID: + hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_TRACKING_ID); + input_set_abs_params(hi->input, ABS_MT_TRACKING_ID, 0, 127, 0, 0); + return 1; + } + return 0; + + /*case HID_UP_BUTTON: + return 0;*/ + + case 0xff000000: + /* ignore HID features */ + return -1; + + } + /* ignore buttons */ + return 0; +} + +//sis_input_mapped : unmapped usage that no use in sis_event +static int sis_input_mapped(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ +#ifdef CONFIG_DEBUG_HID_SIS_INIT + printk (KERN_INFO "sis_input_mapping : usage->hid = %x\n", usage->hid); +#endif //CONFIG_DEBUG_HID_SIS_INIT + + if (usage->type == EV_KEY || usage->type == EV_ABS) + clear_bit(usage->code, *bit); + + return 0; +} + +static void sis_event_emission(struct sis_data *nd, struct input_dev *input) +{ + int i; + bool all_touch_up = true; + for(i=0; i< nd->total; i++) + { + +#ifdef CONFIG_DEBUG_HID_SIS_SENDPOINT + printk(KERN_INFO "MT_event: finger(s)=%d, id=%d, x=%d, y=%d\n", nd->total, nd->pt[i].id, nd->pt[i].x, nd->pt[i].y); + printk(KERN_INFO "MT_event: pressure=%d, width=%d, height=%d, scantime=%d\n", nd->pt[i].pressure, nd->pt[i].width, nd->pt[i].height, nd->scantime); +#endif //CONFIG_DEBUG_HID_SIS_SENDPOINT + + //checking correction of data + if(nd->pt[i].x > MAX_X || nd->pt[i].y > MAX_Y || nd->pt[i].id > MAX_CONTACTID /*|| nd->scantime > MAX_SCANTIME*/) + { + printk(KERN_INFO "point data error : abort sending point this time"); + break; + } + + if(nd->pt[i].pressure) + { + //input_report_abs(input, ABS_MT_TOUCH_MAJOR, max(nd->pt[i].height,nd->pt[i].width)); + //input_report_abs(input, ABS_MT_TOUCH_MINOR, min(nd->pt[i].height,nd->pt[i].width)); + + input_report_abs(input, ABS_MT_PRESSURE, nd->pt[i].pressure); + input_report_abs(input, ABS_MT_POSITION_X, MAX_Y - nd->pt[i].y); + input_report_abs(input, ABS_MT_POSITION_Y, nd->pt[i].x); + input_report_abs(input, ABS_MT_TRACKING_ID, nd->pt[i].id); + input_mt_sync(input); + all_touch_up = false; + } + + if(i == (nd->total - 1) && all_touch_up == true) + input_mt_sync(input); + } + //input_sync(input); + //input_sync will be send by hid default flow +} + +static void sis_event_clear(struct sis_data *nd, int max) +{ + int i; + for(i=0; ipt[i].id = 0; + nd->pt[i].x = 0; + nd->pt[i].y = 0; + nd->pt[i].pressure = 0; + nd->pt[i].width = 0; + nd->pt[i].height = 0; + } + nd->scantime = 0; + idx = -1; + pkg_num = 0; +} + +static int sis_raw_event (struct hid_device *hid, struct hid_report *report, + u8 *raw_data, int size) +{ + struct sis_data *nd = hid_get_drvdata(hid); + nd->ReportID = raw_data[0]; + +#ifdef CONFIG_DEBUG_HID_SIS_SENDPOINT + printk(KERN_INFO "raw_event : ReportID = %d\n", nd->ReportID); +#endif //CONFIG_DEBUG_HID_SIS_SENDPOINT + + hid_set_drvdata(hid, nd); + return 0; +} + +static void sis_event_lastdata(struct hid_device *hid, struct sis_data *nd, struct input_dev *input) +{ + int pkg_n=0; + +//817 method : original format + if ( (hid->product == USB_PRODUCT_ID_SIS817_TOUCH || hid->product == USB_PRODUCT_ID_SISF817_TOUCH) && nd->ReportID == REPORTID_10) + { +#ifdef CONFIG_DEBUG_HID_SIS_SENDPOINT + printk (KERN_INFO "sis_event_lastdata : 817 original format\n"); +#endif //CONFIG_DEBUG_HID_SIS_SENDPOINT + + sis_event_emission(nd, input); + sis_event_clear(nd, MAX_POINT); + } + //817 method : Extend Class Format + else if ( (hid->product == USB_PRODUCT_ID_SIS817_TOUCH || hid->product == USB_PRODUCT_ID_SISF817_TOUCH) && nd->ReportID != REPORTID_10) + { +#ifdef CONFIG_DEBUG_HID_SIS_SENDPOINT + printk (KERN_INFO "sis_event_lastdata : 817 extend format\n"); +#endif //CONFIG_DEBUG_HID_SIS_SENDPOINT + + if(nd->total >= 6) + { + idx = 4; + pkg_num = nd->total; + } + else if(nd->total >= 1) + { + sis_event_emission(nd, input); + sis_event_clear(nd, MAX_POINT); + } + else + { + if(pkg_num >0) + { + nd->total = pkg_num; + sis_event_emission(nd, input); + pkg_n = 0; + sis_event_clear(nd, MAX_POINT); + } + else + { + sis_event_clear(nd, MAX_POINT); + } + } + } + else //816 method + { +#ifdef CONFIG_DEBUG_HID_SIS_SENDPOINT + printk (KERN_INFO "sis_event_lastdata : 816 format\n"); +#endif //CONFIG_DEBUG_HID_SIS_SENDPOINT + + if(nd->total >= 3) + { + idx = 1; + pkg_num = nd->total; + } + else if(nd->total >= 1) + { + sis_event_emission(nd, input); + sis_event_clear(nd, MAX_POINT); + } + else + { + if(pkg_num >0) + { + if((pkg_num%2)>0) + pkg_n = pkg_num+1; + else + pkg_n = pkg_num; + + if(pkg_n == (idx + 1) ) + { + nd->total = pkg_num; + sis_event_emission(nd, input); + pkg_n = 0; + sis_event_clear(nd, MAX_POINT); + } + } + else + { + sis_event_clear(nd, MAX_POINT); + } + } + } +} +/* + * this function is called upon all reports + * so that we can filter contact point information, + * decide whether we are in multi or single touch mode + * and call input_mt_sync after each point if necessary + */ +static int sis_event (struct hid_device *hid, struct hid_field *field, + struct hid_usage *usage, __s32 value) +{ + struct sis_data *nd = hid_get_drvdata(hid); + //printk (KERN_INFO "sis_event"); + + if (hid->claimed & HID_CLAIMED_INPUT) { + struct input_dev *input = field->hidinput->input; +#ifdef CONFIG_DEBUG_HID_SIS_SENDPOINT + printk (KERN_INFO "sis_event : usage->hid = %x, value = %d\n", usage->hid, value); +#endif //CONFIG_DEBUG_HID_SIS_SENDPOINT + switch (usage->hid) { + case HID_DG_INRANGE: + break; + + case HID_DG_TIPSWITCH: + idx++; + nd->pt[idx].pressure = !!value; + break; + + case HID_DG_CONTACTID: + nd->pt[idx].id = value; + break; + + case HID_GD_X: + nd->pt[idx].x = value; + break; + + case HID_GD_Y: + nd->pt[idx].y = value; + break; + + //new usage for SiS817 Extend Class Device + case HID_DG_SCANTIME: + nd->scantime = value; + if ( (nd->ReportID & 0xf0) > REPORTID_TYPE1 ) + sis_event_lastdata(hid, nd, input); + break; + + case HID_DG_WIDTH: + nd->pt[idx].width = value; + break; + + case HID_DG_HEIGHT: + nd->pt[idx].height = value; + break; + + case HID_DG_TIPPRESSURE: + nd->pt[idx].pressure = value; + break; + //end of new usage for SiS817 Extend Class Device + + case HID_DG_CONTACTCOUNT: + nd->total = value; + if ( (nd->ReportID & 0xf0) <= REPORTID_TYPE1 ) + sis_event_lastdata(hid, nd, input); + break; + default: + //fallback to the generic hidinput handling + return 0; + } + } + + /* we have handled the hidinput part, now remains hiddev */ + if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event) + hid->hiddev_hid_event(hid, field, usage, value); + + return 1; +} + +#ifdef CONFIG_HID_SIS_UPDATE_FW +int sis_cdev_open(struct inode *inode, struct file *filp) //20120306 Yuger ioctl for tool +{ + //20110511, Yuger, kill current urb by method of usbhid_stop + struct usbhid_device *usbhid; + +#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW + printk( KERN_INFO "sis_cdev_open\n" ); +#endif //CONFIG_DEBUG_HID_SIS_UPDATE_FW + + if ( !hid_dev_backup ) + { + printk( KERN_INFO "sis_cdev_open : hid_dev_backup is not initialized yet" ); + return -1; + } + + usbhid = hid_dev_backup->driver_data; + + //20110602, Yuger, fix bug: not contact usb cause kernel panic + if( !usbhid ) + { + printk( KERN_INFO "sis_cdev_open : usbhid is not initialized yet" ); + return -1; + } + else if ( !usbhid->urbin ) + { + printk( KERN_INFO "sis_cdev_open : usbhid->urbin is not initialized yet" ); + return -1; + } + else if (hid_dev_backup->vendor == USB_VENDOR_ID_SIS2_TOUCH) + { + usb_fill_int_urb(backup_urb, usbhid->urbin->dev, usbhid->urbin->pipe, + usbhid->urbin->transfer_buffer, usbhid->urbin->transfer_buffer_length, + usbhid->urbin->complete, usbhid->urbin->context, usbhid->urbin->interval); + + clear_bit( HID_STARTED, &usbhid->iofl ); + set_bit( HID_DISCONNECTED, &usbhid->iofl ); + + usb_kill_urb( usbhid->urbin ); + usb_free_urb( usbhid->urbin ); + usbhid->urbin = NULL; + return 0; + } + else + { + printk (KERN_INFO "This is not a SiS device"); + return -801; + } +} + +int sis_cdev_release(struct inode *inode, struct file *filp) +{ + //20110505, Yuger, rebuild the urb which is at the same urb address, then re-submit it + int ret; + struct usbhid_device *usbhid; + unsigned long flags; + +#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW + printk( KERN_INFO "sis_cdev_release" ); +#endif //CONFIG_DEBUG_HID_SIS_UPDATE_FW + + if ( !hid_dev_backup ) + { + printk( KERN_INFO "sis_cdev_release : hid_dev_backup is not initialized yet" ); + return -1; + } + + usbhid = hid_dev_backup->driver_data; + + printk( KERN_INFO "sys_sis_HID_start" ); + + if( !usbhid ) + { + printk( KERN_INFO "sis_cdev_release : usbhid is not initialized yet" ); + return -1; + } + + if( !backup_urb ) + { + printk( KERN_INFO "sis_cdev_release : urb_backup is not initialized yet" ); + return -1; + } + + clear_bit( HID_DISCONNECTED, &usbhid->iofl ); + usbhid->urbin = usb_alloc_urb( 0, GFP_KERNEL ); + + if( !backup_urb->interval ) + { + printk( KERN_INFO "sis_cdev_release : urb_backup->interval does not exist" ); + return -1; + } + + usb_fill_int_urb(usbhid->urbin, backup_urb->dev, backup_urb->pipe, + backup_urb->transfer_buffer, backup_urb->transfer_buffer_length, + backup_urb->complete, backup_urb->context, backup_urb->interval); + usbhid->urbin->transfer_dma = usbhid->inbuf_dma; + usbhid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + set_bit( HID_STARTED, &usbhid->iofl ); + + //method at hid_start_in + spin_lock_irqsave( &usbhid->lock, flags ); + ret = usb_submit_urb( usbhid->urbin, GFP_ATOMIC ); + spin_unlock_irqrestore( &usbhid->lock, flags ); + //yy + +#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW + printk( KERN_INFO "sis_cdev_release : ret = %d", ret ); +#endif //CONFIG_DEBUG_HID_SIS_UPDATE_FW + + return ret; +} + +//SiS 817 only +ssize_t sis_cdev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) +{ + int actual_length = 0, timeout = 0; + u8 *rep_data = NULL; + u16 size = 0; + long rep_ret; + struct usb_interface *intf = to_usb_interface(hid_dev_backup->dev.parent); + struct usb_device *dev = interface_to_usbdev(intf); + +#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW + printk( KERN_INFO "sis_cdev_read\n"); +#endif //CONFIG_DEBUG_HID_SIS_UPDATE_FW + + size = (((u16)(buf[64] & 0xff)) << 24) + (((u16)(buf[65] & 0xff)) << 16) + + (((u16)(buf[66] & 0xff)) << 8) + (u16)(buf[67] & 0xff); + timeout = (((int)(buf[68] & 0xff)) << 24) + (((int)(buf[69] & 0xff)) << 16) + + (((int)(buf[70] & 0xff)) << 8) + (int)(buf[71] & 0xff); + + rep_data = kzalloc(size, GFP_KERNEL); + if (!rep_data) + return -12; + + if ( copy_from_user( rep_data, (void*)buf, size) ) + { + printk( KERN_INFO "copy_to_user fail\n" ); + //free allocated data + kfree( rep_data ); + rep_data = NULL; + return -19; + } + + rep_ret = usb_interrupt_msg(dev, backup_urb->pipe, + rep_data, size, &actual_length, timeout); + +#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW + printk(KERN_INFO "sis_cdev_read : rep_data = "); + for (i=0; i<8; i++) + { + printk ("%02X ", rep_data[i]); + } + printk ("\n"); +#endif //CONFIG_DEBUG_HID_SIS_UPDATE_FW + + if( rep_ret == 0 ) + { + rep_ret = actual_length; + if ( copy_to_user( (void*)buf, rep_data, rep_ret ) ) + { + printk( KERN_INFO "copy_to_user fail\n" ); + //free allocated data + kfree( rep_data ); + rep_data = NULL; + return -19; + } + } + + //free allocated data + kfree( rep_data ); + rep_data = NULL; + +#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW + printk( KERN_INFO "sis_cdev_read : rep_ret = %ld\n", rep_ret ); +#endif //CONFIG_DEBUG_HID_SIS_UPDATE_FW + + return rep_ret; +} + +ssize_t sis_cdev_write( struct file *file, const char __user *buf, size_t count, loff_t *f_pos ) +{ + int i, actual_length = 0; + u8 *tmp_data = NULL; //include report id + u8 *rep_data = NULL; + long rep_ret; + struct usb_interface *intf = to_usb_interface( hid_dev_backup->dev.parent ); + struct usb_device *dev = interface_to_usbdev( intf ); + struct usbhid_device *usbhid = hid_dev_backup->driver_data; + + if ( hid_dev_backup->product == USB_PRODUCT_ID_SIS817_TOUCH || hid_dev_backup->product == USB_PRODUCT_ID_SISF817_TOUCH ) //817 method + { + u16 size = (((u16)(buf[64] & 0xff)) << 24) + (((u16)(buf[65] & 0xff)) << 16) + + (((u16)(buf[66] & 0xff)) << 8) + (u16)(buf[67] & 0xff); + int timeout = (((int)(buf[68] & 0xff)) << 24) + (((int)(buf[69] & 0xff)) << 16) + + (((int)(buf[70] & 0xff)) << 8) + (int)(buf[71] & 0xff); + +#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW + printk( KERN_INFO "sis_cdev_write : 817 method\n"); +#endif //CONFIG_DEBUG_HID_SIS_UPDATE_FW + + rep_data = kzalloc(size, GFP_KERNEL); + if (!rep_data) + return -12; + + if ( copy_from_user( rep_data, (void*)buf, size) ) + { + printk( KERN_INFO "copy_to_user fail\n" ); + //free allocated data + kfree( rep_data ); + rep_data = NULL; + return -19; + } + + rep_ret = usb_interrupt_msg( dev, usbhid->urbout->pipe, + rep_data, size, &actual_length, timeout ); + +#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW + printk(KERN_INFO "sis_cdev_write : rep_data = "); + for (i=0; iproduct == USB_PRODUCT_ID_SIS2_TOUCH || hid_dev_backup->product == USB_PRODUCT_ID_NEW_SIS2_TOUCH ) + { + //20110510, Yuger, for correcting intr data send into interrupt msg(receive, in, endp=2) + tmp_data[0] = 0x0A;//in + + rep_ret = usb_interrupt_msg( dev, backup_urb->pipe, tmp_data, size+1, &actual_length, timeout ); + //yy + +#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW + printk(KERN_INFO "(INT_IN)rep_ret = %ld, actual_length = %d", rep_ret, actual_length); +#endif //CONFIG_DEBUG_HID_SIS_UPDATE_FW + + if( rep_ret == 0 ) + { + rep_ret = actual_length; + } + + //20110510, Yuger, for recovering rep_data + for( i = 0; i < size; i++ ) + { + rep_data[i] = tmp_data[i+1]; + } + //yy + +#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW + printk(KERN_INFO "(INT_IN)size = %u, dir = %u, rep_ret = %ld, rep_data = %X %X %X", size, dir, rep_ret, rep_data[0], rep_data[1], rep_data[2]); +#endif //CONFIG_DEBUG_HID_SIS_UPDATE_FW + + if ( copy_to_user( (void*)buf, rep_data, rep_ret ) ) + { + printk( KERN_INFO "copy_to_user fail\n" ); + //free allocated data + kfree( rep_data ); + kfree( tmp_data ); + rep_data = NULL; + tmp_data = NULL; + return -19; + } + } + else + { + //control message + rep_ret = usb_control_msg( dev, usb_rcvctrlpipe( dev, CTRL ), + request, (USB_DIR_IN|USB_TYPE_VENDOR|USB_RECIP_DEVICE), + value, index, rep_data, size, timeout ); + +#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW + printk ("(CTRL) size = %d, dir = %d, rep_ret = %ld, rep_data = ", size, dir, rep_ret); + for (i=0; iproduct == USB_PRODUCT_ID_SIS2_TOUCH || hid_dev_backup->product == USB_PRODUCT_ID_NEW_SIS2_TOUCH ) + { + //20110510, Yuger, for correcting intr data send into interrupt msg(send, out, endp=1) + tmp_data[0] = 0x09;//out + + rep_ret = usb_interrupt_msg( dev, usbhid->urbout->pipe, tmp_data, size + 1, &actual_length, timeout ); + + //just return success or not(no need to return actual_length if succeed) + + //20110510, Yuger, for recovering rep_data + for( i = 0; i < size; i++ ) + { + rep_data[i] = tmp_data[i+1]; + } + //yy + +#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW + printk(KERN_INFO "(INT_OUT)size = %u, actual_length = %d, rep_ret = %ld, rep_data = %x %x %x", size, actual_length, rep_ret, rep_data[0], rep_data[1], rep_data[2]); +#endif //CONFIG_DEBUG_HID_SIS_UPDATE_FW + + if ( copy_to_user( (void*)buf, rep_data, actual_length-1 ) ) + { + printk( KERN_INFO "copy_to_user fail\n" ); + //free allocated data + kfree( rep_data ); + kfree( tmp_data ); + rep_data = NULL; + tmp_data = NULL; + return -19; + } + } + else + { + //control message + rep_ret = usb_control_msg( dev, usb_sndctrlpipe( dev, CTRL ), + request, (USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_DEVICE), + value, index, rep_data, 16, timeout ); + +#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW + printk ("(CTRL) size = %d, dir = %d, rep_ret = %ld, rep_data = ", size, dir, rep_ret); + for (i=0; iproduct == USB_PRODUCT_ID_SIS9200_TOUCH) + alloc_ret = alloc_chrdev_region(&dev, 0, sis_char_devs_count, BRIDGE_DEVICE_NAME); + else if (hdev->product == USB_PRODUCT_ID_SIS817_TOUCH) + alloc_ret = alloc_chrdev_region(&dev, 0, sis_char_devs_count, SIS817_DEVICE_NAME); + else if (hdev->product == USB_PRODUCT_ID_SISF817_TOUCH) + alloc_ret = alloc_chrdev_region(&dev, 0, sis_char_devs_count, SISF817_DEVICE_NAME); + else + alloc_ret = alloc_chrdev_region(&dev, 0, sis_char_devs_count, INTERNAL_DEVICE_NAME); + + if (alloc_ret) + goto error; + + sis_char_major = MAJOR(dev); + cdev_init(&sis_char_cdev, &sis_cdev_fops); + sis_char_cdev.owner = THIS_MODULE; + cdev_err = cdev_add(&sis_char_cdev, MKDEV(sis_char_major, 0), sis_char_devs_count); + if (cdev_err) + goto error; + + if (hdev->product == USB_PRODUCT_ID_SIS9200_TOUCH) + printk(KERN_INFO "%s driver(major %d) installed.\n", BRIDGE_DEVICE_NAME, sis_char_major); + else if (hdev->product == USB_PRODUCT_ID_SIS817_TOUCH) + printk(KERN_INFO "%s driver(major %d) installed.\n", SIS817_DEVICE_NAME, sis_char_major); + else if (hdev->product == USB_PRODUCT_ID_SISF817_TOUCH) + printk(KERN_INFO "%s driver(major %d) installed.\n", SISF817_DEVICE_NAME, sis_char_major); + else + printk(KERN_INFO "%s driver(major %d) installed.\n", INTERNAL_DEVICE_NAME, sis_char_major); + + // register class + if (hdev->product == USB_PRODUCT_ID_SIS9200_TOUCH) + sis_char_class = class_create(THIS_MODULE, BRIDGE_DEVICE_NAME); + else if (hdev->product == USB_PRODUCT_ID_SIS817_TOUCH) + sis_char_class = class_create(THIS_MODULE, SIS817_DEVICE_NAME); + else if (hdev->product == USB_PRODUCT_ID_SISF817_TOUCH) + sis_char_class = class_create(THIS_MODULE, SISF817_DEVICE_NAME); + else + sis_char_class = class_create(THIS_MODULE, INTERNAL_DEVICE_NAME); + + if(IS_ERR(ptr_err = sis_char_class)) + { + goto err2; + } + + if (hdev->product == USB_PRODUCT_ID_SIS9200_TOUCH) + class_dev = device_create(sis_char_class, NULL, MKDEV(sis_char_major, 0), NULL, BRIDGE_DEVICE_NAME); + else if (hdev->product == USB_PRODUCT_ID_SIS817_TOUCH) + class_dev = device_create(sis_char_class, NULL, MKDEV(sis_char_major, 0), NULL, SIS817_DEVICE_NAME); + else if (hdev->product == USB_PRODUCT_ID_SISF817_TOUCH) + class_dev = device_create(sis_char_class, NULL, MKDEV(sis_char_major, 0), NULL, SISF817_DEVICE_NAME); + else + class_dev = device_create(sis_char_class, NULL, MKDEV(sis_char_major, 0), NULL, INTERNAL_DEVICE_NAME); + + if(IS_ERR(ptr_err = class_dev)) + { + goto err; + } + + return 0; +error: + if (cdev_err == 0) + cdev_del(&sis_char_cdev); + if (alloc_ret == 0) + unregister_chrdev_region(MKDEV(sis_char_major, 0), sis_char_devs_count); + if(input_err != 0) + { + printk("sis_ts_bak error!\n"); + } +err: + device_destroy(sis_char_class, MKDEV(sis_char_major, 0)); +err2: + class_destroy(sis_char_class); + return -1; +} +#endif //CONFIG_HID_SIS_UPDATE_FW + +static int sis_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + int ret; + struct usb_interface *intf = to_usb_interface(hdev->dev.parent); + struct usb_device *dev = interface_to_usbdev(intf); + struct sis_data *nd; + u8 *rep_data = NULL; + +#ifdef CONFIG_HID_SIS_UPDATE_FW + hid_dev_backup = hdev; +#endif //CONFIG_HID_SIS_UPDATE_FW + + printk(KERN_INFO "sis_probe\n"); + +#ifdef CONFIG_HID_SIS_UPDATE_FW + backup_urb = usb_alloc_urb(0, GFP_KERNEL); //0721test + if (!backup_urb) { + dev_err(&hdev->dev, "cannot allocate backup_urb\n"); + return -ENOMEM; + } +#endif //CONFIG_HID_SIS_UPDATE_FW + +// command Set_Feature for changing device from mouse to touch device + rep_data = kmalloc(3,GFP_KERNEL); //return value will be 0xabcd + if (hdev->product == USB_PRODUCT_ID_SIS9200_TOUCH) + { + if(!rep_data) + return -ENOMEM; + rep_data[0] = 0x07; + rep_data[1] = 0x02; + rep_data[2] = 0xA9; + + ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_SET_CONFIGURATION, (USB_DIR_OUT | USB_TYPE_CLASS | + USB_RECIP_INTERFACE), 0x0307, 0, rep_data, 3, 1000); + } + +// allocate memory for sis_data struct + nd = kzalloc(sizeof(struct sis_data), GFP_KERNEL); + if (!nd) { + dev_err(&hdev->dev, "cannot allocate SiS 9200 data\n"); + kfree(rep_data); + rep_data = NULL; + return -ENOMEM; + } + + hid_set_drvdata(hdev, nd); + +#ifdef CONFIG_HID_SIS_UPDATE_FW + //for ioctl + ret = sis_setup_chardev(hdev, nd); + if(ret) + { + printk( KERN_INFO "sis_setup_chardev fail\n"); + } +#endif //CONFIG_HID_SIS_UPDATE_FW + + //set noget for not init reports (speed improvement) + hdev->quirks |= HID_QUIRK_NOGET; + hdev->quirks &= ~HID_QUIRK_MULTITOUCH; //only hid-multitouch cat use this flag! + + ret = hid_parse(hdev); + if (ret) { + dev_err(&hdev->dev, "parse failed\n"); + goto err_free; + } + + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); + if (ret) { + dev_err(&hdev->dev, "hw start failed\n"); + goto err_free; + } + +err_free: + kfree(rep_data); + rep_data = NULL; + return ret; +} + +static void sis_remove(struct hid_device *hdev) +{ +#ifdef CONFIG_HID_SIS_UPDATE_FW + //for ioctl + dev_t dev = MKDEV(sis_char_major, 0); + + printk(KERN_INFO "sis_remove\n"); + + cdev_del(&sis_char_cdev); + unregister_chrdev_region(dev, sis_char_devs_count); + device_destroy(sis_char_class, MKDEV(sis_char_major, 0)); + class_destroy(sis_char_class); +#else //CONFIG_HID_SIS_UPDATE_FW + + printk(KERN_INFO "sis_remove\n"); + +#endif //CONFIG_HID_SIS_UPDATE_FW + +#ifdef CONFIG_HID_SIS_UPDATE_FW + usb_kill_urb( backup_urb ); + usb_free_urb( backup_urb ); + backup_urb = NULL; +#endif + hid_hw_stop(hdev); + kfree(hid_get_drvdata(hdev)); + hid_set_drvdata(hdev, NULL); +} + +static const struct hid_device_id sis_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_SIS2_TOUCH, USB_PRODUCT_ID_SIS2_TOUCH) }, //0x0457, 0x0151 + { HID_USB_DEVICE(USB_VENDOR_ID_SIS2_TOUCH, USB_PRODUCT_ID_SIS_TOUCH) }, //0x0457, 0x0810 + { HID_USB_DEVICE(USB_VENDOR_ID_SIS2_TOUCH, USB_PRODUCT_ID_NEW_SIS2_TOUCH) }, //0x0457, 0x0816 + { HID_USB_DEVICE(USB_VENDOR_ID_SIS2_TOUCH, USB_PRODUCT_ID_SIS9200_TOUCH) }, //0x0457, 0x9200 + { HID_USB_DEVICE(USB_VENDOR_ID_SIS2_TOUCH, USB_PRODUCT_ID_SIS817_TOUCH) }, //0x0457, 0x0817 + { HID_USB_DEVICE(USB_VENDOR_ID_SIS2_TOUCH, USB_PRODUCT_ID_SISF817_TOUCH) }, //0x0457, 0xF817 + { } +}; +MODULE_DEVICE_TABLE(hid, sis_devices); + + + +static struct hid_driver sis_driver = { + .name = "sis", + .id_table = sis_devices, + .probe = sis_probe, + .remove = sis_remove, + .raw_event = sis_raw_event, + .input_mapped = sis_input_mapped, + .input_mapping = sis_input_mapping, + .event = sis_event, +}; + +static int __init sis_init(void) +{ + printk(KERN_INFO "sis_init\n"); + return hid_register_driver(&sis_driver); +} + +static void __exit sis_exit(void) +{ + printk(KERN_INFO "sis_exit\n"); + hid_unregister_driver(&sis_driver); +} + +module_init(sis_init); +module_exit(sis_exit); +MODULE_DESCRIPTION("SiS 817 Touchscreen Driver"); +MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/sitronix/Kconfig b/ANDROID_3.4.5/drivers/input/touchscreen/sitronix/Kconfig new file mode 100755 index 00000000..eb37231f --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/sitronix/Kconfig @@ -0,0 +1,11 @@ +config TOUCHSCREEN_SITRONIX + tristate "Sitronix ST1xx series Capacity Touchscreen Device Support" + default m + depends on ARCH_WMT + ---help--- + Say Y here if you have an WMT based board with touchscreen + attached to it. + If unsure, say N. + To compile this driver as a module, choose M here: the + module will be called s_wmt_ts_sitronix.ko. + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/sitronix/Makefile b/ANDROID_3.4.5/drivers/input/touchscreen/sitronix/Makefile new file mode 100755 index 00000000..b38deb74 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/sitronix/Makefile @@ -0,0 +1,34 @@ +KERNELDIR=../../../../ +CROSS = arm_1103_le- +CC= $(CROSS)gcc +LD= $(CROSS)ld +STRIP = $(CROSS)strip + +DEBUG = n + +# Add your debugging flag (or not) to EXTRA_CFLAGS +ifeq ($(DEBUG),y) +# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines +DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines + +else + DEBFLAGS = -O2 -Wall +endif + +EXTRA_CFLAGS += $(DEBFLAGS) + + +MY_MODULE_NAME=s_wmt_ts_sitronix + +#obj-$(CONFIG_TOUCHSCREEN_SITRONIX) := $(MY_MODULE_NAME).o +obj-m := $(MY_MODULE_NAME).o +$(MY_MODULE_NAME)-objs := sitronix_i2c.o irq_gpio.o + +default: + $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules + $(STRIP) --strip-debug $(MY_MODULE_NAME).ko + @rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions *.order *.symvers + +clean: + @rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/sitronix/irq_gpio.c b/ANDROID_3.4.5/drivers/input/touchscreen/sitronix/irq_gpio.c new file mode 100755 index 00000000..bf57ff92 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/sitronix/irq_gpio.c @@ -0,0 +1,148 @@ +#include +#include +#include +#include +#include "irq_gpio.h" + +int wmt_enable_gpirq(int num) +{ + if(num > 15) + return -1; + + if(num < 4) + REG32_VAL(__GPIO_BASE+0x0300) |= 1<<(num*8+7); //enable interrupt + else if(num >= 4 && num < 8) + REG32_VAL(__GPIO_BASE+0x0304) |= 1<<((num-4)*8+7); //enable interrupt + else if(num >= 8 && num < 12) + REG32_VAL(__GPIO_BASE+0x0308) |= 1<<((num-8)*8+7); //enable interrupt + else + REG32_VAL(__GPIO_BASE+0x030C) |= 1<<((num-12)*8+7); //enable interrupt + + return 0; +} + +int wmt_disable_gpirq(int num) +{ + if(num > 15) + return -1; + + if(num<4) + REG32_VAL(__GPIO_BASE+0x0300) &= ~(1<<(num*8+7)); //enable interrupt + else if(num >= 4 && num < 8) + REG32_VAL(__GPIO_BASE+0x0304) &= ~(1<<((num-4)*8+7)); //enable interrupt + else if(num >= 8 && num < 12) + REG32_VAL(__GPIO_BASE+0x0308) &= ~(1<<((num-8)*8+7)); //enable interrupt + else + REG32_VAL(__GPIO_BASE+0x030C) &= ~(1<<((num-12)*8+7)); //enable interrupt + + return 0; +} + +int wmt_is_tsirq_enable(int num) +{ + int val = 0; + + if(num > 15) + return 0; + + if(num<4) + val = REG32_VAL(__GPIO_BASE+0x0300) & (1<<(num*8+7)); + else if(num >= 4 && num < 8) + val = REG32_VAL(__GPIO_BASE+0x0304) & (1<<((num-4)*8+7)); + else if(num >= 8 && num < 12) + val = REG32_VAL(__GPIO_BASE+0x0308) & (1<<((num-8)*8+7)); + else + val = REG32_VAL(__GPIO_BASE+0x030C) & (1<<((num-12)*8+7)); + + return val?1:0; + +} + +int wmt_is_tsint(int num) +{ + if (num > 15) + { + return 0; + } + return (REG32_VAL(__GPIO_BASE+0x0360) & (1< 15) + { + return; + } + REG32_VAL(__GPIO_BASE+0x0360) = 1<15) + return -1; + //if (num > 9) + //GPIO_PIN_SHARING_SEL_4BYTE_VAL &= ~BIT4; // gpio10,11 as gpio + REG32_VAL(__GPIO_BASE+0x0040) &= ~(1<= 4 && num < 8){//[4,7] + shift = num-4; + offset = 0x0304; + }else if(num >= 8 && num < 12){//[8,11] + shift = num-8; + offset = 0x0308; + }else{// [12,15] + shift = num-12; + offset = 0x030C; + } + + reg = REG32_VAL(__GPIO_BASE + offset); + + switch(type){ + case IRQ_TYPE_LEVEL_LOW: + reg &= ~(1<<(shift*8+2)); + reg &= ~(1<<(shift*8+1)); + reg &= ~(1<<(shift*8)); + break; + case IRQ_TYPE_LEVEL_HIGH: + reg &= ~(1<<(shift*8+2)); + reg &= ~(1<<(shift*8+1)); + reg |= (1<<(shift*8)); + break; + case IRQ_TYPE_EDGE_FALLING: + reg &= ~(1<<(shift*8+2)); + reg |= (1<<(shift*8+1)); + reg &= ~(1<<(shift*8)); + break; + case IRQ_TYPE_EDGE_RISING: + reg &= ~(1<<(shift*8+2)); + reg |= (1<<(shift*8+1)); + reg |= (1<<(shift*8)); + break; + default://both edge + reg |= (1<<(shift*8+2)); + reg &= ~(1<<(shift*8+1)); + reg &= ~(1<<(shift*8)); + break; + + } + //reg |= 1<<(shift*8+7);//enable interrupt + reg &= ~(1<<(shift*8+7)); //disable int + + REG32_VAL(__GPIO_BASE + offset) = reg; + REG32_VAL(__GPIO_BASE+0x0360) = 1< +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include "sitronix_i2c.h" +#include "irq_gpio.h" + +struct sitronix_data *pContext=NULL; +struct i2c_client *l_client=NULL; + +#ifdef TOUCH_KEY + +#define MENU_IDX 0 +#define HOME_IDX 1 +#define BACK_IDX 2 +#define SEARCH_IDX 3 +#define NUM_KEYS 4 + +static int virtual_keys[NUM_KEYS] ={ + KEY_BACK, + KEY_HOME, + KEY_MENU, + KEY_SEARCH +}; +#endif + +#define I2C_BUS1 1 + + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void sitronix_early_suspend(struct early_suspend *h); +static void sitronix_late_resume(struct early_suspend *h); +#endif + +static int sitronix_read(struct sitronix_data *sitronix, u8 *rxdata, int length) +{ + int ret; + struct i2c_msg msg[2]; + + msg[0].addr = sitronix->addr; + msg[0].flags = 0 | I2C_M_NOSTART; + msg[0].len = 1; + msg[0].buf = rxdata; + + msg[1].addr = sitronix->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = length; + msg[1].buf = rxdata; + + //ret = wmt_i2c_xfer_continue_if_4(msg, 2, I2C_BUS1); + ret = i2c_transfer(l_client->adapter, msg, 2); + if (ret <= 0) + dbg_err("msg i2c read error: %d\n", ret); + + return ret; +} + +#ifdef SITRONIX_DEBUG +static int sitronix_write(struct sitronix_data *sitronix, u8 *txdata, int length) +{ + int ret; + struct i2c_msg msg[1]; + + msg[0].addr = sitronix->addr; + msg[0].flags = 0; + msg[0].len = length; + msg[0].buf = txdata; + + //ret = wmt_i2c_xfer_continue_if_4(msg, 1, I2C_BUS1); + ret = i2c_transfer(l_client->adapter, msg, 1); + if (ret <= 0) + dbg_err("msg i2c read error: %d\n", ret); + + return ret; +} + +static int sitronix_get_fw_revision(struct sitronix_data *sitronix) +{ + int ret = 0; + uint8_t buffer[4]={FIRMWARE_REVISION_3,0}; + + ret = sitronix_read(sitronix, buffer, 4); + if (ret < 0){ + dbg_err("read fw revision error (%d)\n", ret); + return ret; + } + + memcpy(sitronix->fw_revision, buffer, 4); + printk("Fw Revision (hex): %x%x%x%x\n", buffer[0], buffer[1], buffer[2], buffer[3]); + + return 0; +} + +static int sitronix_get_max_touches(struct sitronix_data *sitronix) +{ + int ret = 0; + uint8_t buffer[1]={MAX_NUM_TOUCHES}; + + ret = sitronix_read(sitronix, buffer, 1); + if (ret < 0){ + dbg_err("read max touches error (%d)\n", ret); + return ret; + } + + sitronix->max_touches = buffer[0]; + printk("max touches = %d \n",sitronix->max_touches); + + return 0; +} + +static int sitronix_get_protocol(struct sitronix_data *sitronix) +{ + int ret = 0; + uint8_t buffer[1]={I2C_PROTOCOL}; + + ret = sitronix_read(sitronix, buffer, 1); + if (ret < 0){ + dbg_err("read i2c protocol error (%d)\n", ret); + return ret; + } + + sitronix->touch_protocol_type = buffer[0] & I2C_PROTOCOL_BMSK; + sitronix->sensing_mode = (buffer[0] & (ONE_D_SENSING_CONTROL_BMSK << ONE_D_SENSING_CONTROL_SHFT)) >> ONE_D_SENSING_CONTROL_SHFT; + printk("i2c protocol = %d ,sensing mode = %d \n", sitronix->touch_protocol_type, sitronix->sensing_mode); + + return 0; +} + +static int sitronix_get_resolution(struct sitronix_data *sitronix) +{ + int ret = 0; + uint8_t buffer[3]={XY_RESOLUTION_HIGH}; + + ret = sitronix_read(sitronix, buffer, 3); + if (ret < 0){ + dbg_err("read resolution error (%d)\n", ret); + return ret; + } + + sitronix->resolution_x = ((buffer[0] & (X_RES_H_BMSK << X_RES_H_SHFT)) << 4) | buffer[1]; + sitronix->resolution_y = ((buffer[0] & Y_RES_H_BMSK) << 8) | buffer[2]; + printk("Resolution: %d x %d\n", sitronix->resolution_x, sitronix->resolution_y); + + return 0; +} + +static int sitronix_get_chip_id(struct sitronix_data *sitronix) +{ + int ret = 0; + uint8_t buffer[3]={CHIP_ID}; + + ret = sitronix_read(sitronix, buffer, 3); + if (ret < 0){ + dbg_err("read Chip ID error (%d)\n", ret); + return ret; + } + + if(buffer[0] == 0){ + if(buffer[1] + buffer[2] > 32) + sitronix->chip_id = 2; + else + sitronix->chip_id = 0; + }else + sitronix->chip_id = buffer[0]; + + sitronix->Num_X = buffer[1]; + sitronix->Num_Y = buffer[2]; + printk("Chip ID = %d, Num_X = %d, Num_Y = %d\n", sitronix->chip_id, sitronix->Num_X, sitronix->Num_Y); + + return 0; +} + +static int sitronix_get_device_status(struct sitronix_data *sitronix) +{ + int ret = 0; + uint8_t buf[3]={FIRMWARE_VERSION,0}; + + ret = sitronix_read(sitronix, buf, 3); + if (ret < 0){ + dbg_err("read resolution error (%d)\n", ret); + return ret; + } + + printk("Firmware version:%02x, Status Reg:%02x,Ctrl Reg:%02x\n", buf[0], buf[1],buf[2]); + return 0; + +} + +static int sitronix_get_device_info(struct sitronix_data *sitronix) +{ + int ret = 0; + + ret = sitronix_get_resolution(sitronix); + if(ret < 0) return ret; + + ret = sitronix_get_chip_id(sitronix); + if(ret < 0) return ret; + + ret = sitronix_get_fw_revision(sitronix); + if(ret < 0) return ret; + + ret = sitronix_get_protocol(sitronix); + if(ret < 0) return ret; + + ret = sitronix_get_max_touches(sitronix); + if(ret < 0) return ret; + + ret = sitronix_get_device_status(sitronix); + if(ret < 0) return ret; + + if((sitronix->fw_revision[0] == 0) && (sitronix->fw_revision[1] == 0)){ + if(sitronix->touch_protocol_type == SITRONIX_RESERVED_TYPE_0){ + sitronix->touch_protocol_type = SITRONIX_B_TYPE; + printk("i2c protocol (revised) = %d \n", sitronix->touch_protocol_type); + } + } + + if(sitronix->touch_protocol_type == SITRONIX_A_TYPE) + sitronix->pixel_length = PIXEL_DATA_LENGTH_A; + else if(sitronix->touch_protocol_type == SITRONIX_B_TYPE){ + sitronix->pixel_length = PIXEL_DATA_LENGTH_B; + sitronix->max_touches = 2; + printk("max touches (revised) = %d \n", sitronix->max_touches); + } + + return 0; +} +#endif + +static void sitronix_read_work(struct work_struct *work) +{ + struct sitronix_data *sitronix= container_of(work, struct sitronix_data, read_work); + int ret = -1; + u8 buf[22] = {FINGERS,0}; + u8 i = 0, fingers = 0, tskey = 0; + u16 px = 0, py = 0; + u16 x = 0, y = 0; + + ret = sitronix_read(sitronix, buf,sizeof(buf)); + if(ret <= 0){ + dbg_err("get raw data failed!\n"); + goto err_exit; + } + + fingers = buf[0]&0x0f; + if( fingers ){ + /* Report co-ordinates to the multi-touch stack */ + for(i=0; i < fingers; i++){ + if(sitronix->swap){ + y = ((buf[i*4+2]<<4)&0x0700)|buf[i*4+3]; + x = ((buf[i*4+2]<<8)&0x0700)|buf[i*4+4]; + }else{ + x = ((buf[i*4+2]<<4)&0x0700)|buf[i*4+3]; + y = ((buf[i*4+2]<<8)&0x0700)|buf[i*4+4]; + } + + if(!(buf[i*4+2]&0x80)) continue; /*check valid bit */ + + + if(x > sitronix->xresl ) x = sitronix->xresl ; + if(y > sitronix->yresl ) y = sitronix->yresl ; + + px = x; + py = y; + if(sitronix->xch) px = sitronix->xresl - x; + if(sitronix->ych) py = sitronix->yresl - y; + + if (sitronix->lcd_exchg) { + int tmp; + tmp = px; + px = py; + py = sitronix->xresl - tmp; + } + + input_report_abs(sitronix->input_dev, ABS_MT_POSITION_X, px); + input_report_abs(sitronix->input_dev, ABS_MT_POSITION_Y, py); + input_report_abs(sitronix->input_dev, ABS_MT_TRACKING_ID, i+1); + input_mt_sync(sitronix->input_dev); + sitronix->penup = 0; + if(sitronix->dbg) printk("F%d,raw data: x=%-4d, y=%-4d; report data: px=%-4d, py=%-4d\n", i, x, y, px, py); + } + input_sync(sitronix->input_dev); + + } + else if(!sitronix->penup){ + dbg("pen up.\n"); + sitronix->penup = 1; + input_mt_sync(sitronix->input_dev); + input_sync(sitronix->input_dev); + } + + /* virtual keys */ + tskey = buf[1]; + if(tskey){ + if(!sitronix->tkey_idx){ + sitronix->tkey_idx = tskey; + input_report_key(sitronix->input_dev,virtual_keys[sitronix->tkey_idx>>1] , 1); + input_sync(sitronix->input_dev); + dbg("virtual key down, idx=%d\n",sitronix->tkey_idx); + } + }else{ + if(sitronix->tkey_idx){ + dbg("virtual key up , idx=%d\n",sitronix->tkey_idx); + input_report_key(sitronix->input_dev,virtual_keys[sitronix->tkey_idx>>1] , 0); + input_sync(sitronix->input_dev); + sitronix->tkey_idx = tskey; + } + } + +err_exit: + wmt_enable_gpirq(sitronix->irqgpio); + return; +} + + +static irqreturn_t sitronix_isr_handler(int irq, void *dev) +{ + struct sitronix_data *sitronix = dev; + + if (wmt_is_tsint(sitronix->irqgpio)) + { + wmt_clr_int(sitronix->irqgpio); + if (wmt_is_tsirq_enable(sitronix->irqgpio)) + { + wmt_disable_gpirq(sitronix->irqgpio); + if(!sitronix->earlysus) queue_work(sitronix->workqueue, &sitronix->read_work); + } + return IRQ_HANDLED; + } + return IRQ_NONE; +} + +static void sitronix_reset(struct sitronix_data *sitronix) +{ + + gpio_set_value(sitronix->rstgpio, 1); + mdelay(5); + gpio_set_value(sitronix->rstgpio, 0); + mdelay(5); + gpio_set_value(sitronix->rstgpio, 1); + mdelay(5); + + return; +} + +static int sitronix_auto_clb(struct sitronix_data *sitronix) +{ + return 1; +} + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void sitronix_early_suspend(struct early_suspend *handler) +{ + struct sitronix_data *sitronix = container_of(handler, struct sitronix_data, early_suspend); + sitronix->earlysus = 1; + wmt_disable_gpirq(sitronix->irqgpio); + return; +} + +static void sitronix_late_resume(struct early_suspend *handler) +{ + struct sitronix_data *sitronix = container_of(handler, struct sitronix_data, early_suspend); + + sitronix->earlysus = 0; + sitronix_reset(sitronix); + msleep(200); + + wmt_set_gpirq(sitronix->irqgpio, IRQ_TYPE_EDGE_FALLING); + wmt_enable_gpirq(sitronix->irqgpio); + + return; +} +#endif //CONFIG_HAS_EARLYSUSPEND + + +static int sitronix_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct sitronix_data *sitronix = platform_get_drvdata(pdev); + sitronix->earlysus = 1; + wmt_disable_gpirq(sitronix->irqgpio); + return 0; +} + +static int sitronix_resume(struct platform_device *pdev) +{ + struct sitronix_data *sitronix = platform_get_drvdata(pdev); + + sitronix->earlysus = 0; + sitronix_reset(sitronix); + msleep(200); + + wmt_set_gpirq(sitronix->irqgpio, IRQ_TYPE_EDGE_FALLING); + wmt_enable_gpirq(sitronix->irqgpio); + return 0; +} + +static ssize_t cat_dbg(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "dbg \n"); +} + +static ssize_t echo_dbg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct sitronix_data *sitronix = pContext; + + sscanf(buf,"%d",&sitronix->dbg); + + return count; +} +static DEVICE_ATTR(dbg, S_IRUGO | S_IWUSR, cat_dbg, echo_dbg); + +static ssize_t cat_clb(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "calibrate --echo 1 >clb \n"); +} + +static ssize_t echo_clb(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + int cal ; + struct sitronix_data *sitronix = pContext; + + sscanf(buf, "%d", &cal); + if(cal){ + if(sitronix_auto_clb(sitronix) <= 0) printk("Auto calibrate failed.\n"); + } + + return count; +} +static DEVICE_ATTR(clb, S_IRUGO | S_IWUSR, cat_clb, echo_clb); + +static struct attribute *sitronix_attributes[] = { + &dev_attr_clb.attr, + &dev_attr_dbg.attr, + NULL +}; + +static const struct attribute_group sitronix_group = { + .attrs = sitronix_attributes, +}; + +static int sitronix_sysfs_create_group(struct sitronix_data *sitronix, const struct attribute_group *group) +{ + int err; + + sitronix->kobj = kobject_create_and_add("wmtts", NULL) ; + if(!sitronix->kobj){ + dbg_err("kobj create failed.\n"); + return -ENOMEM; + } + + /* Register sysfs hooks */ + err = sysfs_create_group(sitronix->kobj, group); + if (err < 0){ + kobject_del(sitronix->kobj); + dbg_err("Create sysfs group failed!\n"); + return -ENOMEM; + } + + return 0; +} + +static void sitronix_sysfs_remove_group(struct sitronix_data *sitronix, const struct attribute_group *group) +{ + sysfs_remove_group(sitronix->kobj, group); + kobject_del(sitronix->kobj); + return; +} + +static int sitronix_probe(struct platform_device *pdev) +{ + int i; + int err = 0; + struct sitronix_data *sitronix = platform_get_drvdata(pdev); + + INIT_WORK(&sitronix->read_work, sitronix_read_work); + sitronix->workqueue = create_singlethread_workqueue(sitronix->name); + if (!sitronix->workqueue) { + err = -ESRCH; + goto exit_create_singlethread; + } + + err = sitronix_sysfs_create_group(sitronix, &sitronix_group); + if(err < 0){ + dbg("create sysfs group failed.\n"); + goto exit_create_group; + } + + sitronix->input_dev = input_allocate_device(); + if (!sitronix->input_dev) { + err = -ENOMEM; + dbg("failed to allocate input device\n"); + goto exit_input_dev_alloc_failed; + } + + sitronix->input_dev->name = sitronix->name; + sitronix->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + set_bit(INPUT_PROP_DIRECT, sitronix->input_dev->propbit); + + if (sitronix->lcd_exchg) { + input_set_abs_params(sitronix->input_dev, + ABS_MT_POSITION_X, 0, sitronix->yresl, 0, 0); + input_set_abs_params(sitronix->input_dev, + ABS_MT_POSITION_Y, 0, sitronix->xresl, 0, 0); + } else { + input_set_abs_params(sitronix->input_dev, + ABS_MT_POSITION_X, 0, sitronix->xresl, 0, 0); + input_set_abs_params(sitronix->input_dev, + ABS_MT_POSITION_Y, 0, sitronix->yresl, 0, 0); + } + input_set_abs_params(sitronix->input_dev, + ABS_MT_TRACKING_ID, 0, 20, 0, 0); +#ifdef TOUCH_KEY + for (i = 0; i input_dev->keybit); + + sitronix->input_dev->keycode = virtual_keys; + sitronix->input_dev->keycodesize = sizeof(unsigned int); + sitronix->input_dev->keycodemax = NUM_KEYS; +#endif + + err = input_register_device(sitronix->input_dev); + if (err) { + dbg_err("sitronix_ts_probe: failed to register input device.\n"); + goto exit_input_register_device_failed; + } + +#ifdef CONFIG_HAS_EARLYSUSPEND + sitronix->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + sitronix->early_suspend.suspend = sitronix_early_suspend; + sitronix->early_suspend.resume = sitronix_late_resume; + register_early_suspend(&sitronix->early_suspend); +#endif + + if(request_irq(sitronix->irq, sitronix_isr_handler, IRQF_SHARED, sitronix->name, sitronix) < 0){ + dbg_err("Could not allocate irq for ts_sitronix !\n"); + err = -1; + goto exit_register_irq; + } + + wmt_set_gpirq(sitronix->irqgpio, IRQ_TYPE_EDGE_FALLING); + wmt_enable_gpirq(sitronix->irqgpio); + sitronix_reset(sitronix); + msleep(200); +#ifdef SITRONIX_DEBUG + sitronix_get_device_info(sitronix); +#endif + + return 0; + +exit_register_irq: +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&sitronix->early_suspend); +#endif +exit_input_register_device_failed: + input_free_device(sitronix->input_dev); +exit_input_dev_alloc_failed: + sitronix_sysfs_remove_group(sitronix, &sitronix_group); +exit_create_group: + cancel_work_sync(&sitronix->read_work); + destroy_workqueue(sitronix->workqueue); +exit_create_singlethread: + //kfree(sitronix); + return err; +} + +static int sitronix_remove(struct platform_device *pdev) +{ + struct sitronix_data *sitronix = platform_get_drvdata(pdev); + + cancel_work_sync(&sitronix->read_work); + flush_workqueue(sitronix->workqueue); + destroy_workqueue(sitronix->workqueue); + + free_irq(sitronix->irq, sitronix); + wmt_disable_gpirq(sitronix->irqgpio); + +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&sitronix->early_suspend); +#endif + input_unregister_device(sitronix->input_dev); + + sitronix_sysfs_remove_group(sitronix, &sitronix_group); + //kfree(sitronix); + + dbg("remove...\n"); + return 0; +} + +static void sitronix_release(struct device *device) +{ + return; +} + +static struct platform_device sitronix_device = { + .name = DEV_SITRONIX, + .id = 0, + .dev = {.release = sitronix_release}, +}; + +static struct platform_driver sitronix_driver = { + .driver = { + .name = DEV_SITRONIX, + .owner = THIS_MODULE, + }, + .probe = sitronix_probe, + .remove = sitronix_remove, + .suspend = sitronix_suspend, + .resume = sitronix_resume, +}; + +static int check_touch_env(struct sitronix_data *sitronix) +{ + int len = 96; + int Enable; + char retval[96] = {0}; + char *p=NULL; + int ret; + + // Get u-boot parameter + if(wmt_getsyspara("wmt.io.touch", retval, &len)) return -EIO; + + sscanf(retval,"%d:",&Enable); + //check touch enable + if(Enable == 0) return -ENODEV; + + p = strchr(retval,':'); + p++; + + if(strncmp(p,"st1536",6)) return -ENODEV; + + sitronix->name = DEV_SITRONIX; + sitronix->addr = SITRONIX_ADDR; + p = strchr(p,':'); + p++; + sscanf(p,"%d:%d:%d:%d:%d:%d:%d", + &sitronix->xresl, &sitronix->yresl, &sitronix->irqgpio, &sitronix->rstgpio, &sitronix->swap, &sitronix->xch, &sitronix->ych); + + sitronix->irq = IRQ_GPIO; + printk("%s reslx=%d, resly=%d, irqgpio_num=%d, rstgpio_num=%d, XYswap=%d, Xdirch=%d, Ydirch=%d\n", sitronix->name, + sitronix->xresl, sitronix->yresl, sitronix->irqgpio, sitronix->rstgpio, sitronix->swap, sitronix->xch, sitronix->ych); + + sitronix->penup = 1; + + memset(retval,0,sizeof(retval)); + ret = wmt_getsyspara("wmt.display.fb0", retval, &len); + if (!ret) { + int tmp[6]; + p = retval; + sscanf(p, "%d:[%d:%d:%d:%d:%d", &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5]); + if (tmp[4] > tmp[5]) + sitronix->lcd_exchg = 1; + } + + return 0; +} + +struct i2c_board_info ts_i2c_board_info = { + .type = DEV_SITRONIX, + .flags = 0x00, + .addr = SITRONIX_ADDR, + .platform_data = NULL, + .archdata = NULL, + .irq = -1, +}; + +static int ts_i2c_register_device (void) +{ + struct i2c_board_info *ts_i2c_bi; + struct i2c_adapter *adapter = NULL; + //struct i2c_client *client = NULL; + + ts_i2c_bi = &ts_i2c_board_info; + adapter = i2c_get_adapter(I2C_BUS1);/*in bus 1*/ + + if (NULL == adapter) { + printk("can not get i2c adapter, client address error\n"); + return -1; + } + l_client = i2c_new_device(adapter, ts_i2c_bi); + if (l_client == NULL) { + printk("allocate i2c client failed\n"); + return -1; + } + i2c_put_adapter(adapter); + return 0; +} + +static void ts_i2c_unregister_device(void) +{ + if (l_client != NULL) + { + i2c_unregister_device(l_client); + l_client = NULL; + } +} + + +static int __init sitronix_init(void) +{ + int ret = -ENOMEM; + struct sitronix_data *sitronix=NULL; + + if (ts_i2c_register_device()<0) + { + dbg("Error to run ts_i2c_register_device()!\n"); + return -1; + } + + sitronix = kzalloc(sizeof(struct sitronix_data), GFP_KERNEL); + if(!sitronix){ + dbg_err("mem alloc failed.\n"); + return -ENOMEM; + } + + pContext = sitronix; + ret = check_touch_env(sitronix); + if(ret < 0) + goto exit_free_mem; + + ret = gpio_request(sitronix->irqgpio, "ts_irq"); + if (ret < 0) { + printk("gpio(%d) touchscreen irq request fail\n", sitronix->irqgpio); + goto exit_free_mem; + } + + ret = gpio_request(sitronix->rstgpio, "ts_rst"); + if (ret < 0) { + printk("gpio(%d) touchscreen reset request fail\n", sitronix->rstgpio); + goto exit_free_irqgpio; + } + gpio_direction_output(sitronix->rstgpio, 1); + + + ret = platform_device_register(&sitronix_device); + if(ret){ + dbg_err("register platform drivver failed!\n"); + goto exit_free_gpio; + } + platform_set_drvdata(&sitronix_device, sitronix); + + ret = platform_driver_register(&sitronix_driver); + if(ret){ + dbg_err("register platform device failed!\n"); + goto exit_unregister_pdev; + } + + return ret; + +exit_unregister_pdev: + platform_device_unregister(&sitronix_device); +exit_free_gpio: + + gpio_free(sitronix->rstgpio); +exit_free_irqgpio: + gpio_free(sitronix->irqgpio); + +exit_free_mem: + kfree(sitronix); + pContext = NULL; + ts_i2c_unregister_device(); + return ret; +} + +static void sitronix_exit(void) +{ + struct sitronix_data *sitronix; + + if(!pContext) return; + + sitronix = pContext; + + gpio_free(sitronix->irqgpio); + gpio_free(sitronix->rstgpio); + + + platform_driver_unregister(&sitronix_driver); + platform_device_unregister(&sitronix_device); + kfree(pContext); + + ts_i2c_unregister_device(); + return; +} + +late_initcall(sitronix_init); +module_exit(sitronix_exit); + +MODULE_DESCRIPTION("Sitronix Multi-Touch Driver"); +MODULE_LICENSE("GPL"); + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/sitronix/sitronix_i2c.h b/ANDROID_3.4.5/drivers/input/touchscreen/sitronix/sitronix_i2c.h new file mode 100755 index 00000000..8d3df91d --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/sitronix/sitronix_i2c.h @@ -0,0 +1,137 @@ +#ifndef _LINUX_SIT_I2C_H +#define _LINUX_SIT_I2C_H + +#define SITRONIX_ADDR 0x60 +#define DEV_SITRONIX "touch_sitronix" +#define SITRONIX_MAX_SUPPORTED_POINT 5 +#define TOUCH_KEY + +struct sitronix_data { + u16 addr; + const char *name; + + struct input_dev *input_dev; + struct work_struct read_work; + struct workqueue_struct *workqueue; + struct kobject *kobj; + #ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif + int earlysus; + + int xresl; + int yresl; + + int irq; + int irqgpio; + + int rstgpio; + + int xch; + int ych; + int swap; + int lcd_exchg; + + int penup; + int dbg; +#ifdef TOUCH_KEY + //int tkey_pressed; + int tkey_idx; +#endif + u8 fw_revision[4]; + int resolution_x; + int resolution_y; + u8 max_touches; + u8 touch_protocol_type; + u8 chip_id; + + u8 Num_X; + u8 Num_Y; + u8 sensing_mode; + u8 pixel_length; +}; + +typedef enum{ + FIRMWARE_VERSION, + STATUS_REG, + DEVICE_CONTROL_REG, + TIMEOUT_TO_IDLE_REG, + XY_RESOLUTION_HIGH, + X_RESOLUTION_LOW, + Y_RESOLUTION_LOW, + FIRMWARE_REVISION_3 = 0x0C, + FIRMWARE_REVISION_2, + FIRMWARE_REVISION_1, + FIRMWARE_REVISION_0, + FINGERS, + KEYS_REG, + XY0_COORD_H, + X0_COORD_L, + Y0_COORD_L, + I2C_PROTOCOL = 0x3E, + MAX_NUM_TOUCHES, + DATA_0_HIGH, + DATA_0_LOW, + CHIP_ID = 0xF4, + + PAGE_REG = 0xff, +}RegisterOffset; + + +typedef enum{ + XY_COORD_H, + X_COORD_L, + Y_COORD_L, + PIXEL_DATA_LENGTH_B, + PIXEL_DATA_LENGTH_A, +}PIXEL_DATA_FORMAT; + +#define X_RES_H_SHFT 4 +#define X_RES_H_BMSK 0xf +#define Y_RES_H_SHFT 0 +#define Y_RES_H_BMSK 0xf +#define FINGERS_SHFT 0 +#define FINGERS_BMSK 0xf +#define X_COORD_VALID_SHFT 7 +#define X_COORD_VALID_BMSK 0x1 +#define X_COORD_H_SHFT 4 +#define X_COORD_H_BMSK 0x7 +#define Y_COORD_H_SHFT 0 +#define Y_COORD_H_BMSK 0x7 + +typedef enum{ + SITRONIX_RESERVED_TYPE_0, + SITRONIX_A_TYPE, + SITRONIX_B_TYPE, +}I2C_PROTOCOL_TYPE; + +#define I2C_PROTOCOL_SHFT 0x0 +#define I2C_PROTOCOL_BMSK 0x3 + +typedef enum{ + SENSING_BOTH, + SENSING_X_ONLY, + SENSING_Y_ONLY, + SENSING_BOTH_NOT, +}ONE_D_SENSING_CONTROL_MODE; + +#define ONE_D_SENSING_CONTROL_SHFT 0x2 +#define ONE_D_SENSING_CONTROL_BMSK 0x3 + +extern int wmt_setsyspara(char *varname, unsigned char *varval); +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); +//extern int wmt_i2c_xfer_continue_if_4(struct i2c_msg *msg, unsigned int num,int bus_id); + +//#define SITRONIX_DEBUG + +#undef dbg +#ifdef SITRONIX_DEBUG + #define dbg(fmt,args...) printk("DBG:%s_%d:"fmt,__FUNCTION__,__LINE__,##args) +#else + #define dbg(fmt,args...) +#endif + +#undef dbg_err +#define dbg_err(fmt,args...) printk("ERR:%s_%d:"fmt,__FUNCTION__,__LINE__,##args) + +#endif /* _LINUX_SIS_I2C_H */ diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ssd253x_ts/Kconfig b/ANDROID_3.4.5/drivers/input/touchscreen/ssd253x_ts/Kconfig new file mode 100755 index 00000000..a5d9aa73 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ssd253x_ts/Kconfig @@ -0,0 +1,16 @@ +# +# SSD253x capacity touch screen driver configuration +# +config TOUCHSCREEN_SSD253X + tristate "SSD253X I2C Touchscreen Input Driver Support" + depends on ARCH_WMT + default y + help + Say Y here if you have an WMT based board with touchscreen + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called s_wmt_ts_ssd253x. + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ssd253x_ts/Makefile b/ANDROID_3.4.5/drivers/input/touchscreen/ssd253x_ts/Makefile new file mode 100755 index 00000000..d78c8466 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ssd253x_ts/Makefile @@ -0,0 +1,32 @@ +KERNELDIR=../../../../ +CROSS = arm_1103_le- +CC= $(CROSS)gcc +LD= $(CROSS)ld +STRIP = $(CROSS)strip + +DEBUG = n + +# Add your debugging flag (or not) to EXTRA_CFLAGS +ifeq ($(DEBUG),y) +# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines +DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines + +else + DEBFLAGS = -O2 -Wall +endif + +EXTRA_CFLAGS += $(DEBFLAGS) + + +MY_MODULE_NAME=s_wmt_ts_ssd253x + +obj-m := $(MY_MODULE_NAME).o +$(MY_MODULE_NAME)-objs := ssd253x-ts.o wmt_ts.o + +default: + $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules + $(STRIP) --strip-debug $(MY_MODULE_NAME).ko + rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions *.order *.symvers + +clean: + rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ssd253x_ts/ssd253x-ts.c b/ANDROID_3.4.5/drivers/input/touchscreen/ssd253x_ts/ssd253x-ts.c new file mode 100755 index 00000000..c02392cb --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ssd253x_ts/ssd253x-ts.c @@ -0,0 +1,1827 @@ +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif /* CONFIG_HAS_EARLYSUSPEND */ + + +#include "ssd253x-ts.h" +#include "wmt_ts.h" + +//#define CONFIG_TOUCHSCREEN_SSL_DEBUG +#undef CONFIG_TOUCHSCREEN_SSL_DEBUG + +#define DEVICE_ID_REG 2 +#define VERSION_ID_REG 3 +#define AUTO_INIT_RST_REG 68 +#define EVENT_STATUS 121 +#define EVENT_MSK_REG 122 +#define IRQ_MSK_REG 123 +#define FINGER01_REG 124 +#define EVENT_STACK 128 +#define EVENT_FIFO_SCLR 135 +#define TIMESTAMP_REG 136 +#define SELFCAP_STATUS_REG 185 + +#define ON_TOUCH_INT INT_EI11 //GPIO :set the interrupt +#define DEVICE_NAME "touch_ssd253x" +#define SSD253X_I2C_ADDR 0x48 //0x48 + +// SSD2533 Setting +// Touch Panel Example +static struct ChipSetting* ssd253xcfgTable = NULL; +static int l_cfglen = 0; + +static struct ChipSetting ssd253xcfgTable_default[]={ +{2,0x06,0x1B,0x28}, +{2,0xd7,0x00,0x00}, +{2,0xd8,0x00,0x07}, +{2,0xdb,0x00,0x01}, +{2,0x30,0x03,0x08}, +{2,0x34,0xd4,0x1e}, +{2,0x57,0x00,0x06}, +{2,0x40,0x00,0xc8}, +{2,0x41,0x00,0x30}, +{2,0x42,0x00,0xc0}, +{2,0x43,0x00,0x30}, +{2,0x44,0x00,0xc0}, +{2,0x45,0x00,0xc0}, +{2,0x46,0x00,0x0f}, +{2,0x5f,0x00,0x00}, +{2,0x2d,0x00,0x00}, +{2,0x66,0x1F,0x38}, +{2,0x67,0x1c,0x92}, +{2,0x25,0x00,0x02}, +}; + + +// For SSD2533 Bug Version Only // +//#define SSD2533FIXEDCODE + struct ChipSetting ssd253xcfgTable1[]={ +{ 1, 0xA4, 0x00, 0x00}, //MCU prescaler default=01 +{ 1, 0xD4, 0x08, 0x00}, //Dummy Code +{ 1, 0xD4, 0x08, 0x00}, //Set Osc frequency default=8, range 0 to F +}; + + struct ChipSetting Reset[]={ +{ 0, 0x04, 0x00, 0x00}, // SSD2533 +}; + + struct ChipSetting Resume[]={ +{ 0, 0x04, 0x00, 0x00}, // SSD2533 +{ 1, 0x25, 0x12, 0x00}, // Set Operation Mode //Set from int setting +}; + + struct ChipSetting Suspend[] ={ +{ 1, 0x25, 0x00, 0x00}, // Set Operation Mode +{ 0, 0x05, 0x00, 0x00}, // SSD2533 +}; + + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void ssd253x_ts_early_suspend(struct early_suspend *h); +static void ssd253x_ts_late_resume(struct early_suspend *h); +#endif /* CONFIG_HAS_EARLYSUSPEND */ + +static irqreturn_t ssd253x_ts_isr(int irq, void *dev_id); +static enum hrtimer_restart ssd253x_ts_timer(struct hrtimer *timer); +//extern int wmt_i2c_xfer_continue_if_4(struct i2c_msg *msg, unsigned int num,int bus_id); + + +static int SSDS53X_SCREEN_MAX_X = 800; +static int SSDS53X_SCREEN_MAX_Y = 480; + + + +enum{ + IC_SSD2533 = 1, + IC_SSD2543, + IC_SSD2531 +}; + +static int ic_flag; + +static struct workqueue_struct *ssd253x_wq; + +int Ssd_Timer1,Ssd_Timer2,Ssd_Timer_flag; + +struct ssl_ts_priv { + struct input_dev *input; + struct hrtimer timer; + struct work_struct ssl_work; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif + + int irq; + int use_irq; + int FingerNo; + int earlysus; + + int FingerX[FINGERNO]; + int FingerY[FINGERNO]; + int FingerP[FINGERNO]; + + int Resolution; + int EventStatus; + int FingerDetect; + + int sFingerX[FINGERNO]; + int sFingerY[FINGERNO]; + int pFingerX[FINGERNO]; + int pFingerY[FINGERNO]; +}; + +static struct ssl_ts_priv* l_ts = NULL; +struct wmtts_device ssd253x_tsdev; +static DECLARE_WAIT_QUEUE_HEAD(ts_penup_wait_queue); + +#define SD_INIT +#ifdef SD_INIT +#define TP_CHR "tp_chr" + +#include +#include +#include + +static long tp_ioctl(struct file *file, unsigned int cmd, unsigned long arg); +static int tp_open(struct inode *inode, struct file *file); +static int tp_release(struct inode *inode, struct file *file); +static ssize_t tp_read(struct file *file, char __user *buf, size_t count,loff_t *offset); +static ssize_t tp_write(struct file *file, const char __user *buf,size_t count, loff_t *offset); + +//void InitFromSD(struct i2c_client *client); + +//struct ChipSetting _ssd253xcfgTable[200]; +//int sd_init_size=0; + + +//struct i2c_client *g_tp_client; + +#endif + + + +static int ReadRegister(/*struct i2c_client *client,*/uint8_t reg,int ByteNo) +{ + unsigned char buf[4]; + struct i2c_msg msg[2]; + int ret; + struct i2c_client* client = ts_get_i2c_client(); + + memset(buf, 0xFF, sizeof(buf)); + msg[0].addr = SSD253X_I2C_ADDR; + msg[0].flags = 0 | I2C_M_NOSTART; + msg[0].len = 1; + msg[0].buf = ® + + msg[1].addr = SSD253X_I2C_ADDR; + msg[1].flags = I2C_M_RD; + msg[1].len = ByteNo; + msg[1].buf = buf; + + ret = i2c_transfer(client->adapter, msg, 2); + if (ret <= 0) + { + printk("read the address (0x%x) of the ssd253x fail, ret=%d.\n", reg, ret); + return -1; + } + + if(ByteNo==1) return (int)((unsigned int)buf[0]<<0); + if(ByteNo==2) return (int)((unsigned int)buf[1]<<0)|((unsigned int)buf[0]<<8); + if(ByteNo==3) return (int)((unsigned int)buf[2]<<0)|((unsigned int)buf[1]<<8)|((unsigned int)buf[0]<<16); + if(ByteNo==4) return (int)((unsigned int)buf[3]<<0)|((unsigned int)buf[2]<<8)|((unsigned int)buf[1]<<16)|(buf[0]<<24); + return 0; +} + +static int WriteRegister(/*struct i2c_client *client,*/uint8_t Reg,unsigned char Data1,unsigned char Data2,int ByteNo) +{ + struct i2c_msg msg; + unsigned char buf[4]; + int ret; + struct i2c_client* client = ts_get_i2c_client(); + + buf[0]=Reg; + buf[1]=Data1; + buf[2]=Data2; + buf[3]=0; + + msg.addr = SSD253X_I2C_ADDR; + msg.flags = 0; + msg.len = ByteNo+1; + msg.buf = (char *)buf; + ret = i2c_transfer(client->adapter, &msg, 1); + if (ret <= 0) + { + printk(KERN_ERR "write the address (0x%x) of the ssd25xx fail, ret=%d.\n", buf[0], ret); + return -1; + } + return 0; + +} + +int SSD253xdeviceInit1(void) +{ +#ifdef SSD2533FIXEDCODE + int i; + mdelay(600); //SSD2533 ESD2 EEPROM VERSION + for(i=0;ipFingerX[No]!=0x0FFF)&&(X!=0x0FFF)) + { + dx=abs(ssl_priv->pFingerX[No]-X); + dy=abs(ssl_priv->pFingerY[No]-Y); + if(dx+dypFingerX[No]=(FilterMode[Mode][0]*ssl_priv->pFingerX[No]+FilterMode[Mode][1]*X)/8; + ssl_priv->pFingerY[No]=(FilterMode[Mode][0]*ssl_priv->pFingerY[No]+FilterMode[Mode][1]*Y)/8; + } + else + { + ssl_priv->pFingerX[No]=X; + ssl_priv->pFingerY[No]=Y; + } + } + else + { + ssl_priv->pFingerX[No]=X; + ssl_priv->pFingerY[No]=Y; + } + *xpos=ssl_priv->pFingerX[No]; + *ypos=ssl_priv->pFingerY[No]; +} + +void FingerCheckSwap(int *FingerX,int *FingerY,int *FingerP,int FingerNo,int *sFingerX,int *sFingerY) +{ + int i,j; + int index1,index2; + int Vx,Vy; + int Ux,Uy; + int R1x,R1y; + int R2x,R2y; + for(i=0;iR2x+R2y) + { + Ux=FingerX[index1]; + Uy=FingerY[index1]; + Vx=FingerP[index1]; + + FingerX[index1]=FingerX[index2]; + FingerY[index1]=FingerY[index2]; + FingerP[index1]=FingerP[index2]; + + FingerX[index2]=Ux; + FingerY[index2]=Uy; + FingerP[index2]=Vx; + } + break; + } + } + } + } + for(i=0;iinput, KEY_SEARCH, downup); + break; + case 0x02: + input_report_key(ssl_priv->input, KEY_BACK, downup); + break; + case 0x04: + input_report_key(ssl_priv->input, KEY_HOME, downup); + break; + case 0x08: + input_report_key(ssl_priv->input, KEY_MENU, downup); + break; + default: + break; + } + dbg("send %x %x\n", btn_status, downup); +} +#endif + +// for ssd2533(no test) +static int ssd253x_ts_cut_edge0(unsigned short pos,unsigned short x_y) +{ + u8 cut_value = 26; //26 cut_value < 32 + if(pos == 0xfff) + { + return pos; + } + //printk("X: rude data %d\n",pos); + if(x_y) //xpos + { + + if(pos < 16) + pos = cut_value + pos*(48 - cut_value) / 16; + else if(pos > (XPOS_MAX - 16) ) + pos = XPOS_MAX + 16 + (pos - (XPOS_MAX -16))*(48 - cut_value) / 16; + else + pos = pos + 32; + + pos = SSDS53X_SCREEN_MAX_X * pos / (DRIVENO * 64); + //printk("X: changed data %d\n",pos); + return pos; + } + else //ypos + { + if(pos < 16) + pos = cut_value + pos*(48 - cut_value) / 16; + else if(pos > (YPOS_MAX - 16) ) + pos = YPOS_MAX + 16 + (pos - (YPOS_MAX -16))*(48 - cut_value) / 16; + else + pos = pos + 32; + //printk("Y: rude data %d\n",pos); + pos = SSDS53X_SCREEN_MAX_Y* pos / (SENSENO * 64); + //printk("Y: changed data %d\n",pos); + return pos; + } + + +} + +// for ssd2532 +static int ssd253x_ts_cut_edge1(unsigned short pos,unsigned short x_y) +{ + u8 cut_value = 15; //cut_value < 32 + + if(pos == 0xfff){ + return pos; + } + + if(x_y){ //xpos 64-->96 //MAX=896 + pos = pos + cut_value;//????????Ôµ + pos = SSDS53X_SCREEN_MAX_X * pos / (790+cut_value*2);//SSDS53X_SCREEN_MAX_X?????Ò±?Ôµ + return pos; + }else{ //ypos //MAX=576 + pos = pos + cut_value;//?????ϱ?Ôµ + pos = SSDS53X_SCREEN_MAX_Y* pos / (470+cut_value*2);//SSDS53X_SCREEN_MAX_Y?????±?Ôµ + return pos; + } +} + +// for ssd2532,8" ssd253x_pydctp80a1.ts +// x_y:1--x,0--y +static int ssd253x_ts_cut_edge2(unsigned short pos,unsigned short x_y) +{ + int tpos; + + if (pos == 0xfff){ + return pos; + } + + tpos = pos; + if (x_y) + { + if (tpos<20) + { + tpos= tpos+18; + } else if (tpos>585) + { + tpos = tpos-18; + } else { + tpos = (tpos-20)*565/575+30; + } + pos = tpos; + return pos; + } else { + if (tpos <10) + { + tpos = tpos+10; + } else if (tpos >795) + { + tpos = 795; + } else { + tpos = (tpos-10)*775/785+20; + } + pos = tpos; + return pos; + } + +} +// for ssd2532 +static int ssd253x_ts_cut_edge3(unsigned short pos,unsigned short x_y) +{ + u8 cut_value = 15; + + if(pos == 0xfff){ + return pos; + } + + if(x_y){ + pos = pos + cut_value; + pos = SSDS53X_SCREEN_MAX_X * pos / (896+cut_value*2); + return pos; + }else{ + pos = pos + cut_value; + pos = SSDS53X_SCREEN_MAX_Y* pos / (576+cut_value*2); + return pos; + } +} + +// for jun feng TP +static int ssd253x_ts_cut_edge4(unsigned short pos,unsigned short x_y) +{ + unsigned short Cut_Edge_XLeft[64]={ + 0x0008,0x0009,0x000B,0x000C,0x000D,0x000E,0x0010,0x0011, + 0x0012,0x0013,0x0015,0x0016,0x0017,0x0018,0x001A,0x001B, + 0x001C,0x001D,0x001F,0x0020,0x0021,0x0022,0x0024,0x0025, + 0x0026,0x0026,0x0027,0x0028,0x0029,0x002A,0x002B,0x002C, + 0x002C,0x002D,0x002E,0x002F,0x0030,0x0031,0x0032,0x0032, + 0x0033,0x0034,0x0035,0x0036,0x0037,0x0038,0x0038,0x0039, + 0x003A,0x003B,0x003C,0x003D,0x003E,0x003E,0x003F,0x0040, + 0x0041,0x0042,0x0043,0x0044,0x0044,0x0045,0x0046,0x0047 + }; + + unsigned short Cut_Edge_XRight[64]={ + 0x0318,0x0317,0x0315,0x0314,0x0313,0x0312,0x0310,0x030F, + 0x030E,0x030D,0x030B,0x030A,0x0309,0x0308,0x0306,0x0305, + 0x0304,0x0303,0x0301,0x0300,0x02FF,0x02FE,0x02FC,0x02FB, + 0x02FA,0x02FA,0x02F9,0x02F8,0x02F7,0x02F6,0x02F5,0x02F4, + 0x02F4,0x02F3,0x02F2,0x02F1,0x02F0,0x02EF,0x02EE,0x02EE, + 0x02ED,0x02EC,0x02EB,0x02EA,0x02E9,0x02E8,0x02E8,0x02E7, + 0x02E6,0x02E5,0x02E4,0x02E3,0x02E2,0x02E2,0x02E1,0x02E0, + 0x02DF,0x02DE,0x02DD,0x02DC,0x02DC,0x02DB,0x02DA,0x02D9 + }; + + unsigned short Cut_Edge_YUp[64]={ + 0x0006,0x0007,0x0008,0x000A,0x000B,0x000C,0x000D,0x000F, + 0x0010,0x0011,0x0012,0x0014,0x0015,0x0016,0x0017,0x0018, + 0x001A,0x001B,0x001C,0x001D,0x001F,0x0020,0x0021,0x0022, + 0x0022,0x0023,0x0024,0x0025,0x0025,0x0026,0x0027,0x0028, + 0x0029,0x0029,0x002A,0x002B,0x002C,0x002C,0x002D,0x002E, + 0x002F,0x0030,0x0030,0x0031,0x0032,0x0033,0x0033,0x0034, + 0x0035,0x0036,0x0037,0x0037,0x0038,0x0039,0x003A,0x003A, + 0x003B,0x003C,0x003D,0x003E,0x003E,0x003F,0x0040,0x0041 + }; + + unsigned short Cut_Edge_YDown[64]={ + 0x01DA,0x01D9,0x01D8,0x01D6,0x01D5,0x01D4,0x01D3,0x01D1, + 0x01D0,0x01CF,0x01CE,0x01CC,0x01CB,0x01CA,0x01C9,0x01C8, + 0x01C6,0x01C5,0x01C4,0x01C3,0x01C1,0x01C0,0x01BF,0x01BE, + 0x01BE,0x01BD,0x01BC,0x01BB,0x01BB,0x01BA,0x01B9,0x01B8, + 0x01B7,0x01B7,0x01B6,0x01B5,0x01B4,0x01B4,0x01B3,0x01B2, + 0x01B1,0x01B0,0x01B0,0x01AF,0x01AE,0x01AD,0x01AD,0x01AC, + 0x01AB,0x01AA,0x01A9,0x01A9,0x01A8,0x01A7,0x01A6,0x01A6, + 0x01A5,0x01A4,0x01A3,0x01A2,0x01A2,0x01A1,0x01A0,0x019F + }; + int cut_value = 5; //cut_value < 32 + if(pos == 0xfff) + { + return pos; + } + if(x_y) //xpos + { + dbg("X: Raw data %d\n",pos); + if (pos >=XPOS_MAX) + { + pos = XPOS_MAX; + } + if (pos<64) + { + pos = Cut_Edge_XLeft[pos]; //Left cut edge + } + else + if ((XPOS_MAX - pos) <64) + { + pos = Cut_Edge_XRight[XPOS_MAX - pos]; //Right cut edge + } + else + { + pos = pos + cut_value; // + pos = SSDS53X_SCREEN_MAX_X* pos / (790 + cut_value*2);//SSD253X_SCREEN_MAX_X|?????2????????|? + } + dbg("X: Cut edge data %d\n",pos); + return pos; + } + else //ypos + { + + dbg("Y: Raw data %d\n",pos); + if (pos >=YPOS_MAX) + { + pos = YPOS_MAX; + } + if (pos<64) + { + pos = Cut_Edge_YUp[pos]; //Up cut edge + } + else + if ((YPOS_MAX - pos) <64) + { + pos = Cut_Edge_YDown[YPOS_MAX - pos]; //Down cut edge + } + else + { + pos = pos + cut_value; // + pos = SSDS53X_SCREEN_MAX_Y* pos / (470 + cut_value*2);//SSD253X_SCREEN_MAX_X|?????2????????|? + //tpos = pos; + //tpos = /*SSDS53X_SCREEN_MAX_Y*/ (800* pos) / (470 + cut_value*2); + dbg("XPOS_MAX=%d,\n", XPOS_MAX); + dbg("YPOS_MAX=%d,\n",YPOS_MAX); + dbg("Y: Cut edge data pos= %d,tpos=%d\n",pos,tpos); + } + + return pos; + } + + +} + +static int ssd253x_ts_cut_edge5(unsigned short pos,unsigned short x_y) +{ + unsigned short Cut_Edge_XLeft[64]={ + 0x0008,0x0009,0x000B,0x000C,0x000D,0x000E,0x0010,0x0011, + 0x0012,0x0013,0x0015,0x0016,0x0017,0x0018,0x001A,0x001B, + 0x001C,0x001D,0x001F,0x0020,0x0021,0x0022,0x0024,0x0025, + 0x0026,0x0026,0x0027,0x0028,0x0029,0x002A,0x002B,0x002C, + 0x002C,0x002D,0x002E,0x002F,0x0030,0x0031,0x0032,0x0032, + 0x0033,0x0034,0x0035,0x0036,0x0037,0x0038,0x0038,0x0039, + 0x003A,0x003B,0x003C,0x003D,0x003E,0x003E,0x003F,0x0040, + 0x0041,0x0042,0x0043,0x0044,0x0044,0x0045,0x0046,0x0047 + }; + + unsigned short Cut_Edge_XRight[64]={ + 0x0318,0x0317,0x0315,0x0314,0x0313,0x0312,0x0310,0x030F, + 0x030E,0x030D,0x030B,0x030A,0x0309,0x0308,0x0306,0x0305, + 0x0304,0x0303,0x0301,0x0300,0x02FF,0x02FE,0x02FC,0x02FB, + 0x02FA,0x02FA,0x02F9,0x02F8,0x02F7,0x02F6,0x02F5,0x02F4, + 0x02F4,0x02F3,0x02F2,0x02F1,0x02F0,0x02EF,0x02EE,0x02EE, + 0x02ED,0x02EC,0x02EB,0x02EA,0x02E9,0x02E8,0x02E8,0x02E7, + 0x02E6,0x02E5,0x02E4,0x02E3,0x02E2,0x02E2,0x02E1,0x02E0, + 0x02DF,0x02DE,0x02DD,0x02DC,0x02DC,0x02DB,0x02DA,0x02D9 + }; + + unsigned short Cut_Edge_YUp[64]={ + 0x0006,0x0007,0x0008,0x000A,0x000B,0x000C,0x000D,0x000F, + 0x0010,0x0011,0x0012,0x0014,0x0015,0x0016,0x0017,0x0018, + 0x001A,0x001B,0x001C,0x001D,0x001F,0x0020,0x0021,0x0022, + 0x0022,0x0023,0x0024,0x0025,0x0025,0x0026,0x0027,0x0028, + 0x0029,0x0029,0x002A,0x002B,0x002C,0x002C,0x002D,0x002E, + 0x002F,0x0030,0x0030,0x0031,0x0032,0x0033,0x0033,0x0034, + 0x0035,0x0036,0x0037,0x0037,0x0038,0x0039,0x003A,0x003A, + 0x003B,0x003C,0x003D,0x003E,0x003E,0x003F,0x0040,0x0041 + }; + + unsigned short Cut_Edge_YDown[64]={ + 0x01DA,0x01D9,0x01D8,0x01D6,0x01D5,0x01D4,0x01D3,0x01D1, + 0x01D0,0x01CF,0x01CE,0x01CC,0x01CB,0x01CA,0x01C9,0x01C8, + 0x01C6,0x01C5,0x01C4,0x01C3,0x01C1,0x01C0,0x01BF,0x01BE, + 0x01BE,0x01BD,0x01BC,0x01BB,0x01BB,0x01BA,0x01B9,0x01B8, + 0x01B7,0x01B7,0x01B6,0x01B5,0x01B4,0x01B4,0x01B3,0x01B2, + 0x01B1,0x01B0,0x01B0,0x01AF,0x01AE,0x01AD,0x01AD,0x01AC, + 0x01AB,0x01AA,0x01A9,0x01A9,0x01A8,0x01A7,0x01A6,0x01A6, + 0x01A5,0x01A4,0x01A3,0x01A2,0x01A2,0x01A1,0x01A0,0x019F + }; + u8 cut_value = 20; //cut_value < 32 + if(pos == 0xfff) + { + return pos; + } + if(x_y) //xpos + { + dbg("X: Raw data %d\n",pos); + if (pos >=XPOS_MAX) + { + pos = XPOS_MAX; + } + if (pos<64) + { + pos = Cut_Edge_XLeft[pos]; //Left cut edge + } + else + if ((XPOS_MAX - pos) <64) + { + pos = Cut_Edge_XRight[XPOS_MAX - pos]; //Right cut edge + } + else + { + pos = pos + cut_value; // + pos = SSDS53X_SCREEN_MAX_X * pos / (XPOS_MAX + cut_value*2);//SSD253X_SCREEN_MAX_X|??????????|? } + dbg("X: Cut edge data %d\n",pos); + return pos; + } + } + else //ypos + { + + dbg("Y: Raw data %d\n",pos); + if (pos >=YPOS_MAX) + { + pos = YPOS_MAX; + } + if (pos<64) + { + pos = Cut_Edge_YUp[pos]; //Up cut edge + } + else + if ((YPOS_MAX - pos) <64) + { + pos = Cut_Edge_YDown[YPOS_MAX - pos]; //Down cut edge + } + else + { + pos = pos + cut_value; // + pos = SSDS53X_SCREEN_MAX_Y * pos / (YPOS_MAX + cut_value*2);//SSD253X_SCREEN_MAX_X|??????????|? } + dbg("Y: Cut edge data %d\n",pos); + return pos; + } + } + return -1; +} + +static int ssd253x_ts_cut_edge6(unsigned short pos,unsigned short x_y) +{ + + #define XPOS_MAX_D (DRIVENO -EdgeDisable) *64 + #define YPOS_MAX_D (SENSENO -EdgeDisable) *64 + #undef SSD253X_SCREEN_MAX_X + #define SSD253X_SCREEN_MAX_X 800 + #define SSD253X_SCREEN_MAX_Y 480 + + u8 cut_value = 20; //cut_value < 32 + unsigned short Cut_Edge_XLeft[64]={ + 0x0008,0x0009,0x000B,0x000C,0x000D,0x000E,0x0010,0x0011, + 0x0012,0x0013,0x0015,0x0016,0x0017,0x0018,0x001A,0x001B, + 0x001C,0x001D,0x001F,0x0020,0x0021,0x0022,0x0024,0x0025, + 0x0026,0x0026,0x0027,0x0028,0x0029,0x002A,0x002B,0x002C, + 0x002C,0x002D,0x002E,0x002F,0x0030,0x0031,0x0032,0x0032, + 0x0033,0x0034,0x0035,0x0036,0x0037,0x0038,0x0038,0x0039, + 0x003A,0x003B,0x003C,0x003D,0x003E,0x003E,0x003F,0x0040, + 0x0041,0x0042,0x0043,0x0044,0x0044,0x0045,0x0046,0x0047 + }; + + unsigned short Cut_Edge_XRight[64]={ + 0x0318,0x0317,0x0315,0x0314,0x0313,0x0312,0x0310,0x030F, + 0x030E,0x030D,0x030B,0x030A,0x0309,0x0308,0x0306,0x0305, + 0x0304,0x0303,0x0301,0x0300,0x02FF,0x02FE,0x02FC,0x02FB, + 0x02FA,0x02FA,0x02F9,0x02F8,0x02F7,0x02F6,0x02F5,0x02F4, + 0x02F4,0x02F3,0x02F2,0x02F1,0x02F0,0x02EF,0x02EE,0x02EE, + 0x02ED,0x02EC,0x02EB,0x02EA,0x02E9,0x02E8,0x02E8,0x02E7, + 0x02E6,0x02E5,0x02E4,0x02E3,0x02E2,0x02E2,0x02E1,0x02E0, + 0x02DF,0x02DE,0x02DD,0x02DC,0x02DC,0x02DB,0x02DA,0x02D9 + }; + + unsigned short Cut_Edge_YUp[64]={ + 0x0006,0x0007,0x0008,0x000A,0x000B,0x000C,0x000D,0x000F, + 0x0010,0x0011,0x0012,0x0014,0x0015,0x0016,0x0017,0x0018, + 0x001A,0x001B,0x001C,0x001D,0x001F,0x0020,0x0021,0x0022, + 0x0022,0x0023,0x0024,0x0025,0x0025,0x0026,0x0027,0x0028, + 0x0029,0x0029,0x002A,0x002B,0x002C,0x002C,0x002D,0x002E, + 0x002F,0x0030,0x0030,0x0031,0x0032,0x0033,0x0033,0x0034, + 0x0035,0x0036,0x0037,0x0037,0x0038,0x0039,0x003A,0x003A, + 0x003B,0x003C,0x003D,0x003E,0x003E,0x003F,0x0040,0x0041 + }; + + unsigned short Cut_Edge_YDown[64]={ + 0x01DA,0x01D9,0x01D8,0x01D6,0x01D5,0x01D4,0x01D3,0x01D1, + 0x01D0,0x01CF,0x01CE,0x01CC,0x01CB,0x01CA,0x01C9,0x01C8, + 0x01C6,0x01C5,0x01C4,0x01C3,0x01C1,0x01C0,0x01BF,0x01BE, + 0x01BE,0x01BD,0x01BC,0x01BB,0x01BB,0x01BA,0x01B9,0x01B8, + 0x01B7,0x01B7,0x01B6,0x01B5,0x01B4,0x01B4,0x01B3,0x01B2, + 0x01B1,0x01B0,0x01B0,0x01AF,0x01AE,0x01AD,0x01AD,0x01AC, + 0x01AB,0x01AA,0x01A9,0x01A9,0x01A8,0x01A7,0x01A6,0x01A6, + 0x01A5,0x01A4,0x01A3,0x01A2,0x01A2,0x01A1,0x01A0,0x019F + }; + + + if(pos == 0xfff) + { + return pos; + } + if(x_y) //xpos + { + //#ifdef CONFIG_TS_CUTEDGE_DEBUG + dbg("X: Raw data %d\n",pos); + //#endif + if (pos >=XPOS_MAX_D) + { + pos = XPOS_MAX_D; + } + if (pos<64) + { + pos = Cut_Edge_XLeft[pos]; //Left cut edge + } + else + if ((XPOS_MAX_D - pos) <64) + { + pos = Cut_Edge_XRight[XPOS_MAX_D - pos]; //Right cut edge + } + else + { + pos = pos + cut_value; // + pos = SSD253X_SCREEN_MAX_X * pos / (XPOS_MAX_D + cut_value*2);//SSD253X_SCREEN_MAX_X|?????2????????|? + } + //#ifdef CONFIG_TS_CUTEDGE_DEBUG + dbg("X: Cut edge data %d\n",pos); + //#endif + return pos; + } + else //ypos + { + + //#ifdef CONFIG_TS_CUTEDGE_DEBUG + dbg("Y: Raw data %d\n",pos); + //#endif + if (pos >=YPOS_MAX_D) + { + pos = YPOS_MAX_D; + } + if (pos<64) + { + pos = Cut_Edge_YUp[pos]; //Up cut edge + } + else + if ((YPOS_MAX_D - pos) <64) + { + pos = Cut_Edge_YDown[YPOS_MAX_D - pos]; //Down cut edge + } + else + { + pos = pos + cut_value; // + pos = SSD253X_SCREEN_MAX_Y * pos / (YPOS_MAX_D + cut_value*2);//SSD253X_SCREEN_MAX_X|?????2????????|? + } + //#ifdef CONFIG_TS_CUTEDGE_DEBUG + dbg("Y: Cut edge data %d\n",pos); + //#endif + return pos; + } + return -1; +} + +static int ssd253x_ts_cut_edge8(unsigned short pos,unsigned short x_y) +{ + + #define XPOS_MAX_D (DRIVENO -EdgeDisable) *64 + #define YPOS_MAX_D (SENSENO -EdgeDisable) *64 + #undef SSD253X_SCREEN_MAX_X + #define SSD253X_SCREEN_MAX_X 780 + #undef SSD253X_SCREEN_MAX_Y + #define SSD253X_SCREEN_MAX_Y 470 + + u8 cut_value = 10;//30; //cut_value < 32 + unsigned short Cut_Edge_XLeft[64]={ + 0x0008,0x0009,0x000B,0x000C,0x000D,0x000E,0x0010,0x0011, + 0x0012,0x0013,0x0015,0x0016,0x0017,0x0018,0x001A,0x001B, + 0x001C,0x001D,0x001F,0x0020,0x0021,0x0022,0x0024,0x0025, + 0x0026,0x0026,0x0027,0x0028,0x0029,0x002A,0x002B,0x002C, + 0x002C,0x002D,0x002E,0x002F,0x0030,0x0031,0x0032,0x0032, + 0x0033,0x0034,0x0035,0x0036,0x0037,0x0038,0x0038,0x0039, + 0x003A,0x003B,0x003C,0x003D,0x003E,0x003E,0x003F,0x0040, + 0x0041,0x0042,0x0043,0x0044,0x0044,0x0045,0x0046,0x0047 + }; + + unsigned short Cut_Edge_XRight[64]={ + 0x0318,0x0317,0x0315,0x0314,0x0313,0x0312,0x0310,0x030F, + 0x030E,0x030D,0x030B,0x030A,0x0309,0x0308,0x0306,0x0305, + 0x0304,0x0303,0x0301,0x0300,0x02FF,0x02FE,0x02FC,0x02FB, + 0x02FA,0x02FA,0x02F9,0x02F8,0x02F7,0x02F6,0x02F5,0x02F4, + 0x02F4,0x02F3,0x02F2,0x02F1,0x02F0,0x02EF,0x02EE,0x02EE, + 0x02ED,0x02EC,0x02EB,0x02EA,0x02E9,0x02E8,0x02E8,0x02E7, + 0x02E6,0x02E5,0x02E4,0x02E3,0x02E2,0x02E2,0x02E1,0x02E0, + 0x02DF,0x02DE,0x02DD,0x02DC,0x02DC,0x02DB,0x02DA,0x02D9 + }; + + unsigned short Cut_Edge_YUp[64]={ + 0x0006,0x0007,0x0008,0x000A,0x000B,0x000C,0x000D,0x000F, + 0x0010,0x0011,0x0012,0x0014,0x0015,0x0016,0x0017,0x0018, + 0x001A,0x001B,0x001C,0x001D,0x001F,0x0020,0x0021,0x0022, + 0x0022,0x0023,0x0024,0x0025,0x0025,0x0026,0x0027,0x0028, + 0x0029,0x0029,0x002A,0x002B,0x002C,0x002C,0x002D,0x002E, + 0x002F,0x0030,0x0030,0x0031,0x0032,0x0033,0x0033,0x0034, + 0x0035,0x0036,0x0037,0x0037,0x0038,0x0039,0x003A,0x003A, + 0x003B,0x003C,0x003D,0x003E,0x003E,0x003F,0x0040,0x0041 + }; + + unsigned short Cut_Edge_YDown[64]={ + 0x01DA,0x01D9,0x01D8,0x01D6,0x01D5,0x01D4,0x01D3,0x01D1, + 0x01D0,0x01CF,0x01CE,0x01CC,0x01CB,0x01CA,0x01C9,0x01C8, + 0x01C6,0x01C5,0x01C4,0x01C3,0x01C1,0x01C0,0x01BF,0x01BE, + 0x01BE,0x01BD,0x01BC,0x01BB,0x01BB,0x01BA,0x01B9,0x01B8, + 0x01B7,0x01B7,0x01B6,0x01B5,0x01B4,0x01B4,0x01B3,0x01B2, + 0x01B1,0x01B0,0x01B0,0x01AF,0x01AE,0x01AD,0x01AD,0x01AC, + 0x01AB,0x01AA,0x01A9,0x01A9,0x01A8,0x01A7,0x01A6,0x01A6, + 0x01A5,0x01A4,0x01A3,0x01A2,0x01A2,0x01A1,0x01A0,0x019F + }; + + + if(pos == 0xfff) + { + return pos; + } + if(x_y) //xpos + { + //#ifdef CONFIG_TS_CUTEDGE_DEBUG + dbg("X: Raw data %d\n",pos); + //#endif + if (pos >=XPOS_MAX_D) + { + pos = XPOS_MAX_D; + } + if (pos<64) + { + pos = Cut_Edge_XLeft[pos]; //Left cut edge + } + else + if ((XPOS_MAX_D - pos) <64) + { + pos = Cut_Edge_XRight[XPOS_MAX_D - pos]; //Right cut edge + } + else + { + pos = pos + cut_value; // + pos = SSD253X_SCREEN_MAX_X * pos / (XPOS_MAX_D + cut_value*2);//SSD253X_SCREEN_MAX_X|?????2????????|? + } + //#ifdef CONFIG_TS_CUTEDGE_DEBUG + dbg("X: Cut edge data %d\n",pos); + //#endif + return pos; + } + else //ypos + { + + //#ifdef CONFIG_TS_CUTEDGE_DEBUG + dbg("Y: Raw data %d\n",pos); + //#endif + if (pos >=YPOS_MAX_D) + { + pos = YPOS_MAX_D; + } + if (pos<64) + { + pos = Cut_Edge_YUp[pos]; //Up cut edge + } + else + if ((YPOS_MAX_D - pos) <64) + { + pos = Cut_Edge_YDown[YPOS_MAX_D - pos]; //Down cut edge + } + else + { + pos = pos + cut_value; // + pos = SSD253X_SCREEN_MAX_Y * pos / (YPOS_MAX_D + cut_value*2);//SSD253X_SCREEN_MAX_X|?????2????????|? + } + //#ifdef CONFIG_TS_CUTEDGE_DEBUG + dbg("Y: Cut edge data %d\n",pos); + //#endif + return pos; + } +} + +static int ssd253x_ts_cut_edge7(unsigned short pos,unsigned short x_y) +{ + unsigned short SENSENO_7 = 15; + unsigned short DRIVENO_7 = 20; + unsigned short EdgeDisable_7 = 1; // if Edge Disable, set it to 1, else reset to 0, OR SSD2533 set 0 + unsigned short XPOS_MAX_7 = (DRIVENO_7 -EdgeDisable_7) *64; + unsigned short YPOS_MAX_7 = (SENSENO_7 -EdgeDisable_7) *64; + + u8 cut_value = 10; //cut_value < 32 + dbg("enter...\n"); + + if(pos == 0xfff) + { + return pos; + } + if(x_y) //xpos + { + if(pos < 16) + pos = cut_value + pos*(48 - cut_value) / 16; + else if(pos > (XPOS_MAX_7 - 16) ) + pos = XPOS_MAX_7 + 16 + (pos - (XPOS_MAX_7 -16))*(48 - cut_value) / 16; + else + pos = pos + 32; + dbg("xpos_b:%d\n", pos); + pos = SSDS53X_SCREEN_MAX_X * pos / (DRIVENO_7 * 64); + dbg("xpos_a:%d\n", pos); + return pos; + } + else //ypos + { + if(pos < 16) + pos = cut_value + pos*(48 - cut_value) / 16; + else if(pos > (YPOS_MAX_7 - 16) ) + pos = YPOS_MAX_7 + 16 + (pos - (YPOS_MAX_7 -16))*(48 - cut_value) / 16; + else + pos = pos + 32; + dbg("ypos_b:%d\n", pos); + pos = SSDS53X_SCREEN_MAX_Y* pos / (SENSENO_7 * 64); + dbg("ypos_a:%d\n", pos); + return pos; + } + + +} + + +static int ssd253x_ts_cut_edge(unsigned short pos,unsigned short x_y) +{ + switch (wmt_ts_get_cutedge()) + { + case 0: + return ssd253x_ts_cut_edge0(pos,x_y); + break; + case 1: + return ssd253x_ts_cut_edge1(pos,x_y); + break; + case 2: + return ssd253x_ts_cut_edge2(pos,x_y); + break; + case 3: + return ssd253x_ts_cut_edge3(pos,x_y); + break; + case 4: + return ssd253x_ts_cut_edge4(pos,x_y); + break; + case 5: + return ssd253x_ts_cut_edge5(pos,x_y); + break; + case 6: + return ssd253x_ts_cut_edge6(pos,x_y); + break; + case 7: + return ssd253x_ts_cut_edge7(pos,x_y); + break; + case 8: + return ssd253x_ts_cut_edge8(pos,x_y); + break; + default: + return -1; + }; +} + +#ifdef USE_TOUCH_KEY +static u8 btn_status_last = 0; +#endif + +static void ssd253x_ts_work(struct work_struct *work) +{ + int i; + unsigned short xpos=0, ypos=0; + int tx,ty; + //width=0; + int FingerInfo; + int EventStatus; + int FingerX[FINGERNO]; + int FingerY[FINGERNO]; + int FingerP[FINGERNO]; + int clrFlag=0; + int Ssd_Timer; + #ifdef USE_TOUCH_KEY + u8 btn_status; + u8 btn_status_last = 0; + #endif + + struct ssl_ts_priv *ssl_priv = l_ts; + + #ifdef USE_TOUCH_KEY + btn_status = ReadRegister(ssl_priv->client,SELFCAP_STATUS_REG, 1); + //#ifdef CONFIG_TOUCHSCREEN_SSL_DEBUG + dbg("btn pressed:%x\n", btn_status & 0x0f); + //#endif + if (btn_status_last != btn_status){ + if(btn_status){ + btn_status_last = btn_status; + ssd2533_ts_send_keyevent(ssl_priv,btn_status, 1); + dbg("send %x btn_status_last%d \n", btn_status,btn_status_last); + } + else{ + ssd2533_ts_send_keyevent(ssl_priv,btn_status_last, 0); + btn_status_last = 0; + dbg("btn_status_last %x \n", btn_status_last); + } + return ; + } + #endif + + Ssd_Timer = 0; + if(ic_flag == IC_SSD2533){ + if(!Ssd_Timer_flag){ + Ssd_Timer = ReadRegister(TIMESTAMP_REG,2); + if(!Ssd_Timer1){ + Ssd_Timer1 = Ssd_Timer/1000; + } + + Ssd_Timer2 = Ssd_Timer/1000; + + + if((Ssd_Timer2 - Ssd_Timer1) > 10){ + WriteRegister(AUTO_INIT_RST_REG,0x00,0x00,1); + Ssd_Timer_flag = 1; + } + } + } + + EventStatus = ReadRegister(EVENT_STATUS,2)>>4; + ssl_priv->FingerDetect=0; + for(i=0;iFingerNo;i++){ + if((EventStatus>>i)&0x1){ + FingerInfo=ReadRegister(FINGER01_REG+i,4); + xpos = ((FingerInfo>>4)&0xF00)|((FingerInfo>>24)&0xFF); + ypos = ((FingerInfo>>0)&0xF00)|((FingerInfo>>16)&0xFF); + dbg("raw data before cut, F%d:(%d,%d)\n",i,xpos,ypos); + if(xpos!=0xFFF){ + ssl_priv->FingerDetect++; + if (wmt_ts_get_cutedge()>=0){ + xpos = ssd253x_ts_cut_edge(xpos, 1); + ypos = ssd253x_ts_cut_edge(ypos, 0); + } + }else { + EventStatus=EventStatus&~(1<use_irq==1) wmt_enable_gpirq(); + if(ssl_priv->use_irq==2) + { + if(ssl_priv->FingerDetect==0) + { + wmt_enable_gpirq(); + } else { + hrtimer_start(&ssl_priv->timer, ktime_set(0, MicroTimeTInterupt), HRTIMER_MODE_REL); + } + } + if(ic_flag == IC_SSD2533){ + if(clrFlag) WriteRegister(EVENT_FIFO_SCLR,0x01,0x00,1); + } + + if(ssl_priv->input->id.product==0x2533) + if(ssl_priv->input->id.version==0x0101) + FingerCheckSwap(FingerX,FingerY,FingerP,ssl_priv->FingerNo,ssl_priv->sFingerX,ssl_priv->sFingerY); + + // report data + for(i=0;iFingerNo;i++) + { + xpos=FingerX[i]; + ypos=FingerY[i]; + if(ssl_priv->input->id.product==0x2533){ + if(ssl_priv->input->id.version==0x0101) RunningAverage(&xpos,&ypos,i,ssl_priv); + if(ssl_priv->input->id.version==0x0102) RunningAverage(&xpos,&ypos,i,ssl_priv); + } + + if(xpos!=0xFFF) + { + dbg("raw data after cut, F%d:(%d,%d)\n",i,xpos,ypos); + switch (wmt_ts_get_xaxis()) + { + case 1: + tx = ypos; + break; + case 0: + default: + tx = xpos; + break; + } + + switch (wmt_ts_get_xdir()) + { + case 1: + break; + case -1: + tx = SSDS53X_SCREEN_MAX_Y - tx; + break; + default: + break; + }; + + if (tx <0){ + tx = 0; + } else if (tx >= SSDS53X_SCREEN_MAX_Y){ + tx = SSDS53X_SCREEN_MAX_Y-1; + } + switch (wmt_ts_get_yaxis()) + { + + case 0: + ty = xpos; + break; + case 1: + default: + ty = ypos; + break; + } + + switch (wmt_ts_get_ydir()) + { + case 1: + break; + case -1: + ty = SSDS53X_SCREEN_MAX_X - ty; + default: + break; + } + + if (ty < 0){ + ty = 0; + } else if (ty >=SSDS53X_SCREEN_MAX_X){ + ty = SSDS53X_SCREEN_MAX_X-1; + } + + if (wmt_ts_get_lcdexchg()) { + int tmp; + tmp = tx; + tx = ty; + ty = wmt_ts_get_resolvX() - tmp; + } + + ssd253x_tsdev.penup = 0; + input_report_abs(ssl_priv->input, ABS_MT_POSITION_X, tx); + input_report_abs(ssl_priv->input, ABS_MT_POSITION_Y, ty); + /*input_report_abs(ssl_priv->input, ABS_MT_POSITION_X, ty); + input_report_abs(ssl_priv->input, ABS_MT_POSITION_Y, tx);*/ + input_mt_sync(ssl_priv->input); + dbg("report data x=%d,y=%d\n", tx, ty); + + } + else if(ssl_priv->FingerX[i]!=0xFFF){ + input_mt_sync(ssl_priv->input); + //printk("pen up...\n"); + ssd253x_tsdev.penup = 1; + } + + ssl_priv->FingerX[i]=FingerX[i]; + ssl_priv->FingerY[i]=FingerY[i]; + } + + ssl_priv->EventStatus=EventStatus; + input_sync(ssl_priv->input); + if (1 == ssd253x_tsdev.penup){ + wake_up(&ts_penup_wait_queue); + } + +} + + +#define TPIC_INT_PLLLING 0 +#define TPIC_INT_INTERUPT 1 +#define TPIC_INT_HYBRID 2 + + +static int ssd253x_probe(struct platform_device *pdev) +{ + struct ssl_ts_priv *ssl_priv; + struct input_dev *ssl_input; + int error; + int i; + //unsigned int prescale; + + //#ifdef SD_INIT + // g_tp_client = l_client; + //#endif + + SSDS53X_SCREEN_MAX_X = wmt_ts_get_resolvY(); + SSDS53X_SCREEN_MAX_Y = wmt_ts_get_resolvX(); + + ssl_priv = kzalloc(sizeof(*ssl_priv), GFP_KERNEL); + if (!ssl_priv) + { + errlog(" kzalloc Error!\n"); + error=-ENODEV; + goto err0; + } + l_ts = ssl_priv; + + ssl_input = input_allocate_device(); + if (!ssl_input) + { + errlog(" ssd253x_ts_probe: input_allocate_device Error\n"); + error=-ENODEV; + goto freealloc; + } + ssl_input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) | BIT_MASK(EV_SYN) ; + set_bit(INPUT_PROP_DIRECT,ssl_input->propbit); + ssl_input->name = DEVICE_NAME; + ssl_input->id.bustype = BUS_I2C; + ssl_input->id.vendor = 0x2878; // Modify for Vendor ID + + ssl_priv->input = ssl_input; + + ssl_priv->FingerNo=wmt_ts_get_fingernum();//FINGERNO; + ssl_priv->Resolution=64; + + for(i=0;iFingerNo;i++) + { + ssl_priv->sFingerX[i]=0xFFF; + ssl_priv->sFingerY[i]=0xFFF; + + // For Adaptive Running Average + ssl_priv->pFingerX[i]=0xFFF; + ssl_priv->pFingerY[i]=0xFFF; + } + + deviceReset(); + ssl_input->id.product = ReadRegister(DEVICE_ID_REG,2); + ssl_input->id.version = ReadRegister(VERSION_ID_REG,2); + ssl_input->id.product = ReadRegister(DEVICE_ID_REG,2); + + ssl_input->id.version = ReadRegister(VERSION_ID_REG,2); + klog("SSL Touchscreen Device ID : 0x%04X\n",ssl_input->id.product); + klog("SSL Touchscreen Version ID : 0x%04X\n",ssl_input->id.version); + + if(ssl_input->id.product == 0x2531){ + ic_flag = IC_SSD2531; + }else if(ssl_input->id.product == 0x2533) { + ic_flag = IC_SSD2533; + }else if(ssl_input->id.product == 0x2543) { + ic_flag = IC_SSD2543; + } + + if(ic_flag == IC_SSD2533) { + ssl_priv->use_irq = TPIC_INT_HYBRID; + }else if(ic_flag == IC_SSD2543) { + ssl_priv->use_irq = TPIC_INT_INTERUPT; + } + + SSD253xdeviceInit(); + if(ic_flag == IC_SSD2533) { + WriteRegister(EVENT_FIFO_SCLR,0x01,0x00,1); // clear Event FiFo + } + + + if(ssl_priv->input->id.product==0x2531) + ssl_priv->Resolution=32; + else if(ssl_priv->input->id.product==0x2533) + ssl_priv->Resolution=64; + + + if (wmt_ts_get_lcdexchg()) { + input_set_abs_params(ssl_input, ABS_MT_POSITION_X, 0,wmt_ts_get_resolvY(), 0, 0); + input_set_abs_params(ssl_input, ABS_MT_POSITION_Y, 0,wmt_ts_get_resolvX(), 0, 0); + } else { + input_set_abs_params(ssl_input, ABS_MT_POSITION_X, 0,wmt_ts_get_resolvX(), 0, 0); + input_set_abs_params(ssl_input, ABS_MT_POSITION_Y, 0,wmt_ts_get_resolvY(), 0, 0); + } + +#ifdef USE_TOUCH_KEY + set_bit(KEY_MENU, ssl_input->keybit); + set_bit(KEY_HOME, ssl_input->keybit); + set_bit(KEY_BACK, ssl_input->keybit); + set_bit(KEY_SEARCH, ssl_input->keybit); + #endif + error = input_register_device(ssl_input); + if(error) + { + errlog("input_register_device input Error!\n"); + error=-ENODEV; + goto panel_init_fail; + } + if((ssl_priv->use_irq==0)||(ssl_priv->use_irq==2)) + { + hrtimer_init(&ssl_priv->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + ssl_priv->timer.function = ssd253x_ts_timer; + //#ifdef CONFIG_TOUCHSCREEN_SSL_DEBUG + dbg(" ssd253x_ts_probe: timer_init OK!\n"); + //#endif + } + + ssd253x_wq = create_singlethread_workqueue("ssd253x_wq"); + INIT_WORK(&ssl_priv->ssl_work, ssd253x_ts_work); + error = request_irq(wmt_get_tsirqnum(), ssd253x_ts_isr, IRQF_SHARED, "ssd253x_ts_q", l_ts); + if(error){ + errlog("request_irq Error!\n"); + error=-ENODEV; + goto freeque; + } + + wmt_set_gpirq(IRQ_TYPE_EDGE_FALLING); + wmt_disable_gpirq(); + + +#ifdef CONFIG_HAS_EARLYSUSPEND + ssl_priv->early_suspend.suspend = ssd253x_ts_early_suspend; + ssl_priv->early_suspend.resume = ssd253x_ts_late_resume; + ssl_priv->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN+2; + register_early_suspend(&ssl_priv->early_suspend); +#endif + deviceResume(); + wmt_enable_gpirq(); + dbg("SSD253X init ok!\n"); + return 0; + +freeque: + destroy_workqueue(ssd253x_wq); + input_unregister_device(ssl_input); +panel_init_fail: + input_free_device(ssl_input); +freealloc: + kfree(ssl_priv); +err0: + //dev_set_drvdata(&client->dev, NULL); + return error; +} + +static int ssd253x_remove(struct platform_device *pdev) +{ + struct ssl_ts_priv *ssl_priv = l_ts; + + if((ssl_priv->use_irq==0)||(ssl_priv->use_irq==2)) hrtimer_cancel(&ssl_priv->timer); + + //disable int + wmt_disable_gpirq(); + //free irq + free_irq(wmt_get_tsirqnum(), l_ts); +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&ssl_priv->early_suspend); +#endif + // free queue + cancel_work_sync (&ssl_priv->ssl_work); + flush_workqueue(ssd253x_wq); + destroy_workqueue(ssd253x_wq); + input_unregister_device(ssl_priv->input); + input_free_device(ssl_priv->input); + kfree(ssl_priv); + l_ts = NULL; + return 0; +} + + +/* +static int ssd253x_ts_open(struct input_dev *dev) +{ + struct ssl_ts_priv *ssl_priv = l_ts; + + deviceResume(); + if(ssl_priv->use_irq) + { + wmt_enable_gpirq(); //(ssl_priv->irq); + } else { + hrtimer_start(&ssl_priv->timer, ktime_set(1, 0), HRTIMER_MODE_REL); + } + return 0; +} + + +static void ssd253x_ts_close(struct input_dev *dev) +{ + struct ssl_ts_priv *ssl_priv = l_ts; + + // disable interrupt + deviceSuspend(); + if((ssl_priv->use_irq==0)||(ssl_priv->use_irq==2)) + hrtimer_cancel(&ssl_priv->timer); + if((ssl_priv->use_irq==1)||(ssl_priv->use_irq==2)) + wmt_disable_gpirq();//(ssl_priv->irq); +} +*/ +static int ssd253x_resume(struct platform_device *pdev) +{ + struct ssl_ts_priv *ssl_priv = l_ts; + + wmt_disable_gpirq(); + Ssd_Timer_flag = 0; + deviceReset(); + SSD253xdeviceInit(); + if(ic_flag == IC_SSD2533){ + WriteRegister(EVENT_FIFO_SCLR,0x01,0x00,1); // clear Event FiFo + } + deviceResume(); + wmt_set_gpirq(IRQ_TYPE_EDGE_FALLING); + wmt_enable_gpirq(); + + if(! ssl_priv->use_irq) + { + hrtimer_start(&ssl_priv->timer, ktime_set(1, 0), HRTIMER_MODE_REL); + } + ssl_priv->earlysus = 0; + return 0; +} + +static int ssd253x_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct ssl_ts_priv *ssl_priv = l_ts; + + if((ssl_priv->use_irq==0)||(ssl_priv->use_irq==2)) hrtimer_cancel(&ssl_priv->timer); + // disable irq + wmt_disable_gpirq(); + Ssd_Timer_flag = 0; + if(ic_flag == IC_SSD2533){ + deviceSuspend(); + }else if(ic_flag == IC_SSD2543){ + deviceReset(); + } + return 0; +} + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void ssd253x_ts_late_resume(struct early_suspend *h) +{ + struct ssl_ts_priv *ssl_priv = l_ts; + + dbg("...\n"); + if (ssl_priv->earlysus != 0) + { + wmt_disable_gpirq(); + Ssd_Timer_flag = 0; + deviceReset(); + SSD253xdeviceInit(); + WriteRegister(EVENT_FIFO_SCLR,0x01,0x00,1); // clear Event FiFo + deviceResume(); + wmt_set_gpirq(IRQ_TYPE_EDGE_FALLING); + wmt_enable_gpirq(); + + if(! ssl_priv->use_irq) + { + hrtimer_start(&ssl_priv->timer, ktime_set(1, 0), HRTIMER_MODE_REL); + } + ssl_priv->earlysus = 0; + } +} +static void ssd253x_ts_early_suspend(struct early_suspend *h) +{ + struct ssl_ts_priv *ssl_priv = l_ts; + + ssl_priv->earlysus = 1; + if((ssl_priv->use_irq==0)||(ssl_priv->use_irq==2)) hrtimer_cancel(&ssl_priv->timer); + // disable irq + wmt_disable_gpirq(); + Ssd_Timer_flag = 0; + deviceSuspend(); + + return; +} +#endif + + +static irqreturn_t ssd253x_ts_isr(int irq, void *dev_id) +{ + struct ssl_ts_priv *ssl_priv = l_ts; + + if (wmt_is_tsint()) + { + wmt_clr_int(); + if (wmt_is_tsirq_enable()) + { + wmt_disable_gpirq(); + dbg("begin..\n"); + if(!ssl_priv->earlysus) + { + queue_work(ssd253x_wq, &ssl_priv->ssl_work); + } + } + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static enum hrtimer_restart ssd253x_ts_timer(struct hrtimer *timer) +{ + struct ssl_ts_priv *ssl_priv = container_of(timer, struct ssl_ts_priv, timer); + #ifdef CONFIG_TOUCHSCREEN_SSL_DEBUG + printk("+-----------------------------------------+\n"); + printk("| ssd253x_ts_timer! |\n"); + printk("+-----------------------------------------+\n"); + #endif + queue_work(ssd253x_wq, &ssl_priv->ssl_work); + if(ssl_priv->use_irq==0) hrtimer_start(&ssl_priv->timer, ktime_set(0, MicroTimeTInterupt), HRTIMER_MODE_REL); + return HRTIMER_NORESTART; +} + +#ifdef SD_INIT +static const struct file_operations tp_fops = { + .owner = THIS_MODULE, + .read = tp_read, + .write = tp_write, + .unlocked_ioctl = tp_ioctl, + .open = tp_open, + .release = tp_release, +}; + +static struct miscdevice misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = TP_CHR, + .fops = &tp_fops, +}; +#endif + + +static int ssd253x_init(void) +{ + char firmwname[60]; + int i; + + if (deviceReset() != 0) + return -1; + memset(firmwname,0,sizeof(firmwname)); + wmt_ts_get_firmwname(firmwname); + i = read_firmwarefile(firmwname,&ssd253xcfgTable,0x100); + if (i <= 0) + { + l_cfglen = sizeof(ssd253xcfgTable_default)/sizeof(ssd253xcfgTable_default[0]); + ssd253xcfgTable = ssd253xcfgTable_default; + dbg("Using the default configure!\n"); + } else { + l_cfglen = i; + } + Resume[1].No = ssd253xcfgTable[l_cfglen-1].No; + Resume[1].Reg = ssd253xcfgTable[l_cfglen-1].Reg; + Resume[1].Data1 = ssd253xcfgTable[l_cfglen-1].Data1; + Resume[1].Data2 = ssd253xcfgTable[l_cfglen-1].Data2; + if (SSD253xdeviceInit()!= 0) + { + if (i > 0) + { + kfree(ssd253xcfgTable); + } + return -1; + } + // init hardware + +#ifdef SD_INIT + misc_register(&misc); +#endif + + + return 0; +} + +static void ssd253x_exit(void) +{ + klog("remove the module\n"); + +#ifdef SD_INIT + misc_deregister(&misc); +#endif + + + if (ssd253xcfgTable != ssd253xcfgTable_default) + { + kfree(ssd253xcfgTable); + } + +} + +static int ssd253x_wait_penup(struct wmtts_device*tsdev) +{ + int ret = wait_event_interruptible( + ts_penup_wait_queue, + (1==tsdev->penup)); + return ret; +} + + +struct wmtts_device raysen_tsdev = { + .driver_name = "ssd253x_ts", + .ts_id = "SSD253X", + .init = ssd253x_init, + .exit = ssd253x_exit, + .probe = ssd253x_probe, + .remove = ssd253x_remove, + .suspend = ssd253x_suspend, + .resume = ssd253x_resume, + .wait_penup = ssd253x_wait_penup, + .penup = 1, +}; + +#ifdef SD_INIT +static long tp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + return 0; +} + +static int tp_open(struct inode *inode, struct file *file) +{ + return 0; +} +static int tp_release(struct inode *inode, struct file *file) +{ + return 0; +} + +static ssize_t tp_read(struct file *file, char __user *buf, size_t count,loff_t *offset) +{ + char *kbuf; + uint8_t reg; + int ByteNo; + int readValue; + int i; + + kbuf = kmalloc(count,GFP_KERNEL); + + if(copy_from_user(kbuf,buf,1)) { + printk("no enough memory!\n"); + return -1; + } + + reg = (uint8_t)kbuf[0]; + ByteNo = count; + + readValue = ReadRegister( /*g_tp_client, */reg, ByteNo); + + for(i = 0;i < ByteNo;i++){ + kbuf[i] = (readValue>>(8*i)) & 0xff; + } + + if(copy_to_user(buf,kbuf,count)) { + printk("no enough memory!\n"); + return -1; + } + + kfree(kbuf); + + return count; +} + +static ssize_t tp_write(struct file *file, const char __user *buf,size_t count, loff_t *offset) +{ + char *kbuf; + + kbuf = kmalloc(count,GFP_KERNEL); + + if(copy_from_user(kbuf,buf,count)) { + printk("no enough memory!\n"); + return -1; + } + + if(kbuf[1] == 0x01){ + wmt_rst_output(0); + mdelay(5); + wmt_rst_output(1); + mdelay(20); + } + else + { + WriteRegister(/*g_tp_client,*/kbuf[1],kbuf[2],kbuf[3],kbuf[0]); + } + + kfree(kbuf); + + return count; +} + +#endif + + + + +MODULE_AUTHOR("Solomon Systech Ltd - Design Technology, Icarus Choi"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("ssd253x Touchscreen Driver 1.3"); diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ssd253x_ts/ssd253x-ts.h b/ANDROID_3.4.5/drivers/input/touchscreen/ssd253x_ts/ssd253x-ts.h new file mode 100755 index 00000000..fe6edeae --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ssd253x_ts/ssd253x-ts.h @@ -0,0 +1,28 @@ +/************************************************************** +ʹÓÃÇ°×¢ÒâͨµÀÊý£¬Çý¶¯Ä¬ÈÏʹÓÃͨµÀÊÇsense +´óÓÚdrive·ñÔòÐèÒª½«Ê¹Óõ½µÄDRIVENOÓëSENSENOµ÷»» +´ËÇé¿ö°üÀ¨0x66ºÍ0x67¼Ä´æÆ÷£¬µ«²»±ØÐ޸ġ£ +***************************************************************/ +#ifndef __SSD253X_20125181742_TS_H__ +#define __SSD253X_20125181742_TS_H__ +#define DRIVENO 15 +#define SENSENO 10 +#define EdgeDisable 1 // if Edge Disable, set it to 1, else reset to 0 +#define RunningAverageMode 2 //{0,8},{5,3},{6,2},{7,1} +#define RunningAverageDist 4 // Threshold Between two consecutive points +#define MicroTimeTInterupt 10000000 //20000000// 100Hz - 10,000,000us +#define FINGERNO 10 + +//#define USE_TOUCH_KEY + +#define USE_CUT_EDGE //0x8b must be 0x00; EdgeDisable set 0 +//#undef USE_CUT_EDGE + +#ifdef USE_CUT_EDGE + #define XPOS_MAX 576 //(DRIVENO - EdgeDisable) *64 + #define YPOS_MAX 896 //(SENSENO - EdgeDisable) *64 +#endif + + + +#endif diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ssd253x_ts/wmt_ts.c b/ANDROID_3.4.5/drivers/input/touchscreen/ssd253x_ts/wmt_ts.c new file mode 100755 index 00000000..cf63ca13 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ssd253x_ts/wmt_ts.c @@ -0,0 +1,810 @@ +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +#include "wmt_ts.h" +#include "ssd253x-ts.h" + +///////////////////////////////////////////////////////////////// + +// commands for ui +#define TS_IOC_MAGIC 't' + +#define TS_IOCTL_CAL_START _IO(TS_IOC_MAGIC, 1) +#define TS_IOCTL_CAL_DONE _IOW(TS_IOC_MAGIC, 2, int*) +#define TS_IOCTL_GET_RAWDATA _IOR(TS_IOC_MAGIC, 3, int*) +#define TS_IOCTL_CAL_QUIT _IOW(TS_IOC_MAGIC, 4, int*) +#define TS_IOCTL_AUTO_CALIBRATION _IOW(TS_IOC_MAGIC, 5, int*) +#define TS_IOC_MAXNR 5 + +// +#define TS_MAJOR 11 +#define TS_DRIVER_NAME "wmtts_touch" +#define TS_NAME "wmtts" +#define WMTTS_PROC_NAME "wmtts_config" + +#define EXT_GPIO0 0 +#define EXT_GPIO1 1 +#define EXT_GPIO2 2 +#define EXT_GPIO3 3 +#define EXT_GPIO4 4 +#define EXT_GPIO5 5 +#define EXT_GPIO6 6 +#define EXT_GPIO7 7 + +typedef struct { + int a1; + int b1; + int c1; + int a2; + int b2; + int c2; + int delta; +}CALIBRATION_PARAMETER, *PCALIBRATION_PARAMETER; + + +static int lcd_exchg = 0; +static int irq_gpio; +static int rst_gpio; +static int panelres_x; +static int panelres_y; +static int l_xaxis=0; +static int l_xdirect=1; +static int l_yaxis=1; +static int l_ydirect=1; +static int l_cutedge=-1; +static DECLARE_WAIT_QUEUE_HEAD(queue); +static CALIBRATION_PARAMETER g_CalcParam; +static TS_EVENT g_evLast; +static struct mutex cal_mutex; +static DECLARE_WAIT_QUEUE_HEAD(ts_penup_wait_queue); + +extern struct wmtts_device raysen_tsdev; +static struct wmtts_device* l_tsdev = &raysen_tsdev; +static struct i2c_client *l_client=NULL; +static int l_penup = 0; // 1-pen up,0-pen down +static char l_firmid[21]; + +///////////////////////////////////////////////////// +// function declare +///////////////////////////////////////////////////// +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); +extern int wmt_setsyspara(char *varname, unsigned char *varval); + +/////////////////////////////////////////////////////////////////////// +void TouchPanelCalibrateAPoint( + int UncalX, //@PARM The uncalibrated X coordinate + int UncalY, //@PARM The uncalibrated Y coordinate + int *pCalX, //@PARM The calibrated X coordinate + int *pCalY //@PARM The calibrated Y coordinate + ) +{ + int x, y; + mutex_lock(&cal_mutex); + x = (g_CalcParam.a1 * UncalX + g_CalcParam.b1 * UncalY + + g_CalcParam.c1) / g_CalcParam.delta; + y = (g_CalcParam.a2 * UncalX + g_CalcParam.b2 * UncalY + + g_CalcParam.c2) / g_CalcParam.delta; + +//klog("afer(%d,%d)(%d,%d)\n", x,y,panelres_x,panelres_y); + if ( x < 0 ) + x = 0; + + if ( y < 0 ) + y = 0; + if (x >= panelres_x) + x = panelres_x-1; + if (y >= panelres_y) + y = panelres_y-1; + + *pCalX = x; + *pCalY = y; + mutex_unlock(&cal_mutex); + return; +} + +static int parse_firmwarefile(const char* filedata, struct ChipSetting** firmarr, int maxlen) +{ + char endflag[]="/* End flag */"; + const char* p = filedata; + int val[4]; + int i = 0; + int j = 0; + const char* s = NULL; + + // the first { + while (*p!='{') p++; + p++; + s = p; + // calculate the number of array + while (strncmp(p,endflag,strlen(endflag))) + { + if (*p=='{') + { + i++; + } + p++; + }; + dbg("the number of arry:0x%x\n", i); + // alloc the memory for array + *firmarr = kzalloc(sizeof(struct ChipSetting)*i, GFP_KERNEL); + // parse the value of array + p = s; + j = 0; + while (strncmp(p,endflag,strlen(endflag))) + { + if (*p=='{') + { + memset(val,0,sizeof(val)); + sscanf(p,"{%x,%x,%x,%x}",val,val+1,val+2,val+3); + (*firmarr)[j].No = val[0]&0x00FF; + (*firmarr)[j].Reg = val[1]&0x00FF; + (*firmarr)[j].Data1 = val[2]&0x00FF; + (*firmarr)[j].Data2 = val[3]&0x00FF; + dbg("arry[0x%x]:%x,%x,%x,%x\n",j,(*firmarr)[j].No,(*firmarr)[j].Reg,(*firmarr)[j].Data1, + (*firmarr)[j].Data2); + j++; + } + //p = strchr(p,'}'); + p++; + if (j>=i-2) + { + dbg("%s",p); + } + + }; + if (i != j) + { + errlog("Error parsing file(the number of arry not match)!\n"); + return -1; + }; + dbg("paring firmware file end.\n"); + return i; +} + + +static struct device* get_tp_device(void){ + if(l_client == NULL){ + errlog("l_client is NULL\n"); + } + return &l_client->dev; +} + + +//filepath:the path of firmware file; +//firmdata:store the data from firmware file; +//maxlen: the max len of firmdata; +//return:the number of firmware data,negative-parsing error. +int read_firmwarefile(char* filepath, struct ChipSetting** firmdata, int maxlen) +{ + const u8 *data = NULL; + int i = 0; + int ret = -1; + const struct firmware* tpfirmware = NULL; + + klog("ts config file:%s\n",filepath); + + + ret = request_firmware(&tpfirmware, filepath, get_tp_device()); + if (ret < 0) { + errlog("Failed load tp firmware: %s ret=%d\n", filepath,ret); + goto err_end; + } + + data = tpfirmware->data; + + i = parse_firmwarefile(data,firmdata,maxlen); + if (i <= 0) + { + errlog("error to parse firmware file.\n"); + ret = -1; + goto error_parse_fw; + } + ret = i; + + + dbg("success to read firmware file!\n");; + +error_parse_fw: + if(tpfirmware){ + release_firmware(tpfirmware); + tpfirmware = NULL; + } +err_end: + return ret; +} + + + int wmt_ts_get_gpionum(void) +{ + return irq_gpio; +} + +int wmt_ts_get_resetgpnum(void) +{ + return rst_gpio; +} + +int wmt_ts_get_lcdexchg(void) +{ + return lcd_exchg; +} + +int wmt_ts_get_resolvX(void) +{ + return panelres_x; +} + +int wmt_ts_get_resolvY(void) +{ + return panelres_y; +} + +int wmt_ts_get_xaxis(void) +{ + return l_xaxis; +} + +int wmt_ts_get_xdir(void) +{ + return l_xdirect; +} + +int wmt_ts_get_yaxis(void) +{ + return l_yaxis; +} + +int wmt_ts_get_ydir(void) +{ + return l_ydirect; +} + +int wmt_ts_get_cutedge(void) +{ + return l_cutedge; +} + +void wmt_ts_get_firmwname(char* firmname) +{ + sprintf(firmname,"ssd253x_%s_cfg.tpf",l_firmid); +} + +int wmt_ts_get_fingernum(void) +{ + if (!strcmp(l_firmid,"10rs10f1609043psy1")) + { + return 10; + } + return 5; +} + +//up:1-pen up,0-pen down +void wmt_ts_set_penup(int up) +{ + l_penup = up; +} + +// +int wmt_ts_wait_penup(void) +{ + int ret = wait_event_interruptible( + ts_penup_wait_queue, + (1==l_penup)); + return ret; +} + +// return:1-pen up,0-pen dwon +int wmt_ts_ispenup(void) +{ + return l_penup; +} + + +void wmt_ts_wakeup_penup(void) +{ + wake_up(&ts_penup_wait_queue); +} + +int wmt_is_tsirq_enable(void) +{ + int val = 0; + int num = irq_gpio; + + if(num > 11) + return 0; + + if(num<4) + val = REG32_VAL(__GPIO_BASE+0x0300) & (1<<(num*8+7)); + else if(num >= 4 && num < 8) + val = REG32_VAL(__GPIO_BASE+0x0304) & (1<<((num-4)*8+7)); + else + val = REG32_VAL(__GPIO_BASE+0x0308) & (1<<((num-8)*8+7)); + + return val?1:0; + +} + +int wmt_is_tsint(void) +{ + int num = irq_gpio; + + if (num > 11) + { + return 0; + } + return (REG32_VAL(__GPIO_BASE+0x0360) & (1< 11) + { + return; + } + REG32_VAL(__GPIO_BASE+0x0360) = 1<11) + return -1; + //if (num > 9) + //GPIO_PIN_SHARING_SEL_4BYTE_VAL &= ~BIT4; // gpio10,11 as gpio + REG32_VAL(__GPIO_BASE+0x0040) &= ~(1<= 4 && num < 8){//[4,7] + shift = num-4; + offset = 0x0304; + }else{// [8,11] + shift = num-8; + offset = 0x0308; + } + + reg = REG32_VAL(__GPIO_BASE + offset); + + switch(type){ + case IRQ_TYPE_LEVEL_LOW: + reg &= ~(1<<(shift*8+2)); + reg &= ~(1<<(shift*8+1)); + reg &= ~(1<<(shift*8)); + break; + case IRQ_TYPE_LEVEL_HIGH: + reg &= ~(1<<(shift*8+2)); + reg &= ~(1<<(shift*8+1)); + reg |= (1<<(shift*8)); + break; + case IRQ_TYPE_EDGE_FALLING: + reg &= ~(1<<(shift*8+2)); + reg |= (1<<(shift*8+1)); + reg &= ~(1<<(shift*8)); + break; + case IRQ_TYPE_EDGE_RISING: + reg &= ~(1<<(shift*8+2)); + reg |= (1<<(shift*8+1)); + reg |= (1<<(shift*8)); + break; + default://both edge + reg |= (1<<(shift*8+2)); + reg &= ~(1<<(shift*8+1)); + reg &= ~(1<<(shift*8)); + break; + + } + //reg |= 1<<(shift*8+7);//enable interrupt + reg &= ~(1<<(shift*8+7)); //disable int + + REG32_VAL(__GPIO_BASE + offset) = reg; + REG32_VAL(__GPIO_BASE+0x0360) = 1< 11) + return -1; + + if(num<4) + REG32_VAL(__GPIO_BASE+0x0300) |= 1<<(num*8+7); //enable interrupt + else if(num >= 4 && num < 8) + REG32_VAL(__GPIO_BASE+0x0304) |= 1<<((num-4)*8+7); //enable interrupt + else + REG32_VAL(__GPIO_BASE+0x0308) |= 1<<((num-8)*8+7); //enable interrupt + + return 0; +} + +int wmt_disable_gpirq(void) +{ + int num = irq_gpio; + + if(num > 11) + return -1; + + if(num<4) + REG32_VAL(__GPIO_BASE+0x0300) &= ~(1<<(num*8+7)); //enable interrupt + else if(num >= 4 && num < 8) + REG32_VAL(__GPIO_BASE+0x0304) &= ~(1<<((num-4)*8+7)); //enable interrupt + else + REG32_VAL(__GPIO_BASE+0x0308) &= ~(1<<((num-8)*8+7)); //enable interrupt + + return 0; +} + + +int wmt_get_tsirqnum(void) +{ + return IRQ_GPIO; +} + + +int wmt_ts_set_rawcoord(unsigned short x, unsigned short y) +{ + g_evLast.x = x; + g_evLast.y = y; + //dbg("raw(%d,%d)*\n", x, y); + return 0; +} + +static void wmt_ts_platform_release(struct device *device) +{ + return; +} + +static struct platform_device wmt_ts_plt_device = { + .name = TS_DRIVER_NAME, + .id = 0, + .dev = { + .release = wmt_ts_platform_release, + }, +// .num_resources = ARRAY_SIZE(wm9715_ts_resources), +// .resource = wm9715_ts_resources, +}; + +static int wmt_ts_suspend(struct platform_device *pdev, pm_message_t state) +{ + dbg("ts suspend....\n"); + return l_tsdev->suspend(pdev, state); +} +static int wmt_ts_resume(struct platform_device *pdev) +{ + dbg("ts resume....\n"); + return l_tsdev->resume(pdev); +} + +static int wmt_ts_probe(struct platform_device *pdev) +{ + + if (l_tsdev->probe != NULL) + return l_tsdev->probe(pdev); + else + return 0; +} + +static int wmt_ts_remove(struct platform_device *pdev) +{ + + if (l_tsdev->remove != NULL) + return l_tsdev->remove(pdev); + else + return 0; +} + +static struct platform_driver wmt_ts_plt_driver = { + .driver = { + .name = TS_DRIVER_NAME, + .owner = THIS_MODULE, + }, + .probe = wmt_ts_probe, + .remove = wmt_ts_remove, + .suspend = wmt_ts_suspend, + .resume = wmt_ts_resume, +}; + +static int wmt_check_touch_env(void) +{ + int ret = 0; + int len = 150; + char retval[150] = {0},*p=NULL; + int Enable=0,Gpio=0,PX=0,PY=0; + char* s=NULL; + + // Get u-boot parameter + ret = wmt_getsyspara("wmt.io.touch", retval, &len); + if(ret){ + errlog("Read wmt.io.touch Failed.\n"); + return -EIO; + } + sscanf(retval,"%d:",&Enable); + //check touch enable + if(Enable == 0){ + errlog("Touch Screen Is Disabled.\n"); + return -ENODEV; + } + + p = strchr(retval,':'); + p++; + if(strncmp(p, l_tsdev->ts_id,strlen(l_tsdev->ts_id))){//check touch ID + errlog("[WMTENV] %s is not found\n", l_tsdev->ts_id); + return -ENODEV; + } + // get firmwareid + s = p+strlen(l_tsdev->ts_id)+1; //point to firmware id + p = strchr(p,':'); + memset(l_firmid,0,sizeof(l_firmid)); + len = p-s; + if (len>=20) + { + len = 19; + } + strncpy(l_firmid,s,len); + p++; + sscanf(p,"%d:%d:%d:%d:%d:%d:%d:%d:%d",&Gpio,&PX,&PY,&rst_gpio, + &l_xaxis,&l_xdirect, + &l_yaxis,&l_ydirect, + &l_cutedge); + + irq_gpio = Gpio; + panelres_x = PX; + panelres_y = PY; + dbg("p.x=%d,p.y=%d,gpio=%d,resetgpio=%d,\nx-axis=%d,x_dir=%d,y-axis=%d,y_dir=%d,cutedge=%d\nfirmwareid:%s\n", + panelres_x, panelres_y, irq_gpio, rst_gpio, + l_xaxis,l_xdirect,l_yaxis,l_ydirect,l_cutedge, + l_firmid); + + memset(retval,0,sizeof(retval)); + ret = wmt_getsyspara("wmt.display.fb0", retval, &len); + if (!ret) { + int tmp[6]; + p = retval; + sscanf(p, "%d:[%d:%d:%d:%d:%d", &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5]); + if (tmp[4] > tmp[5]) + lcd_exchg = 1; + } + + return 0; +} + +struct i2c_board_info ts_i2c_board_info = { + .type = WMT_TS_I2C_NAME, + .flags = 0x00, + .addr = WMT_TS_I2C_ADDR, + .platform_data = NULL, + .archdata = NULL, + .irq = -1, +}; + +static int ts_i2c_register_device (void) +{ + struct i2c_board_info *ts_i2c_bi; + struct i2c_adapter *adapter = NULL; + //struct i2c_client *client = NULL; + ts_i2c_bi = &ts_i2c_board_info; + adapter = i2c_get_adapter(1);/*in bus 1*/ + + if (NULL == adapter) { + printk("can not get i2c adapter, client address error\n"); + return -1; + } + l_client = i2c_new_device(adapter, ts_i2c_bi); + if (l_client == NULL) { + printk("allocate i2c client failed\n"); + return -1; + } + i2c_put_adapter(adapter); + return 0; +} + +static void ts_i2c_unregister_device(void) +{ + if (l_client != NULL) + { + i2c_unregister_device(l_client); + l_client = NULL; + } +} + +struct i2c_client* ts_get_i2c_client(void) +{ + return l_client; +} + +static int __init wmt_ts_init(void) +{ + int ret = 0; + + if(wmt_check_touch_env()) + return -ENODEV; + + if (ts_i2c_register_device()<0) + { + dbg("Error to run ts_i2c_register_device()!\n"); + return -1; + } + mutex_init(&cal_mutex); + + if (l_tsdev->init() < 0){ + dbg("Errors to init %s ts IC!!!\n", l_tsdev->ts_id); + ret = -1; + goto err_init; + } + // Create device node +/* if (register_chrdev (TS_MAJOR, TS_NAME, &wmt_ts_fops)) { + printk (KERN_ERR "wmt touch: unable to get major %d\n", TS_MAJOR); + return -EIO; + } + + l_dev_class = class_create(THIS_MODULE, TS_NAME); + if (IS_ERR(l_dev_class)){ + ret = PTR_ERR(l_dev_class); + printk(KERN_ERR "Can't class_create touch device !!\n"); + return ret; + } + l_clsdevice = device_create(l_dev_class, NULL, MKDEV(TS_MAJOR, 0), NULL, TS_NAME); + if (IS_ERR(l_clsdevice)){ + ret = PTR_ERR(l_clsdevice); + printk(KERN_ERR "Failed to create device %s !!!",TS_NAME); + return ret; + } +*/ + // register device and driver of platform + ret = platform_device_register(&wmt_ts_plt_device); + if(ret){ + errlog("wmt ts plat device register failed!\n"); + return ret; + } + ret = platform_driver_register(&wmt_ts_plt_driver); + if(ret){ + errlog("can not register platform_driver_register\n"); + platform_device_unregister(&wmt_ts_plt_device); + return ret; + } + + klog("%s driver init ok!\n",l_tsdev->ts_id); + return 0; +err_init: + ts_i2c_unregister_device(); + return ret; +} + +static void __exit wmt_ts_exit(void) +{ + dbg("%s\n",__FUNCTION__); + + l_tsdev->exit(); + platform_driver_unregister(&wmt_ts_plt_driver); + platform_device_unregister(&wmt_ts_plt_device); + //device_destroy(l_dev_class, MKDEV(TS_MAJOR, 0)); + //unregister_chrdev(TS_MAJOR, TS_NAME); + //class_destroy(l_dev_class); + mutex_destroy(&cal_mutex); + ts_i2c_unregister_device(); +} + + +module_init(wmt_ts_init); +module_exit(wmt_ts_exit); + +MODULE_LICENSE("GPL"); + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ssd253x_ts/wmt_ts.h b/ANDROID_3.4.5/drivers/input/touchscreen/ssd253x_ts/wmt_ts.h new file mode 100755 index 00000000..3506773a --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ssd253x_ts/wmt_ts.h @@ -0,0 +1,116 @@ + +#ifndef WMT_TSH_201010191758 +#define WMT_TSH_201010191758 + +#include +#include +#include +#include +#include +#include + + +//#define DEBUG_WMT_TS +#undef dbg +#ifdef DEBUG_WMT_TS +#define dbg(fmt, args...) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__ , ## args) +#else +#define dbg(fmt, args...) +#endif + +#undef errlog +#undef klog +#define errlog(fmt, args...) printk("[%s]: " fmt, __FUNCTION__, ## args) +#define klog(fmt, args...) printk("[%s]: " fmt, __FUNCTION__, ## args) + +#define WMT_TS_I2C_NAME "ssd253x-ts" +#define WMT_TS_I2C_ADDR 0x01 + +//////////////////////////////data type/////////////////////////// +typedef struct { + short pressure; + short x; + short y; + //short millisecs; +} TS_EVENT; + +struct wmtts_device +{ + //data + char* driver_name; + char* ts_id; + //function + int (*init)(void); + int (*probe)(struct platform_device *platdev); + int (*remove)(struct platform_device *pdev); + void (*exit)(void); + int (*suspend)(struct platform_device *pdev, pm_message_t state); + int (*resume)(struct platform_device *pdev); + int (*capacitance_calibrate)(void); + int (*wait_penup)(struct wmtts_device*tsdev); // waiting untill penup + int penup; // 0--pendown;1--penup + +}; + +struct ChipSetting { + char No; + char Reg; + char Data1; + char Data2; +}; + + +//////////////////////////function interface///////////////////////// +extern int wmt_ts_get_gpionum(void); +extern int wmt_ts_iscalibrating(void); +extern int wmt_ts_get_resolvX(void); +extern int wmt_ts_get_resolvY(void); +extern int wmt_ts_set_rawcoord(unsigned short x, unsigned short y); +extern int wmt_set_gpirq(int type); +extern int wmt_get_tsirqnum(void); +extern int wmt_disable_gpirq(void); +extern int wmt_enable_gpirq(void); +extern int wmt_is_tsirq_enable(void); +extern int wmt_is_tsint(void); +extern void wmt_clr_int(void); +extern void wmt_tsreset_init(void); +extern int wmt_ts_get_resetgpnum(void); +extern int wmt_ts_get_lcdexchg(void); +extern void wmt_enable_rst_pull(int enable); +extern void wmt_set_rst_pull(int up); +extern void wmt_rst_output(int high); +extern void wmt_rst_input(void); +extern void wmt_set_intasgp(void); +extern void wmt_intgp_out(int val); +extern void wmt_ts_set_irqinput(void); +extern unsigned int wmt_ts_irqinval(void); +extern void wmt_ts_set_penup(int up); +extern int wmt_ts_wait_penup(void); +extern void wmt_ts_wakeup_penup(void); +extern struct i2c_client* ts_get_i2c_client(void); +extern int wmt_ts_ispenup(void); +extern int wmt_ts_get_xaxis(void); +extern int wmt_ts_get_xdir(void); +extern int wmt_ts_get_yaxis(void); +extern int wmt_ts_get_ydir(void); +extern int wmt_ts_get_cutedge(void); +extern void wmt_ts_get_firmwname(char* firmname); +extern int wmt_ts_get_fingernum(void); + +extern void TouchPanelCalibrateAPoint( + int UncalX, //@PARM The uncalibrated X coordinate + int UncalY, //@PARM The uncalibrated Y coordinate + int *pCalX, //@PARM The calibrated X coordinate + int *pCalY //@PARM The calibrated Y coordinate + ); + +//filepath:the path of firmware file; +//firmdata:store the data from firmware file; +//maxlen: the max len of firmdata; +//return:the number of firmware data,negative-parsing error. +extern int read_firmwarefile(char* filepath, struct ChipSetting** firmdata, int maxlen); + +#endif + + + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/vt1609_ts/Makefile b/ANDROID_3.4.5/drivers/input/touchscreen/vt1609_ts/Makefile new file mode 100755 index 00000000..b3e5b2d3 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/vt1609_ts/Makefile @@ -0,0 +1,4 @@ + +obj-$(CONFIG_TOUCHSCREEN_VT1609) := vt1609_dual.o vt1609_ts.o + + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/vt1609_ts/vt1609_dual.c b/ANDROID_3.4.5/drivers/input/touchscreen/vt1609_ts/vt1609_dual.c new file mode 100755 index 00000000..c88872e5 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/vt1609_ts/vt1609_dual.c @@ -0,0 +1,692 @@ +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "vt1609_ts.h" + + +//#define _DEBUG_ + +#undef dbg +#ifdef _DEBUG_ +#define dbg(fmt, args...) printk(KERN_ERR "[%s][%d]: " fmt, __func__ , __LINE__, ## args) +#else +#define dbg(fmt, args...) +#endif + +#undef dbg_err +#define dbg_err(fmt, args...) printk(KERN_ERR "[%s][%d]##ERROR##: " fmt, __func__ , __LINE__, ## args) + +#define VT1609_DUAL_VERSION "1.1" + +#define DUAL_BUF_LENGTH 17 +#define SINGLE_BUF_LEN 5 +#define MAX_SAMPLE_NUM 5 +#define POLL_TOUT 100 +#define DX_DETLA 4 +#define DX_NUM 5 + +#define VXY 17 +#define SCALE_X 4 +#define SCALE_Y 2 +#define FILTER_COUNT_T1 2 +#define FILTER_COUNT_T2 5 +#define FILTER_COUNT_2T1 5 +#define SAMPLE_COUNT 4 +#define THRESHOLD_DX 256 +#define THRESHOLD_XY 1300 +#define THRESHOLD_DUAL_CNT 1 + +#define CHL_X1 0x01 +#define CHL_X2 0x02 +#define CHL_X3 0x03 +#define CHL_Y1 0x04 +#define CHL_Y2 0x05 +#define CHL_Y3 0x06 + +static int vxy_max_updated = 0; +static int vx_max = 0; +static int vy_max = 0; + +static int dual_cnt = 0; +static int prv_dx = 0; +static int dx1 = 0, dx2 = 0; + +static int TwoCT = 0; +static int FirstCT = 0; +static int TouchCT = 0 ; +static int OneTCAfter2 = 0; +static int TwoTouchFlag = 0; +static struct vt1603_ts_pos pre,fixpos; + +//extern struct vt1603_ts_drvdata *pContext; + +struct dual_avg_buf { + int num; + u32 data[DUAL_BUF_LENGTH]; +}; + +static struct dual_avg_buf x_buf; +static struct dual_avg_buf y_buf; +static struct dual_avg_buf avg_buf; + +static int vt1603_ts_get_ux(int *para); +static int vt1603_ts_get_uy(int *para); +static int vt1603_ts_get_vx(int *para); +static int vt1603_ts_get_vy(int *para); + +static inline void dual_buf_fill(struct dual_avg_buf *dual_buf, u32 data, int len) +{ + dual_buf->data[dual_buf->num % len] = data; + dual_buf->num++; + + return ; +} + +static inline u32 dual_buf_avg(struct dual_avg_buf *dual_buf, int len) +{ + int i, num; + u32 avg = 0; + int max, min; + + num = (dual_buf->num < len)? dual_buf->num : len; + + if(num == 1) + return dual_buf->data[0]; + if(num == 2) + return (dual_buf->data[0]+dual_buf->data[1])/2; + + max = dual_buf->data[0]; + min = dual_buf->data[0]; + for (i = 0; i < num; i++){ + avg += dual_buf->data[i]; + + if(dual_buf->data[i] > max) + max = dual_buf->data[i]; + + if(dual_buf->data[i] < min) + min = dual_buf->data[i]; + } + + return (avg-max-min )/ (num-2); +} + +static void dual_buf_init(struct dual_avg_buf *dual_buf) +{ + memset(dual_buf, 0x00, sizeof(struct dual_avg_buf)); + return ; +} + +static inline void vt1603_ts_report_dual_pos(struct vt1603_ts_drvdata *ts_drv, + struct vt1603_ts_pos *fst,struct vt1603_ts_pos *lst) +{ + struct vt1603_ts_pos p1 = *fst; + struct vt1603_ts_pos p2 = *lst; + + vt1603_ts_pos_calibration(ts_drv,&p1); + vt1603_ts_pos_calibration(ts_drv,&p2); + //dbg("Caled pos1 (%d, %d), pos2 (%d, %d)\n", p1.x, p1.y, p2.x, p2.y); + + input_report_abs(ts_drv->input, ABS_MT_POSITION_X, p1.x); + input_report_abs(ts_drv->input, ABS_MT_POSITION_Y, p1.y); + input_mt_sync(ts_drv->input); + + input_report_abs(ts_drv->input, ABS_MT_POSITION_X, p2.x); + input_report_abs(ts_drv->input, ABS_MT_POSITION_Y, p2.y); + input_mt_sync(ts_drv->input); + + input_sync(ts_drv->input); + + return; +} + +static inline void vt1603_ts_auto_mode(struct vt1603_ts_drvdata *ts_drv) +{ + vt1603_set_reg8(ts_drv, VT1603_PWC_REG, 0x08); + /* auto position conversion mode and panel type config */ + vt1603_set_reg8(ts_drv, VT1603_CR_REG, BIT1); + /* disable pen up/down detection, it is a MUST opearetion */ + vt1603_set_reg8(ts_drv, 0xC8, 0x7F); + + return; +} + +static inline int select_channel(struct vt1603_ts_drvdata *ts_drv,int chl) +{ + switch(chl){ + case CHL_X1://select x1 + vt1603_set_reg8(ts_drv, 0xc6, 0x12); + vt1603_set_reg8(ts_drv, 0xc7, 0x05); + break; + case CHL_X2://select x2 + vt1603_set_reg8(ts_drv, 0xc6, 0x12); + vt1603_set_reg8(ts_drv, 0xc7, 0x04); + break; + case CHL_X3://select x3 + vt1603_set_reg8(ts_drv, 0xc6, 0x12); + vt1603_set_reg8(ts_drv, 0xc7, 0x00); + break; + case CHL_Y1://select y1 + vt1603_set_reg8(ts_drv, 0xc6, 0x21); + vt1603_set_reg8(ts_drv, 0xc7, 0x07); + break; + case CHL_Y2://select y2 + vt1603_set_reg8(ts_drv, 0xc6, 0x21); + vt1603_set_reg8(ts_drv, 0xc7, 0x06); + break; + case CHL_Y3://select y3 + vt1603_set_reg8(ts_drv, 0xc6, 0x21); + vt1603_set_reg8(ts_drv, 0xc7, 0x03); + break; + default://default select x1 + vt1603_set_reg8(ts_drv, 0xc6, 0x12); + vt1603_set_reg8(ts_drv, 0xc7, 0x05); + break; + } + + return 0; +} + +static inline int select_x_channel(struct vt1603_ts_drvdata *ts_drv,int chl) +{ + switch(chl){ + case CHL_X1://select x1 + vt1603_set_reg8(ts_drv, 0xc6, 0x21); + vt1603_set_reg8(ts_drv, 0xc7, 0x07); + break; + case CHL_X2://select x2 + vt1603_set_reg8(ts_drv, 0xc6, 0x21); + vt1603_set_reg8(ts_drv, 0xc7, 0x06); + break; + case CHL_X3://select x3 + vt1603_set_reg8(ts_drv, 0xc6, 0x21); + vt1603_set_reg8(ts_drv, 0xc7, 0x03); + break; + case CHL_Y1://select y1 + vt1603_set_reg8(ts_drv, 0xc6, 0x12); + vt1603_set_reg8(ts_drv, 0xc7, 0x05); + + break; + case CHL_Y2://select y2 + vt1603_set_reg8(ts_drv, 0xc6, 0x12); + vt1603_set_reg8(ts_drv, 0xc7, 0x04); + break; + case CHL_Y3://select y3 + vt1603_set_reg8(ts_drv, 0xc6, 0x12); + vt1603_set_reg8(ts_drv, 0xc7, 0x00); + break; + default://default select x1 + vt1603_set_reg8(ts_drv, 0xc6, 0x12); + vt1603_set_reg8(ts_drv, 0xc7, 0x05); + break; + } + + return 0; +} + +static inline int get_channel_data(struct vt1603_ts_drvdata *ts_drv,int chl) +{ + int i = 0; + int sum = 0; + int buf[MAX_SAMPLE_NUM] = {0}; + u32 now = 0; + u8 tmp = 0; + + if(ts_drv->dual_dev.exch) + select_x_channel(ts_drv,chl); + else + select_channel(ts_drv,chl); + + for (i = 0; i < ts_drv->dual_dev.SAMPLE_CNT; i++) { + vt1603_clrbits(ts_drv, VT1603_INTS_REG, 0x0f); + vt1603_set_reg8(ts_drv, VT1603_CR_REG, 0x10); + udelay(100); + now = jiffies; + while (time_before(jiffies, now + msecs_to_jiffies(POLL_TOUT))) { + tmp = vt1603_get_reg8(ts_drv, VT1603_INTS_REG); + if (tmp & BIT0) { + buf[i] = vt1603_get_reg8(ts_drv, 0xce); + tmp = (vt1603_get_reg8(ts_drv, 0xcf) & 0x0f); + buf[i] |= (tmp << 8); + sum += buf[i]; + goto next; + } + } + printk("VT1609 %s timeout!\n", __func__); + return 0; + + next: + ;//printk("CHL %d buf[%d] is %d\n", chl, i, buf[i]); + } + + return sum/ts_drv->dual_dev.SAMPLE_CNT; + +} + + +static inline int vt1603_get_paramters(struct vt1603_ts_drvdata *ts_drv, int *para) +{ + /* change to manual mode now */ + vt1603_set_reg8(ts_drv, VT1603_CR_REG, 0x00); + /* set prechare to 0x10 */ + vt1603_set_reg8(ts_drv, VT1603_TSPC_REG, 0x10); + /* get parameters now */ + para[0] = get_channel_data(ts_drv, CHL_X1); + para[1] = get_channel_data(ts_drv, CHL_X2); + para[2] = get_channel_data(ts_drv, CHL_Y1); + para[3] = get_channel_data(ts_drv, CHL_Y2); + + para[4] = get_channel_data(ts_drv, CHL_X3); + para[5] = get_channel_data(ts_drv, CHL_Y3); + + /* reset adc, this is a MUST operation */ + vt1603_set_reg8(ts_drv, 0xc8, 0x8f); + vt1603_set_reg8(ts_drv, 0xc0, BIT6 | BIT5 | BIT0); + + return 0; +} + +static int vt1603_get_vxy(struct vt1603_ts_drvdata *ts_drv, int *vx, int *vy) +{ + int i; + int xbuf[5] ={0}, ybuf[5] ={0}; + int sum_vx = 0,sum_vy = 0; + int max_vx = 0,min_vx = 0; + int max_vy = 0,min_vy = 0; + + /* change to manual mode now */ + vt1603_set_reg8(ts_drv, VT1603_CR_REG, 0x00); + /* set prechare to 0x10 */ + vt1603_set_reg8(ts_drv, VT1603_TSPC_REG, 0x10); + for(i=0; i<5; i++){ + xbuf[i] = get_channel_data(ts_drv,CHL_X3); + ybuf[i] = get_channel_data(ts_drv,CHL_Y3); + sum_vx += xbuf[i]; + sum_vy += ybuf[i]; + } + + max_vx = min_vx = xbuf[0]; + max_vy = min_vy = ybuf[0]; + + for(i=0; i<5; i++){ + if(xbuf[i] > max_vx) + max_vx = xbuf[i]; + + if(xbuf[i] < min_vx) + min_vx = xbuf[i]; + + if(ybuf[i] > max_vy) + max_vy = ybuf[i]; + + if(ybuf[i] < min_vy) + min_vy = ybuf[i]; + } + *vx = (sum_vx - max_vx - min_vx)/3; + *vy = (sum_vy - max_vy - min_vy)/3; + dbg("updated vx_max=%d; vy_max=%d\n",*vx, *vy); + /* reset adc, this is a MUST operation */ + vt1603_set_reg8(ts_drv, 0xc8, 0x8f); + vt1603_set_reg8(ts_drv, 0xc0, BIT6 | BIT5 | BIT0); + + return 0; +} + +static inline int vt1603_ts_get_ux(int *para) +{ + return abs(para[1] - para[0]); +} + +static inline int vt1603_ts_get_uy(int *para) +{ + return abs(para[3] - para[2]); +} + +static inline int vt1603_ts_get_vx(int *para) +{ + return abs(vx_max - para[4]); +} + +static inline int vt1603_ts_get_vy(int *para) +{ + return abs(vy_max - para[5]); +} + +static inline int vt1603_ts_nTouch(struct vt1603_ts_drvdata *ts_drv, int *para) +{ + int ux, uy, vx, vy; + + ux = vt1603_ts_get_ux(para); + uy = vt1603_ts_get_uy(para); + vx = vt1603_ts_get_vx(para); + vy = vt1603_ts_get_vy(para); + //printk("ux:%-3d, uy:%-3d, vx:%-3d, vy:%-3d\n", ux, uy, vx, vy); + + if ((vx <= 5) && (vy <= 5)){ + dual_cnt = 0; + return Single_TOUCH; + }else if ((vx >= ts_drv->dual_dev.vxy) || (vy >= ts_drv->dual_dev.vxy)){ + dual_cnt++; + //printk("ux:%-3d, uy:%-3d, vx:%-3d, vy:%-3d\n", ux, uy, vx, vy); + return (dual_cnt > THRESHOLD_DUAL_CNT)? Multi_TOUCH : Single_TOUCH; + }else if (((vx > 5) || (vy > 5)) && ((ux >= 2 * ts_drv->dual_dev.vxy) || (uy >= 2 * ts_drv->dual_dev.vxy))){ + dual_cnt++; + //printk("ux:%-3d, uy:%-3d, vx:%-3d, vy:%-3d\n", ux, uy, vx, vy); + return (dual_cnt > THRESHOLD_DUAL_CNT)? Multi_TOUCH : Single_TOUCH; + }else{ + dual_cnt = 0; + return Single_TOUCH; + } + +} + +static int pos_fix(const int limit, int p) +{ + if (p > limit) p = limit; + if (p < 0) p = 0; + + return (u16)(p & 0xffff); +} + +static int vt1603_ts_update_vxy(struct vt1603_ts_drvdata *ts_drv, int *vx, int *vy) +{ + u8 val; + int timeout = 100; + + val = vt1603_get_reg8(ts_drv, VT1603_CR_REG); + while (timeout-- && val != 0x02) { + msleep(20); + val = vt1603_get_reg8(ts_drv, VT1603_CR_REG); + } + + if(!timeout){ + dbg_err("get vx_max/vy_max failed!\n"); + goto out; + } + + vt1603_get_vxy(ts_drv, vx,vy); + dbg("update vx_max:%d, vy_max:%d\n", vx_max, vy_max); + +out: + vt1603_set_reg8(ts_drv, VT1603_INTS_REG, 0x0F); + + return 0; +} + +void vt1603_ts_dual_support(struct work_struct* dwork) +{ + int nTouch = 0; + int para[6] = { 0 }; + //unsigned long flags = 0; + int vx = 0, vy = 0, dx = 0; + struct vt1603_ts_pos p,pos1, pos2; + struct vt1603_ts_drvdata *ts_drv = NULL; + u8 int_sts = 0; + + ts_drv = container_of(dwork, struct vt1603_ts_drvdata, dual_work.work); + + //spin_lock_irqsave(&ts_drv->spinlock, flags); + mutex_lock(&ts_drv->ts_mutex); + + int_sts = vt1603_get_reg8(ts_drv, VT1603_INTS_REG); + if (int_sts & BIT4 || ts_drv->earlysus) { + if (jiffies_to_msecs(jiffies - ts_drv->ts_stamp) < TS_DEBOUNCE && !ts_drv->earlysus) { + dbg("vt1603 ts debouncing?...\n"); + //vt1603_clr_ts_irq(ts_drv, int_sts & 0x0F); + goto next_loop; + } + dbg("======= penup ======\n"); + + /* update vx_max/vy_max only when first penup */ + if(!vxy_max_updated){ + vxy_max_updated ++; + vt1603_ts_update_vxy(ts_drv, &vx_max, &vy_max); + } + vt1603_ts_auto_mode(ts_drv); + /* vt1603 gpio1 as IRQ output */ + vt1603_set_reg8(ts_drv, VT1603_ISEL_REG36, 0x04); + input_mt_sync(ts_drv->input); + input_sync(ts_drv->input); + ts_drv->pen_state = TS_PENUP_STATE; + #ifdef TOUCH_KEY + vt1603_ts_report_key(ts_drv); + #endif + dual_buf_init(&avg_buf); + dual_buf_init(&x_buf); + dual_buf_init(&y_buf); + + dx2 = 0; + dx1 = 0; + pre.x = 0; + pre.y = 0; + FirstCT = 0; + TwoCT = 0; + TouchCT = None_TOUCH; + OneTCAfter2 = 0; + TwoTouchFlag = 0; + vt1603_clr_ts_irq(ts_drv, int_sts & 0x0F); + + if(!ts_drv->earlysus) + wmt_gpio_unmask_irq(ts_drv->intgpio); + + //spin_unlock_irqrestore(&ts_drv->spinlock, flags); + mutex_unlock(&ts_drv->ts_mutex); + + return; + } + + ts_drv->ts_stamp = jiffies; + ts_drv->pen_state = TS_PENDOWN_STATE; + vt1603_get_paramters(ts_drv, para); + vt1603_ts_auto_mode(ts_drv); + //vt1603_clr_ts_irq(ts_drv, 0x0F & int_sts); + + nTouch = vt1603_ts_nTouch(ts_drv, para); + if(nTouch == Single_TOUCH){ + p.x = (para[0] + para[1]) / 2; + p.y = (para[2] + para[3]) / 2; + + if(TwoTouchFlag ==0 && FirstCT < ts_drv->dual_dev.F1_CNT){ + FirstCT ++; + dbg("Filter First %d Single Touch\n",FirstCT); + goto next_loop; + + }else if(TwoTouchFlag == 1 && OneTCAfter2 < ts_drv->dual_dev.F2T1_CNT){ + dbg("Filter First %d pointer when back to single touch from dual touch\n",OneTCAfter2); + dx1 = 0; + dx2 = 0; + TwoCT = 0; + OneTCAfter2 ++; + dual_buf_init(&x_buf); + dual_buf_init(&y_buf); + dual_buf_init(&avg_buf); + goto next_loop; + + }else if(p.x > vx_max || p.y > vy_max){ + dbg("Pos (%d,%d) beyond vx_max or vy_max\n",p.x,p.y); + goto next_loop; + + }else if((pre.x!=0 && pre.y!=0) && (abs(pre.x-p.x) > THRESHOLD_XY||abs(pre.y-p.y) > THRESHOLD_XY )){ + dbg("Threhold Filter Pos (%-4d,%-4d) ,dx=%-4d,dy=%-4d\n",p.x,p.y,abs(pre.x-p.x),abs(pre.y-p.y)); + pre.x = p.x; + pre.y = p.y; + goto next_loop; + + }else{ + dual_buf_fill(&x_buf, p.x, SINGLE_BUF_LEN); + dual_buf_fill(&y_buf, p.y, SINGLE_BUF_LEN); + p.x = dual_buf_avg(&x_buf, SINGLE_BUF_LEN); + p.y = dual_buf_avg(&y_buf, SINGLE_BUF_LEN); + dbg("Report PHY Pos (%-4d,%-4d)\n",p.x,p.y); + pre.x = p.x; + pre.y = p.y; + #ifdef TOUCH_KEY + if(vt1603_ts_get_key(ts_drv, p)) + goto next_loop; + #endif + + vt1603_ts_report_pos(ts_drv, &p); + + TwoCT = 0; + TouchCT = Single_TOUCH; + OneTCAfter2 = 0; + TwoTouchFlag = 0; + goto next_loop; + } + } + else if(nTouch == Multi_TOUCH){ + vx = vt1603_ts_get_vx(para); + vy = vt1603_ts_get_vy(para); + dx = ts_drv->dual_dev.scale_y * vy + ts_drv->dual_dev.scale_x * vx; + + if(dx1 && dx2) + dx = (dx+dx1+dx2)/3; + dx2 = dx1; + dx1 = dx; + dbg("vx=%-3d, vy=%-3d, dx=%-d, Ddx=%-3d\n",vx,vy,dx,abs(prv_dx-dx)); + + if(TwoCT < ts_drv->dual_dev.F2_CNT){ + TwoCT ++; + dual_buf_init(&avg_buf); + dbg("Filter The First %d Dual Touch\n",TwoCT); + goto next_loop; + + }else if (prv_dx!=0 && (abs(prv_dx - dx) > ts_drv->dual_dev.THR_MAX_DX)){ + dbg("Threhold Filter Dual Touch dx=%d\n",abs(prv_dx - dx) ); + prv_dx = dx; + goto next_loop; + + }else{ + //process and report dual touch data + dual_buf_fill(&avg_buf, dx, DUAL_BUF_LENGTH); + dx = dual_buf_avg(&avg_buf, DUAL_BUF_LENGTH); + + if(abs(prv_dx - dx) < ts_drv->dual_dev.THR_MIN_DX){ + //printk("Replace with last dx Ddx=%d\n",abs(prv_dx - dx)); + dx = prv_dx; + } + + if(TwoTouchFlag==0 && TouchCT==Single_TOUCH){//Single Touch ->Multi Touch + fixpos = pre; + //printk("Touch(%-4d,%-4d) 1--->2\n",pre.x,pre.y); + }else if(TwoTouchFlag==0 && TouchCT==None_TOUCH){//Multi Touch from the beginning + fixpos.x = vx_max/2; + fixpos.y = vy_max/2; + //printk("Touch(%-4d,%-4d) 2--->2\n",pos1.x, pos1.y); + } + + pos1 = fixpos; + pos2.x = fixpos.x; + if(fixpos.y > vy_max/2) + pos2.y = pos_fix(vy_max, (fixpos.y - 150 - dx*DX_DETLA/DX_NUM)); + else + pos2.y = pos_fix(vy_max, (fixpos.y + 150 + dx*DX_DETLA/DX_NUM)); + + dbg("PHY dx=%d, pos1.y=%d, pos2.y=%d\n", dx, pos1.y, pos2.y); + vt1603_ts_report_dual_pos(ts_drv, &pos1, &pos2); + + prv_dx = dx; + TouchCT = Multi_TOUCH; + TwoTouchFlag = 1; + OneTCAfter2 = 0; + #ifdef TOUCH_KEY + if(ts_drv->touch_key_used && ts_drv->ledgpio >= 0) + set_key_led_gpio(ts_drv,HIGH); + #endif + goto next_loop; + } + } + else{ + dbg_err("Main Loop Error!\n"); + } + +next_loop: + queue_delayed_work(ts_drv->workqueue, &ts_drv->dual_work, msecs_to_jiffies(20)); + vt1603_clr_ts_irq(ts_drv, 0x0f); + //spin_unlock_irqrestore(&ts_drv->spinlock, flags); + mutex_unlock(&ts_drv->ts_mutex); + + return ; +} + +int vt1603_dual_init(struct vt1603_ts_drvdata *ts_drv) +{ + int ret = 0; + //unsigned long flags = 0; + int retries = 20; + u8 val = 0; + + if (ts_drv == NULL) { + printk(KERN_ERR "VT1609 TouchScreen Driver Does Not Exsit!\n"); + ret = -1; + goto out; + } + + //spin_lock_irqsave(&ts_drv->spinlock, flags); + mutex_lock(&ts_drv->ts_mutex); + + while (retries--) { + val = vt1603_get_reg8(ts_drv, VT1603_INTS_REG); + if ((val & BIT4) == 0) { + printk(KERN_ERR "Do not keep in touching, when vt1609 driver to be installed!\n"); + msleep(20); + continue ; + } + + val = vt1603_get_reg8(ts_drv, VT1603_CR_REG); + if ( val != 0x02) { + printk(KERN_ERR "VT1609 is not working in TS mode now!reg: C1=0x%02x\n",val); + msleep(10); + continue; + } + + break ; + } + + if (retries == 0) { + printk(KERN_ERR "Enable VT1609 Dual Touch Support Failed!\n"); + ret = -1; + goto out; + } + + + vt1603_set_reg8(ts_drv, VT1603_CDPR_REG, 0x04); + vt1603_set_reg8(ts_drv, VT1603_TSPC_REG, 0x10); + vt1603_get_vxy(ts_drv, &vx_max, &vy_max); + vt1603_ts_auto_mode(ts_drv); + vt1603_clr_ts_irq(ts_drv, BIT0 | BIT2 | BIT3); + + dual_buf_init(&avg_buf); + dual_buf_init(&x_buf); + dual_buf_init(&y_buf); + + printk("VT1609 Dual Touch vx_max=%d,vy_max=%d, vxy=%d ver=%s\n",vx_max, vy_max,ts_drv->dual_dev.vxy,VT1609_DUAL_VERSION); +out: + vt1603_clr_ts_irq(ts_drv, 0x0f); + //spin_unlock_irqrestore(&ts_drv->spinlock, flags); + mutex_unlock(&ts_drv->ts_mutex); + + return ret; +} + +void vt1603_dual_exit(struct vt1603_ts_drvdata *ts_drv) +{ + vt1603_set_reg8(ts_drv, VT1603_CDPR_REG, ts_drv->pdata->sclk_div); + vt1603_set_reg8(ts_drv, VT1603_TSPC_REG, 0x20); + printk("VT1609 Dual Touch Support Disabled.\n"); + + return ; +} + + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/vt1609_ts/vt1609_ts.c b/ANDROID_3.4.5/drivers/input/touchscreen/vt1609_ts/vt1609_ts.c new file mode 100755 index 00000000..f41634fc --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/vt1609_ts/vt1609_ts.c @@ -0,0 +1,1481 @@ +/* + * vt1603_mt_i2c.c: VT1603A Touch-Panel Controller and SAR-ADC Driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: 2011.Jan.21st, version: 1.00 + * + */ + +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vt1609_ts.h" + + +//#define VT1609_DEBUG + +#undef dbg +#ifdef VT1609_DEBUG +#define dbg(fmt, args...) printk(KERN_ERR "[%s][%d]: " fmt, __func__ , __LINE__, ##args) +#else +#define dbg(fmt, args...) +#endif + +static struct vt1603_fifo px; +static struct vt1603_fifo py; +static struct class *vt1603_ts_class; +static struct vt1603_ts_pos pre_pos; +static struct vt1603_ts_cal_info g_CalcParam; +struct vt1603_ts_drvdata *pContext = NULL; + +static int vt1603_ts_isPendown(struct vt1603_ts_drvdata *ts_drv); +static void vt1603_ts_dev_cleanup(struct vt1603_ts_drvdata *ts_drv); + +#ifdef TOUCH_KEY +static unsigned int key_codes[TOUCH_KEY_NUM] = { + [0] = KEY_SEARCH, + [1] = KEY_BACK, + [2] = KEY_HOME, + [3] = KEY_MENU, +}; +#endif + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void vt1603ts_early_suspend(struct early_suspend *h); +static void vt1603ts_late_resume(struct early_suspend *h); +#endif + +#ifdef TOUCH_KEY +static int setup_led_gpio(struct vt1603_ts_drvdata *ts_drv) +{ + if (ts_drv->ledgpio >= 0) + gpio_direction_output(ts_drv->ledgpio, 0); + + return 0; +} + +int set_key_led_gpio(struct vt1603_ts_drvdata *ts_drv, int val) +{ + if (ts_drv->ledgpio >= 0) { + if(val) + gpio_direction_output(ts_drv->ledgpio, 1); + else + gpio_direction_output(ts_drv->ledgpio, 0); + } + + return 0; +} + +static void led_timer_func(unsigned long data) +{ + set_key_led_gpio((struct vt1603_ts_drvdata *)data,LOW); + return; +} + +#endif + + +/* + * vt1603_set_reg8 - set register value of vt1603 + * @ts_drv: vt1603 driver data + * @reg: vt1603 register address + * @val: value register will be set + */ +inline int vt1603_set_reg8(struct vt1603_ts_drvdata *ts_drv, u8 reg, u8 val) +{ + int ret =0; + if (ts_drv->tdev) + ret = ts_drv->tdev->reg_write(ts_drv->tdev,reg,val); + + if(ret) + printk("vt1609 ts write error, errno%d\n", ret); + + return ret; +} + +/* + * vt1603_get_reg8 - get register value of vt1603 + * @ts_drv: vt1603 driver data + * @reg: vt1603 register address + */ +inline u8 vt1603_get_reg8(struct vt1603_ts_drvdata *ts_drv, u8 reg) +{ + u8 val = 0; + int ret = 0; + + if (ts_drv->tdev) + ret = ts_drv->tdev->reg_read(ts_drv->tdev,reg,&val); + + if (ret) + printk("vt1609 ts read error, errno%d\n", ret); + + return val; +} + + +#ifdef VT1609_DEBUG +/* + * vt1603_reg_dump - dubug function, for dump vt1603 related registers + * @ts_drv: vt1603 driver data + */ +static void vt1603_reg_dump(struct vt1603_ts_drvdata *ts_drv) +{ + u8 i; + for (i = 0; i < 15; i++) + dbg("reg[%d]:0x%02X, reg[%d]:0x%02X\n", + i, vt1603_get_reg8(ts_drv, i), i + 0xC0, vt1603_get_reg8(ts_drv, i + 0xC0)); +} +#endif + +/* + * vt1603_setbits - write bit1 to related register's bit + * @ts_drv: vt1603 driver data + * @reg: vt1603 register address + * @mask: bit setting mask + */ +inline void vt1603_setbits(struct vt1603_ts_drvdata *ts_drv, u8 reg, u8 mask) +{ + u8 tmp = 0; + tmp = vt1603_get_reg8(ts_drv, reg) | mask; + vt1603_set_reg8(ts_drv, reg, tmp); + + return; +} + + +/* + * vt1603_clrbits - write bit0 to related register's bit + * @ts_drv: vt1603 driver data + * @reg: vt1603 register address + * @mask:bit setting mask + */ +inline void vt1603_clrbits(struct vt1603_ts_drvdata *ts_drv, u8 reg, u8 mask) +{ + u8 tmp = vt1603_get_reg8(ts_drv, reg) & (~mask); + vt1603_set_reg8(ts_drv, reg, tmp); + + return; +} + +/* + * vt1603_clr_ts_irq - clear touch panel pen down/up and + * conversion end/timeout interrupts + * @ts_drv: vt1603 driver data + * @mask: which interrupt will be cleared + */ +inline int vt1603_clr_ts_irq(struct vt1603_ts_drvdata *ts_drv, u8 mask) +{ + vt1603_setbits(ts_drv, VT1603_INTS_REG, mask); + return 0; +} + + +/* + * Enable I2S CLK, wmt-i2s.c have done this. + */ +static void vt1603_ts_clk_enable(void) +{ +#if 0 + /* set to 11.288MHz */ + auto_pll_divisor(DEV_I2S, CLK_ENABLE , 0, 0); + auto_pll_divisor(DEV_I2S, SET_PLLDIV, 1, 11288); + /*clock = auto_pll_divisor(DEV_I2S, GET_FREQ , 0, 0); + info("%s : clock=%d \n" , __func__, clock);*/ + + /* Enable BIT4:ARFP clock, BIT3:ARF clock */ + PMCEU_VAL |= (BIT4 | BIT3); + + /* Enable BIT2:AUD clock */ + PMCE3_VAL |= BIT2; + + /* disable GPIO and Pull Down mode */ + GPIO_CTRL_GP10_I2S_BYTE_VAL &= ~0xFF; + GPIO_CTRL_GP27_BYTE_VAL &= ~(BIT0 | BIT1 | BIT2); + + GPIO_PULL_EN_GP10_I2S_BYTE_VAL &= ~0xFF; + GPIO_PULL_EN_GP27_BYTE_VAL &= ~(BIT0 | BIT1 | BIT2); + + /* set to 2ch input, 2ch output */ + GPIO_PIN_SHARING_SEL_4BYTE_VAL &= ~(BIT3 | BIT17 | BIT19 | BIT20 | BIT22); + GPIO_PIN_SHARING_SEL_4BYTE_VAL |= (BIT0 | BIT2 | BIT16 | BIT18 | BIT21); +#endif + return; +} + +/* + * vt1603_setup_ts_mode - switch to VT1603 TS mode + * @ts_drv: vt1603 driver data + */ +static int vt1603_setup_ts_mode(struct vt1603_ts_drvdata *ts_drv) +{ + int ret = 0; + struct vt1603_ts_platform_data *ts_pdata; + + ts_pdata = ts_drv->pdata; + ret |= vt1603_set_reg8(ts_drv, VT1603_CDPR_REG, ts_pdata->sclk_div); + if (ts_pdata->panel_type == PANEL_TYPE_4WIRED) + ret |= vt1603_set_reg8(ts_drv, VT1603_CR_REG, BIT1); + else + ret |= vt1603_set_reg8(ts_drv, VT1603_CR_REG, BIT1 | BIT0); + + vt1603_clr_ts_irq(ts_drv, 0x0f); + + return (ret < 0)? -1 : 0; + +} + + +static int vt1603_fifo_push(struct vt1603_fifo *Fifo, int Data) +{ + Fifo->buf[Fifo->head] = Data; + Fifo->head++; + if(Fifo->head >= VT1603_FIFO_LEN){ + Fifo->head = 0; + Fifo->full = 1; + } + + return 0; +} + +static int vt1603_fifo_avg(struct vt1603_fifo Fifo, int *Data) +{ + int i=0; + int Sum=0,Max=0,Min=0; + + if(!Fifo.full && !Fifo.head)//FIFO is empty + return 0; + + if(!Fifo.full ){ + for(i=0; i Fifo.buf[i]) + Min = Fifo.buf[i]; + } + Sum -= Max; + Sum -= Min; + *Data = Sum/(VT1603_FIFO_LEN-2); + + return 0; + +} + + +inline int vt1603_ts_pos_calibration(struct vt1603_ts_drvdata *ts_drv,struct vt1603_ts_pos *to_cal) +{ + int x, y; + + x = (g_CalcParam.a1 * to_cal->x + g_CalcParam.b1 * to_cal->y + + g_CalcParam.c1) / g_CalcParam.delta; + y = (g_CalcParam.a2 * to_cal->x + g_CalcParam.b2 * to_cal->y + + g_CalcParam.c2) / g_CalcParam.delta; + + /* pos check */ + if (x < 0) + x = 0; + if (y < 0) + y = 0; + if (x > ts_drv->resl_x) + x = ts_drv->resl_x - 1; + if (y > ts_drv->resl_y) + y = ts_drv->resl_y - 1; + + if (ts_drv->lcd_exchg) { + int tmp; + tmp = x; + x = y; + y = ts_drv->resl_x - tmp; + } + + to_cal->x = x; + to_cal->y = y; + + return 0; +} + +static inline void vt1603_ts_set_rawdata(struct vt1603_ts_drvdata *ts_drv,struct vt1603_ts_pos *pos) +{ + ts_drv->raw_x = pos->x; + ts_drv->raw_y = pos->y; + + return; +} + +inline void vt1603_ts_report_pos(struct vt1603_ts_drvdata *ts_drv, struct vt1603_ts_pos *pos) +{ + vt1603_ts_set_rawdata(ts_drv,pos); + vt1603_ts_pos_calibration(ts_drv,pos); + + input_report_abs(ts_drv->input, ABS_MT_POSITION_X, pos->x); + input_report_abs(ts_drv->input, ABS_MT_POSITION_Y, pos->y); + input_mt_sync(ts_drv->input); + input_sync(ts_drv->input); + + return; +} + +#ifdef TOUCH_KEY +void vt1603_ts_report_key(struct vt1603_ts_drvdata *ts_drv) +{ + if(ts_drv->touch_key_used ){ + + if(ts_drv->ledgpio >= 0 ) + mod_timer(&ts_drv->led_timer, jiffies+10*HZ); + + if(ts_drv->key_pressed && ts_drv->key_idx < _MAX_NUM ){ + input_report_key(ts_drv->input, key_codes[ts_drv->key_idx], 1); + input_sync(ts_drv->input); + input_report_key(ts_drv->input, key_codes[ts_drv->key_idx], 0); + input_sync(ts_drv->input); + dbg("report as key event %d \n",ts_drv->key_idx); + } + } + + return; +} + +inline int vt1603_ts_get_key(struct vt1603_ts_drvdata *ts_drv,struct vt1603_ts_pos pos) +{ + if(ts_drv->touch_key_used){ + + if(pos.y > ts_drv->tsc_key.low && pos.y < ts_drv->tsc_key.upper){ + + ts_drv->key_pressed = 1; + if(pos.x>(ts_drv->tsc_key.key[_SEARCH].pos-ts_drv->tsc_key.delta) && + pos.x<(ts_drv->tsc_key.key[_SEARCH].pos+ts_drv->tsc_key.delta)){ + ts_drv->key_idx = ts_drv->tsc_key.key[_SEARCH].idx; + } + else if(pos.x>(ts_drv->tsc_key.key[_BACK].pos-ts_drv->tsc_key.delta) && + pos.x<(ts_drv->tsc_key.key[_BACK].pos+ts_drv->tsc_key.delta)){ + ts_drv->key_idx = ts_drv->tsc_key.key[_BACK].idx; + } + else if(pos.x>(ts_drv->tsc_key.key[_HOME].pos-ts_drv->tsc_key.delta) && + pos.x<(ts_drv->tsc_key.key[_HOME].pos+ts_drv->tsc_key.delta)){ + ts_drv->key_idx = ts_drv->tsc_key.key[_HOME].idx; + } + else if(pos.x>(ts_drv->tsc_key.key[_MENU].pos-ts_drv->tsc_key.delta) && + pos.x<(ts_drv->tsc_key.key[_MENU].pos+ts_drv->tsc_key.delta)){ + ts_drv->key_idx = ts_drv->tsc_key.key[_MENU].idx; + } + else{ + ts_drv->key_idx = _MAX_NUM; + } + + if(ts_drv->key_idx < _MAX_NUM && ts_drv->ledgpio >= 0) + set_key_led_gpio(ts_drv,HIGH); + + return 1; + } + + if(ts_drv->ledgpio >= 0) + set_key_led_gpio(ts_drv,HIGH); + } + + ts_drv->key_pressed= 0; + + return 0 ; +} + +#endif + + +/* + * vt1603_ts_get_pos - get touch panel touched position from vt1603 + * conversion register + * @ts_drv: vt1603 driver data + * @pos: vt1603 touch panel touched point conversion data + */ +static inline void vt1603_ts_get_pos(struct vt1603_ts_drvdata *ts_drv, struct vt1603_ts_pos *pos) +{ + u8 datal, datah; + + /* get x-position */ + datal = vt1603_get_reg8(ts_drv, VT1603_XPL_REG); + datah = vt1603_get_reg8(ts_drv, VT1603_XPH_REG); + pos->x = ADC_DATA(datal, datah); + + /* get y-positin */ + datal = vt1603_get_reg8(ts_drv, VT1603_YPL_REG); + datah = vt1603_get_reg8(ts_drv, VT1603_YPH_REG); + pos->y = ADC_DATA(datal, datah); + vt1603_clr_ts_irq(ts_drv, BIT0); + + return; +} + +/* + * vt1603_ts_isPendown - get touch panel pen state from vt1603 + * interrup status register + * @ts_drv: vt1603 driver data + */ +static inline int vt1603_ts_isPendown(struct vt1603_ts_drvdata *ts_drv) +{ + u8 state = vt1603_get_reg8(ts_drv, VT1603_INTS_REG); + + if (state & BIT4) + return TS_PENUP_STATE; + else + return TS_PENDOWN_STATE; +} + + +static inline int vt1603_pos_avg(struct vt1603_ts_pos *pos) +{ + vt1603_fifo_push(&px, pos->x); + vt1603_fifo_push(&py, pos->y); + vt1603_fifo_avg(px, &pos->x); + vt1603_fifo_avg(py, &pos->y); + + return 0; +} + +static int vt1603_pos_cleanup(void) +{ + px.full = 0; + px.head = 0; + + py.full = 0; + py.head = 0; + + return 0; +} + +static void vt1603_read_loop(struct work_struct* dwork) +{ + struct vt1603_ts_drvdata *ts_drv=NULL; + struct vt1603_ts_pos pos; + + ts_drv = container_of(dwork, struct vt1603_ts_drvdata, read_work.work); + ts_drv->pen_state= vt1603_ts_isPendown(ts_drv); + if((ts_drv->pen_state == TS_PENUP_STATE) ||ts_drv->earlysus){ + vt1603_clr_ts_irq(ts_drv, 0x0F); + if(jiffies_to_msecs(jiffies - ts_drv->ts_stamp) < 80 && !ts_drv->earlysus){ + //dbg("Debounceing@@@@@@@@\n"); + goto next_loop; + } + + dbg("============== penup ==============\n"); + vt1603_set_reg8(ts_drv, VT1603_ISEL_REG36, 0x04);/* vt1603 gpio1 as IRQ output */ + input_mt_sync(ts_drv->input); + input_sync(ts_drv->input); + #ifdef TOUCH_KEY + vt1603_ts_report_key(ts_drv); + #endif + pre_pos.x = 0; + pre_pos.y = 0; + ts_drv->hcnt = 0; + vt1603_pos_cleanup(); + + if(!ts_drv->earlysus) + wmt_gpio_unmask_irq(ts_drv->intgpio); + + return; + } + + ts_drv->ts_stamp = jiffies; + vt1603_ts_get_pos(ts_drv, &pos); + + //Filter the first N point + if(ts_drv->hcnt < VT1603_FILTER_HEAD_COUNT){ + ts_drv->hcnt++; + goto next_loop; + } + + /* ƽ»¬Â˲¨*/ + if((pre_pos.x != 0 && pre_pos.y != 0)&&(abs(pre_pos.x-pos.x) > VT1603_JITTER_THRESHOLD||abs(pre_pos.y-pos.y) > VT1603_JITTER_THRESHOLD)){ + pre_pos.x = pos.x; + pre_pos.y = pos.y; + goto next_loop; + } +#ifdef TOUCH_KEY + if(vt1603_ts_get_key(ts_drv,pos)) + goto next_loop; +#endif + + vt1603_pos_avg(&pos); + pre_pos.x = pos.x; + pre_pos.y = pos.y; + + dbg("x=%d, y=%d\n",pos.x,pos.y); + vt1603_ts_report_pos(ts_drv, &pos); + +next_loop: + queue_delayed_work(ts_drv->workqueue, &ts_drv->read_work, 20*HZ/1000); + + return; +} + + +static void vt1603_ts_work(struct work_struct *work) +{ + int int_sts; + //unsigned long flags; + struct vt1603_ts_drvdata *ts_drv=pContext; + + //spin_lock_irqsave(&ts_drv->spinlock, flags); + mutex_lock(&ts_drv->ts_mutex); + int_sts = vt1603_get_reg8(ts_drv, VT1603_INTS_REG); + dbg("+++++++ ts int status 0x%02x +++++++\n",int_sts); + + if ((int_sts & BIT4) == 0 || (int_sts & BIT1) == BIT1){ + if(ts_drv->pen_state == TS_PENUP_STATE){ + vt1603_set_reg8(ts_drv, VT1603_ISEL_REG36, 0x03);/* vt1603 gpio1 as logic high output */ + ts_drv->pen_state = TS_PENDOWN_STATE; + ts_drv->ts_stamp = jiffies; + vt1603_setup_ts_mode(ts_drv); + dbg("============= pendown =============\n"); + vt1603_pos_cleanup(); + if(ts_drv->dual_enable) + vt1603_ts_dual_support(&ts_drv->dual_work.work); + else + vt1603_read_loop(&ts_drv->read_work.work); + + vt1603_clr_ts_irq(ts_drv, int_sts&0x0f); + //spin_unlock_irqrestore(&ts_drv->spinlock, flags); + mutex_unlock(&ts_drv->ts_mutex); + + return; + } + } + + vt1603_clr_ts_irq(ts_drv, int_sts&0x0f); + //spin_unlock_irqrestore(&ts_drv->spinlock, flags); + mutex_unlock(&ts_drv->ts_mutex); + wmt_gpio_unmask_irq(ts_drv->intgpio); + + return ; +} + + +static irqreturn_t vt1603_ts_isr(int irq, void *dev_id) +{ + struct vt1603_ts_drvdata *ts_drv = dev_id; + + if(!gpio_irqstatus(ts_drv->intgpio) || + !is_gpio_irqenable(ts_drv->intgpio)) + return IRQ_NONE; + + wmt_gpio_ack_irq(ts_drv->intgpio); + wmt_gpio_mask_irq(ts_drv->intgpio); + schedule_work(&ts_drv->work); + dbg("@@@@@@@ touch irq @@@@@@@\n"); + + return IRQ_HANDLED; +} + +static int vt1603_register_input(struct vt1603_ts_drvdata * ts_drv) +{ + if(strcmp(ts_drv->dev_id,"VT1609")) + ts_drv->input->name = "vt1603-touch"; + else + ts_drv->input->name = "vt1609-touch"; + + ts_drv->input->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + ts_drv->input->propbit[0] = BIT_MASK(INPUT_PROP_DIRECT); + +#ifdef TOUCH_KEY + if(ts_drv->touch_key_used){ + int i; + for (i = 0; i < TOUCH_KEY_NUM; i++) + set_bit(key_codes[i], ts_drv->input->keybit); + + ts_drv->input->keycode = key_codes; + ts_drv->input->keycodesize = sizeof(unsigned int); + ts_drv->input->keycodemax = TOUCH_KEY_NUM; + } +#endif + if (ts_drv->lcd_exchg) { + input_set_abs_params(ts_drv->input, ABS_MT_POSITION_X, 0, ts_drv->resl_y, 0, 0); + input_set_abs_params(ts_drv->input, ABS_MT_POSITION_Y, 0, ts_drv->resl_x, 0, 0); + } else { + input_set_abs_params(ts_drv->input, ABS_MT_POSITION_X, 0, ts_drv->resl_x, 0, 0); + input_set_abs_params(ts_drv->input, ABS_MT_POSITION_Y, 0, ts_drv->resl_y, 0, 0); + } + + input_register_device(ts_drv->input); + return 0; +} + + +/* + * vt1603_ts_calibration - vt1603 self calibration routine + * @ts_drv: vt1603 driver data + */ +static void vt1603_ts_calibration(struct vt1603_ts_drvdata *ts_drv) +{ + unsigned char i, j, tmp; + unsigned char cal[5][8] = {{0}}; + unsigned int cal_sum[8] = {0}; + struct vt1603_ts_platform_data *ts_pdata; + + dbg("Enter\n"); + ts_pdata = ts_drv->pdata; + for (j = 0; j < 5; j++) { + tmp = BIT6 | BIT0 | (ts_pdata->cal_sel << 4); + vt1603_set_reg8(ts_drv, VT1603_CCCR_REG, tmp); + msleep(100); + for (i = 0; i < 8; i++) + cal[j][i] = vt1603_get_reg8(ts_drv, VT1603_ERR8_REG + i); + } + for (i = 0; i < 8; i++) { + for (j = 0; j < 5; j++) + cal_sum[i] += cal[j][i]; + tmp = (u8)cal_sum[i]/5; + vt1603_set_reg8(ts_drv, VT1603_DBG8_REG + i, tmp); + } + + dbg("Exit\n"); + return ; +} + +/* + * vt1603_ts_reset - reset vt1603, auto postition conversion mode, + * do self calibration if enable + * @ts_drv: vt1603 driver data + */ +static void vt1603_ts_reset(struct vt1603_ts_drvdata * ts_drv) +{ + struct vt1603_ts_platform_data *ts_pdata; + ts_pdata = ts_drv->pdata; + + /* power control enable */ + vt1603_set_reg8(ts_drv, VT1603_PWC_REG, 0x18); + /* begin calibrate if calibration enable */ + if ((ts_pdata != NULL) && (ts_pdata->cal_en == CALIBRATION_ENABLE)) { + vt1603_ts_calibration(ts_drv); + } + + /* clock divider */ + vt1603_set_reg8(ts_drv, VT1603_CDPR_REG, ts_pdata->sclk_div); + + /* clean debug register,for some 2 layer PCB machine enter debug mode unexpected */ + vt1603_set_reg8(ts_drv, VT1603_DCR_REG, 0x00); + + vt1603_set_reg8(ts_drv, VT1603_INTEN_REG, BIT1);//Just Enable pendown IRQ + + /* auto position conversion mode and panel type config */ + if (ts_pdata->panel_type== PANEL_TYPE_4WIRED) + vt1603_set_reg8(ts_drv, VT1603_CR_REG, BIT1); + else + vt1603_set_reg8(ts_drv, VT1603_CR_REG, BIT1 | BIT0); + + /* interrupt control, pen up/down detection enable */ + vt1603_set_reg8(ts_drv, VT1603_INTCR_REG, 0xff); + + /* mask other module interrupts */ + vt1603_set_reg8(ts_drv, VT1603_IMASK_REG27, 0xff); + vt1603_set_reg8(ts_drv, VT1603_IMASK_REG28, 0xFF); + vt1603_set_reg8(ts_drv, VT1603_IMASK_REG29, 0xFF); + /* reset headphone detect irq */ + vt1603_set_reg8(ts_drv, VT1603_IMASK_REG27, 0xfd); + + if (ts_pdata->irq_type == HIGH_ACTIVE|| ts_pdata->irq_type == RISING_EDGE_ACTIVE) + vt1603_clrbits(ts_drv, VT1603_IPOL_REG33, BIT5); + else + vt1603_setbits(ts_drv, VT1603_IPOL_REG33, BIT5); + + vt1603_set_reg8(ts_drv, VT1603_ISEL_REG36, 0x04);/* vt1603 gpio1 as IRQ output */ + /* clear irq */ + vt1603_clr_ts_irq(ts_drv, 0x0F); + + return; +} + + +static struct vt1603_ts_platform_data vt1603_ts_pdata = { + .panel_type = PANEL_TYPE_4WIRED, + .cal_en = CALIBRATION_DISABLE, + .cal_sel = 0x00, + .shift = 0x00, + .sclk_div = 0x08, + .irq_type = LOW_ACTIVE, +}; + +struct delayed_work resume_work; +static void vt1603_resume_work(struct work_struct* dwork) +{ + struct vt1603_ts_drvdata *ts_drv = pContext; + ts_drv->pen_state = TS_PENUP_STATE; + + /* must ensure mclk is available */ + vt1603_ts_clk_enable(); + /* vt1603 ts hardware resume */ + vt1603_ts_reset(ts_drv); + /* clear irq before enale gpio irq */ + vt1603_clr_ts_irq(ts_drv, 0x0f ); + + gpio_direction_input(ts_drv->intgpio); + wmt_gpio_set_irq_type(ts_drv->intgpio, IRQ_TYPE_EDGE_FALLING); + wmt_gpio_unmask_irq(ts_drv->intgpio); + #ifdef TOUCH_KEY + if(ts_drv->touch_key_used && ts_drv->ledgpio >= 0) + setup_led_gpio(ts_drv); +#endif +#ifdef VT1609_DEBUG + /* 4. dump vt1603 to ensure setting ok */ + vt1603_reg_dump(ts_drv); +#endif +} +static __devinit int +vt1603_ts_probe(struct platform_device *pdev) +{ + int ret = 0; + struct vt1603_ts_drvdata *ts_drv = pContext; + struct vt1603_ts_platform_data *ts_pdata = NULL; + + ts_pdata = &vt1603_ts_pdata; + + ts_drv->pdata = ts_pdata; + ts_drv->pen_state = TS_PENUP_STATE; + ts_drv->tdev = dev_get_platdata(&pdev->dev); + + //spin_lock_init(&ts_drv->spinlock); + mutex_init(&ts_drv->ts_mutex); + + dev_set_drvdata(&pdev->dev, ts_drv); +#ifdef CONFIG_HAS_EARLYSUSPEND + ts_drv->earlysuspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + ts_drv->earlysuspend.suspend = vt1603ts_early_suspend; + ts_drv->earlysuspend.resume = vt1603ts_late_resume; + register_early_suspend(&ts_drv->earlysuspend); +#endif + /* 1. mclk enable */ + vt1603_ts_clk_enable(); + /* 2.vt1603 touch-panel and sar-adc module reset */ + vt1603_ts_reset(ts_drv); + +#ifdef VT1609_DEBUG + /* 4. dump vt1603 to ensure setting ok */ + vt1603_reg_dump(ts_drv); +#endif + /* initial battery if battery detection enable */ + /* initial temperature if temperature detection enable */ + + /* request iuput device */ + ts_drv->input = input_allocate_device(); + if (!ts_drv->input) { + printk("vt1603_ts: alloc input device failed"); + ret = -ENOMEM; + goto release_driver_data; + } + vt1603_register_input(ts_drv); + + INIT_DELAYED_WORK(&ts_drv->read_work, vt1603_read_loop); + INIT_DELAYED_WORK(&ts_drv->dual_work, vt1603_ts_dual_support); + INIT_DELAYED_WORK(&resume_work, vt1603_resume_work); + ts_drv->workqueue = create_singlethread_workqueue("vt160x-touch"); + if(!ts_drv->workqueue){ + printk("vt160x create singlethread work queue failed!\n"); + goto release_driver_data; + } + + INIT_WORK(&ts_drv->work, vt1603_ts_work); + + if (request_irq(ts_drv->gpio_irq, vt1603_ts_isr, IRQF_SHARED, "vt160x-touch", ts_drv)) { + printk("vt160x_ts: request IRQ %d failed\n", ts_drv->gpio_irq); + ret = -ENODEV; + } + + wmt_gpio_set_irq_type(ts_drv->intgpio, IRQ_TYPE_EDGE_FALLING); + wmt_gpio_unmask_irq(ts_drv->intgpio); + +#ifdef TOUCH_KEY + if(ts_drv->touch_key_used && ts_drv->ledgpio >= 0) + setup_led_gpio(ts_drv); +#endif + + dbg("%s Touch Screen Driver Installed!\n",ts_drv->dev_id); + return ret; + +release_driver_data: + kfree(ts_drv); + ts_drv = NULL; + + return ret; +} + +static __devexit int +vt1603_ts_remove(struct platform_device *pdev) +{ + struct vt1603_ts_drvdata *ts_drv; + ts_drv = dev_get_drvdata(&pdev->dev); + + dbg("Enter\n"); + + wmt_gpio_mask_irq(ts_drv->intgpio); + if(ts_drv->dual_enable) + vt1603_dual_exit(ts_drv); + + /* input unregister */ + input_unregister_device(ts_drv->input); + cancel_work_sync(&ts_drv->work); + cancel_delayed_work_sync(&ts_drv->dual_work); + cancel_delayed_work_sync(&ts_drv->read_work); + destroy_workqueue(ts_drv->workqueue); + vt1603_ts_dev_cleanup(ts_drv); +#ifdef TOUCH_KEY + if(ts_drv->touch_key_used && ts_drv->ledgpio >= 0) + del_timer_sync(&ts_drv->led_timer); +#endif + +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&ts_drv->earlysuspend); +#endif + /* free vt1603 driver data */ + dev_set_drvdata(&pdev->dev, NULL); + mutex_destroy(&ts_drv->ts_mutex); + free_irq(ts_drv->gpio_irq,ts_drv); + kfree(ts_drv); + ts_drv = NULL; + + dbg("Exit\n"); + return 0; +} + +#ifdef CONFIG_PM + +#ifdef CONFIG_HAS_EARLYSUSPEND + +static void +vt1603ts_early_suspend(struct early_suspend *h) +{ + struct vt1603_ts_drvdata *ts_drv = pContext; + + dbg("Enter\n"); + + wmt_gpio_mask_irq(ts_drv->intgpio); +#ifdef TOUCH_KEY + if(ts_drv->touch_key_used && ts_drv->ledgpio >= 0){ + del_timer_sync(&ts_drv->led_timer); + set_key_led_gpio(ts_drv,LOW); + } +#endif + + ts_drv->earlysus = 1; + dbg("Exit\n"); + return; +} + +static void +vt1603ts_late_resume(struct early_suspend *h) +{ + struct vt1603_ts_drvdata *ts_drv = pContext; + + dbg("Enter\n"); + ts_drv->pen_state = TS_PENUP_STATE; + + /* must ensure mclk is available */ + vt1603_ts_clk_enable(); + /* vt1603 ts hardware resume */ + vt1603_ts_reset(ts_drv); + /* clear irq before enale gpio irq */ + vt1603_clr_ts_irq(ts_drv, 0x0f ); + + ts_drv->earlysus = 0; + //wmt_gpio_set_irq_type(ts_drv->intgpio, IRQ_TYPE_EDGE_FALLING); + wmt_gpio_unmask_irq(ts_drv->intgpio); + #ifdef TOUCH_KEY + if(ts_drv->touch_key_used && ts_drv->ledgpio >= 0) + setup_led_gpio(ts_drv); + dbg("Exit\n"); +#endif + + return; +} + +#endif + +static int +vt1603_ts_suspend(struct platform_device *pdev, pm_message_t message) +{ + struct vt1603_ts_drvdata *ts_drv = dev_get_drvdata(&pdev->dev); + + dbg("Enter\n"); +#ifdef VT1609_DEBUG + /* 4. dump vt1603 to ensure setting ok */ + vt1603_reg_dump(ts_drv); +#endif + + ts_drv = dev_get_drvdata(&pdev->dev); + + wmt_gpio_mask_irq(ts_drv->intgpio); +#ifdef TOUCH_KEY + if(ts_drv->touch_key_used && ts_drv->ledgpio >= 0){ + set_key_led_gpio(ts_drv,LOW); + del_timer_sync(&ts_drv->led_timer); + } +#endif + + dbg("Exit\n"); + return 0; +} + +static int +vt1603_ts_resume(struct platform_device *pdev) +{ + //struct vt1603_ts_drvdata *ts_drv = dev_get_drvdata(&pdev->dev); + + dbg("Enter\n"); + //delay resume work because some resources were closed by audio driver. + schedule_delayed_work(&resume_work, HZ); +#if 0 + ts_drv->pen_state = TS_PENUP_STATE; + + /* must ensure mclk is available */ + vt1603_ts_clk_enable(); + /* vt1603 ts hardware resume */ + vt1603_ts_reset(ts_drv); + /* clear irq before enale gpio irq */ + vt1603_clr_ts_irq(ts_drv, 0x0f ); + + gpio_direction_input(ts_drv->intgpio); + wmt_gpio_set_irq_type(ts_drv->intgpio, IRQ_TYPE_EDGE_FALLING); + wmt_gpio_unmask_irq(ts_drv->intgpio); + #ifdef TOUCH_KEY + if(ts_drv->touch_key_used && ts_drv->ledgpio >= 0) + setup_led_gpio(ts_drv); +#endif +#ifdef VT1609_DEBUG + /* 4. dump vt1603 to ensure setting ok */ + vt1603_reg_dump(ts_drv); +#endif +#endif + dbg("Exit\n"); + + return 0; +} + +#else +#define vt1603_ts_suspend NULL +#define vt1603_ts_resume NULL +#endif + + +static struct platform_driver vt1603_driver = { + .driver = { + .name = VT1603_DRIVER_NAME, + .owner = THIS_MODULE, + }, + .probe = vt1603_ts_probe, + .remove = vt1603_ts_remove, + .suspend = vt1603_ts_suspend, + .resume = vt1603_ts_resume, +}; + +static int vt1603_ts_dev_open(struct inode *inode, struct file *filp) +{ + struct vt1603_ts_drvdata *ts_drv; + + dbg("Enter\n"); + + ts_drv = container_of(inode->i_cdev, struct vt1603_ts_drvdata , cdev); + if (ts_drv == NULL) { + printk("can not get vt1603_ts driver data\n"); + return -ENODATA; + } + filp->private_data = ts_drv; + + dbg("Exit\n"); + return 0; +} + +static int vt1603_ts_dev_close(struct inode *inode, struct file *filp) +{ + struct vt1603_ts_drvdata *ts_drv; + + dbg("Enter\n"); + + ts_drv = container_of(inode->i_cdev, struct vt1603_ts_drvdata , cdev); + if (ts_drv == NULL) { + printk("can not get vt1603_ts driver data\n"); + return -ENODATA; + } + + dbg("Exit\n"); + return 0; +} + +static long vt1603_ts_dev_ioctl(struct file *filp,unsigned int cmd, unsigned long arg) +{ + int ret = 0; + int nBuff[7] = { 0 }; + char env_val[96] = { 0 }; + struct vt1603_ts_drvdata *ts_drv; + + dbg("Enter\n"); + /* check type and command number */ + if (_IOC_TYPE(cmd) != VT1603_TS_IOC_MAGIC) + return -ENOTTY; + + ts_drv = filp->private_data; + switch (cmd) { + case VT1603_TS_IOC_CAL_DONE: + copy_from_user(nBuff, (unsigned int *)arg, 7 * sizeof(int)); + g_CalcParam.a1 = nBuff[0]; + g_CalcParam.b1 = nBuff[1]; + g_CalcParam.c1 = nBuff[2]; + g_CalcParam.a2 = nBuff[3]; + g_CalcParam.b2 = nBuff[4]; + g_CalcParam.c2 = nBuff[5]; + g_CalcParam.delta = nBuff[6]; + + if (g_CalcParam.delta == 0) + g_CalcParam.delta = 1; + + sprintf(env_val, "%d %d %d %d %d %d %d", + nBuff[0], nBuff[1], nBuff[2], nBuff[3], nBuff[4], nBuff[5], nBuff[6]); + + wmt_setsyspara("wmt.io.ts.2dcal", env_val); + printk("TOUCH CAL DONE: [%s]\n", env_val); + break; + + case VT1603_TS_IOC_CAL_RAWDATA: + nBuff[0] = ts_drv->raw_x; + nBuff[1] = ts_drv->raw_y; + copy_to_user((unsigned int *)arg, nBuff, 2 * sizeof(int)); + printk("TOUCH CAL RAWDATA: x=%-4d, y=%-4d \n", nBuff[0], nBuff[1]); + break; + default: + ret = -EINVAL; + break; + } + + dbg("Exit\n"); + return ret; +} + +static struct file_operations vt1603_ts_fops = { + .owner = THIS_MODULE, + .open = vt1603_ts_dev_open, + .unlocked_ioctl = vt1603_ts_dev_ioctl, + .release = vt1603_ts_dev_close, +}; + + +static int vt1603_ts_dev_setup(struct vt1603_ts_drvdata *ts_drv) +{ + dev_t dev_no = 0; + int ret = 0; + struct device *dev = NULL; + + dbg("Enter\n"); + if (VT1603_TS_DEV_MAJOR) { + ts_drv->major = VT1603_TS_DEV_MAJOR; + ts_drv->minor = 0; + dev_no = MKDEV(ts_drv->major, ts_drv->minor); + ret = register_chrdev_region(dev_no, VT1603_TS_NR_DEVS, DEV_NAME); + } else { + ret = alloc_chrdev_region(&dev_no, 0, VT1603_TS_NR_DEVS, DEV_NAME); + ts_drv->major = MAJOR(dev_no); + ts_drv->minor = MINOR(dev_no); + dbg("vt1603_ts device major = %d, minor = %d \n", ts_drv->major,ts_drv->minor); + } + + if (ret < 0) { + printk("can not get major %d\n", ts_drv->major); + goto out; + } + + cdev_init(&ts_drv->cdev, &vt1603_ts_fops); + + ts_drv->cdev.owner = THIS_MODULE; + ts_drv->cdev.ops = &vt1603_ts_fops; + ret = cdev_add(&ts_drv->cdev, dev_no, VT1603_TS_NR_DEVS); + if (ret) { + printk("add char dev for vt1603 ts failed\n"); + goto release_region; + } + + vt1603_ts_class = class_create(THIS_MODULE, ts_drv->dev_id); + if (IS_ERR(vt1603_ts_class)) { + printk("create vt1603_ts class failed\n"); + ret = PTR_ERR(vt1603_ts_class); + goto release_cdev; + } + + dev = device_create(vt1603_ts_class, NULL, dev_no, NULL, DEV_NAME); + if (IS_ERR(dev)) { + printk("create device for vt160x ts failed\n"); + ret = PTR_ERR(dev); + goto release_class; + } + + dbg("Exit\n"); + return ret; + +release_class: + class_destroy(vt1603_ts_class); + vt1603_ts_class = NULL; +release_cdev: + cdev_del(&ts_drv->cdev); +release_region: + unregister_chrdev_region(dev_no, VT1603_TS_NR_DEVS); +out: + return ret; +} + +static void vt1603_ts_dev_cleanup(struct vt1603_ts_drvdata *ts_drv) +{ + dev_t dev_no = MKDEV(ts_drv->major, ts_drv->minor); + + dbg("Enter\n"); + cdev_del(&ts_drv->cdev); + unregister_chrdev_region(dev_no, VT1603_TS_NR_DEVS); + device_destroy(vt1603_ts_class, dev_no); + class_destroy(vt1603_ts_class); + dbg("Exit\n"); +} + +#ifdef TOUCH_KEY +static int parse_touch_key_env(struct vt1603_ts_drvdata *ts_drv) +{ + int i = 0; + int ret = 0; + int len = 96; + char retval[96] = {0}; + char *p = NULL; + + ret = wmt_getsyspara("wmt.ts.vkey", retval, &len); + if(ret){ + printk("Read wmt.ts.vkey Failed.\n"); + return -EIO; + } + + sscanf(retval,"%d:%d:%d:%d", &ts_drv->tsc_key.key_num, + &ts_drv->tsc_key.low, &ts_drv->tsc_key.upper, &ts_drv->tsc_key.delta); + + if(!ts_drv->tsc_key.key_num){ + printk("tsc key number is zero!\n"); + return -EIO; + } + + p = retval; + i = 4; + while(i--){ + p = strchr(p,':'); + p++; + } + + for(i = 0; i < ts_drv->tsc_key.key_num; i++){ + sscanf(p,"%d_%d",&ts_drv->tsc_key.key[i].pos,&ts_drv->tsc_key.key[i].idx ); + p = strchr(p,':'); + p++; + } + + dbg("%d:%d:%d:%d:%d_%d:%d_%d:%d_%d:%d_%d\n", + ts_drv->tsc_key.key_num, + ts_drv->tsc_key.low, + ts_drv->tsc_key.upper, + ts_drv->tsc_key.delta, + ts_drv->tsc_key.key[0].pos, + ts_drv->tsc_key.key[0].idx, + ts_drv->tsc_key.key[1].pos, + ts_drv->tsc_key.key[1].idx, + ts_drv->tsc_key.key[2].pos, + ts_drv->tsc_key.key[2].idx, + ts_drv->tsc_key.key[3].pos, + ts_drv->tsc_key.key[3].idx); + + return 0; + +} +#endif + +static int parse_dual_env(struct vt1603_ts_drvdata *ts_drv) +{ + int ret = 0; + int len = 96; + char retval[96] = {0}; + + len = sizeof(retval); + ret = wmt_getsyspara("wmt.io.vt1609", retval, &len); + if(ret){ + //printk("wmt.io.vt1609 not set, use default parameter.\n"); + ts_drv->dual_dev.vxy = 17; + ts_drv->dual_dev.scale_x = 4; + ts_drv->dual_dev.scale_y = 2; + ts_drv->dual_dev.F1_CNT = 2; + ts_drv->dual_dev.F2_CNT = 7; + ts_drv->dual_dev.F2T1_CNT = 15; + ts_drv->dual_dev.SAMPLE_CNT = 1; + ts_drv->dual_dev.THR_MIN_DX = 13; + ts_drv->dual_dev.THR_MAX_DX = 256; + ts_drv->dual_dev.exch = 0; + + return 0; + } + + sscanf(retval,"%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", &ts_drv->dual_dev.vxy, + &ts_drv->dual_dev.scale_x, + &ts_drv->dual_dev.scale_y, + &ts_drv->dual_dev.F1_CNT, + &ts_drv->dual_dev.F2_CNT, + &ts_drv->dual_dev.F2T1_CNT, + &ts_drv->dual_dev.SAMPLE_CNT, + &ts_drv->dual_dev.THR_MIN_DX, + &ts_drv->dual_dev.THR_MAX_DX, + &ts_drv->dual_dev.exch); + /* + printk("%d:%d:%d:%d:%d:%d:%d:%d:%d\n", + ts_drv->dual_dev.vxy, + ts_drv->dual_dev.scale_x, + ts_drv->dual_dev.scale_y, + ts_drv->dual_dev.F1_CNT, + ts_drv->dual_dev.F2_CNT , + ts_drv->dual_dev.F2T1_CNT , + ts_drv->dual_dev.SAMPLE_CNT , + ts_drv->dual_dev.THR_MIN_DX , + ts_drv->dual_dev.THR_MAX_DX), + ts_drv->dual_dev.exch; + */ + return 0; +} + +static int vt1603_uboot_env_check(struct vt1603_ts_drvdata *ts_drv) +{ + int nBuff[7] = {0}; + int i = 0, Enable = 0; + int intgpio=0; + int ledgpio=-1; + int reslx=480,resly=800; + int ret=0,len = 96; + char retval[96] = {0}; + char *p=NULL; + + // Get u-boot parameter + ret = wmt_getsyspara("wmt.io.touch", retval, &len); + if(ret){ + printk("Read wmt.io.touch Failed.\n"); + return -EIO; + } + + sscanf(retval,"%d:",&Enable); + //check touch enable + if(Enable == 0){ + printk("System touchscreen is disbaled.\n"); + return -ENODEV; + } + + p = strchr(retval,':'); + p++; + if(strncmp(p,"vt1603",6) == 0){//check touch ID + strcpy(ts_drv->dev_id, "VT1603A"); + } + else if(strncmp(p,"vt1609",6) == 0){//check touch ID + ts_drv->dual_enable = 1; + strcpy(ts_drv->dev_id, "VT1609"); + parse_dual_env(ts_drv); + } + else{ + printk("Vt1609 touchscreen driver disabled.\n"); + return -ENODEV; + } + + p = strchr(p,':'); + p++; + sscanf(p,"%d:%d:%d:%d",&reslx, &resly, &intgpio, &ledgpio); + + ts_drv->resl_x = reslx; + ts_drv->resl_y = resly; + + ts_drv->intgpio = intgpio; + + ts_drv->ledgpio = ledgpio; + + ts_drv->gpio_irq = IRQ_GPIO; + + printk("%s-Touch: reslx=%d resly=%d, Interrupt GPIO%d , Virtual Touch Key Led GPIO%d\n",ts_drv->dev_id, + ts_drv->resl_x, ts_drv->resl_y, ts_drv->intgpio, ts_drv->ledgpio); + + len = sizeof(retval); + memset(retval, 0, sizeof(retval)); + + ret = wmt_getsyspara("wmt.io.ts.2dcal", retval, &len); + if(ret){ + printk("Read env wmt.io.ts.2dcal Failed.\n"); + //return -EIO; + } + + for (i = 0; i < sizeof(retval); i++) { + if (retval[i] == ' ' || retval[i] == ',' || retval[i] == ':') + retval[i] = '\0'; + } + + p = retval; + for (i = 0; (i < 7) && (p < (retval + sizeof(retval))); ) { + if (*p == '\0') + p++; + else { + sscanf(p, "%d", &nBuff[i]); + p = p + strlen(p); + i++; + } + } + dbg("Touchscreen Calibrate Data: [%d %d %d %d %d %d %d]\n", + nBuff[0], nBuff[1], nBuff[2], nBuff[3], nBuff[4], nBuff[5], nBuff[6]); + + g_CalcParam.a1 = nBuff[0]; + g_CalcParam.b1 = nBuff[1]; + g_CalcParam.c1 = nBuff[2]; + g_CalcParam.a2 = nBuff[3]; + g_CalcParam.b2 = nBuff[4]; + g_CalcParam.c2 = nBuff[5]; + g_CalcParam.delta = nBuff[6]; + + if(g_CalcParam.delta == 0) + g_CalcParam.delta = 1; + + memset(retval,0,sizeof(retval)); + ret = wmt_getsyspara("wmt.display.fb0", retval, &len); + if (!ret) { + int tmp[6]; + p = retval; + sscanf(p, "%d:[%d:%d:%d:%d:%d", &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5]); + if (tmp[4] > tmp[5]) + ts_drv->lcd_exchg = 1; + } + + return 0; +} + +static int gpio_resource_request(void) +{ + if (gpio_request(pContext->intgpio, "ts_irq") < 0) { + printk("gpio(%d) touchscreen interrupt request fail\n", pContext->intgpio); + return -EIO; + } + gpio_direction_input(pContext->intgpio); + + if (pContext->ledgpio >= 0) { + if (gpio_request(pContext->ledgpio, "ts_led") < 0) { + printk("gpio(%d) touchscreen led gpio request fail\n", pContext->ledgpio); + gpio_free(pContext->intgpio); + return -EIO; + } + gpio_direction_output(pContext->ledgpio, 0); + } + + return 0; +} +static void gpio_resource_free(void) +{ + gpio_free(pContext->intgpio); + if (pContext->ledgpio >= 0) + gpio_free(pContext->ledgpio); +} + + +static int __init vt1603_ts_init(void) +{ + int ret = 0; + struct vt1603_ts_drvdata *ts_drv = NULL; + + dbg("Enter\n"); + ts_drv = kzalloc(sizeof(struct vt1603_ts_drvdata), GFP_KERNEL); + if (!ts_drv) { + printk("vt160x ts: alloc driver data failed\n"); + return -ENOMEM; + } + pContext = ts_drv; + ret = vt1603_uboot_env_check(ts_drv); + if (ret) {//vt1603 touch disabled + goto out; + }else{//vt1603 touch enabled + if (gpio_resource_request()) + goto out; + ret = vt1603_ts_dev_setup(ts_drv);//only touch calibrate need dev node + if (ret) { + printk("##ERR## vt160x ts create device node failed.\n"); + goto freegpio; + } + +#ifdef TOUCH_KEY + if(!parse_touch_key_env(ts_drv)){ + ts_drv->touch_key_used = 1; + if(ts_drv->ledgpio >= 0){//touch virtual key back light led enabled + init_timer(&ts_drv->led_timer); + ts_drv->led_timer.function = led_timer_func; + ts_drv->led_timer.data = (unsigned long) ts_drv; + } + } +#endif + } + + ret = platform_driver_register(&vt1603_driver); + if(ret){ + printk("vt160x platform driver register failed!.\n"); + goto release_dev; + } + + if(ts_drv->dual_enable) + vt1603_dual_init(ts_drv); + + dbg("Exit\n"); + return ret; + +release_dev: + vt1603_ts_dev_cleanup(ts_drv); +freegpio: + gpio_resource_free(); +out: + kfree(ts_drv); + + return ret; +} +//module_init(vt1603_ts_init); +late_initcall(vt1603_ts_init); +static void __exit vt1603_ts_exit(void) +{ + dbg("Enter\n"); + + platform_driver_unregister(&vt1603_driver); + gpio_resource_free(); + + dbg("Exit\n"); +} +module_exit(vt1603_ts_exit); + +MODULE_DESCRIPTION("VT1603A/VT1609 TouchScreen Driver"); +MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/vt1609_ts/vt1609_ts.h b/ANDROID_3.4.5/drivers/input/touchscreen/vt1609_ts/vt1609_ts.h new file mode 100755 index 00000000..31210579 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/vt1609_ts/vt1609_ts.h @@ -0,0 +1,301 @@ +#ifndef __VT1603_TS_H__ +#define __VT1603_TS_H__ +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif + +#define DEV_NAME "wmtts" +#define VT1603_DRIVER_NAME "vt1603-touch" + +#undef abs +#define abs(x) (((x)>0)?(x):(-(x))) + +#define FALSE 0 +#define TRUE 1 +#define VT1603_TS_NR_DEVS 1 +#define VT1603_TS_DEV_MAJOR 160 +#define TS_DEBOUNCE 50 +#define VT1603_FILTER_HEAD_COUNT 2 +#define VT1603_JITTER_THRESHOLD 1200//µ¥µãÇ°ºó2µãÖ®¼äµÄx/y ±ä»¯×î´óÈÝÐíÖµ + +#define None_TOUCH 0x00 +#define Single_TOUCH 0x01 +#define Multi_TOUCH 0x02 + +#define ADC_DATA(low, high) ((((high) & 0x0F) << 8) + (low)) + +/* touch panel type config */ +#define PANEL_TYPE_4WIRED 0x10 +#define PANEL_TYPE_5WIRED 0x11 + +/* enable calibration or not */ +#define CALIBRATION_ENABLE 0x01 +#define CALIBRATION_DISABLE 0x00 + +/* VT1603 working mode */ +#define VT1603_TS_MODE BIT1 +#define VT1603_TEMP_MODE BIT2 +#define VT1603_BAT_MODE BIT3 + +/* VT1603 touch panel state */ +#define TS_PENDOWN_STATE 0x00 +#define TS_PENUP_STATE 0x01 + +struct vt1603_ts_pos { + int x; + int y; +}; + +#define VT1603_FIFO_LEN 3 +struct vt1603_fifo{ + int head; + int full; + int buf[VT1603_FIFO_LEN]; +}; + +#define I2C_BUS 0x00 +#define SPI_BUS 0x01 + +#define VT1603_SPI_FIX_CS 0x00 +#define VT1603_SPI_FAKE_CS 0x03 +#define VT1603_SPI_BUS_0 0x00 +#define VT1603_SPI_BUS_1 0x01 +#define VT1603_MAX_SPI_CLK (20*1000*1000) +#define SPI_DEFAULT_CLK (4*1000*1000) +#define IDLE_DATA_NUM 5 + +#define VT1603_I2C_FIX_ADDR 0x1A +#define VT1603_I2C_FAKE_ADDR 0xFF +#define VT1603_TS_I2C_WCMD 0x00 +#define VT1603_TS_I2C_RCMD 0x01 +#define VT1603_TS_I2C_RWCMD 0x02 +#define VT1603_I2C_BUS_0 0x00 +#define VT1603_I2C_BUS_1 0x01 + +/////////////////////////////// +//#define TOUCH_KEY +#define KEY_DETLA 300 +#define TOUCH_KEY_NUM 4 +#define TOUCH_KEY_LED_GPIO 4 + +#define HIGH 1 +#define LOW 0 + +struct tsc_key{ + int pos; + int idx; +}; + +struct tsc_key_st{ + int key_num; + int low; + int upper; + int delta; + struct tsc_key key[TOUCH_KEY_NUM]; +}; + +enum key_idx{ + _SEARCH, + _BACK, + _HOME, + _MENU, + _MAX_NUM, +}; +///////////////////////// + +enum gpio_irq_type { + HIGH_ACTIVE = 0, + LOW_ACTIVE = 1, + RISING_EDGE_ACTIVE = 3, + FALLING_EDGE_ACTIVE = 4, + UNKOWN_TYPE = 0xFF +}; + +/* + * vt1603_ts_platform_data - vt1603 configuration data + * @panel_type: touch panel type: 4-wired or 5-wired + * @cal_en: enable calibration circuit or not + * @cal_sel: calibratin capacitor control bits + * @shfit: conversion data shfit + * @sclk_div: initial value of sclk dividor if mclk = 12.288MHZ 0x04 = 200ksps 0x08 = 100ksps + * @soc_gpio_irq: soc gpio interrupts, connect with vt1603 gpio1 + */ +struct vt1603_ts_platform_data { + u8 panel_type; + u8 cal_en; + u8 cal_sel:2; + u8 shift; + u8 sclk_div; + int soc_gpio_irq; + int gpio_num; + enum gpio_irq_type irq_type; +}; + +struct vt1609_dual_st{ + int vxy; + + int scale_x; + int scale_y; + + int F1_CNT; + int F2_CNT; + int F2T1_CNT; + int SAMPLE_CNT; + + int THR_MIN_DX; + int THR_MAX_DX; + + int exch; +}; + +struct vt1603_ts_drvdata { + struct vt1603 *tdev; + //spinlock_t spinlock; + struct mutex ts_mutex; + struct input_dev *input; + struct work_struct work; + struct delayed_work read_work; + struct delayed_work dual_work; + struct workqueue_struct *workqueue; + struct vt1603_ts_platform_data *pdata; + + int earlysus; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend earlysuspend; +#endif + char dev_id[32]; + + struct cdev cdev; + int major; + int minor; + + int gpio_irq; + + int intgpio; + + u8 pen_state; + int ts_stamp; + int hcnt; + + int resl_x; + int resl_y; + int lcd_exchg; + + int raw_x; + int raw_y; + + int dual_enable; + struct vt1609_dual_st dual_dev; + + int ledgpio; +#ifdef TOUCH_KEY + int key_idx; + int key_pressed; + int touch_key_used; + struct timer_list led_timer; + struct tsc_key_st tsc_key; +#endif + +}; + +/* VT1603 Register address */ +#define VT1603_BTHD_REG 0x78 +#define VT1603_BCLK_REG 0x88 +#define VT1603_BAEN_REG 0x04 + +#define VT1603_PWC_REG 0xC0 +#define VT1603_CR_REG 0xC1 +#define VT1603_CCCR_REG 0xC2 +#define VT1603_CDPR_REG 0xC3 +#define VT1603_TSPC_REG 0xC4 +#define VT1603_AMCR_REG 0xC7 +#define VT1603_INTCR_REG 0xC8 +#define VT1603_INTEN_REG 0xC9 +#define VT1603_INTS_REG 0xCA +#define VT1603_DCR_REG 0xCB + +#define VT1603_TODCL_REG 0xCC +#define VT1603_TODCH_REG 0xCD + +#define VT1603_DATL_REG 0xCE +#define VT1603_DATH_REG 0xCF + +#define VT1603_XPL_REG 0xD0 +#define VT1603_XPH_REG 0xD1 +#define VT1603_YPL_REG 0xD2 +#define VT1603_YPH_REG 0xD3 + +#define VT1603_BATL_REG 0xD4 +#define VT1603_BATH_REG 0xD5 + +#define VT1603_TEMPL_REG 0xD6 +#define VT1603_TEMPH_REG 0xD7 + +#define VT1603_ERR8_REG 0xD8 +#define VT1603_ERR7_REG 0xD9 +#define VT1603_ERR6_REG 0xDA +#define VT1603_ERR5_REG 0xDB +#define VT1603_ERR4_REG 0xDC +#define VT1603_ERR3_REG 0xDD +#define VT1603_ERR2_REG 0xDE +#define VT1603_ERR1_REG 0xDF + +#define VT1603_DBG8_REG 0xE0 +#define VT1603_DBG7_REG 0xE1 +#define VT1603_DBG6_REG 0xE2 +#define VT1603_DBG5_REG 0xE3 +#define VT1603_DBG4_REG 0xE4 +#define VT1603_DBG3_REG 0xE5 +#define VT1603_DBG2_REG 0xE6 +#define VT1603_DBG1_REG 0xE7 + +/* for VT1603 GPIO1 interrupt setting */ +#define VT1603_IMASK_REG27 27 +#define VT1603_IMASK_REG28 28 +#define VT1603_IMASK_REG29 29 +#define VT1603_IPOL_REG33 33 +#define VT1603_ISEL_REG36 36 + +struct vt1603_ts_cal_info { + int a1; + int b1; + int c1; + int a2; + int b2; + int c2; + int delta; +}; + +/* VT1603 TS and SAR-ADC IOCTL */ +#define VT1603_TS_IOC_MAGIC 't' + +/* for touch screen calibration */ +#define VT1603_TS_IOC_CAL_START _IO(VT1603_TS_IOC_MAGIC, 1) +#define VT1603_TS_IOC_CAL_DONE _IOW(VT1603_TS_IOC_MAGIC, 2, int *) +#define VT1603_TS_IOC_CAL_RAWDATA _IOR(VT1603_TS_IOC_MAGIC, 3, int *) +#define VT1603_TS_IOC_CAL_QUIT _IOW(VT1603_TS_IOC_MAGIC, 4, int *) + +extern int wmt_setsyspara(char *varname, unsigned char *varval); +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlenex); + +int vt1603_clr_ts_irq(struct vt1603_ts_drvdata *ts_drv, u8 mask); +int vt1603_set_reg8(struct vt1603_ts_drvdata *ts_drv, u8 reg, u8 val); +u8 vt1603_get_reg8(struct vt1603_ts_drvdata *ts_drv, u8 reg); +void vt1603_setbits(struct vt1603_ts_drvdata *ts_drv, u8 reg, u8 mask); +void vt1603_clrbits(struct vt1603_ts_drvdata *ts_drv, u8 reg, u8 mask); + +void vt1603_ts_report_pos(struct vt1603_ts_drvdata *ts_drv, struct vt1603_ts_pos *pos); +int vt1603_ts_pos_calibration(struct vt1603_ts_drvdata *ts_drv,struct vt1603_ts_pos *to_cal); + +#ifdef TOUCH_KEY +void vt1603_ts_report_key(struct vt1603_ts_drvdata *ts_drv); +int vt1603_ts_get_key(struct vt1603_ts_drvdata *ts_drv,struct vt1603_ts_pos pos); +int set_key_led_gpio(struct vt1603_ts_drvdata *ts_drv,int val); +#endif + +int vt1603_dual_init(struct vt1603_ts_drvdata *ts_drv); +void vt1603_dual_exit(struct vt1603_ts_drvdata *ts_drv); +void vt1603_ts_dual_support(struct work_struct* work); + +#endif /* __VT1603_TS_H__ */ diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/zet6221_ts/Kconfig b/ANDROID_3.4.5/drivers/input/touchscreen/zet6221_ts/Kconfig new file mode 100755 index 00000000..3bf6dcc3 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/zet6221_ts/Kconfig @@ -0,0 +1,16 @@ +# +# ZET6221 capacity touch screen driver configuration +# +config TOUCHSCREEN_ZET6221 + tristate "ZEITEC ZET6221 I2C Capacitive Touchscreen Input Driver Support" + depends on ARCH_WMT + default y + help + Say Y here if you have an WMT based board with touchscreen + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called s_wmt_ts_zet6221 + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/zet6221_ts/Makefile b/ANDROID_3.4.5/drivers/input/touchscreen/zet6221_ts/Makefile new file mode 100755 index 00000000..102fb212 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/zet6221_ts/Makefile @@ -0,0 +1,32 @@ +KERNELDIR=../../../../ +CROSS = arm_1103_le- +CC= $(CROSS)gcc +LD= $(CROSS)ld +STRIP = $(CROSS)strip + +DEBUG = n + +# Add your debugging flag (or not) to EXTRA_CFLAGS +ifeq ($(DEBUG),y) +# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines +DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines + +else + DEBFLAGS = -O2 -Wall +endif + +EXTRA_CFLAGS += $(DEBFLAGS) + + +MY_MODULE_NAME=s_wmt_ts_zet6221 + +obj-m := $(MY_MODULE_NAME).o +$(MY_MODULE_NAME)-objs := zet6221_i2c.o wmt_ts.o zet6221_downloader.o + +default: + $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules + $(STRIP) --strip-debug $(MY_MODULE_NAME).ko + rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions *.order *.symvers modules.builtin + +clean: + rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers modules.builtin \ No newline at end of file diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/zet6221_ts/wmt_ts.c b/ANDROID_3.4.5/drivers/input/touchscreen/zet6221_ts/wmt_ts.c new file mode 100755 index 00000000..bfc65e7f --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/zet6221_ts/wmt_ts.c @@ -0,0 +1,833 @@ +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "wmt_ts.h" +#include "zet6221_ts.h" + +///////////////////////////////////////////////////////////////// + +// commands for ui +#define TS_IOC_MAGIC 't' + +#define TS_IOCTL_CAL_START _IO(TS_IOC_MAGIC, 1) +#define TS_IOCTL_CAL_DONE _IOW(TS_IOC_MAGIC, 2, int*) +#define TS_IOCTL_GET_RAWDATA _IOR(TS_IOC_MAGIC, 3, int*) +#define TS_IOCTL_CAL_QUIT _IOW(TS_IOC_MAGIC, 4, int*) +#define TS_IOCTL_AUTO_CALIBRATION _IOW(TS_IOC_MAGIC, 5, int*) +#define TS_IOC_MAXNR 5 + +#define TP_INFOR_ARRAY_SIZE (sizeof(l_tpinfor)/sizeof(l_tpinfor[1])) +// +#define TS_MAJOR 11 +#define TS_DRIVER_NAME "wmtts_touch" +#define TS_NAME "wmtts" +#define WMTTS_PROC_NAME "wmtts_config" + +#define EXT_GPIO0 0 +#define EXT_GPIO1 1 +#define EXT_GPIO2 2 +#define EXT_GPIO3 3 +#define EXT_GPIO4 4 +#define EXT_GPIO5 5 +#define EXT_GPIO6 6 +#define EXT_GPIO7 7 + + + +typedef struct { + int a1; + int b1; + int c1; + int a2; + int b2; + int c2; + int delta; +}CALIBRATION_PARAMETER, *PCALIBRATION_PARAMETER; + + +static int irq_gpio; +static int rst_gpio; +static int panelres_x; +static int panelres_y; +static int s_download_option; +static int s_high_Impendence_mode; +static int lcd_exchg = 0; + + +static DECLARE_WAIT_QUEUE_HEAD(queue); +static DECLARE_WAIT_QUEUE_HEAD(ts_penup_wait_queue); + +extern struct wmtts_device zet6221_tsdev; +static struct wmtts_device* l_tsdev = &zet6221_tsdev; +struct proc_dir_entry* l_tsproc = NULL; +static struct i2c_client *l_client=NULL; +static int l_penup = 1; // 1-pen up,0-pen down +int earlysus_en = 0; + +struct tp_infor +{ + //enum tp_type type; + char name[64]; + //unsigned int i2caddr; + unsigned int xaxis; //0: x,1: x swap with y + unsigned int xdir; // 1: positive,-1: revert + unsigned int ydir; // 1: positive,-1: revert + unsigned int max_finger_num; +}; + +static int l_tpindex = -1; +static struct tp_infor l_tpinfor[1]; + +///////////////////////////////////////////////////// +// function declare +///////////////////////////////////////////////////// +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); +extern int wmt_setsyspara(char *varname, unsigned char *varval); +static int ts_writeproc( struct file *file, + const char *buffer, + unsigned long count, + void *data ); +static int ts_readproc(char *page, char **start, off_t off, + int count, int *eof, void *data); +/////////////////////////////////////////////////////////////////////// + +void wmt_ts_get_firmwname(char* firmname) +{ + int offset = 0; + offset = strlen(l_tsdev->ts_id); + switch(ic_model){ + case ZET6223: + l_tpinfor[l_tpindex].name[offset] = '2'; + l_tpinfor[l_tpindex].name[offset+1] = '3'; + break; + case ZET6231: + l_tpinfor[l_tpindex].name[offset] = '3'; + l_tpinfor[l_tpindex].name[offset+1] = '1'; + break; + case ZET6251: + l_tpinfor[l_tpindex].name[offset] = '5'; + l_tpinfor[l_tpindex].name[offset+1] = '1'; + break; + case ZET6221: + default: + l_tpinfor[l_tpindex].name[offset] = '2'; + l_tpinfor[l_tpindex].name[offset+1] = '1'; + break; + } + sprintf(firmname,"%s_fw.bin",l_tpinfor[l_tpindex].name); +} + +unsigned int wmt_ts_get_xaxis(void) +{ + return l_tpinfor[l_tpindex].xaxis; +} + +unsigned int wmt_ts_get_xdir(void) +{ + return l_tpinfor[l_tpindex].xdir; +} + +unsigned int wmt_ts_get_ydir(void) +{ + return l_tpinfor[l_tpindex].ydir; +} + +unsigned int wmt_ts_get_maxfingernum(void) +{ + return l_tpinfor[l_tpindex].max_finger_num; +} + + +int wmt_ts_load_firmware(char* firmwarename, unsigned char** firmdata, int* fwlen) +{ + const struct firmware *fw_entry; + if(request_firmware(&fw_entry, firmwarename, &l_client->dev)!=0) { + printk(KERN_ERR "cat't request firmware\n"); + return -1; + } + if (fw_entry->size <= 0) { + printk(KERN_ERR "load firmware error\n"); + release_firmware(fw_entry); + return -1; + } + + //*firmdata = kzalloc(fw_entry->size + 1, GFP_KERNEL); + memcpy(*firmdata, fw_entry->data, fw_entry->size); + *fwlen = fw_entry->size; + release_firmware(fw_entry); + + return 0; +} + + + + int wmt_ts_get_gpionum(void) +{ + return irq_gpio; +} + +int wmt_ts_get_resetgpnum(void) +{ + return rst_gpio; +} + +int wmt_ts_get_lcdexchg(void) +{ + return lcd_exchg; +} + +int wmt_ts_get_resolvX(void) +{ + return panelres_x; +} + +int wmt_ts_get_resolvY(void) +{ + return panelres_y; +} + +//up:1-pen up,0-pen down +void wmt_ts_set_penup(int up) +{ + l_penup = up; +} + +// +int wmt_ts_wait_penup(void) +{ + int ret = wait_event_interruptible( + ts_penup_wait_queue, + (1==l_penup)); + return ret; +} + +// return:1-pen up,0-pen dwon +int wmt_ts_ispenup(void) +{ + return l_penup; +} + + +void wmt_ts_wakeup_penup(void) +{ + wake_up(&ts_penup_wait_queue); +} + +int wmt_is_tsirq_enable(void) +{ + int val = 0; + int num = irq_gpio; + + if(num > 11) + return 0; + + if(num<4) + val = REG32_VAL(__GPIO_BASE+0x0300) & (1<<(num*8+7)); + else if(num >= 4 && num < 8) + val = REG32_VAL(__GPIO_BASE+0x0304) & (1<<((num-4)*8+7)); + else + val = REG32_VAL(__GPIO_BASE+0x0308) & (1<<((num-8)*8+7)); + + return val?1:0; + +} + +int wmt_is_tsint(void) +{ + int num = irq_gpio; + + if (num > 11) + { + return 0; + } + return (REG32_VAL(__GPIO_BASE+0x0360) & (1< 11) + { + return; + } + REG32_VAL(__GPIO_BASE+0x0360) = 1<11) + return -1; + //if (num > 9) + //GPIO_PIN_SHARING_SEL_4BYTE_VAL &= ~BIT4; // gpio10,11 as gpio + REG32_VAL(__GPIO_BASE+0x0040) &= ~(1<= 4 && num < 8){//[4,7] + shift = num-4; + offset = 0x0304; + }else{// [8,11] + shift = num-8; + offset = 0x0308; + } + + reg = REG32_VAL(__GPIO_BASE + offset); + + switch(type){ + case IRQ_TYPE_LEVEL_LOW: + reg &= ~(1<<(shift*8+2)); + reg &= ~(1<<(shift*8+1)); + reg &= ~(1<<(shift*8)); + break; + case IRQ_TYPE_LEVEL_HIGH: + reg &= ~(1<<(shift*8+2)); + reg &= ~(1<<(shift*8+1)); + reg |= (1<<(shift*8)); + break; + case IRQ_TYPE_EDGE_FALLING: + reg &= ~(1<<(shift*8+2)); + reg |= (1<<(shift*8+1)); + reg &= ~(1<<(shift*8)); + break; + case IRQ_TYPE_EDGE_RISING: + reg &= ~(1<<(shift*8+2)); + reg |= (1<<(shift*8+1)); + reg |= (1<<(shift*8)); + break; + default://both edge + reg |= (1<<(shift*8+2)); + reg &= ~(1<<(shift*8+1)); + reg &= ~(1<<(shift*8)); + break; + + } + //reg |= 1<<(shift*8+7);//enable interrupt + reg &= ~(1<<(shift*8+7)); //disable int + + REG32_VAL(__GPIO_BASE + offset) = reg; + REG32_VAL(__GPIO_BASE+0x0360) = 1< 11) + return -1; + + if(num<4) + REG32_VAL(__GPIO_BASE+0x0300) |= 1<<(num*8+7); //enable interrupt + else if(num >= 4 && num < 8) + REG32_VAL(__GPIO_BASE+0x0304) |= 1<<((num-4)*8+7); //enable interrupt + else + REG32_VAL(__GPIO_BASE+0x0308) |= 1<<((num-8)*8+7); //enable interrupt + + return 0; +} + +int wmt_disable_gpirq(void) +{ + int num = irq_gpio; + + if(num > 11) + return -1; + + if(num<4) + REG32_VAL(__GPIO_BASE+0x0300) &= ~(1<<(num*8+7)); //enable interrupt + else if(num >= 4 && num < 8) + REG32_VAL(__GPIO_BASE+0x0304) &= ~(1<<((num-4)*8+7)); //enable interrupt + else + REG32_VAL(__GPIO_BASE+0x0308) &= ~(1<<((num-8)*8+7)); //enable interrupt + + return 0; +} + + +int wmt_get_tsirqnum(void) +{ + return IRQ_GPIO; +} + +static void wmt_ts_platform_release(struct device *device) +{ + return; +} + +static struct platform_device wmt_ts_plt_device = { + .name = TS_DRIVER_NAME, + .id = 0, + .dev = { + .release = wmt_ts_platform_release, + }, +// .num_resources = ARRAY_SIZE(wm9715_ts_resources), +// .resource = wm9715_ts_resources, +}; + +static int wmt_ts_suspend(struct platform_device *pdev, pm_message_t state) +{ + dbg("ts suspend....\n"); + return l_tsdev->suspend(pdev, state); +} +static int wmt_ts_resume(struct platform_device *pdev) +{ + dbg("ts resume....\n"); + return l_tsdev->resume(pdev); +} + +static int wmt_ts_probe(struct platform_device *pdev) +{ + l_tsproc= create_proc_entry(WMTTS_PROC_NAME, 0666, NULL/*&proc_root*/); + if (l_tsproc != NULL) + { + l_tsproc->read_proc = ts_readproc; + l_tsproc->write_proc = ts_writeproc; + } + + if (l_tsdev->probe != NULL) + return l_tsdev->probe(pdev); + else + return 0; +} + +static int wmt_ts_remove(struct platform_device *pdev) +{ + if (l_tsproc != NULL) + { + remove_proc_entry(WMTTS_PROC_NAME, NULL); + l_tsproc = NULL; + } + + if (l_tsdev->remove != NULL) + return l_tsdev->remove(pdev); + else + return 0; +} + +static struct platform_driver wmt_ts_plt_driver = { + .driver = { + .name = TS_DRIVER_NAME, + .owner = THIS_MODULE, + }, + .probe = wmt_ts_probe, + .remove = wmt_ts_remove, + .suspend = wmt_ts_suspend, + .resume = wmt_ts_resume, +}; + +static int ts_writeproc( struct file *file, + const char *buffer, + unsigned long count, + void *data ) +{ + int calibrate = 0; + int val = 0; + + if (sscanf(buffer, "calibrate=%d\n", &calibrate)) + { + if (1 == calibrate) + { + if((l_tsdev->capacitance_calibrate != NULL) && + (0 == l_tsdev->capacitance_calibrate())) + { + printk(KERN_ALERT "%s calibration successfully!\n", l_tsdev->ts_id); + } else { + printk(KERN_ALERT "%s calibration failed!\n", l_tsdev->ts_id); + } + } + } else if (sscanf(buffer, "reset=%d\n", &val)) + { + + } + return count; +} + +static int ts_readproc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = 0; + + len = sprintf(page, + "echo calibrate=1 > /proc/wmtts_config to calibrate ts.\n"); + return len; +} + + +int is_high_impendence_mode(void) +{ + return s_high_Impendence_mode; +} + +int get_download_option(void) +{ + return s_download_option; +} + + +static int wmt_check_touch_env(void) +{ + int ret = 0; + int len = 96, i = 0; + char retval[200] = {0},*p=NULL,*s=NULL; + int Enable=0; + int val,val1; + + // Get u-boot parameter + ret = wmt_getsyspara("wmt.io.touch", retval, &len); + if(ret){ + errlog("Read wmt.io.touch Failed.\n"); + return -EIO; + } + memset(l_tpinfor,0,sizeof(l_tpinfor[0])); + + p = retval; + sscanf(p,"%d:", &Enable); + p = strchr(p,':');p++; + s = strchr(p,':'); + strncpy(l_tpinfor[0].name,p, (s-p)); + p = s+1; + dbg("ts_name=%s\n", l_tpinfor[0].name); + + ret = sscanf(p,"%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", + &irq_gpio,&panelres_x,&panelres_y,&rst_gpio, + &(l_tpinfor[0].xaxis),&(l_tpinfor[0].xdir),&(l_tpinfor[0].ydir), + &(l_tpinfor[0].max_finger_num),&s_high_Impendence_mode,&s_download_option); + + if (ret < 8) + { + dbg("Wrong format ts u-boot param(%d)!\nwmt.io.touch=%s\n",ret,retval); + return -ENODEV; + } + + //check touch enable + if(Enable == 0){ + errlog("Touch Screen Is Disabled.\n"); + return -ENODEV; + } + + + /*p = strchr(retval,':'); + p++; + if(strncmp(p, l_tsdev->ts_id,strlen(l_tsdev->ts_id))){//check touch ID + //errlog(" %s!=====\n", l_tsdev->ts_id); + return -ENODEV; + }*/ + + //sscanf(p,"%s:", ); + if (strstr(l_tpinfor[0].name, l_tsdev->ts_id) == NULL) + { + errlog("Can't find %s%s!\n", l_tsdev->ts_id,"xx"); + return -ENODEV; + } + l_tpindex = 0; + +/* + p = strchr(p,':'); + p++; + sscanf(p,"%d:%d:%d:%d",&irq_gpio,&panelres_x,&panelres_y,&rst_gpio); + + */ + klog("p.x = %d, p.y = %d, gpio=%d, resetgpio=%d,xaxis=%d,xdir=%d,ydri=%d,maxfingernum=%d,high_Impendence_mode=%d,s_download_option=%d\n", + panelres_x, panelres_y, irq_gpio, rst_gpio, + l_tpinfor[0].xaxis,l_tpinfor[0].xdir,l_tpinfor[0].ydir, + l_tpinfor[0].max_finger_num,s_high_Impendence_mode,s_download_option); + + // parse touch key param + memset(retval,0,sizeof(retval)); + ret = wmt_getsyspara("wmt.io.tskeyindex", retval, &len); + if(ret){ + dbg("no touch key!\n"); + //return -EIO; + } else { + p = retval; + // the number of touch key + sscanf(retval,"%d:", &val); + dbg("tskey num:%d\n",val); + p = strchr(p,':'); + p++; + // touch key range + for (i=0;i tmp[5]) + lcd_exchg = 1; + } + +/* memset(retval,0,sizeof(retval)); + ret = wmt_getsyspara("wmt.io.ts.2dcal", retval, &len); + if(ret){ + errlog("Read env wmt.io.ts.2dcal Failed.\n "); + //return -EIO; + } + i = 0; + while(i < sizeof(retval)){ + if(retval[i]==' ' || retval[i]==',' || retval[i]==':') + retval[i] = '\0'; + i++; + } + + i = 0; + p = retval; + while(i<7 && p < (retval + sizeof(retval))){ + if(*p == '\0') + p++; + else{ + sscanf(p,"%d",&nBuff[i]); + //printk("%d\n",nBuff[i]); + p=p+strlen(p); + i++; + } + } + //sscanf(retval,"%d %d %d %d %d %d %d %d",&nBuff[0],&nBuff[1],&nBuff[2],&nBuff[3],&nBuff[4],&nBuff[5],&nBuff[6]); + dbg("Tsc calibrate init data: [%d %d %d %d %d %d %d]\n",nBuff[0],nBuff[1],nBuff[2],nBuff[3],nBuff[4],nBuff[5],nBuff[6]); + + g_CalcParam.a1 = nBuff[0]; + g_CalcParam.b1 = nBuff[1]; + g_CalcParam.c1 = nBuff[2]; + g_CalcParam.a2 = nBuff[3]; + g_CalcParam.b2 = nBuff[4]; + g_CalcParam.c2 = nBuff[5]; + g_CalcParam.delta = nBuff[6]; + + if(g_CalcParam.delta == 0) + g_CalcParam.delta =1;//avoid divide by zero +*/ + return 0; +} + +struct i2c_board_info ts_i2c_board_info = { + .type = WMT_TS_I2C_NAME, + .flags = 0x00, + .addr = WMT_TS_I2C_ADDR, + .platform_data = NULL, + .archdata = NULL, + .irq = -1, +}; + +static int ts_i2c_register_device (void) +{ + struct i2c_board_info *ts_i2c_bi; + struct i2c_adapter *adapter = NULL; + //struct i2c_client *client = NULL; + ts_i2c_bi = &ts_i2c_board_info; + adapter = i2c_get_adapter(1);/*in bus 1*/ + + if (NULL == adapter) { + printk("can not get i2c adapter, client address error\n"); + return -1; + } + l_client = i2c_new_device(adapter, ts_i2c_bi); + if (l_client == NULL) { + printk("allocate i2c client failed\n"); + return -1; + } + i2c_put_adapter(adapter); + return 0; +} + +static void ts_i2c_unregister_device(void) +{ + if (l_client != NULL) + { + i2c_unregister_device(l_client); + l_client = NULL; + } +} + +struct i2c_client* ts_get_i2c_client(void) +{ + return l_client; +} + +static int __init wmt_ts_init(void) +{ + int ret = 0; + + if(wmt_check_touch_env()) + return -ENODEV; + + //ts_i2c_board_info.addr = l_tpinfor[l_tpindex].i2caddr; + if (ts_i2c_register_device()<0) + { + dbg("Error to run ts_i2c_register_device()!\n"); + return -1; + } + + if (l_tsdev->init() < 0){ + dbg("Errors to init %s ts IC!!!\n", l_tsdev->ts_id); + ret = -1; + goto err_init; + } + + // register device and driver of platform + ret = platform_device_register(&wmt_ts_plt_device); + if(ret){ + errlog("wmt ts plat device register failed!\n"); + return ret; + } + ret = platform_driver_register(&wmt_ts_plt_driver); + if(ret){ + errlog("can not register platform_driver_register\n"); + platform_device_unregister(&wmt_ts_plt_device); + return ret; + } + + klog("%s driver init ok!\n",l_tsdev->ts_id); + return 0; +err_init: + ts_i2c_unregister_device(); + return ret; +} + +static void __exit wmt_ts_exit(void) +{ + dbg("%s\n",__FUNCTION__); + + l_tsdev->exit(); + platform_driver_unregister(&wmt_ts_plt_driver); + platform_device_unregister(&wmt_ts_plt_device); + ts_i2c_unregister_device(); +} + + +module_init(wmt_ts_init); +module_exit(wmt_ts_exit); + +MODULE_LICENSE("GPL"); + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/zet6221_ts/wmt_ts.h b/ANDROID_3.4.5/drivers/input/touchscreen/zet6221_ts/wmt_ts.h new file mode 100755 index 00000000..cab70586 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/zet6221_ts/wmt_ts.h @@ -0,0 +1,149 @@ + +#ifndef WMT_TSH_201010191758 +#define WMT_TSH_201010191758 + +#include +#include +#include +#include +#include + + +//#define DEBUG_WMT_TS +#ifdef DEBUG_WMT_TS +#undef dbg +#define dbg(fmt, args...) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__ , ## args) + +//#define dbg(fmt, args...) if (kpadall_isrundbg()) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__, ## args) + +#else +#define dbg(fmt, args...) +#endif + +#undef errlog +#undef klog +#define errlog(fmt, args...) printk("[%s]: " fmt, __FUNCTION__, ## args) +#define klog(fmt, args...) printk("[%s]: " fmt, __FUNCTION__, ## args) + +#define WMT_TS_I2C_NAME "zet6221-ts" +#define WMT_TS_I2C_ADDR 0x76 + + +#ifndef dim +#define dim(x) (sizeof(x) / sizeof(x[0])) +#endif + +extern int earlysus_en; + +//////////////////////////////data type/////////////////////////// +typedef struct { + short pressure; + short x; + short y; + //short millisecs; +} TS_EVENT; + +struct wmtts_device +{ + //data + char* driver_name; + char* ts_id; + //function + int (*init)(void); + int (*probe)(struct platform_device *platdev); + int (*remove)(struct platform_device *pdev); + void (*exit)(void); + int (*suspend)(struct platform_device *pdev, pm_message_t state); + int (*resume)(struct platform_device *pdev); + int (*capacitance_calibrate)(void); + int (*wait_penup)(struct wmtts_device*tsdev); // waiting untill penup + int penup; // 0--pendown;1--penup + +}; + +enum { + ZET6221 = 0, + ZET6231, + ZET6223, + ZET6251, +}; +extern u8 ic_model; +extern unsigned char* flash_buffer; +extern int l_fwlen; + + +//////////////////////////function interface///////////////////////// +extern int wmt_ts_get_gpionum(void); +extern int wmt_ts_iscalibrating(void); +extern int wmt_ts_get_resolvX(void); +extern int wmt_ts_get_resolvY(void); +extern int wmt_set_gpirq(int type); +extern int wmt_get_tsirqnum(void); +extern int wmt_disable_gpirq(void); +extern int wmt_enable_gpirq(void); +extern int wmt_is_tsirq_enable(void); +extern int wmt_is_tsint(void); +extern void wmt_clr_int(void); +extern void wmt_tsreset_init(void); +extern int wmt_ts_get_resetgpnum(void); +extern int wmt_ts_get_lcdexchg(void); +extern void wmt_enable_rst_pull(int enable); +extern void wmt_set_rst_pull(int up); +extern void wmt_rst_output(int high); +extern void wmt_rst_input(void); +extern void wmt_set_intasgp(void); +extern void wmt_intgp_out(int val); +extern void wmt_ts_set_irqinput(void); +extern unsigned int wmt_ts_irqinval(void); +extern void wmt_ts_set_penup(int up); +extern int wmt_ts_wait_penup(void); +extern void wmt_ts_wakeup_penup(void); +extern struct i2c_client* ts_get_i2c_client(void); +extern int wmt_ts_ispenup(void); +extern unsigned int wmt_ts_get_maxfingernum(void); +extern unsigned int wmt_ts_get_ictype(void); +extern unsigned int wmt_ts_get_xaxis(void); +extern unsigned int wmt_ts_get_xdir(void); +extern unsigned int wmt_ts_get_ydir(void); +// short +extern unsigned int wmt_ts_get_touchheight(void); +// long +extern unsigned int wmt_ts_get_touchwidth(void); +extern void wmt_ts_get_firmwname(char* firmname); +extern int wmt_ts_load_firmware(char* firmwarename, unsigned char** firmdata, int* fwlen); + + + + +extern void TouchPanelCalibrateAPoint( + int UncalX, //@PARM The uncalibrated X coordinate + int UncalY, //@PARM The uncalibrated Y coordinate + int *pCalX, //@PARM The calibrated X coordinate + int *pCalY //@PARM The calibrated Y coordinate + ); + +//filepath:the path of firmware file; +//firmdata:store the data from firmware file; +//maxlen: the max len of firmdata; +//return:the length of firmware data,negative-parsing error. +//extern +u8 zet6221_ts_sfr(struct i2c_client *client); +int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); + + +#define HIGH_IMPENDENCE_MODE 0 +#define NOT_HIGH_IMPENDENCE_MODE 1 + +extern int is_high_impendence_mode(void); + + +#define FORCE_DOWNLOAD 1 +#define FORCE_CANCEL_DOWNLOAD 2 +extern int get_download_option(void); + + + +#endif + + + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/zet6221_ts/zet6221_downloader.c b/ANDROID_3.4.5/drivers/input/touchscreen/zet6221_ts/zet6221_downloader.c new file mode 100755 index 00000000..ac51aa21 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/zet6221_ts/zet6221_downloader.c @@ -0,0 +1,1209 @@ +#include +#include +#include +#include +#include +//#include "zet6221_fw.h" + +#include "wmt_ts.h" + +#define ZET6221_DOWNLOADER_NAME "zet6221_downloader" +#define FEATURE_FW_CHECK_SUM 1 +//#define High_Impendence_Mode + +#define TS_INT_GPIO S3C64XX_GPN(9) /*s3c6410*/ +#define TS_RST_GPIO S3C64XX_GPN(10) /*s3c6410*/ +#define RSTPIN_ENABLE + +#define GPIO_LOW 0 +#define GPIO_HIGH 1 + +//static u8 fw_version0; +//static u8 fw_version1; + +//#define debug_mode 1 +//#define DPRINTK(fmt,args...) do { if (debug_mode) printk(KERN_EMERG "[%s][%d] "fmt"\n", __FUNCTION__, __LINE__, ##args);} while(0) + +static unsigned char zeitec_zet6221_page[131] __initdata; +static unsigned char zeitec_zet6221_page_in[131] __initdata; +unsigned char* flash_buffer = NULL; +int l_fwlen = 0; + +//static u16 fb[8] = {0x3EEA,0x3EED,0x3EF0,0x3EF3,0x3EF6,0x3EF9,0x3EFC,0x3EFF}; +static u16 fb[8] = {0x3DF1,0x3DF4,0x3DF7,0x3DFA,0x3EF6,0x3EF9,0x3EFC,0x3EFF}; +static u16 fb21[8] = {0x3DF1,0x3DF4,0x3DF7,0x3DFA,0x3EF6,0x3EF9,0x3EFC,0x3EFF}; +static u16 fb23[8] = {0x7BFC,0x7BFD,0x7BFE,0x7BFF,0x7C04,0x7C05,0x7C06,0x7C07}; +u8 ic_model = 0; + +extern int zet6221_i2c_write_tsdata(struct i2c_client *client, u8 *data, u8 length); +extern int zet6221_i2c_read_tsdata(struct i2c_client *client, u8 *data, u8 length); +extern u8 pc[]; + + + + +/************************load firmwre data from file************************/ +int zet6221_load_fw(void) +{ + char fwname[256] = {0}; + int ret = -1; + wmt_ts_get_firmwname(fwname); + ret = wmt_ts_load_firmware(fwname, &flash_buffer, &l_fwlen); + if(!ret) { + printk("Success load fw_file: %s, length %d\n", fwname, l_fwlen); + printk("%x,%x,%x,%x\n", flash_buffer[0], flash_buffer[1], flash_buffer[2], flash_buffer[3]); + printk("%x,%x,%x,%x\n", flash_buffer[l_fwlen-4], flash_buffer[l_fwlen-3], flash_buffer[l_fwlen-2], flash_buffer[l_fwlen-1]); + } + return ret; +} + +/***********************free firmware memory*******************************/ +int zet6221_free_fwmem(void) +{ + if (l_fwlen > 0 && flash_buffer != NULL ) + { + kfree(flash_buffer); + flash_buffer = NULL; + l_fwlen = 0; + } + return 0; +} +//#define I2C_CTPM_ADDRESS (0x76) + +/*********************************************************************** +[function]: + callback: write data to ctpm by i2c interface,implemented by special user; +[parameters]: + client[in] :i2c client structure; + bt_ctpm_addr[in] :the address of the ctpm; + pbt_buf[in] :data buffer; + dw_lenth[in] :the length of the data buffer; +[return]: + 1 :success; + 0 :fail; +************************************************************************/ +int i2c_write_interface(struct i2c_client *client, u8 bt_ctpm_addr, u8* pbt_buf, u16 dw_lenth) +{ + struct i2c_msg msg; + msg.addr = bt_ctpm_addr; + msg.flags = 0; + msg.len = dw_lenth; + msg.buf = pbt_buf; + return i2c_transfer(client->adapter,&msg, 1); +} + +/*********************************************************************** +[function]: + callback: read data from ctpm by i2c interface,implemented by special user; +[parameters]: + client[in] :i2c client structure; + bt_ctpm_addr[in] :the address of the ctpm; + pbt_buf[out] :data buffer; + dw_lenth[in] :the length of the data buffer; +[return]: + 1 :success; + 0 :fail; +************************************************************************/ +int i2c_read_interface(struct i2c_client *client, u8 bt_ctpm_addr, u8* pbt_buf, u16 dw_lenth) +{ + struct i2c_msg msg; + msg.addr = bt_ctpm_addr; + msg.flags = I2C_M_RD; + msg.len = dw_lenth; + msg.buf = pbt_buf; + return i2c_transfer(client->adapter,&msg, 1); +} + +/*********************************************************************** + [function]: + callback: check version; + [parameters]: + void + + [return]: + 0: different 1: same; +************************************************************************/ +u8 zet6221_ts_version(void) +{ + int i; + + if(pc == NULL){ + errlog(" pc is NULL\n"); + return 0; + } + if( flash_buffer == NULL ){ + errlog("flash_buffer \n"); + return 0; + } + +#if 1 + dbg("pc: "); + for(i=0;i<8;i++){ + dbg("%02x ",pc[i]); + } + dbg("\n"); + + dbg("src: "); + for(i=0;i<8;i++){ + dbg("%02x ", flash_buffer[fb[i]]); + } + dbg("\n"); +#endif + + mdelay(20); + + for(i=0;i<8;i++) + if(pc[i]!= flash_buffer[fb[i]]) + return 0; + return 1; +} + + +/*********************************************************************** + [function]: + callback: send password 1K (ZET6223) + [parameters]: + client[in]: struct i2c_client — represent an I2C slave device; + + [return]: + 1; +************************************************************************/ +u8 zet6221_ts_sndpwd_1k(struct i2c_client *client) +{ + u8 ts_sndpwd_cmd[3] = {0x20,0xB9,0xA3}; + + int ret; + +#if defined(I2C_CTPM_ADDRESS) + ret=i2c_write_interface(client, I2C_CTPM_ADDRESS, ts_sndpwd_cmd, 3); +#else + ret=zet6221_i2c_write_tsdata(client, ts_sndpwd_cmd, 3); +#endif + + + return 1; +} + + +/*********************************************************************** + [function]: + callback: send password; + [parameters]: + client[in]: struct i2c_client ???represent an I2C slave device; + + [return]: + 1; +************************************************************************/ +u8 zet6221_ts_sndpwd(struct i2c_client *client) +{ + u8 ts_sndpwd_cmd[3] = {0x20,0xC5,0x9D}; + + int ret; + +#if defined(I2C_CTPM_ADDRESS) + ret=i2c_write_interface(client, I2C_CTPM_ADDRESS, ts_sndpwd_cmd, 3); +#else + ret=zet6221_i2c_write_tsdata(client, ts_sndpwd_cmd, 3); +#endif + + return 1; +} + +u8 zet622x_ts_option(struct i2c_client *client) +{ + u8 ts_cmd[1] = {0x27}; + u8 ts_cmd_erase[1] = {0x28}; + u8 ts_in_data[16] = {0}; + u8 ts_out_data[18] = {0}; + int ret; + u16 model; + int i; + u8 high_impendence_data = 0; + const u8 HIGH_IMPENDENCE_MODE_DATA = 0xf1; + const u8 NOT_HIGH_IMPENDENCE_MODE_DATA = 0xf2; + + + dbg("zet622x_ts_option++\n"); + + wmt_rst_output(0); + msleep(10); + //send password + zet6221_ts_sndpwd(client); + msleep(100); + + + +#if defined(I2C_CTPM_ADDRESS) + ret=i2c_write_interface(client, I2C_CTPM_ADDRESS, ts_cmd, dim(ts_cmd)); +#else + ret=zet6221_i2c_write_tsdata(client, ts_cmd, dim(ts_cmd)); +#endif + msleep(2); + + +#if defined(I2C_CTPM_ADDRESS) + ret=i2c_read_interface(client, I2C_CTPM_ADDRESS, ts_in_data, dim(ts_in_data)); +#else + ret=zet6221_i2c_read_tsdata(client, ts_in_data, dim(ts_in_data)); +#endif + //msleep(2); + + dbg("command %02x recv:\n",ts_cmd[0]); + for(i=0;i<16;i++) + { + dbg("%02x ",ts_in_data[i]); + } + dbg("\n"); + // zet6231 recv: ff ff fc 30 ff 80 31 62 ff ff ff ff ff ff ff ff + + model = 0x0; + model = ts_in_data[7]; + model = (model << 8) | ts_in_data[6]; + + switch(model) { + case 0xFFFF: + ret = 1; + ic_model = ZET6221; + for(i=0;i<8;i++) + { + fb[i]=fb21[i]; + } + + if( is_high_impendence_mode() == HIGH_IMPENDENCE_MODE ){ + high_impendence_data = HIGH_IMPENDENCE_MODE_DATA; + }else if( is_high_impendence_mode() == NOT_HIGH_IMPENDENCE_MODE ) { + high_impendence_data = NOT_HIGH_IMPENDENCE_MODE_DATA; + } + + //#if defined(High_Impendence_Mode) + if(ts_in_data[2] != high_impendence_data) + { + + if(zet6221_ts_sfr(client)==0) + { + return 0; + } + + #if defined(I2C_CTPM_ADDRESS) + ret=i2c_write_interface(client, I2C_CTPM_ADDRESS, ts_cmd_erase, dim(ts_cmd_erase)); + #else + ret=zet6221_i2c_write_tsdata(client, ts_cmd_erase, dim(ts_cmd_erase)); + #endif + + msleep(100); + dbg("erase ret=%d \n",ret); + + + for(i=2;i<18;i++) + { + ts_out_data[i]=ts_in_data[i-2]; + } + ts_out_data[0] = 0x21; + ts_out_data[1] = 0xc5; + ts_out_data[4] = high_impendence_data; + + #if defined(I2C_CTPM_ADDRESS) + ret=i2c_write_interface(client, I2C_CTPM_ADDRESS, ts_out_data, 18); + #else + ret=zet6221_i2c_write_tsdata(client, ts_out_data, 18); + #endif + + msleep(100); + dbg("write out data, ret=%d\n",ret); + + + + #if defined(I2C_CTPM_ADDRESS) + ret=i2c_write_interface(client, I2C_CTPM_ADDRESS, ts_cmd, 1); + #else + ret=zet6221_i2c_write_tsdata(client, ts_cmd, 1); + #endif + + msleep(2); + + dbg("send %02x\n",ts_cmd[0]); + + + #if defined(I2C_CTPM_ADDRESS) + ret=i2c_read_interface(client, I2C_CTPM_ADDRESS, ts_in_data, 16); + #else + ret=zet6221_i2c_read_tsdata(client, ts_in_data, 16); + #endif + //msleep(2); + dbg("command %02x recv:\n",ts_cmd[0]); + for(i=0;i<16;i++) + { + dbg("%02x ",ts_in_data[i]); + } + dbg("\n"); + + } + + //#endif + + + + break; + case 0x6223: + ret = 1; + ic_model = ZET6223; + for(i=0;i<8;i++) + { + fb[i]=fb23[i]; + } + break; + case 0x6231: + ret = 1; + ic_model = ZET6231; + for(i=0;i<8;i++) + { + fb[i]=fb23[i]; + } + break; + case 0x6251: + ic_model = ZET6251; + for(i=0;i<8;i++) + { + fb[i] = fb23[i]; + } + break; + default: + errlog("Notice: can't detect the TP IC,use ZET6231 default\n"); + ret = 1; + ic_model = ZET6231; + for(i=0;i<8;i++) + { + fb[i]=fb23[i]; + } + break; + + } + + wmt_rst_output(1); + msleep(10); + + dbg("zet622x_ts_option-- ret:%d\n",ret); + return ret; +} +/*********************************************************************** + [function]: + callback: set/check sfr information; + [parameters]: + client[in]: struct i2c_client ???represent an I2C slave device; + + [return]: + 1; +************************************************************************/ +u8 zet6221_ts_sfr(struct i2c_client *client) +{ + u8 ts_cmd[1] = {0x2C}; + u8 ts_in_data[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + u8 ts_cmd17[17] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + //u8 ts_sfr_data[16] = {0x18,0x76,0x27,0x27,0xFF,0x03,0x8E,0x14,0x00,0x38,0x82,0xEC,0x00,0x00,0x7d,0x03}; + int ret; + int i; + + dbg("zet6221_ts_sfr++"); +#if defined(I2C_CTPM_ADDRESS) + ret=i2c_write_interface(client, I2C_CTPM_ADDRESS, ts_cmd, 1); +#else + ret=zet6221_i2c_write_tsdata(client, ts_cmd, 1); +#endif + msleep(10); + dbg("sfr cmd : 0x%02x \n",ts_cmd[0]); + + + + dbg("sfr rcv : \n"); + +#if defined(I2C_CTPM_ADDRESS) + ret=i2c_read_interface(client, I2C_CTPM_ADDRESS, ts_in_data, 16); +#else + ret=zet6221_i2c_read_tsdata(client, ts_in_data, 16); +#endif + msleep(10); + + if(ts_in_data[14]!=0x3D && ts_in_data[14]!=0x7D) + { + return 0; + } + + for(i=0;i<16;i++) + { + ts_cmd17[i+1]=ts_in_data[i]; + dbg("[%d]%02x\n",i,ts_in_data[i]); + } + + dbg("\n"); + + // need to check 0x3D to open write function + if(ts_in_data[14]!=0x3D) + { + ts_cmd17[15]=0x3D; + + ts_cmd17[0]=0x2B; + +#if defined(I2C_CTPM_ADDRESS) + ret=i2c_write_interface(client, I2C_CTPM_ADDRESS, ts_cmd17, 17); +#else + ret=zet6221_i2c_write_tsdata(client, ts_cmd17, 17); +#endif + + if(ret<0) + { + errlog("enable sfr(0x3D) failed!\n"); + return 0; + } + + } + dbg("zet6221_ts_sfr--"); + return 1; +} + +/*********************************************************************** + [function]: + callback: mass erase flash; + [parameters]: + client[in]: struct i2c_client ???represent an I2C slave device; + + [return]: + 1; +************************************************************************/ +u8 zet6221_ts_masserase(struct i2c_client *client) +{ + u8 ts_cmd[1] = {0x24}; + + int ret; + +#if defined(I2C_CTPM_ADDRESS) + ret=i2c_write_interface(client, I2C_CTPM_ADDRESS, ts_cmd, 1); +#else + ret=zet6221_i2c_write_tsdata(client, ts_cmd, 1); +#endif + + return 1; +} + +/*********************************************************************** + [function]: + callback: erase flash by page; + [parameters]: + client[in]: struct i2c_client ???represent an I2C slave device; + + [return]: + 1; +************************************************************************/ +u8 zet6221_ts_pageerase(struct i2c_client *client,int npage) +{ + u8 ts_cmd[3] = {0x23,0x00,0x00}; + u8 len = 0; + int ret; + + switch(ic_model) + { + case ZET6221: + ts_cmd[1]=npage; + len=2; + break; + case ZET6231: + case ZET6223: + case ZET6251: + ts_cmd[1]=npage & 0xff; + ts_cmd[2]=npage >> 8; + len=3; + break; + default: + ts_cmd[1]=npage & 0xff; + ts_cmd[2]=npage >> 8; + len=3; + break; + } +#if defined(I2C_CTPM_ADDRESS) + ret=i2c_write_interface(client, I2C_CTPM_ADDRESS, ts_cmd, len); +#else + ret=zet6221_i2c_write_tsdata(client, ts_cmd, len); +#endif + msleep(2); + + return 1; +} + +/*********************************************************************** + [function]: + callback: reset mcu; + [parameters]: + client[in]: struct i2c_client ???represent an I2C slave device; + + [return]: + 1; +************************************************************************/ +u8 zet6221_ts_resetmcu(struct i2c_client *client) +{ + u8 ts_cmd[1] = {0x29}; + + int ret; + +#if defined(I2C_CTPM_ADDRESS) + ret=i2c_write_interface(client, I2C_CTPM_ADDRESS, ts_cmd, 1); +#else + ret=zet6221_i2c_write_tsdata(client, ts_cmd, 1); +#endif + + return 1; +} + + +#define CMD_PROG_CHECK_SUM (0x36) +#define CMD_PROG_GET_CHECK_SUM (0x37) +///*********************************************************************** +/// [function]: zet622x_cmd_read_check_sum +/// [parameters]: client, page_id, buf +/// [return]: int +///************************************************************************ +int zet622x_cmd_read_check_sum(struct i2c_client *client, int page_id, u8 * buf) +{ + int ret; + int cmd_len = 3; + + buf[0]= CMD_PROG_CHECK_SUM; + buf[1]= (u8)(page_id) & 0xff; + buf[2]= (u8)(page_id >> 8); + ret=zet6221_i2c_write_tsdata(client, buf, cmd_len); + if(ret<=0) + { + printk("[ZET]: Read check sum fail"); + return ret; + } + + buf[0]= CMD_PROG_GET_CHECK_SUM; + cmd_len = 1; + ret=zet6221_i2c_write_tsdata(client, buf, cmd_len); + if(ret<=0) + { + printk("[ZET]: Read check sum fail"); + return ret; + } + + cmd_len = 1; + ret = zet6221_i2c_read_tsdata(client, buf, cmd_len); + if(ret<=0) + { + printk("[ZET]: Read check sum fail"); + return ret; + } + return 1; +} + + +/*********************************************************************** + [function]: + callback: start HW function; + [parameters]: + client[in]: struct i2c_client ???represent an I2C slave device; + + [return]: + 1; +************************************************************************/ +u8 zet6221_ts_hwcmd(struct i2c_client *client) +{ + u8 ts_cmd[1] = {0xB9}; + + int ret; + +#if defined(I2C_CTPM_ADDRESS) + ret=i2c_write_interface(client, I2C_CTPM_ADDRESS, ts_cmd, 1); +#else + ret=zet6221_i2c_write_tsdata(client, ts_cmd, 1); +#endif + + return 1; +} + +/*********************************************************************** +update FW +************************************************************************/ +int __init zet6221_downloader( struct i2c_client *client ) +{ + int BufLen=0; + int BufPage=0; + int BufIndex=0; + int ret; + int i; + + int nowBufLen=0; + int nowBufPage=0; + int nowBufIndex=0; + int retryCount=0; + int retryTimes = 0; + + int i2cLength=0; + int bufOffset=0; + + dbg("zet6221_downloader++\n"); + +begin_download: + +#if defined(RSTPIN_ENABLE) + //reset mcu + //gpio_direction_output(TS_RST_GPIO, GPIO_LOW); + wmt_rst_output(0); + msleep(5); +#else + zet6221_ts_hwcmd(client); + msleep(200); +#endif + //send password + //send password + ret = zet6221_ts_sndpwd(client); + dbg("zet6221_ts_sndpwd ret=%d\n",ret); + msleep(100); + +/*****compare version*******/ + + //0~3 + memset(zeitec_zet6221_page_in,0x00,131); + switch(ic_model) + { + case ZET6221: + zeitec_zet6221_page_in[0]=0x25; + zeitec_zet6221_page_in[1]=(fb[0] >> 7);//(fb[0]/128); + + i2cLength=2; + break; + case ZET6231: + case ZET6223: + case ZET6251: + default: + zeitec_zet6221_page_in[0]=0x25; + zeitec_zet6221_page_in[1]=(fb[0] >> 7) & 0xff; //(fb[0]/128); + zeitec_zet6221_page_in[2]=(fb[0] >> 7) >> 8; //(fb[0]/128); + + i2cLength=3; + break; + } +#if defined(I2C_CTPM_ADDRESS) + ret=i2c_write_interface(client, I2C_CTPM_ADDRESS, zeitec_zet6221_page_in, i2cLength); +#else + ret=zet6221_i2c_write_tsdata(client, zeitec_zet6221_page_in, i2cLength); + dbg("write_ret =%d, i2caddr=0x%x\n", ret, client->addr); +#endif + msleep(2); + + zeitec_zet6221_page_in[0]=0x0; + zeitec_zet6221_page_in[1]=0x0; + zeitec_zet6221_page_in[2]=0x0; +#if defined(I2C_CTPM_ADDRESS) + ret=i2c_read_interface(client, I2C_CTPM_ADDRESS, zeitec_zet6221_page_in, 128); +#else + ret=zet6221_i2c_read_tsdata(client, zeitec_zet6221_page_in, 128); + dbg("read_ret =%d, i2caddr=0x%x\n", ret, client->addr); +#endif + + //printk("page=%d ",(fb[0] >> 7)); //(fb[0]/128)); + for(i=0;i<4;i++) + { + pc[i]=zeitec_zet6221_page_in[(fb[i] & 0x7f)]; //[(fb[i]%128)]; + dbg("offset[%d]=%d ",i,(fb[i] & 0x7f)); //(fb[i]%128)); + } + dbg("\n"); + + + // 4~7 + memset(zeitec_zet6221_page_in,0x00,131); + switch(ic_model) + { + case ZET6221: + zeitec_zet6221_page_in[0]=0x25; + zeitec_zet6221_page_in[1]=(fb[4] >> 7);//(fb[4]/128); + + i2cLength=2; + break; + case ZET6231: + case ZET6223: + case ZET6251: + zeitec_zet6221_page_in[0]=0x25; + zeitec_zet6221_page_in[1]=(fb[4] >> 7) & 0xff; //(fb[4]/128); + zeitec_zet6221_page_in[2]=(fb[4] >> 7) >> 8; //(fb[4]/128); + + i2cLength=3; + break; + } +#if defined(I2C_CTPM_ADDRESS) + ret=i2c_write_interface(client, I2C_CTPM_ADDRESS, zeitec_zet6221_page_in, i2cLength); +#else + ret=zet6221_i2c_write_tsdata(client, zeitec_zet6221_page_in, i2cLength); + dbg("write_ret =%d, i2caddr=0x%x\n", ret, client->addr); +#endif + + zeitec_zet6221_page_in[0]=0x0; + zeitec_zet6221_page_in[1]=0x0; + zeitec_zet6221_page_in[2]=0x0; +#if defined(I2C_CTPM_ADDRESS) + ret=i2c_read_interface(client, I2C_CTPM_ADDRESS, zeitec_zet6221_page_in, 128); +#else + ret=zet6221_i2c_read_tsdata(client, zeitec_zet6221_page_in, 128); + dbg("read_ret =%d, i2caddr=0x%x\n", ret, client->addr); +#endif + + //printk("page=%d ",(fb[4] >> 7)); //(fb[4]/128)); + for(i=4;i<8;i++) + { + pc[i]=zeitec_zet6221_page_in[(fb[i] & 0x7f)]; //[(fb[i]%128)]; + dbg("offset[%d]=%d ",i,(fb[i] & 0x7f)); //(fb[i]%128)); + } + dbg("\n"); + +#if 1 // need to check + //page 127 + memset(zeitec_zet6221_page_in,0x00,130); + zeitec_zet6221_page_in[0]=0x25; + zeitec_zet6221_page_in[1]=127; +#if defined(I2C_CTPM_ADDRESS) + ret=i2c_write_interface(client, I2C_CTPM_ADDRESS, zeitec_zet6221_page_in, 2); +#else + ret=zet6221_i2c_write_tsdata(client, zeitec_zet6221_page_in, 2); +#endif + + zeitec_zet6221_page_in[0]=0x0; + zeitec_zet6221_page_in[1]=0x0; +#if defined(I2C_CTPM_ADDRESS) + ret=i2c_read_interface(client, I2C_CTPM_ADDRESS, zeitec_zet6221_page_in, 128); +#else + ret=zet6221_i2c_read_tsdata(client, zeitec_zet6221_page_in, 128); +#endif + + for(i=0;i<128;i++) + { + // 0x3F80 = 16256 = 128x127, means skipped the first 127 page (0-126) ,use the page 127. + if(0x3F80+i < l_fwlen/*sizeof(flash_buffer)/sizeof(char)*/) //l_fwlen: the bytes of data read from firmware file + { + if(zeitec_zet6221_page_in[i]!=flash_buffer[0x3F80+i]) + { + errlog("page 127 [%d] doesn't match! continue to download! retry times:%d\n",i,retryTimes); + if( retryTimes++ >= 20){ // retry 20 times ,quit + errlog("May be I2C comunication is error\n"); + goto exit_download; + } + goto proc_sfr; + } + } + } + +#endif + + if( get_download_option() == FORCE_DOWNLOAD ){ + errlog("FORCE_DOWNLOAD\n"); + goto proc_sfr; + } + if( get_download_option() == FORCE_CANCEL_DOWNLOAD ){ + errlog("FORCE_CANCEL_DOWNLOAD\n"); + goto exit_download; + } + if(zet6221_ts_version()!=0){ + klog("tp version is the same,no need to download\n"); + goto exit_download; + } + + + +/*****compare version*******/ +proc_sfr: + //sfr + if(zet6221_ts_sfr(client)==0) + { + +#if 1 + +#if defined(RSTPIN_ENABLE) + + //gpio_direction_output(TS_RST_GPIO, GPIO_HIGH); + wmt_rst_output(1); + msleep(20); + + //gpio_direction_output(TS_RST_GPIO, GPIO_LOW); + wmt_rst_output(0); + msleep(20); + + //gpio_direction_output(TS_RST_GPIO, GPIO_HIGH); + wmt_rst_output(1); +#else + zet6221_ts_resetmcu(client); +#endif + msleep(20); + errlog("zet6221_ts_sfr error, download again\n"); + goto begin_download; + +#endif + + } + msleep(20); + + /// Fix the bug that page#504~#512 failed to write + if(ic_model == ZET6223) + { + zet6221_ts_sndpwd_1k(client); + } + + //erase + if(BufLen==0) + { + //mass erase + dbg( "mass erase\n"); + zet6221_ts_masserase(client); + msleep(200); + + BufLen=l_fwlen;/*sizeof(flash_buffer)/sizeof(char)*/; + }else + { + zet6221_ts_pageerase(client,BufPage); + msleep(200); + } + + + while(BufLen>0) + { +download_page: + + memset(zeitec_zet6221_page,0x00,131); + + klog( "Start: write page%d\n",BufPage); + nowBufIndex=BufIndex; + nowBufLen=BufLen; + nowBufPage=BufPage; + + switch(ic_model) + { + case ZET6221: + bufOffset = 2; + i2cLength=130; + + zeitec_zet6221_page[0]=0x22; + zeitec_zet6221_page[1]=BufPage; + break; + case ZET6231: + case ZET6223: + case ZET6251: + default: + bufOffset = 3; + i2cLength=131; + + zeitec_zet6221_page[0]=0x22; + zeitec_zet6221_page[1]=BufPage & 0xff; + zeitec_zet6221_page[2]=BufPage >> 8; + break; + } + if(BufLen>128) + { + for(i=0;i<128;i++) + { + zeitec_zet6221_page[i+bufOffset]=flash_buffer[BufIndex]; + BufIndex+=1; + } + zeitec_zet6221_page[0]=0x22; + zeitec_zet6221_page[1]=BufPage; + BufLen-=128; + } + else + { + for(i=0;i> 8; + + i2cLength=3; + break; + } +#if defined(I2C_CTPM_ADDRESS) + ret=i2c_write_interface(client, I2C_CTPM_ADDRESS, zeitec_zet6221_page_in, i2cLength); +#else + ret=zet6221_i2c_write_tsdata(client, zeitec_zet6221_page_in, i2cLength); +#endif + msleep(2); + + zeitec_zet6221_page_in[0]=0x0; + zeitec_zet6221_page_in[1]=0x0; + zeitec_zet6221_page_in[2]=0x0; +#if defined(I2C_CTPM_ADDRESS) + ret=i2c_read_interface(client, I2C_CTPM_ADDRESS, zeitec_zet6221_page_in, 128); +#else + ret=zet6221_i2c_read_tsdata(client, zeitec_zet6221_page_in, 128); +#endif + + for(i=0;i<128;i++) + { + if(i < nowBufLen) + { + if(zeitec_zet6221_page[i+bufOffset]!=zeitec_zet6221_page_in[i]) + { + BufIndex=nowBufIndex; + BufLen=nowBufLen; + BufPage=nowBufPage; + + if(retryCount < 5) + { + retryCount++; + goto download_page; + }else + { + //BufIndex=0; + //BufLen=0; + //BufPage=0; + retryCount=0; + +#if defined(RSTPIN_ENABLE) + //gpio_direction_output(TS_RST_GPIO, GPIO_HIGH); + wmt_rst_output(1); + msleep(20); + + //gpio_direction_output(TS_RST_GPIO, GPIO_LOW); + wmt_rst_output(0); + msleep(20); + + //gpio_direction_output(TS_RST_GPIO, GPIO_HIGH); + wmt_rst_output(1); +#else + zet6221_ts_resetmcu(client); +#endif + msleep(20); + goto begin_download; + } + + } + } + } + +#endif + retryCount=0; + BufPage+=1; + } + +exit_download: + +#if defined(RSTPIN_ENABLE) + //gpio_direction_output(TS_RST_GPIO, GPIO_HIGH); + wmt_rst_output(1); + msleep(100); +#endif + + zet6221_ts_resetmcu(client); + msleep(100); + + dbg("zet6221_downloader--\n"); + return 1; + + +} + +int zet622x_resume_downloader(struct i2c_client *client) +{ + int ret = 0; + + int BufLen=0; + int BufPage=0; + int BufIndex=0; + int bufOffset = 0; + + int nowBufLen=0; + int nowBufPage=0; + int nowBufIndex=0; + + int i2cLength = 0; + + int i = 0; + + u8 bPageBuf[256]; + +#ifdef FEATURE_FW_CHECK_SUM + u8 get_check_sum = 0; + u8 check_sum = 0; + int retry_count = 0; + u8 tmp_data[16]; +#endif ///< for FEATURE_FW_CHECK_SUM + + + ///-------------------------------------------------------------/// + /// 1. Set RST=LOW + ///-------------------------------------------------------------/// + wmt_rst_output(0); + msleep(20); + //printk("RST = LOW\n"); + + ///-------------------------------------------------------------/// + /// Send password + ///-------------------------------------------------------------/// + ret = zet6221_ts_sndpwd(client); + if(ret<=0) + { + return ret; + } + + //printk("AAA\n"); + BufLen=l_fwlen;/*sizeof(flash_buffer)/sizeof(char)*/; + //printk("BBB%d\n",BufLen); + + while(BufLen>0) + { + /// memset(zeitec_zet622x_page, 0x00, 131); + nowBufIndex=BufIndex; + nowBufLen=BufLen; + nowBufPage=BufPage; + + switch(ic_model) + { + case ZET6251: + bufOffset = 3; + i2cLength=131; + + bPageBuf[0]=0x22; + bPageBuf[1]=BufPage & 0xff; + bPageBuf[2]=BufPage >> 8; + break; + } + + if(BufLen>128) + { + for(i=0;i<128;i++) + { + bPageBuf[i + bufOffset] = flash_buffer[BufIndex]; + BufIndex += 1; + } + + BufLen = BufLen - 128; + } + else + { + for(i=0;i +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include +#include +#include +#include +#include +#include + +#include +#include "wmt_ts.h" +#include +#include "../../../video/backlight/wmt_bl.h" + + +//fw update. +//#include "zet6221_fw.h" + +/* -------------- global variable definition -----------*/ +#define _MACH_MSM_TOUCH_H_ + +#define ZET_TS_ID_NAME "zet6221-ts" + +#define MJ5_TS_NAME "touch_zet6221" + +//#define TS_INT_GPIO S3C64XX_GPN(9) /*s3c6410*/ +//#define TS1_INT_GPIO AT91_PIN_PB17 /*AT91SAM9G45 external*/ +//#define TS1_INT_GPIO AT91_PIN_PA27 /*AT91SAM9G45 internal*/ +//#define TS_RST_GPIO S3C64XX_GPN(10) + +//#define MT_TYPE_B + +#define TS_RST_GPIO +#define X_MAX 800 //1024 +#define Y_MAX 480 //576 +#define FINGER_NUMBER 5 +#define KEY_NUMBER 3 //0 +//#define P_MAX 1 +#define P_MAX 255 //modify 2013-1-1 +#define D_POLLING_TIME 25000 +#define U_POLLING_TIME 25000 +#define S_POLLING_TIME 100 +#define REPORT_POLLING_TIME 3 +#define RETRY_DOWNLOAD_TIMES 2 + +#define MAX_KEY_NUMBER 8 +#define MAX_FINGER_NUMBER 16 +#define TRUE 1 +#define FALSE 0 + +//#define debug_mode 1 +//#define DPRINTK(fmt,args...) do { if (debug_mode) printk(KERN_EMERG "[%s][%d] "fmt"\n", __FUNCTION__, __LINE__, ##args);} while(0) + +//#define TRANSLATE_ENABLE 1 +#define TOPRIGHT 0 +#define TOPLEFT 1 +#define BOTTOMRIGHT 2 +#define BOTTOMLEFT 3 +#define ORIGIN BOTTOMRIGHT + +#define TIME_CHECK_CHARGE 3000 + +#define I2C_MAJOR 126 +#define I2C_MINORS 256 + + +///=============================================================================================/// +/// IOCTL control Definition +///=============================================================================================/// +#define ZET_IOCTL_CMD_FLASH_READ (20) +#define ZET_IOCTL_CMD_FLASH_WRITE (21) +#define ZET_IOCTL_CMD_RST (22) +#define ZET_IOCTL_CMD_RST_HIGH (23) +#define ZET_IOCTL_CMD_RST_LOW (24) + +#define ZET_IOCTL_CMD_DYNAMIC (25) + +#define ZET_IOCTL_CMD_FW_FILE_PATH_GET (26) +#define ZET_IOCTL_CMD_FW_FILE_PATH_SET (27) + +#define ZET_IOCTL_CMD_MDEV (28) +#define ZET_IOCTL_CMD_MDEV_GET (29) + +#define ZET_IOCTL_CMD_TRAN_TYPE_PATH_GET (30) +#define ZET_IOCTL_CMD_TRAN_TYPE_PATH_SET (31) + +#define ZET_IOCTL_CMD_IDEV (32) +#define ZET_IOCTL_CMD_IDEV_GET (33) + +#define ZET_IOCTL_CMD_MBASE (34) +#define ZET_IOCTL_CMD_MBASE_GET (35) + +#define ZET_IOCTL_CMD_INFO_SET (36) +#define ZET_IOCTL_CMD_INFO_GET (37) + +#define ZET_IOCTL_CMD_TRACE_X_SET (38) +#define ZET_IOCTL_CMD_TRACE_X_GET (39) + +#define ZET_IOCTL_CMD_TRACE_Y_SET (40) +#define ZET_IOCTL_CMD_TRACE_Y_GET (41) + +#define ZET_IOCTL_CMD_IBASE (42) +#define ZET_IOCTL_CMD_IBASE_GET (43) + +#define ZET_IOCTL_CMD_DRIVER_VER_GET (44) +#define ZET_IOCTL_CMD_MBASE_EXTERN_GET (45) + +#define IOCTL_MAX_BUF_SIZE (1024) + +///----------------------------------------------------/// +/// IOCTL ACTION +///----------------------------------------------------/// +#define IOCTL_ACTION_NONE (0) +#define IOCTL_ACTION_FLASH_DUMP (1<<0) + +static int ioctl_action = IOCTL_ACTION_NONE; + +///=============================================================================================/// +/// Transfer type +///=============================================================================================/// +#define TRAN_TYPE_DYNAMIC (0x00) +#define TRAN_TYPE_MUTUAL_SCAN_BASE (0x01) +#define TRAN_TYPE_MUTUAL_SCAN_DEV (0x02) +#define TRAN_TYPE_INIT_SCAN_BASE (0x03) +#define TRAN_TYPE_INIT_SCAN_DEV (0x04) +#define TRAN_TYPE_KEY_MUTUAL_SCAN_BASE (0x05) +#define TRAN_TYPE_KEY_MUTUAL_SCAN_DEV (0x06) +#define TRAN_TYPE_KEY_DATA (0x07) +#define TRAN_TYPE_MTK_TYPE (0x0A) +#define TRAN_TYPE_FOCAL_TYPE (0x0B) + +///=============================================================================================/// +/// TP Trace +///=============================================================================================/// +#define TP_DEFAULT_ROW (10) +#define TP_DEFAULT_COL (15) + +#define DRIVER_VERSION "$Revision: 44 $" +//static char const *revision="$Revision: 44 $"; + +///=============================================================================================/// +/// Macro Definition +///=============================================================================================/// +#define MAX_FLASH_BUF_SIZE (0x10000) + +///---------------------------------------------------------------------------------/// +/// 18. IOCTRL Debug +///---------------------------------------------------------------------------------/// +#define FEATURE_IDEV_OUT_ENABLE +#define FEATURE_MBASE_OUT_ENABLE +#define FEATURE_MDEV_OUT_ENABLE +#define FEATURE_INFO_OUT_EANBLE +#define FEATURE_IBASE_OUT_ENABLE + + + +///-------------------------------------/// +/// firmware save / load +///-------------------------------------/// +u32 data_offset = 0; +struct inode *inode = NULL; +mm_segment_t old_fs; + +char driver_version[128]; + +//#define FW_FILE_NAME "/vendor/modules/zet62xx.bin" +char fw_file_name[128]; +///-------------------------------------/// +/// Transmit Type Mode Path parameters +///-------------------------------------/// +/// External SD-Card could be +/// "/mnt/sdcard/" +/// "/mnt/extsd/" +///-------------------------------------/// + +// It should be the path where adb tools can push files in +#define TRAN_MODE_FILE_PATH "/data/local/tmp/" +char tran_type_mode_file_name[128]; +u8 *tran_data = NULL; + +///-------------------------------------/// +/// Mutual Dev Mode parameters +///-------------------------------------/// +/// External SD-Card could be +/// "/mnt/sdcard/zetmdev" +/// "/mnt/extsd/zetmdev" +///-------------------------------------/// +#ifdef FEATURE_MDEV_OUT_ENABLE + #define MDEV_FILE_NAME "zetmdev" + #define MDEV_MAX_FILE_ID (10) + #define MDEV_MAX_DATA_SIZE (2048) +///-------------------------------------/// +/// mutual dev variables +///-------------------------------------/// + u8 *mdev_data = NULL; + int mdev_file_id = 0; +#endif ///< FEATURE_MDEV_OUT_ENABLE + +///-------------------------------------/// +/// Initial Base Mode parameters +///-------------------------------------/// +/// External SD-Card could be +/// "/mnt/sdcard/zetibase" +/// "/mnt/extsd/zetibase" +///-------------------------------------/// +#ifdef FEATURE_IBASE_OUT_ENABLE + #define IBASE_FILE_NAME "zetibase" + #define IBASE_MAX_FILE_ID (10) + #define IBASE_MAX_DATA_SIZE (512) + +///-------------------------------------/// +/// initial base variables +///-------------------------------------/// + u8 *ibase_data = NULL; + int ibase_file_id = 0; +#endif ///< FEATURE_IBASE_OUT_ENABLE + +///-------------------------------------/// +/// Initial Dev Mode parameters +///-------------------------------------/// +/// External SD-Card could be +/// "/mnt/sdcard/zetidev" +/// "/mnt/extsd/zetidev" +///-------------------------------------/// +#ifdef FEATURE_IDEV_OUT_ENABLE + #define IDEV_FILE_NAME "zetidev" + #define IDEV_MAX_FILE_ID (10) + #define IDEV_MAX_DATA_SIZE (512) + +///-------------------------------------/// +/// initial dev variables +///-------------------------------------/// + u8 *idev_data = NULL; + int idev_file_id = 0; +#endif ///< FEATURE_IDEV_OUT_ENABLE + +///-------------------------------------/// +/// Mutual Base Mode parameters +///-------------------------------------/// +/// External SD-Card could be +/// "/mnt/sdcard/zetmbase" +/// "/mnt/extsd/zetmbase" +///-------------------------------------/// +#ifdef FEATURE_MBASE_OUT_ENABLE + #define MBASE_FILE_NAME "zetmbase" + #define MBASE_MAX_FILE_ID (10) + #define MBASE_MAX_DATA_SIZE (2048) + +///-------------------------------------/// +/// mutual base variables +///-------------------------------------/// + u8 *mbase_data = NULL; + int mbase_file_id = 0; +#endif ///< FEATURE_MBASE_OUT_ENABLE + +///-------------------------------------/// +/// infomation variables +///-------------------------------------/// +#ifdef FEATURE_INFO_OUT_EANBLE + #define INFO_MAX_DATA_SIZE (64) + #define INFO_DATA_SIZE (17) + #define ZET6221_INFO (0x00) + #define ZET6231_INFO (0x0B) + #define ZET6223_INFO (0x0D) + #define ZET6251_INFO (0x0C) + #define UNKNOW_INFO (0xFF) + u8 *info_data = NULL; +#endif ///< FEATURE_INFO_OUT_EANBLE +///-------------------------------------/// +/// Default transfer type +///-------------------------------------/// +u8 transfer_type = TRAN_TYPE_DYNAMIC; + +///-------------------------------------/// +/// Default TP TRACE +///-------------------------------------/// +int row = TP_DEFAULT_ROW; +int col = TP_DEFAULT_COL; + +struct msm_ts_platform_data { + unsigned int x_max; + unsigned int y_max; + unsigned int pressure_max; +}; + +struct zet6221_tsdrv { + struct i2c_client *i2c_ts; + struct work_struct work1; + struct input_dev *input; + struct timer_list polling_timer; + struct delayed_work work; // for polling + struct workqueue_struct *queue; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif + unsigned int gpio; /* GPIO used for interrupt of TS1*/ + unsigned int irq; + unsigned int x_max; + unsigned int y_max; + unsigned int pressure_max; +}; + +struct i2c_dev +{ + struct list_head list; + struct i2c_adapter *adap; + struct device *dev; +}; + +static struct i2c_dev *zet_i2c_dev; +static struct class *i2c_dev_class; +static LIST_HEAD (i2c_dev_list); +static DEFINE_SPINLOCK(i2c_dev_list_lock); + +struct zet6221_tsdrv * l_ts = NULL; +static int l_suspend = 0; // 1:suspend, 0:normal state + +//static int resetCount = 0; //albert++ 20120807 + + +//static u16 polling_time = S_POLLING_TIME; + +static int l_powermode = -1; +static struct mutex i2c_mutex; +static struct wake_lock downloadWakeLock; + + +//static int __devinit zet6221_ts_probe(struct i2c_client *client, const struct i2c_device_id *id); +//static int __devexit zet6221_ts_remove(struct i2c_client *dev); +extern int register_bl_notifier(struct notifier_block *nb); + +extern int unregister_bl_notifier(struct notifier_block *nb); + +extern int zet6221_downloader( struct i2c_client *client/*, unsigned short ver, unsigned char * data */); +extern int zet622x_resume_downloader(struct i2c_client *client); +extern u8 zet6221_ts_version(void); +extern u8 zet6221_ts_get_report_mode_t(struct i2c_client *client); +extern u8 zet622x_ts_option(struct i2c_client *client); +extern int zet6221_load_fw(void); +extern int zet6221_free_fwmem(void); + +void zet6221_ts_charger_mode_disable(void); +void zet6221_ts_charger_mode(void); +static int zet_fw_size(void); +static void zet_fw_save(char *file_name); +static void zet_fw_load(char *file_name); +static void zet_fw_init(void); +#ifdef FEATURE_MDEV_OUT_ENABLE +static void zet_mdev_save(char *file_name); +#endif ///< FEATURE_MDEV_OUT_ENABLE +#ifdef FEATURE_IDEV_OUT_ENABLE +static void zet_idev_save(char *file_name); +#endif ///< FEATURE_IDEV_OUT_ENABLE +#ifdef FEATURE_IBASE_OUT_ENABLE +static void zet_ibase_save(char *file_name); +#endif ///< FEATURE_IBASE_OUT_ENABLE +#ifdef FEATURE_MBASE_OUT_ENABLE +static void zet_mbase_save(char *file_name); +#endif ///< FEATURE_MBASE_OUT_ENABLE +static void zet_information_save(char *file_name); + +static struct task_struct *resume_download_task; + + + +//static int filterCount = 0; +//static u32 filterX[MAX_FINGER_NUMBER][2], filterY[MAX_FINGER_NUMBER][2]; + +//static u8 key_menu_pressed = 0x1; +//static u8 key_back_pressed = 0x1; +//static u8 key_search_pressed = 0x1; + +static u16 ResolutionX=X_MAX; +static u16 ResolutionY=Y_MAX; +static u16 FingerNum=0; +static u16 KeyNum=0; +static int bufLength=0; +static u8 xyExchange=0; +static u16 inChargerMode = 0; +static struct i2c_client *this_client; +struct workqueue_struct *ts_wq = NULL; +static int l_tskey[4][2] = { + {KEY_BACK,0}, + {KEY_MENU,0}, + {KEY_HOME,0}, + {KEY_SEARCH,0}, +}; + +u8 pc[8]; +// {IC Model, FW Version, FW version,Codebase Type=0x08, Customer ID, Project ID, Config Board No, Config Serial No} + +//Touch Screen +/*static const struct i2c_device_id zet6221_ts_idtable[] = { + { ZET_TS_ID_NAME, 0 }, + { } +}; + +static struct i2c_driver zet6221_ts_driver = { + .driver = { + .owner = THIS_MODULE, + .name = ZET_TS_ID_NAME, + }, + .probe = zet6221_ts_probe, + .remove = __devexit_p(zet6221_ts_remove), + .id_table = zet6221_ts_idtable, +}; +*/ + +void zet6221_set_tskey(int index,int key) +{ + l_tskey[index][0] = key; +} + + +void check_charger(void) +{ + mutex_lock(&i2c_mutex); + if (!wmt_charger_is_dc_plugin()) + { + klog("disable_mode\n"); + zet6221_ts_charger_mode_disable(); + } else { + klog("charge mode\n"); + zet6221_ts_charger_mode(); + } + mutex_unlock(&i2c_mutex); + l_powermode = wmt_charger_is_dc_plugin(); +} + + +void check_charger_polling(void) +{ + if(l_suspend == 1) + { + return; + } + + if (wmt_charger_is_dc_plugin() != l_powermode) + { + check_charger(); + } + + ///-------------------------------------------------------------------/// + /// IOCTL Action + ///-------------------------------------------------------------------/// + if(ioctl_action & IOCTL_ACTION_FLASH_DUMP) + { + printk("[ZET]: IOCTL_ACTION: Dump flash\n"); + zet_fw_save(fw_file_name); + ioctl_action &= ~IOCTL_ACTION_FLASH_DUMP; + } + + return; +} + + + +//extern unsigned int wmt_bat_is_batterypower(void); +/*********************************************************************** + [function]: + callback: Timer Function if there is no interrupt fuction; + [parameters]: + arg[in]: arguments; + [return]: + NULL; +************************************************************************/ + +static void polling_timer_func(struct work_struct *work) +{ + struct zet6221_tsdrv *ts = l_ts; + //schedule_work(&ts->work1); + //queue_work(ts_wq,&ts->work1); + //dbg("check mode!\n"); +/* + if (wmt_bat_is_batterypower() != l_powermode) + { + mutex_lock(&i2c_mutex); + if (wmt_bat_is_batterypower()) + { + klog("disable_mode\n"); + zet6221_ts_charger_mode_disable(); + } else { + klog("charge mode\n"); + zet6221_ts_charger_mode(); + } + mutex_unlock(&i2c_mutex); + l_powermode = wmt_bat_is_batterypower(); + } +*/ + + check_charger_polling(); + queue_delayed_work(ts->queue, &ts->work, msecs_to_jiffies(TIME_CHECK_CHARGE)); + + + //mod_timer(&ts->polling_timer,jiffies + msecs_to_jiffies(TIME_CHECK_CHARGE)); +} + + + +///********************************************************************** +/// [function]: zet622x_i2c_get_free_dev +/// [parameters]: adap +/// [return]: void +///********************************************************************** +static struct i2c_dev *zet622x_i2c_get_free_dev(struct i2c_adapter *adap) +{ + struct i2c_dev *i2c_dev; + + if (adap->nr >= I2C_MINORS) + { + printk("[ZET] : i2c-dev:out of device minors (%d) \n",adap->nr); + return ERR_PTR (-ENODEV); + } + + i2c_dev = kzalloc(sizeof(*i2c_dev), GFP_KERNEL); + if (!i2c_dev) + { + return ERR_PTR(-ENOMEM); + } + i2c_dev->adap = adap; + + spin_lock(&i2c_dev_list_lock); + list_add_tail(&i2c_dev->list, &i2c_dev_list); + spin_unlock(&i2c_dev_list_lock); + + return i2c_dev; +} + +///********************************************************************** +/// [function]: zet622x_i2c_dev_get_by_minor +/// [parameters]: index +/// [return]: i2c_dev +///********************************************************************** +static struct i2c_dev *zet622x_i2c_dev_get_by_minor(unsigned index) +{ + struct i2c_dev *i2c_dev; + spin_lock(&i2c_dev_list_lock); + + list_for_each_entry(i2c_dev, &i2c_dev_list, list) + { + printk(" [ZET] : line = %d ,i2c_dev->adapt->nr = %d,index = %d.\n",__LINE__,i2c_dev->adap->nr,index); + if(i2c_dev->adap->nr == index) + { + goto LABEL_FOUND; + } + } + i2c_dev = NULL; + +LABEL_FOUND: + spin_unlock(&i2c_dev_list_lock); + + return i2c_dev ; +} + + + +//extern int wmt_i2c_xfer_continue_if_4(struct i2c_msg *msg, unsigned int num,int bus_id); +/*********************************************************************** + [function]: + callback: read data by i2c interface; + [parameters]: + client[in]: struct i2c_client â€?represent an I2C slave device; + data [out]: data buffer to read; + length[in]: data length to read; + [return]: + Returns negative errno, else the number of messages executed; +************************************************************************/ +int zet6221_i2c_read_tsdata(struct i2c_client *client, u8 *data, u8 length) +{ + struct i2c_msg msg; + msg.addr = client->addr; + msg.flags = I2C_M_RD; + msg.len = length; + msg.buf = data; + return i2c_transfer(client->adapter,&msg, 1); + + /*int rc = 0; + + memset(data, 0, length); + rc = i2c_master_recv(client, data, length); + if (rc <= 0) + { + errlog("error!\n"); + return -EINVAL; + } else if (rc != length) + { + dbg("want:%d,real:%d\n", length, rc); + } + return rc;*/ +} + +/*********************************************************************** + [function]: + callback: write data by i2c interface; + [parameters]: + client[in]: struct i2c_client â€?represent an I2C slave device; + data [out]: data buffer to write; + length[in]: data length to write; + [return]: + Returns negative errno, else the number of messages executed; +************************************************************************/ +int zet6221_i2c_write_tsdata(struct i2c_client *client, u8 *data, u8 length) +{ + struct i2c_msg msg; + msg.addr = client->addr; + msg.flags = 0; + msg.len = length; + msg.buf = data; + return i2c_transfer(client->adapter,&msg, 1); + + /*int ret = i2c_master_recv(client, data, length); + if (ret <= 0) + { + errlog("error!\n"); + } + return ret; + */ +} + +/*********************************************************************** + [function]: + callback: coordinate traslating; + [parameters]: + px[out]: value of X axis; + py[out]: value of Y axis; + p [in]: pressed of released status of fingers; + [return]: + NULL; +************************************************************************/ +void touch_coordinate_traslating(u32 *px, u32 *py, u8 p) +{ + int i; + u8 pressure; + + #if ORIGIN == TOPRIGHT + for(i=0;i> (MAX_FINGER_NUMBER-i-1)) & 0x1; + if(pressure) + { + px[i] = X_MAX - px[i]; + } + } + #elif ORIGIN == BOTTOMRIGHT + for(i=0;i> (MAX_FINGER_NUMBER-i-1)) & 0x1; + if(pressure) + { + px[i] = X_MAX - px[i]; + py[i] = Y_MAX - py[i]; + } + } + #elif ORIGIN == BOTTOMLEFT + for(i=0;i> (MAX_FINGER_NUMBER-i-1)) & 0x1; + if(pressure) + { + py[i] = Y_MAX - py[i]; + } + } + #endif +} + +/*********************************************************************** + [function]: + callback: reset function; + [parameters]: + void; + [return]: + void; +************************************************************************/ +void ctp_reset(void) +{ +#if defined(TS_RST_GPIO) + //reset mcu + /* gpio_direction_output(TS_RST_GPIO, 1); + msleep(1); + gpio_direction_output(TS_RST_GPIO, 0); + msleep(10); + gpio_direction_output(TS_RST_GPIO, 1); + msleep(20);*/ + wmt_rst_output(1); + msleep(1); + wmt_rst_output(0); + msleep(10); + wmt_rst_output(1); + msleep(5); + dbg("has done\n"); +#else + u8 ts_reset_cmd[1] = {0xb0}; + zet6221_i2c_write_tsdata(this_client, ts_reset_cmd, 1); +#endif + +} + + +///********************************************************************** +/// [function]: zet622x_ts_parse_mutual_dev +/// [parameters]: client +/// [return]: u8 +///********************************************************************** +#ifdef FEATURE_MDEV_OUT_ENABLE +u8 zet622x_ts_parse_mutual_dev(struct i2c_client *client) +{ + int mdev_packet_size = (row+2) * (col + 2); + int ret = 0; + int idx = 0; + int len = mdev_packet_size; + char mdev_file_name_out[128]; + + int step_size = col + 2; + + while(len > 0) + { + if(len < step_size) + { + step_size = len; + } + + ret = zet6221_i2c_read_tsdata(client, &tran_data[idx], step_size); + len -= step_size; + idx += step_size; + } + + sprintf(mdev_file_name_out, "%s%s%02d.bin", tran_type_mode_file_name, MDEV_FILE_NAME, mdev_file_id); + zet_mdev_save(mdev_file_name_out); + mdev_file_id = (mdev_file_id +1)% (MDEV_MAX_FILE_ID); + return ret; +} +#endif ///< FEATURE_MDEV_OUT_ENABLE + +///********************************************************************** +/// [function]: zet622x_ts_parse_initial_base +/// [parameters]: client +/// [return]: u8 +///********************************************************************** +#ifdef FEATURE_IBASE_OUT_ENABLE +u8 zet622x_ts_parse_initial_base(struct i2c_client *client) +{ + int ibase_packet_size = (row + col) * 2; + int ret = 0; + int idx = 0; + int len = ibase_packet_size; + char ibase_file_name_out[128]; + + int step_size = ibase_packet_size; + + while(len > 0) + { + ret = zet6221_i2c_read_tsdata(client, &tran_data[idx], step_size); + len -= step_size; + } + sprintf(ibase_file_name_out, "%s%s%02d.bin", tran_type_mode_file_name, IBASE_FILE_NAME, ibase_file_id); + zet_ibase_save(ibase_file_name_out); + ibase_file_id = (ibase_file_id +1)% (IBASE_MAX_FILE_ID); + return ret; +} +#endif ///< FEATURE_IBASE_OUT_ENABLE + +///********************************************************************** +/// [function]: zet622x_ts_parse_initial_dev +/// [parameters]: client +/// [return]: u8 +///********************************************************************** +#ifdef FEATURE_IDEV_OUT_ENABLE +u8 zet622x_ts_parse_initial_dev(struct i2c_client *client) +{ + int idev_packet_size = (row + col); + int ret = 0; + int idx = 0; + int len = idev_packet_size; + char idev_file_name_out[128]; + + int step_size = idev_packet_size; + + while(len > 0) + { + ret = zet6221_i2c_read_tsdata(client, &tran_data[idx], step_size); + len -= step_size; + } + sprintf(idev_file_name_out, "%s%s%02d.bin", tran_type_mode_file_name, IDEV_FILE_NAME, idev_file_id); + zet_idev_save(idev_file_name_out); + idev_file_id = (idev_file_id +1)% (IDEV_MAX_FILE_ID); + return ret; +} +#endif ///< FEATURE_IDEV_OUT_ENABLE + +///********************************************************************** +/// [function]: zet622x_ts_parse_mutual_base +/// [parameters]: client +/// [return]: u8 +///********************************************************************** +#ifdef FEATURE_MBASE_OUT_ENABLE +u8 zet622x_ts_parse_mutual_base(struct i2c_client *client) +{ + int mbase_packet_size = (row * col * 2); + int ret = 0; + int idx = 0; + int len = mbase_packet_size; + char mbase_file_name_out[128]; + + int step_size = col*2; + + while(len > 0) + { + if(len < step_size) + { + step_size = len; + } + + ret = zet6221_i2c_read_tsdata(client, &tran_data[idx], step_size); + len -= step_size; + idx += step_size; + } + sprintf(mbase_file_name_out, "%s%s%02d.bin",tran_type_mode_file_name, MBASE_FILE_NAME, mbase_file_id); + zet_mbase_save(mbase_file_name_out); + mbase_file_id = (mbase_file_id +1)% (MBASE_MAX_FILE_ID); + return ret; +} +#endif ///< FEATURE_MBASE_OUT_ENABLE + +/*********************************************************************** + [function]: + callback: read finger information from TP; + [parameters]: + client[in]: struct i2c_client â€?represent an I2C slave device; + x[out]: values of X axis; + y[out]: values of Y axis; + z[out]: values of Z axis; + pr[out]: pressed of released status of fingers; + ky[out]: pressed of released status of keys; + [return]: + Packet ID; +************************************************************************/ +u8 zet6221_ts_get_xy_from_panel(struct i2c_client *client, u32 *x, u32 *y, u32 *z, u32 *pr, u32 *ky) +{ + u8 ts_data[70]; + int ret; + int i; + + memset(ts_data,0,70); + + ret=zet6221_i2c_read_tsdata(client, ts_data, bufLength); + + *pr = ts_data[1]; + *pr = (*pr << 8) | ts_data[2]; + + for(i=0;i>4)*256 + (u8)ts_data[(3+4*i)+1]; + y[i]=(u8)((ts_data[3+4*i]) & 0x0f)*256 + (u8)ts_data[(3+4*i)+2]; + z[i]=(u8)((ts_data[(3+4*i)+3]) & 0x0f); + } + + //if key enable + if(KeyNum > 0) + *ky = ts_data[3+4*FingerNum]; + + return ts_data[0]; +} + +/*********************************************************************** + [function]: + callback: get dynamic report information; + [parameters]: + client[in]: struct i2c_client â€?represent an I2C slave device; + + [return]: + 1; +************************************************************************/ +u8 zet6221_ts_get_report_mode(struct i2c_client *client) +{ + u8 ts_report_cmd[1] = {0xb2}; + //u8 ts_reset_cmd[1] = {0xb0}; + u8 ts_in_data[17] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + + int ret; + int i; + int count=0; + + ret=zet6221_i2c_write_tsdata(client, ts_report_cmd, 1); + + if (ret > 0) + { + while(1) + { + msleep(1); + + //if (gpio_get_value(TS_INT_GPIO) == 0) + if (wmt_ts_irqinval() == 0) + { + dbg( "int low\n"); + ret=zet6221_i2c_read_tsdata(client, ts_in_data, 17); + + if(ret > 0) + { + + for(i=0;i<8;i++) + { + pc[i]=ts_in_data[i] & 0xff; + } + + if(pc[3] != 0x08) + { + errlog("=============== zet6221_ts_get_report_mode report error ===============\n"); + return 0; + } + + xyExchange = (ts_in_data[16] & 0x8) >> 3; + if(xyExchange == 1) + { + ResolutionY= ts_in_data[9] & 0xff; + ResolutionY= (ResolutionY << 8)|(ts_in_data[8] & 0xff); + ResolutionX= ts_in_data[11] & 0xff; + ResolutionX= (ResolutionX << 8) | (ts_in_data[10] & 0xff); + } + else + { + ResolutionX = ts_in_data[9] & 0xff; + ResolutionX = (ResolutionX << 8)|(ts_in_data[8] & 0xff); + ResolutionY = ts_in_data[11] & 0xff; + ResolutionY = (ResolutionY << 8) | (ts_in_data[10] & 0xff); + } + + FingerNum = (ts_in_data[15] & 0x7f); + KeyNum = (ts_in_data[15] & 0x80); + + if(KeyNum==0) + bufLength = 3+4*FingerNum; + else + bufLength = 3+4*FingerNum+1; + + //DPRINTK( "bufLength=%d\n",bufLength); + + break; + + }else + { + errlog ("=============== zet6221_ts_get_report_mode read error ===============\n"); + return 0; + } + + }else + { + //DPRINTK( "int high\n"); + if(count++ > 30) + { + errlog ("=============== zet6221_ts_get_report_mode time out ===============\n"); + return 0; + } + + } + } + + } + return 1; +} + +#if 0 +static int zet6221_is_ts(struct i2c_client *client) +{ + /*u8 ts_in_data[17] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + + ctp_reset(); + if (zet6221_i2c_read_tsdata(client, ts_in_data, 17) <= 0) + { + return 0; + } + return 1;*/ + return 1; +} +#endif + +/*********************************************************************** + [function]: + callback: get dynamic report information with timer delay; + [parameters]: + client[in]: struct i2c_client represent an I2C slave device; + + [return]: + 1; +************************************************************************/ + +u8 zet6221_ts_get_report_mode_t(struct i2c_client *client) +{ + u8 ts_report_cmd[1] = {0xb2}; + u8 ts_in_data[17] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + + int ret; + int i; + + ret=zet6221_i2c_write_tsdata(client, ts_report_cmd, 1); + msleep(10); + + dbg("ret=%d,i2c_addr=0x%x\n", ret, client->addr); + if (ret > 0) + { + //mdelay(10); + //msleep(10); + dbg("=============== zet6221_ts_get_report_mode_t ===============\n"); + ret=zet6221_i2c_read_tsdata(client, ts_in_data, 17); + + if(ret > 0) + { + + for(i=0;i<8;i++) + { + pc[i]=ts_in_data[i] & 0xff; + } + + if(pc[3] != 0x08) + { + errlog("=============== zet6221_ts_get_report_mode_t report error ===============\n"); + return 0; + } + + xyExchange = (ts_in_data[16] & 0x8) >> 3; + if(xyExchange == 1) + { + ResolutionY= ts_in_data[9] & 0xff; + ResolutionY= (ResolutionY << 8)|(ts_in_data[8] & 0xff); + ResolutionX= ts_in_data[11] & 0xff; + ResolutionX= (ResolutionX << 8) | (ts_in_data[10] & 0xff); + } + else + { + ResolutionX = ts_in_data[9] & 0xff; + ResolutionX = (ResolutionX << 8)|(ts_in_data[8] & 0xff); + ResolutionY = ts_in_data[11] & 0xff; + ResolutionY = (ResolutionY << 8) | (ts_in_data[10] & 0xff); + } + + FingerNum = (ts_in_data[15] & 0x7f); + KeyNum = (ts_in_data[15] & 0x80); + inChargerMode = (ts_in_data[16] & 0x2) >> 1; + + if(KeyNum==0) + bufLength = 3+4*FingerNum; + else + bufLength = 3+4*FingerNum+1; + + }else + { + errlog ("=============== zet6221_ts_get_report_mode_t READ ERROR ===============\n"); + return 0; + } + + }else + { + errlog("=============== zet6221_ts_get_report_mode_t WRITE ERROR ===============\n"); + return 0; + } + return 1; +} + +/*********************************************************************** + [function]: + callback: interrupt function; + [parameters]: + irq[in]: irq value; + dev_id[in]: dev_id; + + [return]: + NULL; +************************************************************************/ +static irqreturn_t zet6221_ts_interrupt(int irq, void *dev_id) +{ + struct zet6221_tsdrv *ts_drv = dev_id; + int j = 0; + if (wmt_is_tsint()) + { + wmt_clr_int(); + if (wmt_is_tsirq_enable() && l_suspend == 0) + { + wmt_disable_gpirq(); + dbg("begin..\n"); + //if (!work_pending(&l_tsdata.pen_event_work)) + if (wmt_ts_irqinval() == 0) + { + queue_work(ts_wq, &ts_drv->work1); + } else { + if(KeyNum > 0) + { + //if (0 == ky) + { + for (j=0;j<4;j++) + { + if (l_tskey[j][1] != 0) + { + l_tskey[j][1] = 0; + } + } + dbg("finish one key report!\n"); + } + } + wmt_enable_gpirq(); + } + } + return IRQ_HANDLED; + } + + return IRQ_NONE; + + /*//polling_time = D_POLLING_TIME; + + if (gpio_get_value(TS_INT_GPIO) == 0) + { + // IRQ is triggered by FALLING code here + struct zet6221_tsdrv *ts_drv = dev_id; + schedule_work(&ts_drv->work1); + //DPRINTK("TS1_INT_GPIO falling\n"); + }else + { + //DPRINTK("TS1_INT_GPIO raising\n"); + } + + return IRQ_HANDLED;*/ +} + +/*********************************************************************** + [function]: + callback: touch information handler; + [parameters]: + _work[in]: struct work_struct; + + [return]: + NULL; +************************************************************************/ +static void zet6221_ts_work(struct work_struct *_work) +{ + u32 x[MAX_FINGER_NUMBER], y[MAX_FINGER_NUMBER], z[MAX_FINGER_NUMBER], pr, ky, points; + u32 px,py,pz; + u8 ret; + u8 pressure; + int i,j; + int tx,ty; + int xmax,ymax; + int realnum = 0; + struct zet6221_tsdrv *ts = + container_of(_work, struct zet6221_tsdrv, work1); + + struct i2c_client *tsclient1 = ts->i2c_ts; + + if(l_suspend == 1) + { + return; + } + + if (bufLength == 0) + { + wmt_enable_gpirq(); + return; + } + /*if(resetCount == 1) + { + resetCount = 0; + wmt_enable_gpirq(); + return; + }*/ + + //if (gpio_get_value(TS_INT_GPIO) != 0) + if (wmt_ts_irqinval() != 0) + { + /* do not read when IRQ is triggered by RASING*/ + //DPRINTK("INT HIGH\n"); + dbg("INT HIGH....\n"); + wmt_enable_gpirq(); + return; + } + + ///-------------------------------------------/// + /// Transfer Type : Mutual Dev Mode + ///-------------------------------------------/// +#ifdef FEATURE_MDEV_OUT_ENABLE + if(transfer_type == TRAN_TYPE_MUTUAL_SCAN_DEV) + { + zet622x_ts_parse_mutual_dev(tsclient1); + wmt_enable_gpirq(); + return; + } +#endif ///< FEATURE_MDEV_OUT_ENABLE + + ///-------------------------------------------/// + /// Transfer Type : Initial Base Mode + ///-------------------------------------------/// +#ifdef FEATURE_IBASE_OUT_ENABLE + if(transfer_type == TRAN_TYPE_INIT_SCAN_BASE) + { + zet622x_ts_parse_initial_base(tsclient1); + wmt_enable_gpirq(); + return; + } +#endif ///< FEATURE_IBASE_OUT_ENABLE + + ///-------------------------------------------/// + /// Transfer Type : Initial Dev Mode + ///-------------------------------------------/// +#ifdef FEATURE_IDEV_OUT_ENABLE + if(transfer_type == TRAN_TYPE_INIT_SCAN_DEV) + { + zet622x_ts_parse_initial_dev(tsclient1); + wmt_enable_gpirq(); + return; + } +#endif ///< TRAN_TYPE_INIT_SCAN_DEV + + ///-------------------------------------------/// + /// Transfer Type : Mutual Base Mode + ///-------------------------------------------/// +#ifdef FEATURE_MBASE_OUT_ENABLE + if(transfer_type == TRAN_TYPE_MUTUAL_SCAN_BASE) + { + zet622x_ts_parse_mutual_base(tsclient1); + wmt_enable_gpirq(); + return; + } +#endif ///< FEATURE_MBASE_OUT_ENABLE + + mutex_lock(&i2c_mutex); + ret = zet6221_ts_get_xy_from_panel(tsclient1, x, y, z, &pr, &ky); + mutex_unlock(&i2c_mutex); + + if(ret == 0x3C) + { + + dbg( "x1= %d, y1= %d x2= %d, y2= %d [PR] = %d [KY] = %d\n", x[0], y[0], x[1], y[1], pr, ky); + + points = pr; + + #if defined(TRANSLATE_ENABLE) + touch_coordinate_traslating(x, y, points); + #endif + realnum = 0; + + for(i=0;i> (MAX_FINGER_NUMBER-i-1)) & 0x1; + dbg( "valid=%d pressure[%d]= %d x= %d y= %d\n",points , i, pressure,x[i],y[i]); + + if(pressure) + { + px = x[i]; + py = y[i]; + pz = z[i]; + + dbg("raw%d(%d,%d) xaxis:%d ResolutionX:%d ResolutionY:%d\n", i, px, py,wmt_ts_get_xaxis(),ResolutionX,ResolutionY); + + //input_report_abs(ts->input, ABS_MT_TRACKING_ID, i); + //input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, P_MAX); + //input_report_abs(ts->input, ABS_MT_POSITION_X, x[i]); + //input_report_abs(ts->input, ABS_MT_POSITION_Y, y[i]); + if (wmt_ts_get_xaxis() == 0) + { + tx = px; + ty = py; + xmax = ResolutionX; + ymax = ResolutionY; + } else { + tx = py; + ty = px; + xmax = ResolutionY; + ymax = ResolutionX; + } + if (wmt_ts_get_xdir() == -1) + { + tx = xmax - tx; + } + if (wmt_ts_get_ydir() == -1) + { + ty = ymax - ty; + } + //tx = ResolutionY - py; + //ty = px; + dbg("rpt%d(%d,%d)\n", i, tx, ty); + //add for cross finger 2013-1-10 + #ifdef MT_TYPE_B + input_mt_slot(ts->input, i); + input_mt_report_slot_state(ts->input, MT_TOOL_FINGER,true); + #endif + input_report_abs(ts->input, ABS_MT_TRACKING_ID, i); + //input_report_key(ts->input, BTN_TOUCH, 1); + //input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, pz); + //******************************* + + if (wmt_ts_get_lcdexchg()) { + int tmp; + tmp = tx; + tx = ty; + ty = ResolutionY - tmp; + } + + input_report_abs(ts->input, ABS_MT_POSITION_X, tx /*px*/); + input_report_abs(ts->input, ABS_MT_POSITION_Y, ty /*py*/); + + #ifndef MT_TYPE_B + input_mt_sync(ts->input); + #endif + realnum++; + if (wmt_ts_ispenup()) + { + wmt_ts_set_penup(0); + } + + }else + { + //input_report_abs(ts->input, ABS_MT_TRACKING_ID, i); + //input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, 0); + //input_mt_sync(ts->input); + #ifdef MT_TYPE_B + input_mt_slot(ts->input, i); + input_mt_report_slot_state(ts->input, MT_TOOL_FINGER,false); + input_report_abs(ts->input, ABS_MT_TRACKING_ID, -1); + #endif //add cross finger 2013-1-10 + dbg("p%d not pen down\n",i); + } + } + + #ifdef MT_TYPE_B + input_mt_report_pointer_emulation(ts->input, true); + #endif //add finger cross 2013-1-10 + //printk("<<input); + dbg("report one point group\n"); + } else if (!wmt_ts_ispenup()) + {//********here no finger press 2013-1-10 + //add 2013-1-10 cross finger issue! + #ifdef MT_TYPE_B + for(i=0;iinput, i); + input_mt_report_slot_state(ts->input, MT_TOOL_FINGER,false); + input_report_abs(ts->input, ABS_MT_TRACKING_ID, -1); + } + input_mt_report_pointer_emulation(ts->input, true); + #else + //input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, 0); + //input_mt_sync(ts->input); + //input_report_abs(ts->input, ABS_MT_TRACKING_ID, -1); + //input_report_key(ts->input, BTN_TOUCH, 0); + #endif + //********************************** + input_mt_sync(ts->input); + input_sync(ts->input); + dbg("real pen up!\n"); + wmt_ts_set_penup(1); + } + + if(KeyNum > 0) + { + //for(i=0;iinput, l_tskey[i][0], 1); + input_report_key(ts->input, l_tskey[i][0], 0); + input_sync(ts->input); + dbg("report key_%d\n", l_tskey[i][0]); + break; + } + } + + } + } + } + + dbg("normal end...\n"); + }else { + dbg("do nothing!\n"); + if(KeyNum > 0) + { + //if (0 == ky) + { + for (j=0;j<4;j++) + { + if (l_tskey[j][1] != 0) + { + l_tskey[j][1] = 0; + } + } + dbg("finish one key report!\n"); + } + } + } + wmt_enable_gpirq(); + +} + +/*********************************************************************** + [function]: + callback: charger mode enable; + [parameters]: + void + + [return]: + void +************************************************************************/ +void zet6221_ts_charger_mode() +{ + //struct zet6221_tsdrv *zet6221_ts; + u8 ts_write_charge_cmd[1] = {0xb5}; + int ret=0; + ret=zet6221_i2c_write_tsdata(this_client, ts_write_charge_cmd, 1); +} +EXPORT_SYMBOL_GPL(zet6221_ts_charger_mode); + +/*********************************************************************** + [function]: + callback: charger mode disable; + [parameters]: + void + + [return]: + void +************************************************************************/ +void zet6221_ts_charger_mode_disable(void) +{ + //struct zet6221_tsdrv *zet6221_ts; + u8 ts_write_cmd[1] = {0xb6}; + int ret=0; + ret=zet6221_i2c_write_tsdata(this_client, ts_write_cmd, 1); +} +EXPORT_SYMBOL_GPL(zet6221_ts_charger_mode_disable); + + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void ts_early_suspend(struct early_suspend *handler) +{ + //Sleep Mode +/* u8 ts_sleep_cmd[1] = {0xb1}; + int ret=0; + ret=zet6221_i2c_write_tsdata(this_client, ts_sleep_cmd, 1); + return; + */ + wmt_disable_gpirq(); + l_suspend = 1; + //del_timer(&l_ts->polling_timer); + +} + +static void ts_late_resume(struct early_suspend *handler) +{ + resetCount = 1; + //if (l_suspend != 0) + { + //wmt_disable_gpirq(); + //ctp_reset(); + //wmt_set_gpirq(IRQ_TYPE_EDGE_FALLING); + wmt_enable_gpirq(); + l_suspend = 0; + } + //l_powermode = -1; + //mod_timer(&l_ts->polling_timer,jiffies + msecs_to_jiffies(TIME_CHECK_CHARGE)); + +} +#endif +static int zet_ts_suspend(struct platform_device *pdev, pm_message_t state) +{ + wmt_disable_gpirq(); + l_suspend = 1; + return 0; +} + + +/*********************************************************************** + [function]: + resume_download_thread + [parameters]: + arg + + [return]: + int; +************************************************************************/ +int resume_download_thread(void *arg) +{ + char fw_name[64]; + wake_lock(&downloadWakeLock); + sprintf(fw_name, "%szet62xx.bin", tran_type_mode_file_name); + zet_fw_load(fw_name); + //printk("Thread : Enter\n"); +// if((iRomType == ROM_TYPE_SRAM) || +// (iRomType == ROM_TYPE_OTP)) //SRAM,OTP + // { + zet622x_resume_downloader(this_client); + check_charger(); + l_suspend = 0; + //printk("zet622x download OK\n"); + // } + //printk("Thread : Leave\n"); + wake_unlock(&downloadWakeLock); + return 0; +} + +static int zet_ts_resume(struct platform_device *pdev) +{ + wmt_disable_gpirq(); + ctp_reset(); + + if(ic_model == ZET6251) { + //upload bin to flash_buffer, just for debug + resume_download_task = kthread_create(resume_download_thread, NULL , "resume_download"); + if(IS_ERR(resume_download_task)) { + errlog("cread thread failed\n"); + } + wake_up_process(resume_download_task); + } else { + check_charger(); + l_suspend = 0; + } + + wmt_set_gpirq(IRQ_TYPE_EDGE_FALLING); + if (!earlysus_en) + wmt_enable_gpirq(); + + ///--------------------------------------/// + /// Set transfer type to dynamic mode + ///--------------------------------------/// + transfer_type = TRAN_TYPE_DYNAMIC; + + return 0; +} + + +///********************************************************************** +/// [function]: zet622x_ts_set_transfer_type +/// [parameters]: void +/// [return]: void +///********************************************************************** +int zet622x_ts_set_transfer_type(u8 bTransType) +{ + u8 ts_cmd[10] = {0xC1, 0x02, TRAN_TYPE_DYNAMIC, 0x55, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00}; + int ret = 0; + ts_cmd[2] = bTransType; + ret = zet6221_i2c_write_tsdata(this_client, ts_cmd, 10); + return ret; +} + + +///********************************************************************** +/// [function]: zet622x_ts_set_transfer_type +/// [parameters]: void +/// [return]: void +///********************************************************************** +#ifdef FEATURE_INFO_OUT_EANBLE +int zet622x_ts_set_info_type(void) +{ + int ret = 1; + char info_file_name_out[128]; + + /// ic type + switch(ic_model) + { + case ZET6221: + tran_data[0] = ZET6221_INFO; + break; + case ZET6223: + tran_data[0] = ZET6223_INFO; + break; + case ZET6231: + tran_data[0] = ZET6231_INFO; + break; + case ZET6251: + tran_data[0] = ZET6251_INFO; + break; + default: + tran_data[0] = UNKNOW_INFO; + break; + } + + /// resolution + if(xyExchange== 1) + { + tran_data[16] = 0x8; + tran_data[9] = ((ResolutionY >> 8)&0xFF); + tran_data[8] = (ResolutionY &0xFF); + tran_data[11] = ((ResolutionX >> 8)&0xFF); + tran_data[10] = (ResolutionX &0xFF); + } + else + { + tran_data[16] = 0x00; + tran_data[9] = ((ResolutionX >> 8)&0xFF); + tran_data[8] = (ResolutionX &0xFF); + tran_data[11] = ((ResolutionY >> 8)&0xFF); + tran_data[10] = (ResolutionY &0xFF); + } + + /// trace X + tran_data[13] = TP_DEFAULT_COL; ///< trace x + /// trace Y + tran_data[14] = TP_DEFAULT_ROW; ///< trace y + + if(KeyNum > 0) + { + tran_data[15] = (0x80 | FingerNum); + } + else + { + tran_data[15] = FingerNum; + } + + sprintf(info_file_name_out, "%sinfo.bin",tran_type_mode_file_name); + zet_information_save(info_file_name_out); + + printk("[ZET] : ic:%d, traceX:%d, traceY:%d\n", tran_data[0],tran_data[13],tran_data[14]); + return ret; +} +#endif ///< FEATURE_INFO_OUT_EANBLE + +///*********************************************************************** +/// [function]: zet_mdev_save +/// [parameters]: char * +/// [return]: void +///************************************************************************ +static void zet_mdev_save(char *file_name) +{ + struct file *fp; + int data_total_len = (row+2) * (col + 2); + + ///-------------------------------------------------------/// + /// create the file that stores the mutual dev data + ///-------------------------------------------------------/// + fp = filp_open(file_name, O_RDWR | O_CREAT, 0644); + if(IS_ERR(fp)) + { + printk("[ZET] : Failed to open %s\n", file_name); + return; + } + old_fs = get_fs(); + set_fs(KERNEL_DS); + + vfs_write(fp, tran_data, data_total_len, &(fp->f_pos)); + memcpy(mdev_data, tran_data, data_total_len); + set_fs(old_fs); + filp_close(fp, 0); + + return; +} + +///*********************************************************************** +/// [function]: zet_idev_save +/// [parameters]: char * +/// [return]: void +///************************************************************************ +#ifdef FEATURE_IDEV_OUT_ENABLE +static void zet_idev_save(char *file_name) +{ + struct file *fp; + int data_total_len = (row + col); + + ///-------------------------------------------------------/// + /// create the file that stores the initial dev data + ///-------------------------------------------------------/// + fp = filp_open(file_name, O_RDWR | O_CREAT, 0644); + if(IS_ERR(fp)) + { + printk("[ZET] : Failed to open %s\n", file_name); + return; + } + old_fs = get_fs(); + set_fs(KERNEL_DS); + + vfs_write(fp, tran_data, data_total_len, &(fp->f_pos)); + memcpy(idev_data, tran_data, data_total_len); + set_fs(old_fs); + filp_close(fp, 0); + + return; +} +#endif ///< FEATURE_IDEV_OUT_ENABLE + +///*********************************************************************** +/// [function]: zet_ibase_save +/// [parameters]: char * +/// [return]: void +///************************************************************************ +#ifdef FEATURE_IBASE_OUT_ENABLE +static void zet_ibase_save(char *file_name) +{ + struct file *fp; + int data_total_len = (row + col) * 2; + + ///-------------------------------------------------------/// + /// create the file that stores the initial base data + ///-------------------------------------------------------/// + fp = filp_open(file_name, O_RDWR | O_CREAT, 0644); + if(IS_ERR(fp)) + { + printk("[ZET] : Failed to open %s\n", file_name); + return; + } + old_fs = get_fs(); + set_fs(KERNEL_DS); + + vfs_write(fp, tran_data, data_total_len, &(fp->f_pos)); + memcpy(ibase_data, tran_data, data_total_len); + set_fs(old_fs); + filp_close(fp, 0); + + return; +} +#endif ///< FEATURE_IBASE_OUT_ENABLE + +///*********************************************************************** +/// [function]: zet_mbase_save +/// [parameters]: char * +/// [return]: void +///************************************************************************ +#ifdef FEATURE_MBASE_OUT_ENABLE +static void zet_mbase_save(char *file_name) +{ + struct file *fp; + int data_total_len = (row * col * 2); + + ///-------------------------------------------------------/// + /// create the file that stores the mutual base data + ///-------------------------------------------------------/// + fp = filp_open(file_name, O_RDWR | O_CREAT, 0644); + if(IS_ERR(fp)) + { + printk("[ZET] : Failed to open %s\n", file_name); + return; + } + old_fs = get_fs(); + set_fs(KERNEL_DS); + + vfs_write(fp, tran_data, data_total_len, &(fp->f_pos)); + memcpy(mbase_data, tran_data, data_total_len); + set_fs(old_fs); + filp_close(fp, 0); + + return; +} +#endif ///< FEATURE_MBASE_OUT_ENABLE + +///*********************************************************************** +/// [function]: zet_information_save +/// [parameters]: char * +/// [return]: void +///************************************************************************ +#ifdef FEATURE_INFO_OUT_EANBLE +static void zet_information_save(char *file_name) +{ + struct file *fp; + int data_total_len = INFO_DATA_SIZE; + + ///-------------------------------------------------------/// + /// create the file that stores the mutual base data + ///-------------------------------------------------------/// + fp = filp_open(file_name, O_RDWR | O_CREAT, 0644); + if(IS_ERR(fp)) + { + printk("[ZET] : Failed to open %s\n", file_name); + return; + } + old_fs = get_fs(); + set_fs(KERNEL_DS); + + vfs_write(fp, tran_data, data_total_len, &(fp->f_pos)); + memcpy(info_data, tran_data, data_total_len); + set_fs(old_fs); + filp_close(fp, 0); + + return; +} +#endif ///< FEATURE_INFO_OUT_EANBLE + +///************************************************************************ +/// [function]: zet_dv_set_file_name +/// [parameters]: void +/// [return]: void +///************************************************************************ +static void zet_dv_set_file_name(char *file_name) +{ + strcpy(driver_version, file_name); +} + +///************************************************************************ +/// [function]: zet_fw_set_file_name +/// [parameters]: void +/// [return]: void +///************************************************************************ +static void zet_fw_set_file_name(void)//char *file_name) +{ + char fwname[256] = {0}; + wmt_ts_get_firmwname(fwname); + sprintf(fw_file_name,"/system/etc/firmware/%s",fwname); + //strcpy(fw_file_name, file_name); +} + +///************************************************************************ +/// [function]: zet_mdev_set_file_name +/// [parameters]: void +/// [return]: void +///************************************************************************ +static void zet_tran_type_set_file_name(char *file_name) +{ + strcpy(tran_type_mode_file_name, file_name); +} + + +///*********************************************************************** +/// [function]: zet_fw_size +/// [parameters]: void +/// [return]: void +///************************************************************************ +static int zet_fw_size(void) +{ + int flash_total_len = 0x8000; + + switch(ic_model) + { + case ZET6221: + flash_total_len = 0x4000; + break; + case ZET6223: + flash_total_len = 0x10000; + break; + case ZET6231: + case ZET6251: + default: + flash_total_len = 0x8000; + break; + } + + return flash_total_len; +} + + +///*********************************************************************** +/// [function]: zet_fw_save +/// [parameters]: file name +/// [return]: void +///************************************************************************ +static void zet_fw_save(char *file_name) +{ + struct file *fp; + int flash_total_len = 0; + + fp = filp_open(file_name, O_RDWR | O_CREAT, 0644); + if(IS_ERR(fp)) + { + printk("[ZET] : Failed to open %s\n", file_name); + return; + } + old_fs = get_fs(); + set_fs(KERNEL_DS); + + flash_total_len = zet_fw_size(); + printk("[ZET] : flash_total_len = 0x%04x\n",flash_total_len ); + + vfs_write(fp, flash_buffer, flash_total_len, &(fp->f_pos)); + + set_fs(old_fs); + + filp_close(fp, 0); + + + return; +} + +///*********************************************************************** +/// [function]: zet_fw_load +/// [parameters]: file name +/// [return]: void +///************************************************************************ +static void zet_fw_load(char *file_name) +{ + int file_length = 0; + struct file *fp; + loff_t *pos; + + //printk("[ZET]: find %s\n", file_name); + fp = filp_open(file_name, O_RDONLY, 0644); + if(IS_ERR(fp)) + { + //printk("[ZET]: No firmware file detected\n"); + return; + } + + ///----------------------------/// + /// Load from file + ///----------------------------/// + printk("[ZET]: Load from %s\n", file_name); + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + /// Get file size + inode = fp->f_dentry->d_inode; + file_length = (int)inode->i_size; + //l_fwlen = file_length; + + pos = &(fp->f_pos); + + vfs_read(fp, &flash_buffer[0], file_length, pos); + + //file_length + set_fs(old_fs); + filp_close(fp, 0); + + +} + +///************************************************************************ +/// [function]: zet_fw_init +/// [parameters]: void +/// [return]: void +///************************************************************************ +static void zet_fw_init(void) +{ + //int i; + + if(flash_buffer == NULL) + { + flash_buffer = kmalloc(MAX_FLASH_BUF_SIZE, GFP_KERNEL); + } + + ///---------------------------------------------/// + /// Init the mutual dev buffer + ///---------------------------------------------/// + if(mdev_data== NULL) + { + mdev_data = kmalloc(MDEV_MAX_DATA_SIZE, GFP_KERNEL); + } + if(idev_data== NULL) + { + idev_data = kmalloc(IDEV_MAX_DATA_SIZE, GFP_KERNEL); + } + + if(mbase_data== NULL) + { + mbase_data = kmalloc(MBASE_MAX_DATA_SIZE, GFP_KERNEL); + } + if(ibase_data== NULL) + { + ibase_data = kmalloc(IBASE_MAX_DATA_SIZE, GFP_KERNEL); + } + + if(tran_data == NULL) + { + tran_data = kmalloc(MBASE_MAX_DATA_SIZE, GFP_KERNEL); + } + + if(info_data == NULL) + { + info_data = kmalloc(INFO_MAX_DATA_SIZE, GFP_KERNEL); + } + + /*printk("[ZET]: Load from header\n"); + + if(ic_model == ZET6221) + { + for(i = 0 ; i < sizeof(zeitec_zet6221_firmware) ; i++) + { + flash_buffer[i] = zeitec_zet6221_firmware[i]; + } + } + else if(ic_model == ZET6223) + { + for(i = 0 ; i < sizeof(zeitec_zet6223_firmware) ; i++) + { + flash_buffer[i] = zeitec_zet6223_firmware[i]; + } + } + else if(ic_model == ZET6231) + { + for(i = 0 ; i < sizeof(zeitec_zet6231_firmware) ; i++) + { + flash_buffer[i] = zeitec_zet6231_firmware[i]; + } + } + else if(ic_model == ZET6251) + { + for(i = 0 ; i < sizeof(zeitec_zet6251_firmware) ; i++) + { + flash_buffer[i] = zeitec_zet6251_firmware[i]; + } + } + + /// Load firmware from bin file + zet_fw_load(fw_file_name);*/ +} + +///************************************************************************ +/// [function]: zet_fw_exit +/// [parameters]: void +/// [return]: void +///************************************************************************ +static void zet_fw_exit(void) +{ + ///---------------------------------------------/// + /// free mdev_data + ///---------------------------------------------/// + if(mdev_data!=NULL) + { + kfree(mdev_data); + mdev_data = NULL; + } + + if(idev_data!=NULL) + { + kfree(idev_data); + idev_data = NULL; + } + + if(mbase_data!=NULL) + { + kfree(mbase_data); + mbase_data = NULL; + } + + if(ibase_data!=NULL) + { + kfree(ibase_data); + ibase_data = NULL; + } + + if(tran_data != NULL) + { + kfree(tran_data); + tran_data = NULL; + } + + if(info_data != NULL) + { + kfree(info_data); + info_data = NULL; + } + + + ///---------------------------------------------/// + /// free flash buffer + ///---------------------------------------------/// + if(flash_buffer!=NULL) + { + kfree(flash_buffer); + flash_buffer = NULL; +} + +} + +///************************************************************************ +/// [function]: zet_fops_open +/// [parameters]: file +/// [return]: int +///************************************************************************ +static int zet_fops_open(struct inode *inode, struct file *file) +{ + int subminor; + int ret = 0; + struct i2c_client *client; + struct i2c_adapter *adapter; + struct i2c_dev *i2c_dev; + + subminor = iminor(inode); + printk("[ZET] : ZET_FOPS_OPEN , subminor=%d\n",subminor); + + i2c_dev = zet622x_i2c_dev_get_by_minor(subminor); + if (!i2c_dev) + { + printk("error i2c_dev\n"); + return -ENODEV; + } + + adapter = i2c_get_adapter(i2c_dev->adap->nr); + if(!adapter) + { + return -ENODEV; + } + + client = kzalloc(sizeof(*client), GFP_KERNEL); + + if(!client) + { + i2c_put_adapter(adapter); + ret = -ENOMEM; + } + snprintf(client->name, I2C_NAME_SIZE, "pctp_i2c_ts%d", adapter->nr); + //client->driver = &zet622x_i2c_driver; + client->driver = this_client->driver; + client->adapter = adapter; + file->private_data = client; + + return 0; +} + + +///************************************************************************ +/// [function]: zet_fops_release +/// [parameters]: inode, file +/// [return]: int +///************************************************************************ +static int zet_fops_release (struct inode *inode, struct file *file) +{ + struct i2c_client *client = file->private_data; + + printk("[ZET] : zet_fops_release -> line : %d\n",__LINE__ ); + + i2c_put_adapter(client->adapter); + kfree(client); + file->private_data = NULL; + return 0; +} + +///************************************************************************ +/// [function]: zet_fops_read +/// [parameters]: file, buf, count, ppos +/// [return]: size_t +///************************************************************************ +static ssize_t zet_fops_read(struct file *file, char __user *buf, size_t count, + loff_t *ppos) +{ + int i; + int iCnt = 0; + char str[256]; + int len = 0; + + printk("[ZET] : zet_fops_read -> line : %d\n",__LINE__ ); + + ///-------------------------------/// + /// Print message + ///-------------------------------/// + sprintf(str, "Please check \"%s\"\n", fw_file_name); + len = strlen(str); + + ///-------------------------------/// + /// if read out + ///-------------------------------/// + if(data_offset >= len) + { + return 0; + } + + for(i = 0 ; i < count-1 ; i++) + { + buf[i] = str[data_offset]; + buf[i+1] = 0; + iCnt++; + data_offset++; + if(data_offset >= len) + { + break; + } + } + + ///-------------------------------/// + /// Save file + ///-------------------------------/// + if(data_offset == len) + { + zet_fw_save(fw_file_name); + } + return iCnt; +} + +///************************************************************************ +/// [function]: zet_fops_write +/// [parameters]: file, buf, count, ppos +/// [return]: size_t +///************************************************************************ +static ssize_t zet_fops_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + printk("[ZET]: zet_fops_write -> %s\n", buf); + data_offset = 0; + return count; +} + +///************************************************************************ +/// [function]: ioctl +/// [parameters]: file , cmd , arg +/// [return]: long +///************************************************************************ +static long zet_fops_ioctl(struct file *file, unsigned int cmd, unsigned long arg ) +{ + u8 __user * user_buf = (u8 __user *) arg; + + u8 buf[IOCTL_MAX_BUF_SIZE]; + int data_size; + + if(copy_from_user(buf, user_buf, IOCTL_MAX_BUF_SIZE)) + { + printk("[ZET]: zet_ioctl: copy_from_user fail\n"); + return 0; + } + + printk("[ZET]: zet_ioctl -> cmd = %d, %02x, %02x\n", cmd, buf[0], buf[1]); + + if(cmd == ZET_IOCTL_CMD_FLASH_READ) + { + printk("[ZET]: zet_ioctl -> ZET_IOCTL_CMD_FLASH_DUMP cmd = %d, file=%s\n", cmd, (char *)buf); + ioctl_action |= IOCTL_ACTION_FLASH_DUMP; + } + else if(cmd == ZET_IOCTL_CMD_FLASH_WRITE) + { + printk("[ZET]: zet_ioctl -> ZET_IOCTL_CMD_FLASH_WRITE cmd = %d\n", cmd); + { //upload bin to flash_buffer + char fw_name[64]; + sprintf(fw_name, "%szet62xx.bin", tran_type_mode_file_name); + zet_fw_load(fw_name); + } + zet622x_resume_downloader(this_client); + } + else if(cmd == ZET_IOCTL_CMD_RST) + { + printk("[ZET]: zet_ioctl -> ZET_IOCTL_CMD_RST cmd = %d\n", cmd); + //ctp_reset(); + wmt_rst_output(1); + + wmt_rst_output(0); + msleep(20); + wmt_rst_output(1); + + transfer_type = TRAN_TYPE_DYNAMIC; + } + else if(cmd == ZET_IOCTL_CMD_RST_HIGH) + { + wmt_rst_output(1); + } + else if(cmd == ZET_IOCTL_CMD_RST_LOW) + { + wmt_rst_output(0); + } + else if(cmd == ZET_IOCTL_CMD_MDEV) + { + ///---------------------------------------------------/// + /// set mutual dev mode + ///---------------------------------------------------/// + zet622x_ts_set_transfer_type(TRAN_TYPE_MUTUAL_SCAN_DEV); + transfer_type = TRAN_TYPE_MUTUAL_SCAN_DEV; + + } + else if(cmd == ZET_IOCTL_CMD_IBASE) + { + ///---------------------------------------------------/// + /// set initial base mode + ///---------------------------------------------------/// + zet622x_ts_set_transfer_type(TRAN_TYPE_INIT_SCAN_BASE); + transfer_type = TRAN_TYPE_INIT_SCAN_BASE; + + } +#ifdef FEATURE_IDEV_OUT_ENABLE + else if(cmd == ZET_IOCTL_CMD_IDEV) + { + ///---------------------------------------------------/// + /// set initial dev mode + ///---------------------------------------------------/// + zet622x_ts_set_transfer_type(TRAN_TYPE_INIT_SCAN_DEV); + transfer_type = TRAN_TYPE_INIT_SCAN_DEV; + + } +#endif ///< FEATURE_IDEV_OUT_ENABLE +#ifdef FEATURE_MBASE_OUT_ENABLE + else if(cmd == ZET_IOCTL_CMD_MBASE) + { + ///---------------------------------------------------/// + /// set Mutual Base mode + ///---------------------------------------------------/// + zet622x_ts_set_transfer_type(TRAN_TYPE_MUTUAL_SCAN_BASE); + transfer_type = TRAN_TYPE_MUTUAL_SCAN_BASE; + + } +#endif ///< FEATURE_MBASE_OUT_ENABLE + else if(cmd == ZET_IOCTL_CMD_DYNAMIC) + { + zet622x_ts_set_transfer_type(TRAN_TYPE_DYNAMIC); + transfer_type = TRAN_TYPE_DYNAMIC; + } + else if(cmd == ZET_IOCTL_CMD_FW_FILE_PATH_GET) + { + memset(buf, 0x00, 64); + strcpy(buf, fw_file_name); + printk("[ZET]: zet_ioctl: Get FW_FILE_NAME = %s\n", buf); + } + else if(cmd == ZET_IOCTL_CMD_FW_FILE_PATH_SET) + { + strcpy(fw_file_name, buf); + printk("[ZET]: zet_ioctl: set FW_FILE_NAME = %s\n", buf); + + } + else if(cmd == ZET_IOCTL_CMD_MDEV_GET) + { + data_size = (row+2)*(col+2); + memcpy(buf, mdev_data, data_size); + printk("[ZET]: zet_ioctl: Get MDEV data size=%d\n", data_size); + } + else if(cmd == ZET_IOCTL_CMD_TRAN_TYPE_PATH_SET) + { + strcpy(tran_type_mode_file_name, buf); + printk("[ZET]: zet_ioctl: Set ZET_IOCTL_CMD_TRAN_TYPE_PATH_ = %s\n", buf); + } + else if(cmd == ZET_IOCTL_CMD_TRAN_TYPE_PATH_GET) + { + memset(buf, 0x00, 64); + strcpy(buf, tran_type_mode_file_name); + printk("[ZET]: zet_ioctl: Get ZET_IOCTL_CMD_TRAN_TYPE_PATH = %s\n", buf); + } + else if(cmd == ZET_IOCTL_CMD_IDEV_GET) + { + data_size = (row + col); + memcpy(buf, idev_data, data_size); + printk("[ZET]: zet_ioctl: Get IDEV data size=%d\n", data_size); + } + else if(cmd == ZET_IOCTL_CMD_IBASE_GET) + { + data_size = (row + col)*2; + memcpy(buf, ibase_data, data_size); + printk("[ZET]: zet_ioctl: Get IBASE data size=%d\n", data_size); + } + else if(cmd == ZET_IOCTL_CMD_MBASE_GET) + { + data_size = (row*col*2); + if(data_size > IOCTL_MAX_BUF_SIZE) + { + data_size = IOCTL_MAX_BUF_SIZE; + } + memcpy(buf, mbase_data, data_size); + printk("[ZET]: zet_ioctl: Get MBASE data size=%d\n", data_size); + } + else if(cmd == ZET_IOCTL_CMD_INFO_SET) + { + printk("[ZET]: zet_ioctl: ZET_IOCTL_CMD_INFO_SET\n"); + zet622x_ts_set_info_type(); + } + else if(cmd == ZET_IOCTL_CMD_INFO_GET) + { + data_size = INFO_DATA_SIZE; + memcpy(buf, info_data, data_size); + printk("[ZET]: zet_ioctl: Get INFO data size=%d,IC: %x,X:%d,Y:%d\n", data_size, info_data[0], info_data[13], info_data[14]); + } + else if(cmd == ZET_IOCTL_CMD_TRACE_X_SET) + { + printk("[ZET]: zet_ioctl: ZET_IOCTL_CMD_TRACE_X_SET\n"); + } + else if(cmd == ZET_IOCTL_CMD_TRACE_X_GET) + { + printk("[ZET]: zet_ioctl: Get TRACEX data\n"); + } + else if(cmd == ZET_IOCTL_CMD_TRACE_Y_SET) + { + printk("[ZET]: zet_ioctl: ZET_IOCTL_CMD_TRACE_Y_SET\n"); + } + else if(cmd == ZET_IOCTL_CMD_TRACE_Y_GET) + { + printk("[ZET]: zet_ioctl: Get TRACEY data \n"); + } + else if(cmd == ZET_IOCTL_CMD_DRIVER_VER_GET) + { + memset(buf, 0x00, 64); + strcpy(buf, driver_version); + printk("[ZET]: zet_ioctl: Get DRIVER_VERSION = %s\n", buf); + printk("[ZET]: zet_ioctl: Get SVN = %s\n", DRIVER_VERSION); + } + else if(cmd == ZET_IOCTL_CMD_MBASE_EXTERN_GET) + { + data_size = (row*col*2) - IOCTL_MAX_BUF_SIZE; + if(data_size < 1) + { + data_size = 1; + } + memcpy(buf, (mbase_data+IOCTL_MAX_BUF_SIZE), data_size); + printk("[ZET]: zet_ioctl: Get MBASE extern data size=%d\n", data_size); + } + + if(copy_to_user(user_buf, buf, IOCTL_MAX_BUF_SIZE)) + { + printk("[ZET]: zet_ioctl: copy_to_user fail\n"); + return 0; + } + + return 0; +} + +///************************************************************************ +/// file_operations +///************************************************************************ +static const struct file_operations zet622x_ts_fops = +{ + .owner = THIS_MODULE, + .open = zet_fops_open, + .read = zet_fops_read, + .write = zet_fops_write, + .unlocked_ioctl = zet_fops_ioctl, + .compat_ioctl = zet_fops_ioctl, + .release = zet_fops_release, +}; + +static int zet6221_ts_probe(struct i2c_client *client/*, const struct i2c_device_id *id*/) +{ + int result = -1; + int count = 0; + int download_count = 0; + int download_ok = 0; + struct input_dev *input_dev; + struct device *dev; + + + struct zet6221_tsdrv *zet6221_ts; + + dbg( "[TS] zet6221_ts_probe \n"); + + zet6221_ts = kzalloc(sizeof(struct zet6221_tsdrv), GFP_KERNEL); + l_ts = zet6221_ts; + zet6221_ts->i2c_ts = client; + //zet6221_ts->gpio = TS_INT_GPIO; /*s3c6410*/ + //zet6221_ts->gpio = TS1_INT_GPIO; + + this_client = client; + + i2c_set_clientdata(client, zet6221_ts); + + //client->driver = &zet6221_ts_driver; + ts_wq = create_singlethread_workqueue("zet6221ts_wq"); + if (!ts_wq) + { + errlog("Failed to create workqueue!\n"); + goto err_create_wq; + } + + INIT_WORK(&zet6221_ts->work1, zet6221_ts_work); + + input_dev = input_allocate_device(); + if (!input_dev || !zet6221_ts) { + result = -ENOMEM; + goto fail_alloc_mem; + } + + //i2c_set_clientdata(client, zet6221_ts); + + input_dev->name = MJ5_TS_NAME; + input_dev->phys = "zet6221_touch/input0"; + input_dev->id.bustype = BUS_HOST; + input_dev->id.vendor = 0x0001; + input_dev->id.product = 0x0002; + input_dev->id.version = 0x0100; +//bootloader + zet622x_ts_option(client); + msleep(100); + + download_count = 0; + download_ok = 0; + zet_fw_init(); + do{ + if (zet6221_load_fw()) + { + errlog("Can't load the firmware of zet62xx!\n"); + } else { + zet6221_downloader(client); + //ctp_reset(); //cancel it? need to check + } + udelay(100); + + count=0; + do{ + ctp_reset(); + + if(zet6221_ts_get_report_mode_t(client)==0) //get IC info by delay + { + ResolutionX = X_MAX; + ResolutionY = Y_MAX; + FingerNum = FINGER_NUMBER; + KeyNum = KEY_NUMBER; + if(KeyNum==0) + bufLength = 3+4*FingerNum; + else + bufLength = 3+4*FingerNum+1; + errlog("[warning] zet6221_ts_get_report_mode_t report error!!use default value\n"); + }else + { + if(zet6221_ts_version()==1) // zet6221_ts_version() depends on zet6221_downloader() + // cancel download firmware, need to comment it. + { + dbg("get report mode ok!\n"); + download_ok = 1; + } + } + count++; + }while(countevbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + set_bit(INPUT_PROP_DIRECT, input_dev->propbit); + if (wmt_ts_get_lcdexchg()) { + input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, ResolutionX, 0, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, ResolutionY, 0, 0); + } else { + input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, ResolutionY, 0, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, ResolutionX, 0, 0); + } + + set_bit(KEY_BACK, input_dev->keybit); + set_bit(KEY_HOME, input_dev->keybit); + set_bit(KEY_MENU, input_dev->keybit); + + //*******************************add 2013-1-10 + set_bit(ABS_MT_TRACKING_ID, input_dev->absbit); + //set_bit(ABS_MT_TOUCH_MAJOR, input_dev->absbit); + input_set_abs_params(input_dev,ABS_MT_TRACKING_ID, 0, FingerNum, 0, 0); + //input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, P_MAX, 0, 0); + //set_bit(BTN_TOUCH, input_dev->keybit); + + #ifdef MT_TYPE_B + input_mt_init_slots(input_dev, FingerNum); + #endif + //set_bit(KEY_SEARCH, input_dev->keybit); + + //input_dev->evbit[0] = BIT(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + //input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + + result = input_register_device(input_dev); + if (result) + goto fail_ip_reg; + + zet6221_ts->input = input_dev; + + input_set_drvdata(zet6221_ts->input, zet6221_ts); + mutex_init(&i2c_mutex); + wake_lock_init(&downloadWakeLock, WAKE_LOCK_SUSPEND, "resume_download"); + zet6221_ts->queue = create_singlethread_workqueue("ts_check_charge_queue"); + INIT_DELAYED_WORK(&zet6221_ts->work, polling_timer_func); + + //setup_timer(&zet6221_ts->polling_timer, polling_timer_func, (unsigned long)zet6221_ts); + //mod_timer(&zet6221_ts->polling_timer,jiffies + msecs_to_jiffies(TIME_CHECK_CHARGE)); + + + //s3c6410 + //result = gpio_request(zet6221_ts->gpio, "GPN"); + wmt_set_gpirq(IRQ_TYPE_EDGE_FALLING); + wmt_disable_gpirq(); + /*result = gpio_request(zet6221_ts->gpio, "GPN"); + if (result) + goto gpio_request_fail; + */ + + zet6221_ts->irq = wmt_get_tsirqnum();//gpio_to_irq(zet6221_ts->gpio); + dbg( "[TS] zet6221_ts_probe.gpid_to_irq [zet6221_ts->irq=%d]\n",zet6221_ts->irq); + + result = request_irq(zet6221_ts->irq, zet6221_ts_interrupt,IRQF_SHARED /*IRQF_TRIGGER_FALLING*/, + ZET_TS_ID_NAME, zet6221_ts); + if (result) + { + errlog("Can't alloc ts irq=%d\n", zet6221_ts->irq); + goto request_irq_fail; + } + + + ///-----------------------------------------------/// + /// Set the default firmware bin file name & mutual dev file name + ///-----------------------------------------------/// + zet_dv_set_file_name(DRIVER_VERSION); + zet_fw_set_file_name();//FW_FILE_NAME); + zet_tran_type_set_file_name(TRAN_MODE_FILE_PATH); + + ///---------------------------------/// + /// Set file operations + ///---------------------------------/// + result = register_chrdev(I2C_MAJOR, "zet_i2c_ts", &zet622x_ts_fops); + if(result) + { + printk(KERN_ERR "%s:register chrdev failed\n",__FILE__); + goto fail_register_chrdev; + } + ///---------------------------------/// + /// Create device class + ///---------------------------------/// + i2c_dev_class = class_create(THIS_MODULE,"zet_i2c_dev"); + if(IS_ERR(i2c_dev_class)) + { + result = PTR_ERR(i2c_dev_class); + goto fail_create_class; + } + ///--------------------------------------------/// + /// Get a free i2c dev + ///--------------------------------------------/// + zet_i2c_dev = zet622x_i2c_get_free_dev(client->adapter); + if(IS_ERR(zet_i2c_dev)) + { + result = PTR_ERR(zet_i2c_dev); + goto fail_get_free_dev; + } + dev = device_create(i2c_dev_class, &client->adapter->dev, + MKDEV(I2C_MAJOR,client->adapter->nr), NULL, "zet62xx_ts%d", client->adapter->nr); + if(IS_ERR(dev)) + { + result = PTR_ERR(dev); + goto fail_create_device; + } + +#ifdef CONFIG_HAS_EARLYSUSPEND + zet6221_ts->early_suspend.suspend = ts_early_suspend, + zet6221_ts->early_suspend.resume = ts_late_resume, + zet6221_ts->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 1;//,EARLY_SUSPEND_LEVEL_DISABLE_FB + 2; + register_early_suspend(&zet6221_ts->early_suspend); +#endif + //disable_irq(zet6221_ts->irq); + ctp_reset(); + wmt_enable_gpirq(); + queue_delayed_work(zet6221_ts->queue, &zet6221_ts->work, msecs_to_jiffies(TIME_CHECK_CHARGE)); + //mod_timer(&zet6221_ts->polling_timer,jiffies + msecs_to_jiffies(TIME_CHECK_CHARGE)); + dbg("ok\n"); + return 0; + +fail_create_device: + kfree(zet_i2c_dev); +fail_get_free_dev: + class_destroy(i2c_dev_class); +fail_create_class: + unregister_chrdev(I2C_MAJOR, "zet_i2c_ts"); +fail_register_chrdev: + free_irq(zet6221_ts->irq, zet6221_ts); +request_irq_fail: + destroy_workqueue(zet6221_ts->queue); + cancel_delayed_work_sync(&zet6221_ts->work); + //gpio_free(zet6221_ts->gpio); +//gpio_request_fail: + free_irq(zet6221_ts->irq, zet6221_ts); + wake_lock_destroy(&downloadWakeLock); + input_unregister_device(input_dev); + input_dev = NULL; +fail_ip_reg: +fail_alloc_mem: + input_free_device(input_dev); + destroy_workqueue(ts_wq); + cancel_work_sync(&zet6221_ts->work1); + zet_fw_exit(); +err_create_wq: + kfree(zet6221_ts); + return result; +} + +static int zet6221_ts_remove(void /*struct i2c_client *dev*/) +{ + struct zet6221_tsdrv *zet6221_ts = l_ts;//i2c_get_clientdata(dev); + + //del_timer(&zet6221_ts->polling_timer); +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&zet6221_ts->early_suspend); +#endif + wmt_disable_gpirq(); + device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR,this_client->adapter->nr)); + kfree(zet_i2c_dev); + class_destroy(i2c_dev_class); + unregister_chrdev(I2C_MAJOR, "zet_i2c_ts"); + free_irq(zet6221_ts->irq, zet6221_ts); + //gpio_free(zet6221_ts->gpio); + //del_timer_sync(&zet6221_ts->polling_timer); + destroy_workqueue(zet6221_ts->queue); + cancel_delayed_work_sync(&zet6221_ts->work); + input_unregister_device(zet6221_ts->input); + wake_lock_destroy(&downloadWakeLock); + cancel_work_sync(&zet6221_ts->work1); + destroy_workqueue(ts_wq); + zet_fw_exit(); + kfree(zet6221_ts); + + return 0; +} + +static int wmt_wakeup_bl_notify(struct notifier_block *nb, unsigned long event, + void *dummy) +{ + //printk("get notify\n"); + switch (event) { + case BL_CLOSE: + l_suspend = 1; + //printk("\nclose backlight\n\n"); + //printk("disable irq\n\n"); + wmt_disable_gpirq(); + break; + case BL_OPEN: + l_suspend = 0; + //printk("\nopen backlight\n\n"); + //printk("enable irq\n\n"); + wmt_enable_gpirq(); + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block wmt_bl_notify = { + .notifier_call = wmt_wakeup_bl_notify, +}; + +static int zet6221_ts_init(void) +{ + //u8 ts_data[70]; + //int ret; + + /*ctp_reset(); + memset(ts_data,0,70); + ret=zet6221_i2c_read_tsdata(ts_get_i2c_client(), ts_data, 8); + if (ret <= 0) + { + dbg("Can't find zet6221!\n"); + return -1; + } + if (!zet6221_is_ts(ts_get_i2c_client())) + { + dbg("isn't zet6221!\n"); + return -1; + }*/ + if (zet6221_ts_probe(ts_get_i2c_client())) + { + return -1; + } + if (earlysus_en) + register_bl_notifier(&wmt_bl_notify); + //i2c_add_driver(&zet6221_ts_driver); + return 0; +} +//module_init(zet6221_ts_init); + +static void zet6221_ts_exit(void) +{ + zet6221_ts_remove(); + if (earlysus_en) + unregister_bl_notifier(&wmt_bl_notify); + //i2c_del_driver(&zet6221_ts_driver); +} +//module_exit(zet6221_ts_exit); + +void zet6221_set_ts_mode(u8 mode) +{ + dbg( "[Touch Screen]ts mode = %d \n", mode); +} +//EXPORT_SYMBOL_GPL(zet6221_set_ts_mode); + +struct wmtts_device zet6221_tsdev = { + .driver_name = WMT_TS_I2C_NAME, + .ts_id = "ZET62", + .init = zet6221_ts_init, + .exit = zet6221_ts_exit, + .suspend = zet_ts_suspend, + .resume = zet_ts_resume, +}; + + +MODULE_DESCRIPTION("ZET6221 I2C Touch Screen driver"); +MODULE_LICENSE("GPL v2"); diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/zet6221_ts/zet6221_ts.h b/ANDROID_3.4.5/drivers/input/touchscreen/zet6221_ts/zet6221_ts.h new file mode 100755 index 00000000..671bb29d --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/zet6221_ts/zet6221_ts.h @@ -0,0 +1,6 @@ +#ifndef ZET6221_TSH_201010191758 +#define ZET6221_TSH_201010191758 + +extern void zet6221_set_tskey(int index,int key); + +#endif -- cgit