Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- From 503568a576cf00b29eb77c674da1d98da0b1d042 Mon Sep 17 00:00:00 2001
- From: hehao <hehao@xiaomi.com>
- Date: Sat, 30 Sep 2017 17:25:02 +0800
- Subject: [PATCH] Kernel: Xiaomi kernel changes for Xiaomi 6
- The Patch based on QualComm release version: MSM8998.LA.1.1.r1-00232-STD.PROD-3
- The kernel config file used is sagit_user_defconfig
- Change-Id: Ie189e10280cd733e8d8bd403a992adae9a8a2521
- Signed-off-by: hehao <hehao@xiaomi.com>
- ---
- Documentation/devicetree/bindings/gpu/adreno.txt | 3 +
- arch/Kconfig | 7 +
- arch/arm/boot/dts/qcom/Makefile | 34 +-
- .../boot/dts/qcom/batterydata-c1-atl-3350mAh.dtsi | 69 +
- .../boot/dts/qcom/batterydata-c1-sdi-3440mAh.dtsi | 69 +
- .../boot/dts/qcom/batterydata-itech-3020mAh.dtsi | 54 +
- .../dts/qcom/dsi-panel-jdi-fhd-r63452-cmd.dtsi | 272 +
- .../dts/qcom/dsi-panel-lgd-fhd-td4322-cmd.dtsi | 270 +
- .../dts/qcom/dsi-panel-lgd-sw43401-wqhd-cmd.dtsi | 111 +
- arch/arm/boot/dts/qcom/msm-pm8998.dtsi | 6 +-
- arch/arm/boot/dts/qcom/msm-pmi8998.dtsi | 23 +-
- arch/arm/boot/dts/qcom/msm8998-audio.dtsi | 18 -
- arch/arm/boot/dts/qcom/msm8998-blsp.dtsi | 1 -
- .../boot/dts/qcom/msm8998-camera-sensor-cdp.dtsi | 2 +
- .../boot/dts/qcom/msm8998-camera-sensor-mtp.dtsi | 192 +-
- .../boot/dts/qcom/msm8998-camera-sensor-qrd.dtsi | 100 +-
- arch/arm/boot/dts/qcom/msm8998-camera.dtsi | 9 +-
- .../qcom/msm8998-interposer-camera-sensor-mtp.dtsi | 13 +-
- .../qcom/msm8998-interposer-camera-sensor-qrd.dtsi | 13 +-
- arch/arm/boot/dts/qcom/msm8998-mdss-panels.dtsi | 89 +-
- arch/arm/boot/dts/qcom/msm8998-mdss.dtsi | 2 +
- arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi | 284 +-
- arch/arm/boot/dts/qcom/msm8998-pm.dtsi | 1 +
- arch/arm/boot/dts/qcom/msm8998-regulator.dtsi | 35 +-
- arch/arm/boot/dts/qcom/msm8998-v2.dtsi | 8 +-
- arch/arm/boot/dts/qcom/msm8998.dtsi | 53 +-
- .../arm/boot/dts/qcom/sagit-camera-sensor-mtp.dtsi | 478 ++
- arch/arm/boot/dts/qcom/sagit-msm8998-mtp.dts | 39 +
- arch/arm/boot/dts/qcom/sagit-msm8998-mtp.dtsi | 944 +++
- arch/arm/boot/dts/qcom/sagit-msm8998-v2-mtp.dts | 24 +
- arch/arm/boot/dts/qcom/sagit-msm8998-v2.1-mtp.dts | 24 +
- arch/arm64/Kconfig | 15 +
- arch/arm64/configs/msmcortex_defconfig | 2 +-
- arch/arm64/configs/sagit_user_defconfig | 723 ++
- arch/arm64/include/asm/bootinfo.h | 55 +
- arch/arm64/include/asm/hwconf_manager.h | 21 +
- arch/arm64/kernel/Makefile | 2 +
- arch/arm64/kernel/bootinfo.c | 214 +
- arch/arm64/kernel/hwconf_manager.c | 459 ++
- arch/arm64/kernel/process.c | 2 +-
- arch/arm64/kernel/setup.c | 12 +
- drivers/Makefile | 2 +-
- drivers/android/binder.c | 3 +-
- drivers/base/power/wakeup.c | 4 +
- drivers/base/syscore.c | 11 +-
- drivers/block/zram/zram_drv.c | 41 +-
- drivers/bluetooth/btfm_slim.h | 2 +
- drivers/bluetooth/btfm_slim_codec.c | 4 +
- drivers/bluetooth/btfm_slim_wcn3990.c | 13 +-
- drivers/char/diag/diag_masks.c | 2 +
- drivers/clk/msm/clock-debug.c | 2 +-
- drivers/clk/msm/clock-mmss-8998.c | 2 +
- drivers/clk/msm/mdss/mdss-dsi-pll-8998.c | 2 +-
- drivers/elliptic/Makefile | 17 +
- drivers/elliptic/elliptic.c | 716 ++
- drivers/elliptic/elliptic_data_io.h | 100 +
- drivers/elliptic/elliptic_device.h | 54 +
- drivers/elliptic/elliptic_mixer_controls.h | 27 +
- drivers/elliptic/elliptic_sysfs.c | 182 +
- drivers/elliptic/elliptic_sysfs.h | 10 +
- drivers/elliptic/io_modules/Makefile | 2 +
- drivers/elliptic/io_modules/msm/elliptic_data_io.c | 94 +
- drivers/elliptic/io_modules/userspace/Makefile | 2 +
- .../io_modules/userspace/elliptic_data_io.c | 208 +
- .../elliptic/io_modules/userspace_test/Makefile | 2 +
- .../io_modules/userspace_test/elliptic_data_io.c | 126 +
- drivers/firmware/qcom/tz_log.c | 4 +-
- drivers/gpu/msm/kgsl.h | 2 +-
- drivers/gpu/msm/kgsl_pwrctrl.c | 39 +-
- drivers/gpu/msm/kgsl_pwrctrl.h | 3 +
- drivers/hid/usbhid/hiddev.c | 18 +-
- drivers/input/Kconfig | 9 +
- drivers/input/Makefile | 1 +
- drivers/input/evdev.c | 113 +-
- drivers/input/fingerprint/Kconfig | 18 +
- drivers/input/fingerprint/Makefile | 9 +
- drivers/input/fingerprint/fpc1268_tee/Kconfig | 10 +
- drivers/input/fingerprint/fpc1268_tee/Makefile | 1 +
- .../input/fingerprint/fpc1268_tee/fpc1020_tee.c | 633 ++
- drivers/input/fingerprint/goodix/Kconfig | 10 +
- drivers/input/fingerprint/goodix/Makefile | 1 +
- drivers/input/fingerprint/goodix/gf_common.c | 331 +
- drivers/input/fingerprint/goodix/gf_common.h | 27 +
- drivers/input/fingerprint/goodix/gf_spi.c | 986 +++
- drivers/input/fingerprint/goodix/gf_spi.h | 102 +
- drivers/input/fingerprint/goodix/platform.c | 134 +
- drivers/input/fingerprint/goodix_ta/Kconfig | 10 +
- drivers/input/fingerprint/goodix_ta/Makefile | 1 +
- drivers/input/fingerprint/goodix_ta/gf_spi.c | 906 ++
- drivers/input/fingerprint/goodix_ta/gf_spi.h | 155 +
- drivers/input/fingerprint/goodix_ta/netlink.c | 98 +
- drivers/input/fingerprint/goodix_ta/platform.c | 98 +
- drivers/input/input.c | 135 +
- drivers/input/misc/qpnp-power-on.c | 107 +
- drivers/input/touchscreen/Kconfig | 2 +
- drivers/input/touchscreen/Makefile | 3 +
- drivers/input/touchscreen/ft5x46/Kconfig | 52 +
- drivers/input/touchscreen/ft5x46/Makefile | 8 +
- drivers/input/touchscreen/ft5x46/focaltech_test.c | 313 +
- drivers/input/touchscreen/ft5x46/focaltech_test.h | 119 +
- .../touchscreen/ft5x46/focaltech_test_ft5x46.c | 806 ++
- .../touchscreen/ft5x46/focaltech_test_ft5x46.h | 22 +
- drivers/input/touchscreen/ft5x46/ft5x46_ts.c | 3051 +++++++
- drivers/input/touchscreen/ft5x46/ft5x46_ts_i2c.c | 256 +
- drivers/input/touchscreen/ft5x46/ft5x46_ts_spi.c | 133 +
- .../input/touchscreen/synaptics_dsx_force/Kconfig | 124 +
- .../input/touchscreen/synaptics_dsx_force/Makefile | 17 +
- .../synaptics_dsx_force/synaptics_dsx_active_pen.c | 631 ++
- .../synaptics_dsx_force/synaptics_dsx_core.c | 5987 ++++++++++++++
- .../synaptics_dsx_force/synaptics_dsx_core.h | 541 ++
- .../synaptics_dsx_force/synaptics_dsx_fw_update.c | 5486 +++++++++++++
- .../synaptics_dsx_force/synaptics_dsx_gesture.c | 2312 ++++++
- .../synaptics_dsx_force/synaptics_dsx_i2c.c | 901 ++
- .../synaptics_dsx_force/synaptics_dsx_proximity.c | 693 ++
- .../synaptics_dsx_force/synaptics_dsx_rmi_dev.c | 1060 +++
- .../synaptics_dsx_rmi_hid_i2c.c | 1005 +++
- .../synaptics_dsx_force/synaptics_dsx_spi.c | 711 ++
- .../synaptics_dsx_test_reporting.c | 6884 ++++++++++++++++
- .../synaptics_dsx_force/synaptics_dsx_video.c | 417 +
- drivers/irqchip/irq-gic-v3.c | 14 +
- drivers/irqchip/msm_show_resume_irq.c | 2 +-
- drivers/leds/leds-qpnp-flash-v2.c | 34 +-
- drivers/leds/leds-qpnp-wled.c | 11 +-
- drivers/leds/leds-qpnp.c | 30 +
- drivers/md/dm-bufio.c | 14 +-
- .../media/platform/msm/camera_v2/camera/camera.c | 4 +-
- .../platform/msm/camera_v2/common/cam_smmu_api.c | 148 +-
- .../platform/msm/camera_v2/common/cam_smmu_api.h | 27 +-
- .../platform/msm/camera_v2/common/cam_soc_api.c | 9 +-
- .../msm/camera_v2/common/msm_camera_io_util.c | 6 +-
- .../media/platform/msm/camera_v2/isp/msm_buf_mgr.c | 77 +-
- drivers/media/platform/msm/camera_v2/isp/msm_isp.c | 20 +-
- drivers/media/platform/msm/camera_v2/isp/msm_isp.h | 32 +-
- .../media/platform/msm/camera_v2/isp/msm_isp32.c | 2 +-
- .../media/platform/msm/camera_v2/isp/msm_isp40.c | 3 +-
- .../media/platform/msm/camera_v2/isp/msm_isp44.c | 3 +-
- .../media/platform/msm/camera_v2/isp/msm_isp46.c | 3 +-
- .../media/platform/msm/camera_v2/isp/msm_isp47.c | 103 +-
- .../media/platform/msm/camera_v2/isp/msm_isp47.h | 6 +-
- .../media/platform/msm/camera_v2/isp/msm_isp48.c | 1 -
- .../platform/msm/camera_v2/isp/msm_isp_axi_util.c | 272 +-
- .../platform/msm/camera_v2/isp/msm_isp_axi_util.h | 9 +-
- .../msm/camera_v2/isp/msm_isp_stats_util.c | 41 +-
- .../platform/msm/camera_v2/isp/msm_isp_util.c | 155 +-
- .../media/platform/msm/camera_v2/ispif/msm_ispif.c | 16 +-
- .../platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c | 4 +-
- .../msm/camera_v2/jpeg_dma/msm_jpeg_dma_hw.c | 56 +-
- drivers/media/platform/msm/camera_v2/msm.c | 23 +-
- .../camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c | 12 +-
- .../platform/msm/camera_v2/pproc/cpp/msm_cpp.c | 309 +-
- .../platform/msm/camera_v2/pproc/cpp/msm_cpp.h | 12 +-
- .../msm/camera_v2/sensor/actuator/msm_actuator.c | 35 +-
- .../platform/msm/camera_v2/sensor/cci/msm_cci.c | 79 +-
- .../platform/msm/camera_v2/sensor/cci/msm_cci.h | 3 +-
- .../platform/msm/camera_v2/sensor/csid/msm_csid.c | 29 +-
- .../sensor/csiphy/include/msm_csiphy_5_0_1_hwreg.h | 3 +-
- .../sensor/csiphy/include/msm_csiphy_5_0_hwreg.h | 3 +-
- .../msm/camera_v2/sensor/csiphy/msm_csiphy.c | 48 +-
- .../msm/camera_v2/sensor/csiphy/msm_csiphy.h | 3 +-
- .../msm/camera_v2/sensor/eeprom/msm_eeprom.c | 117 +-
- .../msm/camera_v2/sensor/eeprom/msm_eeprom.h | 47 +
- .../msm/camera_v2/sensor/flash/msm_flash.c | 83 +
- .../platform/msm/camera_v2/sensor/msm_sensor.c | 176 +-
- .../msm/camera_v2/sensor/msm_sensor_driver.c | 51 +-
- .../msm/camera_v2/sensor/msm_sensor_init.c | 2 +-
- .../platform/msm/camera_v2/sensor/ois/OIS_coef.h | 497 ++
- .../msm/camera_v2/sensor/ois/OIS_coef_ST.h | 497 ++
- .../platform/msm/camera_v2/sensor/ois/OIS_defi.h | 1115 +++
- .../platform/msm/camera_v2/sensor/ois/OIS_func.c | 640 ++
- .../platform/msm/camera_v2/sensor/ois/OIS_head.h | 150 +
- .../platform/msm/camera_v2/sensor/ois/OIS_prog.h | 4631 +++++++++++
- .../msm/camera_v2/sensor/ois/OIS_prog_ST.h | 4631 +++++++++++
- .../platform/msm/camera_v2/sensor/ois/OIS_user.c | 282 +
- .../platform/msm/camera_v2/sensor/ois/msm_ois.c | 107 +-
- .../platform/msm/camera_v2/sensor/ois/msm_ois.h | 3 +
- drivers/media/rc/Kconfig | 25 +
- drivers/media/rc/Makefile | 4 +
- drivers/media/rc/ir-lirc-codec.c | 47 +-
- drivers/media/rc/lirc_dev.c | 3 +-
- drivers/media/rc/peelir.c | 515 ++
- drivers/media/rc/peelir.h | 81 +
- drivers/media/rc/pwm-ir.c | 391 +
- drivers/media/rc/rc-main.c | 20 +-
- drivers/mfd/Makefile | 1 +
- drivers/mfd/spk-id.c | 209 +
- drivers/misc/qseecom.c | 9 +-
- drivers/nfc/nq-nci.c | 11 +-
- drivers/of/fdt.c | 20 +
- drivers/of/of_batterydata.c | 12 +-
- drivers/pinctrl/qcom/pinctrl-msm.c | 125 +-
- drivers/pinctrl/qcom/pinctrl-msm.h | 1 -
- drivers/platform/msm/Kconfig | 6 +
- drivers/platform/msm/Makefile | 1 +
- drivers/platform/msm/gpio_rf.c | 298 +
- drivers/platform/msm/ipa/ipa_v3/ipa.c | 2 +
- .../platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt.c | 2 +-
- drivers/power/reset/msm-poweroff.c | 35 +-
- drivers/power/supply/qcom/battery.c | 14 +-
- drivers/power/supply/qcom/fg-core.h | 3 +
- drivers/power/supply/qcom/pmic-voter.c | 16 +-
- drivers/power/supply/qcom/qpnp-fg-gen3.c | 207 +-
- drivers/power/supply/qcom/qpnp-smb2.c | 203 +-
- drivers/power/supply/qcom/smb-lib.c | 695 +-
- drivers/power/supply/qcom/smb-lib.h | 34 +-
- drivers/power/supply/qcom/smb-reg.h | 9 +-
- drivers/power/supply/qcom/smb138x-charger.c | 4 +-
- drivers/pwm/core.c | 34 +-
- drivers/rtc/qpnp-rtc.c | 32 +
- drivers/scsi/scsi_lib.c | 11 +-
- drivers/scsi/ufs/ufs-debugfs.c | 158 +-
- drivers/scsi/ufs/ufs.h | 2 +
- drivers/scsi/ufs/ufshcd.c | 12 +
- drivers/scsi/ufs/ufshcd.h | 5 +
- drivers/soc/qcom/Kconfig | 5 +
- drivers/soc/qcom/Makefile | 2 +
- drivers/soc/qcom/avtimer.c | 2 +-
- drivers/soc/qcom/pil-q6v5-mss.c | 43 +-
- drivers/soc/qcom/qdsp6v2/apr.c | 42 +-
- drivers/soc/qcom/qdsp6v2/apr_tal_glink.c | 7 +
- drivers/soc/qcom/qdsp6v2/voice_svc.c | 2 +-
- drivers/soc/qcom/qpnp-haptic.c | 2063 +++--
- drivers/soc/qcom/scm.c | 2 +-
- drivers/soc/qcom/serial_num.c | 121 +
- drivers/soc/qcom/socinfo.c | 32 +
- drivers/soc/qcom/system_stats.c | 46 +
- drivers/soc/qcom/watchdog_v2.c | 32 +-
- drivers/spmi/spmi-pmic-arb.c | 3 +
- drivers/staging/android/Kconfig | 12 +
- drivers/staging/android/Makefile | 1 +
- drivers/staging/android/ion/ion.c | 2 +-
- drivers/staging/android/lowmemorykiller.c | 277 +-
- drivers/staging/android/memsw_state.c | 311 +
- drivers/staging/android/memsw_state.h | 48 +
- drivers/tty/serial/msm_serial.c | 50 +-
- drivers/usb/dwc3/dwc3-msm.c | 10 +-
- drivers/usb/dwc3/ep0.c | 5 +
- drivers/usb/dwc3/gadget.c | 10 +-
- drivers/usb/gadget/composite.c | 7 +-
- drivers/usb/pd/policy_engine.c | 3 +-
- drivers/usb/phy/phy-msm-qusb-v2.c | 16 +
- drivers/video/fbdev/msm/mdss_debug_xlog.c | 12 +-
- drivers/video/fbdev/msm/mdss_dsi.c | 48 +-
- drivers/video/fbdev/msm/mdss_dsi.h | 68 +
- drivers/video/fbdev/msm/mdss_dsi_host.c | 96 +
- drivers/video/fbdev/msm/mdss_dsi_panel.c | 606 +-
- drivers/video/fbdev/msm/mdss_fb.c | 51 +-
- drivers/video/fbdev/msm/mdss_mdp.h | 6 +-
- drivers/video/fbdev/msm/mdss_mdp_layer.c | 6 +-
- drivers/video/fbdev/msm/mdss_mdp_pp.c | 5 +-
- drivers/video/fbdev/msm/mdss_panel.h | 13 +
- firmware/Makefile | 9 +
- firmware/ft5216_biel.fw.ihex | 1245 +++
- firmware/st_fts_biel.ftb.ihex | 6270 ++++++++++++++
- firmware/st_fts_lens.ftb.ihex | 6270 ++++++++++++++
- firmware/st_fts_lg.ftb.ihex | 6126 ++++++++++++++
- firmware/synaptics_jdi_3330_c1.fw.ihex | 8618 +++++++++++++++++++
- firmware/synaptics_jdi_3331_c1.fw.ihex | 8624 ++++++++++++++++++++
- firmware/synaptics_lgd_4322_c1.fw.ihex | 8034 ++++++++++++++++++
- fs/dcache.c | 2 -
- fs/ecryptfs/keystore.c | 12 +-
- fs/eventpoll.c | 14 +-
- fs/f2fs/Kconfig | 6 +
- fs/f2fs/Makefile | 1 +
- fs/f2fs/crypto.c | 24 +-
- fs/f2fs/crypto_key.c | 65 +-
- fs/f2fs/data.c | 4 +-
- fs/f2fs/f2fs.h | 17 +
- fs/f2fs/f2fs_crypto.h | 5 +
- fs/f2fs/f2fs_ice.c | 110 +
- fs/f2fs/f2fs_ice.h | 105 +
- fs/pstore/Kconfig | 8 +
- fs/pstore/inode.c | 40 +
- fs/pstore/ram.c | 68 +
- fs/sdcardfs/main.c | 8 +
- include/linux/cJSON.h | 73 +
- include/linux/cpuset.h | 4 +
- include/linux/hwinfo.h | 18 +
- include/linux/input.h | 23 +
- include/linux/input/ft5x46_ts.h | 199 +
- include/linux/input/qpnp-power-on.h | 19 +
- include/linux/input/synaptics_dsx.h | 166 +
- include/linux/kernel.h | 4 +
- include/linux/mdss_io_util.h | 6 +
- include/linux/mfd/spk-id.h | 32 +
- include/linux/of_fdt.h | 3 +
- include/linux/pwm.h | 3 -
- include/linux/sched.h | 9 +-
- include/linux/zsmalloc.h | 3 +
- include/media/msm_cam_sensor.h | 10 +
- include/media/pwm-ir.h | 26 +
- include/media/rc-core.h | 4 +
- include/media/rc-map.h | 39 +-
- include/soc/qcom/socinfo.h | 9 +
- include/soc/qcom/watchdog.h | 5 +
- include/sound/apr_elliptic.h | 104 +
- include/uapi/media/msm_cam_sensor.h | 12 +
- include/uapi/media/msmb_isp.h | 13 -
- include/uapi/scsi/ufs/ufs.h | 3 +-
- init/Kconfig | 8 +
- kernel/cpuset.c | 40 +
- kernel/irq/pm.c | 15 +
- kernel/locking/spinlock_debug.c | 5 +
- kernel/printk/printk.c | 7 +
- kernel/sched/core.c | 5 +
- kernel/time/alarmtimer.c | 3 +
- lib/Kconfig | 5 +
- lib/Kconfig.debug | 15 +
- lib/Makefile | 2 +
- lib/cJSON.c | 871 ++
- mm/page_alloc.c | 7 +-
- mm/vmscan.c | 7 +
- net/dccp/input.c | 3 +-
- net/ipv4/ip_sockglue.c | 9 +-
- net/packet/af_packet.c | 8 +-
- security/pfe/Makefile | 4 +-
- security/pfe/pfk.c | 18 +-
- security/pfe/pfk_f2fs.c | 190 +
- security/pfe/pfk_f2fs.h | 38 +
- sound/soc/codecs/Kconfig | 11 +
- sound/soc/codecs/Makefile | 5 +
- sound/soc/codecs/tas2559/Makefile | 6 +
- sound/soc/codecs/tas2559/tas2559-codec.c | 1047 +++
- sound/soc/codecs/tas2559/tas2559-codec.h | 30 +
- sound/soc/codecs/tas2559/tas2559-core.c | 2936 +++++++
- sound/soc/codecs/tas2559/tas2559-core.h | 94 +
- sound/soc/codecs/tas2559/tas2559-misc.c | 653 ++
- sound/soc/codecs/tas2559/tas2559-misc.h | 61 +
- sound/soc/codecs/tas2559/tas2559-regmap.c | 1289 +++
- sound/soc/codecs/tas2559/tas2559.h | 527 ++
- sound/soc/codecs/tas2559/tas2560.h | 143 +
- sound/soc/codecs/tas2559/tiload.c | 428 +
- sound/soc/codecs/tas2559/tiload.h | 61 +
- sound/soc/codecs/tfa98xx/Makefile | 36 +
- sound/soc/codecs/tfa98xx/config.h | 141 +
- sound/soc/codecs/tfa98xx/tfa.h | 117 +
- sound/soc/codecs/tfa98xx/tfa1_tfafieldnames.h | 900 ++
- sound/soc/codecs/tfa98xx/tfa2_tfafieldnames_N1C.h | 1522 ++++
- sound/soc/codecs/tfa98xx/tfa9887B_init.c | 77 +
- sound/soc/codecs/tfa98xx/tfa9887_init.c | 57 +
- sound/soc/codecs/tfa98xx/tfa9887_tfafieldnames.h | 60 +
- sound/soc/codecs/tfa98xx/tfa9888_init.c | 188 +
- sound/soc/codecs/tfa98xx/tfa9890_init.c | 181 +
- sound/soc/codecs/tfa98xx/tfa9890_tfafieldnames.h | 76 +
- sound/soc/codecs/tfa98xx/tfa9891_genregs.h | 1125 +++
- sound/soc/codecs/tfa98xx/tfa9891_init.c | 51 +
- sound/soc/codecs/tfa98xx/tfa9891_tfafieldnames.h | 515 ++
- sound/soc/codecs/tfa98xx/tfa9897_init.c | 131 +
- sound/soc/codecs/tfa98xx/tfa98xx.c | 3489 ++++++++
- sound/soc/codecs/tfa98xx/tfa98xx_genregs_N1C.h | 3853 +++++++++
- sound/soc/codecs/tfa98xx/tfa98xx_parameters.h | 754 ++
- sound/soc/codecs/tfa98xx/tfa98xx_tfafieldnames.h | 90 +
- sound/soc/codecs/tfa98xx/tfa_container.c | 2462 ++++++
- sound/soc/codecs/tfa98xx/tfa_container.h | 403 +
- sound/soc/codecs/tfa98xx/tfa_container_crc32.c | 108 +
- sound/soc/codecs/tfa98xx/tfa_debug.c | 286 +
- sound/soc/codecs/tfa98xx/tfa_dsp.c | 3406 ++++++++
- sound/soc/codecs/tfa98xx/tfa_dsp_fw.h | 119 +
- sound/soc/codecs/tfa98xx/tfa_hal.c | 124 +
- sound/soc/codecs/tfa98xx/tfa_internal.h | 108 +
- sound/soc/codecs/tfa98xx/tfa_osal.c | 40 +
- sound/soc/codecs/tfa98xx/tfa_service.h | 1010 +++
- sound/soc/codecs/usb-headset.c | 342 +
- sound/soc/codecs/usb-headset.h | 9 +
- sound/soc/codecs/wcd-mbhc-v2.c | 53 +-
- sound/soc/codecs/wcd9335.c | 8 +-
- sound/soc/msm/Kconfig | 4 +
- sound/soc/msm/msm-dai-fe.c | 5 +-
- sound/soc/msm/msm8998.c | 703 +-
- sound/soc/msm/qdsp6v2/Makefile | 5 +-
- sound/soc/msm/qdsp6v2/apr_elliptic.c | 225 +
- sound/soc/msm/qdsp6v2/msm-elliptic.c | 602 ++
- sound/soc/msm/qdsp6v2/msm-elliptic.h | 12 +
- sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c | 4 +-
- sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c | 6 +
- sound/soc/msm/qdsp6v2/q6adm.c | 2 +-
- sound/soc/msm/qdsp6v2/q6afe.c | 26 +-
- sound/soc/msm/qdsp6v2/q6core.c | 2 +-
- sound/soc/msm/qdsp6v2/q6voice.c | 2 +-
- sound/soc/soc-core.c | 8 +-
- 379 files changed, 138864 insertions(+), 3493 deletions(-)
- create mode 100644 arch/arm/boot/dts/qcom/batterydata-c1-atl-3350mAh.dtsi
- create mode 100644 arch/arm/boot/dts/qcom/batterydata-c1-sdi-3440mAh.dtsi
- create mode 100644 arch/arm/boot/dts/qcom/batterydata-itech-3020mAh.dtsi
- create mode 100644 arch/arm/boot/dts/qcom/dsi-panel-jdi-fhd-r63452-cmd.dtsi
- create mode 100644 arch/arm/boot/dts/qcom/dsi-panel-lgd-fhd-td4322-cmd.dtsi
- create mode 100644 arch/arm/boot/dts/qcom/dsi-panel-lgd-sw43401-wqhd-cmd.dtsi
- create mode 100644 arch/arm/boot/dts/qcom/sagit-camera-sensor-mtp.dtsi
- create mode 100644 arch/arm/boot/dts/qcom/sagit-msm8998-mtp.dts
- create mode 100644 arch/arm/boot/dts/qcom/sagit-msm8998-mtp.dtsi
- create mode 100644 arch/arm/boot/dts/qcom/sagit-msm8998-v2-mtp.dts
- create mode 100644 arch/arm/boot/dts/qcom/sagit-msm8998-v2.1-mtp.dts
- create mode 100644 arch/arm64/configs/sagit_user_defconfig
- create mode 100644 arch/arm64/include/asm/bootinfo.h
- create mode 100644 arch/arm64/include/asm/hwconf_manager.h
- create mode 100644 arch/arm64/kernel/bootinfo.c
- create mode 100644 arch/arm64/kernel/hwconf_manager.c
- create mode 100644 drivers/elliptic/Makefile
- create mode 100644 drivers/elliptic/elliptic.c
- create mode 100644 drivers/elliptic/elliptic_data_io.h
- create mode 100644 drivers/elliptic/elliptic_device.h
- create mode 100644 drivers/elliptic/elliptic_mixer_controls.h
- create mode 100644 drivers/elliptic/elliptic_sysfs.c
- create mode 100644 drivers/elliptic/elliptic_sysfs.h
- create mode 100644 drivers/elliptic/io_modules/Makefile
- create mode 100644 drivers/elliptic/io_modules/msm/elliptic_data_io.c
- create mode 100644 drivers/elliptic/io_modules/userspace/Makefile
- create mode 100644 drivers/elliptic/io_modules/userspace/elliptic_data_io.c
- create mode 100644 drivers/elliptic/io_modules/userspace_test/Makefile
- create mode 100644 drivers/elliptic/io_modules/userspace_test/elliptic_data_io.c
- create mode 100644 drivers/input/fingerprint/Kconfig
- create mode 100644 drivers/input/fingerprint/Makefile
- create mode 100644 drivers/input/fingerprint/fpc1268_tee/Kconfig
- create mode 100644 drivers/input/fingerprint/fpc1268_tee/Makefile
- create mode 100644 drivers/input/fingerprint/fpc1268_tee/fpc1020_tee.c
- create mode 100644 drivers/input/fingerprint/goodix/Kconfig
- create mode 100644 drivers/input/fingerprint/goodix/Makefile
- create mode 100644 drivers/input/fingerprint/goodix/gf_common.c
- create mode 100644 drivers/input/fingerprint/goodix/gf_common.h
- create mode 100644 drivers/input/fingerprint/goodix/gf_spi.c
- create mode 100644 drivers/input/fingerprint/goodix/gf_spi.h
- create mode 100644 drivers/input/fingerprint/goodix/platform.c
- create mode 100644 drivers/input/fingerprint/goodix_ta/Kconfig
- create mode 100644 drivers/input/fingerprint/goodix_ta/Makefile
- create mode 100644 drivers/input/fingerprint/goodix_ta/gf_spi.c
- create mode 100644 drivers/input/fingerprint/goodix_ta/gf_spi.h
- create mode 100644 drivers/input/fingerprint/goodix_ta/netlink.c
- create mode 100644 drivers/input/fingerprint/goodix_ta/platform.c
- create mode 100644 drivers/input/touchscreen/ft5x46/Kconfig
- create mode 100644 drivers/input/touchscreen/ft5x46/Makefile
- create mode 100644 drivers/input/touchscreen/ft5x46/focaltech_test.c
- create mode 100644 drivers/input/touchscreen/ft5x46/focaltech_test.h
- create mode 100644 drivers/input/touchscreen/ft5x46/focaltech_test_ft5x46.c
- create mode 100644 drivers/input/touchscreen/ft5x46/focaltech_test_ft5x46.h
- create mode 100644 drivers/input/touchscreen/ft5x46/ft5x46_ts.c
- create mode 100644 drivers/input/touchscreen/ft5x46/ft5x46_ts_i2c.c
- create mode 100644 drivers/input/touchscreen/ft5x46/ft5x46_ts_spi.c
- create mode 100644 drivers/input/touchscreen/synaptics_dsx_force/Kconfig
- create mode 100644 drivers/input/touchscreen/synaptics_dsx_force/Makefile
- create mode 100644 drivers/input/touchscreen/synaptics_dsx_force/synaptics_dsx_active_pen.c
- create mode 100644 drivers/input/touchscreen/synaptics_dsx_force/synaptics_dsx_core.c
- create mode 100644 drivers/input/touchscreen/synaptics_dsx_force/synaptics_dsx_core.h
- create mode 100644 drivers/input/touchscreen/synaptics_dsx_force/synaptics_dsx_fw_update.c
- create mode 100644 drivers/input/touchscreen/synaptics_dsx_force/synaptics_dsx_gesture.c
- create mode 100644 drivers/input/touchscreen/synaptics_dsx_force/synaptics_dsx_i2c.c
- create mode 100644 drivers/input/touchscreen/synaptics_dsx_force/synaptics_dsx_proximity.c
- create mode 100644 drivers/input/touchscreen/synaptics_dsx_force/synaptics_dsx_rmi_dev.c
- create mode 100644 drivers/input/touchscreen/synaptics_dsx_force/synaptics_dsx_rmi_hid_i2c.c
- create mode 100644 drivers/input/touchscreen/synaptics_dsx_force/synaptics_dsx_spi.c
- create mode 100644 drivers/input/touchscreen/synaptics_dsx_force/synaptics_dsx_test_reporting.c
- create mode 100644 drivers/input/touchscreen/synaptics_dsx_force/synaptics_dsx_video.c
- create mode 100644 drivers/media/platform/msm/camera_v2/sensor/ois/OIS_coef.h
- create mode 100644 drivers/media/platform/msm/camera_v2/sensor/ois/OIS_coef_ST.h
- create mode 100644 drivers/media/platform/msm/camera_v2/sensor/ois/OIS_defi.h
- create mode 100644 drivers/media/platform/msm/camera_v2/sensor/ois/OIS_func.c
- create mode 100644 drivers/media/platform/msm/camera_v2/sensor/ois/OIS_head.h
- create mode 100644 drivers/media/platform/msm/camera_v2/sensor/ois/OIS_prog.h
- create mode 100644 drivers/media/platform/msm/camera_v2/sensor/ois/OIS_prog_ST.h
- create mode 100644 drivers/media/platform/msm/camera_v2/sensor/ois/OIS_user.c
- create mode 100644 drivers/media/rc/peelir.c
- create mode 100644 drivers/media/rc/peelir.h
- create mode 100644 drivers/media/rc/pwm-ir.c
- create mode 100644 drivers/mfd/spk-id.c
- create mode 100644 drivers/platform/msm/gpio_rf.c
- mode change 100644 => 100755 drivers/power/supply/qcom/smb-lib.c
- mode change 100644 => 100755 drivers/power/supply/qcom/smb-lib.h
- mode change 100644 => 100755 drivers/soc/qcom/pil-q6v5-mss.c
- create mode 100644 drivers/soc/qcom/serial_num.c
- create mode 100644 drivers/staging/android/memsw_state.c
- create mode 100644 drivers/staging/android/memsw_state.h
- create mode 100644 firmware/ft5216_biel.fw.ihex
- create mode 100644 firmware/st_fts_biel.ftb.ihex
- create mode 100644 firmware/st_fts_lens.ftb.ihex
- create mode 100644 firmware/st_fts_lg.ftb.ihex
- create mode 100644 firmware/synaptics_jdi_3330_c1.fw.ihex
- create mode 100644 firmware/synaptics_jdi_3331_c1.fw.ihex
- create mode 100644 firmware/synaptics_lgd_4322_c1.fw.ihex
- create mode 100644 fs/f2fs/f2fs_ice.c
- create mode 100644 fs/f2fs/f2fs_ice.h
- create mode 100644 include/linux/cJSON.h
- create mode 100644 include/linux/hwinfo.h
- create mode 100644 include/linux/input/ft5x46_ts.h
- create mode 100644 include/linux/input/synaptics_dsx.h
- create mode 100644 include/linux/mfd/spk-id.h
- create mode 100644 include/media/pwm-ir.h
- create mode 100644 include/sound/apr_elliptic.h
- create mode 100644 lib/cJSON.c
- create mode 100644 security/pfe/pfk_f2fs.c
- create mode 100644 security/pfe/pfk_f2fs.h
- create mode 100644 sound/soc/codecs/tas2559/Makefile
- create mode 100644 sound/soc/codecs/tas2559/tas2559-codec.c
- create mode 100644 sound/soc/codecs/tas2559/tas2559-codec.h
- create mode 100644 sound/soc/codecs/tas2559/tas2559-core.c
- create mode 100644 sound/soc/codecs/tas2559/tas2559-core.h
- create mode 100644 sound/soc/codecs/tas2559/tas2559-misc.c
- create mode 100644 sound/soc/codecs/tas2559/tas2559-misc.h
- create mode 100644 sound/soc/codecs/tas2559/tas2559-regmap.c
- create mode 100644 sound/soc/codecs/tas2559/tas2559.h
- create mode 100644 sound/soc/codecs/tas2559/tas2560.h
- create mode 100644 sound/soc/codecs/tas2559/tiload.c
- create mode 100644 sound/soc/codecs/tas2559/tiload.h
- create mode 100644 sound/soc/codecs/tfa98xx/Makefile
- create mode 100644 sound/soc/codecs/tfa98xx/config.h
- create mode 100644 sound/soc/codecs/tfa98xx/tfa.h
- create mode 100644 sound/soc/codecs/tfa98xx/tfa1_tfafieldnames.h
- create mode 100644 sound/soc/codecs/tfa98xx/tfa2_tfafieldnames_N1C.h
- create mode 100644 sound/soc/codecs/tfa98xx/tfa9887B_init.c
- create mode 100644 sound/soc/codecs/tfa98xx/tfa9887_init.c
- create mode 100644 sound/soc/codecs/tfa98xx/tfa9887_tfafieldnames.h
- create mode 100644 sound/soc/codecs/tfa98xx/tfa9888_init.c
- create mode 100644 sound/soc/codecs/tfa98xx/tfa9890_init.c
- create mode 100644 sound/soc/codecs/tfa98xx/tfa9890_tfafieldnames.h
- create mode 100644 sound/soc/codecs/tfa98xx/tfa9891_genregs.h
- create mode 100644 sound/soc/codecs/tfa98xx/tfa9891_init.c
- create mode 100644 sound/soc/codecs/tfa98xx/tfa9891_tfafieldnames.h
- create mode 100644 sound/soc/codecs/tfa98xx/tfa9897_init.c
- create mode 100644 sound/soc/codecs/tfa98xx/tfa98xx.c
- create mode 100644 sound/soc/codecs/tfa98xx/tfa98xx_genregs_N1C.h
- create mode 100644 sound/soc/codecs/tfa98xx/tfa98xx_parameters.h
- create mode 100644 sound/soc/codecs/tfa98xx/tfa98xx_tfafieldnames.h
- create mode 100644 sound/soc/codecs/tfa98xx/tfa_container.c
- create mode 100644 sound/soc/codecs/tfa98xx/tfa_container.h
- create mode 100644 sound/soc/codecs/tfa98xx/tfa_container_crc32.c
- create mode 100644 sound/soc/codecs/tfa98xx/tfa_debug.c
- create mode 100644 sound/soc/codecs/tfa98xx/tfa_dsp.c
- create mode 100644 sound/soc/codecs/tfa98xx/tfa_dsp_fw.h
- create mode 100644 sound/soc/codecs/tfa98xx/tfa_hal.c
- create mode 100644 sound/soc/codecs/tfa98xx/tfa_internal.h
- create mode 100644 sound/soc/codecs/tfa98xx/tfa_osal.c
- create mode 100644 sound/soc/codecs/tfa98xx/tfa_service.h
- create mode 100644 sound/soc/codecs/usb-headset.c
- create mode 100644 sound/soc/codecs/usb-headset.h
- create mode 100644 sound/soc/msm/qdsp6v2/apr_elliptic.c
- create mode 100644 sound/soc/msm/qdsp6v2/msm-elliptic.c
- create mode 100644 sound/soc/msm/qdsp6v2/msm-elliptic.h
- diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt
- index 1ca89b5..a5ee614 100644
- --- a/Documentation/devicetree/bindings/gpu/adreno.txt
- +++ b/Documentation/devicetree/bindings/gpu/adreno.txt
- @@ -83,6 +83,9 @@ DCVS Core info
- Optional Properties:
- - qcom,initial-powerlevel: This value indicates which qcom,gpu-pwrlevel should be used at start time
- and when coming back out of resume
- +- qcom,restrict-powerlevel: This value to limit max GPU power level jump during the clock switch and
- + while coming back out of slumber. Max GPU power level jump still allowed
- + from the restricted-pwerlevel.
- - qcom,bus-control: Boolean. Enables an independent bus vote from the gpu frequency
- - qcom,bus-width: Bus width in number of bytes. This enables dynamic AB bus voting based on
- bus width and actual bus transactions.
- diff --git a/arch/Kconfig b/arch/Kconfig
- index 98f64ad..2156b1b 100644
- --- a/arch/Kconfig
- +++ b/arch/Kconfig
- @@ -527,6 +527,13 @@ config HAVE_COPY_THREAD_TLS
- normal C parameter passing, rather than extracting the syscall
- argument from pt_regs.
- +config ARCH_HAS_ELF_RANDOMIZE
- + bool
- + help
- + An architecture supports choosing randomized locations for
- + stack, mmap, brk, and ET_DYN. Defined functions:
- + - arch_mmap_rnd()
- +
- config HAVE_ARCH_MMAP_RND_BITS
- bool
- help
- diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile
- index 92e8ec5..1ded211 100644
- --- a/arch/arm/boot/dts/qcom/Makefile
- +++ b/arch/arm/boot/dts/qcom/Makefile
- @@ -102,39 +102,13 @@ dtb-$(CONFIG_ARCH_MSM8996) += msm8996-v2-pmi8994-cdp.dtb \
- apq8096-v3-pmi8996-mdm9x55-slimbus-mtp.dtb \
- apq8096-v3-pmi8996-dragonboard.dtb
- -dtb-$(CONFIG_ARCH_MSM8998) += msm8998-sim.dtb \
- - msm8998-rumi.dtb \
- - msm8998-cdp.dtb \
- - msm8998-mtp.dtb \
- - msm8998-qrd.dtb \
- - msm8998-v2-sim.dtb \
- - msm8998-v2-rumi.dtb \
- +dtb-$(CONFIG_ARCH_MSM8998) += msm8998-mtp.dtb \
- msm8998-v2-mtp.dtb \
- - msm8998-v2-cdp.dtb \
- - msm8998-v2-qrd.dtb \
- - msm8998-qrd-skuk.dtb \
- - msm8998-v2-qrd-skuk.dtb \
- - msm8998-qrd-vr1.dtb \
- - msm8998-v2-qrd-vr1.dtb \
- - msm8998-v2-qrd-skuk-evt3.dtb \
- - msm8998-v2-qrd-skuk-hdk.dtb \
- - apq8998-mtp.dtb \
- - apq8998-cdp.dtb \
- - apq8998-v2-mtp.dtb \
- - apq8998-v2-cdp.dtb \
- - apq8998-v2-qrd.dtb \
- - apq8998-v2-qrd-skuk-hdk.dtb \
- msm8998-v2.1-mtp.dtb \
- msm8998-v2.1-mtp-4k-display.dtb \
- - msm8998-v2.1-cdp.dtb \
- - msm8998-v2.1-qrd.dtb \
- - apq8998-v2.1-mtp.dtb \
- - apq8998-v2.1-cdp.dtb \
- - apq8998-v2.1-qrd.dtb \
- - apq8998-v2.1-mediabox.dtb \
- - msm8998-v2.1-interposer-sdm660-cdp.dtb \
- - msm8998-v2.1-interposer-sdm660-mtp.dtb \
- - msm8998-v2.1-interposer-sdm660-qrd.dtb
- + sagit-msm8998-mtp.dtb \
- + sagit-msm8998-v2-mtp.dtb \
- + sagit-msm8998-v2.1-mtp.dtb
- dtb-$(CONFIG_ARCH_MSMHAMSTER) += msmhamster-rumi.dtb
- diff --git a/arch/arm/boot/dts/qcom/batterydata-c1-atl-3350mAh.dtsi b/arch/arm/boot/dts/qcom/batterydata-c1-atl-3350mAh.dtsi
- new file mode 100644
- index 0000000..dbcdd24
- --- /dev/null
- +++ b/arch/arm/boot/dts/qcom/batterydata-c1-atl-3350mAh.dtsi
- @@ -0,0 +1,69 @@
- +
- +qcom,c1_atl_3350mah {
- + qcom,max-voltage-uv = <4400000>;
- + qcom,nom-batt-capacity-mah = <3350>;
- + qcom,fg-cc-cv-threshold-mv = <4390>;
- + qcom,batt-id-kohm = <68>;
- + qcom,battery-beta = <3435>;
- + qcom,battery-type = "c1_atl";
- + qcom,checksum = <0x23EB>;
- + qcom,gui-version = "PMI8998GUI - 2.0.0.54";
- + qcom,fg-profile-data = [
- + 66 1F B6 05
- + 70 0A 9D FC
- + 73 1D 37 F5
- + 41 12 2B 14
- + BF 18 D7 22
- + AD 45 96 52
- + 57 00 00 00
- + 0F 00 00 00
- + 00 00 8C C4
- + 9C CD 72 CB
- + 22 00 08 00
- + 41 E3 A1 07
- + 4D FD 6F F3
- + 45 E4 8F 12
- + FC 0C 23 33
- + 19 06 09 20
- + 27 00 14 00
- + F9 1F 4E 05
- + A9 0A 27 06
- + 2B 1D 43 01
- + 45 00 99 04
- + 38 19 CA 22
- + 98 45 CF 52
- + 59 00 00 00
- + 0C 00 00 00
- + 00 00 82 CC
- + 20 C2 57 AD
- + 1C 00 00 00
- + 29 F2 A1 07
- + 27 07 A3 EB
- + FB E4 FD 02
- + 59 D5 D2 1A
- + AD 33 CC FF
- + 07 10 00 00
- + 15 0D 66 46
- + 1C 00 40 00
- + 7E 01 0A FA
- + FF 00 00 00
- + 00 00 00 00
- + 00 00 00 00
- + 00 00 00 00
- + 00 00 00 00
- + 00 00 00 00
- + 00 00 00 00
- + 00 00 00 00
- + 00 00 00 00
- + 00 00 00 00
- + 00 00 00 00
- + 00 00 00 00
- + 00 00 00 00
- + 00 00 00 00
- + 00 00 00 00
- + 00 00 00 00
- + 00 00 00 00
- + 00 00 00 00
- + 00 00 00 00
- + ];
- +};
- diff --git a/arch/arm/boot/dts/qcom/batterydata-c1-sdi-3440mAh.dtsi b/arch/arm/boot/dts/qcom/batterydata-c1-sdi-3440mAh.dtsi
- new file mode 100644
- index 0000000..b9664d6
- --- /dev/null
- +++ b/arch/arm/boot/dts/qcom/batterydata-c1-sdi-3440mAh.dtsi
- @@ -0,0 +1,69 @@
- +
- +qcom,c1_sdi_3440mah {
- + qcom,max-voltage-uv = <4400000>;
- + qcom,nom-batt-capacity-mah = <3350>;
- + qcom,fg-cc-cv-threshold-mv = <4390>;
- + qcom,batt-id-kohm = <30>;
- + qcom,battery-beta = <3435>;
- + qcom,battery-type = "c1_sdi";
- + qcom,checksum = <0x623E>;
- + qcom,gui-version = "PMI8998GUI - 2.0.0.54";
- + qcom,fg-profile-data = [
- + A8 1F 68 05
- + B2 0A 09 FC
- + 4F 1D 2C E2
- + 27 0A 46 0C
- + 8A 18 4F 23
- + F7 44 CB 53
- + 5B 00 00 00
- + 0E 00 00 00
- + 00 00 08 B5
- + 30 C4 85 AC
- + 2E 00 08 00
- + 22 00 E1 ED
- + 10 06 79 FA
- + 37 04 EC 03
- + BE E5 33 22
- + 36 06 09 20
- + 27 00 14 00
- + EE 1F 48 05
- + C4 0A F9 05
- + 70 1D E7 D2
- + 4E 0B A9 14
- + EE 19 07 22
- + FC 3C 06 4B
- + 52 00 00 00
- + 13 00 00 00
- + 00 00 C3 CC
- + 41 AA 41 C3
- + 21 00 00 00
- + 66 00 E1 ED
- + F7 06 2A F2
- + F6 F4 FF FA
- + 9B F5 1B 1A
- + 99 33 CC FF
- + 07 10 00 00
- + 1A 0D 66 46
- + 21 00 40 00
- + 6C 01 0A FA
- + FF 00 00 00
- + 00 00 00 00
- + 00 00 00 00
- + 00 00 00 00
- + 00 00 00 00
- + 00 00 00 00
- + 00 00 00 00
- + 00 00 00 00
- + 00 00 00 00
- + 00 00 00 00
- + 00 00 00 00
- + 00 00 00 00
- + 00 00 00 00
- + 00 00 00 00
- + 00 00 00 00
- + 00 00 00 00
- + 00 00 00 00
- + 00 00 00 00
- + 00 00 00 00
- + ];
- +};
- diff --git a/arch/arm/boot/dts/qcom/batterydata-itech-3020mAh.dtsi b/arch/arm/boot/dts/qcom/batterydata-itech-3020mAh.dtsi
- new file mode 100644
- index 0000000..bf5a301
- --- /dev/null
- +++ b/arch/arm/boot/dts/qcom/batterydata-itech-3020mAh.dtsi
- @@ -0,0 +1,54 @@
- +/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
- + * Copyright (C) 2017 XiaoMi, 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.
- + */
- +
- +qcom,itech-3020mah {
- + qcom,max-voltage-uv = <4400000>;
- + qcom,v-cutoff-uv = <3400000>;
- + qcom,chg-term-ua = <100000>;
- + qcom,batt-id-kohm = <150>;
- + qcom,battery-type = "itech_3020mah";
- + qcom,fg-profile-data = [
- + E8 83 0C 7D
- + E9 80 B2 76
- + 20 83 40 73
- + D7 6C 59 7E
- + FB 81 58 93
- + 0D AE 02 B1
- + 5B 12 D7 82
- + 86 78 F3 76
- + 4A 71 0C 83
- + 1B 80 73 8D
- + 49 89 07 82
- + D8 99 79 BC
- + AA C8 7C 17
- + F8 0B F4 5B
- + CE 6E 71 FD
- + 09 2E 79 44
- + 52 43 00 00
- + DE 3D 2A 37
- + D3 46 00 00
- + 00 00 00 00
- + 00 00 00 00
- + 3A 6B B7 69
- + DD 6C 83 83
- + 42 76 CA 68
- + 78 75 EF 80
- + D4 74 56 5B
- + 00 00 00 00
- + 0A A5 5A D2
- + 54 A0 71 0C
- + 28 00 FF 36
- + F0 11 30 03
- + 00 00 00 00
- + ];
- +};
- diff --git a/arch/arm/boot/dts/qcom/dsi-panel-jdi-fhd-r63452-cmd.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-jdi-fhd-r63452-cmd.dtsi
- new file mode 100644
- index 0000000..6d5eb05
- --- /dev/null
- +++ b/arch/arm/boot/dts/qcom/dsi-panel-jdi-fhd-r63452-cmd.dtsi
- @@ -0,0 +1,272 @@
- +/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
- + * Copyright (C) 2017 XiaoMi, 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.
- + */
- +
- +/*---------------------------------------------------------------------------
- + * This file is autogenerated file using gcdb parser. Please do not edit it.
- + * Update input XML file to add a new entry or update variable in this file
- + * VERSION = "1.0"
- + *---------------------------------------------------------------------------*/
- +&soc {
- + dsi_jdi_fhd_r63452_cmd: qcom,mdss_dsi_jdi_fhd_r63452_cmd {
- + qcom,mdss-dsi-panel-name = "jdi fhd cmd incell dsi panel";
- + qcom,mdss-dsi-panel-id = <0>;
- + qcom,mdss-dsi-panel-model = "JDI FHD R63452 CMD PANEL";
- + qcom,mdss-dsi-panel-sleepwrmod = <0>;
- + qcom,mdss-dsi-panel-type = "dsi_cmd_mode";
- + qcom,mdss-dsi-panel-framerate = <60>;
- + qcom,mdss-dsi-virtual-channel-id = <0>;
- + qcom,mdss-dsi-stream = <0>;
- + qcom,mdss-dsi-panel-width = <1080>;
- + qcom,mdss-dsi-panel-height = <1920>;
- + qcom,mdss-dsi-h-front-porch = <120>;
- + qcom,mdss-dsi-h-back-porch = <40>;
- + qcom,mdss-dsi-h-pulse-width = <16>;
- + qcom,mdss-dsi-h-sync-skew = <0>;
- + qcom,mdss-dsi-v-back-porch = <4>;
- + qcom,mdss-dsi-v-front-porch = <4>;
- + qcom,mdss-dsi-v-pulse-width = <2>;
- + qcom,mdss-dsi-h-left-border = <0>;
- + qcom,mdss-dsi-h-right-border = <0>;
- + qcom,mdss-dsi-v-top-border = <0>;
- + qcom,mdss-dsi-v-bottom-border = <0>;
- + qcom,mdss-dsi-bpp = <24>;
- + qcom,mdss-dsi-color-order = <0>;
- + qcom,mdss-dsi-underflow-color = <0xff>;
- + qcom,mdss-dsi-border-color = <0>;
- + qcom,mdss-dsi-on-command = [
- + 29 00 00 00 00 00 02 b0 00
- + 29 00 00 00 00 00 02 d6 01
- + 29 00 00 00 00 00 0E EC 64 DC EC 3B 52 00 0B 0B 13 15 68 0B B5
- + 29 00 00 00 00 00 02 b0 03
- + 39 00 00 00 00 00 02 35 00
- + 39 00 00 00 00 00 02 36 00
- + 39 00 00 00 00 00 02 3A 77
- + 39 00 00 00 00 00 05 2A 00 00 04 37
- + 39 00 00 00 00 00 05 2B 00 00 07 7F
- + 39 00 00 00 00 00 03 44 00 00
- + 39 00 00 00 00 00 02 51 FF
- + 39 00 00 00 00 00 02 53 24
- + 39 00 00 00 00 00 02 55 00
- + 39 00 00 00 00 00 02 5E 00
- + 39 00 00 00 00 00 02 84 00
- + 05 01 00 00 14 00 02 29 00
- + 05 01 00 00 50 00 02 11 00
- + 29 00 00 00 00 00 02 B0 04
- + 39 00 00 00 00 00 02 84 00
- + 29 00 00 00 00 00 02 C8 11
- + 29 01 00 00 00 00 02 B0 03
- +];
- + qcom,mdss-dsi-off-command = [
- + 29 00 00 00 00 00 02 b0 00
- + 29 00 00 00 00 00 02 d6 01
- + 29 00 00 00 00 00 0E EC 64 DC EC 3B 52 00 0B 0B 13 15 68 0B 95
- + 29 00 00 00 00 00 02 b0 03
- + 05 01 00 00 02 00 02 28 00
- + 05 01 00 00 78 00 02 10 00];
- + qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
- + qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
- + qcom,mdss-dsi-h-sync-pulse = <0>;
- + qcom,mdss-dsi-traffic-mode = "burst_mode";
- + qcom,mdss-dsi-bllp-eof-power-mode;
- + qcom,mdss-dsi-bllp-power-mode;
- + qcom,mdss-dsi-lp11-init;
- + qcom,mdss-dsi-lane-0-state;
- + qcom,mdss-dsi-lane-1-state;
- + qcom,mdss-dsi-lane-2-state;
- + qcom,mdss-dsi-lane-3-state;
- + qcom,mdss-dsi-panel-timings = [e3 50 36 00 a9 a3 3a 50 3d 03 04 00];
- + qcom,mdss-dsi-t-clk-post = <0x20>;
- + qcom,mdss-dsi-t-clk-pre = <0x36>;
- + qcom,mdss-dsi-bl-min-level = <1>;
- + qcom,mdss-dsi-bl-max-level = <4095>;
- + qcom,mdss-brightness-max-level = <4095>;
- + qcom,mdss-dsi-dma-trigger = "trigger_sw";
- + qcom,mdss-dsi-mdp-trigger = "none";
- + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
- + qcom,mdss-dsi-reset-sequence = <1 10>, <0 1>, <1 10>;
- + qcom,mdss-pan-physical-width-dimension = <64>;
- + qcom,mdss-pan-physical-height-dimension = <114>;
- + qcom,mdss-dsi-te-pin-select = <1>;
- + qcom,mdss-dsi-wr-mem-start = <0x2c>;
- + qcom,mdss-dsi-wr-mem-continue = <0x3c>;
- + qcom,mdss-dsi-te-dcs-command = <1>;
- + qcom,mdss-dsi-te-check-enable;
- + qcom,mdss-dsi-te-using-te-pin;
- + qcom,mdss-dsi-tx-eot-append;
- + qcom,mdss-panel-on-dimming-delay = <120>;
- + qcom,dispparam-enabled;
- + qcom,mdss-night-brightness = <7 25 43 61>;
- + qcom,mdss-dsi-dispparam-cabcon-command = [
- + 29 01 00 00 00 00 02 B0 04
- + 15 01 00 00 00 00 02 55 81
- + 29 01 00 00 00 00 08 B8 AB 51 09 00 10 00 00
- + 29 01 00 00 00 00 1A CE 55 40 56 6E 87 A0 B6 CF E8 E9 EA EB EC ED EE EF FF 04 00 04 04 42 00 69 5A
- + 29 01 00 00 00 00 0A F9 64 FF E0 BE 00 8D BF 80 00
- + 29 01 00 00 00 00 02 B0 03
- + ];
- + qcom,mdss-dsi-dispparam-cabcguion-command = [
- + 29 01 00 00 00 00 02 B0 04
- + 15 01 00 00 00 00 02 55 81
- + 29 01 00 00 00 00 08 B8 AB 51 09 00 10 00 00
- + 29 01 00 00 00 00 1A CE 55 40 56 6E 87 A0 B6 CF E8 E9 EA EB EC ED EE EF FF 04 00 04 04 42 00 69 5A
- + 29 01 00 00 00 00 0A F9 64 FF E0 BE 00 8D BF 80 00
- + 29 01 00 00 00 00 02 B0 03
- + ];
- + qcom,mdss-dsi-dispparam-cabcstillon-command = [
- + 29 01 00 00 00 00 02 B0 04
- + 15 01 00 00 00 00 02 55 82
- + 29 01 00 00 00 00 08 B9 89 27 41 00 2E 00 00
- + 29 01 00 00 00 00 1A CE 55 40 46 4E 57 60 6A 75 81 8E 9B A8 B6 C3 D1 E2 FF 04 00 04 04 42 04 69 5A
- + 29 01 00 00 00 00 0A F9 64 FF E0 BE 00 8D BF 80 00
- + 29 01 00 00 00 00 02 B0 03
- + ];
- + qcom,mdss-dsi-dispparam-cabcmovieon-command = [
- + 29 01 00 00 00 00 02 B0 04
- + 15 01 00 00 00 00 02 55 83
- + 29 01 00 00 00 00 08 BA B7 27 3E 00 1F 00 00
- + 29 01 00 00 00 00 1A CE 55 40 46 4E 57 60 6A 75 81 8E 9B A8 B6 C3 D1 E2 FF 04 00 04 04 42 04 69 5A
- + 29 01 00 00 00 00 0A F9 64 3F E0 BE 00 8D BF 80 00
- + 29 01 00 00 00 00 02 B0 03
- + ];
- + qcom,mdss-dsi-dispparam-cabcoff-command = [
- + 39 01 00 00 01 00 02 55 00
- + ];
- + qcom,mdss-dsi-dispparam-dimmingon-command = [
- + 39 01 00 00 01 00 02 53 2C
- + ];
- + qcom,mdss-dsi-dispparam-idleon-command = [
- + 39 01 00 00 01 00 02 39 00
- + ];
- + qcom,mdss-dsi-dispparam-idleoff-command = [
- + 39 01 00 00 01 00 02 38 00
- + ];
- + qcom,mdss-dsi-dispparam-warm-command = [
- + 29 01 00 00 00 00 02 B0 04
- + 39 01 00 00 00 00 02 84 80
- + 29 01 00 00 00 00 32 C8 01 00 FB 05 FD FC E0 00 FA 02 F6 FC F0 00 F8 FF ED FC 01 00 FA 05 F9 BC 00 FA 02 F4 EB 00 FB FE EC FC 00 FA 05 FC FC 00 F9 03 F6 DB 00 FA 00 F6 AB
- + 29 01 00 00 00 00 02 CA 1C
- + 29 01 00 00 00 00 02 B0 03
- + ];
- + qcom,mdss-dsi-dispparam-warm-command-state = "dsi_hs_mode";
- + qcom,mdss-dsi-dispparam-cold-command = [
- + 29 01 00 00 00 00 02 B0 04
- + 39 01 00 00 00 00 02 84 7F
- + 29 01 00 00 00 00 32 C8 01 00 FB 05 FD FC E0 00 FA 02 F6 FC F0 00 F8 FF ED FC 01 00 FA 05 F9 BC 00 FA 02 F4 EB 00 FB FE EC FC 00 FA 05 FC FC 00 F9 03 F6 DB 00 FA 00 F6 AB
- + 29 01 00 00 00 00 02 CA 1C
- + 29 01 00 00 00 00 02 B0 03
- + ];
- + qcom,mdss-dsi-dispparam-cold-command-state = "dsi_hs_mode";
- + qcom,mdss-dsi-dispparam-default-command = [
- + 29 01 00 00 00 00 02 B0 04
- + 39 01 00 00 00 00 02 84 00
- + 29 01 00 00 00 00 02 C8 11
- + 29 01 00 00 00 00 02 CA 1C
- + 29 01 00 00 00 00 02 B0 03
- + ];
- + qcom,mdss-dsi-dispparam-default-command-state = "dsi_hs_mode";
- + qcom,mdss-dsi-dispparam-papermode-command = [
- + 29 01 00 00 00 00 02 55 80
- + 29 01 00 00 00 00 02 B0 04
- + 39 01 00 00 00 00 02 84 00
- + 29 01 00 00 00 00 14 c8 01 00 f4 07 fc e3 f3 00 f6 04 f7 fc f2 00 fd ff 02 00 12
- + 29 01 00 00 00 00 2C CA 1D FC FC 48 00 00 D3 00 00 D3 00 00 D3 00 00 D3 00 00 D3 00 00 D3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- + 29 01 00 00 00 00 02 B0 03
- + ];
- + qcom,mdss-dsi-dispparam-papermode-command-state = "dsi_hs_mode";
- + qcom,mdss-dsi-dispparam-papermode1-command = [
- + 29 01 00 00 00 00 02 B0 04
- + 39 01 00 00 00 00 02 84 00
- + 29 01 00 00 00 00 32 C8 01 00 F8 07 FB D7 F1 00 F8 01 F7 FC F1 00 F6 01 F2 C0 02 00 F9 05 01 59 00 F8 01 F9 B1 00 F7 FE ED FC 00 F9 06 FC ED 00 F8 01 F7 FC 00 F7 01 F6 82
- + 29 01 00 00 00 00 02 CA 1C
- + 29 01 00 00 00 00 02 B0 03
- + ];
- + qcom,mdss-dsi-dispparam-papermode1-command-state = "dsi_hs_mode";
- + qcom,mdss-dsi-dispparam-papermode2-command = [
- + 29 01 00 00 00 00 02 B0 04
- + 39 01 00 00 00 00 02 84 00
- + 29 01 00 00 00 00 32 C8 01 00 FC 03 F8 FC 00 00 FC FF F5 BB 00 00 02 FF F9 76 00 00 FC 03 F8 FC 00 FC FF F5 BB 00 02 FF F9 76 00 FC 03 F8 FC 00 FC FF F5 BB 00 02 FF F9 76
- + 29 01 00 00 00 00 02 CA 1C
- + 29 01 00 00 00 00 02 B0 03
- + ];
- + qcom,mdss-dsi-dispparam-papermode2-command-state = "dsi_hs_mode";
- + qcom,mdss-dsi-dispparam-papermode3-command = [
- + 29 01 00 00 00 00 02 B0 04
- + 39 01 00 00 00 00 02 84 00
- + 29 01 00 00 00 00 32 c8 01 00 FC 03 F8 FC 00 00 FB FF F6 AA 00 00 FE 01 FA 4B 00 00 FC 03 F8 FC 00 FB FF F6 AA 00 FE 01 FA 4B 00 FC 03 F8 FC 00 FB FF F6 AA 00 FE 01 FA 4B
- + 29 01 00 00 00 00 02 CA 1C
- + 29 01 00 00 00 00 02 B0 03
- + ];
- + qcom,mdss-dsi-dispparam-papermode3-command-state = "dsi_hs_mode";
- + qcom,mdss-dsi-dispparam-papermode4-command = [
- + 29 01 00 00 00 00 02 B0 04
- + 39 01 00 00 00 00 02 84 00
- + 29 01 00 00 00 00 32 c8 01 00 FC 03 F8 FC 00 00 FD FF F7 9A 00 00 03 01 FC 27 00 00 FC 03 F8 FC 00 FD FF F7 9A 00 03 01 FC 27 00 FC 03 F8 FC 00 FD FF F7 9A 00 03 01 FC 27
- + 29 01 00 00 00 00 02 CA 1C
- + 29 01 00 00 00 00 02 B0 03
- + ];
- + qcom,mdss-dsi-dispparam-papermode4-command-state = "dsi_hs_mode";
- + qcom,mdss-dsi-dispparam-papermode5-command = [
- + 29 01 00 00 00 00 02 55 80
- + 29 01 00 00 00 00 02 B0 04
- + 39 01 00 00 00 00 02 84 00
- + 29 01 00 00 00 00 14 c8 01 00 f4 08 fb d5 f3 00 f5 04 f7 fc f1 00 fd ff 02 00 22
- + 29 01 00 00 00 00 2C CA 1D FC FC E4 00 00 FA 00 00 FA 00 00 FA 00 00 FA 00 00 FA 00 00 FA 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- + 29 01 00 00 00 00 02 B0 03
- + ];
- + qcom,mdss-dsi-dispparam-papermode5-command-state = "dsi_hs_mode";
- + qcom,mdss-dsi-dispparam-papermode6-command = [
- + 29 01 00 00 00 00 02 55 80
- + 29 01 00 00 00 00 02 B0 04
- + 39 01 00 00 00 00 02 84 00
- + 29 01 00 00 00 00 14 c8 01 00 f4 08 fb db f2 00 f6 04 f7 fc f3 00 fd ff 02 00 22
- + 29 01 00 00 00 00 2C CA 1D FC FC B0 00 00 ED 00 00 ED 00 00 ED 00 00 ED 00 00 ED 00 00 ED 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- + 29 01 00 00 00 00 02 B0 03
- + ];
- + qcom,mdss-dsi-dispparam-papermode6-command-state = "dsi_hs_mode";
- + qcom,mdss-dsi-dispparam-papermode7-command = [
- + 29 01 00 00 00 00 02 55 80
- + 29 01 00 00 00 00 02 B0 04
- + 39 01 00 00 00 00 02 84 00
- + 29 01 00 00 00 00 14 c8 01 00 f4 08 fc df f2 00 f6 04 f7 fc f1 00 fd ff 02 00 12
- + 29 01 00 00 00 00 2C CA 1D FC FC 7C 00 00 E0 00 00 E0 00 00 E0 00 00 E0 00 00 E0 00 00 E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- + 29 01 00 00 00 00 02 B0 03
- + ];
- + qcom,mdss-dsi-dispparam-papermode7-command-state = "dsi_hs_mode";
- + qcom,mdss-dsi-dispparam-normal1-command = [
- + 29 01 00 00 00 00 02 B0 04
- + 39 01 00 00 00 00 02 84 00
- + 29 01 00 00 00 00 32 C8 01 00 FD FE FC D8 00 00 FC FE FB DC 00 00 01 F3 F0 FC 00 00 FE FD F9 99 00 FE FC FB C8 00 FF F4 EB FC 00 FE FA FD FC 00 FE FB FA E5 00 FF F6 F2 D3
- + 29 01 00 00 00 00 02 CA 1C
- + 29 01 00 00 00 00 02 B0 03
- + ];
- + qcom,mdss-dsi-dispparam-normal1-command-state = "dsi_hs_mode";
- + qcom,mdss-dsi-dispparam-normal2-command = [
- + 29 01 00 00 00 00 02 B0 04
- + 39 01 00 00 00 00 02 84 00
- + 29 01 00 00 00 00 02 C8 11
- + 29 01 00 00 00 00 02 CA 1C
- + 29 01 00 00 00 00 02 B0 03
- + ];
- + qcom,mdss-dsi-dispparam-normal2-command-state = "dsi_hs_mode";
- + qcom,mdss-dsi-dispparam-srgb-command = [
- + 05 01 00 00 10 00 02 11 00
- + 29 01 00 00 00 00 02 B0 00
- + 29 01 00 00 00 00 02 D6 01
- + 29 01 00 00 00 00 13 C8 01 00 FD FE FC FC 00 00 FC FE FB FC 00 00 01 F3 F0 FC
- + 29 01 00 00 00 00 02 CA 1D
- + 29 01 00 00 00 00 02 84 00
- + 29 01 00 00 00 00 02 B0 03
- + ];
- + qcom,mdss-dsi-dispparam-srgb-command-state = "dsi_hs_mode";
- + };
- +};
- diff --git a/arch/arm/boot/dts/qcom/dsi-panel-lgd-fhd-td4322-cmd.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-lgd-fhd-td4322-cmd.dtsi
- new file mode 100644
- index 0000000..3c32b6c
- --- /dev/null
- +++ b/arch/arm/boot/dts/qcom/dsi-panel-lgd-fhd-td4322-cmd.dtsi
- @@ -0,0 +1,270 @@
- +/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
- + * Copyright (C) 2017 XiaoMi, 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.
- + */
- +
- +/*---------------------------------------------------------------------------
- + * This file is autogenerated file using gcdb parser. Please do not edit it.
- + * Update input XML file to add a new entry or update variable in this file
- + * VERSION = "1.0"
- + *---------------------------------------------------------------------------*/
- +&soc {
- + dsi_lgd_fhd_td4322_cmd: qcom,mdss_dsi_lgd_fhd_td4322_cmd {
- + qcom,mdss-dsi-panel-name = "lgd fhd cmd incell dsi panel";
- + qcom,mdss-dsi-panel-id = <1>;
- + qcom,mdss-dsi-panel-model = "LGD FHD TD4322 CMD PANEL";
- + qcom,mdss-dsi-panel-sleepwrmod = <0>;
- + qcom,mdss-dsi-panel-type = "dsi_cmd_mode";
- + qcom,mdss-dsi-panel-framerate = <60>;
- + qcom,mdss-dsi-virtual-channel-id = <0>;
- + qcom,mdss-dsi-stream = <0>;
- + qcom,mdss-dsi-panel-width = <1080>;
- + qcom,mdss-dsi-panel-height = <1920>;
- + qcom,mdss-dsi-h-front-porch = <120>;
- + qcom,mdss-dsi-h-back-porch = <40>;
- + qcom,mdss-dsi-h-pulse-width = <16>;
- + qcom,mdss-dsi-h-sync-skew = <0>;
- + qcom,mdss-dsi-v-back-porch = <4>;
- + qcom,mdss-dsi-v-front-porch = <4>;
- + qcom,mdss-dsi-v-pulse-width = <2>;
- + qcom,mdss-dsi-h-left-border = <0>;
- + qcom,mdss-dsi-h-right-border = <0>;
- + qcom,mdss-dsi-v-top-border = <0>;
- + qcom,mdss-dsi-v-bottom-border = <0>;
- + qcom,mdss-dsi-bpp = <24>;
- + qcom,mdss-dsi-color-order = <0>;
- + qcom,mdss-dsi-underflow-color = <0xff>;
- + qcom,mdss-dsi-border-color = <0>;
- + qcom,mdss-dsi-on-command = [
- + 15 00 00 00 00 00 02 51 ff
- + 15 00 00 00 00 00 02 53 24
- + 15 00 00 00 00 00 02 55 00
- + 15 00 00 00 00 00 02 35 00
- + 39 01 00 00 00 00 05 30 00 00 02 A7
- + 05 01 00 00 46 00 02 11 00
- + 05 01 00 00 14 00 02 29 00
- + 29 00 00 00 00 00 02 B0 04
- + 39 00 00 00 00 00 02 84 00
- + 29 00 00 00 00 00 02 C8 11
- + 29 00 00 00 00 00 02 CA 1C
- + 29 00 00 00 00 00 02 EA 0F
- + 29 01 00 00 00 00 02 B0 03];
- + qcom,mdss-dsi-off-command = [
- + 05 01 00 00 14 00 02 28 00
- + 05 01 00 00 78 00 02 10 00];
- + qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
- + qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
- + qcom,esd-check-enabled;
- + qcom,mdss-dsi-panel-status-check-mode = "reg_multi_read";
- + /* mdss-dsi-panel-status-command store all ESD releated commands and expected
- + status values, and every command can have more than one returned values */
- + qcom,mdss-dsi-panel-status-command = [
- + 06 01 00 00 00 00 02 0A 1c
- + 06 01 00 00 00 00 02 EB 00];
- + qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode";
- + qcom,mdss-dsi-panel-mcap-off-cmds = [29 01 00 00 00 00 02 B0 00];
- + qcom,mdss-dsi-panel-mcap-on-cmds = [29 01 00 00 00 00 02 B0 03];
- + qcom,mdss-dsi-panel-mcap-off-cmds-state = "dsi_lp_mode";
- + qcom,mdss-dsi-panel-mcap-on-cmds-state = "dsi_lp_mode";
- + qcom,mdss-dsi-tx-eot-append;
- + qcom,mdss-dsi-h-sync-pulse = <0>;
- + qcom,mdss-dsi-traffic-mode = "burst_mode";
- + qcom,mdss-dsi-bllp-eof-power-mode;
- + qcom,mdss-dsi-bllp-power-mode;
- + qcom,mdss-dsi-lp11-init;
- + qcom,mdss-dsi-lane-0-state;
- + qcom,mdss-dsi-lane-1-state;
- + qcom,mdss-dsi-lane-2-state;
- + qcom,mdss-dsi-lane-3-state;
- + qcom,mdss-dsi-panel-timings = [e3 50 36 00 a9 a3 3a 50 3d 03 04 00];
- + qcom,mdss-dsi-t-clk-post = <0x20>;
- + qcom,mdss-dsi-t-clk-pre = <0x36>;
- + qcom,mdss-dsi-bl-min-level = <1>;
- + qcom,mdss-dsi-bl-max-level = <4095>;
- + qcom,mdss-brightness-max-level = <4095>;
- + qcom,mdss-dsi-dma-trigger = "trigger_sw";
- + qcom,mdss-dsi-mdp-trigger = "none";
- + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
- + qcom,mdss-dsi-reset-sequence = <0 1>, <1 20>;
- + qcom,mdss-pan-physical-width-dimension = <64>;
- + qcom,mdss-pan-physical-height-dimension = <114>;
- + qcom,mdss-dsi-te-pin-select = <1>;
- + qcom,mdss-dsi-wr-mem-start = <0x2c>;
- + qcom,mdss-dsi-wr-mem-continue = <0x3c>;
- + qcom,mdss-dsi-te-dcs-command = <1>;
- + qcom,mdss-dsi-te-check-enable;
- + qcom,mdss-dsi-te-using-te-pin;
- + qcom,mdss-panel-on-dimming-delay = <120>;
- + qcom,dispparam-enabled;
- + qcom,mdss-night-brightness = <7 25 43 61>;
- + qcom,mdss-dsi-dispparam-cabcon-command = [
- + 29 01 00 00 00 00 02 B0 04
- + 15 01 00 00 00 00 02 55 81
- + 29 01 00 00 00 00 08 B8 AB 51 09 00 10 00 00
- + 29 01 00 00 00 00 1A CE 55 40 56 6E 87 A0 B6 CF E8 E9 EA EB EC ED EE EF FF 04 00 04 04 42 00 69 5A
- + 29 01 00 00 00 00 0A F9 64 FF E0 BE 00 8D BF 80 00
- + 29 01 00 00 00 00 02 B0 03
- + ];
- + qcom,mdss-dsi-dispparam-cabcguion-command = [
- + 29 01 00 00 00 00 02 B0 04
- + 15 01 00 00 00 00 02 55 81
- + 29 01 00 00 00 00 08 B8 AB 51 09 00 10 00 00
- + 29 01 00 00 00 00 1A CE 55 40 56 6E 87 A0 B6 CF E8 E9 EA EB EC ED EE EF FF 04 00 04 04 42 00 69 5A
- + 29 01 00 00 00 00 0A F9 64 FF E0 BE 00 8D BF 80 00
- + 29 01 00 00 00 00 02 B0 03
- + ];
- + qcom,mdss-dsi-dispparam-cabcstillon-command = [
- + 29 01 00 00 00 00 02 B0 04
- + 15 01 00 00 00 00 02 55 82
- + 29 01 00 00 00 00 08 B9 89 27 41 00 2E 00 00
- + 29 01 00 00 00 00 1A CE 55 40 46 4E 57 60 6A 75 81 8E 9B A8 B6 C3 D1 E2 FF 04 00 04 04 42 04 69 5A
- + 29 01 00 00 00 00 0A F9 64 FF E0 BE 00 8D BF 80 00
- + 29 01 00 00 00 00 02 B0 03
- + ];
- + qcom,mdss-dsi-dispparam-cabcmovieon-command = [
- + 29 01 00 00 00 00 02 B0 04
- + 15 01 00 00 00 00 02 55 83
- + 29 01 00 00 00 00 08 BA B7 27 3E 00 1F 00 00
- + 29 01 00 00 00 00 1A CE 55 40 46 4E 57 60 6A 75 81 8E 9B A8 B6 C3 D1 E2 FF 04 00 04 04 42 04 69 5A
- + 29 01 00 00 00 00 0A F9 64 3F E0 BE 00 8D BF 80 00
- + 29 01 00 00 00 00 02 B0 03
- + ];
- + qcom,mdss-dsi-dispparam-cabcoff-command = [
- + 39 01 00 00 01 00 02 55 00
- + ];
- + qcom,mdss-dsi-dispparam-dimmingon-command = [
- + 39 01 00 00 01 00 02 53 2C
- + ];
- + qcom,mdss-dsi-dispparam-idleon-command = [
- + 39 01 00 00 01 00 02 39 00
- + ];
- + qcom,mdss-dsi-dispparam-idleoff-command = [
- + 39 01 00 00 01 00 02 38 00
- + ];
- + qcom,mdss-dsi-dispparam-warm-command = [
- + 29 01 00 00 00 00 02 B0 04
- + 39 01 00 00 00 00 02 84 80
- + 29 01 00 00 00 00 38 C8 01 00 11 04 0A FC F0 00 0E 01 07 FC F0 00 10 01 01 FC 00 00 0E 04 02 BE F0 00 0D 01 05 DB F0 00 10 01 01 FC 00 00 11 04 0A FC F0 00 0E 00 06 E0 F0 00 10 01 01 B9 00
- + 29 01 00 00 00 00 02 CA 1C
- + 29 01 00 00 00 00 02 B0 03
- + ];
- + qcom,mdss-dsi-dispparam-warm-command-state = "dsi_hs_mode";
- + qcom,mdss-dsi-dispparam-cold-command = [
- + 29 01 00 00 00 00 02 B0 04
- + 39 01 00 00 00 00 02 84 7F
- + 29 01 00 00 00 00 38 C8 01 00 11 04 0A FC F0 00 0E 01 07 FC F0 00 10 01 01 FC 00 00 0E 04 02 BE F0 00 0D 01 05 DB F0 00 10 01 01 FC 00 00 11 04 0A FC F0 00 0E 00 06 E0 F0 00 10 01 01 B9 00
- + 29 01 00 00 00 00 02 CA 1C
- + 29 01 00 00 00 00 02 B0 03
- + ];
- + qcom,mdss-dsi-dispparam-cold-command-state = "dsi_hs_mode";
- + qcom,mdss-dsi-dispparam-default-command = [
- + 29 01 00 00 00 00 02 B0 04
- + 39 01 00 00 00 00 02 84 00
- + 29 01 00 00 00 00 02 C8 11
- + 29 01 00 00 00 00 02 CA 1C
- + 29 01 00 00 00 00 02 B0 03
- + ];
- + qcom,mdss-dsi-dispparam-default-command-state = "dsi_hs_mode";
- + qcom,mdss-dsi-dispparam-papermode-command = [
- + 29 01 00 00 00 00 02 55 80
- + 29 01 00 00 00 00 02 B0 04
- + 39 01 00 00 00 00 02 84 00
- + 29 01 00 00 00 00 14 C8 01 00 FF 01 FF FC 00 00 FD FF FF F9 00 00 FE 01 FB 00 00
- + 29 01 00 00 00 00 2C CA 1D FC FC 50 00 00 D5 00 00 D5 00 00 D5 00 00 D5 00 00 D5 00 00 D5 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- + 29 01 00 00 00 00 02 B0 03
- + ];
- + qcom,mdss-dsi-dispparam-papermode-command-state = "dsi_hs_mode";
- + qcom,mdss-dsi-dispparam-papermode1-command = [
- + 29 01 00 00 00 00 02 B0 04
- + 39 01 00 00 00 00 02 84 00
- + 29 01 00 00 00 00 14 C8 01 00 FF 01 02 FC 00 00 FA 01 FF F7 00 00 FE 01 FA C2 00
- + 29 01 00 00 00 00 02 CA 1C
- + 29 01 00 00 00 00 02 B0 03
- + ];
- + qcom,mdss-dsi-dispparam-papermode1-command-state = "dsi_hs_mode";
- + qcom,mdss-dsi-dispparam-papermode2-command = [
- + 29 01 00 00 00 00 02 B0 04
- + 39 01 00 00 00 00 02 84 00
- + 29 01 00 00 00 00 32 C8 01 00 FC 03 F8 FC 00 00 FC FF F5 BB 00 00 02 FF F9 76 00 00 FC 03 F8 FC 00 FC FF F5 BB 00 02 FF F9 76 00 FC 03 F8 FC 00 FC FF F5 BB 00 02 FF F9 76
- + 29 01 00 00 00 00 02 CA 1C
- + 29 01 00 00 00 00 02 B0 03
- + ];
- + qcom,mdss-dsi-dispparam-papermode2-command-state = "dsi_hs_mode";
- + qcom,mdss-dsi-dispparam-papermode3-command = [
- + 29 01 00 00 00 00 02 B0 04
- + 39 01 00 00 00 00 02 84 00
- + 29 01 00 00 00 00 32 C8 01 00 FC 03 F8 FC 00 00 FB FF F6 AA 00 00 FE 01 FA 4B 00 00 FC 03 F8 FC 00 FB FF F6 AA 00 FE 01 FA 4B 00 FC 03 F8 FC 00 FB FF F6 AA 00 FE 01 FA 4B
- + 29 01 00 00 00 00 02 CA 1C
- + 29 01 00 00 00 00 02 B0 03
- + ];
- + qcom,mdss-dsi-dispparam-papermode3-command-state = "dsi_hs_mode";
- + qcom,mdss-dsi-dispparam-papermode4-command = [
- + 29 01 00 00 00 00 02 B0 04
- + 39 01 00 00 00 00 02 84 00
- + 29 01 00 00 00 00 32 C8 01 00 FC 03 F8 FC 00 00 FD FF F7 9A 00 00 03 01 FC 27 00 00 FC 03 F8 FC 00 FD FF F7 9A 00 03 01 FC 27 00 FC 03 F8 FC 00 FD FF F7 9A 00 03 01 FC 27
- + 29 01 00 00 00 00 02 CA 1C
- + 29 01 00 00 00 00 02 B0 03
- + ];
- + qcom,mdss-dsi-dispparam-papermode4-command-state = "dsi_hs_mode";
- + qcom,mdss-dsi-dispparam-papermode5-command = [
- + 29 01 00 00 00 00 02 55 80
- + 29 01 00 00 00 00 02 B0 04
- + 39 01 00 00 00 00 02 84 00
- + 29 01 00 00 00 00 14 C8 01 00 FF 01 FF FC 00 00 F9 01 FE F8 00 00 FE 01 FC 00 00
- + 29 01 00 00 00 00 2C CA 1D FC FC E4 00 00 FA 00 00 FA 00 00 FA 00 00 FA 00 00 FA 00 00 FA 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- + 29 01 00 00 00 00 02 B0 03
- + ];
- + qcom,mdss-dsi-dispparam-papermode5-command-state = "dsi_hs_mode";
- + qcom,mdss-dsi-dispparam-papermode6-command = [
- + 29 01 00 00 00 00 02 55 80
- + 29 01 00 00 00 00 02 B0 04
- + 39 01 00 00 00 00 02 84 00
- + 29 01 00 00 00 00 14 C8 01 00 FF 01 FF FC 00 00 F9 01 FE F8 00 00 FE 01 FC 00 00
- + 29 01 00 00 00 00 2C CA 1D FC FC C4 00 00 F2 00 00 F2 00 00 F2 00 00 F2 00 00 F2 00 00 F2 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- + 29 01 00 00 00 00 02 B0 03
- + ];
- + qcom,mdss-dsi-dispparam-papermode6-command-state = "dsi_hs_mode";
- + qcom,mdss-dsi-dispparam-papermode7-command = [
- + 29 01 00 00 00 00 02 55 80
- + 29 01 00 00 00 00 02 B0 04
- + 39 01 00 00 00 00 02 84 00
- + 29 01 00 00 00 00 14 C8 01 00 FF 01 FF FC 00 00 FD FF FF F9 00 00 FE 01 FB 00 00
- + 29 01 00 00 00 00 2C CA 1D FC FC 84 00 00 E2 00 00 E2 00 00 E2 00 00 E2 00 00 E2 00 00 E2 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- + 29 01 00 00 00 00 02 B0 03
- + ];
- + qcom,mdss-dsi-dispparam-papermode7-command-state = "dsi_hs_mode";
- + qcom,mdss-dsi-dispparam-normal1-command = [
- + 29 01 00 00 00 00 02 B0 04
- + 39 01 00 00 00 00 02 84 00
- + 29 01 00 00 00 00 38 C8 01 00 11 04 0A FC F0 00 0E 01 07 FC F0 00 10 01 01 FC 00 00 0E 04 02 BE F0 00 0D 01 05 DB F0 00 10 01 01 FC 00 00 11 04 0A FC F0 00 0E 00 06 E0 F0 00 10 01 01 B9 00
- + 29 01 00 00 00 00 02 CA 1C
- + 29 01 00 00 00 00 02 B0 03
- + ];
- + qcom,mdss-dsi-dispparam-normal1-command-state = "dsi_hs_mode";
- + qcom,mdss-dsi-dispparam-normal2-command = [
- + 29 01 00 00 00 00 02 B0 04
- + 39 01 00 00 00 00 02 84 00
- + 29 01 00 00 00 00 02 C8 11
- + 29 01 00 00 00 00 02 CA 1C
- + 29 01 00 00 00 00 02 B0 03
- + ];
- + qcom,mdss-dsi-dispparam-normal2-command-state = "dsi_hs_mode";
- + qcom,mdss-dsi-dispparam-srgb-command = [
- + 05 01 00 00 10 00 02 11 00
- + 29 01 00 00 00 00 02 B0 00
- + 29 01 00 00 00 00 02 84 00
- + 29 01 00 00 00 00 02 C8 00
- + 29 01 00 00 00 00 02 CA 1D
- + 29 01 00 00 00 00 02 B0 03
- + ];
- + qcom,mdss-dsi-dispparam-srgb-command-state = "dsi_hs_mode";
- + };
- +};
- diff --git a/arch/arm/boot/dts/qcom/dsi-panel-lgd-sw43401-wqhd-cmd.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-lgd-sw43401-wqhd-cmd.dtsi
- new file mode 100644
- index 0000000..bf81aae
- --- /dev/null
- +++ b/arch/arm/boot/dts/qcom/dsi-panel-lgd-sw43401-wqhd-cmd.dtsi
- @@ -0,0 +1,111 @@
- +/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
- + * Copyright (C) 2017 XiaoMi, 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.
- + */
- +
- +/*---------------------------------------------------------------------------
- + * This file is autogenerated file using gcdb parser. Please do not edit it.
- + * Update input XML file to add a new entry or update variable in this file
- + * VERSION = "1.0"
- + *---------------------------------------------------------------------------*/
- +&soc {
- + dsi_lgd_sw43401_wqhd_cmd: qcom,mdss_dsi_lgd_sw43401_wqhd_cmd {
- + qcom,mdss-dsi-panel-name = "lgd sw43401 cmd wqhd oled panel";
- + qcom,mdss-dsi-panel-sleepwrmod = <0>;
- + qcom,mdss-dsi-panel-id = <4>;
- + qcom,mdss-dsi-panel-model = "LGD SW43401 WQHD DSC CMD";
- + qcom,mdss-dsi-panel-type = "dsi_cmd_mode";
- + qcom,mdss-dsi-panel-framerate = <60>;
- + qcom,mdss-dsi-virtual-channel-id = <0>;
- + qcom,mdss-dsi-stream = <0>;
- + qcom,mdss-dsi-panel-width = <1440>;
- + qcom,mdss-dsi-panel-height = <2560>;
- + qcom,mdss-dsi-h-front-porch = <120>;
- + qcom,mdss-dsi-h-back-porch = <120>;
- + qcom,mdss-dsi-h-pulse-width = <16>;
- + qcom,mdss-dsi-h-sync-skew = <0>;
- + qcom,mdss-dsi-v-back-porch = <48>;
- + qcom,mdss-dsi-v-front-porch = <40>;
- + qcom,mdss-dsi-v-pulse-width = <8>;
- + qcom,mdss-dsi-h-left-border = <0>;
- + qcom,mdss-dsi-h-right-border = <0>;
- + qcom,mdss-dsi-v-top-border = <0>;
- + qcom,mdss-dsi-v-bottom-border = <0>;
- + qcom,mdss-dsi-bpp = <24>;
- + qcom,mdss-dsi-color-order = <0>;
- + qcom,mdss-dsi-underflow-color = <0xff>;
- + qcom,mdss-dsi-border-color = <0>;
- + qcom,mdss-dsi-on-command = [
- + 15 01 00 00 14 00 02 B0 5A
- + 39 01 00 00 00 00 03 51 00 00 /* b3 */
- + 15 01 00 00 00 00 02 53 20
- + 15 01 00 00 00 00 02 55 0C
- + 05 01 00 00 00 00 02 35 00
- + 15 01 00 00 00 00 02 FA 16
- + 05 01 00 00 14 00 02 11 00
- + 15 01 00 00 14 00 02 B0 5A
- + 39 01 00 00 00 00 07 B1 8A FF 4A 14 14 14
- + 39 01 00 00 00 00 0C B2 3D 41 02 80 FF FF 15 00 00 00 00
- + 39 01 00 00 00 00 06 B3 00 08 00 00 00
- + 39 01 00 00 00 00 0e B4 21 12 81 00 ff 00 78 00 ff 80 00 68 02
- + 39 01 00 00 00 00 0e B5 9a 80 00 a0 05 00 0a d0 02 00 05 d0 02
- + 39 01 00 00 00 00 0e B6 a6 89 0a c0 20 14 00 10 00 00 18 f0 10
- + 39 01 00 00 00 00 03 B7 33 A6
- + 39 01 00 00 0a 00 03 D3 24 0C
- + 15 01 00 00 01 00 02 B0 00
- + 05 01 00 00 78 00 02 29 00
- + ];
- + qcom,mdss-dsi-off-command = [
- + 05 01 00 00 02 00 02 28 00
- + 05 01 00 00 80 00 02 10 00];
- + qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
- + qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
- + qcom,mdss-dsi-h-sync-pulse = <0>;
- + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event";
- + qcom,mdss-dsi-bllp-eof-power-mode;
- + qcom,mdss-dsi-bllp-power-mode;
- + qcom,mdss-dsi-lp11-init;
- + qcom,mdss-dsi-lane-0-state;
- + qcom,mdss-dsi-lane-1-state;
- + qcom,mdss-dsi-lane-2-state;
- + qcom,mdss-dsi-lane-3-state;
- + qcom,mdss-dsi-panel-timings = [00 15 05 05 08 0d 05 05 04 03 04 00];
- + qcom,mdss-dsi-t-clk-post = <0x05>;
- + qcom,mdss-dsi-t-clk-pre = <0x1b>;
- + qcom,mdss-dsi-bl-min-level = <10>;
- + qcom,mdss-dsi-bl-max-level = <255>;
- + qcom,mdss-dsi-dma-trigger = "trigger_sw";
- + qcom,mdss-dsi-mdp-trigger = "none";
- + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs";
- + qcom,mdss-dsi-reset-sequence = <1 20>, <0 10>, <1 100>;
- + qcom,mdss-pan-physical-width-dimension = <64>;
- + qcom,mdss-pan-physical-height-dimension = <114>;
- + qcom,mdss-dsi-tx-eot-append;
- + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_amoled>;
- + qcom,mdss-dsi-te-pin-select = <1>;
- + qcom,mdss-dsi-te-dcs-command = <1>;
- + qcom,mdss-dsi-te-check-enable;
- + qcom,mdss-dsi-te-using-te-pin;
- + qcom,mdss-dsi-wr-mem-start = <0x2c>;
- + qcom,mdss-dsi-wr-mem-continue = <0x3c>;
- + qcom,compression-mode = "dsc";
- + qcom,config-select = <&dsi_lgd_dsc_cmd_config0>;
- + dsi_lgd_dsc_cmd_config0: config0 {
- + qcom,mdss-dsc-encoders = <1>;
- + qcom,mdss-dsc-slice-height = <1280>;
- + qcom,mdss-dsc-slice-width = <720>;
- + qcom,mdss-dsc-slice-per-pkt = <2>;
- + qcom,mdss-dsc-bit-per-component = <8>;
- + qcom,mdss-dsc-bit-per-pixel = <8>;
- + qcom,mdss-dsc-block-prediction-enable;
- + };
- + };
- +};
- diff --git a/arch/arm/boot/dts/qcom/msm-pm8998.dtsi b/arch/arm/boot/dts/qcom/msm-pm8998.dtsi
- index e13cdf4..a458241 100644
- --- a/arch/arm/boot/dts/qcom/msm-pm8998.dtsi
- +++ b/arch/arm/boot/dts/qcom/msm-pm8998.dtsi
- @@ -1,4 +1,5 @@
- /* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
- + * Copyright (C) 2017 XiaoMi, 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
- @@ -36,6 +37,7 @@
- interrupt-names = "kpdpwr", "resin",
- "resin-bark", "kpdpwr-resin-bark";
- qcom,pon-dbc-delay = <15625>;
- + qcom,kpdpwr-sw-debounce;
- qcom,system-reset;
- qcom,store-hard-reset-reason;
- @@ -55,9 +57,9 @@
- qcom,pon-type = <3>;
- qcom,support-reset = <1>;
- qcom,pull-up = <1>;
- - qcom,s1-timer = <6720>;
- + qcom,s1-timer = <1352>;
- qcom,s2-timer = <2000>;
- - qcom,s2-type = <PON_POWER_OFF_DVDD_HARD_RESET>;
- + qcom,s2-type = <PON_POWER_OFF_WARM_RESET>;
- qcom,use-bark;
- };
- };
- diff --git a/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi b/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi
- index ad32ab0..35a7bdf 100644
- --- a/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi
- +++ b/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi
- @@ -1,4 +1,5 @@
- /* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
- + * Copyright (C) 2017 XiaoMi, 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
- @@ -78,7 +79,7 @@
- gpio@c400 {
- reg = <0xc400 0x100>;
- qcom,pin-num = <5>;
- - status = "disabled";
- + status = "okay";
- };
- gpio@c500 {
- @@ -384,11 +385,9 @@
- qcom,fg-memif@4400 {
- status = "okay";
- reg = <0x4400 0x100>;
- - interrupts = <0x2 0x44 0x0 IRQ_TYPE_EDGE_BOTH>,
- - <0x2 0x44 0x1 IRQ_TYPE_EDGE_BOTH>,
- + interrupts = <0x2 0x44 0x1 IRQ_TYPE_EDGE_BOTH>,
- <0x2 0x44 0x2 IRQ_TYPE_EDGE_BOTH>;
- - interrupt-names = "ima-rdy",
- - "mem-xcp",
- + interrupt-names = "mem-xcp",
- "dma-grant";
- };
- };
- @@ -425,7 +424,7 @@
- qcom,supported-sizes = <6>, <9>;
- qcom,ramp-index = <1>;
- #pwm-cells = <2>;
- - status = "disabled";
- + status = "okay";
- };
- pmi8998_pwm_3: pwm@b300 {
- @@ -496,8 +495,6 @@
- qcom,max-current = <12>;
- qcom,default-state = "off";
- linux,name = "red";
- - linux,default-trigger =
- - "battery-charging";
- };
- green_led: qcom,rgb_1 {
- @@ -509,7 +506,6 @@
- qcom,max-current = <12>;
- qcom,default-state = "off";
- linux,name = "green";
- - linux,default-trigger = "battery-full";
- };
- blue_led: qcom,rgb_2 {
- @@ -521,7 +517,6 @@
- qcom,max-current = <12>;
- qcom,default-state = "off";
- linux,name = "blue";
- - linux,default-trigger = "boot-indication";
- };
- };
- @@ -612,7 +607,7 @@
- linux,default-trigger = "bkl-trigger";
- qcom,fdbk-output = "auto";
- qcom,vref-uv = <127500>;
- - qcom,switch-freq-khz = <800>;
- + qcom,switch-freq-khz = <600>;
- qcom,ovp-mv = <29600>;
- qcom,ilim-ma = <970>;
- qcom,boost-duty-ns = <26>;
- @@ -623,7 +618,6 @@
- qcom,fs-curr-ua = <25000>;
- qcom,cons-sync-write-delay-us = <1000>;
- qcom,led-strings-list = [00 01 02 03];
- - qcom,en-ext-pfet-sc-pro;
- qcom,pmic-revid = <&pmi8998_revid>;
- qcom,loop-auto-gm-en;
- status = "okay";
- @@ -652,7 +646,6 @@
- qcom,lra-high-z = "opt1";
- qcom,lra-auto-res-mode = "qwd";
- qcom,lra-res-cal-period = <4>;
- - qcom,correct-lra-drive-freq;
- };
- flash_led: qcom,leds@d300 {
- @@ -717,7 +710,7 @@
- pmi8998_torch0: qcom,torch_0 {
- label = "torch";
- qcom,led-name = "led:torch_0";
- - qcom,max-current = <500>;
- + qcom,max-current = <100>;
- qcom,default-led-trigger = "torch0_trigger";
- qcom,id = <0>;
- qcom,current-ma = <300>;
- @@ -729,7 +722,7 @@
- pmi8998_torch1: qcom,torch_1 {
- label = "torch";
- qcom,led-name = "led:torch_1";
- - qcom,max-current = <500>;
- + qcom,max-current = <100>;
- qcom,default-led-trigger = "torch1_trigger";
- qcom,id = <1>;
- qcom,current-ma = <300>;
- diff --git a/arch/arm/boot/dts/qcom/msm8998-audio.dtsi b/arch/arm/boot/dts/qcom/msm8998-audio.dtsi
- index 86a31a4..c1121cb 100644
- --- a/arch/arm/boot/dts/qcom/msm8998-audio.dtsi
- +++ b/arch/arm/boot/dts/qcom/msm8998-audio.dtsi
- @@ -82,7 +82,6 @@
- qcom,msm-mbhc-hphl-swh = <0>;
- qcom,msm-mbhc-gnd-swh = <0>;
- - qcom,us-euro-gpios = <&wcd_us_euro_gpio>;
- qcom,hph-en0-gpio = <&hph_en0_gpio>;
- qcom,hph-en1-gpio = <&hph_en1_gpio>;
- qcom,tasha-mclk-clk-freq = <9600000>;
- @@ -216,9 +215,6 @@
- qcom,hph-en1-gpio = <&tavil_hph_en1>;
- qcom,tavil-mclk-clk-freq = <9600000>;
- - qcom,usbc-analog-en1_gpio = <&wcd_usbc_analog_en1_gpio>;
- - qcom,usbc-analog-en2_n_gpio = <&wcd_usbc_analog_en2n_gpio>;
- -
- asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
- <&loopback>, <&compress>, <&hostless>,
- <&afe>, <&lsm>, <&routing>, <&cpe>, <&compr>,
- @@ -305,20 +301,6 @@
- pinctrl-1 = <&wcd_gnd_mic_swap_idle>;
- };
- - wcd_usbc_analog_en1_gpio: msm_cdc_pinctrl@59 {
- - compatible = "qcom,msm-cdc-pinctrl";
- - pinctrl-names = "aud_active", "aud_sleep";
- - pinctrl-0 = <&wcd_usbc_analog_en1_active>;
- - pinctrl-1 = <&wcd_usbc_analog_en1_idle>;
- - };
- -
- - wcd_usbc_analog_en2n_gpio: msm_cdc_pinctrl@60 {
- - compatible = "qcom,msm-cdc-pinctrl";
- - pinctrl-names = "aud_active", "aud_sleep";
- - pinctrl-0 = <&wcd_usbc_analog_en2n_active>;
- - pinctrl-1 = <&wcd_usbc_analog_en2n_idle>;
- - };
- -
- wcd9xxx_intc: wcd9xxx-irq {
- status = "ok";
- compatible = "qcom,wcd9xxx-irq";
- diff --git a/arch/arm/boot/dts/qcom/msm8998-blsp.dtsi b/arch/arm/boot/dts/qcom/msm8998-blsp.dtsi
- index b9e323d..c40e7a7 100644
- --- a/arch/arm/boot/dts/qcom/msm8998-blsp.dtsi
- +++ b/arch/arm/boot/dts/qcom/msm8998-blsp.dtsi
- @@ -621,7 +621,6 @@
- interrupt-names = "spi_irq", "spi_bam_irq";
- interrupts = <0 106 0>, <0 239 0>;
- spi-max-frequency = <50000000>;
- - qcom,use-bam;
- qcom,ver-reg-exists;
- qcom,bam-consumer-pipe-index = <16>;
- qcom,bam-producer-pipe-index = <17>;
- diff --git a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-cdp.dtsi
- index d5c8900..494bfd8 100644
- --- a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-cdp.dtsi
- +++ b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-cdp.dtsi
- @@ -1,5 +1,6 @@
- /*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
- + * Copyright (C) 2017 XiaoMi, 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
- @@ -280,6 +281,7 @@
- qcom,eeprom-src = <&eeprom1>;
- qcom,actuator-src = <&actuator1>;
- cam_vdig-supply = <&pm8998_lvs1>;
- + qcom,led-flash-src = <&led_flash0>;
- cam_vio-supply = <&pm8998_lvs1>;
- cam_vana-supply = <&pmi8998_bob>;
- qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
- diff --git a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-mtp.dtsi
- index 321079a..9bfcc06 100644
- --- a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-mtp.dtsi
- +++ b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-mtp.dtsi
- @@ -1,5 +1,6 @@
- /*
- - * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
- + * Copyright (c) 2016, The Linux Foundation. All rights reserved.
- + * Copyright (C) 2017 XiaoMi, 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
- @@ -27,17 +28,7 @@
- qcom,flash-source = <&pmi8998_flash2>;
- qcom,torch-source = <&pmi8998_torch2>;
- qcom,switch-source = <&pmi8998_switch1>;
- - status = "ok";
- - };
- -
- - actuator_regulator: gpio-regulator@0 {
- - compatible = "regulator-fixed";
- - regulator-name = "rear_vana_regulator";
- - regulator-min-microvolt = <2800000>;
- - regulator-max-microvolt = <2800000>;
- - enable-active-high;
- - gpio = <&tlmm 27 0>;
- - vin-supply = <&pmi8998_bob>;
- + status = "disable";
- };
- };
- @@ -47,11 +38,14 @@
- reg = <0x0>;
- compatible = "qcom,actuator";
- qcom,cci-master = <0>;
- - cam_vaf-supply = <&actuator_regulator>;
- - qcom,cam-vreg-name = "cam_vaf";
- - qcom,cam-vreg-min-voltage = <2800000>;
- - qcom,cam-vreg-max-voltage = <2800000>;
- - qcom,cam-vreg-op-mode = <0>;
- + gpios = <&tlmm 29 0>;
- + qcom,gpio-vaf = <0>;
- + qcom,gpio-req-tbl-num = <0>;
- + qcom,gpio-req-tbl-flags = <0>;
- + qcom,gpio-req-tbl-label = "CAM_VAF";
- + pinctrl-names = "cam_default", "cam_suspend";
- + pinctrl-0 = <&cam_actuator_vaf_active>;
- + pinctrl-1 = <&cam_actuator_vaf_suspend>;
- };
- actuator1: qcom,actuator@1 {
- @@ -59,31 +53,14 @@
- reg = <0x1>;
- compatible = "qcom,actuator";
- qcom,cci-master = <1>;
- - cam_vaf-supply = <&actuator_regulator>;
- - qcom,cam-vreg-name = "cam_vaf";
- - qcom,cam-vreg-min-voltage = <2800000>;
- - qcom,cam-vreg-max-voltage = <2800000>;
- - qcom,cam-vreg-op-mode = <0>;
- - };
- -
- - tof0: qcom,tof@0 {
- - cell-index = <0>;
- - reg = <0x29>;
- - compatible = "st,stmvl53l0";
- - qcom,cci-master = <0>;
- - cam_cci-supply = <&pm8998_lvs1>;
- - cam_laser-supply = <&actuator_regulator>;
- - qcom,cam-vreg-name = "cam_cci", "cam_laser";
- - qcom,cam-vreg-min-voltage = <0 0>;
- - qcom,cam-vreg-max-voltage = <0 2800000>;
- - pinctrl-names = "cam_default", "cam_suspend";
- - pinctrl-0 = <&cam_tof_active>;
- - pinctrl-1 = <&cam_tof_suspend>;
- - stm,irq-gpio = <&tlmm 26 0x2008>;
- - gpios = <&tlmm 126 0>;
- + gpios = <&tlmm 29 0>;
- + qcom,gpio-vaf = <0>;
- qcom,gpio-req-tbl-num = <0>;
- qcom,gpio-req-tbl-flags = <0>;
- - qcom,gpio-req-tbl-label = "CAM_CE";
- + qcom,gpio-req-tbl-label = "CAM_VAF";
- + pinctrl-names = "cam_default", "cam_suspend";
- + pinctrl-0 = <&cam_actuator_vaf_active>;
- + pinctrl-1 = <&cam_actuator_vaf_suspend>;
- };
- ois0: qcom,ois@0 {
- @@ -99,6 +76,7 @@
- pinctrl-names = "cam_default", "cam_suspend";
- pinctrl-0 = <&cam_actuator_vaf_active>;
- pinctrl-1 = <&cam_actuator_vaf_suspend>;
- + status = "disabled";
- };
- eeprom0: qcom,eeprom@0 {
- @@ -228,18 +206,14 @@
- reg = <0x0>;
- qcom,csiphy-sd-index = <0>;
- qcom,csid-sd-index = <0>;
- - qcom,mount-angle = <270>;
- + qcom,mount-angle = <90>;
- qcom,led-flash-src = <&led_flash0>;
- qcom,actuator-src = <&actuator0>;
- - qcom,ois-src = <&ois0>;
- - qcom,eeprom-src = <&eeprom0>;
- cam_vio-supply = <&pm8998_lvs1>;
- - cam_vana-supply = <&pmi8998_bob>;
- - cam_vdig-supply = <&pm8998_s3>;
- - qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig";
- - qcom,cam-vreg-min-voltage = <0 3312000 1352000>;
- - qcom,cam-vreg-max-voltage = <0 3600000 1352000>;
- - qcom,cam-vreg-op-mode = <0 80000 105000>;
- + qcom,cam-vreg-name = "cam_vio";
- + qcom,cam-vreg-min-voltage = <0>;
- + qcom,cam-vreg-max-voltage = <0>;
- + qcom,cam-vreg-op-mode = <0>;
- qcom,gpio-no-mux = <0>;
- pinctrl-names = "cam_default", "cam_suspend";
- pinctrl-0 = <&cam_sensor_mclk0_active
- @@ -249,16 +223,16 @@
- gpios = <&tlmm 13 0>,
- <&tlmm 30 0>,
- <&pm8998_gpios 20 0>,
- - <&tlmm 29 0>;
- + <&tlmm 80 0>;
- qcom,gpio-reset = <1>;
- - qcom,gpio-vdig = <2>;
- - qcom,gpio-vana = <3>;
- + qcom,gpio-vana = <2>;
- + qcom,gpio-vdig = <3>;
- qcom,gpio-req-tbl-num = <0 1 2 3>;
- qcom,gpio-req-tbl-flags = <1 0 0 0>;
- qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
- "CAM_RESET0",
- - "CAM_VDIG",
- - "CAM_VANA";
- + "CAM_VANA",
- + "CAM_VDIG";
- qcom,sensor-position = <0>;
- qcom,sensor-mode = <0>;
- qcom,cci-master = <0>;
- @@ -273,19 +247,18 @@
- cell-index = <1>;
- compatible = "qcom,camera";
- reg = <0x1>;
- - qcom,csiphy-sd-index = <1>;
- - qcom,csid-sd-index = <1>;
- + qcom,csiphy-sd-index = <2>;
- + qcom,csid-sd-index = <2>;
- qcom,mount-angle = <90>;
- qcom,eeprom-src = <&eeprom1>;
- - qcom,led-flash-src = <&led_flash0>;
- qcom,actuator-src = <&actuator1>;
- + qcom,led-flash-src = <&led_flash0>;
- cam_vdig-supply = <&pm8998_lvs1>;
- cam_vio-supply = <&pm8998_lvs1>;
- - cam_vana-supply = <&pmi8998_bob>;
- - qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
- - qcom,cam-vreg-min-voltage = <0 0 3312000>;
- - qcom,cam-vreg-max-voltage = <0 0 3600000>;
- - qcom,cam-vreg-op-mode = <0 0 80000>;
- + qcom,cam-vreg-name = "cam_vio";
- + qcom,cam-vreg-min-voltage = <0>;
- + qcom,cam-vreg-max-voltage = <0>;
- + qcom,cam-vreg-op-mode = <0>;
- qcom,gpio-no-mux = <0>;
- pinctrl-names = "cam_default", "cam_suspend";
- pinctrl-0 = <&cam_sensor_mclk2_active
- @@ -294,14 +267,17 @@
- &cam_sensor_rear2_suspend>;
- gpios = <&tlmm 15 0>,
- <&tlmm 9 0>,
- - <&tlmm 8 0>;
- + <&pm8998_gpios 20 0>,
- + <&tlmm 80 0>;
- qcom,gpio-reset = <1>;
- qcom,gpio-vana = <2>;
- - qcom,gpio-req-tbl-num = <0 1 2>;
- - qcom,gpio-req-tbl-flags = <1 0 0>;
- - qcom,gpio-req-tbl-label = "CAMIF_MCLK1",
- - "CAM_RESET1",
- - "CAM_VANA1";
- + qcom,gpio-vdig = <3>;
- + qcom,gpio-req-tbl-num = <0 1 2 3>;
- + qcom,gpio-req-tbl-flags = <1 0 0 0>;
- + qcom,gpio-req-tbl-label = "CAMIF_MCLK2",
- + "CAM_RESET2",
- + "CAM_VDIG",
- + "CAM_VANA";
- qcom,sensor-position = <0>;
- qcom,sensor-mode = <0>;
- qcom,cci-master = <1>;
- @@ -316,40 +292,36 @@
- cell-index = <2>;
- compatible = "qcom,camera";
- reg = <0x02>;
- - qcom,csiphy-sd-index = <2>;
- - qcom,csid-sd-index = <2>;
- - qcom,mount-angle = <90>;
- - qcom,eeprom-src = <&eeprom2>;
- - qcom,led-flash-src = <&led_flash1>;
- - qcom,actuator-src = <&actuator1>;
- + qcom,csiphy-sd-index = <1>;
- + qcom,csid-sd-index = <1>;
- + qcom,mount-angle = <270>;
- cam_vio-supply = <&pm8998_lvs1>;
- cam_vana-supply = <&pm8998_l22>;
- - cam_vdig-supply = <&pm8998_s3>;
- - qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig";
- + qcom,cam-vreg-name = "cam_vio", "cam_vana";
- qcom,cam-vreg-min-voltage =
- - <0 2864000 1352000>;
- + <0 2864000>;
- qcom,cam-vreg-max-voltage =
- - <0 2864000 1352000>;
- - qcom,cam-vreg-op-mode = <0 80000 105000>;
- + <0 2864000>;
- + qcom,cam-vreg-op-mode = <0 80000>;
- qcom,gpio-no-mux = <0>;
- pinctrl-names = "cam_default", "cam_suspend";
- pinctrl-0 = <&cam_sensor_mclk1_active
- - &cam_sensor_front_active &led_enable>;
- + &cam_sensor_front_active>;
- pinctrl-1 = <&cam_sensor_mclk1_suspend
- - &cam_sensor_front_suspend &led_disable>;
- + &cam_sensor_front_suspend>;
- gpios = <&tlmm 14 0>,
- + <&tlmm 27 0>,
- <&tlmm 28 0>,
- - <&pm8998_gpios 9 0>,
- - <&tlmm 21 0>;
- - qcom,gpio-reset = <1>;
- - qcom,gpio-vdig = <2>;
- - qcom,gpio-flash-en = <3>;
- + <&pm8998_gpios 9 0>;
- + qcom,gpio-standby = <1>;
- + qcom,gpio-reset = <2>;
- + qcom,gpio-vdig = <3>;
- qcom,gpio-req-tbl-num = <0 1 2 3>;
- qcom,gpio-req-tbl-flags = <1 0 0 0>;
- - qcom,gpio-req-tbl-label = "CAMIF_MCLK2",
- - "CAM_RESET2",
- - "CAM_VDIG",
- - "FLASH_EN";
- + qcom,gpio-req-tbl-label = "CAMIF_MCLK1",
- + "CAM_STANDBY1",
- + "CAM_RESET1",
- + "CAM_VDIG";
- qcom,sensor-position = <1>;
- qcom,sensor-mode = <0>;
- qcom,cci-master = <1>;
- @@ -359,46 +331,6 @@
- clock-names = "cam_src_clk", "cam_clk";
- qcom,clock-rates = <24000000 0>;
- };
- -
- - qcom,camera@3 {
- - cell-index = <3>;
- - compatible = "qcom,camera";
- - reg = <0x03>;
- - qcom,csiphy-sd-index = <1>;
- - qcom,csid-sd-index = <1>;
- - qcom,mount-angle = <270>;
- - qcom,led-flash-src = <&led_flash1>;
- - cam_vio-supply = <&pm8998_lvs1>;
- - cam_vana-supply = <&pm8998_l22>;
- - cam_vdig-supply = <&pm8998_s3>;
- - qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig";
- - qcom,cam-vreg-min-voltage =
- - <0 2864000 1352000>;
- - qcom,cam-vreg-max-voltage =
- - <0 2864000 1352000>;
- - qcom,cam-vreg-op-mode = <0 80000 105000>;
- - qcom,gpio-no-mux = <0>;
- - pinctrl-names = "cam_default", "cam_suspend";
- - pinctrl-0 = <&cam_sensor_mclk3_active
- - &cam_sensor_front_iris_active>;
- - pinctrl-1 = <&cam_sensor_mclk3_suspend
- - &cam_sensor_front_iris_suspend>;
- - gpios = <&tlmm 16 0>,
- - <&tlmm 23 0>;
- - qcom,gpio-reset = <1>;
- - qcom,gpio-req-tbl-num = <0 1>;
- - qcom,gpio-req-tbl-flags = <1 0>;
- - qcom,gpio-req-tbl-label = "CAMIF_MCLK3",
- - "CAM_RESET3";
- - qcom,sensor-position = <1>;
- - qcom,sensor-mode = <0>;
- - qcom,cci-master = <1>;
- - status = "ok";
- - clocks = <&clock_mmss clk_mclk3_clk_src>,
- - <&clock_mmss clk_mmss_camss_mclk3_clk>;
- - clock-names = "cam_src_clk", "cam_clk";
- - qcom,clock-rates = <24000000 0>;
- - };
- };
- &pm8998_gpios {
- gpio@c800 { /* GPIO 9 - CAMERA SENSOR 2 VDIG */
- diff --git a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-qrd.dtsi b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-qrd.dtsi
- index 8c51aa6..093a7da 100644
- --- a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-qrd.dtsi
- +++ b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-qrd.dtsi
- @@ -1,6 +1,7 @@
- /*
- * Copyright (c) 2016, The Linux Foundation. All rights reserved.
- + * Copyright (C) 2017 XiaoMi, 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
- @@ -28,7 +29,7 @@
- qcom,flash-source = <&pmi8998_flash2>;
- qcom,torch-source = <&pmi8998_torch2>;
- qcom,switch-source = <&pmi8998_switch1>;
- - status = "ok";
- + status = "disable";
- };
- };
- @@ -38,7 +39,7 @@
- reg = <0x0>;
- compatible = "qcom,actuator";
- qcom,cci-master = <0>;
- - gpios = <&tlmm 27 0>;
- + gpios = <&tlmm 29 0>;
- qcom,gpio-vaf = <0>;
- qcom,gpio-req-tbl-num = <0>;
- qcom,gpio-req-tbl-flags = <0>;
- @@ -53,7 +54,7 @@
- reg = <0x1>;
- compatible = "qcom,actuator";
- qcom,cci-master = <1>;
- - gpios = <&tlmm 27 0>;
- + gpios = <&tlmm 29 0>;
- qcom,gpio-vaf = <0>;
- qcom,gpio-req-tbl-num = <0>;
- qcom,gpio-req-tbl-flags = <0>;
- @@ -209,28 +210,22 @@
- qcom,mount-angle = <270>;
- qcom,led-flash-src = <&led_flash0>;
- qcom,actuator-src = <&actuator0>;
- - qcom,ois-src = <&ois0>;
- - qcom,eeprom-src = <&eeprom0>;
- cam_vio-supply = <&pm8998_lvs1>;
- - cam_vana-supply = <&pmi8998_bob>;
- - cam_vdig-supply = <&pm8998_s3>;
- - qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig";
- - qcom,cam-vreg-min-voltage = <0 3312000 1352000>;
- - qcom,cam-vreg-max-voltage = <0 3312000 1352000>;
- - qcom,cam-vreg-op-mode = <0 80000 105000>;
- + qcom,cam-vreg-name = "cam_vio";
- + qcom,cam-vreg-min-voltage = <0>;
- + qcom,cam-vreg-max-voltage = <0>;
- + qcom,cam-vreg-op-mode = <0>;
- qcom,gpio-no-mux = <0>;
- pinctrl-names = "cam_default", "cam_suspend";
- - pinctrl-0 = <&cam_sensor_mclk0_active
- - &cam_sensor_rear_active>;
- - pinctrl-1 = <&cam_sensor_mclk0_suspend
- - &cam_sensor_rear_suspend>;
- + pinctrl-0 = <&cam_sensor_mclk0_active &cam_sensor_rear_active>;
- + pinctrl-1 = <&cam_sensor_mclk0_suspend &cam_sensor_rear_suspend>;
- gpios = <&tlmm 13 0>,
- <&tlmm 30 0>,
- <&pm8998_gpios 20 0>,
- - <&tlmm 29 0>;
- + <&tlmm 80 0>;
- qcom,gpio-reset = <1>;
- - qcom,gpio-vdig = <2>;
- - qcom,gpio-vana = <3>;
- + qcom,gpio-vana = <2>;
- + qcom,gpio-vdig = <3>;
- qcom,gpio-req-tbl-num = <0 1 2 3>;
- qcom,gpio-req-tbl-flags = <1 0 0 0>;
- qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
- @@ -251,33 +246,33 @@
- cell-index = <1>;
- compatible = "qcom,camera";
- reg = <0x1>;
- - qcom,csiphy-sd-index = <1>;
- - qcom,csid-sd-index = <1>;
- + qcom,csiphy-sd-index = <2>;
- + qcom,csid-sd-index = <2>;
- qcom,mount-angle = <90>;
- - qcom,eeprom-src = <&eeprom1>;
- - cam_vdig-supply = <&pm8998_lvs1>;
- cam_vio-supply = <&pm8998_lvs1>;
- cam_vana-supply = <&pmi8998_bob>;
- - qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
- - qcom,cam-vreg-min-voltage = <0 0 3312000>;
- - qcom,cam-vreg-max-voltage = <0 0 3312000>;
- - qcom,cam-vreg-op-mode = <0 0 80000>;
- + qcom,actuator-src = <&actuator1>;
- + qcom,cam-vreg-name = "cam_vio";
- + qcom,cam-vreg-min-voltage = <0>;
- + qcom,cam-vreg-max-voltage = <0>;
- + qcom,cam-vreg-op-mode = <0>;
- qcom,gpio-no-mux = <0>;
- pinctrl-names = "cam_default", "cam_suspend";
- - pinctrl-0 = <&cam_sensor_mclk2_active
- - &cam_sensor_rear2_active>;
- - pinctrl-1 = <&cam_sensor_mclk2_suspend
- - &cam_sensor_rear2_suspend>;
- + pinctrl-0 = <&cam_sensor_mclk2_active &cam_sensor_rear_active>;
- + pinctrl-1 = <&cam_sensor_mclk2_suspend &cam_sensor_rear_suspend>;
- gpios = <&tlmm 15 0>,
- <&tlmm 9 0>,
- - <&tlmm 8 0>;
- + <&pm8998_gpios 20 0>,
- + <&tlmm 80 0>;
- qcom,gpio-reset = <1>;
- qcom,gpio-vana = <2>;
- - qcom,gpio-req-tbl-num = <0 1 2>;
- - qcom,gpio-req-tbl-flags = <1 0 0>;
- - qcom,gpio-req-tbl-label = "CAMIF_MCLK1",
- - "CAM_RESET1",
- - "CAM_VANA1";
- + qcom,gpio-vdig = <3>;
- + qcom,gpio-req-tbl-num = <0 1 2 3>;
- + qcom,gpio-req-tbl-flags = <1 0 0 0>;
- + qcom,gpio-req-tbl-label = "CAMIF_MCLK2",
- + "CAM_RESET2",
- + "CAM_VDIG",
- + "CAM_VANA";
- qcom,sensor-position = <0>;
- qcom,sensor-mode = <0>;
- qcom,cci-master = <1>;
- @@ -292,21 +287,17 @@
- cell-index = <2>;
- compatible = "qcom,camera";
- reg = <0x02>;
- - qcom,csiphy-sd-index = <2>;
- - qcom,csid-sd-index = <2>;
- - qcom,mount-angle = <90>;
- - qcom,eeprom-src = <&eeprom2>;
- - qcom,led-flash-src = <&led_flash1>;
- - qcom,actuator-src = <&actuator1>;
- + qcom,csiphy-sd-index = <1>;
- + qcom,csid-sd-index = <1>;
- + qcom,mount-angle = <270>;
- cam_vio-supply = <&pm8998_lvs1>;
- cam_vana-supply = <&pm8998_l22>;
- - cam_vdig-supply = <&pm8998_s3>;
- - qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig";
- + qcom,cam-vreg-name = "cam_vio", "cam_vana";
- qcom,cam-vreg-min-voltage =
- - <0 2864000 1352000>;
- + <0 2864000>;
- qcom,cam-vreg-max-voltage =
- - <0 2864000 1352000>;
- - qcom,cam-vreg-op-mode = <0 80000 105000>;
- + <0 2864000>;
- + qcom,cam-vreg-op-mode = <0 80000>;
- qcom,gpio-no-mux = <0>;
- pinctrl-names = "cam_default", "cam_suspend";
- pinctrl-0 = <&cam_sensor_mclk1_active
- @@ -314,14 +305,17 @@
- pinctrl-1 = <&cam_sensor_mclk1_suspend
- &cam_sensor_front_suspend>;
- gpios = <&tlmm 14 0>,
- + <&tlmm 27 0>,
- <&tlmm 28 0>,
- <&pm8998_gpios 9 0>;
- - qcom,gpio-reset = <1>;
- - qcom,gpio-vdig = <2>;
- - qcom,gpio-req-tbl-num = <0 1 2>;
- - qcom,gpio-req-tbl-flags = <1 0 0>;
- - qcom,gpio-req-tbl-label = "CAMIF_MCLK2",
- - "CAM_RESET2",
- + qcom,gpio-standby = <1>;
- + qcom,gpio-reset = <2>;
- + qcom,gpio-vdig = <3>;
- + qcom,gpio-req-tbl-num = <0 1 2 3>;
- + qcom,gpio-req-tbl-flags = <1 0 0 0>;
- + qcom,gpio-req-tbl-label = "CAMIF_MCLK1",
- + "CAM_STANDBY1",
- + "CAM_RESET1",
- "CAM_VDIG";
- qcom,sensor-position = <1>;
- qcom,sensor-mode = <0>;
- diff --git a/arch/arm/boot/dts/qcom/msm8998-camera.dtsi b/arch/arm/boot/dts/qcom/msm8998-camera.dtsi
- index f874444..1525010 100644
- --- a/arch/arm/boot/dts/qcom/msm8998-camera.dtsi
- +++ b/arch/arm/boot/dts/qcom/msm8998-camera.dtsi
- @@ -1,5 +1,6 @@
- /*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
- + * Copyright (C) 2017 XiaoMi, 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
- @@ -535,9 +536,9 @@
- "NO_SET_RATE", "NO_SET_RATE",
- "NO_SET_RATE", "NO_SET_RATE",
- "INIT_RATE",
- - "NO_SET_RATE", "NO_SET_RATE",
- + "INIT_RATE", "NO_SET_RATE",
- "INIT_RATE",
- - "NO_SET_RATE", "NO_SET_RATE";
- + "INIT_RATE", "NO_SET_RATE";
- status = "ok";
- };
- @@ -856,7 +857,7 @@
- qcom,hw-thd-dat = <22>;
- qcom,hw-thd-sta = <162>;
- qcom,hw-tbuf = <227>;
- - qcom,hw-scl-stretch-en = <0>;
- + qcom,hw-scl-stretch-en = <1>;
- qcom,hw-trdhld = <6>;
- qcom,hw-tsp = <3>;
- qcom,cci-clk-src = <37500000>;
- @@ -871,7 +872,7 @@
- qcom,hw-thd-dat = <22>;
- qcom,hw-thd-sta = <35>;
- qcom,hw-tbuf = <62>;
- - qcom,hw-scl-stretch-en = <0>;
- + qcom,hw-scl-stretch-en = <1>;
- qcom,hw-trdhld = <6>;
- qcom,hw-tsp = <3>;
- qcom,cci-clk-src = <37500000>;
- diff --git a/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-mtp.dtsi
- index d00ae0f..b57800d 100644
- --- a/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-mtp.dtsi
- +++ b/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-mtp.dtsi
- @@ -1,5 +1,6 @@
- /*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
- + * Copyright (C) 2017 XiaoMi, 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
- @@ -12,12 +13,6 @@
- */
- &soc {
- - /delete-node/qcom,camera-flash@0;
- - /delete-node/qcom,camera-flash@1;
- - /delete-node/gpio-regulator@0;
- -};
- -
- -&soc {
- tlmm: pinctrl@03400000 {
- cam_sensor_rear_active: cam_sensor_rear_active {
- /* RESET, STANDBY */
- @@ -138,17 +133,19 @@
- };
- };
- +&soc {
- + /delete-node/gpio-regulator@0;
- +};
- +
- &cci {
- /delete-node/qcom,camera@0;
- /delete-node/qcom,camera@1;
- /delete-node/qcom,camera@2;
- - /delete-node/qcom,camera@3;
- /delete-node/qcom,eeprom@0;
- /delete-node/qcom,eeprom@1;
- /delete-node/qcom,eeprom@2;
- /delete-node/qcom,actuator@0;
- /delete-node/qcom,actuator@1;
- - /delete-node/qcom,tof@0;
- /delete-node/qcom,ois@0;
- };
- diff --git a/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-qrd.dtsi b/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-qrd.dtsi
- index 42414db..7ffbe65 100644
- --- a/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-qrd.dtsi
- +++ b/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-qrd.dtsi
- @@ -1,5 +1,6 @@
- /*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
- + * Copyright (C) 2017 XiaoMi, 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
- @@ -12,12 +13,6 @@
- */
- &soc {
- - /delete-node/qcom,camera-flash@0;
- - /delete-node/qcom,camera-flash@1;
- - /delete-node/gpio-regulator@0;
- -};
- -
- -&soc {
- tlmm: pinctrl@03400000 {
- cam_sensor_rear_active: cam_sensor_rear_active {
- /* RESET, STANDBY */
- @@ -176,17 +171,19 @@
- };
- };
- +&soc {
- + /delete-node/gpio-regulator@0;
- +};
- +
- &cci {
- /delete-node/qcom,camera@0;
- /delete-node/qcom,camera@1;
- /delete-node/qcom,camera@2;
- - /delete-node/qcom,camera@3;
- /delete-node/qcom,eeprom@0;
- /delete-node/qcom,eeprom@1;
- /delete-node/qcom,eeprom@2;
- /delete-node/qcom,actuator@0;
- /delete-node/qcom,actuator@1;
- - /delete-node/qcom,tof@0;
- /delete-node/qcom,ois@0;
- };
- diff --git a/arch/arm/boot/dts/qcom/msm8998-mdss-panels.dtsi b/arch/arm/boot/dts/qcom/msm8998-mdss-panels.dtsi
- index d0d1333..14975c5 100644
- --- a/arch/arm/boot/dts/qcom/msm8998-mdss-panels.dtsi
- +++ b/arch/arm/boot/dts/qcom/msm8998-mdss-panels.dtsi
- @@ -1,4 +1,5 @@
- /* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
- + * Copyright (C) 2017 XiaoMi, 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
- @@ -24,6 +25,9 @@
- #include "dsi-panel-jdi-dualmipi-cmd.dtsi"
- #include "dsi-panel-sharp-1080p-cmd.dtsi"
- #include "dsi-panel-jdi-1080p-video.dtsi"
- +#include "dsi-panel-jdi-fhd-r63452-cmd.dtsi"
- +#include "dsi-panel-lgd-fhd-td4322-cmd.dtsi"
- +#include "dsi-panel-lgd-sw43401-wqhd-cmd.dtsi"
- #include "dsi-panel-sharp-dualmipi-1080p-120hz.dtsi"
- #include "dsi-panel-jdi-a407-dualmipi-wqhd-cmd.dtsi"
- #include "dsi-panel-sim-video.dtsi"
- @@ -41,10 +45,12 @@
- qcom,panel-supply-entry@0 {
- reg = <0>;
- qcom,supply-name = "wqhd-vddio";
- - qcom,supply-min-voltage = <1880000>;
- - qcom,supply-max-voltage = <1880000>;
- + qcom,supply-min-voltage = <1800000>;
- + qcom,supply-max-voltage = <1800000>;
- qcom,supply-enable-load = <32000>;
- qcom,supply-disable-load = <80>;
- + qcom,supply-post-on-sleep = <1>;
- + qcom,supply-pre-off-sleep = <10>;
- };
- qcom,panel-supply-entry@1 {
- @@ -64,10 +70,39 @@
- qcom,supply-enable-load = <100000>;
- qcom,supply-disable-load = <100>;
- qcom,supply-post-on-sleep = <10>;
- + qcom,supply-pre-off-sleep = <5>;
- + };
- + };
- +};
- +
- +&soc {
- + dsi_panel_pwr_supply_amoled: dsi_panel_pwr_supply_amoled {
- + #address-cells = <1>;
- + #size-cells = <0>;
- +
- + qcom,panel-supply-entry@0 {
- + reg = <0>;
- + qcom,supply-name = "wqhd-vddio";
- + qcom,supply-min-voltage = <1800000>;
- + qcom,supply-max-voltage = <1800000>;
- + qcom,supply-enable-load = <32000>;
- + qcom,supply-disable-load = <80>;
- + #qcom,supply-post-on-sleep = <5>;
- + };
- +
- + qcom,panel-supply-entry@1 {
- + reg = <0>;
- + qcom,supply-name = "vpnl";
- + qcom,supply-min-voltage = <3000000>;
- + qcom,supply-max-voltage = <3000000>;
- + qcom,supply-enable-load = <32000>;
- + qcom,supply-disable-load = <80>;
- + qcom,supply-post-on-sleep = <5>;
- };
- };
- };
- +
- &soc {
- dsi_panel_pwr_supply_no_labibb: dsi_panel_pwr_supply_no_labibb {
- #address-cells = <1>;
- @@ -84,6 +119,44 @@
- };
- };
- +&soc {
- + dsi_panel_pwr_supply_lgd_td4322: dsi_panel_pwr_supply_lgd_td4322 {
- + #address-cells = <1>;
- + #size-cells = <0>;
- +
- + qcom,panel-supply-entry@0 {
- + reg = <0>;
- + qcom,supply-name = "wqhd-vddio";
- + qcom,supply-min-voltage = <1800000>;
- + qcom,supply-max-voltage = <1800000>;
- + qcom,supply-enable-load = <32000>;
- + qcom,supply-disable-load = <80>;
- + qcom,supply-post-on-sleep = <10>;
- + qcom,supply-pre-off-sleep = <10>;
- + };
- +
- + qcom,panel-supply-entry@1 {
- + reg = <1>;
- + qcom,supply-name = "lab";
- + qcom,supply-min-voltage = <4600000>;
- + qcom,supply-max-voltage = <6000000>;
- + qcom,supply-enable-load = <100000>;
- + qcom,supply-disable-load = <100>;
- + };
- +
- + qcom,panel-supply-entry@2 {
- + reg = <2>;
- + qcom,supply-name = "ibb";
- + qcom,supply-min-voltage = <4600000>;
- + qcom,supply-max-voltage = <6000000>;
- + qcom,supply-enable-load = <100000>;
- + qcom,supply-disable-load = <100>;
- + qcom,supply-post-on-sleep = <10>;
- + qcom,supply-pre-off-sleep = <5>;
- + };
- + };
- +};
- +
- &dsi_dual_nt35597_video {
- qcom,mdss-dsi-panel-timings = [00 1c 08 07 23 22 07 07 05 03 04 00];
- qcom,mdss-dsi-t-clk-post = <0x0d>;
- @@ -180,6 +253,18 @@
- qcom,mdss-dsi-t-clk-pre = <0x28>;
- };
- +&dsi_jdi_fhd_r63452_cmd {
- + qcom,mdss-dsi-panel-timings = [00 1a 07 06 0a 11 07 07 05 03 04 00];
- + qcom,mdss-dsi-t-clk-post = <0x07>;
- + qcom,mdss-dsi-t-clk-pre = <0x28>;
- +};
- +
- +&dsi_lgd_fhd_td4322_cmd {
- + qcom,mdss-dsi-panel-timings = [00 1a 07 06 0a 11 07 07 05 03 04 00];
- + qcom,mdss-dsi-t-clk-post = <0x07>;
- + qcom,mdss-dsi-t-clk-pre = <0x28>;
- +};
- +
- &dsi_dual_sharp_1080_120hz_cmd {
- qcom,mdss-dsi-panel-timings = [00 19 05 06 0a 0f 05 06 05 03 04 00];
- qcom,mdss-dsi-t-clk-post = <0x7>;
- diff --git a/arch/arm/boot/dts/qcom/msm8998-mdss.dtsi b/arch/arm/boot/dts/qcom/msm8998-mdss.dtsi
- index 2b9e13e..ffe70b8 100644
- --- a/arch/arm/boot/dts/qcom/msm8998-mdss.dtsi
- +++ b/arch/arm/boot/dts/qcom/msm8998-mdss.dtsi
- @@ -1,4 +1,5 @@
- /* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
- + * Copyright (C) 2017 XiaoMi, 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
- @@ -379,6 +380,7 @@
- reg-names = "dsi_ctrl", "dsi_phy", "mmss_misc_phys";
- qcom,timing-db-mode;
- + vpnl-supply = <&disp_vpnl_vreg>;
- wqhd-vddio-supply = <&pm8998_l14>;
- lab-supply = <&lab_regulator>;
- ibb-supply = <&ibb_regulator>;
- diff --git a/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi
- index 7159301..7003658 100644
- --- a/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi
- +++ b/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi
- @@ -1,4 +1,5 @@
- /* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
- + * Copyright (C) 2017 XiaoMi, 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
- @@ -942,12 +943,12 @@
- cam_actuator_vaf_active: cam_actuator_vaf_active {
- /* ACTUATOR POWER */
- mux {
- - pins = "gpio27";
- + pins = "gpio29";
- function = "gpio";
- };
- config {
- - pins = "gpio27";
- + pins = "gpio29";
- bias-disable; /* No PULL */
- drive-strength = <2>; /* 2 MA */
- };
- @@ -956,12 +957,12 @@
- cam_actuator_vaf_suspend: cam_actuator_vaf_suspend {
- /* ACTUATOR POWER */
- mux {
- - pins = "gpio27";
- + pins = "gpio29";
- function = "gpio";
- };
- config {
- - pins = "gpio27";
- + pins = "gpio29";
- bias-pull-down; /* PULL DOWN */
- drive-strength = <2>; /* 2 MA */
- };
- @@ -1004,7 +1005,7 @@
- config {
- pins = "gpio13";
- bias-disable; /* No PULL */
- - drive-strength = <2>; /* 2 MA */
- + drive-strength = <4>; /* 2 MA */
- };
- };
- @@ -1019,19 +1020,19 @@
- config {
- pins = "gpio13";
- bias-pull-down; /* PULL DOWN */
- - drive-strength = <2>; /* 2 MA */
- + drive-strength = <4>; /* 2 MA */
- };
- };
- cam_sensor_rear_active: cam_sensor_rear_active {
- /* RESET, STANDBY */
- mux {
- - pins = "gpio30","gpio29";
- + pins = "gpio30", "gpio80";
- function = "gpio";
- };
- config {
- - pins = "gpio30","gpio29";
- + pins = "gpio30", "gpio80";
- bias-disable; /* No PULL */
- drive-strength = <2>; /* 2 MA */
- };
- @@ -1291,12 +1292,12 @@
- cam_sensor_rear_suspend: cam_sensor_rear_suspend {
- /* RESET, STANDBY */
- mux {
- - pins = "gpio30","gpio29";
- + pins = "gpio30","gpio80";
- function = "gpio";
- };
- config {
- - pins = "gpio30","gpio29";
- + pins = "gpio30","gpio80";
- bias-disable; /* No PULL */
- drive-strength = <2>; /* 2 MA */
- };
- @@ -1313,7 +1314,7 @@
- config {
- pins = "gpio14";
- bias-disable; /* No PULL */
- - drive-strength = <2>; /* 2 MA */
- + drive-strength = <4>; /* 2 MA */
- };
- };
- @@ -1328,7 +1329,7 @@
- config {
- pins = "gpio14";
- bias-pull-down; /* PULL DOWN */
- - drive-strength = <2>; /* 2 MA */
- + drive-strength = <4>; /* 2 MA */
- };
- };
- @@ -1365,12 +1366,12 @@
- cam_sensor_rear2_active: cam_sensor_rear2_active {
- /* RESET, STANDBY */
- mux {
- - pins = "gpio9","gpio8";
- + pins = "gpio9";
- function = "gpio";
- };
- config {
- - pins = "gpio9","gpio8";
- + pins = "gpio9";
- bias-disable; /* No PULL */
- drive-strength = <2>; /* 2 MA */
- };
- @@ -1485,11 +1486,11 @@
- cam_sensor_rear2_suspend: cam_sensor_rear2_suspend {
- /* RESET, STANDBY */
- mux {
- - pins = "gpio9","gpio8";
- + pins = "gpio9";
- function = "gpio";
- };
- config {
- - pins = "gpio9","gpio8";
- + pins = "gpio9";
- bias-disable; /* No PULL */
- drive-strength = <2>; /* 2 MA */
- };
- @@ -1506,7 +1507,7 @@
- config {
- pins = "gpio15";
- bias-disable; /* No PULL */
- - drive-strength = <2>; /* 2 MA */
- + drive-strength = <4>; /* 2 MA */
- };
- };
- @@ -1521,19 +1522,19 @@
- config {
- pins = "gpio15";
- bias-pull-down; /* PULL DOWN */
- - drive-strength = <2>; /* 2 MA */
- + drive-strength = <4>; /* 2 MA */
- };
- };
- cam_sensor_front_active: cam_sensor_front_active {
- /* RESET VANA*/
- mux {
- - pins = "gpio28", "gpio29";
- + pins = "gpio28", "gpio27","gpio9";
- function = "gpio";
- };
- config {
- - pins = "gpio28", "gpio29";
- + pins = "gpio28", "gpio27","gpio9";
- bias-disable; /* No PULL */
- drive-strength = <2>; /* 2 MA */
- };
- @@ -1609,12 +1610,12 @@
- cam_sensor_front_suspend: cam_sensor_front_suspend {
- /* RESET */
- mux {
- - pins = "gpio28";
- + pins = "gpio28", "gpio27","gpio9";
- function = "gpio";
- };
- config {
- - pins = "gpio28";
- + pins = "gpio28", "gpio27","gpio9";
- bias-disable; /* No PULL */
- drive-strength = <2>; /* 2 MA */
- };
- @@ -1661,6 +1662,31 @@
- };
- };
- + mdss_vpnl_active: mdss_vpnl_active {
- + mux {
- + pins = "gpio63";
- + function = "gpio";
- + };
- + config {
- + pins = "gpio63";
- + drive-strength = <8>; /* 8 mA */
- + bias-disable=<0>;
- + output-high;
- + };
- + };
- +
- + mdss_vpnl_suspend: mdss_vpnl_suspend {
- + mux {
- + pins = "gpio63";
- + function = "gpio";
- + };
- + config {
- + pins = "gpio63";
- + drive-strength = <2>; /* 2 mA */
- + bias-pull-down; /* pull down */
- + };
- + };
- +
- pmx_mdss_te {
- mdss_te_active: mdss_te_active {
- mux {
- @@ -1890,7 +1916,7 @@
- config {
- pins = "gpio89";
- drive-strength = <2>;
- - bias-pull-down;
- + bias-disable;
- };
- };
- @@ -1954,6 +1980,46 @@
- };
- };
- + bk_ts_mux {
- + bk_ts_active: bk_ts_active {
- + mux {
- + pins = "gpio58", "gpio59";
- + function = "gpio";
- + };
- +
- + config {
- + pins = "gpio58", "gpio59";
- + drive-strength = <16>;
- + bias-pull-up;
- + };
- + };
- +
- + bk_ts_reset_suspend: bk_ts_reset_suspend {
- + mux {
- + pins = "gpio59";
- + function = "gpio";
- + };
- +
- + config {
- + pins = "gpio59";
- + drive-strength = <2>;
- + bias-disable;
- + };
- + };
- +
- + bk_ts_int_suspend: bk_ts_int_suspend {
- + mux {
- + pins = "gpio58";
- + function = "gpio";
- + };
- +
- + config {
- + pins = "gpio58";
- + drive-strength = <2>;
- + bias-disable;
- + };
- + };
- + };
- sdc2_clk_on: sdc2_clk_on {
- config {
- pins = "sdc2_clk";
- @@ -3200,6 +3266,75 @@
- };
- };
- + fp_mux {
- + fp_active: fp_active {
- + mux {
- + pins = "gpio121";
- + function = "gpio";
- + };
- + config {
- + pins = "gpio121";
- + drive-strength = <8>;
- + bias-disable;
- + };
- + };
- +
- + fp_suspend: fp_suspend {
- + mux {
- + pins = "gpio121";
- + function = "gpio";
- + };
- + config {
- + pins = "gpio121";
- + drive-strength = <2>;
- + bias-disable;
- + };
- + };
- + };
- + /* GPIO_37 : FP_RESET_N */
- + msm_gpio_37: msm_gpio_37 {
- + mux {
- + pins = "gpio37";
- + function = "gpio";
- + };
- +
- + config {
- + pins = "gpio37";
- + drive-strength = <2>;
- + bias-disable;
- + output-low;
- + };
- + };
- +
- + /* GPIO_37 : FP_RESET_N, state device active*/
- + msm_gpio_37_output_high: msm_gpio_37_output_high {
- + mux {
- + pins = "gpio37";
- + function = "gpio";
- + };
- +
- + config {
- + pins = "gpio37";
- + drive-strength = <2>;
- + bias-disable;
- + output-high;
- + };
- + };
- +
- + /* GPIO_121 : FP_INT_N */
- + msm_gpio_121: msm_gpio_121 {
- + mux {
- + pins = "gpio121";
- + function = "gpio";
- + };
- +
- + config {
- + pins = "gpio121";
- + drive-strength = <2>;
- + bias-pull-down;
- + };
- + };
- +
- spkr_1_sd_mediabox {
- spkr_1_sd_sleep_mediabox: spkr_1_sd_sleep_mediabox {
- mux {
- @@ -3254,6 +3389,31 @@
- };
- };
- + gpio_rf {
- + gpio_rf_active: gpio_rf_active {
- + mux {
- + pins = "gpio119";
- + function = "gpio";
- + };
- + config {
- + pins = "gpio119";
- + drive-strength = <2>;
- + bias-disable;
- + };
- + };
- + gpio_rf_suspend: gpio_rf_suspend {
- + mux {
- + pins = "gpio119";
- + function = "gpio";
- + };
- + config {
- + pins = "gpio119";
- + drive-strength = <2>;
- + bias-disable;
- + };
- + };
- + };
- +
- sdc2_cd_on_mediabox: sdc2_cd_on_mediabox {
- mux {
- pins = "gpio86";
- @@ -3279,5 +3439,83 @@
- drive-strength = <2>; /* 2 MA */
- };
- };
- +
- + rcv_id {
- + rcv_id_no_pull: rcv_id_no_pull {
- + mux {
- + pins = "gpio11";
- + function = "gpio";
- + };
- + config {
- + pins = "gpio11";
- + drive-strength = <8>;
- + bias-disable;
- + input-enable;
- + };
- + };
- + rcv_id_pull_up: rcv_id_pull_up {
- + mux {
- + pins = "gpio11";
- + function = "gpio";
- + };
- + config {
- + pins = "gpio11";
- + drive-strength = <8>;
- + bias-pull-up;
- + input-enable;
- + };
- + };
- + rcv_id_pull_down: rcv_id_pull_down {
- + mux {
- + pins = "gpio11";
- + function = "gpio";
- + };
- + config {
- + pins = "gpio11";
- + drive-strength = <8>;
- + bias-pull-down;
- + input-enable;
- + };
- + };
- + };
- +
- + spk_id {
- + spk_id_no_pull: spk_id_no_pull {
- + mux {
- + pins = "gpio100";
- + function = "gpio";
- + };
- + config {
- + pins = "gpio100";
- + drive-strength = <8>;
- + bias-disable;
- + input-enable;
- + };
- + };
- + spk_id_pull_up: spk_id_pull_up {
- + mux {
- + pins = "gpio100";
- + function = "gpio";
- + };
- + config {
- + pins = "gpio100";
- + drive-strength = <8>;
- + bias-pull-up;
- + input-enable;
- + };
- + };
- + spk_id_pull_down: spk_id_pull_down {
- + mux {
- + pins = "gpio100";
- + function = "gpio";
- + };
- + config {
- + pins = "gpio100";
- + drive-strength = <8>;
- + bias-pull-down;
- + input-enable;
- + };
- + };
- + };
- };
- };
- diff --git a/arch/arm/boot/dts/qcom/msm8998-pm.dtsi b/arch/arm/boot/dts/qcom/msm8998-pm.dtsi
- index 8fd75c3..4a0cda6 100644
- --- a/arch/arm/boot/dts/qcom/msm8998-pm.dtsi
- +++ b/arch/arm/boot/dts/qcom/msm8998-pm.dtsi
- @@ -755,6 +755,7 @@
- <16 42>,
- <17 46>,
- <18 50>,
- + <0xff 52>,
- <19 53>,
- <20 54>,
- <21 56>,
- diff --git a/arch/arm/boot/dts/qcom/msm8998-regulator.dtsi b/arch/arm/boot/dts/qcom/msm8998-regulator.dtsi
- index 9307a3b..9ae423f 100644
- --- a/arch/arm/boot/dts/qcom/msm8998-regulator.dtsi
- +++ b/arch/arm/boot/dts/qcom/msm8998-regulator.dtsi
- @@ -1,4 +1,5 @@
- /* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
- + * Copyright (C) 2017 XiaoMi, 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
- @@ -222,8 +223,9 @@
- rpm-regulator-ldoa6 {
- status = "okay";
- pm8998_l6: regulator-l6 {
- - regulator-min-microvolt = <1808000>;
- - regulator-max-microvolt = <1808000>;
- + regulator-min-microvolt = <1800000>;
- + regulator-max-microvolt = <1800000>;
- + qcom,init-ldo-mode = <1>;
- status = "okay";
- };
- };
- @@ -306,8 +308,8 @@
- rpm-regulator-ldoa14 {
- status = "okay";
- pm8998_l14: regulator-l14 {
- - regulator-min-microvolt = <1880000>;
- - regulator-max-microvolt = <1880000>;
- + regulator-min-microvolt = <1800000>;
- + regulator-max-microvolt = <1800000>;
- proxy-supply = <&pm8998_l14>;
- qcom,proxy-consumer-enable;
- qcom,proxy-consumer-current = <32000>;
- @@ -1123,6 +1125,31 @@
- qcom,acc-sel-l1-bit-pos = <0>;
- qcom,acc-sel-l1-bit-size = <1>;
- };
- +
- + disp_vpnl_vreg: disp_vpnl_vreg {
- + compatible = "regulator-fixed";
- + regulator-name = "disp_vpnl_vreg";
- + start-delay-us = <4000>;
- + enable-active-high;
- + gpio = <&tlmm 63 0>;
- + };
- +
- + disp_vddts_vreg: disp_vddts_vreg {
- + compatible = "regulator-fixed";
- + regulator-name = "disp_vddts_vreg";
- + startup-delay-us = <4000>;
- + enable-active-high;
- + regulator-boot-on;
- + gpio = <&tlmm 50 0>;
- + };
- +
- + fp_vdd_vreg: fp_vdd_vreg {
- + compatible = "regulator-fixed";
- + regulator-name = "fp_vdd_vreg";
- + startup-delay-us = <4000>;
- + enable-active-high;
- + gpio = <&tlmm 35 0>;
- + };
- };
- &pmi8998_charger {
- diff --git a/arch/arm/boot/dts/qcom/msm8998-v2.dtsi b/arch/arm/boot/dts/qcom/msm8998-v2.dtsi
- index 8e85640..deff6c3 100644
- --- a/arch/arm/boot/dts/qcom/msm8998-v2.dtsi
- +++ b/arch/arm/boot/dts/qcom/msm8998-v2.dtsi
- @@ -1,4 +1,5 @@
- /* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
- + * Copyright (C) 2017 XiaoMi, 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
- @@ -1117,11 +1118,9 @@
- &qusb_phy0 {
- reg = <0x0c012000 0x2a8>,
- - <0x01fcb24c 0x4>,
- - <0x00784238 0x4>;
- + <0x01fcb24c 0x4>;
- reg-names = "qusb_phy_base",
- - "tcsr_clamp_dig_n_1p8",
- - "efuse_addr";
- + "tcsr_clamp_dig_n_1p8";
- qcom,efuse-bit-pos = <16>;
- qcom,efuse-num-bits = <4>;
- qcom,qusb-phy-init-seq =
- @@ -1199,6 +1198,7 @@
- /* Updated chip ID */
- qcom,chipid = <0x05040001>;
- qcom,initial-pwrlevel = <6>;
- + qcom,restrict-pwrlevel = <1>;
- qcom,gpu-pwrlevels {
- #address-cells = <1>;
- diff --git a/arch/arm/boot/dts/qcom/msm8998.dtsi b/arch/arm/boot/dts/qcom/msm8998.dtsi
- index 4f27b3f..eed82c7 100644
- --- a/arch/arm/boot/dts/qcom/msm8998.dtsi
- +++ b/arch/arm/boot/dts/qcom/msm8998.dtsi
- @@ -1,4 +1,5 @@
- /* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
- + * Copyright (C) 2017 XiaoMi, 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
- @@ -286,40 +287,40 @@
- reg = <0 0x85800000 0 0x3700000>;
- };
- - pil_ipa_gpu_mem: pil_ipa_gpu_region@95200000 {
- + pil_ipa_gpu_mem: pil_ipa_gpu_region@95600000 {
- compatible = "removed-dma-pool";
- no-map;
- - reg = <0 0x95200000 0 0x100000>;
- + reg = <0 0x95600000 0 0x100000>;
- };
- - pil_slpi_mem: pil_slpi_region@94300000 {
- + pil_slpi_mem: pil_slpi_region@94700000 {
- compatible = "removed-dma-pool";
- no-map;
- - reg = <0 0x94300000 0 0xf00000>;
- + reg = <0 0x94700000 0 0xf00000>;
- };
- - pil_mba_mem: pil_mba_region@94100000 {
- + pil_mba_mem: pil_mba_region@94500000 {
- compatible = "removed-dma-pool";
- no-map;
- - reg = <0 0x94100000 0 0x200000>;
- + reg = <0 0x94500000 0 0x200000>;
- };
- - pil_video_mem: pil_video_region@93c00000 {
- + pil_video_mem: pil_video_region@94000000 {
- compatible = "removed-dma-pool";
- no-map;
- - reg = <0 0x93c00000 0 0x500000>;
- + reg = <0 0x94000000 0 0x500000>;
- };
- - modem_mem: modem_region@8cc00000 {
- + modem_mem: modem_region@8d000000 {
- compatible = "removed-dma-pool";
- no-map;
- - reg = <0 0x8cc00000 0 0x7000000>;
- + reg = <0 0x8d000000 0 0x7000000>;
- };
- pil_adsp_mem: pil_adsp_region@0x8b200000 {
- compatible = "removed-dma-pool";
- no-map;
- - reg = <0 0x8b200000 0 0x1a00000>;
- + reg = <0 0x8b200000 0 0x1e00000>;
- };
- spss_mem: spss_region@8ab00000 { /* for SPSS-PIL */
- @@ -1774,6 +1775,7 @@
- snps,has-lpm-erratum;
- snps,hird-threshold = /bits/ 8 <0x10>;
- snps,num-gsi-evt-buffs = <0x3>;
- + maximum-speed = "high-speed";
- };
- qcom,usbbam@a904000 {
- @@ -2292,10 +2294,14 @@
- qcom,sensor-name = "quiet_therm";
- };
- sensor_information28: qcom,sensor-information-28 {
- + qcom,sensor-type = "adc";
- + qcom,sensor-name = "xo_therm";
- + };
- + sensor_information29: qcom,sensor-information-29 {
- qcom,sensor-type = "llm";
- qcom,sensor-name = "limits_sensor-01";
- };
- - sensor_information29: qcom,sensor-information-29 {
- + sensor_information30: qcom,sensor-information-30 {
- qcom,sensor-type = "llm";
- qcom,sensor-name = "limits_sensor-02";
- };
- @@ -2819,8 +2825,8 @@
- reg = <0x17817000 0x1000>;
- reg-names = "wdt-base";
- interrupts = <0 3 0>, <0 4 0>;
- - qcom,bark-time = <11000>;
- - qcom,pet-time = <10000>;
- + qcom,bark-time = <20000>;
- + qcom,pet-time = <15000>;
- qcom,ipi-ping;
- qcom,wakeup-enable;
- qcom,scandump-size = <0x40000>;
- @@ -3252,34 +3258,53 @@
- };
- &gdsc_venus {
- + clock-names = "bus_clk", "maxi_clk", "core_clk";
- + clocks = <&clock_mmss clk_mmss_video_axi_clk>,
- + <&clock_mmss clk_mmss_video_maxi_clk>,
- + <&clock_mmss clk_mmss_video_core_clk>;
- status = "ok";
- };
- &gdsc_venus_core0 {
- + clock-names = "core0_clk";
- + clocks = <&clock_mmss clk_mmss_video_subcore0_clk>;
- status = "ok";
- qcom,support-hw-trigger;
- };
- &gdsc_venus_core1 {
- + clock-names = "core1_clk";
- + clocks = <&clock_mmss clk_mmss_video_subcore1_clk>;
- status = "ok";
- qcom,support-hw-trigger;
- };
- &gdsc_camss_top {
- + ock-names = "bus_clk", "vfe_axi";
- + clocks = <&clock_mmss clk_mmss_camss_cpp_axi_clk>,
- + <&clock_mmss clk_mmss_camss_vfe_vbif_axi_clk>;
- status = "ok";
- };
- &gdsc_vfe0 {
- + clock-names = "core0_clk" , "core0_stream_clk";
- + clocks = <&clock_mmss clk_mmss_camss_vfe0_clk>,
- + <&clock_mmss clk_mmss_camss_vfe0_stream_clk>;
- parent-supply = <&gdsc_camss_top>;
- status = "ok";
- };
- &gdsc_vfe1 {
- + clock-names = "core1_clk" , "core1_stream_clk";
- + clocks = <&clock_mmss clk_mmss_camss_vfe1_clk>,
- + <&clock_mmss clk_mmss_camss_vfe1_stream_clk>;
- parent-supply = <&gdsc_camss_top>;
- status = "ok";
- };
- &gdsc_cpp {
- + clock-names = "core_clk";
- + clocks = <&clock_mmss clk_mmss_camss_cpp_clk>;
- parent-supply = <&gdsc_camss_top>;
- qcom,support-hw-trigger;
- status = "ok";
- diff --git a/arch/arm/boot/dts/qcom/sagit-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/qcom/sagit-camera-sensor-mtp.dtsi
- new file mode 100644
- index 0000000..dc84d6b
- --- /dev/null
- +++ b/arch/arm/boot/dts/qcom/sagit-camera-sensor-mtp.dtsi
- @@ -0,0 +1,478 @@
- +/*
- + * Copyright (c) 2016, The Linux Foundation. All rights reserved.
- + * Copyright (C) 2017 XiaoMi, 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.
- + */
- +
- +&soc {
- + led_flash0: qcom,camera-flash@0 {
- + cell-index = <0>;
- + compatible = "qcom,camera-flash";
- + qcom,flash-source = <&pmi8998_flash0 &pmi8998_flash1>;
- + qcom,torch-source = <&pmi8998_torch0 &pmi8998_torch1>;
- + qcom,switch-source = <&pmi8998_switch0>;
- + status = "ok";
- + };
- +
- + led_flash1: qcom,camera-flash@1 {
- + cell-index = <1>;
- + compatible = "qcom,camera-flash";
- + qcom,flash-source = <&pmi8998_flash2>;
- + qcom,torch-source = <&pmi8998_torch2>;
- + qcom,switch-source = <&pmi8998_switch1>;
- + status = "disable";
- + };
- +
- + vaf_gpio_supply: vaf_gpio_supply {
- + compatible = "regulator-fixed";
- + regulator-name = "vaf_gpio_supply";
- + regulator-min-microvolt = <2800000>;
- + regulator-max-microvolt = <2800000>;
- + startup-delay-us = <4000>;
- + enable-active-high;
- + gpio = <&tlmm 29 0>;
- + };
- +
- + vana_gpio_supply: vana_gpio_supply {
- + compatible = "regulator-fixed";
- + regulator-name = "vana_gpio_supply";
- + regulator-min-microvolt = <2800000>;
- + regulator-max-microvolt = <2800000>;
- + startup-delay-us = <4000>;
- + enable-active-high;
- + gpio = <&tlmm 80 0>;
- + };
- +
- + vdig_gpio_supply: vdig_gpio_supply {
- + compatible = "regulator-fixed";
- + regulator-name = "vdig_gpio_supply";
- + regulator-min-microvolt = <1100000>;
- + regulator-max-microvolt = <1100000>;
- + startup-delay-us = <4000>;
- + enable-active-high;
- + gpio = <&pm8998_gpios 20 0>;
- + };
- +};
- +
- +&cci {
- + actuator0: qcom,actuator@0 {
- + cell-index = <0>;
- + reg = <0x0>;
- + compatible = "qcom,actuator";
- + qcom,cci-master = <0>;
- + cam_vaf-supply = <&vaf_gpio_supply>;
- + qcom,cam-vreg-name = "cam_vaf";
- + qcom,cam-vreg-min-voltage = <2800000>;
- + qcom,cam-vreg-max-voltage = <2800000>;
- + qcom,cam-vreg-op-mode = <100000>;
- + };
- +
- + actuator1: qcom,actuator@1 {
- + cell-index = <1>;
- + reg = <0x1>;
- + compatible = "qcom,actuator";
- + qcom,cci-master = <1>;
- + cam_vaf-supply = <&vaf_gpio_supply>;
- + qcom,cam-vreg-name = "cam_vaf";
- + qcom,cam-vreg-min-voltage = <2800000>;
- + qcom,cam-vreg-max-voltage = <2800000>;
- + qcom,cam-vreg-op-mode = <100000>;
- + };
- +
- + ois0: qcom,ois@0 {
- + cell-index = <0>;
- + reg = <0x0>;
- + compatible = "qcom,ois";
- + qcom,cci-master = <0>;
- + cam_vaf-supply = <&vaf_gpio_supply>;
- + qcom,cam-vreg-name = "cam_vaf";
- + qcom,cam-vreg-min-voltage = <2800000>;
- + qcom,cam-vreg-max-voltage = <2800000>;
- + qcom,cam-vreg-op-mode = <100000>;
- + };
- +
- + eeprom0: qcom,eeprom@0 {
- + cell-index = <0>;
- + reg = <0>;
- + qcom,eeprom-name = "sagit_imx386_semco";
- + compatible = "qcom,eeprom";
- + qcom,slave-addr = <0xa0>;
- + qcom,i2c-freq-mode = <1>;
- + qcom,num-blocks = <1>;
- + qcom,page0 = <0 0 0 0 0 0>;
- + qcom,poll0 = <0 0 0 0 0 0>;
- + qcom,mem0 = <7039 0x00 2 0 1 0>;
- + cam_vio-supply = <&pm8998_lvs1>;
- + cam_vdig-supply = <&vdig_gpio_supply>;
- + cam_vana-supply = <&vana_gpio_supply>;
- + qcom,cam-vreg-name = "cam_vio", "cam_vdig", "cam_vana";
- + qcom,cam-vreg-min-voltage = <0 1000000 2600000>;
- + qcom,cam-vreg-max-voltage = <0 1200000 2900000>;
- + qcom,cam-vreg-op-mode = <0 1100000 2800000>;
- + qcom,cam-power-seq-type = "sensor_vreg";
- + qcom,cam-power-seq-val = "cam_vio";
- + qcom,cam-power-seq-cfg-val = <1>;
- + qcom,cam-power-seq-delay = <1>;
- + qcom,gpio-no-mux = <0>;
- + pinctrl-names = "cam_default", "cam_suspend";
- + pinctrl-0 = <&cam_sensor_mclk0_active
- + &cam_sensor_rear_active>;
- + pinctrl-1 = <&cam_sensor_mclk0_suspend
- + &cam_sensor_rear_suspend>;
- + gpios = <&tlmm 13 0>,
- + <&tlmm 30 0>;
- + qcom,gpio-reset = <1>;
- + qcom,gpio-req-tbl-num = <0 1>;
- + qcom,gpio-req-tbl-flags = <1 0>;
- + qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
- + "CAM_RESET0";
- + qcom,sensor-position = <0>;
- + qcom,sensor-mode = <0>;
- + qcom,cci-master = <0>;
- + status = "ok";
- + clocks = <&clock_mmss clk_mclk0_clk_src>,
- + <&clock_mmss clk_mmss_camss_mclk0_clk>;
- + clock-names = "cam_src_clk", "cam_clk";
- + qcom,clock-rates = <24000000 0>;
- + };
- +
- + eeprom1: qcom,eeprom@1 {
- + cell-index = <1>;
- + reg = <1>;
- + qcom,eeprom-name = "sagit_s5k3m3_semco";
- + compatible = "qcom,eeprom";
- + qcom,slave-addr = <0xa0>;
- + qcom,i2c-freq-mode = <1>;
- + qcom,num-blocks = <1>;
- + qcom,page0 = <0 0 0 0 0 0>;
- + qcom,poll0 = <0 0 0 0 0 0>;
- + qcom,mem0 = <4912 0x00 2 0 1 0>;
- + cam_vio-supply = <&pm8998_lvs1>;
- + cam_vdig-supply = <&vdig_gpio_supply>;
- + cam_vana-supply = <&vana_gpio_supply>;
- + qcom,cam-vreg-name = "cam_vio", "cam_vdig", "cam_vana";
- + qcom,cam-vreg-min-voltage = <0 1000000 2800000>;
- + qcom,cam-vreg-max-voltage = <0 1100000 2800000>;
- + qcom,cam-vreg-op-mode = <0 1100000 2800000>;
- + qcom,cam-power-seq-type = "sensor_vreg";
- + qcom,cam-power-seq-val = "cam_vio";
- + qcom,cam-power-seq-cfg-val = <1>;
- + qcom,cam-power-seq-delay = <1>;
- + qcom,gpio-no-mux = <0>;
- + pinctrl-names = "cam_default", "cam_suspend";
- + pinctrl-0 = <&cam_sensor_mclk0_active
- + &cam_sensor_rear_active>;
- + pinctrl-1 = <&cam_sensor_mclk0_suspend
- + &cam_sensor_rear_suspend>;
- + gpios = <&tlmm 13 0>,
- + <&tlmm 30 0>;
- + qcom,gpio-reset = <1>;
- + qcom,gpio-req-tbl-num = <0 1>;
- + qcom,gpio-req-tbl-flags = <1 0>;
- + qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
- + "CAM_RESET0";
- + qcom,sensor-position = <0>;
- + qcom,sensor-mode = <0>;
- + qcom,cci-master = <0>;
- + status = "ok";
- + clocks = <&clock_mmss clk_mclk0_clk_src>,
- + <&clock_mmss clk_mmss_camss_mclk0_clk>;
- + clock-names = "cam_src_clk", "cam_clk";
- + qcom,clock-rates = <24000000 0>;
- + };
- +
- + eeprom2: qcom,eeprom@2 {
- + cell-index = <2>;
- + reg = <0x2>;
- + qcom,eeprom-name = "sagit_imx268_primax";
- + compatible = "qcom,eeprom";
- + qcom,slave-addr = <0x34>;
- + qcom,i2c-freq-mode = <1>;
- + qcom,num-blocks = <4>;
- + qcom,saddr0 = <0x34>;
- + qcom,page0 = <1 0x0A02 2 0x00 1 0>;
- + qcom,pageen0 = <1 0x0A00 2 0x01 1 0>;
- + qcom,poll0 = <0 0x0 0 0x0 0 0>;
- + qcom,mem0 = <64 0x0A04 2 0 1 0>;
- +
- + qcom,saddr1 = <0x34>;
- + qcom,page1 = <1 0x0A02 2 0x01 1 0>;
- + qcom,pageen1 = <1 0x0A00 2 0x01 1 0>;
- + qcom,poll1 = <0 0x0 0 0x0 0 0>;
- + qcom,mem1 = <64 0x0A04 2 0 1 0>;
- +
- + qcom,saddr2 = <0x34>;
- + qcom,page2 = <1 0x0A02 2 0x02 1 0>;
- + qcom,pageen2 = <1 0x0A00 2 0x01 1 0>;
- + qcom,poll2 = <0 0x0 0 0x0 0 0>;
- + qcom,mem2 = <64 0x0A04 2 0 1 0>;
- +
- + qcom,saddr3 = <0x34>;
- + qcom,page3 = <1 0x0A02 2 0x03 1 0>;
- + qcom,pageen3 = <0 0x0A00 2 0x01 1 0>;
- + qcom,poll3 = <0 0x0 0 0x0 0 0>;
- + qcom,mem3 = <64 0x0A04 2 0 1 0>;
- +
- + cam_vio-supply = <&pm8998_lvs1>;
- + cam_vana-supply = <&pm8998_l22>;
- + qcom,cam-vreg-name = "cam_vio", "cam_vana";
- + qcom,cam-vreg-min-voltage = <0 2864000>;
- + qcom,cam-vreg-max-voltage = <0 2864000>;
- + qcom,cam-vreg-op-mode = <0 80000>;
- + qcom,cam-power-seq-type = "sensor_gpio", "sensor_gpio", "sensor_gpio", "sensor_vreg", "sensor_vreg", "sensor_clk", "sensor_gpio", "sensor_gpio";
- + qcom,cam-power-seq-val = "sensor_gpio_reset","sensor_gpio_standby", "sensor_gpio_vdig", "cam_vio", "cam_vana", "sensor_cam_mclk", "sensor_gpio_reset","sensor_gpio_standby";
- + qcom,cam-power-seq-cfg-val = <0 0 1 1 2864000 24000000 1 1>;
- + qcom,cam-power-seq-delay = <1 1 1 1 1 1 1 1>;
- + qcom,gpio-no-mux = <0>;
- + pinctrl-names = "cam_default", "cam_suspend";
- + pinctrl-0 = <&cam_sensor_mclk1_active
- + &cam_sensor_front_active>;
- + pinctrl-1 = <&cam_sensor_mclk1_suspend
- + &cam_sensor_front_suspend>;
- + gpios = <&tlmm 14 0>,
- + <&tlmm 27 0>,
- + <&tlmm 28 0>,
- + <&pm8998_gpios 9 0>;
- + qcom,gpio-standby = <1>;
- + qcom,gpio-reset = <2>;
- + qcom,gpio-vdig = <3>;
- + qcom,gpio-req-tbl-num = <0 1 2 3>;
- + qcom,gpio-req-tbl-flags = <1 0 0 0>;
- + qcom,gpio-req-tbl-label = "CAMIF_MCLK1",
- + "CAM_STANDBY1",
- + "CAM_RESET1",
- + "CAM_VDIG";
- + qcom,cci-master = <1>;
- + status = "ok";
- +
- + clocks = <&clock_mmss clk_mclk1_clk_src>,
- + <&clock_mmss clk_mmss_camss_mclk1_clk>;
- + clock-names = "cam_src_clk", "cam_clk";
- + qcom,clock-rates = <24000000 0>;
- + };
- +
- + eeprom3: qcom,eeprom@3 {
- + cell-index = <3>;
- + reg = <0x3>;
- + qcom,eeprom-name = "sagit_imx268_liteon";
- + compatible = "qcom,eeprom";
- + qcom,slave-addr = <0x34>;
- + qcom,i2c-freq-mode = <1>;
- + qcom,num-blocks = <4>;
- + qcom,saddr0 = <0x34>;
- + qcom,page0 = <1 0x0A02 2 0x00 1 0>;
- + qcom,pageen0 = <1 0x0A00 2 0x01 1 0>;
- + qcom,poll0 = <0 0x0 0 0x0 0 0>;
- + qcom,mem0 = <64 0x0A04 2 0 1 0>;
- +
- + qcom,saddr1 = <0x34>;
- + qcom,page1 = <1 0x0A02 2 0x01 1 0>;
- + qcom,pageen1 = <1 0x0A00 2 0x01 1 0>;
- + qcom,poll1 = <0 0x0 0 0x0 0 0>;
- + qcom,mem1 = <64 0x0A04 2 0 1 0>;
- +
- + qcom,saddr2 = <0x34>;
- + qcom,page2 = <1 0x0A02 2 0x02 1 0>;
- + qcom,pageen2 = <1 0x0A00 2 0x01 1 0>;
- + qcom,poll2 = <0 0x0 0 0x0 0 0>;
- + qcom,mem2 = <64 0x0A04 2 0 1 0>;
- +
- + qcom,saddr3 = <0x34>;
- + qcom,page3 = <1 0x0A02 2 0x03 1 0>;
- + qcom,pageen3 = <0 0x0A00 2 0x01 1 0>;
- + qcom,poll3 = <0 0x0 0 0x0 0 0>;
- + qcom,mem3 = <64 0x0A04 2 0 1 0>;
- +
- + cam_vio-supply = <&pm8998_lvs1>;
- + cam_vana-supply = <&pm8998_l22>;
- + qcom,cam-vreg-name = "cam_vio", "cam_vana";
- + qcom,cam-vreg-min-voltage = <0 2864000>;
- + qcom,cam-vreg-max-voltage = <0 2864000>;
- + qcom,cam-vreg-op-mode = <0 80000>;
- + qcom,cam-power-seq-type = "sensor_gpio", "sensor_gpio", "sensor_gpio", "sensor_vreg", "sensor_vreg", "sensor_clk", "sensor_gpio", "sensor_gpio";
- + qcom,cam-power-seq-val = "sensor_gpio_reset","sensor_gpio_standby", "sensor_gpio_vdig", "cam_vio", "cam_vana", "sensor_cam_mclk", "sensor_gpio_reset","sensor_gpio_standby";
- + qcom,cam-power-seq-cfg-val = <0 0 1 1 2864000 24000000 1 1>;
- + qcom,cam-power-seq-delay = <1 1 1 1 1 1 1 1>;
- + qcom,gpio-no-mux = <0>;
- + pinctrl-names = "cam_default", "cam_suspend";
- + pinctrl-0 = <&cam_sensor_mclk1_active
- + &cam_sensor_front_active>;
- + pinctrl-1 = <&cam_sensor_mclk1_suspend
- + &cam_sensor_front_suspend>;
- + gpios = <&tlmm 14 0>,
- + <&tlmm 27 0>,
- + <&tlmm 28 0>,
- + <&pm8998_gpios 9 0>;
- + qcom,gpio-standby = <1>;
- + qcom,gpio-reset = <2>;
- + qcom,gpio-vdig = <3>;
- + qcom,gpio-req-tbl-num = <0 1 2 3>;
- + qcom,gpio-req-tbl-flags = <1 0 0 0>;
- + qcom,gpio-req-tbl-label = "CAMIF_MCLK1",
- + "CAM_STANDBY1",
- + "CAM_RESET1",
- + "CAM_VDIG";
- + qcom,cci-master = <1>;
- + status = "ok";
- +
- + clocks = <&clock_mmss clk_mclk1_clk_src>,
- + <&clock_mmss clk_mmss_camss_mclk1_clk>;
- + clock-names = "cam_src_clk", "cam_clk";
- + qcom,clock-rates = <24000000 0>;
- + };
- +
- + qcom,camera@0 {
- + cell-index = <0>;
- + compatible = "qcom,camera";
- + reg = <0x0>;
- + qcom,csiphy-sd-index = <0>;
- + qcom,csid-sd-index = <0>;
- + qcom,mount-angle = <90>;
- + qcom,led-flash-src = <&led_flash0>;
- + qcom,actuator-src = <&actuator0>;
- + qcom,eeprom-src = <&eeprom0>;
- + qcom,ois-src = <&ois0>;
- + cam_vio-supply = <&pm8998_lvs1>;
- + cam_vdig-supply = <&vdig_gpio_supply>;
- + cam_vana-supply = <&vana_gpio_supply>;
- + qcom,cam-vreg-name = "cam_vio", "cam_vdig", "cam_vana";
- + qcom,cam-vreg-min-voltage = <0 1000000 2600000>;
- + qcom,cam-vreg-max-voltage = <0 1200000 2900000>;
- + qcom,cam-vreg-op-mode = <0 1100000 2800000>;
- + qcom,gpio-no-mux = <0>;
- + pinctrl-names = "cam_default", "cam_suspend";
- + pinctrl-0 = <&cam_sensor_mclk0_active
- + &cam_sensor_rear_active>;
- + pinctrl-1 = <&cam_sensor_mclk0_suspend
- + &cam_sensor_rear_suspend>;
- + gpios = <&tlmm 13 0>,
- + <&tlmm 30 0>;
- + qcom,gpio-reset = <1>;
- + qcom,gpio-req-tbl-num = <0 1>;
- + qcom,gpio-req-tbl-flags = <1 0>;
- + qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
- + "CAM_RESET0";
- + qcom,sensor-position = <0>;
- + qcom,sensor-mode = <0>;
- + qcom,cci-master = <0>;
- + status = "ok";
- + clocks = <&clock_mmss clk_mclk0_clk_src>,
- + <&clock_mmss clk_mmss_camss_mclk0_clk>;
- + clock-names = "cam_src_clk", "cam_clk";
- + qcom,clock-rates = <24000000 0>;
- + };
- +
- + qcom,camera@1 {
- + cell-index = <1>;
- + compatible = "qcom,camera";
- + reg = <0x1>;
- + qcom,csiphy-sd-index = <2>;
- + qcom,csid-sd-index = <2>;
- + qcom,mount-angle = <90>;
- + qcom,led-flash-src = <&led_flash0>;
- + qcom,actuator-src = <&actuator1>;
- + qcom,eeprom-src = <&eeprom1>;
- + cam_vio-supply = <&pm8998_lvs1>;
- + cam_vdig-supply = <&vdig_gpio_supply>;
- + cam_vana-supply = <&vana_gpio_supply>;
- + qcom,cam-vreg-name = "cam_vio", "cam_vdig", "cam_vana";
- + qcom,cam-vreg-min-voltage = <0 1000000 2800000>;
- + qcom,cam-vreg-max-voltage = <0 1100000 2800000>;
- + qcom,cam-vreg-op-mode = <0 1100000 2800000>;
- + qcom,gpio-no-mux = <0>;
- + pinctrl-names = "cam_default", "cam_suspend";
- + pinctrl-0 = <&cam_sensor_mclk2_active
- + &cam_sensor_rear2_active>;
- + pinctrl-1 = <&cam_sensor_mclk2_suspend
- + &cam_sensor_rear2_suspend>;
- + gpios = <&tlmm 15 0>,
- + <&tlmm 9 0>;
- + qcom,gpio-reset = <1>;
- + qcom,gpio-req-tbl-num = <0 1>;
- + qcom,gpio-req-tbl-flags = <1 0>;
- + qcom,gpio-req-tbl-label = "CAMIF_MCLK2",
- + "CAM_RESET2";
- + qcom,sensor-position = <0>;
- + qcom,sensor-mode = <0>;
- + qcom,cci-master = <1>;
- + status = "ok";
- + clocks = <&clock_mmss clk_mclk2_clk_src>,
- + <&clock_mmss clk_mmss_camss_mclk2_clk>;
- + clock-names = "cam_src_clk", "cam_clk";
- + qcom,clock-rates = <24000000 0>;
- + };
- +
- + qcom,camera@2 {
- + cell-index = <2>;
- + compatible = "qcom,camera";
- + reg = <0x02>;
- + qcom,csiphy-sd-index = <1>;
- + qcom,csid-sd-index = <1>;
- + qcom,mount-angle = <270>;
- + qcom,eeprom-src = <&eeprom2 &eeprom3>;
- + cam_vio-supply = <&pm8998_lvs1>;
- + cam_vana-supply = <&pm8998_l22>;
- + qcom,cam-vreg-name = "cam_vio", "cam_vana";
- + qcom,cam-vreg-min-voltage =
- + <0 2864000>;
- + qcom,cam-vreg-max-voltage =
- + <0 2864000>;
- + qcom,cam-vreg-op-mode = <0 80000>;
- + qcom,gpio-no-mux = <0>;
- + pinctrl-names = "cam_default", "cam_suspend";
- + pinctrl-0 = <&cam_sensor_mclk1_active
- + &cam_sensor_front_active>;
- + pinctrl-1 = <&cam_sensor_mclk1_suspend
- + &cam_sensor_front_suspend>;
- + gpios = <&tlmm 14 0>,
- + <&tlmm 27 0>,
- + <&tlmm 28 0>,
- + <&pm8998_gpios 9 0>;
- + qcom,gpio-standby = <1>;
- + qcom,gpio-reset = <2>;
- + qcom,gpio-vdig = <3>;
- + qcom,gpio-req-tbl-num = <0 1 2 3>;
- + qcom,gpio-req-tbl-flags = <1 0 0 0>;
- + qcom,gpio-req-tbl-label = "CAMIF_MCLK1",
- + "CAM_STANDBY1",
- + "CAM_RESET1",
- + "CAM_VDIG";
- + qcom,sensor-position = <1>;
- + qcom,sensor-mode = <0>;
- + qcom,cci-master = <1>;
- + status = "ok";
- + clocks = <&clock_mmss clk_mclk1_clk_src>,
- + <&clock_mmss clk_mmss_camss_mclk1_clk>;
- + clock-names = "cam_src_clk", "cam_clk";
- + qcom,clock-rates = <24000000 0>;
- + };
- +};
- +&pm8998_gpios {
- + gpio@c800 { /* GPIO 9 - CAMERA SENSOR 2 VDIG */
- + qcom,mode = <1>; /* Output */
- + qcom,pull = <5>; /* No Pull */
- + qcom,vin-sel = <0>; /* VIN1 GPIO_LV */
- + qcom,src-sel = <0>; /* GPIO */
- + qcom,invert = <0>; /* Invert */
- + qcom,master-en = <1>; /* Enable GPIO */
- + status = "ok";
- + };
- +
- + gpio@d300 { /* GPIO 20 - CAMERA SENSOR 0 VDIG */
- + qcom,mode = <1>; /* Output */
- + qcom,pull = <5>; /* No Pull */
- + qcom,vin-sel = <1>; /* VIN1 GPIO_MV */
- + qcom,src-sel = <0>; /* GPIO */
- + qcom,invert = <0>; /* Invert */
- + qcom,master-en = <1>; /* Enable GPIO */
- + status = "ok";
- + };
- +};
- diff --git a/arch/arm/boot/dts/qcom/sagit-msm8998-mtp.dts b/arch/arm/boot/dts/qcom/sagit-msm8998-mtp.dts
- new file mode 100644
- index 0000000..acf0942
- --- /dev/null
- +++ b/arch/arm/boot/dts/qcom/sagit-msm8998-mtp.dts
- @@ -0,0 +1,39 @@
- +/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
- + * Copyright (C) 2017 XiaoMi, 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.
- + */
- +
- +
- +/dts-v1/;
- +
- +#include "msm8998.dtsi"
- +#include "sagit-msm8998-mtp.dtsi"
- +
- +/ {
- + model = "Qualcomm Technologies, Inc. MSM 8998 v1 MTP";
- + compatible = "qcom,msm8998-mtp", "qcom,msm8998", "qcom,mtp";
- + qcom,board-id = <30 0>;
- +};
- +
- +&qusb_phy0 {
- + qcom,qusb-phy-host-init-seq =
- + /* value reg_offsets> */
- + <0x63 0x210
- + 0x13 0x04
- + 0x7c 0x18c
- + 0x80 0x2c
- + 0x0a 0x184
- + 0x8c 0x21c
- + 0x05 0x23c
- + 0x03 0x240
- + 0xff 0x218
- + 0x62 0x210>;
- +};
- diff --git a/arch/arm/boot/dts/qcom/sagit-msm8998-mtp.dtsi b/arch/arm/boot/dts/qcom/sagit-msm8998-mtp.dtsi
- new file mode 100644
- index 0000000..92c3252
- --- /dev/null
- +++ b/arch/arm/boot/dts/qcom/sagit-msm8998-mtp.dtsi
- @@ -0,0 +1,944 @@
- +/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
- + * Copyright (C) 2017 XiaoMi, 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.
- + */
- +
- +#include <dt-bindings/interrupt-controller/irq.h>
- +#include "msm8998-pinctrl.dtsi"
- +#include "sagit-camera-sensor-mtp.dtsi"
- +/ {
- + bluetooth: bt_wcn3990 {
- + compatible = "qca,wcn3990";
- + qca,bt-vdd-io-supply = <&pm8998_s3>;
- + qca,bt-vdd-xtal-supply = <&pm8998_s5>;
- + qca,bt-vdd-core-supply = <&pm8998_l7>;
- + qca,bt-vdd-pa-supply = <&pm8998_l17>;
- + qca,bt-vdd-ldo-supply = <&pm8998_l25>;
- + qca,bt-chip-pwd-supply = <&pmi8998_bob_pin1>;
- + clocks = <&clock_gcc clk_rf_clk2_pin>;
- + clock-names = "rf_clk2";
- +
- + qca,bt-vdd-io-voltage-level = <1352000 1352000>;
- + qca,bt-vdd-xtal-voltage-level = <2040000 2040000>;
- + qca,bt-vdd-core-voltage-level = <1800000 1800000>;
- + qca,bt-vdd-pa-voltage-level = <1304000 1304000>;
- + qca,bt-vdd-ldo-voltage-level = <3312000 3312000>;
- + qca,bt-chip-pwd-voltage-level = <3600000 3600000>;
- +
- + qca,bt-vdd-io-current-level = <1>; /* LPM/PFM */
- + qca,bt-vdd-xtal-current-level = <1>; /* LPM/PFM */
- + qca,bt-vdd-core-current-level = <1>; /* LPM/PFM */
- + qca,bt-vdd-pa-current-level = <1>; /* LPM/PFM */
- + qca,bt-vdd-ldo-current-level = <1>; /* LPM/PFM */
- + };
- +};
- +
- +&blsp1_uart3_hs {
- + status = "ok";
- +};
- +
- +&ufsphy1 {
- + vdda-phy-supply = <&pm8998_l1>;
- + vdda-pll-supply = <&pm8998_l2>;
- + vddp-ref-clk-supply = <&pm8998_l26>;
- + vdda-phy-max-microamp = <51400>;
- + vdda-pll-max-microamp = <14600>;
- + vddp-ref-clk-max-microamp = <100>;
- + vddp-ref-clk-always-on;
- + status = "ok";
- +};
- +
- +&ufs1 {
- + vdd-hba-supply = <&gdsc_ufs>;
- + vdd-hba-fixed-regulator;
- + vcc-supply = <&pm8998_l20>;
- + vccq-supply = <&pm8998_l26>;
- + vccq2-supply = <&pm8998_s4>;
- + vcc-max-microamp = <750000>;
- + vccq-max-microamp = <560000>;
- + vccq2-max-microamp = <750000>;
- + status = "ok";
- +};
- +
- +&ufs_ice {
- + status = "ok";
- +};
- +
- +&sdhc_2 {
- + vdd-supply = <&pm8998_l21>;
- + qcom,vdd-voltage-level = <2950000 2960000>;
- + qcom,vdd-current-level = <200 800000>;
- +
- + vdd-io-supply = <&pm8998_l13>;
- + qcom,vdd-io-voltage-level = <1808000 2960000>;
- + qcom,vdd-io-current-level = <200 22000>;
- +
- + pinctrl-names = "active", "sleep";
- + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>;
- + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>;
- +
- + qcom,clk-rates = <400000 20000000 25000000
- + 50000000 100000000 200000000>;
- + qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
- +
- + cd-gpios = <&tlmm 95 0x1>;
- +
- + status = "ok";
- +};
- +
- +&uartblsp2dm1 {
- + status = "ok";
- + pinctrl-names = "default";
- + pinctrl-0 = <&uart_console_active>;
- +};
- +
- +&pm8998_gpios {
- + /* GPIO 6 for Vol+ Key */
- + gpio@c500 {
- + status = "okay";
- + qcom,mode = <0>;
- + qcom,pull = <0>;
- + qcom,vin-sel = <0>;
- + qcom,src-sel = <0>;
- + qcom,out-strength = <1>;
- + };
- +
- + /* GPIO 7 for Snapshot Key */
- + gpio@c600 {
- + status = "okay";
- + qcom,mode = <0>;
- + qcom,pull = <0>;
- + qcom,vin-sel = <0>;
- + qcom,src-sel = <0>;
- + qcom,out-strength = <1>;
- + };
- +
- + /* GPIO 8 for Focus Key */
- + gpio@c700 {
- + status = "okay";
- + qcom,mode = <0>;
- + qcom,pull = <0>;
- + qcom,vin-sel = <0>;
- + qcom,src-sel = <0>;
- + qcom,out-strength = <1>;
- + };
- +
- + gpio@cc00 { /* GPIO 13 */
- + qcom,mode = <1>;
- + qcom,output-type = <0>;
- + qcom,pull = <5>;
- + qcom,vin-sel = <0>;
- + qcom,out-strength = <1>;
- + qcom,src-sel = <3>;
- + qcom,master-en = <1>;
- + status = "okay";
- + };
- +
- + /* GPIO 21 (NFC_CLK_REQ) */
- + gpio@d400 {
- + qcom,mode = <0>;
- + qcom,vin-sel = <1>;
- + qcom,src-sel = <0>;
- + qcom,master-en = <1>;
- + status = "okay";
- + };
- +
- + /* GPIO 18 SMB138X */
- + gpio@d100 {
- + qcom,mode = <0>;
- + qcom,pull = <0>;
- + qcom,vin-sel = <0>;
- + qcom,src-sel = <0>;
- + qcom,master-en = <1>;
- + status = "okay";
- + };
- +};
- +
- +&pmi8998_gpios {
- + /* GPIO 3 for NS5S1153 AUDIO_SEL pin */
- + gpio@c200 {
- + status = "okay";
- + qcom,mode = <1>; /* Digital out */
- + qcom,pull = <5>; /* No pull */
- + qcom,vin-sel = <1>; /* 1.8v */
- + qcom,src-sel = <0>;
- + qcom,out-strength = <1>;
- + qcom,master-en = <1>;
- + };
- +
- + /* GPIO 5 for INFARED_DRV */
- + gpio@c400 {
- + status = "okay";
- + qcom,mode = <1>; /* QPNP_PIN_MODE_DIG_OUT */
- + qcom,pull = <4>; /*PULL DOWN 10uA*/
- + qcom,src-sel = <2>; /*SPECIAL FUNCTION 1*/
- + qcom,master-en = <1>; /*ENABLE GPIO*/
- + qcom,out-strength = <2>; /*Medium strength current*/
- + };
- +
- + /* GPIO 6 for the internal QNOVO discharge FET control signal */
- + gpio@c500 {
- + status = "okay";
- + qcom,mode = <1>;
- + qcom,pull = <5>;
- + qcom,vin-sel = <0>;
- + qcom,src-sel = <2>;
- + qcom,out-strength = <1>;
- + qcom,master-en = <1>;
- + };
- +};
- +
- +&i2c_5 {
- + status = "okay";
- + synaptics_dsi_i2c@20 {
- + compatible = "synaptics,dsx-i2c-force";
- + reg = <0x20>;
- + interrupt-parent = <&tlmm>;
- + interrupts = <125 0x2008>;
- + vdd-supply = <&pm8998_l6>;
- + lab-supply = <&lab_regulator>;
- + ibb-supply = <&ibb_regulator>;
- + disp-supply = <&pm8998_l14>;
- + avdd-supply = <&disp_vddts_vreg>;
- + synaptics,pwr-reg-name = "vdd";
- + synaptics,lab-reg-name = "lab";
- + synaptics,ibb-reg-name = "ibb";
- + synaptics,disp-reg-name = "disp";
- + synaptics,bus-reg-name = "avdd";
- + synaptics,ub-i2c-addr = <0x2c>;
- + pinctrl-names = "pmx_ts_active", "pmx_ts_suspend";
- + pinctrl-0 = <&ts_active>;
- + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>;
- + synaptics,mdss-dsi-reset = <&tlmm 8 0>;
- + synaptics,reset-gpio = <&tlmm 89 0x00>;
- + synaptics,irq-gpio = <&tlmm 125 0x2008>;
- + synaptics,reset-gpio-name = "dsx_reset";
- + synaptics,irq-gpio-name = "dsx_irq";
- + synaptics,irq-on-state = <0>;
- + synaptics,irq-flags = <0x2008>; /* IRQF_ONESHOT | IRQF_TRIGGER_LOW */
- + synaptics,power-delay-ms = <5>;
- + synaptics,reset-delay-ms = <200>;
- + synaptics,reset-active-ms = <5>;
- + synaptics,power-on-state = <1>;
- + synaptics,reset-on-state = <0>;
- + synaptics,mdss-reset-state = <1>;
- + synaptics,panel-is-incell;
- + synaptics,cap-button-codes = <158 139 102>;
- + synaptics,short-jdi-25 = "000: 0xfb\n001: 0xef\n002: 0xff\n003: 0xff\n004: 0x18\n005: 0x00\n006: 0x00";
- + synaptics,short-jdi-26 = "000: 0x03\n001: 0x00\n002: 0x00\n003: 0x00\n004: 0x00\n005: 0x00\n006: 0x00";
- + clock-names = "iface_clk", "core_clk";
- + clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
- + <&clock_gcc clk_gcc_blsp1_qup5_i2c_apps_clk>;
- + synaptics,guest-serialization-as-lockdown;
- + synaptics,tp-id-byte = /bits/ 8 <0>;
- + synaptics,config-array-size = <3>;
- + synaptics,cfg_1 {
- + synaptics,chip-id = <0>;
- + synaptics,chip-id-name = "S3330";
- + synaptics,tp-id = /bits/ 8 <0x31>;
- + synaptics,fw-name = "synaptics_jdi_3330_c1.fw";
- + };
- + synaptics,cfg_2 {
- + synaptics,chip-id = <1>;
- + synaptics,chip-id-name = "S3331";
- + synaptics,tp-id = /bits/ 8 <0x31>;
- + synaptics,fw-name = "synaptics_jdi_3331_c1.fw";
- + };
- + synaptics,cfg_3 {
- + synaptics,chip-id = <2>;
- + synaptics,chip-id-name = "TD4322";
- + synaptics,chip-is-tddi;
- + synaptics,disp-pre-on-sleep = <10>;
- + synaptics,disp-post-on-sleep = <10>;
- + synaptics,disp-pre-off-sleep = <10>;
- + synaptics,disp-post-off-sleep = <0>;
- + synaptics,lab-pre-on-sleep = <0>;
- + synaptics,lab-post-on-sleep = <10>;
- + synaptics,lab-pre-off-sleep = <10>;
- + synaptics,lab-post-off-sleep = <0>;
- + synaptics,ibb-pre-on-sleep = <0>;
- + synaptics,ibb-post-on-sleep = <10>;
- + synaptics,ibb-pre-off-sleep = <10>;
- + synaptics,ibb-post-off-sleep = <0>;
- + synaptics,tp-id = /bits/ 8 <0x34>;
- + synaptics,fw-name = "synaptics_lgd_4322_c1.fw";
- + };
- + };
- +};
- +
- +&i2c_6 { /* BLSP1 QUP6 (NFC) */
- + status = "okay";
- + nq@28 {
- + compatible = "qcom,nq-nci";
- + reg = <0x28>;
- + qcom,nq-irq = <&tlmm 92 0x00>;
- + qcom,nq-ven = <&tlmm 12 0x00>;
- + qcom,nq-firm = <&tlmm 93 0x00>;
- + qcom,nq-clkreq = <&pm8998_gpios 21 0x00>;
- + qcom,nq-esepwr = <&tlmm 116 0x00>;
- + interrupt-parent = <&tlmm>;
- + qcom,clk-src = "BBCLK3";
- + interrupts = <92 0>;
- + interrupt-names = "nfc_irq";
- + pinctrl-names = "nfc_active", "nfc_suspend";
- + pinctrl-0 = <&nfc_int_active &nfc_enable_active>;
- + pinctrl-1 = <&nfc_int_suspend &nfc_enable_suspend>;
- + clocks = <&clock_gcc clk_ln_bb_clk3_pin>;
- + clock-names = "ref_clk";
- + };
- +};
- +
- +&i2c_10 { /* BLSP2 QUP4 (Speaker Smart PA)*/
- + status = "okay";
- + tfa98xx@34 {
- + compatible = "nxp,tfa98xx";
- + reg = <0x34>;
- + reset-gpio = <&tlmm 41 0>;
- + irq-gpio = <&tlmm 42 0>;
- + spk-id = <&spk_id_pin>;
- + };
- +};
- +
- +&mdss_hdmi_tx {
- + status = "disabled";
- + pinctrl-names = "hdmi_hpd_active", "hdmi_ddc_active", "hdmi_cec_active",
- + "hdmi_active", "hdmi_sleep";
- + pinctrl-0 = <&mdss_hdmi_5v_active &mdss_hdmi_hpd_active
- + &mdss_hdmi_ddc_suspend &mdss_hdmi_cec_suspend>;
- + pinctrl-1 = <&mdss_hdmi_5v_active &mdss_hdmi_hpd_active
- + &mdss_hdmi_ddc_active &mdss_hdmi_cec_suspend>;
- + pinctrl-2 = <&mdss_hdmi_5v_active &mdss_hdmi_hpd_active
- + &mdss_hdmi_cec_active &mdss_hdmi_ddc_suspend>;
- + pinctrl-3 = <&mdss_hdmi_5v_active &mdss_hdmi_hpd_active
- + &mdss_hdmi_ddc_active &mdss_hdmi_cec_active>;
- + pinctrl-4 = <&mdss_hdmi_5v_suspend &mdss_hdmi_hpd_suspend
- + &mdss_hdmi_ddc_suspend &mdss_hdmi_cec_suspend>;
- +};
- +
- +&mdss_hdmi_pll {
- + status = "disabled";
- +};
- +
- +&mdss_mdp {
- + qcom,mdss-pref-prim-intf = "dsi";
- +};
- +
- +&mdss_dsi {
- + hw-config = "single_dsi";
- +};
- +
- +&mdss_dsi0 {
- + qcom,dsi-pref-prim-pan = <&dsi_jdi_fhd_r63452_cmd>;
- + pinctrl-names = "mdss_default", "mdss_sleep";
- + pinctrl-0 = <&mdss_dsi_active &mdss_te_active>;
- + pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>;
- + qcom,platform-reset-gpio = <&tlmm 94 0>;
- + qcom,platform-te-gpio = <&tlmm 10 0>;
- + qcom,panel-mode-gpio = <&tlmm 91 0>;
- +};
- +
- +&mdss_dsi1 {
- + status = "disabled";
- +};
- +
- +&mdss_dsi1_pll {
- + status = "disabled";
- +};
- +
- +&labibb {
- + status = "ok";
- + qcom,qpnp-labibb-mode = "lcd";
- +};
- +
- +&dsi_dual_nt35597_video {
- + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
- + qcom,mdss-dsi-bl-min-level = <1>;
- + qcom,mdss-dsi-bl-max-level = <4095>;
- + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
- + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
- +};
- +
- +&dsi_dual_nt35597_cmd {
- + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
- + qcom,mdss-dsi-bl-min-level = <1>;
- + qcom,mdss-dsi-bl-max-level = <4095>;
- + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
- + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
- +};
- +
- +&dsi_dual_nt35597_truly_video {
- + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
- + qcom,mdss-dsi-bl-min-level = <1>;
- + qcom,mdss-dsi-bl-max-level = <4095>;
- + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
- + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
- +};
- +
- +&dsi_dual_nt35597_truly_cmd {
- + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
- + qcom,mdss-dsi-bl-min-level = <1>;
- + qcom,mdss-dsi-bl-max-level = <4095>;
- + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
- + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
- +};
- +
- +&dsi_nt35597_dsc_video {
- + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
- + qcom,mdss-dsi-bl-min-level = <1>;
- + qcom,mdss-dsi-bl-max-level = <4095>;
- + qcom,mdss-dsi-mode-sel-gpio-state = "single_port";
- + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
- +};
- +
- +&dsi_nt35597_dsc_cmd {
- + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
- + qcom,mdss-dsi-bl-min-level = <1>;
- + qcom,mdss-dsi-bl-max-level = <4095>;
- + qcom,mdss-dsi-mode-sel-gpio-state = "single_port";
- + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
- +};
- +
- +&dsi_sharp_4k_dsc_video {
- + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
- + qcom,mdss-dsi-bl-min-level = <1>;
- + qcom,mdss-dsi-bl-max-level = <4095>;
- + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
- +};
- +
- +&dsi_sharp_4k_dsc_cmd {
- + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
- + qcom,mdss-dsi-bl-min-level = <1>;
- + qcom,mdss-dsi-bl-max-level = <4095>;
- + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
- +};
- +
- +&dsi_dual_jdi_video {
- + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
- + qcom,mdss-dsi-bl-min-level = <1>;
- + qcom,mdss-dsi-bl-max-level = <4095>;
- + qcom,5v-boost-gpio = <&tlmm 51 0>;
- + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
- +};
- +
- +&dsi_dual_jdi_cmd {
- + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
- + qcom,mdss-dsi-bl-min-level = <1>;
- + qcom,mdss-dsi-bl-max-level = <4095>;
- + qcom,5v-boost-gpio = <&tlmm 51 0>;
- + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
- +};
- +
- +&dsi_jdi_fhd_r63452_cmd {
- + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
- + qcom,mdss-dsi-bl-min-level = <1>;
- + qcom,mdss-dsi-bl-max-level = <4095>;
- + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
- +};
- +
- +&dsi_lgd_fhd_td4322_cmd {
- + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
- + qcom,mdss-dsi-bl-min-level = <1>;
- + qcom,mdss-dsi-bl-max-level = <4095>;
- + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_lgd_td4322>;
- +};
- +
- +&dsi_dual_sharp_1080_120hz_cmd {
- + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
- + qcom,mdss-dsi-bl-min-level = <1>;
- + qcom,mdss-dsi-bl-max-level = <4095>;
- + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
- +};
- +
- +&mem_client_3_size {
- + qcom,peripheral-size = <0x500000>;
- +};
- +
- +&pmi8998_haptics {
- + status = "okay";
- + qcom,wave-play-rate-us = <5000>;
- + qcom,vmax-mv = <3248>;
- + qcom,wave-shape = "sine";
- + qcom,brake-pattern = [03 02 00 00];
- + qcom,brake-pattern-count = <9>;
- + qcom,disable_force_back_emf_delay;
- + qcom,vmax-overbrake-mv = <3596>;
- + qcom,brake-pattern-arry = [03 00 00 00
- + 03 02 00 00
- + 03 03 01 00
- + 03 03 02 01
- + 03 03 03 02
- + 03 03 03 02
- + 03 03 03 02
- + 03 03 03 02
- + 03 03 03 03];
- +};
- +
- +&pm8998_vadc {
- + chan@83 {
- + label = "vph_pwr";
- + reg = <0x83>;
- + qcom,decimation = <2>;
- + qcom,pre-div-channel-scaling = <1>;
- + qcom,calibration-type = "absolute";
- + qcom,scale-function = <0>;
- + qcom,hw-settle-time = <0>;
- + qcom,fast-avg-setup = <0>;
- + };
- +
- + chan@85 {
- + label = "vcoin";
- + reg = <0x85>;
- + qcom,decimation = <2>;
- + qcom,pre-div-channel-scaling = <1>;
- + qcom,calibration-type = "absolute";
- + qcom,scale-function = <0>;
- + qcom,hw-settle-time = <0>;
- + qcom,fast-avg-setup = <0>;
- + };
- +
- + chan@4c {
- + label = "xo_therm";
- + reg = <0x4c>;
- + qcom,decimation = <2>;
- + qcom,pre-div-channel-scaling = <0>;
- + qcom,calibration-type = "ratiometric";
- + qcom,scale-function = <4>;
- + qcom,hw-settle-time = <2>;
- + qcom,fast-avg-setup = <0>;
- + };
- +
- + chan@4d {
- + label = "msm_therm";
- + reg = <0x4d>;
- + qcom,decimation = <2>;
- + qcom,pre-div-channel-scaling = <0>;
- + qcom,calibration-type = "ratiometric";
- + qcom,scale-function = <2>;
- + qcom,hw-settle-time = <2>;
- + qcom,fast-avg-setup = <0>;
- + };
- +
- + chan@4e {
- + label = "emmc_therm";
- + reg = <0x4e>;
- + qcom,decimation = <2>;
- + qcom,pre-div-channel-scaling = <0>;
- + qcom,calibration-type = "ratiometric";
- + qcom,scale-function = <2>;
- + qcom,hw-settle-time = <2>;
- + qcom,fast-avg-setup = <0>;
- + };
- +
- + chan@4f {
- + label = "pa_therm0";
- + reg = <0x4f>;
- + qcom,decimation = <2>;
- + qcom,pre-div-channel-scaling = <0>;
- + qcom,calibration-type = "ratiometric";
- + qcom,scale-function = <2>;
- + qcom,hw-settle-time = <2>;
- + qcom,fast-avg-setup = <0>;
- + };
- +
- + chan@50 {
- + label = "pa_therm1";
- + reg = <0x50>;
- + qcom,decimation = <2>;
- + qcom,pre-div-channel-scaling = <0>;
- + qcom,calibration-type = "ratiometric";
- + qcom,scale-function = <2>;
- + qcom,hw-settle-time = <2>;
- + qcom,fast-avg-setup = <0>;
- + };
- +
- + chan@51 {
- + label = "quiet_therm";
- + reg = <0x51>;
- + qcom,decimation = <2>;
- + qcom,pre-div-channel-scaling = <0>;
- + qcom,calibration-type = "ratiometric";
- + qcom,scale-function = <2>;
- + qcom,hw-settle-time = <2>;
- + qcom,fast-avg-setup = <0>;
- + };
- +};
- +
- +&pm8998_adc_tm {
- + chan@83 {
- + label = "vph_pwr";
- + reg = <0x83>;
- + qcom,pre-div-channel-scaling = <1>;
- + qcom,calibration-type = "absolute";
- + qcom,scale-function = <0>;
- + qcom,hw-settle-time = <0>;
- + qcom,btm-channel-number = <0x60>;
- + };
- +
- + chan@4d {
- + label = "msm_therm";
- + reg = <0x4d>;
- + qcom,pre-div-channel-scaling = <0>;
- + qcom,calibration-type = "ratiometric";
- + qcom,scale-function = <2>;
- + qcom,hw-settle-time = <2>;
- + qcom,btm-channel-number = <0x68>;
- + qcom,thermal-node;
- + };
- +
- + chan@4e {
- + label = "emmc_therm";
- + reg = <0x4e>;
- + qcom,pre-div-channel-scaling = <0>;
- + qcom,calibration-type = "ratiometric";
- + qcom,scale-function = <2>;
- + qcom,hw-settle-time = <2>;
- + qcom,btm-channel-number = <0x80>;
- + qcom,thermal-node;
- + };
- +
- + chan@4f {
- + label = "pa_therm0";
- + reg = <0x4f>;
- + qcom,pre-div-channel-scaling = <0>;
- + qcom,calibration-type = "ratiometric";
- + qcom,scale-function = <2>;
- + qcom,hw-settle-time = <2>;
- + qcom,btm-channel-number = <0x88>;
- + qcom,thermal-node;
- + };
- +
- + chan@50 {
- + label = "pa_therm1";
- + reg = <0x50>;
- + qcom,pre-div-channel-scaling = <0>;
- + qcom,calibration-type = "ratiometric";
- + qcom,scale-function = <2>;
- + qcom,hw-settle-time = <2>;
- + qcom,btm-channel-number = <0x90>;
- + qcom,thermal-node;
- + };
- +
- + chan@51 {
- + label = "quiet_therm";
- + reg = <0x51>;
- + qcom,pre-div-channel-scaling = <0>;
- + qcom,calibration-type = "ratiometric";
- + qcom,scale-function = <2>;
- + qcom,hw-settle-time = <2>;
- + qcom,btm-channel-number = <0x70>;
- + qcom,thermal-node;
- + };
- +
- + chan@4c {
- + label = "xo_therm";
- + reg = <0x4c>;
- + qcom,pre-div-channel-scaling = <0>;
- + qcom,calibration-type = "ratiometric";
- + qcom,scale-function = <4>;
- + qcom,hw-settle-time = <2>;
- + qcom,btm-channel-number = <0x78>;
- + qcom,thermal-node;
- + };
- +};
- +
- +&wil6210 {
- + status = "ok";
- +};
- +
- +&slim_aud {
- + tasha_codec {
- + qcom,cdc-micbias1-mv = <2750>;
- + qcom,cdc-micbias2-mv = <1800>;
- + qcom,cdc-micbias3-mv = <1800>;
- + qcom,cdc-micbias4-mv = <2750>;
- + };
- +};
- +
- +&soc {
- + sound-tavil {
- + status = "disabled";
- + };
- +
- + sound-9335 {
- + qcom,audio-routing =
- + "AIF4 VI", "MCLK",
- + "RX_BIAS", "MCLK",
- + "MADINPUT", "MCLK",
- + "AMIC1", "MIC BIAS2",
- + "MIC BIAS2", "Handset Mic",
- + "AMIC2", "MIC BIAS2",
- + "MIC BIAS2", "Headset Mic",
- + "AMIC3", "MIC BIAS1",
- + "MIC BIAS1", "ANCRight Headset Mic",
- + "AMIC4", "MIC BIAS1",
- + "MIC BIAS1", "ANCLeft Headset Mic",
- + "AMIC5", "MIC BIAS4",
- + "MIC BIAS4", "Handset Mic",
- + "AMIC6", "MIC BIAS4",
- + "MIC BIAS4", "Analog Mic6";
- +
- + qcom,wsa-max-devs = <0>;
- + qcom,msm-mbhc-hphl-swh = <1>;
- + qcom,us-euro-gpios = <&wcd_us_euro_gpio>;
- +
- + qcom,asel-gpio = <&pmi8998_gpios 3 0x00>;
- + qcom,hsdet-gpio = <&tlmm 8 0x01>;
- +
- + qcom,spk-id-pin = <&spk_id_pin>;
- + qcom,rcv-id-pin = <&rcv_id_pin>;
- + };
- +
- + spk_id_pin: spk-id-pin@100 {
- + compatible = "audio,speaker-id";
- + audio,speaker-id-gpio = <&tlmm 100 0x00>;
- + pinctrl-names = "pull_down", "pull_up", "no_pull";
- + pinctrl-0 = <&spk_id_pull_down>;
- + pinctrl-1 = <&spk_id_pull_up>;
- + pinctrl-2 = <&spk_id_no_pull>;
- + };
- +
- + rcv_id_pin: rcv-id-pin@11 {
- + compatible = "audio,speaker-id";
- + audio,speaker-id-gpio = <&tlmm 11 0x00>;
- + pinctrl-names = "pull_down", "pull_up", "no_pull";
- + pinctrl-0 = <&rcv_id_pull_down>;
- + pinctrl-1 = <&rcv_id_pull_up>;
- + pinctrl-2 = <&rcv_id_no_pull>;
- + };
- +
- + qcom,msm-dai-mi2s {
- + dai_mi2s3: qcom,msm-dai-q6-mi2s-quat {
- + qcom,msm-mi2s-rx-lines = <1>;
- + qcom,msm-mi2s-tx-lines = <2>;
- + pinctrl-names = "default", "sleep";
- + pinctrl-0 = <&quat_mi2s_active
- + &quat_mi2s_sd0_active
- + &quat_mi2s_sd1_active>;
- + pinctrl-1 = <&quat_mi2s_sleep
- + &quat_mi2s_sd0_sleep
- + &quat_mi2s_sd1_sleep>;
- + };
- + };
- +
- + sn_fuse: snfuse@0x786134 {
- + compatible = "qcom,sn-fuse";
- + reg = <0x786134 0x4>;
- + reg-names = "sn-base";
- + };
- +
- + gpio_keys {
- + compatible = "gpio-keys";
- + input-name = "gpio-keys";
- + status = "okay";
- +
- + vol_up {
- + label = "volume_up";
- + gpios = <&pm8998_gpios 6 0x1>;
- + linux,input-type = <1>;
- + linux,code = <115>;
- + gpio-key,wakeup;
- + debounce-interval = <15>;
- + };
- +
- + hall_key0 {
- + label = "hall_key0";
- + gpios = <&tlmm 124 0x01>;
- + linux,input-type = <5>;
- + linux,code = <0>;
- + gpio-key,wakeup;
- + debounce-interval = <15>;
- + };
- + };
- +
- + gpio_rf {
- + pinctrl-names = "tlmm_gpio_rf_active","tlmm_gpio_rf_suspend";
- + pinctrl-0 = <&gpio_rf_active>;
- + pinctrl-1 = <&gpio_rf_suspend>;
- + compatible = "gpio_rf";
- + gpios = <&tlmm 119 0x01>;
- + debounce-interval = <15>;
- + };
- +
- + qcom,msm-dai-mi2s {
- + dai_mi2s3: qcom,msm-dai-q6-mi2s-quat {
- + qcom,msm-mi2s-rx-lines = <1>;
- + qcom,msm-mi2s-tx-lines = <2>;
- + pinctrl-names = "default", "sleep";
- + pinctrl-0 = <&quat_mi2s_active
- + &quat_mi2s_sd0_active
- + &quat_mi2s_sd1_active>;
- + pinctrl-1 = <&quat_mi2s_sleep
- + &quat_mi2s_sd0_sleep
- + &quat_mi2s_sd1_sleep>;
- + };
- + };
- + pwm_ir {
- + compatible = "pwm-ir";
- + pwms = <&pmi8998_pwm_2 0 0>;
- + };
- +
- + fingerprint_fpc {
- + status = "ok";
- + compatible = "fpc,fpc1020";
- + interrupt-parent = <&tlmm>;
- + interrupts = <121 0x0>;
- + fpc,gpio_rst = <&tlmm 37 0x0>;
- + fpc,gpio_irq = <&tlmm 121 0x0>;
- + vdd_ana-supply = <&fp_vdd_vreg>;
- + /* fpc,enable-on-boot; */
- + /* fpc,enable-wakeup; */
- +
- + pinctrl-names = "fpc1020_reset_reset",
- + "fpc1020_reset_active",
- + "fpc1020_irq_active";
- +
- + pinctrl-0 = <&msm_gpio_37>;
- + pinctrl-1 = <&msm_gpio_37_output_high>;
- + pinctrl-2 = <&msm_gpio_121>;
- + };
- +
- + fingerprint_goodix {
- + compatible = "goodix,fingerprint";
- + fp-gpio-reset = <&tlmm 37 0>;
- + fp-gpio-irq = <&tlmm 121 0>;
- + pinctrl-names = "pmx_fp_active", "pmx_fp_suspend";
- + pinctrl-0 = <&fp_active>;
- + pinctrl-1 = <&fp_suspend>;
- + clock-names = "iface_clk", "core_clk";
- + clocks = <&clock_gcc clk_gcc_blsp2_ahb_clk>,
- + <&clock_gcc clk_gcc_blsp2_qup6_spi_apps_clk>;
- + status = "ok";
- + };
- +};
- +
- +&spi_2 {
- + compatible = "qcom,spi-qup-v2";
- + #address-cells = <1>;
- + #size-cells = <0>;
- + reg-names = "spi_physical", "spi_bam_physical";
- + reg = <0xC176000 0x600>,
- + <0xC144000 0x25000>;
- + interrupt-names = "spi_irq", "spi_bam_irq";
- + interrupts = <0 96 0>, <0 238 0>;
- + spi-max-frequency = <19200000>;
- + qcom,use-bam;
- + qcom,ver-reg-exists;
- + qcom,bam-consumer-pipe-index = <8>;
- + qcom,bam-producer-pipe-index = <9>;
- + qcom,master-id = <86>;
- + qcom,use-pinctrl;
- + pinctrl-names = "spi_default", "spi_sleep";
- + pinctrl-0 = <&spi_2_active>;
- + pinctrl-1 = <&spi_2_sleep>;
- + clock-names = "iface_clk", "core_clk";
- + clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
- + <&clock_gcc clk_gcc_blsp1_qup2_spi_apps_clk>;
- + status = "ok";
- + peel_ir@0 {
- + compatible = "peel_ir";
- + reg = <0>;
- + spi-max-frequency = <19200000>;
- + peel_ir,lr-gpio = <73>;
- + peel_ir,lr-gpio-valid = <1>;
- + peel_ir,spi-bpw = <32>;
- + peel_ir,spi-clk-speed= <960000>;
- + peel_ir,spi-mode = <0>;
- + peel_ir,peel-field = <2345>;
- + status = "ok";
- + };
- +};
- +
- +&pcie0 {
- + status = "disabled";
- +};
- +
- +&fp_vdd_vreg {
- + regulator-always-on;
- +};
- +
- +&pmi8998_wled {
- + qcom,led-strings-list = [00 01];
- + qcom,fs-curr-ua = <20000>;
- + qcom,en-cabc;
- +};
- +
- +/* Red led was used for powersupply of White led */
- +&red_led {
- + qcom,start-idx = <1>;
- + qcom,idx-len = <10>;
- + qcom,duty-pcts = [00 19 32 4B 64
- + 64 4B 32 19 00];
- + qcom,lut-flags = <3>;
- + qcom,pause-lo = <0>;
- + qcom,pause-hi = <0>;
- + qcom,ramp-step-ms = <255>;
- + qcom,use-blink;
- + linux,name = "white";
- +};
- +
- +/* Blue led was used for powersupply of left button key backlight */
- +&blue_led {
- + linux,name = "button-backlight";
- +};
- +
- +/* Green led was used for powersupply of right button key backlight */
- +&green_led {
- + linux,name = "button-backlight1";
- +};
- +&pmi8998_charger {
- + qcom,usb-icl-ua = <3000000>;
- + qcom,fcc-max-ua = <3200000>;
- + qcom,auto-recharge-soc;
- +
- + qcom,thermal-mitigation
- + = <1800000 1600000 1400000 1200000 1000000 1000000 1000000>;
- + qcom,thermal-mitigation-dcp
- + = <1800000 1600000 1400000 1200000 1000000 1000000 1000000>;
- + qcom,thermal-mitigation-qc3
- + = <3000000 2425000 2125000 1825000 1525000 1225000 925000>;
- + qcom,thermal-mitigation-qc2
- + = <1600000 1400000 1200000 1000000 900000 900000 900000>;
- +};
- +&pmi8998_fg {
- + qcom,fg-force-load-profile;
- + qcom,fg-sys-term-current = <(-300)>;
- + qcom,fg-chg-term-current = <120>;
- + qcom,fg-auto-recharge-soc;
- + qcom,fg-recharge-soc-thr = <99>;
- + qcom,fg-cutoff-voltage = <3400>;
- + qcom,fg-empty-voltage = <3100>;
- + qcom,fg-jeita-hyst-temp = <0>;
- + qcom,fg-jeita-thresholds = <0 15 45 60>;
- + qcom,fg-esr-clamp-mohms = <60>;
- + qcom,fg-batt-temp-delta = <6>;
- + qcom,hold-soc-while-full;
- +};
- +/{
- + mtp_batterydata: qcom,battery-data {
- + qcom,batt-id-range-pct = <15>;
- + #include "batterydata-c1-atl-3350mAh.dtsi"
- + #include "batterydata-c1-sdi-3440mAh.dtsi"
- + #include "batterydata-itech-3020mAh.dtsi"
- + };
- +};
- +
- +
- +&qusb_phy0 {
- + qcom,qusb-phy-init-seq =
- + /* <value reg_offset> */
- + <0x80 0x0
- + 0x13 0x04
- + 0x7c 0x18c
- + 0x80 0x2c
- + 0x0a 0x184
- + 0xf0 0x23c
- + 0x0d 0x240>;
- +};
- diff --git a/arch/arm/boot/dts/qcom/sagit-msm8998-v2-mtp.dts b/arch/arm/boot/dts/qcom/sagit-msm8998-v2-mtp.dts
- new file mode 100644
- index 0000000..a53954e
- --- /dev/null
- +++ b/arch/arm/boot/dts/qcom/sagit-msm8998-v2-mtp.dts
- @@ -0,0 +1,24 @@
- +/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
- + * Copyright (C) 2017 XiaoMi, 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.
- + */
- +
- +
- +/dts-v1/;
- +
- +#include "msm8998-v2.dtsi"
- +#include "sagit-msm8998-mtp.dtsi"
- +
- +/ {
- + model = "Qualcomm Technologies, Inc. MSM 8998 v2 MTP";
- + compatible = "qcom,msm8998-mtp", "qcom,msm8998", "qcom,mtp";
- + qcom,board-id = <30 0>;
- +};
- diff --git a/arch/arm/boot/dts/qcom/sagit-msm8998-v2.1-mtp.dts b/arch/arm/boot/dts/qcom/sagit-msm8998-v2.1-mtp.dts
- new file mode 100644
- index 0000000..aae3991
- --- /dev/null
- +++ b/arch/arm/boot/dts/qcom/sagit-msm8998-v2.1-mtp.dts
- @@ -0,0 +1,24 @@
- +/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
- + * Copyright (C) 2017 XiaoMi, 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.
- + */
- +
- +
- +/dts-v1/;
- +
- +#include "msm8998-v2.1.dtsi"
- +#include "sagit-msm8998-mtp.dtsi"
- +
- +/ {
- + model = "Qualcomm Technologies, Inc. MSM 8998 v2.1 MTP";
- + compatible = "qcom,msm8998-mtp", "qcom,msm8998", "qcom,mtp";
- + qcom,board-id = <30 0>;
- +};
- diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
- index 3b01369..420346b 100644
- --- a/arch/arm64/Kconfig
- +++ b/arch/arm64/Kconfig
- @@ -1088,3 +1088,18 @@ source "arch/arm64/crypto/Kconfig"
- endif
- source "lib/Kconfig"
- +
- +config BOOT_INFO
- + bool "Boot information from bootloader"
- + default y
- + help
- + On embedded linux device, we try to collect more information from
- + bootloader to kernel. eg. powerup reason.
- +
- +config HWCONF_MANAGER
- + bool "Hardware configuration and monitor information"
- + default y
- + depends on CJSON
- + help
- + It provides all kinds of components configuration information and
- + monitor values.
- diff --git a/arch/arm64/configs/msmcortex_defconfig b/arch/arm64/configs/msmcortex_defconfig
- index 6f55e27..9129ca1 100644
- --- a/arch/arm64/configs/msmcortex_defconfig
- +++ b/arch/arm64/configs/msmcortex_defconfig
- @@ -290,8 +290,8 @@ CONFIG_KEYBOARD_GPIO=y
- CONFIG_INPUT_JOYSTICK=y
- CONFIG_INPUT_TOUCHSCREEN=y
- CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE_v21=y
- +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV_v21=y
- CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_v21=y
- -CONFIG_SECURE_TOUCH=y
- CONFIG_TOUCHSCREEN_ST=y
- CONFIG_TOUCHSCREEN_ST_I2C=y
- CONFIG_INPUT_MISC=y
- diff --git a/arch/arm64/configs/sagit_user_defconfig b/arch/arm64/configs/sagit_user_defconfig
- new file mode 100644
- index 0000000..f374b39
- --- /dev/null
- +++ b/arch/arm64/configs/sagit_user_defconfig
- @@ -0,0 +1,723 @@
- +CONFIG_LOCALVERSION="-perf"
- +CONFIG_AUDIT=y
- +# CONFIG_AUDITSYSCALL is not set
- +CONFIG_NO_HZ=y
- +CONFIG_HIGH_RES_TIMERS=y
- +CONFIG_IRQ_TIME_ACCOUNTING=y
- +CONFIG_RCU_EXPERT=y
- +CONFIG_RCU_FAST_NO_HZ=y
- +CONFIG_RCU_NOCB_CPU=y
- +CONFIG_RCU_NOCB_CPU_ALL=y
- +# CONFIG_IKCONFIG is not set
- +# CONFIG_IKCONFIG_PROC is not set
- +CONFIG_LOG_BUF_SHIFT=21
- +CONFIG_LOG_CPU_MAX_BUF_SHIFT=17
- +CONFIG_CGROUP_FREEZER=y
- +CONFIG_CPUSETS=y
- +CONFIG_CGROUP_CPUACCT=y
- +CONFIG_CGROUP_SCHEDTUNE=y
- +CONFIG_RT_GROUP_SCHED=y
- +CONFIG_SCHED_HMP=y
- +CONFIG_SCHED_HMP_CSTATE_AWARE=y
- +CONFIG_SCHED_CORE_CTL=y
- +CONFIG_NAMESPACES=y
- +# CONFIG_UTS_NS is not set
- +# CONFIG_PID_NS is not set
- +CONFIG_SCHED_AUTOGROUP=y
- +CONFIG_SCHED_TUNE=y
- +CONFIG_BLK_DEV_INITRD=y
- +# CONFIG_RD_XZ is not set
- +# CONFIG_RD_LZO is not set
- +# CONFIG_RD_LZ4 is not set
- +CONFIG_CC_OPTIMIZE_FOR_SIZE=y
- +CONFIG_KALLSYMS_ALL=y
- +# CONFIG_AIO is not set
- +# CONFIG_MEMBARRIER is not set
- +CONFIG_EMBEDDED=y
- +# CONFIG_SLUB_DEBUG is not set
- +# CONFIG_COMPAT_BRK is not set
- +CONFIG_PROFILING=y
- +CONFIG_CC_STACKPROTECTOR_REGULAR=y
- +CONFIG_ARCH_MMAP_RND_COMPAT_BITS=16
- +CONFIG_MODULES=y
- +CONFIG_MODULE_UNLOAD=y
- +CONFIG_MODULE_FORCE_UNLOAD=y
- +CONFIG_MODVERSIONS=y
- +CONFIG_MODULE_SIG=y
- +CONFIG_MODULE_SIG_FORCE=y
- +CONFIG_MODULE_SIG_SHA512=y
- +CONFIG_PARTITION_ADVANCED=y
- +CONFIG_ARCH_QCOM=y
- +CONFIG_ARCH_MSM8998=y
- +CONFIG_ARCH_MSMHAMSTER=y
- +CONFIG_PCI=y
- +CONFIG_PCI_MSM=y
- +CONFIG_SCHED_MC=y
- +CONFIG_NR_CPUS=8
- +CONFIG_QCOM_TLB_EL2_HANDLER=y
- +CONFIG_PREEMPT=y
- +CONFIG_HZ_100=y
- +CONFIG_ARM64_REG_REBALANCE_ON_CTX_SW=y
- +CONFIG_CMA=y
- +CONFIG_CMA_DEBUGFS=y
- +CONFIG_ZSMALLOC=y
- +CONFIG_BALANCE_ANON_FILE_RECLAIM=y
- +CONFIG_SECCOMP=y
- +CONFIG_ARMV8_DEPRECATED=y
- +CONFIG_SWP_EMULATION=y
- +CONFIG_CP15_BARRIER_EMULATION=y
- +CONFIG_SETEND_EMULATION=y
- +# CONFIG_EFI is not set
- +CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y
- +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
- +CONFIG_COMPAT=y
- +CONFIG_PM_AUTOSLEEP=y
- +CONFIG_PM_WAKELOCKS=y
- +CONFIG_PM_WAKELOCKS_LIMIT=0
- +# CONFIG_PM_WAKELOCKS_GC is not set
- +CONFIG_CPU_FREQ=y
- +CONFIG_CPU_FREQ_GOV_POWERSAVE=y
- +CONFIG_CPU_FREQ_GOV_USERSPACE=y
- +CONFIG_CPU_FREQ_GOV_ONDEMAND=y
- +CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
- +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
- +CONFIG_CPU_BOOST=y
- +CONFIG_NET=y
- +CONFIG_PACKET=y
- +CONFIG_UNIX=y
- +CONFIG_XFRM_USER=y
- +CONFIG_XFRM_STATISTICS=y
- +CONFIG_NET_KEY=y
- +CONFIG_INET=y
- +CONFIG_IP_MULTICAST=y
- +CONFIG_IP_ADVANCED_ROUTER=y
- +CONFIG_IP_MULTIPLE_TABLES=y
- +CONFIG_IP_ROUTE_VERBOSE=y
- +CONFIG_IP_PNP=y
- +CONFIG_IP_PNP_DHCP=y
- +CONFIG_INET_AH=y
- +CONFIG_INET_ESP=y
- +CONFIG_INET_IPCOMP=y
- +CONFIG_INET_DIAG_DESTROY=y
- +CONFIG_IPV6_ROUTER_PREF=y
- +CONFIG_IPV6_ROUTE_INFO=y
- +CONFIG_IPV6_OPTIMISTIC_DAD=y
- +CONFIG_INET6_AH=y
- +CONFIG_INET6_ESP=y
- +CONFIG_INET6_IPCOMP=y
- +CONFIG_IPV6_MIP6=y
- +CONFIG_IPV6_MULTIPLE_TABLES=y
- +CONFIG_IPV6_SUBTREES=y
- +CONFIG_NETFILTER=y
- +CONFIG_NF_CONNTRACK=y
- +CONFIG_NF_CONNTRACK_SECMARK=y
- +CONFIG_NF_CONNTRACK_EVENTS=y
- +CONFIG_NF_CT_PROTO_DCCP=y
- +CONFIG_NF_CT_PROTO_SCTP=y
- +CONFIG_NF_CT_PROTO_UDPLITE=y
- +CONFIG_NF_CONNTRACK_AMANDA=y
- +CONFIG_NF_CONNTRACK_FTP=y
- +CONFIG_NF_CONNTRACK_H323=y
- +CONFIG_NF_CONNTRACK_IRC=y
- +CONFIG_NF_CONNTRACK_NETBIOS_NS=y
- +CONFIG_NF_CONNTRACK_PPTP=y
- +CONFIG_NF_CONNTRACK_SANE=y
- +CONFIG_NF_CONNTRACK_TFTP=y
- +CONFIG_NF_CT_NETLINK=y
- +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
- +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
- +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
- +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
- +CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y
- +CONFIG_NETFILTER_XT_TARGET_LOG=y
- +CONFIG_NETFILTER_XT_TARGET_MARK=y
- +CONFIG_NETFILTER_XT_TARGET_NFLOG=y
- +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
- +CONFIG_NETFILTER_XT_TARGET_NOTRACK=y
- +CONFIG_NETFILTER_XT_TARGET_TEE=y
- +CONFIG_NETFILTER_XT_TARGET_TPROXY=y
- +CONFIG_NETFILTER_XT_TARGET_TRACE=y
- +CONFIG_NETFILTER_XT_TARGET_SECMARK=y
- +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
- +CONFIG_NETFILTER_XT_MATCH_COMMENT=y
- +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
- +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
- +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
- +CONFIG_NETFILTER_XT_MATCH_DSCP=y
- +CONFIG_NETFILTER_XT_MATCH_ESP=y
- +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
- +CONFIG_NETFILTER_XT_MATCH_HELPER=y
- +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
- +# CONFIG_NETFILTER_XT_MATCH_L2TP is not set
- +CONFIG_NETFILTER_XT_MATCH_LENGTH=y
- +CONFIG_NETFILTER_XT_MATCH_LIMIT=y
- +CONFIG_NETFILTER_XT_MATCH_MAC=y
- +CONFIG_NETFILTER_XT_MATCH_MARK=y
- +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
- +CONFIG_NETFILTER_XT_MATCH_POLICY=y
- +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
- +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
- +CONFIG_NETFILTER_XT_MATCH_QUOTA=y
- +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
- +CONFIG_NETFILTER_XT_MATCH_SOCKET=y
- +CONFIG_NETFILTER_XT_MATCH_STATE=y
- +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
- +CONFIG_NETFILTER_XT_MATCH_STRING=y
- +CONFIG_NETFILTER_XT_MATCH_TIME=y
- +CONFIG_NETFILTER_XT_MATCH_U32=y
- +CONFIG_NF_CONNTRACK_IPV4=y
- +CONFIG_IP_NF_IPTABLES=y
- +CONFIG_IP_NF_MATCH_AH=y
- +CONFIG_IP_NF_MATCH_ECN=y
- +CONFIG_IP_NF_MATCH_RPFILTER=y
- +CONFIG_IP_NF_MATCH_TTL=y
- +CONFIG_IP_NF_FILTER=y
- +CONFIG_IP_NF_TARGET_REJECT=y
- +CONFIG_IP_NF_NAT=y
- +CONFIG_IP_NF_TARGET_MASQUERADE=y
- +CONFIG_IP_NF_TARGET_NETMAP=y
- +CONFIG_IP_NF_TARGET_REDIRECT=y
- +CONFIG_IP_NF_MANGLE=y
- +CONFIG_IP_NF_RAW=y
- +CONFIG_IP_NF_SECURITY=y
- +CONFIG_IP_NF_ARPTABLES=y
- +CONFIG_IP_NF_ARPFILTER=y
- +CONFIG_IP_NF_ARP_MANGLE=y
- +CONFIG_NF_CONNTRACK_IPV6=y
- +CONFIG_IP6_NF_IPTABLES=y
- +CONFIG_IP6_NF_MATCH_RPFILTER=y
- +CONFIG_IP6_NF_FILTER=y
- +CONFIG_IP6_NF_TARGET_REJECT=y
- +CONFIG_IP6_NF_MANGLE=y
- +CONFIG_IP6_NF_RAW=y
- +CONFIG_BRIDGE_NF_EBTABLES=y
- +CONFIG_BRIDGE_EBT_BROUTE=y
- +CONFIG_L2TP=y
- +CONFIG_L2TP_V3=y
- +CONFIG_L2TP_IP=y
- +CONFIG_L2TP_ETH=y
- +CONFIG_BRIDGE=y
- +CONFIG_NET_SCHED=y
- +CONFIG_NET_SCH_HTB=y
- +CONFIG_NET_SCH_PRIO=y
- +CONFIG_NET_SCH_MULTIQ=y
- +CONFIG_NET_SCH_INGRESS=y
- +CONFIG_NET_CLS_FW=y
- +CONFIG_NET_CLS_U32=y
- +CONFIG_CLS_U32_MARK=y
- +CONFIG_NET_CLS_FLOW=y
- +CONFIG_NET_EMATCH=y
- +CONFIG_NET_EMATCH_CMP=y
- +CONFIG_NET_EMATCH_NBYTE=y
- +CONFIG_NET_EMATCH_U32=y
- +CONFIG_NET_EMATCH_META=y
- +CONFIG_NET_EMATCH_TEXT=y
- +CONFIG_NET_CLS_ACT=y
- +CONFIG_NET_ACT_GACT=y
- +CONFIG_NET_ACT_MIRRED=y
- +CONFIG_NET_ACT_SKBEDIT=y
- +CONFIG_RMNET_DATA=y
- +CONFIG_RMNET_DATA_FC=y
- +CONFIG_RMNET_DATA_DEBUG_PKT=y
- +CONFIG_SOCKEV_NLMCAST=y
- +CONFIG_BT=y
- +CONFIG_MSM_BT_POWER=y
- +CONFIG_BTFM_SLIM=y
- +CONFIG_BTFM_SLIM_WCN3990=y
- +CONFIG_CFG80211=y
- +CONFIG_CFG80211_INTERNAL_REGDB=y
- +CONFIG_RFKILL=y
- +CONFIG_NFC_NQ=y
- +CONFIG_IPC_ROUTER=y
- +CONFIG_IPC_ROUTER_SECURITY=y
- +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y
- +CONFIG_DMA_CMA=y
- +# CONFIG_PNP_DEBUG_MESSAGES is not set
- +CONFIG_ZRAM=y
- +CONFIG_ZRAM_DEBUG=y
- +CONFIG_SWAP=y
- +CONFIG_MEMCG=y
- +CONFIG_MEMCG_SWAP=y
- +CONFIG_ANDROID_WHETSTONE=y
- +CONFIG_CGROUP_MEM_RES_CTLR=y
- +CONFIG_CGROUP_MEM_RES_CTLR_SWAP=y
- +CONFIG_BLK_DEV_LOOP=y
- +CONFIG_BLK_DEV_RAM=y
- +CONFIG_BLK_DEV_RAM_SIZE=8192
- +CONFIG_QSEECOM=y
- +CONFIG_HDCP_QSEECOM=y
- +CONFIG_UID_CPUTIME=y
- +CONFIG_QPNP_MISC=y
- +CONFIG_SCSI=y
- +CONFIG_BLK_DEV_SD=y
- +CONFIG_CHR_DEV_SG=y
- +CONFIG_CHR_DEV_SCH=y
- +CONFIG_SCSI_CONSTANTS=y
- +CONFIG_SCSI_LOGGING=y
- +CONFIG_SCSI_SCAN_ASYNC=y
- +CONFIG_SCSI_UFSHCD=y
- +CONFIG_SCSI_UFSHCD_PLATFORM=y
- +CONFIG_SCSI_UFS_QCOM=y
- +CONFIG_SCSI_UFS_QCOM_ICE=y
- +CONFIG_MD=y
- +CONFIG_BLK_DEV_MD=y
- +CONFIG_MD_LINEAR=y
- +CONFIG_BLK_DEV_DM=y
- +CONFIG_DM_CRYPT=y
- +CONFIG_DM_REQ_CRYPT=y
- +CONFIG_DM_UEVENT=y
- +CONFIG_DM_VERITY=y
- +CONFIG_DM_VERITY_FEC=y
- +CONFIG_DM_ANDROID_VERITY=y
- +CONFIG_NETDEVICES=y
- +CONFIG_BONDING=y
- +CONFIG_DUMMY=y
- +CONFIG_TUN=y
- +CONFIG_SKY2=y
- +CONFIG_RNDIS_IPA=y
- +CONFIG_SMSC911X=y
- +CONFIG_PPP=y
- +CONFIG_PPP_BSDCOMP=y
- +CONFIG_PPP_DEFLATE=y
- +CONFIG_PPP_MPPE=y
- +CONFIG_PPPOLAC=y
- +CONFIG_PPPOPNS=y
- +CONFIG_USB_USBNET=y
- +CONFIG_USB_USBNET=y
- +CONFIG_WCNSS_MEM_PRE_ALLOC=y
- +CONFIG_ATH_CARDS=y
- +CONFIG_WIL6210=m
- +CONFIG_CLD_LL_CORE=y
- +CONFIG_INPUT_EVDEV=y
- +CONFIG_INPUT_KEYRESET=y
- +CONFIG_KEYBOARD_GPIO=y
- +# CONFIG_INPUT_MOUSE is not set
- +CONFIG_INPUT_TOUCHSCREEN=y
- +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FORCE=y
- +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_I2C_FORCE=y
- +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE_FORCE=y
- +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV_FORCE=y
- +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_FORCE=y
- +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_TEST_REPORTING_FORCE=y
- +CONFIG_SECURE_TOUCH=y
- +CONFIG_INPUT_MISC=y
- +CONFIG_INPUT_HBTP_INPUT=y
- +CONFIG_INPUT_QPNP_POWER_ON=y
- +CONFIG_INPUT_UINPUT=y
- +CONFIG_INPUT_STMVL53L0=y
- +CONFIG_INPUT_FINGERPRINT=y
- +CONFIG_INPUT_GPIO=y
- +CONFIG_FINGERPRINT_GOODIX_TA=y
- +CONFIG_FINGERPRINT_FPC1268_TEE=y
- +# CONFIG_SERIO_SERPORT is not set
- +# CONFIG_VT is not set
- +# CONFIG_LEGACY_PTYS is not set
- +# CONFIG_DEVMEM is not set
- +# CONFIG_DEVKMEM is not set
- +# CONFIG_SERIAL_MSM is not set
- +# CONFIG_SERIAL_MSM_CONSOLE is not set
- +CONFIG_SERIAL_MSM_HS=y
- +CONFIG_SERIAL_MSM_SMD=y
- +CONFIG_DIAG_CHAR=y
- +CONFIG_HW_RANDOM=y
- +CONFIG_HW_RANDOM_MSM_LEGACY=y
- +CONFIG_MSM_ADSPRPC=y
- +CONFIG_MSM_RDBG=m
- +CONFIG_I2C_CHARDEV=y
- +CONFIG_I2C_MSM_V2=y
- +CONFIG_SLIMBUS_MSM_NGD=y
- +CONFIG_SOUNDWIRE=y
- +CONFIG_SPI=y
- +CONFIG_SPI_QUP=y
- +CONFIG_SPI_SPIDEV=y
- +CONFIG_SPMI=y
- +CONFIG_PINCTRL_MSM8998=y
- +CONFIG_PINCTRL_SDM660=y
- +CONFIG_GPIOLIB=y
- +CONFIG_GPIO_SYSFS=y
- +CONFIG_GPIO_QPNP_PIN=y
- +CONFIG_POWER_RESET_QCOM=y
- +CONFIG_QCOM_DLOAD_MODE=y
- +CONFIG_POWER_RESET_XGENE=y
- +CONFIG_POWER_RESET_SYSCON=y
- +CONFIG_QPNP_FG_GEN3=y
- +CONFIG_MSM_BCL_CTL=y
- +CONFIG_MSM_BCL_PERIPHERAL_CTL=y
- +CONFIG_BATTERY_BCL=y
- +CONFIG_QPNP_SMB2=y
- +CONFIG_SMB138X_CHARGER=y
- +CONFIG_QPNP_QNOVO=y
- +CONFIG_MSM_PM=y
- +CONFIG_APSS_CORE_EA=y
- +CONFIG_MSM_APM=y
- +CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
- +CONFIG_CPU_THERMAL=y
- +CONFIG_LIMITS_MONITOR=y
- +CONFIG_LIMITS_LITE_HW=y
- +CONFIG_THERMAL_MONITOR=y
- +CONFIG_THERMAL_TSENS8974=y
- +CONFIG_THERMAL_QPNP=y
- +CONFIG_THERMAL_QPNP_ADC_TM=y
- +CONFIG_QCOM_THERMAL_LIMITS_DCVS=y
- +CONFIG_MFD_SPMI_PMIC=y
- +CONFIG_MFD_I2C_PMIC=y
- +CONFIG_WCD9335_CODEC=y
- +CONFIG_WCD934X_CODEC=y
- +CONFIG_REGULATOR=y
- +CONFIG_REGULATOR_FIXED_VOLTAGE=y
- +CONFIG_REGULATOR_RPM_SMD=y
- +CONFIG_REGULATOR_QPNP=y
- +CONFIG_REGULATOR_QPNP_LABIBB=y
- +CONFIG_REGULATOR_QPNP_LCDB=y
- +CONFIG_REGULATOR_SPM=y
- +CONFIG_REGULATOR_CPR3_HMSS=y
- +CONFIG_REGULATOR_CPR3_MMSS=y
- +CONFIG_REGULATOR_CPRH_KBSS=y
- +CONFIG_REGULATOR_MEM_ACC=y
- +CONFIG_REGULATOR_PROXY_CONSUMER=y
- +CONFIG_REGULATOR_STUB=y
- +CONFIG_MEDIA_SUPPORT=y
- +CONFIG_MEDIA_CAMERA_SUPPORT=y
- +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y
- +CONFIG_MEDIA_CONTROLLER=y
- +CONFIG_VIDEO_V4L2_SUBDEV_API=y
- +CONFIG_VIDEO_ADV_DEBUG=y
- +CONFIG_VIDEO_FIXED_MINOR_RANGES=y
- +CONFIG_V4L_PLATFORM_DRIVERS=y
- +CONFIG_MSM_CAMERA=y
- +CONFIG_MSM_CAMERA_DEBUG=y
- +CONFIG_MSMB_CAMERA=y
- +CONFIG_MSMB_CAMERA_DEBUG=y
- +CONFIG_MSM_CAMERA_SENSOR=y
- +CONFIG_MSM_CPP=y
- +CONFIG_MSM_CCI=y
- +CONFIG_MSM_CSI20_HEADER=y
- +CONFIG_MSM_CSI22_HEADER=y
- +CONFIG_MSM_CSI30_HEADER=y
- +CONFIG_MSM_CSI31_HEADER=y
- +CONFIG_MSM_CSIPHY=y
- +CONFIG_MSM_CSID=y
- +CONFIG_MSM_EEPROM=y
- +CONFIG_MSM_ISPIF=y
- +CONFIG_IMX134=y
- +CONFIG_IMX132=y
- +CONFIG_OV9724=y
- +CONFIG_OV5648=y
- +CONFIG_GC0339=y
- +CONFIG_OV8825=y
- +CONFIG_OV8865=y
- +CONFIG_s5k4e1=y
- +CONFIG_OV12830=y
- +CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y
- +CONFIG_MSMB_JPEG=y
- +CONFIG_MSM_FD=y
- +CONFIG_MSM_JPEGDMA=y
- +CONFIG_MSM_VIDC_V4L2=y
- +CONFIG_MSM_VIDC_VMEM=y
- +CONFIG_MSM_VIDC_GOVERNORS=y
- +CONFIG_MSM_SDE_ROTATOR=y
- +CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y
- +CONFIG_DVB_MPQ=m
- +CONFIG_DVB_MPQ_DEMUX=m
- +CONFIG_TSPP=m
- +CONFIG_QCOM_KGSL=y
- +CONFIG_FB=y
- +CONFIG_FB_ARMCLCD=y
- +CONFIG_FB_MSM=y
- +CONFIG_FB_MSM_MDSS=y
- +CONFIG_FB_MSM_MDSS_WRITEBACK=y
- +CONFIG_FB_MSM_MDSS_HDMI_PANEL=y
- +CONFIG_FB_MSM_MDSS_DP_PANEL=y
- +# CONFIG_FB_MSM_MDSS_XLOG_DEBUG is not set
- +CONFIG_LOGO=y
- +# CONFIG_LOGO_LINUX_MONO is not set
- +# CONFIG_LOGO_LINUX_VGA16 is not set
- +CONFIG_SOUND=y
- +CONFIG_SND=y
- +CONFIG_SND_USB_AUDIO=y
- +CONFIG_SND_USB_AUDIO_QMI=y
- +CONFIG_SND_SOC=y
- +CONFIG_SND_SOC_MSM8998=y
- +CONFIG_UHID=y
- +CONFIG_HID_APPLE=y
- +CONFIG_HID_ELECOM=y
- +CONFIG_HID_MAGICMOUSE=y
- +CONFIG_HID_MICROSOFT=y
- +CONFIG_HID_MULTITOUCH=y
- +CONFIG_HID_PLANTRONICS=y
- +CONFIG_USB=y
- +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
- +CONFIG_USB_XHCI_HCD=y
- +CONFIG_USB_EHCI_HCD=y
- +CONFIG_USB_EHCI_HCD_PLATFORM=y
- +CONFIG_USB_OHCI_HCD=y
- +CONFIG_USB_OHCI_HCD_PLATFORM=y
- +CONFIG_USB_STORAGE=y
- +CONFIG_USB_DWC3=y
- +CONFIG_USB_ISP1760=y
- +CONFIG_USB_ISP1760_HOST_ROLE=y
- +CONFIG_USB_PD_POLICY=y
- +CONFIG_QPNP_USB_PDPHY=y
- +CONFIG_USB_EHSET_TEST_FIXTURE=y
- +CONFIG_USB_OTG_WAKELOCK=y
- +CONFIG_NOP_USB_XCEIV=y
- +CONFIG_USB_MSM_SSPHY_QMP=y
- +CONFIG_MSM_QUSB_PHY=y
- +CONFIG_DUAL_ROLE_USB_INTF=y
- +CONFIG_USB_GADGET=y
- +CONFIG_USB_GADGET_VBUS_DRAW=500
- +CONFIG_USB_CONFIGFS=y
- +CONFIG_USB_CONFIGFS_NCM=y
- +CONFIG_USB_CONFIGFS_MASS_STORAGE=y
- +CONFIG_USB_CONFIGFS_F_FS=y
- +CONFIG_USB_CONFIGFS_F_MTP=y
- +CONFIG_USB_CONFIGFS_F_PTP=y
- +CONFIG_USB_CONFIGFS_F_ACC=y
- +CONFIG_USB_CONFIGFS_UEVENT=y
- +CONFIG_USB_CONFIGFS_F_MIDI=y
- +CONFIG_USB_CONFIGFS_F_HID=y
- +CONFIG_USB_CONFIGFS_F_DIAG=y
- +CONFIG_USB_CONFIGFS_F_GSI=y
- +CONFIG_USB_CONFIGFS_F_CDEV=y
- +CONFIG_USB_CONFIGFS_F_QDSS=y
- +CONFIG_USB_CONFIGFS_F_CCID=y
- +CONFIG_MMC=y
- +CONFIG_MMC_PERF_PROFILING=y
- +CONFIG_MMC_CLKGATE=y
- +CONFIG_MMC_BLOCK_MINORS=32
- +CONFIG_MMC_TEST=y
- +CONFIG_MMC_SDHCI=y
- +CONFIG_MMC_SDHCI_PLTFM=y
- +CONFIG_MMC_SDHCI_MSM=y
- +CONFIG_LEDS_QPNP=y
- +CONFIG_LEDS_QPNP_FLASH_V2=y
- +CONFIG_LEDS_QPNP_WLED=y
- +CONFIG_LEDS_SYSCON=y
- +CONFIG_LEDS_TRIGGERS=y
- +CONFIG_SWITCH=y
- +CONFIG_RTC_CLASS=y
- +CONFIG_RTC_DRV_QPNP=y
- +CONFIG_DMADEVICES=y
- +CONFIG_QCOM_SPS_DMA=y
- +CONFIG_UIO=y
- +CONFIG_UIO_MSM_SHAREDMEM=y
- +CONFIG_STAGING=y
- +CONFIG_ASHMEM=y
- +CONFIG_ANDROID_TIMED_GPIO=y
- +CONFIG_ANDROID_LOW_MEMORY_KILLER=y
- +CONFIG_MULTIPLE_LMK=y
- +CONFIG_ION=y
- +CONFIG_ION_MSM=y
- +CONFIG_QPNP_REVID=y
- +CONFIG_QPNP_COINCELL=y
- +CONFIG_SPS=y
- +CONFIG_SPS_SUPPORT_NDP_BAM=y
- +CONFIG_IPA=y
- +CONFIG_RMNET_IPA=y
- +CONFIG_GSI=y
- +CONFIG_IPA3=y
- +CONFIG_RMNET_IPA3=y
- +CONFIG_GPIO_USB_DETECT=y
- +CONFIG_SEEMP_CORE=y
- +CONFIG_USB_BAM=y
- +CONFIG_MSM_MDSS_PLL=y
- +CONFIG_REMOTE_SPINLOCK_MSM=y
- +CONFIG_MSM_TIMER_LEAP=y
- +CONFIG_IOMMU_IO_PGTABLE_FAST=y
- +CONFIG_ARM_SMMU=y
- +CONFIG_IOMMU_DEBUG=y
- +CONFIG_IOMMU_DEBUG_TRACKING=y
- +CONFIG_IOMMU_TESTS=y
- +# CONFIG_QCOM_COMMON_LOG is not set
- +# CONFIG_SERIAL_EARLYCON is not set
- +# CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC is not set
- +CONFIG_MSM_SMEM=y
- +CONFIG_QPNP_HAPTIC=y
- +CONFIG_MSM_SMD=y
- +CONFIG_MSM_GLINK=y
- +CONFIG_MSM_GLINK_LOOPBACK_SERVER=y
- +CONFIG_MSM_GLINK_SMD_XPRT=y
- +CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT=y
- +CONFIG_MSM_GLINK_SPI_XPRT=y
- +CONFIG_MSM_SPCOM=y
- +CONFIG_MSM_SPSS_UTILS=y
- +CONFIG_MSM_SMEM_LOGGING=y
- +CONFIG_MSM_SMP2P=y
- +CONFIG_MSM_SMP2P_TEST=y
- +CONFIG_MSM_QMI_INTERFACE=y
- +CONFIG_MSM_RPM_SMD=y
- +CONFIG_QCOM_BUS_SCALING=y
- +CONFIG_MSM_SERVICE_LOCATOR=y
- +CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
- +CONFIG_MSM_SYSMON_GLINK_COMM=y
- +CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y
- +CONFIG_MSM_GLINK_PKT=y
- +CONFIG_MSM_SPM=y
- +CONFIG_QCOM_SCM=y
- +CONFIG_QCOM_WATCHDOG_V2=y
- +CONFIG_DUMP_ALL_STACKS=y
- +# CONFIG_FIRE_WATCHDOG is not set
- +CONFIG_QCOM_IRQ_HELPER=y
- +CONFIG_QCOM_MEMORY_DUMP_V2=y
- +CONFIG_ICNSS=y
- +CONFIG_MSM_RUN_QUEUE_STATS=y
- +CONFIG_MSM_BOOT_STATS=y
- +CONFIG_MSM_ADSP_LOADER=y
- +CONFIG_MSM_PERFORMANCE=y
- +CONFIG_MSM_SUBSYSTEM_RESTART=y
- +CONFIG_MSM_PIL=y
- +CONFIG_MSM_PIL_SSR_GENERIC=y
- +CONFIG_MSM_PIL_MSS_QDSP6V5=y
- +CONFIG_TRACER_PKT=y
- +# CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC is not set
- +CONFIG_MSM_MPM_OF=y
- +CONFIG_MSM_EVENT_TIMER=y
- +CONFIG_MSM_AVTIMER=y
- +CONFIG_QCOM_REMOTEQDSS=y
- +CONFIG_MSM_SERVICE_NOTIFIER=y
- +CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
- +CONFIG_MSM_RPM_LOG=y
- +CONFIG_MSM_RPM_STATS_LOG=y
- +CONFIG_QSEE_IPC_IRQ_BRIDGE=y
- +CONFIG_QCOM_SMCINVOKE=y
- +CONFIG_QCOM_EARLY_RANDOM=y
- +CONFIG_MEM_SHARE_QMI_SERVICE=y
- +CONFIG_QCOM_BIMC_BWMON=y
- +CONFIG_ARM_MEMLAT_MON=y
- +CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y
- +CONFIG_DEVFREQ_GOV_MEMLAT=y
- +CONFIG_QCOM_DEVFREQ_DEVBW=y
- +CONFIG_SPDM_SCM=y
- +CONFIG_DEVFREQ_SPDM=y
- +CONFIG_EXTCON=y
- +CONFIG_IIO=y
- +CONFIG_QCOM_RRADC=y
- +CONFIG_QCOM_TADC=y
- +CONFIG_PWM=y
- +CONFIG_PWM_QPNP=y
- +CONFIG_ARM_GIC_V3_ACL=y
- +CONFIG_ANDROID=y
- +CONFIG_ANDROID_BINDER_IPC=y
- +CONFIG_ANDROID_BINDER_DEVICES="binder,hwbinder"
- +CONFIG_MSM_TZ_LOG=y
- +CONFIG_SENSORS_SSC=y
- +CONFIG_EXT2_FS=y
- +CONFIG_EXT2_FS_XATTR=y
- +CONFIG_EXT3_FS=y
- +CONFIG_EXT4_FS_SECURITY=y
- +CONFIG_EXT4_ENCRYPTION=y
- +CONFIG_EXT4_FS_ENCRYPTION=y
- +CONFIG_EXT4_FS_ICE_ENCRYPTION=y
- +CONFIG_FUSE_FS=y
- +CONFIG_MSDOS_FS=y
- +CONFIG_VFAT_FS=y
- +CONFIG_TMPFS=y
- +CONFIG_TMPFS_POSIX_ACL=y
- +CONFIG_ECRYPT_FS=y
- +CONFIG_ECRYPT_FS_MESSAGING=y
- +CONFIG_NLS_CODEPAGE_437=y
- +CONFIG_NLS_ISO8859_1=y
- +CONFIG_PRINTK_TIME=y
- +CONFIG_DEBUG_INFO=y
- +CONFIG_DYNAMIC_DEBUG=y
- +CONFIG_MAGIC_SYSRQ=y
- +CONFIG_PANIC_TIMEOUT=1
- +CONFIG_SCHEDSTATS=y
- +CONFIG_TIMER_STATS=y
- +# CONFIG_DEBUG_PREEMPT is not set
- +CONFIG_IPC_LOGGING=y
- +CONFIG_QCOM_RTB=y
- +CONFIG_QCOM_RTB_SEPARATE_CPUS=y
- +CONFIG_CPU_FREQ_SWITCH_PROFILER=y
- +CONFIG_DEBUG_SET_MODULE_RONX=y
- +CONFIG_DEBUG_RODATA=y
- +CONFIG_DEBUG_ALIGN_RODATA=y
- +CONFIG_CORESIGHT=y
- +CONFIG_CORESIGHT_EVENT=y
- +CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y
- +CONFIG_CORESIGHT_QCOM_REPLICATOR=y
- +CONFIG_CORESIGHT_STM=y
- +CONFIG_CORESIGHT_HWEVENT=y
- +CONFIG_CORESIGHT_CTI=y
- +CONFIG_CORESIGHT_TPDA=y
- +CONFIG_CORESIGHT_TPDM=y
- +CONFIG_CORESIGHT_QPDI=y
- +CONFIG_CORESIGHT_SOURCE_DUMMY=y
- +CONFIG_PFK=y
- +CONFIG_SECURITY=y
- +CONFIG_SECURITY_SELINUX=y
- +CONFIG_SECURITY_SMACK=y
- +CONFIG_CRYPTO_ECHAINIV=y
- +CONFIG_CRYPTO_XCBC=y
- +CONFIG_CRYPTO_MD4=y
- +CONFIG_CRYPTO_TWOFISH=y
- +CONFIG_CRYPTO_ANSI_CPRNG=y
- +CONFIG_CRYPTO_DEV_QCRYPTO=y
- +CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y
- +CONFIG_CRYPTO_DEV_QCEDEV=y
- +CONFIG_CRYPTO_DEV_OTA_CRYPTO=y
- +CONFIG_CRYPTO_DEV_QCOM_ICE=y
- +CONFIG_SYSTEM_TRUSTED_KEYS="verity.x509.pem"
- +CONFIG_ARM64_CRYPTO=y
- +CONFIG_CRYPTO_SHA1_ARM64_CE=y
- +CONFIG_CRYPTO_SHA2_ARM64_CE=y
- +CONFIG_CRYPTO_GHASH_ARM64_CE=y
- +CONFIG_CRYPTO_AES_ARM64_CE_CCM=y
- +CONFIG_CRYPTO_AES_ARM64_CE_BLK=y
- +CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y
- +CONFIG_CRYPTO_CRC32_ARM64=y
- +CONFIG_QMI_ENCDEC=y
- +
- +CONFIG_PSTORE=y
- +CONFIG_PSTORE_CONSOLE=y
- +CONFIG_PSTORE_RAM=y
- +CONFIG_PSTORE_PMSG=y
- +CONFIG_CMDLINE="ramoops_memreserve=4M"
- +CONFIG_CMDLINE_EXTEND=y
- +CONFIG_BOOT_INFO=y
- +CONFIG_CJSON=y
- +CONFIG_HWCONF_MANAGER=y
- +CONFIG_OF_FLATTREE=y
- +CONFIG_SERIAL_NUM=y
- +CONFIG_LAST_TOUCH_EVENTS=y
- +CONFIG_SPI_PEELIR=y
- +
- +## MIUI ADD:START
- +## Multi userspace config support
- +CONFIG_KEYS=y
- +CONFIG_ENCRYPTED_KEYS=y
- +CONFIG_CRYPTO=y
- +CONFIG_CRYPTO_AES=y
- +CONFIG_CRYPTO_SHA1=y
- +CONFIG_CRYPTO_SHA256=y
- +CONFIG_CRYPTO_MD5=y
- +CONFIG_CRYPTO_GF128MUL=y
- +CONFIG_CRYPTO_SEQIV=y
- +CONFIG_CRYPTO_CTR=y
- +CONFIG_CRYPTO_XTS=y
- +CONFIG_NET_NS=y
- +CONFIG_VETH=y
- +CONFIG_GPIO_RF=y
- +## END
- +
- +
- +#MIUI ADD
- +#Add CIFS Config
- +CONFIG_NETWORK_FILESYSTEMS=y
- +CONFIG_CIFS=y
- +CONFIG_NLS=y
- +CONFIG_NLS_DEFAULT="iso8859-1"
- +CONFIG_NLS_CODEPAGE_936=y
- +CONFIG_NLS_CODEPAGE_950=y
- +CONFIG_NLS_UTF8=y
- +#MIUI END
- +CONFIG_F2FS_FS=y
- +CONFIG_F2FS_STAT_FS=y
- +CONFIG_F2FS_FS_XATTR=y
- +CONFIG_F2FS_FS_POSIX_ACL=y
- +CONFIG_F2FS_FS_SECURITY=y
- +CONFIG_F2FS_FS_ENCRYPTION=y
- +CONFIG_F2FS_FS_ICE_ENCRYPTION=y
- +
- +# cpuset totally exlusive support for vr
- +CONFIG_CPUSET_EXCLUSIVE_IND=y
- diff --git a/arch/arm64/include/asm/bootinfo.h b/arch/arm64/include/asm/bootinfo.h
- new file mode 100644
- index 0000000..697813e
- --- /dev/null
- +++ b/arch/arm64/include/asm/bootinfo.h
- @@ -0,0 +1,55 @@
- +/*
- + * bootinfo.h
- + *
- + * 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.
- + */
- +
- +#ifndef __ASMARM_BOOTINFO_H
- +#define __ASMARM_BOOTINFO_H
- +
- +#define HW_DEVID_VERSION_SHIFT 8
- +#define HW_DEVID_VERSION_MASK 0xF00UL
- +#define HW_MAJOR_VERSION_SHIFT 4
- +#define HW_MAJOR_VERSION_MASK 0xF0
- +#define HW_MINOR_VERSION_SHIFT 0
- +#define HW_MINOR_VERSION_MASK 0x0F
- +
- +typedef enum {
- + PU_REASON_EVENT_HWRST,
- + PU_REASON_EVENT_SMPL,
- + PU_REASON_EVENT_RTC,
- + PU_REASON_EVENT_DC_CHG,
- + PU_REASON_EVENT_USB_CHG,
- + PU_REASON_EVENT_PON1,
- + PU_REASON_EVENT_CABLE,
- + PU_REASON_EVENT_KPD,
- + PU_REASON_EVENT_WARMRST,
- + PU_REASON_EVENT_LPK,
- + PU_REASON_EVENT_LCK,
- + PU_REASON_MAX
- +} powerup_reason_t;
- +
- +enum {
- + RS_REASON_EVENT_WDOG,
- + RS_REASON_EVENT_KPANIC,
- + RS_REASON_EVENT_NORMAL,
- + RS_REASON_EVENT_OTHER,
- + RS_REASON_MAX
- +};
- +
- +#define RESTART_EVENT_WDOG 0x10000
- +#define RESTART_EVENT_KPANIC 0x20000
- +#define RESTART_EVENT_NORMAL 0x40000
- +#define RESTART_EVENT_OTHER 0x80000
- +
- +unsigned int get_powerup_reason(void);
- +int is_abnormal_powerup(void);
- +void set_powerup_reason(unsigned int powerup_reason);
- +unsigned int get_hw_version(void);
- +void set_hw_version(unsigned int hw_version);
- +unsigned int get_hw_version_devid(void);
- +unsigned int get_hw_version_major(void);
- +unsigned int get_hw_version_minor(void);
- +#endif
- diff --git a/arch/arm64/include/asm/hwconf_manager.h b/arch/arm64/include/asm/hwconf_manager.h
- new file mode 100644
- index 0000000..50e162c
- --- /dev/null
- +++ b/arch/arm64/include/asm/hwconf_manager.h
- @@ -0,0 +1,21 @@
- +/*
- + * hwconf_manager.h
- + *
- + * 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.
- + */
- +
- +#ifndef _LINUX_HWCONF_MANAGER_H
- +#define _LINUX_HWCONF_MANAGER_H
- +
- +int register_hw_component_info(char *component_name);
- +int add_hw_component_info(char *component_name, char *key, char *value);
- +int unregister_hw_component_info(char *component_name);
- +
- +int register_hw_monitor_info(char *component_name);
- +int add_hw_monitor_info(char *component_name, char *mon_key, char *mon_value);
- +int update_hw_monitor_info(char *component_name, char *mon_key, char *mon_value);
- +int unregister_hw_monitor_info(char *component_name);
- +
- +#endif
- diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
- index f6e0269..3bd7ff7 100644
- --- a/arch/arm64/kernel/Makefile
- +++ b/arch/arm64/kernel/Makefile
- @@ -40,6 +40,8 @@ arm64-obj-$(CONFIG_CPU_PM) += sleep.o suspend.o
- arm64-obj-$(CONFIG_CPU_IDLE) += cpuidle.o
- arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o
- arm64-obj-$(CONFIG_KGDB) += kgdb.o
- +arm64-obj-$(CONFIG_BOOT_INFO) += bootinfo.o
- +arm64-obj-$(CONFIG_HWCONF_MANAGER) += hwconf_manager.o
- arm64-obj-$(CONFIG_EFI) += efi.o efi-entry.stub.o
- arm64-obj-$(CONFIG_PCI) += pci.o
- arm64-obj-$(CONFIG_ARMV8_DEPRECATED) += armv8_deprecated.o
- diff --git a/arch/arm64/kernel/bootinfo.c b/arch/arm64/kernel/bootinfo.c
- new file mode 100644
- index 0000000..a248c92
- --- /dev/null
- +++ b/arch/arm64/kernel/bootinfo.c
- @@ -0,0 +1,214 @@
- +/*
- + * bootinfo.c
- + *
- + * Copyright (C) 2017 XiaoMi, 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 as
- + * published by the Free Software Foundation.
- + */
- +
- +#include <linux/module.h>
- +#include <linux/kernel.h>
- +#include <linux/init.h>
- +#include <linux/fs.h>
- +#include <linux/string.h>
- +#include <asm/setup.h>
- +#include <asm/bootinfo.h>
- +#include <linux/bitops.h>
- +#include <linux/input/qpnp-power-on.h>
- +
- +static const char * const powerup_reasons[PU_REASON_MAX] = {
- + [PU_REASON_EVENT_KPD] = "keypad",
- + [PU_REASON_EVENT_RTC] = "rtc",
- + [PU_REASON_EVENT_CABLE] = "cable",
- + [PU_REASON_EVENT_SMPL] = "smpl",
- + [PU_REASON_EVENT_PON1] = "pon1",
- + [PU_REASON_EVENT_USB_CHG] = "usb_chg",
- + [PU_REASON_EVENT_DC_CHG] = "dc_chg",
- + [PU_REASON_EVENT_HWRST] = "hw_reset",
- + [PU_REASON_EVENT_LPK] = "long_power_key",
- + [PU_REASON_EVENT_LCK] = "long_combo_key",
- +};
- +
- +static const char * const reset_reasons[RS_REASON_MAX] = {
- + [RS_REASON_EVENT_WDOG] = "wdog",
- + [RS_REASON_EVENT_KPANIC] = "kpanic",
- + [RS_REASON_EVENT_NORMAL] = "reboot",
- + [RS_REASON_EVENT_OTHER] = "other",
- +};
- +
- +static struct kobject *bootinfo_kobj;
- +static powerup_reason_t powerup_reason;
- +static unsigned int hw_version;
- +
- +#define bootinfo_attr(_name) \
- +static struct kobj_attribute _name##_attr = { \
- + .attr = { \
- + .name = __stringify(_name), \
- + .mode = 0644, \
- + }, \
- + .show = _name##_show, \
- + .store = NULL, \
- +}
- +
- +#define bootinfo_func_init(type, name, initval) \
- +static type name = (initval); \
- +type get_##name(void) \
- +{ \
- + return name; \
- +} \
- +void set_##name(type __##name) \
- +{ \
- + name = __##name; \
- +}
- +
- +int is_abnormal_powerup(void)
- +{
- + u32 pu_reason = get_powerup_reason();
- + return (pu_reason & (RESTART_EVENT_KPANIC | RESTART_EVENT_WDOG)) |
- + (pu_reason & BIT(PU_REASON_EVENT_HWRST) & RESTART_EVENT_OTHER);
- +}
- +
- +static ssize_t powerup_reason_show(struct kobject *kobj,
- + struct kobj_attribute *attr, char *buf)
- +{
- + char *s = buf;
- + u32 pu_reason;
- + int pu_reason_index = PU_REASON_MAX;
- + u32 reset_reason;
- + int reset_reason_index = RS_REASON_MAX;
- +
- + pu_reason = get_powerup_reason();
- + if (pu_reason & BIT(PU_REASON_EVENT_WARMRST)
- + && qpnp_pon_is_lck()) {
- + pu_reason_index = PU_REASON_EVENT_LCK;
- + s += snprintf(s, strlen(powerup_reasons[pu_reason_index]) + 1,
- + powerup_reasons[pu_reason_index]);
- + pr_debug("%s: pu_reason [0x%x] index %d\n",
- + __func__, pu_reason, pu_reason_index);
- + goto out;
- + }
- +
- + if (((pu_reason & BIT(PU_REASON_EVENT_HWRST))
- + && qpnp_pon_is_ps_hold_reset()) ||
- + (pu_reason & BIT(PU_REASON_EVENT_WARMRST))) {
- + reset_reason = pu_reason >> 16;
- + reset_reason_index = find_first_bit((unsigned long *)&reset_reason,
- + sizeof(reset_reason)*BITS_PER_BYTE);
- + if (reset_reason_index < RS_REASON_MAX && reset_reason_index >= 0) {
- + s += snprintf(s, strlen(reset_reasons[reset_reason_index]) + 1,
- + reset_reasons[reset_reason_index]);
- + pr_debug("%s: rs_reason [0x%x], first non-zero bit %d\n",
- + __func__, reset_reason, reset_reason_index);
- + goto out;
- + };
- + }
- + if (qpnp_pon_is_lpk() &&
- + (pu_reason & BIT(PU_REASON_EVENT_HWRST)))
- + pu_reason_index = PU_REASON_EVENT_LPK;
- + else if (pu_reason & BIT(PU_REASON_EVENT_HWRST))
- + pu_reason_index = PU_REASON_EVENT_HWRST;
- + else if (pu_reason & BIT(PU_REASON_EVENT_SMPL))
- + pu_reason_index = PU_REASON_EVENT_SMPL;
- + else if (pu_reason & BIT(PU_REASON_EVENT_RTC))
- + pu_reason_index = PU_REASON_EVENT_RTC;
- + else if (pu_reason & BIT(PU_REASON_EVENT_USB_CHG))
- + pu_reason_index = PU_REASON_EVENT_USB_CHG;
- + else if (pu_reason & BIT(PU_REASON_EVENT_DC_CHG))
- + pu_reason_index = PU_REASON_EVENT_DC_CHG;
- + else if (pu_reason & BIT(PU_REASON_EVENT_KPD))
- + pu_reason_index = PU_REASON_EVENT_KPD;
- + else if (pu_reason & BIT(PU_REASON_EVENT_PON1))
- + pu_reason_index = PU_REASON_EVENT_PON1;
- + if (pu_reason_index < PU_REASON_MAX && pu_reason_index >= 0) {
- + s += snprintf(s, strlen(powerup_reasons[pu_reason_index]) + 1,
- + powerup_reasons[pu_reason_index]);
- + pr_debug("%s: pu_reason [0x%x] index %d\n",
- + __func__, pu_reason, pu_reason_index);
- + goto out;
- + }
- + s += snprintf(s, 15, "unknown reboot");
- +out:
- + return (s - buf);
- +}
- +
- +static ssize_t powerup_reason_details_show(struct kobject *kobj,
- + struct kobj_attribute *attr, char *buf)
- +{
- + u32 pu_reason;
- +
- + pu_reason = get_powerup_reason();
- +
- + return snprintf(buf, 11, "0x%x\n", pu_reason);
- +}
- +
- +static ssize_t hw_version_show(struct kobject *kobj,
- + struct kobj_attribute *attr, char *buf)
- +{
- + u32 hw_version;
- +
- + hw_version = get_hw_version();
- +
- + return snprintf(buf, 11, "0x%x\n", hw_version);
- +}
- +
- +bootinfo_attr(powerup_reason);
- +bootinfo_attr(powerup_reason_details);
- +bootinfo_attr(hw_version);
- +bootinfo_func_init(u32, powerup_reason, 0);
- +bootinfo_func_init(u32, hw_version, 0);
- +
- +unsigned int get_hw_version_devid(void)
- +{
- + return ((get_hw_version() & HW_DEVID_VERSION_MASK)
- + >> HW_DEVID_VERSION_SHIFT);
- +}
- +EXPORT_SYMBOL(get_hw_version_devid);
- +
- +static struct attribute *g[] = {
- + &powerup_reason_attr.attr,
- + &powerup_reason_details_attr.attr,
- + &hw_version_attr.attr,
- + NULL,
- +};
- +
- +static struct attribute_group attr_group = {
- + .attrs = g,
- +};
- +
- +static int __init bootinfo_init(void)
- +{
- + int ret = -ENOMEM;
- +
- + bootinfo_kobj = kobject_create_and_add("bootinfo", NULL);
- + if (bootinfo_kobj == NULL) {
- + pr_err("bootinfo_init: subsystem_register failed\n");
- + goto fail;
- + }
- +
- + ret = sysfs_create_group(bootinfo_kobj, &attr_group);
- + if (ret) {
- + pr_err("bootinfo_init: subsystem_register failed\n");
- + goto sys_fail;
- + }
- +
- + return ret;
- +
- +sys_fail:
- + kobject_del(bootinfo_kobj);
- +fail:
- + return ret;
- +
- +}
- +
- +static void __exit bootinfo_exit(void)
- +{
- + if (bootinfo_kobj) {
- + sysfs_remove_group(bootinfo_kobj, &attr_group);
- + kobject_del(bootinfo_kobj);
- + }
- +}
- +
- +core_initcall(bootinfo_init);
- +module_exit(bootinfo_exit);
- diff --git a/arch/arm64/kernel/hwconf_manager.c b/arch/arm64/kernel/hwconf_manager.c
- new file mode 100644
- index 0000000..8d1a507
- --- /dev/null
- +++ b/arch/arm64/kernel/hwconf_manager.c
- @@ -0,0 +1,459 @@
- +/*
- + * hwconf_manager.c
- + *
- + * Copyright (C) 2017 XiaoMi, 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 as
- + * published by the Free Software Foundation.
- + */
- +
- +#include <linux/module.h>
- +#include <linux/kernel.h>
- +#include <linux/init.h>
- +#include <linux/fs.h>
- +#include <linux/string.h>
- +#include <linux/slab.h>
- +#include <linux/ctype.h>
- +#include <linux/debugfs.h>
- +#include <linux/crypto.h>
- +#include <linux/cJSON.h>
- +#include <asm/setup.h>
- +#include <asm/hwconf_manager.h>
- +
- +struct hw_info_manager {
- + cJSON *hw_config;
- + cJSON *hw_monitor;
- + struct crypto_cipher *tfm;
- + struct kobject *hwconf_kobj;
- + struct dentry *hwconf_check;
- +};
- +
- +struct hw_info_manager *info_manager;
- +
- +#define INIT_KEY "0123456789"
- +char crypto_key[32] = INIT_KEY;
- +
- +#define __HWINFO_DECRYPT_DEBUG__ 0
- +
- +#define hwconf_attr(_name) \
- +static struct kobj_attribute _name##_attr = { \
- + .attr = { \
- + .name = __stringify(_name), \
- + .mode = 0644, \
- + }, \
- + .show = _name##_show, \
- + .store = _name##_store, \
- +}
- +
- +int add_hw_component_info(char *component_name, char *key, char *value)
- +{
- + cJSON *component;
- +
- + if (!info_manager->hw_config) {
- + pr_err("hwconfig_manager is still not ready.\n");
- + return -EINVAL;
- + }
- +
- + component = cJSON_GetObjectItem(info_manager->hw_config,
- + component_name);
- + if (!component)
- + return -EINVAL;
- +
- + if (cJSON_HasObjectItem(component, key)) {
- + pr_err("%s is added in %s already\n", key, component_name);
- + return -EINVAL;
- + }
- +
- + cJSON_AddStringToObject(component, key, value);
- + pr_debug("%s: %s\n", __func__, cJSON_Print(component));
- +
- + return 0;
- +}
- +EXPORT_SYMBOL(add_hw_component_info);
- +
- +int register_hw_component_info(char *component_name)
- +{
- + cJSON *component;
- +
- + if (!info_manager->hw_config) {
- + pr_err("hwconfig_manager is still not ready.\n");
- + return -EINVAL;
- + }
- +
- + component = cJSON_GetObjectItem(info_manager->hw_config,
- + component_name);
- + if (component) {
- + pr_err("%s is registered already\n", component_name);
- + return -EINVAL;
- + }
- +
- + component = cJSON_CreateObject();
- + cJSON_AddItemToObject(info_manager->hw_config,
- + component_name, component);
- + pr_debug("%s: %s\n", __func__, cJSON_Print(component));
- +
- + return 0;
- +}
- +EXPORT_SYMBOL(register_hw_component_info);
- +
- +int unregister_hw_component_info(char *component_name)
- +{
- + cJSON *component;
- +
- + if (!info_manager->hw_config) {
- + pr_err("hwconfig_manager is still not ready.\n");
- + return -EINVAL;
- + }
- +
- + component = cJSON_GetObjectItem(info_manager->hw_config,
- + component_name);
- + if (!component)
- + return -EINVAL;
- +
- + cJSON_DetachItemFromObject(info_manager->hw_config,
- + component_name);
- +
- + return 0;
- +}
- +EXPORT_SYMBOL(unregister_hw_component_info);
- +
- +int update_hw_monitor_info(char *component_name, char *mon_key, char *mon_value)
- +{
- + cJSON *component;
- +
- + if (!info_manager->hw_monitor) {
- + pr_err("hwconfig_manager is still not ready.\n");
- + return -EINVAL;
- + }
- +
- + component = cJSON_GetObjectItem(info_manager->hw_monitor,
- + component_name);
- + if (!component) {
- + pr_err("No component %s\n", component_name);
- + return -EINVAL;
- + }
- +
- + if (!cJSON_HasObjectItem(component, mon_key)) {
- + pr_err("No key %s\n", mon_key);
- + return -EINVAL;
- + }
- +
- + cJSON_DeleteItemFromObject(component, mon_key);
- + cJSON_AddStringToObject(component, mon_key, mon_value);
- +
- + pr_debug("%s: %s\n", __func__, cJSON_Print(info_manager->hw_monitor));
- +
- + return 0;
- +}
- +EXPORT_SYMBOL(update_hw_monitor_info);
- +
- +int add_hw_monitor_info(char *component_name, char *mon_key, char *mon_value)
- +{
- + cJSON *component;
- +
- + if (!info_manager->hw_monitor) {
- + pr_err("hwconfig_manager is still not ready.\n");
- + return -EINVAL;
- + }
- +
- + component = cJSON_GetObjectItem(info_manager->hw_monitor,
- + component_name);
- + if (!component)
- + return -EINVAL;
- +
- + if (cJSON_HasObjectItem(component, mon_key)) {
- + pr_err("%s is added in %s already\n", mon_key, component_name);
- + return -EINVAL;
- + }
- +
- + cJSON_AddStringToObject(component, mon_key, mon_value);
- + pr_debug("%s: %s\n", __func__, cJSON_Print(component));
- +
- + return 0;
- +}
- +EXPORT_SYMBOL(add_hw_monitor_info);
- +
- +int register_hw_monitor_info(char *component_name)
- +{
- + cJSON *component;
- +
- + if (!info_manager->hw_monitor) {
- + pr_err("hwconfig_manager is still not ready.\n");
- + return -EINVAL;
- + }
- +
- + component = cJSON_GetObjectItem(info_manager->hw_monitor,
- + component_name);
- + if (component) {
- + pr_err("%s is registered already\n", component_name);
- + return -EINVAL;
- + }
- +
- + component = cJSON_CreateObject();
- + cJSON_AddItemToObject(info_manager->hw_monitor,
- + component_name, component);
- + pr_debug("%s: %s\n", __func__, cJSON_Print(component));
- +
- + return 0;
- +}
- +EXPORT_SYMBOL(register_hw_monitor_info);
- +
- +int unregister_hw_monitor_info(char *component_name)
- +{
- + cJSON *component;
- +
- + if (!info_manager->hw_monitor) {
- + pr_err("hwconfig_manager is still not ready.\n");
- + return -EINVAL;
- + }
- +
- + component = cJSON_GetObjectItem(info_manager->hw_monitor,
- + component_name);
- + if (!component)
- + return -EINVAL;
- +
- + cJSON_DetachItemFromObject(info_manager->hw_monitor,
- + component_name);
- +
- + return 0;
- +}
- +EXPORT_SYMBOL(unregister_hw_monitor_info);
- +
- +static ssize_t hw_info_store(struct kobject *kobj,
- + struct kobj_attribute *attr, const char *buf,
- + size_t count)
- +{
- + memcpy(crypto_key, buf, sizeof(crypto_key));
- +
- + pr_debug("%s crypto_key=%s\n", __func__, crypto_key);
- +
- + return count;
- +}
- +
- +#if __HWINFO_DECRYPT_DEBUG__
- +static int hw_info_decrypt_test(char *buf, size_t len)
- +{
- + char *dest;
- + unsigned int blocksize;
- + int i;
- + int ret;
- +
- + info_manager->tfm = crypto_alloc_cipher("aes",
- + CRYPTO_ALG_TYPE_BLKCIPHER, CRYPTO_ALG_ASYNC);
- + if (IS_ERR(info_manager->tfm)) {
- + pr_err("Failed to load transform for aes mode!\n");
- + ret = -EINVAL;
- + goto out;
- + }
- +
- + ret = crypto_cipher_setkey(info_manager->tfm, crypto_key,
- + sizeof(crypto_key));
- + if (ret) {
- + pr_err("Failed to setkey\n");
- + ret = -EINVAL;
- + goto free_cipher;
- + }
- +
- + blocksize = crypto_cipher_blocksize(info_manager->tfm);
- + if (!blocksize) {
- + ret = -EINVAL;
- + goto free_cipher;
- + }
- +
- + dest = kzalloc(len, GFP_KERNEL);
- + if (!dest) {
- + ret = -ENOMEM;
- + goto free_cipher;
- + }
- +
- + for (i = 0; i < len; i += blocksize)
- + crypto_cipher_decrypt_one(info_manager->tfm,
- + &dest[i], &buf[i]);
- +
- + pr_debug("%s: %s\n", __func__, dest);
- +
- + kfree(dest);
- +free_cipher:
- + crypto_free_cipher(info_manager->tfm);
- +out:
- + return ret;
- +}
- +#endif
- +
- +static ssize_t hw_info_show(struct kobject *kobj,
- + struct kobj_attribute *attr, char *buf)
- +{
- + int ret;
- + char *src = cJSON_Print(info_manager->hw_config);
- + int i;
- + unsigned int blocksize;
- + char *padding;
- + int blocks = 0;
- +
- + if (!strncmp(crypto_key, INIT_KEY, sizeof(crypto_key))) {
- + pr_err("crypto_key == INIT_KEY\n");
- + return 0;
- + }
- +
- + /* Allocate transform for AES CRYPTO_ALG_TYPE_BLKCIPHER */
- + info_manager->tfm = crypto_alloc_cipher("aes",
- + CRYPTO_ALG_TYPE_BLKCIPHER, CRYPTO_ALG_ASYNC);
- + if (IS_ERR(info_manager->tfm)) {
- + pr_err("Failed to load transform for aes mode!\n");
- + return 0;
- + }
- +
- + pr_debug("%s crypto_key=%s\n", __func__, crypto_key);
- + ret = crypto_cipher_setkey(info_manager->tfm, crypto_key,
- + sizeof(crypto_key));
- + if (ret) {
- + pr_err("Failed to setkey\n");
- + crypto_free_cipher(info_manager->tfm);
- + return 0;
- + }
- +
- + blocksize = crypto_cipher_blocksize(info_manager->tfm);
- + if (!blocksize)
- + return 0;
- +
- + padding = kmalloc(blocksize + 1, GFP_KERNEL);
- + if (!padding)
- + return -ENOMEM;
- +
- + /* start encrypt */
- + for (i = 0; i < strlen(src); i += blocksize) {
- + memset(padding, 0, blocksize + 1);
- + strlcpy(padding, &src[i], blocksize + 1);
- + crypto_cipher_encrypt_one(info_manager->tfm,
- + &buf[i], padding);
- + blocks++;
- + }
- +
- + kfree(padding);
- + crypto_free_cipher(info_manager->tfm);
- +
- +#if __HWINFO_DECRYPT_DEBUG__
- + hw_info_decrypt_test(buf, blocks * blocksize);
- +#endif
- +
- + return blocks * blocksize;
- +}
- +
- +static ssize_t hw_mon_store(struct kobject *kobj,
- + struct kobj_attribute *attr, const char *buf,
- + size_t count)
- +{
- + int on = 99;
- + char component_name[32] = { 0 };
- + int len;
- +
- + len = sscanf(buf, "%s %d", component_name, &on);
- +
- + pr_debug("%s component_name=%s, on=%d\n", __func__, component_name, on);
- +
- + if (on == 0)
- + unregister_hw_monitor_info(component_name);
- +
- + return count;
- +}
- +
- +static ssize_t hw_mon_show(struct kobject *kobj,
- + struct kobj_attribute *attr, char *buf)
- +{
- + return snprintf(buf, PAGE_SIZE, "%s\n",
- + cJSON_Print(info_manager->hw_monitor));
- +}
- +
- +hwconf_attr(hw_info);
- +hwconf_attr(hw_mon);
- +
- +static struct attribute *g[] = {
- + &hw_info_attr.attr,
- + &hw_mon_attr.attr,
- + NULL,
- +};
- +
- +static struct attribute_group attr_group = {
- + .attrs = g,
- +};
- +
- +static int hwconf_debugfs_get(void *data, u64 *val)
- +{
- + pr_debug("hw_config:\n%s\n", cJSON_Print(info_manager->hw_config));
- + pr_debug("hw_monitor:\n%s\n", cJSON_Print(info_manager->hw_monitor));
- + *val = 0;
- + return 0;
- +}
- +
- +static int hwconf_debugfs_set(void *data, u64 val)
- +{
- + if (val == 1) {
- + register_hw_component_info("debugfs_hwconf");
- + add_hw_component_info("debugfs_hwconf", "key1", "value1");
- +
- + register_hw_monitor_info("debugfs_hwmon");
- + add_hw_monitor_info("debugfs_hwmon", "key2", "value2");
- + } else if (val == 2) {
- + update_hw_monitor_info("debugfs_hwmon", "key2", "value3");
- + } else if (val == 3) {
- + unregister_hw_component_info("debugfs_hwconf");
- + unregister_hw_monitor_info("debugfs_hwmon");
- + }
- + return 0;
- +}
- +DEFINE_SIMPLE_ATTRIBUTE(hwconf_check_fops, hwconf_debugfs_get,
- + hwconf_debugfs_set, "%llu\n");
- +
- +static int __init hwconf_init(void)
- +{
- + int ret = -ENOMEM;
- +
- + info_manager = kmalloc(sizeof(*info_manager), GFP_KERNEL);
- + if (!info_manager)
- + return ret;
- +
- + info_manager->hw_config = cJSON_CreateObject();
- + info_manager->hw_monitor = cJSON_CreateObject();
- +
- + info_manager->hwconf_kobj = kobject_create_and_add("hwconf", NULL);
- + if (!info_manager->hwconf_kobj) {
- + pr_err("hwconf_init: subsystem_register failed\n");
- + goto fail;
- + }
- +
- + ret = sysfs_create_group(info_manager->hwconf_kobj, &attr_group);
- + if (ret) {
- + pr_err("hwconf_init: subsystem_register failed\n");
- + goto sys_fail;
- + }
- +
- + info_manager->hwconf_check = debugfs_create_file("hwconf_check",
- + 0644, NULL, NULL, &hwconf_check_fops);
- +
- + return ret;
- +
- +sys_fail:
- + kobject_del(info_manager->hwconf_kobj);
- +fail:
- + cJSON_Delete(info_manager->hw_config);
- + cJSON_Delete(info_manager->hw_monitor);
- + kfree(info_manager);
- +
- + return ret;
- +}
- +
- +static void __exit hwconf_exit(void)
- +{
- + cJSON_Delete(info_manager->hw_config);
- + cJSON_Delete(info_manager->hw_monitor);
- +
- + if (info_manager->hwconf_kobj) {
- + sysfs_remove_group(info_manager->hwconf_kobj, &attr_group);
- + kobject_del(info_manager->hwconf_kobj);
- + }
- + debugfs_remove(info_manager->hwconf_check);
- +}
- +
- +core_initcall(hwconf_init);
- +module_exit(hwconf_exit);
- diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
- index 5a09efa..1a189b5 100644
- --- a/arch/arm64/kernel/process.c
- +++ b/arch/arm64/kernel/process.c
- @@ -260,7 +260,7 @@ void __show_regs(struct pt_regs *regs)
- printk("\n");
- }
- if (!user_mode(regs))
- - show_extra_register_data(regs, 64);
- + show_extra_register_data(regs, 256);
- printk("\n");
- }
- diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
- index 326c53b..76c4a02 100644
- --- a/arch/arm64/kernel/setup.c
- +++ b/arch/arm64/kernel/setup.c
- @@ -3,6 +3,7 @@
- *
- * Copyright (C) 1995-2001 Russell King
- * Copyright (C) 2012 ARM Ltd.
- + * Copyright (C) 2017 XiaoMi, 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 as
- @@ -65,6 +66,17 @@
- #include <asm/xen/hypervisor.h>
- #include <asm/mmu_context.h>
- +#include <asm/bootinfo.h>
- +
- +#ifdef CONFIG_OF_FLATTREE
- +void __init early_init_dt_setup_pureason_arch(unsigned long pu_reason)
- +{
- + set_powerup_reason(pu_reason);
- + pr_info("Powerup reason=0x%x\n", get_powerup_reason());
- +}
- +#endif
- +
- +
- unsigned int boot_reason;
- EXPORT_SYMBOL(boot_reason);
- diff --git a/drivers/Makefile b/drivers/Makefile
- index eb67aad..7ee655c 100644
- --- a/drivers/Makefile
- +++ b/drivers/Makefile
- @@ -50,7 +50,7 @@ obj-$(CONFIG_RESET_CONTROLLER) += reset/
- obj-y += tty/
- obj-y += char/
- -
- +obj-y += elliptic/
- # gpu/ comes after char for AGP vs DRM startup and after iommu
- obj-y += gpu/
- diff --git a/drivers/android/binder.c b/drivers/android/binder.c
- index 5ce31c8..285ffcc 100644
- --- a/drivers/android/binder.c
- +++ b/drivers/android/binder.c
- @@ -3,6 +3,7 @@
- * Android IPC Subsystem
- *
- * Copyright (C) 2007-2008 Google, Inc.
- + * Copyright (C) 2017 XiaoMi, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- @@ -2500,7 +2501,7 @@ static int binder_thread_write(struct binder_proc *proc,
- if (list_empty(&buffer->target_node->async_todo))
- buffer->target_node->has_async_transaction = 0;
- else
- - list_move_tail(buffer->target_node->async_todo.next, &thread->todo);
- + list_move_tail(buffer->target_node->async_todo.next, &proc->todo);
- }
- trace_binder_transaction_buffer_release(buffer);
- binder_transaction_buffer_release(proc, buffer, NULL);
- diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
- index 09c07f5..292d888 100644
- --- a/drivers/base/power/wakeup.c
- +++ b/drivers/base/power/wakeup.c
- @@ -2,6 +2,7 @@
- * drivers/base/power/wakeup.c - System wakeup events framework
- *
- * Copyright (c) 2010 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
- + * Copyright (C) 2017 XiaoMi, Inc.
- *
- * This file is released under the GPLv2.
- */
- @@ -870,6 +871,7 @@ EXPORT_SYMBOL_GPL(pm_print_active_wakeup_sources);
- * since the old value was stored. Also return true if the current number of
- * wakeup events being processed is different from zero.
- */
- +bool wakeup_irq_abort_suspend;
- bool pm_wakeup_pending(void)
- {
- unsigned long flags;
- @@ -896,6 +898,7 @@ bool pm_wakeup_pending(void)
- void pm_system_wakeup(void)
- {
- pm_abort_suspend = true;
- + wakeup_irq_abort_suspend = true;
- freeze_wake();
- }
- EXPORT_SYMBOL_GPL(pm_system_wakeup);
- @@ -903,6 +906,7 @@ EXPORT_SYMBOL_GPL(pm_system_wakeup);
- void pm_wakeup_clear(void)
- {
- pm_abort_suspend = false;
- + wakeup_irq_abort_suspend = false;
- pm_wakeup_irq = 0;
- }
- diff --git a/drivers/base/syscore.c b/drivers/base/syscore.c
- index 96c34a9..43fc837 100644
- --- a/drivers/base/syscore.c
- +++ b/drivers/base/syscore.c
- @@ -2,6 +2,7 @@
- * syscore.c - Execution of system core operations.
- *
- * Copyright (C) 2011 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
- + * Copyright (C) 2017 XiaoMi, Inc.
- *
- * This file is released under the GPLv2.
- */
- @@ -46,17 +47,25 @@ EXPORT_SYMBOL_GPL(unregister_syscore_ops);
- *
- * This function is executed with one CPU on-line and disabled interrupts.
- */
- +extern bool wakeup_irq_abort_suspend;
- int syscore_suspend(void)
- {
- struct syscore_ops *ops;
- int ret = 0;
- + char suspend_abort[MAX_SUSPEND_ABORT_LEN];
- trace_suspend_resume(TPS("syscore_suspend"), 0, true);
- pr_debug("Checking wakeup interrupts\n");
- /* Return error code if there are any wakeup interrupts pending. */
- - if (pm_wakeup_pending())
- + if (pm_wakeup_pending()) {
- + if (wakeup_irq_abort_suspend == false) {
- + pm_get_active_wakeup_sources(suspend_abort, MAX_SUSPEND_ABORT_LEN);
- + log_suspend_abort_reason(suspend_abort);
- + }
- + pr_err("PM: Abort system core suspend, wakeup interrupt or wakeup source detected");
- return -EBUSY;
- + }
- WARN_ONCE(!irqs_disabled(),
- "Interrupts enabled before system core suspend.\n");
- diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
- index 3c59417..fc7bfcb 100644
- --- a/drivers/block/zram/zram_drv.c
- +++ b/drivers/block/zram/zram_drv.c
- @@ -3,6 +3,7 @@
- *
- * Copyright (C) 2008, 2009, 2010 Nitin Gupta
- * 2012, 2013 Minchan Kim
- + * Copyright (C) 2017 XiaoMi, Inc.
- *
- * This code is released using a dual license strategy: BSD/GPL
- * You can choose the licence that better fits your requirements.
- @@ -49,6 +50,7 @@ static const char *default_compressor = "lzo";
- /* Module params (documentation at end) */
- static unsigned int num_devices = 1;
- +static struct zram **zram_devices;
- static inline void deprecated_attr_warn(const char *name)
- {
- @@ -411,6 +413,31 @@ static ssize_t compact_store(struct device *dev,
- return len;
- }
- +int zs_get_page_usage(unsigned long *total_pool_pages,
- + unsigned long *total_ori_pages)
- +{
- + int i;
- + *total_pool_pages = *total_ori_pages = 0;
- + if (!zram_devices)
- + return 0;
- + for (i = 0; i < num_devices; i++) {
- + struct zram *zram = zram_devices[i];
- + struct zram_meta *meta;
- + if (!zram)
- + return 0;
- + meta = zram->meta;
- + if (!down_read_trylock(&zram->init_lock))
- + continue;
- + if (init_done(zram)) {
- + *total_pool_pages += zs_get_total_pages(meta->mem_pool);
- + *total_ori_pages += atomic64_read(
- + &zram->stats.pages_stored);
- + }
- + up_read(&zram->init_lock);
- + }
- + return 0;
- +}
- +
- static ssize_t io_stat_show(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- @@ -1204,7 +1231,7 @@ static int zram_add(void)
- {
- struct zram *zram;
- struct request_queue *queue;
- - int ret, device_id;
- + int i, ret, device_id;
- zram = kzalloc(sizeof(struct zram), GFP_KERNEL);
- if (!zram)
- @@ -1288,6 +1315,13 @@ static int zram_add(void)
- zram->meta = NULL;
- zram->max_comp_streams = 1;
- + for (i = 0; i < num_devices; i++) {
- + if (!zram_devices[i]) {
- + zram_devices[i] = zram;
- + break;
- + }
- + }
- +
- pr_info("Added device: %s\n", zram->disk->disk_name);
- return device_id;
- @@ -1410,6 +1444,7 @@ static int zram_remove_cb(int id, void *ptr, void *data)
- static void destroy_devices(void)
- {
- + kfree(zram_devices);
- class_unregister(&zram_control_class);
- idr_for_each(&zram_index_idr, &zram_remove_cb, NULL);
- idr_destroy(&zram_index_idr);
- @@ -1420,6 +1455,10 @@ static int __init zram_init(void)
- {
- int ret;
- + zram_devices = kzalloc(num_devices * sizeof(struct zram *), GFP_KERNEL);
- + if (!zram_devices)
- + return -ENOMEM;
- +
- ret = class_register(&zram_control_class);
- if (ret) {
- pr_err("Unable to register zram-control class\n");
- diff --git a/drivers/bluetooth/btfm_slim.h b/drivers/bluetooth/btfm_slim.h
- index e67c696..bff12f0 100644
- --- a/drivers/bluetooth/btfm_slim.h
- +++ b/drivers/bluetooth/btfm_slim.h
- @@ -1,4 +1,5 @@
- /* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
- + * Copyright (C) 2017 XiaoMi, 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
- @@ -68,6 +69,7 @@ struct btfmslim {
- uint32_t num_rx_port;
- uint32_t num_tx_port;
- + uint32_t sample_rate;
- struct btfmslim_ch *rx_chs;
- struct btfmslim_ch *tx_chs;
- diff --git a/drivers/bluetooth/btfm_slim_codec.c b/drivers/bluetooth/btfm_slim_codec.c
- index 1ed366f..db72144 100644
- --- a/drivers/bluetooth/btfm_slim_codec.c
- +++ b/drivers/bluetooth/btfm_slim_codec.c
- @@ -1,4 +1,5 @@
- /* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
- + * Copyright (C) 2017 XiaoMi, 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
- @@ -134,6 +135,9 @@ int btfm_slim_dai_prepare(struct snd_pcm_substream *substream,
- BTFMSLIM_DBG("dai->name: %s, dai->id: %d, dai->rate: %d", dai->name,
- dai->id, dai->rate);
- + /* save sample rate */
- + btfmslim->sample_rate = dai->rate;
- +
- switch (dai->id) {
- case BTFM_FM_SLIM_TX:
- grp = true; nchan = 2;
- diff --git a/drivers/bluetooth/btfm_slim_wcn3990.c b/drivers/bluetooth/btfm_slim_wcn3990.c
- index a451ff3..f081fa0 100644
- --- a/drivers/bluetooth/btfm_slim_wcn3990.c
- +++ b/drivers/bluetooth/btfm_slim_wcn3990.c
- @@ -1,4 +1,5 @@
- /* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
- + * Copyright (C) 2017 XiaoMi, 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
- @@ -120,18 +121,6 @@ int btfm_slim_chrk_enable_port(struct btfmslim *btfmslim, uint8_t port_num,
- BTFMSLIM_ERR("failed to write (%d) reg 0x%x", ret, reg);
- goto error;
- }
- - } else if (port_num == CHRK_SB_PGD_PORT_TX_SCO) {
- - /* SCO Tx */
- - reg_val = 0x1 << CHRK_SB_PGD_PORT_TX_SCO;
- - reg = CHRK_SB_PGD_TX_PORTn_MULTI_CHNL_0(port_num);
- - BTFMSLIM_DBG("writing reg_val (%d) to reg(%x)",
- - reg_val, reg);
- - ret = btfm_slim_write(btfmslim, reg, 1, ®_val, IFD);
- - if (ret) {
- - BTFMSLIM_ERR("failed to write (%d) reg 0x%x",
- - ret, reg);
- - goto error;
- - }
- }
- /* Enable Tx port hw auto recovery for underrun or overrun error */
- diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c
- index 3c10462..d5bdd80 100644
- --- a/drivers/char/diag/diag_masks.c
- +++ b/drivers/char/diag/diag_masks.c
- @@ -1,4 +1,5 @@
- /* Copyright (c) 2008-2017, The Linux Foundation. All rights reserved.
- + * Copyright (C) 2017 XiaoMi, 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
- @@ -707,6 +708,7 @@ static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len,
- pr_err_ratelimited("diag: In %s, unable to allocate memory for msg mask ptr, mask_size: %d\n",
- __func__, mask_size);
- mutex_unlock(&mask->lock);
- + mutex_unlock(&mask_info->lock);
- return -ENOMEM;
- }
- mask->ptr = temp;
- diff --git a/drivers/clk/msm/clock-debug.c b/drivers/clk/msm/clock-debug.c
- index 0fe93ed..4bb2980 100644
- --- a/drivers/clk/msm/clock-debug.c
- +++ b/drivers/clk/msm/clock-debug.c
- @@ -35,7 +35,7 @@ static LIST_HEAD(clk_list);
- static DEFINE_MUTEX(clk_list_lock);
- static struct dentry *debugfs_base;
- -static u32 debug_suspend;
- +static u32 debug_suspend = 1;
- static int clock_debug_rate_set(void *data, u64 val)
- {
- diff --git a/drivers/clk/msm/clock-mmss-8998.c b/drivers/clk/msm/clock-mmss-8998.c
- index fdaaa72..63d0e18 100644
- --- a/drivers/clk/msm/clock-mmss-8998.c
- +++ b/drivers/clk/msm/clock-mmss-8998.c
- @@ -1,4 +1,5 @@
- /* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
- + * Copyright (C) 2017 XiaoMi, 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
- @@ -359,6 +360,7 @@ static struct rcg_clk mdp_clk_src = {
- .set_rate = set_rate_hid,
- .freq_tbl = ftbl_mdp_clk_src,
- .current_freq = &rcg_dummy_freq,
- + .non_local_control_timeout = 1000,
- .non_local_children = true,
- .base = &virt_base,
- .c = {
- diff --git a/drivers/clk/msm/mdss/mdss-dsi-pll-8998.c b/drivers/clk/msm/mdss/mdss-dsi-pll-8998.c
- index ad6d80d..36e4c05 100644
- --- a/drivers/clk/msm/mdss/mdss-dsi-pll-8998.c
- +++ b/drivers/clk/msm/mdss/mdss-dsi-pll-8998.c
- @@ -156,7 +156,7 @@ static void dsi_pll_config_slave(struct mdss_pll_resources *rsc)
- rsc->slave = NULL;
- if (!orsc) {
- - pr_warn("slave PLL unavilable, assuming standalone config\n");
- + pr_debug("slave PLL unavilable, assuming standalone config\n");
- return;
- }
- diff --git a/drivers/elliptic/Makefile b/drivers/elliptic/Makefile
- new file mode 100644
- index 0000000..b4161b6
- --- /dev/null
- +++ b/drivers/elliptic/Makefile
- @@ -0,0 +1,17 @@
- +ccflags-y := -I$(src) -Wall -Werror
- +IO_MODULE := msm
- +MIXER_MODULE := test
- +
- +EXTRA_CFLAGS += -DDEBUG
- +
- +obj-y += elliptic.o io_modules/$(IO_MODULE)/elliptic_data_io.o elliptic_sysfs.o
- +# elliptic_driver-y := elliptic.o
- +# elliptic_driver-y += io_modules/$(IO_MODULE)/elliptic_data_io.o
- +# elliptic_driver-y += mixer_controls/$(MIXER_MODULE)/elliptic_mixer_controls.o
- +# elliptic_driver-y += elliptic_sysfs.o
- +
- +# .PHONY: clean
- +# all:
- +# make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) modules
- +# clean:
- +# rm *.o *.ko
- diff --git a/drivers/elliptic/elliptic.c b/drivers/elliptic/elliptic.c
- new file mode 100644
- index 0000000..a399f14
- --- /dev/null
- +++ b/drivers/elliptic/elliptic.c
- @@ -0,0 +1,716 @@
- +/**
- +* Copyright Elliptic Labs
- +* Copyright (C) 2017 XiaoMi, Inc.
- +*
- +*/
- +/* #define DEBUG*/
- +#include <linux/module.h>
- +#include <linux/kernel.h>
- +#include <linux/version.h>
- +/* includes the file structure, that is, file open read close */
- +#include <linux/fs.h>
- +
- +#include <sound/apr_elliptic.h>
- +
- +/* include the character device, makes cdev avilable */
- +#include <linux/cdev.h>
- +#include <linux/semaphore.h>
- +
- +/* includes copy_user vice versa */
- +#include <linux/uaccess.h>
- +#include <linux/spinlock.h>
- +#include <linux/slab.h>
- +#include <linux/stat.h>
- +#include <linux/init.h>
- +#include <linux/platform_device.h>
- +#include <linux/types.h>
- +#include <linux/kdev_t.h>
- +#include <linux/device.h>
- +
- +#include <linux/pm_wakeup.h>
- +#include <linux/kfifo.h>
- +#include <linux/poll.h>
- +#include <linux/kobject.h>
- +
- +#include "elliptic_sysfs.h"
- +#include "elliptic_device.h"
- +#include "elliptic_data_io.h"
- +
- +static struct elliptic_device *elliptic_devices;
- +
- +/* Global variable for the device class*/
- +struct class *elliptic_class;
- +
- +typedef uint32_t el_fifo_size_t;
- +
- +/* Major number provided by the kernel*/
- +static dev_t elliptic_major;
- +
- +static struct wakeup_source *wake_source;
- +
- +
- +void elliptic_data_reset_debug_counters(struct elliptic_data
- + *elliptic_data) {
- +
- + elliptic_data->isr_fifo_flush_count = 0;
- + elliptic_data->userspace_fifo_flush_count = 0;
- +}
- +
- +void elliptic_data_print_debug_counters(struct elliptic_data
- + *elliptic_data) {
- +
- + if (elliptic_data->isr_fifo_flush_count > 0) {
- + EL_PRINT_E("isr fifo flushed %u times",
- + elliptic_data->isr_fifo_flush_count);
- + }
- +
- + if (elliptic_data->userspace_fifo_flush_count > 0) {
- + EL_PRINT_E("userspace fifo flushed %u times",
- + elliptic_data->userspace_fifo_flush_count);
- + }
- +
- + if (elliptic_data->userspace_read_total !=
- + elliptic_data->isr_write_total) {
- + EL_PRINT_I("user space reads / isr writes : %u / %u",
- + elliptic_data->userspace_read_total,
- + elliptic_data->isr_write_total);
- + }
- +
- + EL_PRINT_I(
- + "total isr fifo flushed count : %u",
- + elliptic_data->isr_fifo_flush_count_total);
- +
- + EL_PRINT_I("total userspace fifo flushed count : %u",
- + elliptic_data->userspace_fifo_flush_count_total);
- +
- +
- +}
- +
- +void elliptic_data_update_debug_counters(struct elliptic_data
- + *elliptic_data)
- +{
- + elliptic_data->isr_fifo_flush_count_total +=
- + elliptic_data->isr_fifo_flush_count;
- + elliptic_data->userspace_fifo_flush_count_total +=
- + elliptic_data->userspace_fifo_flush_count;
- +}
- +
- +
- +/* spin lock for isr must be held prior to calling */
- +static void elliptic_data_flush_isr_fifo(struct elliptic_data
- + *elliptic_data)
- +{
- + kfifo_reset(&elliptic_data->fifo_isr);
- +}
- +
- +/* mutex lock for user space copy must be held prior to calling */
- +static void elliptic_data_flush_userspace_fifo(struct elliptic_data
- + *elliptic_data)
- +{
- + kfifo_reset(&elliptic_data->fifo_userspace);
- +}
- +
- +/* inode refers to the actual file on disk */
- +static int device_open(struct inode *inode, struct file *filp)
- +{
- + unsigned int major;
- + unsigned int minor;
- + struct elliptic_device *dev;
- + struct elliptic_data *elliptic_data;
- +
- + major = imajor(inode);
- + minor = iminor(inode);
- +
- + if (major != elliptic_major || minor < 0
- + || minor >= ELLIPTIC_NUM_DEVICES) {
- + EL_PRINT_W("no device found with minor=%d and major=%d",
- + major, minor);
- + return -ENODEV; /* No such device */
- + }
- +
- + dev = NULL;
- + dev = &elliptic_devices[minor];
- + filp->private_data = dev;
- +
- + if (inode->i_cdev != &dev->cdev) {
- + EL_PRINT_W("dev pointer mismatch");
- + return -ENODEV; /* No such device */
- + }
- +
- + if (down_interruptible(&dev->sem) != 0) {
- + EL_PRINT_E("the device has been opened, unable to open lock");
- + return -EINVAL;
- + }
- +
- + elliptic_data = &dev->el_data;
- + spin_lock(&elliptic_data->fifo_isr_spinlock);
- + elliptic_data_flush_isr_fifo(elliptic_data);
- + spin_unlock(&elliptic_data->fifo_isr_spinlock);
- +
- + mutex_lock(&elliptic_data->fifo_usp_lock);
- + elliptic_data_flush_userspace_fifo(elliptic_data);
- + mutex_unlock(&elliptic_data->fifo_usp_lock);
- +
- + elliptic_data_reset_debug_counters(elliptic_data);
- +
- + EL_PRINT_I("Opened device elliptic%u", minor);
- + dev->opened = 1;
- + return 0;
- +}
- +
- +static void elliptic_data_work_handler(struct work_struct *ws)
- +{
- + struct elliptic_data *elliptic_data;
- + unsigned long flags;
- +
- + unsigned int fifo_result = 0;
- + size_t available_space = 0;
- +
- + elliptic_data = container_of(ws, struct elliptic_data, work);
- +
- + if (kfifo_is_empty(&elliptic_data->fifo_isr)) {
- + EL_PRINT_W("work handler called when isr fifo is empty");
- + return;
- + }
- +
- + mutex_lock(&elliptic_data->fifo_usp_lock);
- +
- + spin_lock_irqsave(&elliptic_data->fifo_isr_spinlock, flags);
- +
- + fifo_result = kfifo_out(&elliptic_data->fifo_isr,
- + elliptic_data->isr_swap_buffer, ELLIPTIC_MSG_BUF_SIZE);
- + if (fifo_result == 0) {
- + EL_PRINT_E("failed to copy from fifo isr to swap buffer %u",
- + fifo_result);
- + goto fail;
- + }
- +
- + available_space = kfifo_avail(&elliptic_data->fifo_userspace);
- +
- + if (available_space < ELLIPTIC_MSG_BUF_SIZE) {
- + EL_PRINT_E("available_space %lu, entry_size %lu. Flushing fifo",
- + available_space, (size_t)ELLIPTIC_MSG_BUF_SIZE);
- +
- + ++elliptic_data->userspace_fifo_flush_count;
- + elliptic_data_flush_userspace_fifo(elliptic_data);
- + goto fail;
- + }
- +
- + fifo_result = kfifo_in(&elliptic_data->fifo_userspace,
- + elliptic_data->isr_swap_buffer, ELLIPTIC_MSG_BUF_SIZE);
- + if (fifo_result == 0) {
- + EL_PRINT_E("failed to copy from swap to fifo user space: %u",
- + fifo_result);
- + goto fail;
- + }
- +
- + spin_unlock_irqrestore(&elliptic_data->fifo_isr_spinlock, flags);
- + mutex_unlock(&elliptic_data->fifo_usp_lock);
- + wake_up_interruptible(&elliptic_data->fifo_usp_not_empty);
- + __pm_wakeup_event(wake_source, elliptic_data->wakeup_timeout);
- + return;
- +
- +fail:
- + spin_unlock_irqrestore(&elliptic_data->fifo_isr_spinlock, flags);
- + mutex_unlock(&elliptic_data->fifo_usp_lock);
- +
- +}
- +
- +#define WORK_QUEUE_HANDLER_NAME_LENGTH 64
- +int elliptic_data_initialize(struct elliptic_data
- + *elliptic_data, size_t queue_size,
- + unsigned int wakeup_timeout, int id)
- +{
- + int is_power_of_two;
- +
- + char name[WORK_QUEUE_HANDLER_NAME_LENGTH] = {0};
- +
- + is_power_of_two = (queue_size != 0) && !(queue_size & (queue_size - 1));
- +
- + if (is_power_of_two != 1) {
- + EL_PRINT_E("non power of 2 fifo size");
- + return -EINVAL;
- + }
- +
- + if (kfifo_alloc(&elliptic_data->fifo_isr,
- + queue_size, GFP_KERNEL) != 0) {
- + EL_PRINT_E("failed to allocate fifo isr");
- + return -EINVAL;
- + }
- +
- + if (kfifo_alloc(&elliptic_data->fifo_userspace,
- + queue_size, GFP_KERNEL) != 0) {
- +
- + EL_PRINT_E("failed to allocate fifo user space");
- + return -EINVAL;
- + }
- +
- +
- + atomic_set(&elliptic_data->abort_io, 0);
- + spin_lock_init(&elliptic_data->fifo_isr_spinlock);
- +
- + INIT_WORK(&elliptic_data->work, elliptic_data_work_handler);
- + mutex_init(&elliptic_data->fifo_usp_lock);
- + init_waitqueue_head(&elliptic_data->fifo_usp_not_empty);
- +
- + snprintf(name, WORK_QUEUE_HANDLER_NAME_LENGTH,
- + "%s_%d", "ELLIPTIC_DATA_WORK_HANDLER", id);
- + elliptic_data->wq = create_singlethread_workqueue(name);
- +
- + return 0;
- +}
- +
- +int elliptic_data_cleanup(struct elliptic_data *elliptic_data)
- +{
- + spin_unlock(&elliptic_data->fifo_isr_spinlock);
- + kfifo_free(&elliptic_data->fifo_isr);
- + return 0;
- +}
- +
- +size_t elliptic_data_pop(struct elliptic_data
- + *elliptic_data, char __user *buffer, size_t buffer_size)
- +{
- + int result;
- + unsigned int num_copied;
- +
- + if (buffer_size < ELLIPTIC_MSG_BUF_SIZE) {
- + EL_PRINT_E("buffer_size : %lu smaller than %lu",
- + buffer_size, (size_t)ELLIPTIC_MSG_BUF_SIZE);
- + return 0;
- + }
- +
- + result = wait_event_interruptible(elliptic_data->fifo_usp_not_empty,
- + (kfifo_is_empty(&elliptic_data->fifo_userspace) == 0)
- + || (atomic_read(&elliptic_data->abort_io) == 1));
- +
- + if (atomic_read(&elliptic_data->abort_io) == 1) {
- + atomic_set(&elliptic_data->abort_io, 0);
- + EL_PRINT_D("pop cancelled");
- + return 0;
- + }
- +
- +
- + if (result == 0) {
- + mutex_lock(&elliptic_data->fifo_usp_lock);
- +
- + num_copied = 0;
- + result = kfifo_to_user(&elliptic_data->fifo_userspace, buffer,
- + ELLIPTIC_MSG_BUF_SIZE, &num_copied);
- +
- + if (result == -EFAULT) {
- + EL_PRINT_E("failed kfifo_to_user");
- + mutex_unlock(&elliptic_data->fifo_usp_lock);
- + return 0;
- + }
- +
- + mutex_unlock(&elliptic_data->fifo_usp_lock);
- + ++elliptic_data->userspace_read_total;
- +
- + if ((size_t)num_copied != ELLIPTIC_MSG_BUF_SIZE) {
- + EL_PRINT_E("copied less than entry size : %u"
- + , num_copied);
- + return (size_t)num_copied;
- + }
- + } else {
- + if (-ERESTARTSYS == result)
- + EL_PRINT_D("wait interrupted");
- + else
- + EL_PRINT_E("wait error = %d", result);
- + }
- +
- + return (size_t)ELLIPTIC_MSG_BUF_SIZE;
- +}
- +
- +int elliptic_data_push(const char *buffer, size_t buffer_size)
- +{
- + size_t available_space;
- + size_t space_required;
- + size_t zeros_to_pad;
- + int err;
- + int i;
- + unsigned long flags;
- + struct elliptic_device *device;
- + struct elliptic_data *elliptic_data;
- + unsigned int fifo_result;
- + static uint8_t zero_pad_buffer[ELLIPTIC_MSG_BUF_SIZE];
- +
- + err = 0;
- + fifo_result = 0;
- +
- + if (buffer_size > ELLIPTIC_MSG_BUF_SIZE) {
- + EL_PRINT_E("buffer size %lu is larger than max buffer size %lu",
- + buffer_size, (size_t)ELLIPTIC_MSG_BUF_SIZE);
- + return -EINVAL;
- + }
- +
- +
- + zeros_to_pad = ELLIPTIC_MSG_BUF_SIZE - buffer_size;
- +
- + for (i = 0; i < ELLIPTIC_NUM_DEVICES; ++i) {
- + device = &elliptic_devices[i];
- + elliptic_data = &device->el_data;
- +
- + if ((!device->opened))
- + continue;
- +
- + available_space = kfifo_avail(&elliptic_data->fifo_isr);
- + space_required = ELLIPTIC_MSG_BUF_SIZE;
- +
- + spin_lock_irqsave(&elliptic_data->fifo_isr_spinlock, flags);
- +
- + if (available_space < space_required) {
- + EL_PRINT_W("fifo space too small: %lu, flushing fifo",
- + available_space);
- +
- + ++elliptic_data->isr_fifo_flush_count;
- + elliptic_data_flush_isr_fifo(elliptic_data);
- + }
- +
- + fifo_result = kfifo_in(&elliptic_data->fifo_isr,
- + buffer, buffer_size);
- + if (fifo_result == 0) {
- + EL_PRINT_W("failed to push buffer to fifo");
- + spin_unlock_irqrestore(
- + &elliptic_data->fifo_isr_spinlock, flags);
- + continue;
- + }
- +
- + if (zeros_to_pad > 0) {
- + fifo_result = kfifo_in(
- + &elliptic_data->fifo_isr, zero_pad_buffer,
- + zeros_to_pad);
- + if (fifo_result == 0) {
- + EL_PRINT_W("zero pad failed, flushing fifo");
- + spin_unlock_irqrestore(
- + &elliptic_data->fifo_isr_spinlock,
- + flags);
- +
- + ++elliptic_data->isr_fifo_flush_count;
- + elliptic_data_flush_isr_fifo(elliptic_data);
- + continue;
- + }
- + }
- +
- + ++elliptic_data->isr_write_total;
- + spin_unlock_irqrestore(
- + &elliptic_data->fifo_isr_spinlock, flags);
- +
- + queue_work(elliptic_data->wq, &elliptic_data->work);
- + }
- +
- + return err;
- +}
- +
- +
- +/**
- +*
- +* @return Number of bytes read.
- +*/
- +static ssize_t device_read(struct file *fp, char __user *buff,
- + size_t length, loff_t *ppos)
- +{
- + ssize_t bytes_read = 0;
- + struct elliptic_device *elliptic_device;
- + struct elliptic_data *elliptic_data;
- +
- + elliptic_device = (struct elliptic_device *)fp->private_data;
- + elliptic_data = (struct elliptic_data *)&elliptic_device->el_data;
- +
- + bytes_read = elliptic_data_pop(elliptic_data, buff, length);
- +
- + return bytes_read;
- +}
- +
- +/**
- +*
- +* @return number of bytes actually written
- +*/
- +static ssize_t device_write(struct file *fp, const char *buff,
- + size_t length, loff_t *ppos)
- +{
- + ssize_t ret_val;
- +
- + ret_val = 0;
- + if ((buff != NULL) && (length != 0))
- + ret_val = elliptic_data_io_write(ELLIPTIC_ULTRASOUND_SET_PARAMS,
- + buff, length);
- +
- + return ret_val >= 0 ? (ssize_t)length : 0;
- +}
- +
- +
- +static long device_ioctl(struct file *fp, unsigned int number,
- + unsigned long param)
- +{
- + struct elliptic_device *device;
- + struct elliptic_data *elliptic_data;
- + int err;
- + unsigned int mirror_tag, mirror_payload_size;
- + unsigned char *data_ptr;
- +
- + device = (struct elliptic_device *)(fp->private_data);
- + elliptic_data = &device->el_data;
- +
- + switch (number) {
- + case IOCTL_ELLIPTIC_DATA_IO_CANCEL:
- + EL_PRINT_D("IOCTL_ELLIPTIC_CANCEL_READ %ld",
- + param);
- + elliptic_data_io_cancel(elliptic_data);
- + break;
- +
- + case IOCTL_ELLIPTIC_DATA_IO_MIRROR:
- + data_ptr = (unsigned char *) param;
- + mirror_tag = *(unsigned int *) data_ptr;
- + mirror_payload_size = *((unsigned int *) data_ptr + 1);
- +
- + if ((mirror_tag == MIRROR_TAG) &&
- + (mirror_payload_size != 0) &&
- + (mirror_payload_size <=
- + (ELLIPTIC_SET_PARAMS_SIZE * 4))) {
- +
- + err = elliptic_data_io_write(
- + ELLIPTIC_ULTRASOUND_SET_PARAMS,
- + (data_ptr + 8), mirror_payload_size);
- +
- + if (err != 0) {
- + EL_PRINT_E("elliptic_data_io_write failed");
- + return err;
- + }
- +
- + } else {
- + EL_PRINT_E("TAG or Length is not valid");
- + }
- +
- + break;
- +
- + default:
- + EL_PRINT_W("UNKNOWN IOCTL number=%d", number);
- + break;
- + }
- +
- + return 0;
- +}
- +
- +
- +static unsigned int device_poll(struct file *file,
- + struct poll_table_struct *poll_table)
- +{
- + unsigned int mask;
- +
- + struct elliptic_device *device;
- + struct elliptic_data *elliptic_data;
- +
- + mask = 0;
- + device = (struct elliptic_device *)file->private_data;
- + elliptic_data = (struct elliptic_data *)&device->el_data;
- +
- + poll_wait(file, &elliptic_data->fifo_usp_not_empty, poll_table);
- +
- + if (!kfifo_is_empty(&elliptic_data->fifo_userspace))
- + mask = POLLIN | POLLRDNORM;
- +
- + return mask;
- +}
- +
- +
- +static int device_close(struct inode *inode, struct file *filp)
- +{
- + struct elliptic_device *device;
- + struct elliptic_data *elliptic_data;
- + unsigned int minor;
- +
- + device = filp->private_data;
- + elliptic_data = &device->el_data;
- + minor = iminor(inode);
- + if (device == NULL) {
- + EL_PRINT_E("device not found");
- + return -ENODEV;
- + }
- +
- + device->opened = 0;
- + elliptic_data_update_debug_counters(elliptic_data);
- + elliptic_data_print_debug_counters(elliptic_data);
- +
- + up(&device->sem);
- +
- + EL_PRINT_I("Closed device elliptic%u", minor);
- + return 0;
- +}
- +
- +/* defines the file operations provided by the driver */
- +static const struct file_operations elliptic_fops = {
- + .owner = THIS_MODULE, /* prevents unloading when operations are in use*/
- + .open = device_open, /*to open the device*/
- + .write = device_write, /*to write to the device*/
- + .read = device_read, /*to read the device*/
- + .poll = device_poll,
- + .unlocked_ioctl = device_ioctl, /* IOCTL calls */
- + .release = device_close, /*to close the device*/
- +};
- +
- +
- +static int elliptic_device_initialize(struct elliptic_device
- + *elliptic_device, int minor, struct class *class)
- +{
- + int err;
- + dev_t device_number;
- + struct device *device;
- +
- + BUG_ON(elliptic_device == NULL || class == NULL);
- +
- + err = 0;
- + device = NULL;
- + device_number = MKDEV(elliptic_major, minor);
- + /* Memory is to be allocated when the device is opened the first time */
- + sema_init(&elliptic_device->sem, 1);
- + cdev_init(&elliptic_device->cdev, &elliptic_fops);
- + elliptic_device->cdev.owner = THIS_MODULE;
- +
- + err = cdev_add(&elliptic_device->cdev, device_number, 1);
- +
- + if (err) {
- + EL_PRINT_E("error %d while trying to add %s%d",
- + err, ELLIPTIC_DEVICENAME, minor);
- + return err;
- + }
- +
- + device = device_create(class, NULL, device_number,
- + NULL, ELLIPTIC_DEVICENAME "%d", minor);
- +
- + if (IS_ERR(device)) {
- + err = PTR_ERR(device);
- + EL_PRINT_E("error %d while trying to create %s%d",
- + err, ELLIPTIC_DEVICENAME, minor);
- + cdev_del(&elliptic_device->cdev);
- + return err;
- + }
- +
- + if (err) {
- + EL_PRINT_E("failed device initialize");
- + return err;
- + }
- +
- + return 0;
- +}
- +
- +static void elliptic_device_cleanup(struct elliptic_device *dev, int minor,
- + struct class *class)
- +
- +{
- + BUG_ON(dev == NULL || class == NULL);
- + device_destroy(class, MKDEV(elliptic_major, minor));
- + cdev_del(&dev->cdev);
- + up(&dev->sem);
- +}
- +
- +static void elliptic_driver_cleanup(int devices_to_destroy)
- +{
- + int i;
- +
- + if (elliptic_devices) {
- + elliptic_data_io_cleanup();
- +
- + for (i = 0; i < devices_to_destroy; ++i) {
- + elliptic_data_cleanup(&elliptic_devices[i].el_data);
- + elliptic_device_cleanup(
- + &elliptic_devices[i], i, elliptic_class);
- + }
- +
- + kfree(elliptic_devices);
- + }
- +
- + if (elliptic_class)
- + class_destroy(elliptic_class);
- +
- + unregister_chrdev_region(
- + MKDEV(elliptic_major, 0), ELLIPTIC_NUM_DEVICES);
- +}
- +static int __init elliptic_driver_init(void)
- +{
- + int err;
- + int i;
- + int devices_to_destroy;
- + dev_t device_number;
- +
- + err = alloc_chrdev_region(&device_number, 0, ELLIPTIC_NUM_DEVICES,
- + ELLIPTIC_DEVICENAME);
- +
- + if (err < 0) {
- + EL_PRINT_E("Failed to allocate cdev region");
- + return err;
- + }
- +
- + elliptic_major = MAJOR(device_number);
- + elliptic_class = class_create(THIS_MODULE, "chardev");
- +
- + if (elliptic_class == NULL) {
- + EL_PRINT_E("Class creation failed");
- + goto fail;
- + }
- +
- + err = elliptic_initialize_sysfs();
- +
- + if (err)
- + goto fail;
- +
- + elliptic_devices = (struct elliptic_device *)
- + kzalloc(sizeof(struct elliptic_device) * ELLIPTIC_NUM_DEVICES,
- + GFP_KERNEL);
- +
- + if (elliptic_devices == NULL) {
- + err = -ENOMEM;
- + goto fail;
- + }
- +
- + if (elliptic_data_io_initialize())
- + goto fail;
- +
- +
- + devices_to_destroy = 0;
- +
- + for (i = 0; i < ELLIPTIC_NUM_DEVICES; ++i) {
- + if (elliptic_device_initialize(&elliptic_devices[i], i,
- + elliptic_class)) {
- + devices_to_destroy = i;
- + goto fail;
- + }
- +
- + if (elliptic_data_initialize(&elliptic_devices[i].el_data,
- + ELLIPTIC_DATA_FIFO_SIZE, ELLIPTIC_WAKEUP_TIMEOUT, i)) {
- + goto fail;
- + }
- + }
- +
- + wake_source = kmalloc(sizeof(struct wakeup_source), GFP_KERNEL);
- +
- + if (!wake_source) {
- + EL_PRINT_E("failed to allocate wake source");
- + return -ENOMEM;
- + }
- +
- + wakeup_source_init(wake_source, "elliptic_wake_source");
- +
- + return 0;
- +
- +fail:
- + elliptic_driver_cleanup(devices_to_destroy);
- + return err;
- +}
- +
- +static void elliptic_driver_exit(void)
- +{
- + if (wake_source) {
- + wakeup_source_trash(wake_source);
- + kfree(wake_source);
- + }
- +
- + elliptic_cleanup_sysfs();
- + elliptic_driver_cleanup(ELLIPTIC_NUM_DEVICES);
- +}
- +
- +MODULE_AUTHOR("Elliptic Labs");
- +MODULE_DESCRIPTION("Providing Interface to UPS data");
- +MODULE_LICENSE("GPL");
- +
- +module_init(elliptic_driver_init);
- +module_exit(elliptic_driver_exit);
- diff --git a/drivers/elliptic/elliptic_data_io.h b/drivers/elliptic/elliptic_data_io.h
- new file mode 100644
- index 0000000..648e519
- --- /dev/null
- +++ b/drivers/elliptic/elliptic_data_io.h
- @@ -0,0 +1,100 @@
- +/**
- +* Copyright Elliptic Labs 2015-2016
- +* Copyright (C) 2017 XiaoMi, Inc.
- +*
- +*/
- +
- +#pragma once
- +
- +#include <linux/types.h>
- +#include <linux/kfifo.h>
- +#include <linux/spinlock.h>
- +#include <linux/wait.h>
- +#include <linux/module.h>
- +#include <linux/kernel.h>
- +#include <linux/workqueue.h>
- +
- +#define ELLIPTIC_DATA_IO_AP_TO_DSP 0
- +#define ELLIPTIC_DATA_IO_DSP_TO_AP 1
- +
- +#define ELLIPTIC_DATA_IO_READ_OK 0
- +#define ELLIPTIC_DATA_IO_READ_BUSY 1
- +#define ELLIPTIC_DATA_IO_READ_CANCEL 2
- +
- +#define ELLIPTIC_MSG_BUF_SIZE 512
- +
- +/* wake source timeout in ms*/
- +#define ELLIPTIC_WAKEUP_TIMEOUT 250
- +
- +#define ELLIPTIC_DATA_FIFO_SIZE (PAGE_SIZE)
- +
- +
- +enum elliptic_message_id {
- + ELLIPTIC_MESSAGE_PAYLOAD, /* Input to AP*/
- + ELLIPTIC_MESSAGE_RAW, /* Output from AP*/
- + ELLIPTIC_MESSAGE_CALIBRATION,
- + ELLIPTIC_MAX_MESSAGE_IDS
- +};
- +
- +struct elliptic_data {
- + unsigned int wakeup_timeout; /* wake lock timeout */
- +
- + /* members for top half interrupt handling */
- + struct kfifo fifo_isr;
- + spinlock_t fifo_isr_spinlock;
- +
- + /* buffer to swap data from isr fifo to userspace fifo */
- + uint8_t isr_swap_buffer[ELLIPTIC_MSG_BUF_SIZE];
- +
- + /* members for bottom half handling */
- + struct kfifo fifo_userspace;
- + struct mutex fifo_usp_lock;
- + wait_queue_head_t fifo_usp_not_empty;
- +
- + atomic_t abort_io;
- + struct work_struct work;
- + struct workqueue_struct *wq;
- +
- + /* debug counters, reset between open/close */
- + uint32_t isr_fifo_flush_count;
- + uint32_t userspace_fifo_flush_count;
- +
- + /* debug counters, persistent */
- + uint32_t isr_fifo_flush_count_total;
- + uint32_t userspace_fifo_flush_count_total;
- + uint32_t userspace_read_total;
- + uint32_t isr_write_total;
- +
- +};
- +
- +/* Elliptic IO module API (implemented by IO module)*/
- +
- +int elliptic_data_io_initialize(void);
- +int elliptic_data_io_cleanup(void);
- +void elliptic_data_io_cancel(struct elliptic_data *);
- +
- +int32_t elliptic_data_io_write(uint32_t message_id, const char *data,
- + size_t data_size);
- +
- +int32_t elliptic_data_io_transact(uint32_t message_id, const char *data,
- + size_t data_size, char *output_data, size_t output_data_size);
- +
- +
- +/* Elliptic driver API (implemented by main driver)*/
- +int elliptic_data_initialize(struct elliptic_data *,
- + size_t max_queue_size, unsigned int wakeup_timeout, int id);
- +
- +int elliptic_data_cleanup(struct elliptic_data *);
- +
- +void elliptic_data_reset_debug_counters(struct elliptic_data *);
- +void elliptic_data_update_debug_counters(struct elliptic_data *);
- +void elliptic_data_print_debug_counters(struct elliptic_data *);
- +
- +size_t elliptic_data_pop(struct elliptic_data *,
- + char __user *buffer, size_t buffer_size);
- +
- +void elliptic_data_cancel(struct elliptic_data *);
- +
- +/* Called from IO module*/
- +int elliptic_data_push(const char *buffer, size_t buffer_size);
- +
- diff --git a/drivers/elliptic/elliptic_device.h b/drivers/elliptic/elliptic_device.h
- new file mode 100644
- index 0000000..87c7b15
- --- /dev/null
- +++ b/drivers/elliptic/elliptic_device.h
- @@ -0,0 +1,54 @@
- +/**
- + * Copyright Elliptic Labs
- + * Copyright (C) 2017 XiaoMi, Inc.
- + *
- + */
- +
- +#pragma once
- +
- +#include <linux/ioctl.h>
- +#include <linux/cdev.h>
- +#include <linux/semaphore.h>
- +#include "elliptic_data_io.h"
- +
- +#define ELLIPTIC_DEVICENAME "elliptic"
- +#define ELLIPTIC_NUM_DEVICES 2
- +
- +#define IOCTL_ELLIPTIC_APP 197
- +#define MIRROR_TAG 0x3D0A4842
- +
- +#define IOCTL_ELLIPTIC_DATA_IO_CANCEL \
- + _IO(IOCTL_ELLIPTIC_APP, 2)
- +
- +#define IOCTL_ELLIPTIC_ACTIVATE_ENGINE \
- + _IOW(IOCTL_ELLIPTIC_APP, 3, int)
- +
- +#define IOCTL_ELLIPTIC_SET_RAMP_DOWN \
- + _IO(IOCTL_ELLIPTIC_APP, 4)
- +
- +#define IOCTL_ELLIPTIC_SYSTEM_CONFIGURATION \
- + _IOW(IOCTL_ELLIPTIC_APP, 5, int)
- +
- +#define IOCTL_ELLIPTIC_DATA_IO_MIRROR \
- + _IOW(IOCTL_ELLIPTIC_APP, 117, unsigned char *)
- +
- +struct elliptic_device {
- + int opened;
- + struct cdev cdev;
- + struct semaphore sem;
- + struct elliptic_data el_data;
- +};
- +
- +
- +#define EL_PRINT_E(string, arg...) \
- + pr_err("[ELUS] : (%s) : " string "\n", __func__, ##arg)
- +
- +#define EL_PRINT_W(string, arg...) \
- + pr_warn("[ELUS] : (%s) : " string "\n", __func__, ##arg)
- +
- +#define EL_PRINT_I(string, arg...) \
- + pr_info("[ELUS] : (%s) : " string "\n", __func__, ##arg)
- +
- +#define EL_PRINT_D(string, arg...) \
- + pr_debug("[ELUS] : (%s) : " string "\n", __func__, ##arg)
- +
- diff --git a/drivers/elliptic/elliptic_mixer_controls.h b/drivers/elliptic/elliptic_mixer_controls.h
- new file mode 100644
- index 0000000..356923d
- --- /dev/null
- +++ b/drivers/elliptic/elliptic_mixer_controls.h
- @@ -0,0 +1,27 @@
- +#pragma once
- +#include <sound/core.h>
- +#include <sound/pcm.h>
- +#include <sound/soc.h>
- +#include <linux/types.h>
- +
- +
- +#define ELLIPTIC_OBJ_ID_CALIBRATION_DATA 1
- +#define ELLIPTIC_OBJ_ID_VERSION_INFO 2
- +#define ELLIPTIC_OBJ_ID_BRANCH_INFO 3
- +
- +struct elliptic_engine_version_info {
- + uint32_t major;
- + uint32_t minor;
- + uint32_t build;
- + uint32_t revision;
- +};
- +
- +struct elliptic_shared_data_block {
- + uint32_t object_id;
- + size_t size;
- + void *buffer;
- +};
- +
- +struct elliptic_shared_data_block *elliptic_get_shared_obj(uint32_t
- + object_id);
- +
- diff --git a/drivers/elliptic/elliptic_sysfs.c b/drivers/elliptic/elliptic_sysfs.c
- new file mode 100644
- index 0000000..680cc92
- --- /dev/null
- +++ b/drivers/elliptic/elliptic_sysfs.c
- @@ -0,0 +1,182 @@
- +#include <linux/kobject.h>
- +#include <linux/sysfs.h>
- +#include <linux/device.h>
- +#include <linux/uaccess.h>
- +#include <linux/module.h>
- +#include "elliptic_device.h"
- +#include "elliptic_sysfs.h"
- +#include "elliptic_mixer_controls.h"
- +
- +static int kobject_create_and_add_failed;
- +static int sysfs_create_group_failed;
- +
- +static ssize_t calibration_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count) {
- +
- + ssize_t result;
- +
- + struct elliptic_shared_data_block *calibration_obj =
- + elliptic_get_shared_obj(ELLIPTIC_OBJ_ID_CALIBRATION_DATA);
- +
- + if (calibration_obj == NULL) {
- + EL_PRINT_E("calibration_obj is NULL");
- + return -EINVAL;
- + }
- +
- + if (count > calibration_obj->size) {
- + EL_PRINT_E("write length %zu larger than buffer", count);
- + return 0;
- + }
- +
- + memcpy(calibration_obj->buffer, buf, count);
- + result = (ssize_t)count;
- + return result;
- +}
- +
- +static ssize_t calibration_show(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + ssize_t result;
- + int length;
- + int i;
- + uint8_t *caldata;
- +
- + struct elliptic_shared_data_block *calibration_obj =
- + elliptic_get_shared_obj(ELLIPTIC_OBJ_ID_CALIBRATION_DATA);
- +
- + if (kobject_create_and_add_failed)
- + EL_PRINT_E("kobject_create_and_add_failed");
- +
- + if (sysfs_create_group_failed)
- + EL_PRINT_E("sysfs_create_group_failed");
- +
- + if (calibration_obj == NULL) {
- + EL_PRINT_E("calibration_obj is NULL");
- + return -EINVAL;
- + }
- +
- + if (calibration_obj->size > PAGE_SIZE) {
- + EL_PRINT_E("calibration_obj->size > PAGE_SIZE");
- + return -EINVAL;
- + }
- +
- + caldata = (uint8_t *)calibration_obj->buffer;
- + length = 0;
- + for (i = 0; i < calibration_obj->size; ++i)
- + length += snprintf(buf + length, PAGE_SIZE - length, "0x%02x ",
- + caldata[i]);
- +
- + length += snprintf(buf + length, PAGE_SIZE - length, "\n");
- + result = (ssize_t)length;
- + return result;
- +}
- +
- +static ssize_t version_show(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + ssize_t result;
- + struct elliptic_engine_version_info *version_info;
- + int length;
- +
- + struct elliptic_shared_data_block *version_obj =
- + elliptic_get_shared_obj(ELLIPTIC_OBJ_ID_VERSION_INFO);
- +
- + if (kobject_create_and_add_failed)
- + EL_PRINT_E("kobject_create_and_add_failed");
- +
- + if (sysfs_create_group_failed)
- + EL_PRINT_E("sysfs_create_group_failed");
- +
- + if (version_obj == NULL) {
- + EL_PRINT_E("version_obj is NULL");
- + return -EINVAL;
- + }
- +
- + if (version_obj->size > PAGE_SIZE) {
- + EL_PRINT_E("version_obj->size > PAGE_SIZE");
- + return -EINVAL;
- + }
- +
- + version_info = (struct elliptic_engine_version_info *)
- + version_obj->buffer;
- +
- + length = snprintf(buf, PAGE_SIZE, "%d.%d.%d.%d\n",
- + version_info->major, version_info->minor, version_info->build,
- + version_info->revision);
- +
- + result = (ssize_t)length;
- + return result;
- +}
- +
- +static ssize_t branch_show(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + int length;
- +
- + struct elliptic_shared_data_block *branch_obj =
- + elliptic_get_shared_obj(ELLIPTIC_OBJ_ID_BRANCH_INFO);
- +
- + if (branch_obj == NULL) {
- + EL_PRINT_E("branch_obj not found");
- + return 0;
- + }
- +
- + if (branch_obj->size > PAGE_SIZE) {
- + EL_PRINT_E("branch_obj->size > PAGE_SIZE");
- + return -EINVAL;
- + }
- +
- + length = snprintf(buf, PAGE_SIZE - 1, "%s\n",
- + (const char *)(branch_obj->buffer));
- +
- + return (ssize_t)length;
- +}
- +
- +
- +static struct device_attribute calibration_attr = __ATTR_RW(calibration);
- +static struct device_attribute version_attr = __ATTR_RO(version);
- +static struct device_attribute branch_attr = __ATTR_RO(branch);
- +
- +static struct attribute *elliptic_attrs[] = {
- + &calibration_attr.attr,
- + &version_attr.attr,
- + &branch_attr.attr,
- + NULL,
- +};
- +
- +static struct attribute_group elliptic_attr_group = {
- + .name = ELLIPTIC_SYSFS_ENGINE_FOLDER,
- + .attrs = elliptic_attrs,
- +};
- +
- +static struct kobject *elliptic_sysfs_kobj;
- +
- +int elliptic_initialize_sysfs(void)
- +{
- + int err;
- +
- + elliptic_sysfs_kobj = kobject_create_and_add(ELLIPTIC_SYSFS_ROOT_FOLDER,
- + kernel_kobj->parent);
- +
- + if (!elliptic_sysfs_kobj) {
- + kobject_create_and_add_failed = 1;
- + EL_PRINT_E("failed to create kobj");
- + return -ENOMEM;
- + }
- +
- + err = sysfs_create_group(elliptic_sysfs_kobj, &elliptic_attr_group);
- +
- + if (err) {
- + sysfs_create_group_failed = 1;
- + EL_PRINT_E("failed to create sysfs group");
- + kobject_put(elliptic_sysfs_kobj);
- + return -ENOMEM;
- + }
- +
- + return 0;
- +}
- +
- +void elliptic_cleanup_sysfs(void)
- +{
- + kobject_put(elliptic_sysfs_kobj);
- +}
- diff --git a/drivers/elliptic/elliptic_sysfs.h b/drivers/elliptic/elliptic_sysfs.h
- new file mode 100644
- index 0000000..25a2187b
- --- /dev/null
- +++ b/drivers/elliptic/elliptic_sysfs.h
- @@ -0,0 +1,10 @@
- +#pragma once
- +
- +#define ELLIPTIC_SYSFS_ENGINE_FOLDER "engine"
- +#define ELLIPTIC_SYSFS_ROOT_FOLDER "elliptic"
- +#define ELLIPTIC_SYSFS_CALIBRATION_FILENAME "calibration"
- +#define ELLIPTIC_SYSFS_VERSION_FILENAME "version"
- +
- +
- +int elliptic_initialize_sysfs(void);
- +void elliptic_cleanup_sysfs(void);
- diff --git a/drivers/elliptic/io_modules/Makefile b/drivers/elliptic/io_modules/Makefile
- new file mode 100644
- index 0000000..66ee789
- --- /dev/null
- +++ b/drivers/elliptic/io_modules/Makefile
- @@ -0,0 +1,2 @@
- +# TODO: add config parameter for which io module to build
- +#obj-y += userspace/
- diff --git a/drivers/elliptic/io_modules/msm/elliptic_data_io.c b/drivers/elliptic/io_modules/msm/elliptic_data_io.c
- new file mode 100644
- index 0000000..a1b5105
- --- /dev/null
- +++ b/drivers/elliptic/io_modules/msm/elliptic_data_io.c
- @@ -0,0 +1,94 @@
- +/**
- + * Copyright Elliptic Labs
- + * Copyright (C) 2017 XiaoMi, Inc.
- + *
- + */
- +
- +#include <linux/module.h>
- +#include <linux/kernel.h>
- +#include <linux/init.h>
- +#include <linux/fs.h>
- +#include <linux/debugfs.h>
- +#include <linux/slab.h>
- +#include <linux/mm.h>
- +
- +
- +#include <linux/module.h>
- +#include <linux/kernel.h>
- +#include <linux/version.h>
- +/* includes the file structure, that is, file open read close */
- +#include <linux/fs.h>
- +
- +/* include the character device, makes cdev avilable */
- +#include <linux/cdev.h>
- +#include <linux/semaphore.h>
- +
- +/* includes copy_user vice versa */
- +#include <linux/uaccess.h>
- +
- +#include <linux/slab.h>
- +#include <linux/stat.h>
- +#include <linux/init.h>
- +#include <linux/platform_device.h>
- +#include <linux/types.h>
- +#include <linux/kdev_t.h>
- +#include <linux/device.h>
- +
- +
- +#include <linux/kernel.h>
- +#include <linux/version.h>
- +#include <linux/types.h>
- +#include <linux/sched.h>
- +#include <linux/wait.h>
- +#include <linux/mutex.h>
- +#include <asm/atomic.h>
- +#include <asm/uaccess.h>
- +#include <linux/errno.h>
- +
- +#include "elliptic_data_io.h"
- +#include "elliptic_device.h"
- +
- +#include <sound/apr_elliptic.h>
- +#define IO_PING_PONG_BUFFER_SIZE 512
- +
- +struct elliptic_msm_io_device {
- +};
- +
- +/* static struct elliptic_msm_io_device io_device;*/
- +
- +
- +int elliptic_data_io_initialize(void)
- +{
- + return 0;
- +}
- +
- +int elliptic_data_io_cleanup(void)
- +{
- + return 0;
- +}
- +
- +void elliptic_data_io_cancel(struct elliptic_data *elliptic_data)
- +{
- + atomic_set(&elliptic_data->abort_io, 1);
- + wake_up_interruptible(&elliptic_data->fifo_usp_not_empty);
- +
- +}
- +
- +int32_t elliptic_data_io_write(uint32_t message_id, const char *data,
- + size_t data_size)
- +{
- + uint32_t port_id;
- +
- + port_id = ELLIPTIC_PORT_ID;
- + return ultrasound_apr_set(port_id, &message_id, (u8 *)data,
- + (int32_t)data_size);
- +}
- +
- +int32_t elliptic_data_io_transact(uint32_t message_id, const char *data,
- + size_t data_size, char *output_data, size_t output_data_size)
- +{
- + pr_err("%s : unimplemented\n", __func__);
- + return -EINVAL;
- +}
- +
- +
- diff --git a/drivers/elliptic/io_modules/userspace/Makefile b/drivers/elliptic/io_modules/userspace/Makefile
- new file mode 100644
- index 0000000..907ddc2
- --- /dev/null
- +++ b/drivers/elliptic/io_modules/userspace/Makefile
- @@ -0,0 +1,2 @@
- +# TODO: add config parameter for which io module to build
- +#obj-y += elliptic_data_io.o
- diff --git a/drivers/elliptic/io_modules/userspace/elliptic_data_io.c b/drivers/elliptic/io_modules/userspace/elliptic_data_io.c
- new file mode 100644
- index 0000000..d82a6c9
- --- /dev/null
- +++ b/drivers/elliptic/io_modules/userspace/elliptic_data_io.c
- @@ -0,0 +1,208 @@
- +/**
- + * Copyright Elliptic Labs
- + * Copyright (C) 2017 XiaoMi, Inc.
- + *
- + */
- +
- +#include <linux/module.h>
- +#include <linux/kernel.h>
- +#include <linux/init.h>
- +#include <linux/fs.h>
- +#include <linux/debugfs.h>
- +#include <linux/slab.h>
- +#include <linux/mm.h>
- +
- +
- +#include <linux/module.h>
- +#include <linux/kernel.h>
- +#include <linux/version.h>
- +/* includes the file structure, that is, file open read close */
- +#include <linux/fs.h>
- +
- +/* include the character device, makes cdev avilable */
- +#include <linux/cdev.h>
- +#include <linux/semaphore.h>
- +
- +/* includes copy_user vice versa */
- +#include <linux/uaccess.h>
- +
- +#include <linux/slab.h>
- +#include <linux/stat.h>
- +#include <linux/init.h>
- +#include <linux/platform_device.h>
- +#include <linux/types.h>
- +#include <linux/kdev_t.h>
- +#include <linux/device.h>
- +
- +
- +#include <linux/kernel.h>
- +#include <linux/version.h>
- +#include <linux/types.h>
- +#include <linux/sched.h>
- +#include <linux/wait.h>
- +#include <linux/mutex.h>
- +#include <asm/atomic.h>
- +#include <asm/uaccess.h>
- +#include <linux/errno.h>
- +
- +#include "elliptic_data_io.h"
- +#include "elliptic_device.h"
- +
- +
- +static dev_t elliptic_usermode_io_major;
- +#define USERMODE_IO_DEVICE_NAME "elliptic_um_io"
- +#define UM_IO_PING_PONG_BUFFER_SIZE 512
- +struct elliptic_usermode_io_device {
- + struct cdev cdev;
- + struct semaphore sem;
- + struct mutex lock;
- + int ping_pong_idx;
- + char tmp_buffer[2][UM_IO_PING_PONG_BUFFER_SIZE];
- +};
- +
- +static struct elliptic_usermode_io_device io_device;
- +
- +static int device_open(struct inode *inode, struct file *filp)
- +{
- + if (inode->i_cdev != &io_device.cdev) {
- + pr_warn("elliptic : dev pointer mismatch\n");
- + return -ENODEV; /* No such device */
- + }
- +
- + if (down_interruptible(&io_device.sem) != 0)
- + return -EEXIST;
- + return 0;
- +}
- +
- +static ssize_t device_write(struct file *fp, const char __user *buff,
- + size_t length, loff_t *ppos)
- +{
- + size_t write_len;
- + size_t copy_result;
- + int push_result;
- + int err;
- +
- + err = mutex_lock_interruptible(&io_device.lock);
- + if (err == -EINTR) {
- + pr_warn("%s : locking interrupted\n", __func__);
- + return 0;
- + } else if (err < 0) {
- + pr_warn("%s : failed to acquire lock\n", __func__);
- + return 0;
- + }
- +
- + write_len = min_t(size_t, UM_IO_PING_PONG_BUFFER_SIZE, length);
- + copy_result = copy_from_user(
- + io_device.tmp_buffer[io_device.ping_pong_idx], buff, write_len);
- +
- + if (copy_result > 0) {
- + mutex_unlock(&io_device.lock);
- + return (write_len - copy_result);
- + }
- +
- + push_result = elliptic_data_push(
- + io_device.tmp_buffer[io_device.ping_pong_idx], write_len);
- +
- + if (push_result) {
- + pr_err("elliptic: %s failed to push fifo data\n", __func__);
- + mutex_unlock(&io_device.lock);
- + return 0;
- + }
- + io_device.ping_pong_idx = 1 - io_device.ping_pong_idx;
- + mutex_unlock(&io_device.lock);
- + return write_len;
- +}
- +
- +static int device_close(struct inode *inode, struct file *filp)
- +{
- + up(&io_device.sem);
- + return 0;
- +}
- +
- +static const struct file_operations
- +elliptic_usermode_io_fops = {
- + .owner = THIS_MODULE,
- + .open = device_open,
- + .write = device_write,
- + .release = device_close,
- +};
- +
- +static int elliptic_usermode_io_driver_init(void)
- +{
- + struct device *device;
- + dev_t device_number;
- + int err;
- +
- + err = alloc_chrdev_region(
- + &device_number, 0, 1, USERMODE_IO_DEVICE_NAME);
- +
- + if (err < 0) {
- + pr_err("failed to allocate chrdev region\n");
- + return err;
- + }
- +
- + elliptic_usermode_io_major = MAJOR(device_number);
- + device_number = MKDEV(elliptic_usermode_io_major, 0);
- + device = device_create(
- + elliptic_class, NULL, device_number,
- + NULL, USERMODE_IO_DEVICE_NAME);
- +
- + if (IS_ERR(device)) {
- + unregister_chrdev(
- + elliptic_usermode_io_major, USERMODE_IO_DEVICE_NAME);
- + pr_err("Failed to create the device\n");
- + return PTR_ERR(device);
- + }
- +
- + cdev_init(&io_device.cdev, &elliptic_usermode_io_fops);
- + io_device.cdev.owner = THIS_MODULE;
- + err = cdev_add(&io_device.cdev, device_number, 1);
- + if (err) {
- + pr_warn("elliptic : error %d while trying to add %s%d",
- + err, ELLIPTIC_DEVICENAME, 0);
- + return err;
- + }
- +
- + sema_init(&io_device.sem, 1);
- + mutex_init(&io_device.lock);
- + return 0;
- +}
- +
- +static void elliptic_usermode_io_driver_exit(void)
- +{
- + BUG_ON(elliptic_class == NULL);
- + device_destroy(elliptic_class, MKDEV(elliptic_usermode_io_major, 0));
- + cdev_del(&io_device.cdev);
- + unregister_chrdev(elliptic_usermode_io_major, USERMODE_IO_DEVICE_NAME);
- + up(&io_device.sem);
- +}
- +
- +
- +int elliptic_data_io_initialize(void)
- +{
- + elliptic_usermode_io_driver_init();
- + return 0;
- +}
- +
- +int elliptic_data_io_cleanup(void)
- +{
- + elliptic_usermode_io_driver_exit();
- + return 0;
- +}
- +
- +void elliptic_data_io_cancel(void)
- +{
- +
- +}
- +
- +size_t elliptic_data_io_write(uint32_t message_id, const char *data,
- + size_t data_size)
- +{
- + return 0;
- +}
- +
- +size_t elliptic_data_io_transact(uint32_t message_id, const char *data,
- + size_t data_size, char *output_data, size_t output_data_size)
- +{
- + return 0;
- +}
- diff --git a/drivers/elliptic/io_modules/userspace_test/Makefile b/drivers/elliptic/io_modules/userspace_test/Makefile
- new file mode 100644
- index 0000000..907ddc2
- --- /dev/null
- +++ b/drivers/elliptic/io_modules/userspace_test/Makefile
- @@ -0,0 +1,2 @@
- +# TODO: add config parameter for which io module to build
- +#obj-y += elliptic_data_io.o
- diff --git a/drivers/elliptic/io_modules/userspace_test/elliptic_data_io.c b/drivers/elliptic/io_modules/userspace_test/elliptic_data_io.c
- new file mode 100644
- index 0000000..23a136c
- --- /dev/null
- +++ b/drivers/elliptic/io_modules/userspace_test/elliptic_data_io.c
- @@ -0,0 +1,126 @@
- +/**
- + * Copyright Elliptic Labs
- + * Copyright (C) 2017 XiaoMi, Inc.
- + *
- + */
- +
- +#include <linux/kernel.h>
- +#include <linux/version.h>
- +#include <linux/types.h>
- +#include <linux/sched.h>
- +#include <linux/wait.h>
- +#include <linux/mutex.h>
- +#include <asm/atomic.h>
- +#include <asm/uaccess.h>
- +#include <linux/errno.h>
- +#include <linux/slab.h>
- +
- +#include <linux/kernel.h>
- +#include <linux/kthread.h>
- +#include <linux/delay.h>
- +#include <linux/sched.h>
- +
- +#include "elliptic_data_io.h"
- +#include "elliptic_device.h"
- +
- +static struct task_struct *simulating_task;
- +static atomic_t cancel;
- +
- +struct elliptic_data_io_state {
- +};
- +
- +struct data_packet_header {
- + int32_t t1;
- + union {
- + uint32_t t2;
- + uint8_t t2s[4];
- + };
- + union {
- + uint32_t s1;
- + uint8_t s1s[4];
- + };
- +};
- +
- +
- +#define APR_TEST_SIZE 460
- +struct elliptic_message {
- + struct data_packet_header header;
- + uint8_t data[APR_TEST_SIZE - (sizeof(struct data_packet_header))];
- +};
- +
- +static void fill_buffer(int32_t *buffer, size_t len, int32_t value)
- +{
- + size_t i;
- +
- + for (i = 0; i < len; ++i)
- + buffer[i] = value;
- +}
- +
- +
- +static struct elliptic_message output_message;
- +int simulating_thread(void *context)
- +{
- + static int32_t count;
- + int result;
- +
- + count = 0;
- + msleep(20);
- +
- + pr_debug("%s\n", __func__);
- + output_message.header.t2s[0] = (1<<4) | 3;
- + output_message.header.s1s[0] = 100;
- +
- + while (atomic_read(&cancel) == 0) {
- + if (kthread_should_stop())
- + do_exit(0);
- +
- + output_message.header.t1 = count;
- +
- +
- + fill_buffer((int32_t *)output_message.data, 100, count);
- + result = elliptic_data_push((const char *)&output_message,
- + APR_TEST_SIZE);
- +
- + ++count;
- + if (result != 0)
- + pr_warn("failed to push data\n");
- +
- + msleep(20);
- + }
- + return 0;
- +}
- +
- +int32_t elliptic_data_io_write(uint32_t message_id, const char *data,
- + size_t data_size) {
- + return 0;
- + }
- +
- +int32_t elliptic_data_io_transact(uint32_t message_id, const char *data,
- + size_t data_size, char *output_data, size_t output_data_size) {
- + return 0;
- +}
- +
- +
- +void elliptic_data_io_cancel(struct elliptic_data *elliptic_data)
- +{
- + atomic_set(&elliptic_data->abort_io, 1);
- + wake_up_interruptible(&elliptic_data->fifo_usp_not_empty);
- +}
- +
- +
- +int elliptic_data_io_initialize(void)
- +{
- + pr_debug("%s\n", __func__);
- + atomic_set(&cancel, 0);
- + simulating_task = kthread_run(&simulating_thread, NULL,
- + "el_simulating_thread");
- + return 0;
- +}
- +
- +int elliptic_data_io_cleanup(void)
- +{
- + kthread_stop(simulating_task);
- + atomic_set(&cancel, 1);
- + msleep(200);
- + return 0;
- +}
- diff --git a/drivers/firmware/qcom/tz_log.c b/drivers/firmware/qcom/tz_log.c
- index 11bd3aa..aa2d856 100644
- --- a/drivers/firmware/qcom/tz_log.c
- +++ b/drivers/firmware/qcom/tz_log.c
- @@ -27,8 +27,8 @@
- #include <soc/qcom/scm.h>
- #include <soc/qcom/qseecomi.h>
- -/* QSEE_LOG_BUF_SIZE = 32K */
- -#define QSEE_LOG_BUF_SIZE 0x8000
- +/* QSEE_LOG_BUF_SIZE = 64K */
- +#define QSEE_LOG_BUF_SIZE 0x10000
- /* TZ Diagnostic Area legacy version number */
- diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
- index 2a9ac89..7a546983 100644
- --- a/drivers/gpu/msm/kgsl.h
- +++ b/drivers/gpu/msm/kgsl.h
- @@ -50,7 +50,7 @@
- /* The number of memstore arrays limits the number of contexts allowed.
- * If more contexts are needed, update multiple for MEMSTORE_SIZE
- */
- -#define KGSL_MEMSTORE_SIZE ((int)(PAGE_SIZE * 2))
- +#define KGSL_MEMSTORE_SIZE ((int)(PAGE_SIZE * 8))
- #define KGSL_MEMSTORE_GLOBAL (0)
- #define KGSL_PRIORITY_MAX_RB_LEVELS 4
- #define KGSL_MEMSTORE_MAX (KGSL_MEMSTORE_SIZE / \
- diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
- index 0150d50..b17daf1 100644
- --- a/drivers/gpu/msm/kgsl_pwrctrl.c
- +++ b/drivers/gpu/msm/kgsl_pwrctrl.c
- @@ -1,4 +1,5 @@
- /* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
- + * Copyright (C) 2017 XiaoMi, 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
- @@ -33,6 +34,7 @@
- #define KGSL_PWRFLAGS_AXI_ON 2
- #define KGSL_PWRFLAGS_IRQ_ON 3
- #define KGSL_PWRFLAGS_NAP_OFF 5
- +#define KGSL_PWRFLAGS_RESTRICT_MAX_LEVEL_JUMP 6
- #define UPDATE_BUSY_VAL 1000000
- @@ -355,6 +357,16 @@ void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device,
- */
- kgsl_pwrctrl_set_thermal_cycle(pwr, new_level);
- + /* Check any restriction over new level jump */
- + if (test_bit(KGSL_PWRFLAGS_RESTRICT_MAX_LEVEL_JUMP,
- + &device->pwrctrl.ctrl_flags)) {
- + if (new_level == 0 &&
- + old_level > device->pwrctrl.restrict_pwrlevel)
- + new_level = device->pwrctrl.restrict_pwrlevel;
- + else if (new_level == 0 && old_level == 0)
- + new_level = device->pwrctrl.restrict_pwrlevel;
- + }
- +
- if (new_level == old_level)
- return;
- @@ -2094,6 +2106,13 @@ int kgsl_pwrctrl_init(struct kgsl_device *device)
- if (of_property_read_bool(pdev->dev.of_node, "qcom,no-nap"))
- device->pwrctrl.ctrl_flags |= BIT(KGSL_PWRFLAGS_NAP_OFF);
- + if (!of_property_read_u32(pdev->dev.of_node, "qcom,restrict-pwrlevel",
- + &pwr->restrict_pwrlevel)) {
- + device->pwrctrl.ctrl_flags |=
- + BIT(KGSL_PWRFLAGS_RESTRICT_MAX_LEVEL_JUMP);
- + KGSL_PWR_ERR(device, "qcom,restrict-pwrlevel is Enabled \n");
- + }
- +
- if (pwr->num_pwrlevels == 0) {
- KGSL_PWR_ERR(device, "No power levels are defined\n");
- result = -EINVAL;
- @@ -2499,6 +2518,7 @@ static int _init(struct kgsl_device *device)
- static int _wake(struct kgsl_device *device)
- {
- struct kgsl_pwrctrl *pwr = &device->pwrctrl;
- + bool limit_max_pwrlevel = false;
- int status = 0;
- switch (device->state) {
- @@ -2521,6 +2541,18 @@ static int _wake(struct kgsl_device *device)
- kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_ON);
- kgsl_pwrscale_wake(device);
- kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
- +
- + /*
- + * Check any restriction on max power level, clk_set_rate()
- + * wil set based on the active_pwrlevel.
- + */
- + if (test_bit(KGSL_PWRFLAGS_RESTRICT_MAX_LEVEL_JUMP,
- + &pwr->ctrl_flags) &&
- + (pwr->active_pwrlevel == 0)) {
- + pwr->active_pwrlevel = pwr->restrict_pwrlevel;
- + limit_max_pwrlevel = true;
- + }
- +
- /* fall through */
- case KGSL_STATE_NAP:
- /* Turn on the core clocks */
- @@ -2539,8 +2571,13 @@ static int _wake(struct kgsl_device *device)
- */
- kgsl_pwrctrl_pwrlevel_change_settings(device, 0);
- kgsl_pwrctrl_pwrlevel_change_settings(device, 1);
- +
- /* All settings for power level transitions are complete*/
- - pwr->previous_pwrlevel = pwr->active_pwrlevel;
- + if (limit_max_pwrlevel)
- + pwr->previous_pwrlevel = 0;
- + else
- + pwr->previous_pwrlevel = pwr->active_pwrlevel;
- +
- mod_timer(&device->idle_timer, jiffies +
- device->pwrctrl.interval_timeout);
- break;
- diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h
- index 42f918b..7366ded 100644
- --- a/drivers/gpu/msm/kgsl_pwrctrl.h
- +++ b/drivers/gpu/msm/kgsl_pwrctrl.h
- @@ -1,4 +1,5 @@
- /* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
- + * Copyright (C) 2017 XiaoMi, 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
- @@ -117,6 +118,7 @@ struct kgsl_regulator {
- * @previous_pwrlevel - The power level before transition
- * @thermal_pwrlevel - maximum powerlevel constraint from thermal
- * @default_pwrlevel - device wake up power level
- + * @restrict_pwrlevel - maximum power level jump to restrict
- * @max_pwrlevel - maximum allowable powerlevel per the user
- * @min_pwrlevel - minimum allowable powerlevel per the user
- * @num_pwrlevels - number of available power levels
- @@ -171,6 +173,7 @@ struct kgsl_pwrctrl {
- unsigned int previous_pwrlevel;
- unsigned int thermal_pwrlevel;
- unsigned int default_pwrlevel;
- + unsigned int restrict_pwrlevel;
- unsigned int wakeup_maxpwrlevel;
- unsigned int max_pwrlevel;
- unsigned int min_pwrlevel;
- diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c
- index 700145b..4ad880d 100644
- --- a/drivers/hid/usbhid/hiddev.c
- +++ b/drivers/hid/usbhid/hiddev.c
- @@ -1,6 +1,7 @@
- /*
- * Copyright (c) 2001 Paul Stewart
- * Copyright (c) 2001 Vojtech Pavlik
- + * Copyright (C) 2017 XiaoMi, Inc.
- *
- * HID char devices, giving access to raw HID device events.
- *
- @@ -510,17 +511,18 @@ static noinline int hiddev_ioctl_usage(struct hiddev *hiddev, unsigned int cmd,
- goto inval;
- field = report->field[uref->field_index];
- + }
- - if (cmd == HIDIOCGCOLLECTIONINDEX) {
- - if (uref->usage_index >= field->maxusage)
- - goto inval;
- - } else if (uref->usage_index >= field->report_count)
- + if (cmd == HIDIOCGCOLLECTIONINDEX) {
- + if (uref->usage_index >= field->maxusage)
- goto inval;
- - }
- + } else if (uref->usage_index >= field->report_count)
- + goto inval;
- - if ((cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) &&
- - (uref_multi->num_values > HID_MAX_MULTI_USAGES ||
- - uref->usage_index + uref_multi->num_values > field->report_count))
- + else if ((cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) &&
- + (uref_multi->num_values > HID_MAX_MULTI_USAGES ||
- + uref->usage_index + uref_multi->num_values >
- + field->report_count))
- goto inval;
- switch (cmd) {
- diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
- index 2557dcd..bf6d228 100644
- --- a/drivers/input/Kconfig
- +++ b/drivers/input/Kconfig
- @@ -200,6 +200,13 @@ config INPUT_KEYCOMBO
- ---help---
- Say Y here if you want to take action when some keys are pressed;
- +config LAST_TOUCH_EVENTS
- + bool "Last touch events"
- + default n
- + depends on INPUT
- + ---help---
- + Say Y here if you want to get last touch events.
- +
- comment "Input Device Drivers"
- source "drivers/input/keyboard/Kconfig"
- @@ -214,6 +221,8 @@ source "drivers/input/touchscreen/Kconfig"
- source "drivers/input/misc/Kconfig"
- +source "drivers/input/fingerprint/Kconfig"
- +
- endif
- menu "Hardware I/O ports"
- diff --git a/drivers/input/Makefile b/drivers/input/Makefile
- index 2a6d05a..d74a160 100644
- --- a/drivers/input/Makefile
- +++ b/drivers/input/Makefile
- @@ -24,6 +24,7 @@ obj-$(CONFIG_INPUT_JOYSTICK) += joystick/
- obj-$(CONFIG_INPUT_TABLET) += tablet/
- obj-$(CONFIG_INPUT_TOUCHSCREEN) += touchscreen/
- obj-$(CONFIG_INPUT_MISC) += misc/
- +obj-$(CONFIG_INPUT_FINGERPRINT) += fingerprint/
- obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o
- obj-$(CONFIG_INPUT_KEYRESET) += keyreset.o
- diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
- index e9ae3d5..7fbfb9b 100644
- --- a/drivers/input/evdev.c
- +++ b/drivers/input/evdev.c
- @@ -2,6 +2,7 @@
- * Event char devices, giving access to raw input device events.
- *
- * Copyright (c) 1999-2002 Vojtech Pavlik
- + * Copyright (C) 2017 XiaoMi, 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 as published by
- @@ -107,51 +108,6 @@ static bool __evdev_is_filtered(struct evdev_client *client,
- return mask && !test_bit(code, mask);
- }
- -/* flush queued events of type @type, caller must hold client->buffer_lock */
- -static void __evdev_flush_queue(struct evdev_client *client, unsigned int type)
- -{
- - unsigned int i, head, num;
- - unsigned int mask = client->bufsize - 1;
- - bool is_report;
- - struct input_event *ev;
- -
- - BUG_ON(type == EV_SYN);
- -
- - head = client->tail;
- - client->packet_head = client->tail;
- -
- - /* init to 1 so a leading SYN_REPORT will not be dropped */
- - num = 1;
- -
- - for (i = client->tail; i != client->head; i = (i + 1) & mask) {
- - ev = &client->buffer[i];
- - is_report = ev->type == EV_SYN && ev->code == SYN_REPORT;
- -
- - if (ev->type == type) {
- - /* drop matched entry */
- - continue;
- - } else if (is_report && !num) {
- - /* drop empty SYN_REPORT groups */
- - continue;
- - } else if (head != i) {
- - /* move entry to fill the gap */
- - client->buffer[head].time = ev->time;
- - client->buffer[head].type = ev->type;
- - client->buffer[head].code = ev->code;
- - client->buffer[head].value = ev->value;
- - }
- -
- - num++;
- - head = (head + 1) & mask;
- -
- - if (is_report) {
- - num = 0;
- - client->packet_head = head;
- - }
- - }
- -
- - client->head = head;
- -}
- static void __evdev_queue_syn_dropped(struct evdev_client *client)
- {
- @@ -179,14 +135,6 @@ static void __evdev_queue_syn_dropped(struct evdev_client *client)
- }
- }
- -static void evdev_queue_syn_dropped(struct evdev_client *client)
- -{
- - unsigned long flags;
- -
- - spin_lock_irqsave(&client->buffer_lock, flags);
- - __evdev_queue_syn_dropped(client);
- - spin_unlock_irqrestore(&client->buffer_lock, flags);
- -}
- static int evdev_set_clk_type(struct evdev_client *client, unsigned int clkid)
- {
- @@ -898,53 +846,6 @@ static int evdev_handle_set_keycode_v2(struct input_dev *dev, void __user *p)
- return input_set_keycode(dev, &ke);
- }
- -/*
- - * If we transfer state to the user, we should flush all pending events
- - * of the same type from the client's queue. Otherwise, they might end up
- - * with duplicate events, which can screw up client's state tracking.
- - * If bits_to_user fails after flushing the queue, we queue a SYN_DROPPED
- - * event so user-space will notice missing events.
- - *
- - * LOCKING:
- - * We need to take event_lock before buffer_lock to avoid dead-locks. But we
- - * need the even_lock only to guarantee consistent state. We can safely release
- - * it while flushing the queue. This allows input-core to handle filters while
- - * we flush the queue.
- - */
- -static int evdev_handle_get_val(struct evdev_client *client,
- - struct input_dev *dev, unsigned int type,
- - unsigned long *bits, unsigned int maxbit,
- - unsigned int maxlen, void __user *p,
- - int compat)
- -{
- - int ret;
- - unsigned long *mem;
- - size_t len;
- -
- - len = BITS_TO_LONGS(maxbit) * sizeof(unsigned long);
- - mem = kmalloc(len, GFP_KERNEL);
- - if (!mem)
- - return -ENOMEM;
- -
- - spin_lock_irq(&dev->event_lock);
- - spin_lock(&client->buffer_lock);
- -
- - memcpy(mem, bits, len);
- -
- - spin_unlock(&dev->event_lock);
- -
- - __evdev_flush_queue(client, type);
- -
- - spin_unlock_irq(&client->buffer_lock);
- -
- - ret = bits_to_user(mem, maxbit, maxlen, p, compat);
- - if (ret < 0)
- - evdev_queue_syn_dropped(client);
- -
- - kfree(mem);
- -
- - return ret;
- -}
- static int evdev_handle_mt_request(struct input_dev *dev,
- unsigned int size,
- @@ -1182,20 +1083,16 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
- return evdev_handle_mt_request(dev, size, ip);
- case EVIOCGKEY(0):
- - return evdev_handle_get_val(client, dev, EV_KEY, dev->key,
- - KEY_MAX, size, p, compat_mode);
- + return bits_to_user(dev->key, KEY_MAX, size, p, compat_mode);
- case EVIOCGLED(0):
- - return evdev_handle_get_val(client, dev, EV_LED, dev->led,
- - LED_MAX, size, p, compat_mode);
- + return bits_to_user(dev->led, LED_MAX, size, p, compat_mode);
- case EVIOCGSND(0):
- - return evdev_handle_get_val(client, dev, EV_SND, dev->snd,
- - SND_MAX, size, p, compat_mode);
- + return bits_to_user(dev->snd, SND_MAX, size, p, compat_mode);
- case EVIOCGSW(0):
- - return evdev_handle_get_val(client, dev, EV_SW, dev->sw,
- - SW_MAX, size, p, compat_mode);
- + return bits_to_user(dev->sw, SW_MAX, size, p, compat_mode);
- case EVIOCGNAME(0):
- return str_to_user(dev->name, size, p);
- diff --git a/drivers/input/fingerprint/Kconfig b/drivers/input/fingerprint/Kconfig
- new file mode 100644
- index 0000000..16b1eeb
- --- /dev/null
- +++ b/drivers/input/fingerprint/Kconfig
- @@ -0,0 +1,18 @@
- +#
- +# Fingerprint driver configuration
- +#
- +menuconfig INPUT_FINGERPRINT
- + bool "Fingerprints"
- + help
- + Say Y here, and a list of supported fingerprints will be displayed.
- + This option doesn't affect the kernel.
- +
- + If unsure, say Y.
- +
- +if INPUT_FINGERPRINT
- +
- +source "drivers/input/fingerprint/goodix/Kconfig"
- +source "drivers/input/fingerprint/goodix_ta/Kconfig"
- +source "drivers/input/fingerprint/fpc1268_tee/Kconfig"
- +
- +endif
- diff --git a/drivers/input/fingerprint/Makefile b/drivers/input/fingerprint/Makefile
- new file mode 100644
- index 0000000..21bb763
- --- /dev/null
- +++ b/drivers/input/fingerprint/Makefile
- @@ -0,0 +1,9 @@
- +#
- +# Makefile for the fingerprint drivers.
- +#
- +
- +# Each configuration option enables a list of files.
- +
- +obj-$(CONFIG_FINGERPRINT_GOODIX) += goodix/
- +obj-$(CONFIG_FINGERPRINT_GOODIX_TA) += goodix_ta/
- +obj-$(CONFIG_FINGERPRINT_FPC1268_TEE) += fpc1268_tee/
- diff --git a/drivers/input/fingerprint/fpc1268_tee/Kconfig b/drivers/input/fingerprint/fpc1268_tee/Kconfig
- new file mode 100644
- index 0000000..918a582
- --- /dev/null
- +++ b/drivers/input/fingerprint/fpc1268_tee/Kconfig
- @@ -0,0 +1,10 @@
- +config FINGERPRINT_FPC1268_TEE
- + tristate "Finger print card fpc1268"
- + depends on INPUT_FINGERPRINT
- + help
- + Say Y here to enable support for retrieving self-test reports.
- +
- + If unsure, say N.
- +
- + To compile this driver as a module, choose M here.
- +
- diff --git a/drivers/input/fingerprint/fpc1268_tee/Makefile b/drivers/input/fingerprint/fpc1268_tee/Makefile
- new file mode 100644
- index 0000000..f32432e
- --- /dev/null
- +++ b/drivers/input/fingerprint/fpc1268_tee/Makefile
- @@ -0,0 +1 @@
- +obj-$(CONFIG_FINGERPRINT_FPC1268_TEE) += fpc1020_tee.o
- diff --git a/drivers/input/fingerprint/fpc1268_tee/fpc1020_tee.c b/drivers/input/fingerprint/fpc1268_tee/fpc1020_tee.c
- new file mode 100644
- index 0000000..2bec8a7
- --- /dev/null
- +++ b/drivers/input/fingerprint/fpc1268_tee/fpc1020_tee.c
- @@ -0,0 +1,633 @@
- +/*
- + * FPC1020 Fingerprint sensor device driver
- + *
- + * This driver will control the platform resources that the FPC fingerprint
- + * sensor needs to operate. The major things are probing the sensor to check
- + * that it is actually connected and let the Kernel know this and with that also
- + * enabling and disabling of regulators, controlling GPIOs such as sensor reset
- + * line, sensor IRQ line.
- + *
- + * The driver will expose most of its available functionality in sysfs which
- + * enables dynamic control of these features from eg. a user space process.
- + *
- + * The sensor's IRQ events will be pushed to Kernel's event handling system and
- + * are exposed in the drivers event node.
- + *
- + * This driver will NOT send any commands to the sensor it only controls the
- + * electrical parts.
- + *
- + *
- + * Copyright (c) 2015 Fingerprint Cards AB <tech@fingerprints.com>
- + * Copyright (C) 2017 XiaoMi, 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
- + * as published by the Free Software Foundation.
- + */
- +
- +#include <linux/atomic.h>
- +#include <linux/delay.h>
- +#include <linux/gpio.h>
- +#include <linux/interrupt.h>
- +#include <linux/kernel.h>
- +#include <linux/module.h>
- +#include <linux/mutex.h>
- +#include <linux/of.h>
- +#include <linux/of_gpio.h>
- +#include <linux/platform_device.h>
- +#include <linux/regulator/consumer.h>
- +#include <linux/wakelock.h>
- +#include <linux/hwinfo.h>
- +#include <asm/hwconf_manager.h>
- +
- +#define FPC_TTW_HOLD_TIME 2000
- +
- +#define RESET_LOW_SLEEP_MIN_US 5000
- +#define RESET_LOW_SLEEP_MAX_US (RESET_LOW_SLEEP_MIN_US + 100)
- +#define RESET_HIGH_SLEEP1_MIN_US 100
- +#define RESET_HIGH_SLEEP1_MAX_US (RESET_HIGH_SLEEP1_MIN_US + 100)
- +#define RESET_HIGH_SLEEP2_MIN_US 5000
- +#define RESET_HIGH_SLEEP2_MAX_US (RESET_HIGH_SLEEP2_MIN_US + 100)
- +#define PWR_ON_SLEEP_MIN_US 100
- +#define PWR_ON_SLEEP_MAX_US (PWR_ON_SLEEP_MIN_US + 900)
- +
- +#define NUM_PARAMS_REG_ENABLE_SET 2
- +
- +
- +static const char * const pctl_names[] = {
- + "fpc1020_reset_reset",
- + "fpc1020_reset_active",
- + "fpc1020_irq_active",
- +};
- +
- +struct vreg_config {
- + char *name;
- + unsigned long vmin;
- + unsigned long vmax;
- + int ua_load;
- +};
- +
- +static const struct vreg_config const vreg_conf[] = {
- + { "vdd_ana", 1800000UL, 1800000UL, 6000, },
- +};
- +
- +struct fpc1020_data {
- + struct device *dev;
- +
- + struct pinctrl *fingerprint_pinctrl;
- + struct pinctrl_state *pinctrl_state[ARRAY_SIZE(pctl_names)];
- + struct regulator *vreg[ARRAY_SIZE(vreg_conf)];
- +
- + struct wake_lock ttw_wl;
- + int irq_gpio;
- + int rst_gpio;
- + struct mutex lock; /* To set/get exported values in sysfs */
- + bool prepared;
- + atomic_t wakeup_enabled; /* Used both in ISR and non-ISR */
- + int irqf;
- +};
- +
- +static irqreturn_t fpc1020_irq_handler(int irq, void *handle);
- +static int fpc1020_request_named_gpio(struct fpc1020_data *fpc1020,
- + const char *label, int *gpio);
- +
- +static int vreg_setup(struct fpc1020_data *fpc1020, const char *name,
- + bool enable)
- +{
- + size_t i;
- + int rc;
- + struct regulator *vreg;
- + struct device *dev = fpc1020->dev;
- +
- + for (i = 0; i < ARRAY_SIZE(fpc1020->vreg); i++) {
- + const char *n = vreg_conf[i].name;
- +
- + if (!strncmp(n, name, strlen(n)))
- + goto found;
- + }
- +
- + dev_err(dev, "Regulator %s not found\n", name);
- +
- + return -EINVAL;
- +
- +found:
- + vreg = fpc1020->vreg[i];
- + if (enable) {
- + if (!vreg) {
- + vreg = regulator_get(dev, name);
- + if (IS_ERR(vreg)) {
- + dev_err(dev, "Unable to get %s\n", name);
- + return PTR_ERR(vreg);
- + }
- + }
- + rc = regulator_enable(vreg);
- + if (rc) {
- + dev_err(dev, "error enabling %s: %d\n", name, rc);
- + regulator_put(vreg);
- + vreg = NULL;
- + }
- + fpc1020->vreg[i] = vreg;
- + } else {
- + if (vreg) {
- + if (regulator_is_enabled(vreg)) {
- + regulator_disable(vreg);
- + dev_dbg(dev, "disabled %s\n", name);
- + }
- + regulator_put(vreg);
- + fpc1020->vreg[i] = NULL;
- + }
- + rc = 0;
- + }
- +
- + return rc;
- +}
- +
- +/**
- + * sysfs node for controlling clocks.
- + *
- + * This is disabled in platform variant of this driver but kept for
- + * backwards compatibility. Only prints a debug print that it is
- + * disabled.
- + */
- +static ssize_t clk_enable_set(struct device *dev,
- + struct device_attribute *attr,
- + const char *buf, size_t count)
- +{
- + dev_dbg(dev,
- + "clk_enable sysfs node not enabled in platform driver\n");
- +
- + return count;
- +}
- +static DEVICE_ATTR(clk_enable, S_IWUSR, NULL, clk_enable_set);
- +
- +/**
- + * Will try to select the set of pins (GPIOS) defined in a pin control node of
- + * the device tree named @p name.
- + *
- + * The node can contain several eg. GPIOs that is controlled when selecting it.
- + * The node may activate or deactivate the pins it contains, the action is
- + * defined in the device tree node itself and not here. The states used
- + * internally is fetched at probe time.
- + *
- + * @see pctl_names
- + * @see fpc1020_probe
- + */
- +static int select_pin_ctl(struct fpc1020_data *fpc1020, const char *name)
- +{
- + size_t i;
- + int rc;
- + struct device *dev = fpc1020->dev;
- +
- + for (i = 0; i < ARRAY_SIZE(fpc1020->pinctrl_state); i++) {
- + const char *n = pctl_names[i];
- +
- + if (!strncmp(n, name, strlen(n))) {
- + rc = pinctrl_select_state(fpc1020->fingerprint_pinctrl,
- + fpc1020->pinctrl_state[i]);
- + if (rc)
- + dev_err(dev, "cannot select '%s'\n", name);
- + else
- + dev_dbg(dev, "Selected '%s'\n", name);
- + goto exit;
- + }
- + }
- +
- + rc = -EINVAL;
- + dev_err(dev, "%s:'%s' not found\n", __func__, name);
- +
- +exit:
- + return rc;
- +}
- +
- +static ssize_t pinctl_set(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count)
- +{
- + struct fpc1020_data *fpc1020 = dev_get_drvdata(dev);
- + int rc;
- +
- + mutex_lock(&fpc1020->lock);
- + rc = select_pin_ctl(fpc1020, buf);
- + mutex_unlock(&fpc1020->lock);
- +
- + return rc ? rc : count;
- +}
- +static DEVICE_ATTR(pinctl_set, S_IWUSR, NULL, pinctl_set);
- +
- +static ssize_t regulator_enable_set(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count)
- +{
- + struct fpc1020_data *fpc1020 = dev_get_drvdata(dev);
- + char op;
- + char name[16];
- + int rc;
- + bool enable;
- +
- + if (NUM_PARAMS_REG_ENABLE_SET != sscanf(buf, "%15[^,],%c", name, &op))
- + return -EINVAL;
- + if (op == 'e')
- + enable = true;
- + else if (op == 'd')
- + enable = false;
- + else
- + return -EINVAL;
- +
- + mutex_lock(&fpc1020->lock);
- + rc = vreg_setup(fpc1020, name, enable);
- + mutex_unlock(&fpc1020->lock);
- +
- + return rc ? rc : count;
- +}
- +static DEVICE_ATTR(regulator_enable, S_IWUSR, NULL, regulator_enable_set);
- +
- +static int hw_reset(struct fpc1020_data *fpc1020)
- +{
- + int irq_gpio;
- + struct device *dev = fpc1020->dev;
- + int rc = select_pin_ctl(fpc1020, "fpc1020_reset_active");
- +
- + if (rc)
- + goto exit;
- + usleep_range(RESET_HIGH_SLEEP1_MIN_US, RESET_HIGH_SLEEP1_MAX_US);
- +
- + rc = select_pin_ctl(fpc1020, "fpc1020_reset_reset");
- + if (rc)
- + goto exit;
- + usleep_range(RESET_LOW_SLEEP_MIN_US, RESET_LOW_SLEEP_MAX_US);
- +
- + rc = select_pin_ctl(fpc1020, "fpc1020_reset_active");
- + if (rc)
- + goto exit;
- + usleep_range(RESET_HIGH_SLEEP2_MIN_US, RESET_HIGH_SLEEP2_MAX_US);
- +
- + irq_gpio = gpio_get_value(fpc1020->irq_gpio);
- + dev_info(dev, "IRQ after reset %d\n", irq_gpio);
- +
- +exit:
- + return rc;
- +}
- +
- +static ssize_t hw_reset_set(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count)
- +{
- + int rc;
- + struct fpc1020_data *fpc1020 = dev_get_drvdata(dev);
- +
- + if (!strncmp(buf, "reset", strlen("reset"))) {
- + mutex_lock(&fpc1020->lock);
- + rc = hw_reset(fpc1020);
- + mutex_unlock(&fpc1020->lock);
- + } else {
- + return -EINVAL;
- + }
- +
- + return rc ? rc : count;
- +}
- +static DEVICE_ATTR(hw_reset, S_IWUSR, NULL, hw_reset_set);
- +
- +/**
- + * Will setup GPIOs, and regulators to correctly initialize the touch sensor to
- + * be ready for work.
- + *
- + * In the correct order according to the sensor spec this function will
- + * enable/disable regulators, and reset line, all to set the sensor in a
- + * correct power on or off state "electrical" wise.
- + *
- + * @see device_prepare_set
- + * @note This function will not send any commands to the sensor it will only
- + * control it "electrically".
- + */
- +static int device_prepare(struct fpc1020_data *fpc1020, bool enable)
- +{
- + int rc;
- + struct device *dev = fpc1020->dev;
- +
- + mutex_lock(&fpc1020->lock);
- + if (enable && !fpc1020->prepared) {
- + rc = select_pin_ctl(fpc1020, "fpc1020_irq_active");
- + if (rc) {
- + pr_err("irq gpio set active failed\n");
- + goto exit;
- + }
- +
- + rc = fpc1020_request_named_gpio(fpc1020, "fpc,gpio_irq",
- + &fpc1020->irq_gpio);
- + if (rc) {
- + pr_err("irq gpio request failed\n");
- + goto exit;
- + }
- + rc = fpc1020_request_named_gpio(fpc1020, "fpc,gpio_rst",
- + &fpc1020->rst_gpio);
- + if (rc) {
- + pr_err("reset gpio request failed\n");
- + goto irq_gpio_exit;
- + }
- + rc = devm_request_threaded_irq(dev, gpio_to_irq(fpc1020->irq_gpio),
- + NULL, fpc1020_irq_handler, fpc1020->irqf,
- + dev_name(dev), fpc1020);
- + if (rc) {
- + pr_err("could not request irq %d\n",
- + gpio_to_irq(fpc1020->irq_gpio));
- + goto rst_gpio_exit;
- + }
- +
- + dev_dbg(dev, "requested irq %d\n", gpio_to_irq(fpc1020->irq_gpio));
- +
- + /* Request that the interrupt should be wakeable */
- + enable_irq_wake(gpio_to_irq(fpc1020->irq_gpio));
- + select_pin_ctl(fpc1020, "fpc1020_reset_reset");
- + rc = vreg_setup(fpc1020, "vdd_ana", true);
- + if (rc)
- + goto free_irq_exit;
- +
- + usleep_range(PWR_ON_SLEEP_MIN_US, PWR_ON_SLEEP_MAX_US);
- +
- + /* As we can't control chip select here the other part of the
- + * sensor driver eg. the TEE driver needs to do a _SOFT_ reset
- + * on the sensor after power up to be sure that the sensor is
- + * in a good state after power up. Okeyed by ASIC. */
- +
- + (void)select_pin_ctl(fpc1020, "fpc1020_reset_active");
- + hw_reset(fpc1020);
- + fpc1020->prepared = true;
- + } else if (!enable && fpc1020->prepared) {
- + rc = 0;
- + (void)select_pin_ctl(fpc1020, "fpc1020_reset_reset");
- +
- + usleep_range(PWR_ON_SLEEP_MIN_US, PWR_ON_SLEEP_MAX_US);
- +
- + (void)vreg_setup(fpc1020, "vdd_ana", false);
- +free_irq_exit:
- + disable_irq(gpio_to_irq(fpc1020->irq_gpio));
- + devm_free_irq(dev, gpio_to_irq(fpc1020->irq_gpio), fpc1020);
- +rst_gpio_exit:
- + devm_gpio_free(dev, fpc1020->rst_gpio);
- +irq_gpio_exit:
- + devm_gpio_free(dev, fpc1020->irq_gpio);
- +exit:
- + fpc1020->prepared = false;
- + } else {
- + rc = 0;
- + }
- + mutex_unlock(&fpc1020->lock);
- +
- + return rc;
- +}
- +
- +/**
- + * sysfs node to enable/disable (power up/power down) the touch sensor
- + *
- + * @see device_prepare
- + */
- +static ssize_t device_prepare_set(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count)
- +{
- + int rc;
- + struct fpc1020_data *fpc1020 = dev_get_drvdata(dev);
- +
- + if (!strncmp(buf, "enable", strlen("enable")))
- + rc = device_prepare(fpc1020, true);
- + else if (!strncmp(buf, "disable", strlen("disable")))
- + rc = device_prepare(fpc1020, false);
- + else
- + return -EINVAL;
- +
- + return rc ? rc : count;
- +}
- +static DEVICE_ATTR(device_prepare, S_IWUSR, NULL, device_prepare_set);
- +
- +/**
- + * sysfs node for controlling whether the driver is allowed
- + * to wake up the platform on interrupt.
- + */
- +static ssize_t wakeup_enable_set(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count)
- +{
- + struct fpc1020_data *fpc1020 = dev_get_drvdata(dev);
- + ssize_t ret = count;
- +
- + mutex_lock(&fpc1020->lock);
- + mutex_unlock(&fpc1020->lock);
- +
- + return ret;
- +}
- +static DEVICE_ATTR(wakeup_enable, S_IWUSR, NULL, wakeup_enable_set);
- +
- +/**
- + * sysf node to check the interrupt status of the sensor, the interrupt
- + * handler should perform sysf_notify to allow userland to poll the node.
- + */
- +static ssize_t irq_get(struct device *dev,
- + struct device_attribute *attr,
- + char *buf)
- +{
- + struct fpc1020_data *fpc1020 = dev_get_drvdata(dev);
- + int irq = gpio_get_value(fpc1020->irq_gpio);
- +
- + return scnprintf(buf, PAGE_SIZE, "%i\n", irq);
- +}
- +
- +/**
- + * writing to the irq node will just drop a printk message
- + * and return success, used for latency measurement.
- + */
- +static ssize_t irq_ack(struct device *dev,
- + struct device_attribute *attr,
- + const char *buf, size_t count)
- +{
- + struct fpc1020_data *fpc1020 = dev_get_drvdata(dev);
- +
- + dev_dbg(fpc1020->dev, "%s\n", __func__);
- +
- + return count;
- +}
- +static DEVICE_ATTR(irq, S_IRUSR | S_IWUSR, irq_get, irq_ack);
- +
- +static struct attribute *attributes[] = {
- + &dev_attr_pinctl_set.attr,
- + &dev_attr_device_prepare.attr,
- + &dev_attr_regulator_enable.attr,
- + &dev_attr_hw_reset.attr,
- + &dev_attr_wakeup_enable.attr,
- + &dev_attr_clk_enable.attr,
- + &dev_attr_irq.attr,
- + NULL
- +};
- +
- +static const struct attribute_group attribute_group = {
- + .attrs = attributes,
- +};
- +
- +static irqreturn_t fpc1020_irq_handler(int irq, void *handle)
- +{
- + struct fpc1020_data *fpc1020 = handle;
- +
- + dev_dbg(fpc1020->dev, "%s\n", __func__);
- +
- + if (atomic_read(&fpc1020->wakeup_enabled)) {
- + wake_lock_timeout(&fpc1020->ttw_wl,
- + msecs_to_jiffies(FPC_TTW_HOLD_TIME));
- + }
- +
- + sysfs_notify(&fpc1020->dev->kobj, NULL, dev_attr_irq.attr.name);
- +
- + return IRQ_HANDLED;
- +}
- +
- +static int fpc1020_request_named_gpio(struct fpc1020_data *fpc1020,
- + const char *label, int *gpio)
- +{
- + struct device *dev = fpc1020->dev;
- + struct device_node *np = dev->of_node;
- + int rc = of_get_named_gpio(np, label, 0);
- +
- + if (rc < 0) {
- + dev_err(dev, "failed to get '%s'\n", label);
- + return rc;
- + }
- + *gpio = rc;
- +
- + rc = devm_gpio_request(dev, *gpio, label);
- + if (rc) {
- + dev_err(dev, "failed to request gpio %d\n", *gpio);
- + return rc;
- + }
- + dev_dbg(dev, "%s %d\n", label, *gpio);
- +
- + return 0;
- +}
- +
- +static int fpc1020_probe(struct platform_device *pdev)
- +{
- + struct device *dev = &pdev->dev;
- + int rc = 0;
- + size_t i;
- +
- + struct device_node *np = dev->of_node;
- + struct fpc1020_data *fpc1020 = devm_kzalloc(dev, sizeof(*fpc1020),
- + GFP_KERNEL);
- +
- + if (!fpc1020) {
- + dev_err(dev,
- + "failed to allocate memory for struct fpc1020_data\n");
- + rc = -ENOMEM;
- + goto exit;
- + }
- +
- + fpc1020->dev = dev;
- + platform_set_drvdata(pdev, fpc1020);
- +
- + if (!np) {
- + dev_err(dev, "no of node found\n");
- + rc = -EINVAL;
- + goto exit;
- + }
- +
- + fpc1020->fingerprint_pinctrl = devm_pinctrl_get(dev);
- + if (IS_ERR(fpc1020->fingerprint_pinctrl)) {
- + if (PTR_ERR(fpc1020->fingerprint_pinctrl) == -EPROBE_DEFER) {
- + dev_info(dev, "pinctrl not ready\n");
- + rc = -EPROBE_DEFER;
- + goto exit;
- + }
- + dev_err(dev, "Target does not use pinctrl\n");
- + fpc1020->fingerprint_pinctrl = NULL;
- + rc = -EINVAL;
- + goto exit;
- + }
- +
- + for (i = 0; i < ARRAY_SIZE(fpc1020->pinctrl_state); i++) {
- + const char *n = pctl_names[i];
- + struct pinctrl_state *state =
- + pinctrl_lookup_state(fpc1020->fingerprint_pinctrl, n);
- + if (IS_ERR(state)) {
- + dev_err(dev, "cannot find '%s'\n", n);
- + rc = -EINVAL;
- + goto exit;
- + }
- + dev_info(dev, "found pin control %s\n", n);
- + fpc1020->pinctrl_state[i] = state;
- + }
- +
- + atomic_set(&fpc1020->wakeup_enabled, 1);
- +
- + fpc1020->irqf = IRQF_TRIGGER_RISING | IRQF_ONESHOT | IRQF_NO_SUSPEND;
- + device_init_wakeup(dev, 1);
- +/*
- + if (of_property_read_bool(dev->of_node, "fpc,enable-wakeup")) {
- + fpc1020->irqf |= IRQF_NO_SUSPEND;
- + device_init_wakeup(dev, 1);
- + }
- +*/
- + mutex_init(&fpc1020->lock);
- +
- + wake_lock_init(&fpc1020->ttw_wl, WAKE_LOCK_SUSPEND, "fpc_ttw_wl");
- +
- + rc = sysfs_create_group(&dev->kobj, &attribute_group);
- + if (rc) {
- + dev_err(dev, "could not create sysfs\n");
- + goto exit;
- + }
- +
- + if (of_property_read_bool(dev->of_node, "fpc,enable-on-boot")) {
- + dev_info(dev, "Enabling hardware\n");
- + (void)device_prepare(fpc1020, true);
- + }
- + dev_info(dev, "%s: ok\n", __func__);
- +exit:
- + return rc;
- +}
- +
- +static int fpc1020_remove(struct platform_device *pdev)
- +{
- + struct fpc1020_data *fpc1020 = platform_get_drvdata(pdev);
- +
- + sysfs_remove_group(&pdev->dev.kobj, &attribute_group);
- + mutex_destroy(&fpc1020->lock);
- + wake_lock_destroy(&fpc1020->ttw_wl);
- + (void)vreg_setup(fpc1020, "vdd_ana", false);
- + dev_info(&pdev->dev, "%s\n", __func__);
- +
- + return 0;
- +}
- +
- +static struct of_device_id fpc1020_of_match[] = {
- + { .compatible = "fpc,fpc1020", },
- + {}
- +};
- +MODULE_DEVICE_TABLE(of, fpc1020_of_match);
- +
- +static struct platform_driver fpc1020_driver = {
- + .driver = {
- + .name = "fpc1020",
- + .owner = THIS_MODULE,
- + .of_match_table = fpc1020_of_match,
- + },
- + .probe = fpc1020_probe,
- + .remove = fpc1020_remove,
- +};
- +
- +static int __init fpc1020_init(void)
- +{
- + int rc = platform_driver_register(&fpc1020_driver);
- +
- + if (!rc)
- + pr_info("%s OK\n", __func__);
- + else
- + pr_err("%s %d\n", __func__, rc);
- +
- + return rc;
- +}
- +
- +static void __exit fpc1020_exit(void)
- +{
- + pr_info("%s\n", __func__);
- + platform_driver_unregister(&fpc1020_driver);
- +}
- +
- +module_init(fpc1020_init);
- +module_exit(fpc1020_exit);
- +
- +MODULE_LICENSE("GPL v2");
- +MODULE_AUTHOR("Aleksej Makarov");
- +MODULE_AUTHOR("Henrik Tillman <henrik.tillman@fingerprints.com>");
- +MODULE_DESCRIPTION("FPC1020 Fingerprint sensor device driver.");
- diff --git a/drivers/input/fingerprint/goodix/Kconfig b/drivers/input/fingerprint/goodix/Kconfig
- new file mode 100644
- index 0000000..a86948d
- --- /dev/null
- +++ b/drivers/input/fingerprint/goodix/Kconfig
- @@ -0,0 +1,10 @@
- +config FINGERPRINT_GOODIX
- + tristate "Finger print card FPC"
- + depends on INPUT_FINGERPRINT
- + help
- + Say Y here to enable support for retrieving self-test reports.
- +
- + If unsure, say N.
- +
- + To compile this driver as a module, choose M here.
- +
- diff --git a/drivers/input/fingerprint/goodix/Makefile b/drivers/input/fingerprint/goodix/Makefile
- new file mode 100644
- index 0000000..c235359
- --- /dev/null
- +++ b/drivers/input/fingerprint/goodix/Makefile
- @@ -0,0 +1 @@
- +obj-$(CONFIG_FINGERPRINT_GOODIX) += gf_spi.o platform.o gf_common.o
- diff --git a/drivers/input/fingerprint/goodix/gf_common.c b/drivers/input/fingerprint/goodix/gf_common.c
- new file mode 100644
- index 0000000..af876a6
- --- /dev/null
- +++ b/drivers/input/fingerprint/goodix/gf_common.c
- @@ -0,0 +1,331 @@
- +#include "gf_common.h"
- +#include "gf_spi.h"
- +
- +#if defined(USE_SPI_BUS)
- +#include <linux/spi/spi.h>
- +#include <linux/spi/spidev.h>
- +#elif defined(USE_PLATFORM_BUS)
- +#include <linux/platform_device.h>
- +#endif
- +
- +
- +/******************** Function Definitions *************************/
- +
- +#ifdef SPI_ASYNC
- +static void gf_spi_complete(void *arg)
- +{
- + complete(arg);
- +}
- +#endif
- +
- +int gf_spi_read_bytes(struct gf_dev *gf_dev, unsigned short addr, unsigned short data_len,
- + unsigned char *rx_buf)
- +{
- +#ifdef SPI_ASYNC
- + DECLARE_COMPLETION_ONSTACK(write_done);
- +#endif
- + struct spi_message msg;
- + struct spi_transfer *xfer;
- + int ret = 0;
- +
- + xfer = kzalloc(sizeof(*xfer)*2, GFP_KERNEL);
- + if (xfer == NULL) {
- + pr_err("%s, No memory for command.\n", __func__);
- + return -ENOMEM;
- + }
- +
- + /*send gf command to device.*/
- + spi_message_init(&msg);
- + rx_buf[0] = GF_W;
- + rx_buf[1] = (unsigned char)((addr >> 8)&0xFF);
- + rx_buf[2] = (unsigned char)(addr & 0xFF);
- + xfer[0].tx_buf = rx_buf;
- + xfer[0].len = 3;
- + spi_message_add_tail(&xfer[0], &msg);
- +
- + /*if wanted to read data from gf.
- + *Should write Read command to device
- + *before read any data from device.
- + */
- + spi_sync(gf_dev->spi, &msg);
- + spi_message_init(&msg);
- + memset(rx_buf, 0xff, data_len + 4);
- + rx_buf[3] = GF_R;
- + xfer[1].tx_buf = &rx_buf[3];
- + xfer[1].rx_buf = &rx_buf[3];
- + xfer[1].len = data_len + 1;
- +
- + spi_message_add_tail(&xfer[1], &msg);
- +
- +#ifdef SPI_ASYNC
- + msg.complete = gf_spi_complete;
- + msg.context = &write_done;
- +
- + spin_lock_irq(&gf_dev->spi_lock);
- + ret = spi_async(gf_dev->spi, &msg);
- + spin_unlock_irq(&gf_dev->spi_lock);
- + if (ret == 0) {
- + wait_for_completion(&write_done);
- + if (msg.status == 0)
- + ret = msg.actual_length - 1;
- + }
- +#else
- + ret = spi_sync(gf_dev->spi, &msg);
- + if (ret == 0) {
- + ret = msg.actual_length - 1;
- + }
- +#endif
- + kfree(xfer);
- + if (xfer != NULL)
- + xfer = NULL;
- +
- + return 0;
- +}
- +
- +int gf_spi_write_bytes(struct gf_dev *gf_dev, unsigned short addr, unsigned short data_len,
- + unsigned char *tx_buf)
- +{
- +#ifdef SPI_ASYNC
- + DECLARE_COMPLETION_ONSTACK(read_done);
- +#endif
- + struct spi_message msg;
- + struct spi_transfer *xfer;
- + int ret = 0;
- +
- + xfer = kzalloc(sizeof(*xfer), GFP_KERNEL);
- + if (xfer == NULL) {
- + pr_err("%s, No memory for command.\n", __func__);
- + return -ENOMEM;
- + }
- +
- + /*send gf command to device.*/
- + spi_message_init(&msg);
- + tx_buf[0] = GF_W;
- + tx_buf[1] = (unsigned char)((addr >> 8)&0xFF);
- + tx_buf[2] = (unsigned char)(addr & 0xFF);
- + xfer[0].tx_buf = tx_buf;
- + xfer[0].len = data_len + 3;
- + spi_message_add_tail(xfer, &msg);
- +#ifdef SPI_ASYNC
- + msg.complete = gf_spi_complete;
- + msg.context = &read_done;
- +
- + spin_lock_irq(&gf_dev->spi_lock);
- + ret = spi_async(gf_dev->spi, &msg);
- + spin_unlock_irq(&gf_dev->spi_lock);
- + if (ret == 0) {
- + wait_for_completion(&read_done);
- + if (msg.status == 0)
- + ret = msg.actual_length - GF_WDATA_OFFSET;
- + }
- +#else
- + ret = spi_sync(gf_dev->spi, &msg);
- + if (ret == 0) {
- + ret = msg.actual_length - GF_WDATA_OFFSET;
- + }
- +#endif
- + kfree(xfer);
- + if (xfer != NULL)
- + xfer = NULL;
- +
- + return 0;
- +}
- +
- +int gf_spi_read_word(struct gf_dev *gf_dev, unsigned short addr, unsigned short *value)
- +{
- + int status = 0;
- + u8 *buf = NULL;
- + mutex_lock(&gf_dev->buf_lock);
- + status = gf_spi_read_bytes(gf_dev, addr, 2, gf_dev->gBuffer);
- + buf = gf_dev->gBuffer + GF_RDATA_OFFSET;
- + *value = ((unsigned short)(buf[0]<<8)) | buf[1];
- + mutex_unlock(&gf_dev->buf_lock);
- + return status;
- +}
- +
- +int gf_spi_write_word(struct gf_dev *gf_dev, unsigned short addr, unsigned short value)
- +{
- + int status = 0;
- + mutex_lock(&gf_dev->buf_lock);
- + gf_dev->gBuffer[GF_WDATA_OFFSET] = 0x00;
- + gf_dev->gBuffer[GF_WDATA_OFFSET+1] = 0x01;
- + gf_dev->gBuffer[GF_WDATA_OFFSET+2] = (u8)(value>>8);
- + gf_dev->gBuffer[GF_WDATA_OFFSET+3] = (u8)(value & 0x00ff);
- + status = gf_spi_write_bytes(gf_dev, addr, 4, gf_dev->gBuffer);
- + mutex_unlock(&gf_dev->buf_lock);
- +
- + return status;
- +}
- +
- +void endian_exchange(int len, unsigned char *buf)
- +{
- + int i;
- + u8 buf_tmp;
- + for (i = 0; i < len/2; i++) {
- + buf_tmp = buf[2*i+1];
- + buf[2*i+1] = buf[2*i] ;
- + buf[2*i] = buf_tmp;
- + }
- +}
- +
- +int gf_spi_read_data(struct gf_dev *gf_dev, unsigned short addr, int len, unsigned char *value)
- +{
- + int status;
- +
- + mutex_lock(&gf_dev->buf_lock);
- + status = gf_spi_read_bytes(gf_dev, addr, len, gf_dev->gBuffer);
- + memcpy(value, gf_dev->gBuffer+GF_RDATA_OFFSET, len);
- + mutex_unlock(&gf_dev->buf_lock);
- +
- + return status;
- +}
- +
- +int gf_spi_read_data_bigendian(struct gf_dev *gf_dev, unsigned short addr, int len, unsigned char *value)
- +{
- + int status;
- +
- + mutex_lock(&gf_dev->buf_lock);
- + status = gf_spi_read_bytes(gf_dev, addr, len, gf_dev->gBuffer);
- + memcpy(value, gf_dev->gBuffer+GF_RDATA_OFFSET, len);
- + mutex_unlock(&gf_dev->buf_lock);
- +
- + endian_exchange(len, value);
- + return status;
- +}
- +
- +int gf_spi_write_data(struct gf_dev *gf_dev, unsigned short addr, int len, unsigned char *value)
- +{
- + int status = 0;
- + unsigned short addr_len = 0;
- + unsigned char *buf = NULL;
- +
- + if (len > 1024 * 10) {
- + pr_err("%s length is large.\n", __func__);
- + return -EPERM;
- + }
- +
- + addr_len = len / 2;
- +
- + buf = kzalloc(len + 2, GFP_KERNEL);
- + if (buf == NULL) {
- + pr_err("%s, No memory for gBuffer.\n", __func__);
- + return -ENOMEM;
- + }
- +
- + buf[0] = (unsigned char) ((addr_len & 0xFF00) >> 8);
- + buf[1] = (unsigned char) (addr_len & 0x00FF);
- + memcpy(buf+2, value, len);
- + endian_exchange(len, buf+2);
- +
- + mutex_lock(&gf_dev->buf_lock);
- + memcpy(gf_dev->gBuffer+GF_WDATA_OFFSET, buf, len+2);
- + kfree(buf);
- +
- + status = gf_spi_write_bytes(gf_dev, addr, len+2, gf_dev->gBuffer);
- + mutex_unlock(&gf_dev->buf_lock);
- +
- + return status;
- +}
- +
- +/***
- + * Yfpan Change gf_spi_send_cmd()interface for Milan HV Series.
- + * (Now add for MilanE HV)
- + ***/
- +int gf_spi_send_cmd(struct gf_dev *gf_dev, unsigned char *cmd, int len)
- +{
- + struct spi_message msg;
- + struct spi_transfer *xfer;
- + int ret;
- +
- + /***
- + * Add for HV Enable and Voltage value
- + **/
- + unsigned short cmd_15v_enable = 0x08D0;
- + unsigned short cmd_14v_enable = 0x18D0;
- + unsigned short cmd_13v_enable = 0x28D0;
- + unsigned short cmd_12v_enable = 0x38D0;
- + unsigned short cmd_11v_enable = 0x48D0;
- + unsigned short cmd_10v_enable = 0x58D0;
- + unsigned short cmd_9v_enable = 0x68D0;
- + unsigned short cmd_8v_enable = 0x78D0;
- + unsigned short cmd_7v_enable = 0x88D0;
- + unsigned short cmd_hv_disable = 0x00D0;
- +
- + spi_message_init(&msg);
- + xfer = kzalloc(sizeof(*xfer), GFP_KERNEL);
- +
- + if (xfer == NULL) {
- + pr_err("%s, No memory for command.\n", __func__);
- + return -ENOMEM;
- + }
- +
- + switch (*cmd) {
- + case 0x08:
- + pr_info("%s Enable HV and set voltage to 15v.", __func__);
- + xfer->tx_buf = &cmd_15v_enable;
- + xfer->len = 2;
- + break;
- + case 0x18:
- + pr_info("%s Enable HV and set voltage to 14v.", __func__);
- + xfer->tx_buf = &cmd_14v_enable;
- + xfer->len = 2;
- + break;
- + case 0x28:
- + pr_info("%s Enable HV and set voltage to 13v.", __func__);
- + xfer->tx_buf = &cmd_13v_enable;
- + xfer->len = 2;
- + break;
- + case 0x38:
- + pr_info("%s Enable HV and set voltage to 12v.", __func__);
- + xfer->tx_buf = &cmd_12v_enable;
- + xfer->len = 2;
- + break;
- + case 0x48:
- + pr_info("%s Enable HV and set voltage to 11v.", __func__);
- + xfer->tx_buf = &cmd_11v_enable;
- + xfer->len = 2;
- + break;
- + case 0x58:
- + pr_info("%s Enable HV and set voltage to 10v.", __func__);
- + xfer->tx_buf = &cmd_10v_enable;
- + xfer->len = 2;
- + break;
- + case 0x68:
- + pr_info("%s Enable HV and set voltage to 9v.", __func__);
- + xfer->tx_buf = &cmd_9v_enable;
- + xfer->len = 2;
- + break;
- + case 0x78:
- + pr_info("%s Enable HV and set voltage to 8v.", __func__);
- + xfer->tx_buf = &cmd_8v_enable;
- + xfer->len = 2;
- + break;
- + case 0x88:
- + case 0x98:
- + case 0xa8:
- + case 0xb8:
- + case 0xd8:
- + pr_info("%s Enable HV and set voltage to 7v.", __func__);
- + xfer->tx_buf = &cmd_7v_enable;
- + xfer->len = 2;
- + break;
- + case 0x00:
- + pr_info("%s Disable HV.", __func__);
- + xfer->tx_buf = &cmd_hv_disable;
- + xfer->len = 2;
- + break;
- + default:
- + xfer->tx_buf = cmd;
- + xfer->len = len;
- + break;
- + }
- +
- + spi_message_add_tail(xfer, &msg);
- + ret = spi_sync(gf_dev->spi, &msg);
- +
- + kfree(xfer);
- + if (xfer != NULL)
- + xfer = NULL;
- +
- + return ret;
- +}
- diff --git a/drivers/input/fingerprint/goodix/gf_common.h b/drivers/input/fingerprint/goodix/gf_common.h
- new file mode 100644
- index 0000000..7c10ef9
- --- /dev/null
- +++ b/drivers/input/fingerprint/goodix/gf_common.h
- @@ -0,0 +1,27 @@
- +#ifndef __GF_COMMON_H__
- +#define __GF_COMMON_H__
- +
- +#include "gf_spi.h"
- +
- +/****************Function prototypes*****************/
- +int gf_spi_read_bytes(struct gf_dev *gf_dev, unsigned short addr,
- + unsigned short data_len, unsigned char *rx_buf);
- +
- +int gf_spi_write_bytes(struct gf_dev *gf_dev, unsigned short addr,
- + unsigned short data_len, unsigned char *tx_buf);
- +
- +int gf_spi_read_word(struct gf_dev *gf_dev, unsigned short addr, unsigned short *value);
- +
- +int gf_spi_write_word(struct gf_dev *gf_dev, unsigned short addr, unsigned short value);
- +
- +int gf_spi_read_data(struct gf_dev *gf_dev, unsigned short addr,
- + int len, unsigned char *value);
- +
- +int gf_spi_read_data_bigendian(struct gf_dev *gf_dev, unsigned short addr,
- + int len, unsigned char *value);
- +
- +int gf_spi_write_data(struct gf_dev *gf_dev, unsigned short addr,
- + int len, unsigned char *value);
- +
- +int gf_spi_send_cmd(struct gf_dev *gf_dev, unsigned char *cmd, int len);
- +#endif
- diff --git a/drivers/input/fingerprint/goodix/gf_spi.c b/drivers/input/fingerprint/goodix/gf_spi.c
- new file mode 100644
- index 0000000..63769bd
- --- /dev/null
- +++ b/drivers/input/fingerprint/goodix/gf_spi.c
- @@ -0,0 +1,986 @@
- +/*Simple synchronous userspace interface to SPI devices
- + *
- + * Copyright (C) 2006 SWAPP
- + * Andrea Paterniani <a.paterniani@swapp-eng.it>
- + * Copyright (C) 2007 David Brownell (simplification, cleanup)
- + * Copyright (C) 2017 XiaoMi, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- + */
- +#include <linux/init.h>
- +#include <linux/module.h>
- +#include <linux/ioctl.h>
- +#include <linux/fs.h>
- +#include <linux/device.h>
- +#include <linux/input.h>
- +#include <linux/clk.h>
- +#include <linux/err.h>
- +#include <linux/list.h>
- +#include <linux/errno.h>
- +#include <linux/mutex.h>
- +#include <linux/slab.h>
- +#include <linux/compat.h>
- +#include <linux/delay.h>
- +#include <asm/uaccess.h>
- +#include <linux/ktime.h>
- +#include <linux/interrupt.h>
- +#include <linux/irq.h>
- +#include <linux/gpio.h>
- +#include <linux/regulator/consumer.h>
- +#include <linux/of_gpio.h>
- +#include <linux/timer.h>
- +#include <linux/notifier.h>
- +#include <linux/fb.h>
- +#include <linux/pm_qos.h>
- +#include <linux/cpufreq.h>
- +#include <linux/wakelock.h>
- +#include "gf_spi.h"
- +#include "gf_common.h"
- +
- +#if defined(USE_SPI_BUS)
- +#include <linux/spi/spi.h>
- +#include <linux/spi/spidev.h>
- +#elif defined(USE_PLATFORM_BUS)
- +#include <linux/platform_device.h>
- +#endif
- +
- +#define GF_SPIDEV_NAME "goodix,fingerprint"
- +/*device name after register in charater*/
- +#define GF_DEV_NAME "goodix_fp"
- +#define GF_INPUT_NAME "qwerty" /*"goodix_fp" */
- +
- +#define CHRD_DRIVER_NAME "goodix_fp_spi"
- +#define CLASS_NAME "goodix_fp"
- +
- +#define SPIDEV_MAJOR 214 /* assigned */
- +#define N_SPI_MINORS 32 /* ... up to 256 */
- +
- +
- +/*GF regs*/
- +#define GF_CHIP_ID_LO 0x0000
- +#define GF_CHIP_ID_HI 0x0002
- +#define GF_VENDOR_ID 0x0006
- +#define GF_IRQ_CTRL2 0x0124
- +#define GF_IRQ_CTRL3 0x0126
- +
- +/*GF input keys*/
- +#define GF_KEY_POWER KEY_POWER
- +#define GF_KEY_HOME KEY_HOME
- +#define GF_KEY_MENU KEY_MENU
- +#define GF_KEY_BACK KEY_BACK
- +#define GF_UP_KEY KEY_UP
- +#define GF_DOWN_KEY KEY_DOWN
- +#define GF_LEFT_KEY KEY_LEFT
- +#define GF_RIGHT_KEY KEY_RIGHT
- +#define GF_KEY_FORCE KEY_F9
- +#define GF_APP_SWITCH KEY_F19
- +#define GF_KEY_F1 KEY_F1
- +#define GF_KEY_F2 KEY_F2
- +#define GF_KEY_F3 KEY_F3
- +/**************************debug******************************/
- +#define GF_DEBUG
- +/*#undef GF_DEBUG*/
- +
- +#ifdef GF_DEBUG
- +#define gf_dbg(fmt, args...) do { \
- + pr_info("gf:" fmt, ##args);\
- +} while (0)
- +#define FUNC_ENTRY() pr_info("gf:%s, entry\n", __func__)
- +#define FUNC_EXIT() pr_info("gf:%s, exit\n", __func__)
- +#else
- +#define gf_dbg(fmt, args...)
- +#define FUNC_ENTRY()
- +#define FUNC_EXIT()
- +#endif
- +
- +/*Global variables*/
- +static DECLARE_BITMAP(minors, N_SPI_MINORS);
- +static LIST_HEAD(device_list);
- +static DEFINE_MUTEX(device_list_lock);
- +
- +static struct gf_dev gf;
- +static unsigned int bufsiz = 22180;
- +static unsigned char g_frame_buf[22180] = {0};
- +static unsigned short g_vendorID = 0;
- +static unsigned int g_chipID = 0;
- +static struct wake_lock fp_wakelock;
- +static unsigned int gf_spi_speed[GF_SPI_KEEP_SPEED] = {4800000, 4800000};
- +
- +/******************* CLK Related Start ****************/
- +static long spi_clk_max_rate(struct clk *clk, unsigned long rate)
- +{
- + long lowest_available, nearest_low, step_size, cur;
- + long step_direction = -1;
- + long guess = rate;
- + int max_steps = 10;
- +
- + FUNC_ENTRY();
- + cur = clk_round_rate(clk, rate);
- + if (cur == rate)
- + return rate;
- +
- + /* if we got here then: cur > rate */
- + lowest_available = clk_round_rate(clk, 0);
- + if (lowest_available > rate)
- + return -EINVAL;
- +
- + step_size = (rate - lowest_available) >> 1;
- + nearest_low = lowest_available;
- +
- + while (max_steps-- && step_size) {
- + guess += step_size * step_direction;
- + cur = clk_round_rate(clk, guess);
- +
- + if ((cur < rate) && (cur > nearest_low))
- + nearest_low = cur;
- + /*
- + * if we stepped too far, then start stepping in the other
- + * direction with half the step size
- + */
- + if (((cur > rate) && (step_direction > 0))
- + || ((cur < rate) && (step_direction < 0))) {
- + step_direction = -step_direction;
- + step_size >>= 1;
- + }
- + }
- + return nearest_low;
- +}
- +
- +static void spi_clock_set(struct gf_dev *gf_dev, int speed)
- +{
- + long rate;
- + int rc;
- + FUNC_ENTRY();
- +
- + rate = spi_clk_max_rate(gf_dev->core_clk, speed);
- + if (rate < 0) {
- + pr_info("%s: no match found for requested clock frequency:%d",
- + __func__, speed);
- + return;
- + }
- +
- + rc = clk_set_rate(gf_dev->core_clk, rate);
- +}
- +
- +#ifdef USE_SPI_BUS
- +static int gfspi_ioctl_clk_init(struct spi_device *spi, struct gf_dev *data)
- +{
- + pr_debug("%s: enter\n", __func__);
- +
- + FUNC_ENTRY();
- + data->clk_enabled = 0;
- + data->core_clk = clk_get(&spi->dev, "core_clk");
- + if (IS_ERR_OR_NULL(data->core_clk)) {
- + pr_err("%s: fail to get core_clk\n", __func__);
- + return -EPERM;
- + }
- + data->iface_clk = clk_get(&spi->dev, "iface_clk");
- + if (IS_ERR_OR_NULL(data->iface_clk)) {
- + pr_err("%s: fail to get iface_clk\n", __func__);
- + clk_put(data->core_clk);
- + data->core_clk = NULL;
- + return -ENOENT;
- + }
- + return 0;
- +}
- +
- +static int gfspi_ioctl_clk_enable(struct gf_dev *data)
- +{
- + int err;
- +
- + pr_debug("%s: enter\n", __func__);
- + FUNC_ENTRY();
- +
- + if (data->clk_enabled)
- + return 0;
- +
- + err = clk_prepare_enable(data->core_clk);
- + if (err) {
- + pr_err("%s: fail to enable core_clk\n", __func__);
- + return -EPERM;
- + }
- +
- + err = clk_prepare_enable(data->iface_clk);
- + if (err) {
- + pr_err("%s: fail to enable iface_clk\n", __func__);
- + clk_disable_unprepare(data->core_clk);
- + return -ENOENT;
- + }
- +
- + data->clk_enabled = 1;
- +
- + return 0;
- +}
- +
- +static int gfspi_ioctl_clk_disable(struct gf_dev *data)
- +{
- + FUNC_ENTRY();
- +
- + if (!data->clk_enabled)
- + return 0;
- +
- + clk_disable_unprepare(data->core_clk);
- + clk_disable_unprepare(data->iface_clk);
- + data->clk_enabled = 0;
- +
- + return 0;
- +}
- +
- +static int gfspi_ioctl_clk_uninit(struct gf_dev *data)
- +{
- + pr_debug("%s: enter\n", __func__);
- +
- + FUNC_ENTRY();
- + if (data->clk_enabled)
- + gfspi_ioctl_clk_disable(data);
- +
- + if (!IS_ERR_OR_NULL(data->core_clk)) {
- + clk_put(data->core_clk);
- + data->core_clk = NULL;
- + }
- +
- + if (!IS_ERR_OR_NULL(data->iface_clk)) {
- + clk_put(data->iface_clk);
- + data->iface_clk = NULL;
- + }
- +
- + return 0;
- +}
- +#endif
- +/******************* CLK Related End ****************/
- +
- +/******************* Enable/Disable IRQ Start ****************/
- +static void gf_enable_irq(struct gf_dev *gf_dev)
- +{
- + FUNC_ENTRY();
- +
- + if (gf_dev->irq_enabled) {
- + pr_warn("IRQ has been enabled.\n");
- + } else {
- + enable_irq(gf_dev->irq);
- + gf_dev->irq_enabled = 1;
- + }
- +
- + FUNC_EXIT();
- +}
- +
- +static void gf_disable_irq(struct gf_dev *gf_dev)
- +{
- + FUNC_ENTRY();
- +
- + if (gf_dev->irq_enabled) {
- + gf_dev->irq_enabled = 0;
- + disable_irq(gf_dev->irq);
- + } else {
- + pr_warn("IRQ has been disabled.\n");
- + }
- +
- + FUNC_EXIT();
- +}
- +/******************* Enable/Disable IRQ End ****************/
- +
- +void gf_spi_setup(struct gf_dev *gf_dev, enum gf_spi_transfer_speed speed)
- +{
- +
- + int ret = 0;
- +
- + pr_info("####### %s %d \n", __func__, __LINE__);
- + if (speed == GF_SPI_KEEP_SPEED)
- + return;
- + gf_dev->spi->mode = SPI_MODE_0;
- + gf_dev->spi->max_speed_hz = gf_spi_speed[speed];
- + gf_dev->spi->bits_per_word = 8;
- + ret = spi_setup(gf_dev->spi);
- + pr_info("%s spi_setup ret = %d", __func__, ret);
- +}
- +
- +static int gf_write_configs(struct gf_dev *gf_dev, struct gf_configs *config, int len)
- +{
- + int cnt;
- + int length = len;
- + int ret = 0;
- + for (cnt = 0; cnt < length; cnt++) {
- + ret = gf_spi_write_word(gf_dev, config[cnt].addr, config[cnt].value);
- + if (ret < 0) {
- + pr_info("%s failed. \n", __func__);
- + return ret;
- + }
- + }
- +
- + return 0;
- +}
- +
- +static ssize_t gf_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
- +{
- + struct gf_dev *gf_dev = filp->private_data;
- + int status = 0;
- + int len = 0;
- +
- + if (buf == NULL || count > bufsiz) {
- + pr_info("%s input parameters invalid. bufsiz = %d,count = %d \n",
- + __func__, bufsiz, (int)count);
- + return -EMSGSIZE;
- + }
- +
- + len = gf_spi_read_data(gf_dev, 0xAAAA, count, g_frame_buf);
- + status = copy_to_user(buf, g_frame_buf, count);
- + if (status != 0) {
- + pr_info("%s copy_to_user failed. status = %d \n", __func__, status);
- + return -EFAULT;
- + }
- + return 0;
- +}
- +
- +
- +static long gf_ioctl(struct file *filp, unsigned int cmd,
- + unsigned long arg)
- +{
- + struct gf_dev *gf_dev = NULL;
- + struct gf_ioc_transfer *ioc = NULL;
- + struct gf_key gf_key = {0};
- + u8 *tmpbuf = NULL;
- + int ret = 0;
- + int retval = 0;
- + int err = 0;
- + unsigned char command = 0;
- + struct gf_configs *p_cfg = NULL;
- + unsigned char cfg_len = 0;
- + struct gf_mode_config *p_mode_cfg = NULL;
- + enum gf_spi_transfer_speed speed;
- +
- + if (_IOC_TYPE(cmd) != GF_IOC_MAGIC)
- + return -ENOTTY;
- + /* Check access direction once here; don't repeat below.
- + * IOC_DIR is from the user perspective, while access_ok is
- + * from the kernel perspective; so they look reversed.
- + */
- + if (_IOC_DIR(cmd) & _IOC_READ)
- + err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd));
- + if (err == 0 && _IOC_DIR(cmd) & _IOC_WRITE)
- + err = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd));
- + if (err)
- + return -EFAULT;
- +
- + gf_dev = (struct gf_dev *)filp->private_data;
- + switch (cmd) {
- + case GF_IOC_RW:
- + ioc = kzalloc(sizeof(*ioc), GFP_KERNEL);
- + if (ioc == NULL) {
- + pr_info("kzalloc ioc failed. \n");
- + retval = -ENOMEM;
- + break;
- + }
- +
- + /*copy command data from user to kernel.*/
- + if (copy_from_user(ioc, (struct gf_ioc_transfer *)arg, sizeof(*ioc))) {
- + pr_info("Failed to copy command from user to kernel.\n");
- + retval = -EFAULT;
- + break;
- + }
- +
- + tmpbuf = kzalloc(ioc->len, GFP_KERNEL);
- + if (tmpbuf == NULL) {
- + pr_info("kzalloc buf failed. \n");
- + retval = -ENOMEM;
- + break;
- + }
- + if ((ioc->len > bufsiz) || (ioc->len == 0)) {
- + pr_info("%s The request length[%d] is longer than supported maximum buffer length[%d].\n"
- + , __func__, ioc->len, bufsiz);
- + retval = -EMSGSIZE;
- + break;
- + }
- +
- + if (ioc->cmd == GF_R) {
- + mutex_lock(&gf_dev->frame_lock);
- + gf_spi_read_data(gf_dev, ioc->addr, ioc->len, tmpbuf);
- +
- + ret = copy_to_user((void __user *)ioc->buf, tmpbuf, ioc->len);
- + mutex_unlock(&gf_dev->frame_lock);
- +
- + if (ret) {
- + pr_info("%s Failed to copy data from kernel to user.\n", __func__);
- + retval = -EFAULT;
- + break;
- + }
- + } else if (ioc->cmd == GF_W) {
- + ret = copy_from_user(tmpbuf, (void __user *)ioc->buf, ioc->len);
- + if (ret) {
- + pr_info("%s Failed to copy data from user to kernel.\n", __func__);
- + retval = -EFAULT;
- + break;
- + }
- + mutex_lock(&gf_dev->frame_lock);
- + gf_spi_write_data(gf_dev, ioc->addr, ioc->len, tmpbuf);
- + mutex_unlock(&gf_dev->frame_lock);
- + } else {
- + pr_warn("%s Error command for ioc->cmd.\n", __func__);
- + retval = -EFAULT;
- + }
- + break;
- + case GF_IOC_CMD:
- + retval = __get_user(command , (u32 __user *)arg);
- + mutex_lock(&gf_dev->frame_lock);
- + gf_spi_send_cmd(gf_dev, &command, 1);
- + mutex_unlock(&gf_dev->frame_lock);
- + mdelay(1);
- + break;
- + case GF_IOC_CONFIG:
- + p_mode_cfg = kzalloc(sizeof(*p_mode_cfg), GFP_KERNEL);
- + if (p_mode_cfg == NULL) {
- + pr_info("kzalloc p_mode_cfg failed. \n");
- + retval = -ENOMEM;
- + break;
- + }
- +
- + if (copy_from_user(p_mode_cfg, (struct gf_mode_config *)arg, sizeof(*p_mode_cfg))) {
- + pr_info("Failed to copy command from user to kernel.\n");
- + retval = -EFAULT;
- + break;
- + }
- +
- + cfg_len = p_mode_cfg->cfg_len*sizeof(struct gf_configs);
- + if (cfg_len > 0) {
- + p_cfg = kzalloc(cfg_len, GFP_KERNEL);
- + if (p_mode_cfg == NULL) {
- + pr_info("kzalloc p_cfg failed. \n");
- + retval = -ENOMEM;
- + break;
- + }
- + } else {
- + pr_info("err cfg_len = %d\n", cfg_len);
- + retval = -EFAULT;
- + break;
- + }
- +
- + if (copy_from_user(p_cfg, p_mode_cfg->p_cfg, cfg_len)) {
- + pr_info("Failed to copy command from user to kernel.\n");
- + retval = -EFAULT;
- + break;
- + }
- + gf_write_configs(gf_dev, p_cfg, p_mode_cfg->cfg_len);
- + break;
- + case GF_IOC_RESET:
- + pr_info("%s GF_IOC_REINIT \n", __func__);
- +
- + gf_hw_reset(gf_dev, 0);
- + break;
- + case GF_IOC_ENABLE_IRQ:
- + pr_info("%s ++++++++++++ GF_IOC_ENABLE_IRQ \n", __func__);
- + gf_enable_irq(gf_dev);
- + break;
- + case GF_IOC_DISABLE_IRQ:
- + pr_info("%s ------------ GF_IOC_DISABLE_IRQ \n", __func__);
- + gf_disable_irq(gf_dev);
- + break;
- + case GF_IOC_SENDKEY:
- + if (copy_from_user
- + (&gf_key, (struct gf_key *)arg, sizeof(struct gf_key))) {
- + pr_warn("Failed to copy data from user space,line=%d.\n", __LINE__);
- + retval = -EFAULT;
- + break;
- +
- + }
- + input_report_key(gf_dev->input, gf_key.key, gf_key.value);
- + input_sync(gf_dev->input);
- + break;
- + case GF_IOC_SETSPEED:
- + retval = __get_user(speed, (u32 __user *)arg);
- + gf_spi_setup(gf_dev, speed);
- + break;
- + default:
- + pr_info("%s gf doesn't support this command.\n", __func__);
- + pr_info("%s CMD = 0x%x,_IOC_DIR:0x%x,_IOC_TYPE:0x%x,IOC_NR:0x%x,IOC_SIZE:0x%x\n",
- + __func__, cmd, _IOC_DIR(cmd), _IOC_TYPE(cmd), _IOC_NR(cmd), _IOC_SIZE(cmd));
- + retval = -EFAULT;
- + break;
- + }
- +
- + if (tmpbuf != NULL) {
- + kfree(tmpbuf);
- + tmpbuf = NULL;
- + }
- + if (ioc != NULL) {
- + kfree(ioc);
- + ioc = NULL;
- + }
- + if (p_cfg != NULL) {
- + kfree(p_cfg);
- + p_cfg = NULL;
- + }
- + if (p_mode_cfg != NULL) {
- + kfree(p_mode_cfg);
- + p_mode_cfg = NULL;
- + }
- + return retval;
- +}
- +
- +#ifdef CONFIG_COMPAT
- + static long
- +gf_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
- +{
- + return gf_ioctl(filp, cmd, (unsigned long)compat_ptr(arg));
- +}
- +#endif /*CONFIG_COMPAT*/
- +
- +static irqreturn_t gf_irq(int irq, void *handle)
- +{
- + struct gf_dev *gf_dev = &gf;
- + unsigned short irq_reg = 0;
- +
- + wake_lock(&fp_wakelock);
- +#ifdef GF_FASYNC
- + gf_spi_read_word(gf_dev, GF_IRQ_CTRL3, &irq_reg);
- + if (irq_reg != 0x08) {
- + if (gf_dev->async)
- + kill_fasync(&gf_dev->async, SIGIO, POLL_IN);
- + }
- +#endif
- +
- + return IRQ_HANDLED;
- +}
- +
- +static int gf_open(struct inode *inode, struct file *filp)
- +{
- + struct gf_dev *gf_dev;
- + int status = -ENXIO;
- + int cnt = 0;
- + unsigned short reg = 0;
- +
- + FUNC_ENTRY();
- +
- + mutex_lock(&device_list_lock);
- +
- + list_for_each_entry(gf_dev, &device_list, device_entry) {
- + if (gf_dev->devt == inode->i_rdev) {
- + gf_dbg("Found\n");
- + status = 0;
- + break;
- + }
- + }
- +
- + if (status == 0) {
- + if (status == 0) {
- + gf_dev->users++;
- + filp->private_data = gf_dev;
- +
- + gf_hw_reset(gf_dev, 0);
- + while (cnt < 5) {
- + gf_spi_read_word(gf_dev, GF_IRQ_CTRL3, ®);
- + if (reg == 0x100 || reg == 0x400 || reg == 0x800) {
- + gf_spi_write_word(gf_dev, GF_IRQ_CTRL2, reg);
- + gf_dbg("reg = 0x%04x cnt = %d\n", reg, cnt);
- + break;
- + }
- + cnt++;
- + }
- +
- + nonseekable_open(inode, filp);
- + gf_dbg("Succeed to open device. irq = %d, user = %d\n",
- + gf_dev->irq, gf_dev->users);
- + if (gf_dev->users == 1) {
- + gf_enable_irq(gf_dev);
- + }
- + }
- + } else {
- + gf_dbg("No device for minor %d\n", iminor(inode));
- + }
- +
- + mutex_unlock(&device_list_lock);
- + FUNC_EXIT();
- + return status;
- +}
- +
- +#ifdef GF_FASYNC
- +static int gf_fasync(int fd, struct file *filp, int mode)
- +{
- + struct gf_dev *gf_dev = filp->private_data;
- + int ret;
- +
- + FUNC_ENTRY();
- + ret = fasync_helper(fd, filp, mode, &gf_dev->async);
- + FUNC_EXIT();
- + gf_dbg("ret = %d\n", ret);
- + return ret;
- +}
- +#endif
- +
- +static int gf_release(struct inode *inode, struct file *filp)
- +{
- + struct gf_dev *gf_dev;
- + int status = 0;
- +
- + FUNC_ENTRY();
- + mutex_lock(&device_list_lock);
- + gf_dev = filp->private_data;
- + filp->private_data = NULL;
- +
- + /*last close?? */
- + gf_dev->users--;
- + if (!gf_dev->users) {
- +
- + gf_dbg("disble_irq. irq = %d\n", gf_dev->irq);
- + gf_disable_irq(gf_dev);
- + }
- + mutex_unlock(&device_list_lock);
- + FUNC_EXIT();
- + return status;
- +}
- +
- +static const struct file_operations gf_fops = {
- + .owner = THIS_MODULE,
- + /* REVISIT switch to aio primitives, so that userspace
- + * gets more complete API coverage. It'll simplify things
- + * too, except for the locking.
- + */
- + .unlocked_ioctl = gf_ioctl,
- +#ifdef CONFIG_COMPAT
- + .compat_ioctl = gf_compat_ioctl,
- +#endif /*CONFIG_COMPAT*/
- + .open = gf_open,
- + .release = gf_release,
- + .read = gf_read,
- +#ifdef GF_FASYNC
- + .fasync = gf_fasync,
- +#endif
- +};
- +
- +static void gf_reg_key_kernel(struct gf_dev *gf_dev)
- +{
- + __set_bit(EV_KEY, gf_dev->input->evbit);
- + __set_bit(GF_KEY_POWER, gf_dev->input->keybit);
- + __set_bit(GF_KEY_HOME, gf_dev->input->keybit);
- + __set_bit(GF_KEY_MENU, gf_dev->input->keybit);
- + __set_bit(GF_KEY_BACK, gf_dev->input->keybit);
- + __set_bit(GF_UP_KEY, gf_dev->input->keybit);
- + __set_bit(GF_RIGHT_KEY, gf_dev->input->keybit);
- + __set_bit(GF_LEFT_KEY, gf_dev->input->keybit);
- + __set_bit(GF_DOWN_KEY, gf_dev->input->keybit);
- + __set_bit(GF_KEY_FORCE, gf_dev->input->keybit);
- + __set_bit(GF_APP_SWITCH, gf_dev->input->keybit);
- +
- +
- + __set_bit(GF_KEY_F1, gf_dev->input->keybit);
- + __set_bit(GF_KEY_F2, gf_dev->input->keybit);
- + __set_bit(GF_KEY_F3, gf_dev->input->keybit);
- +
- + gf_dev->input->name = GF_INPUT_NAME;
- + if (input_register_device(gf_dev->input))
- + pr_warn("Failed to register GF as input device.\n");
- +}
- +
- +static struct class *gf_class;
- +#if defined(USE_SPI_BUS)
- +static int gf_probe(struct spi_device *spi)
- +#elif defined(USE_PLATFORM_BUS)
- +static int gf_probe(struct platform_device *pdev)
- +#endif
- +{
- + struct gf_dev *gf_dev = &gf;
- + int status = -EINVAL;
- + unsigned long minor;
- + int ret;
- + unsigned short chip_id_1 = 0;
- + unsigned short chip_id_2 = 0;
- + FUNC_ENTRY();
- + /* Initialize the driver data */
- + INIT_LIST_HEAD(&gf_dev->device_entry);
- +#if defined(USE_SPI_BUS)
- + gf_dev->spi = spi;
- +#elif defined(USE_PLATFORM_BUS)
- + gf_dev->spi = pdev;
- +#endif
- + gf_dev->irq_gpio = -EINVAL;
- + gf_dev->reset_gpio = -EINVAL;
- + gf_dev->pwr_gpio = -EINVAL;
- + gf_dev->device_available = 0;
- + gf_dev->fb_black = 0;
- +
- + mutex_init(&gf_dev->buf_lock);
- + mutex_init(&gf_dev->frame_lock);
- + spin_lock_init(&gf_dev->spi_lock);
- +
- + if (gf_parse_dts(gf_dev))
- + goto error;
- +
- + if (gf_power_on(gf_dev))
- + goto error;
- +
- + if (gf_hw_reset(gf_dev, 0))
- + goto error;
- +
- + /* If we can allocate a minor number, hook up this device.
- + * Reusing minors is fine so long as udev or mdev is working.
- + */
- + mutex_lock(&device_list_lock);
- + minor = find_first_zero_bit(minors, N_SPI_MINORS);
- + if (minor < N_SPI_MINORS) {
- + struct device *dev;
- +
- + gf_dev->devt = MKDEV(SPIDEV_MAJOR, minor);
- + dev = device_create(gf_class, &gf_dev->spi->dev, gf_dev->devt,
- + gf_dev, GF_DEV_NAME);
- + status = IS_ERR(dev) ? PTR_ERR(dev) : 0;
- + } else {
- + dev_dbg(&gf_dev->spi->dev, "no minor number available!\n");
- + status = -ENODEV;
- + }
- +
- + if (status == 0) {
- + set_bit(minor, minors);
- + list_add(&gf_dev->device_entry, &device_list);
- + } else {
- + gf_dev->devt = 0;
- + }
- + mutex_unlock(&device_list_lock);
- + wake_lock_init(&fp_wakelock, WAKE_LOCK_SUSPEND, "fp_wakelock");
- +
- + if (status == 0) {
- + gf_dev->gBuffer = kzalloc(bufsiz + GF_RDATA_OFFSET, GFP_KERNEL);
- + if (gf_dev->gBuffer == NULL) {
- + return -ENOMEM;
- + }
- +
- + /*input device subsystem */
- + gf_dev->input = input_allocate_device();
- + if (gf_dev->input == NULL) {
- + dev_dbg(&gf_dev->input->dev,
- + "Faile to allocate input device.\n");
- + status = -ENOMEM;
- + }
- +#ifdef USE_SPI_BUS
- + /* Enable spi clock */
- + if (gfspi_ioctl_clk_init(spi, gf_dev))
- + goto gfspi_probe_clk_init_failed;
- +
- + if (gfspi_ioctl_clk_enable(gf_dev))
- + goto gfspi_probe_clk_enable_failed;
- +
- + spi_clock_set(gf_dev, 9600000);
- +#else
- + pr_info("Get the clk resource.\n");
- + gf_dev->core_clk = clk_get(&pdev->dev, "core_clk");
- + if (IS_ERR(gf_dev->core_clk)) {
- + pr_warn("Failed to get core_clk.\n");
- + goto error;
- + }
- + gf_dev->iface_clk = clk_get(&pdev->dev, "iface_clk");
- + if (IS_ERR(gf_dev->iface_clk)) {
- + pr_warn("Failed to get iface_clk.\n");
- + goto error;
- + }
- +#endif
- +
- + gf_reg_key_kernel(gf_dev);
- +
- + gf_spi_setup(gf_dev, GF_SPI_HIGH_SPEED);
- + gf_dev->irq = gf_irq_num(gf_dev);
- + ret = request_threaded_irq(gf_dev->irq, NULL, gf_irq,
- + IRQF_TRIGGER_RISING | IRQF_ONESHOT,
- + "gf", gf_dev);
- + if (!ret) {
- + pr_info("%s called enable_irq_wake.\n", __func__);
- + enable_irq_wake(gf_dev->irq);
- +
- + gf_dev->irq_enabled = 1;
- + gf_disable_irq(gf_dev);
- + }
- + }
- + gf_spi_write_word(gf_dev, GF_IRQ_CTRL2, 0xFFFF); /*0x0124, 0x0400 clean reset INT*/
- +
- + /*Get vendorID */
- + gf_spi_read_word(gf_dev, GF_VENDOR_ID, &g_vendorID);
- + pr_info("%s vendorID = 0x%04X\n", __func__, g_vendorID);
- +
- + gf_spi_read_word(gf_dev, GF_CHIP_ID_LO, &chip_id_1);
- + gf_spi_read_word(gf_dev, GF_CHIP_ID_HI, &chip_id_2);
- + g_chipID = ((chip_id_2<<16)|(chip_id_1)) >> 8;
- + pr_info("%s: chip_id_hi = 0x%x, chip_id_low = 0x%x, g_chipID is 0x%08x \n", __func__, chip_id_2, chip_id_1, g_chipID);
- +
- + pr_info("succeed to probe.\n");
- + gf_dev->device_available = 1;
- + return status;
- +
- +error:
- + gf_cleanup(gf_dev);
- + gf_dev->device_available = 0;
- + if (gf_dev->devt != 0) {
- + pr_info("Err: status = %d\n", status);
- + mutex_lock(&device_list_lock);
- + list_del(&gf_dev->device_entry);
- + device_destroy(gf_class, gf_dev->devt);
- + clear_bit(MINOR(gf_dev->devt), minors);
- + mutex_unlock(&device_list_lock);
- +#ifdef USE_SPI_BUS
- +gfspi_probe_clk_enable_failed:
- + gfspi_ioctl_clk_uninit(gf_dev);
- +gfspi_probe_clk_init_failed:
- +#else
- + if (gf_dev->iface_clk != NULL)
- + clk_put(gf_dev->iface_clk);
- +
- + if (gf_dev->core_clk != NULL)
- + clk_put(gf_dev->core_clk);
- +
- +#endif
- + if (gf_dev->input != NULL)
- + input_unregister_device(gf_dev->input);
- +
- +
- + }
- + if (gf_dev->gBuffer != NULL) {
- + kfree(gf_dev->gBuffer);
- + }
- +
- + FUNC_EXIT();
- + return status;
- +}
- +
- +/*static int __devexit gf_remove(struct spi_device *spi)*/
- +#if defined(USE_SPI_BUS)
- +static int gf_remove(struct spi_device *spi)
- +#elif defined(USE_PLATFORM_BUS)
- +static int gf_remove(struct platform_device *pdev)
- +#endif
- +{
- + struct gf_dev *gf_dev = &gf;
- + FUNC_ENTRY();
- +
- + wake_lock_destroy(&fp_wakelock);
- + /* make sure ops on existing fds can abort cleanly */
- + if (gf_dev->irq)
- + free_irq(gf_dev->irq, gf_dev);
- +
- + if (gf_dev->input != NULL)
- + input_unregister_device(gf_dev->input);
- + input_free_device(gf_dev->input);
- +
- + /* prevent new opens */
- + mutex_lock(&device_list_lock);
- + list_del(&gf_dev->device_entry);
- + device_destroy(gf_class, gf_dev->devt);
- + clear_bit(MINOR(gf_dev->devt), minors);
- +
- + gf_cleanup(gf_dev);
- + gf_dev->device_available = 0;
- + fb_unregister_client(&gf_dev->notifier);
- +
- +#ifdef USE_SPI_BUS
- + gfspi_ioctl_clk_uninit(gf_dev);
- +#else
- + if (gf_dev->iface_clk != NULL)
- + clk_put(gf_dev->iface_clk);
- +
- + if (gf_dev->core_clk != NULL)
- + clk_put(gf_dev->core_clk);
- +
- +#endif
- +
- +
- + if (gf_dev->users == 0) {
- + if (gf_dev->gBuffer)
- + kfree(gf_dev->gBuffer);
- + } else {
- + pr_info("Not free_pages.\n");
- + }
- +
- + mutex_unlock(&device_list_lock);
- +
- + FUNC_EXIT();
- + return 0;
- +}
- +
- +static struct of_device_id gx_match_table[] = {
- + {.compatible = GF_SPIDEV_NAME,},
- + {},
- +};
- +
- +#if defined(USE_SPI_BUS)
- +static struct spi_driver gf_driver = {
- +#elif defined(USE_PLATFORM_BUS)
- + static struct platform_driver gf_driver = {
- +#endif
- + .driver = {
- + .name = GF_DEV_NAME,
- + .owner = THIS_MODULE,
- +#if defined(USE_SPI_BUS)
- +#endif
- + .of_match_table = gx_match_table,
- + },
- + .probe = gf_probe,
- + .remove = gf_remove,
- + };
- +
- +static int __init gf_init(void)
- +{
- + int status;
- + FUNC_ENTRY();
- +
- + /* Claim our 256 reserved device numbers. Then register a class
- + * that will key udev/mdev to add/remove /dev nodes. Last, register
- + * the driver which manages those device numbers.
- + */
- +
- + BUILD_BUG_ON(N_SPI_MINORS > 256);
- + status = register_chrdev(SPIDEV_MAJOR, CHRD_DRIVER_NAME, &gf_fops);
- + pr_info("SPIDEV_MAJOR = %d\n", SPIDEV_MAJOR);
- + if (status < 0) {
- + pr_warn("Failed to register char device!\n");
- + FUNC_EXIT();
- + return status;
- + }
- + gf_class = class_create(THIS_MODULE, CLASS_NAME);
- + if (IS_ERR(gf_class)) {
- + unregister_chrdev(SPIDEV_MAJOR, gf_driver.driver.name);
- + pr_warn("Failed to create class.\n");
- + FUNC_EXIT();
- + return PTR_ERR(gf_class);
- + }
- +#if defined(USE_PLATFORM_BUS)
- + status = platform_driver_register(&gf_driver);
- +#elif defined(USE_SPI_BUS)
- + status = spi_register_driver(&gf_driver);
- +#endif
- + if (status < 0) {
- + class_destroy(gf_class);
- + unregister_chrdev(SPIDEV_MAJOR, gf_driver.driver.name);
- + pr_warn("Failed to register SPI driver.\n");
- + }
- +
- + pr_info(" status = 0x%x\n", status);
- + FUNC_EXIT();
- + return 0;
- +}
- +
- +module_init(gf_init);
- +
- +static void __exit gf_exit(void)
- +{
- + FUNC_ENTRY();
- +#if defined(USE_PLATFORM_BUS)
- + platform_driver_unregister(&gf_driver);
- +#elif defined(USE_SPI_BUS)
- + spi_unregister_driver(&gf_driver);
- +#endif
- + class_destroy(gf_class);
- + unregister_chrdev(SPIDEV_MAJOR, gf_driver.driver.name);
- + FUNC_EXIT();
- +}
- +
- +module_exit(gf_exit);
- +
- +MODULE_DESCRIPTION("User mode SPI device interface");
- +MODULE_LICENSE("GPL");
- +MODULE_ALIAS("spi:gf-spi");
- diff --git a/drivers/input/fingerprint/goodix/gf_spi.h b/drivers/input/fingerprint/goodix/gf_spi.h
- new file mode 100644
- index 0000000..2d96c88
- --- /dev/null
- +++ b/drivers/input/fingerprint/goodix/gf_spi.h
- @@ -0,0 +1,102 @@
- +#ifndef __GF_SPI_H
- +#define __GF_SPI_H
- +
- +#include <linux/types.h>
- +#include <linux/notifier.h>
- +/**********************************************************/
- +#define USE_SPI_BUS 1
- +#define GF_FASYNC 1 /* If support fasync mechanism.*/
- +
- +/****************Chip Specific***********************/
- +#define GF_W 0xF0
- +#define GF_R 0xF1
- +#define GF_WDATA_OFFSET (0x3)
- +#define GF_RDATA_OFFSET (0x4)
- +
- +struct gf_configs {
- + unsigned short addr;
- + unsigned short value;
- +};
- +
- +struct gf_mode_config {
- + struct gf_configs *p_cfg;
- + unsigned int cfg_len;
- +};
- +
- +enum gf_spi_transfer_speed {
- + GF_SPI_LOW_SPEED = 0,
- + GF_SPI_HIGH_SPEED,
- + GF_SPI_KEEP_SPEED,
- +};
- +
- +#define GF_IOC_MAGIC 'g'
- +#define GF_IOC_RESET _IO(GF_IOC_MAGIC, 0)
- +#define GF_IOC_RW _IOWR(GF_IOC_MAGIC, 1, struct gf_ioc_transfer)
- +#define GF_IOC_CMD _IOW(GF_IOC_MAGIC, 2, unsigned char)
- +#define GF_IOC_CONFIG _IOW(GF_IOC_MAGIC, 3, void*)
- +#define GF_IOC_ENABLE_IRQ _IO(GF_IOC_MAGIC, 4)
- +#define GF_IOC_DISABLE_IRQ _IO(GF_IOC_MAGIC, 5)
- +#define GF_IOC_SENDKEY _IOW(GF_IOC_MAGIC, 6, struct gf_key)
- +#define GF_IOC_SETSPEED _IOW(GF_IOC_MAGIC, 7, enum gf_spi_transfer_speed)
- +#define GF_IOC_MAXNR 8
- +
- +struct gf_ioc_transfer {
- + unsigned char cmd;
- + unsigned char reserve;
- + unsigned short addr;
- + unsigned int len;
- + unsigned char *buf;
- +};
- +
- +struct gf_key {
- + unsigned int key;
- + int value;
- +};
- +
- +struct gf_key_map {
- + char *name;
- + unsigned short val;
- +};
- +
- +struct gf_dev {
- + dev_t devt;
- + spinlock_t spi_lock;
- + struct list_head device_entry;
- +#if defined(USE_SPI_BUS)
- + struct spi_device *spi;
- +#elif defined(USE_PLATFORM_BUS)
- + struct platform_device *spi;
- +#endif
- + struct clk *core_clk;
- + struct clk *iface_clk;
- +
- + struct input_dev *input;
- + /* buffer is NULL unless this device is open (users > 0) */
- + unsigned users;
- + signed irq_gpio;
- + signed reset_gpio;
- + signed pwr_gpio;
- + int irq;
- + int irq_enabled;
- + int clk_enabled;
- +#ifdef GF_FASYNC
- + struct fasync_struct *async;
- +#endif
- + struct notifier_block notifier;
- + char device_available;
- + char fb_black;
- + unsigned char *gBuffer;
- + struct mutex buf_lock;
- + struct mutex frame_lock;
- +};
- +
- +int gf_parse_dts(struct gf_dev *gf_dev);
- +void gf_cleanup(struct gf_dev *gf_dev);
- +
- +int gf_power_on(struct gf_dev *gf_dev);
- +int gf_power_off(struct gf_dev *gf_dev);
- +
- +int gf_hw_reset(struct gf_dev *gf_dev, unsigned int delay_ms);
- +int gf_irq_num(struct gf_dev *gf_dev);
- +
- +#endif /*__GF_SPI_H*/
- diff --git a/drivers/input/fingerprint/goodix/platform.c b/drivers/input/fingerprint/goodix/platform.c
- new file mode 100644
- index 0000000..0d1b03e
- --- /dev/null
- +++ b/drivers/input/fingerprint/goodix/platform.c
- @@ -0,0 +1,134 @@
- +#include <linux/delay.h>
- +#include <linux/workqueue.h>
- +#include <linux/of_gpio.h>
- +#include <linux/gpio.h>
- +#include <linux/regulator/consumer.h>
- +#include <linux/timer.h>
- +#include <linux/err.h>
- +
- +#include "gf_spi.h"
- +
- +#if defined(USE_SPI_BUS)
- +#include <linux/spi/spi.h>
- +#include <linux/spi/spidev.h>
- +#elif defined(USE_PLATFORM_BUS)
- +#include <linux/platform_device.h>
- +#endif
- +
- +/*GPIO pins reference.*/
- +int gf_parse_dts(struct gf_dev *gf_dev)
- +{
- + int rc = 0;
- + /*get pwr resource*/
- + gf_dev->pwr_gpio = of_get_named_gpio(gf_dev->spi->dev.of_node, "goodix, gpio_pwr", 0);
- + if (!gpio_is_valid(gf_dev->pwr_gpio)) {
- + pr_info("PWR GPIO is invalid.\n");
- + return -EPERM;
- + }
- + rc = gpio_request(gf_dev->pwr_gpio, "goodix_pwr");
- + if (rc) {
- + dev_err(&gf_dev->spi->dev, "Failed to request PWR GPIO. rc = %d\n", rc);
- + return -EPERM;
- + }
- +
- + /*get reset resource*/
- + gf_dev->reset_gpio = of_get_named_gpio(gf_dev->spi->dev.of_node, "goodix, gpio_reset", 0);
- + if (!gpio_is_valid(gf_dev->reset_gpio)) {
- + pr_info("RESET GPIO is invalid.\n");
- + return -EPERM;
- + }
- + rc = gpio_request(gf_dev->reset_gpio, "goodix_reset");
- + if (rc) {
- + dev_err(&gf_dev->spi->dev, "Failed to request RESET GPIO. rc = %d\n", rc);
- + return -EPERM;
- + }
- + gpio_direction_output(gf_dev->reset_gpio, 1);
- +
- + /*get irq resourece*/
- + gf_dev->irq_gpio = of_get_named_gpio(gf_dev->spi->dev.of_node, "goodix, gpio_irq", 0);
- + pr_info("gf:irq_gpio:%d\n", gf_dev->irq_gpio);
- + if (!gpio_is_valid(gf_dev->irq_gpio)) {
- + pr_info("IRQ GPIO is invalid.\n");
- + return -EPERM;
- + }
- +
- + rc = gpio_request(gf_dev->irq_gpio, "goodix_irq");
- + if (rc) {
- + dev_err(&gf_dev->spi->dev, "Failed to request IRQ GPIO. rc = %d\n", rc);
- + return -EPERM;
- + }
- + gpio_direction_input(gf_dev->irq_gpio);
- +
- + //power on
- + gpio_direction_output(gf_dev->pwr_gpio, 1);
- +
- + return 0;
- +}
- +
- +void gf_cleanup(struct gf_dev *gf_dev)
- +{
- + pr_info("[info] %s\n", __func__);
- + if (gpio_is_valid(gf_dev->irq_gpio)) {
- + gpio_free(gf_dev->irq_gpio);
- + pr_info("remove irq_gpio success\n");
- + }
- + if (gpio_is_valid(gf_dev->reset_gpio)) {
- + gpio_free(gf_dev->reset_gpio);
- + pr_info("remove reset_gpio success\n");
- + }
- + if (gpio_is_valid(gf_dev->pwr_gpio)) {
- + gpio_free(gf_dev->pwr_gpio);
- + pr_info("remove pwr_gpio success\n");
- + }
- +}
- +
- +/*power management*/
- +int gf_power_on(struct gf_dev *gf_dev)
- +{
- + int rc = 0;
- + if (gpio_is_valid(gf_dev->pwr_gpio)) {
- + gpio_set_value(gf_dev->pwr_gpio, 1);
- + }
- + msleep(10);
- + pr_info("---- power on ok ----\n");
- +
- + return rc;
- +}
- +
- +int gf_power_off(struct gf_dev* gf_dev)
- +{
- + int rc = 0;
- + if (gpio_is_valid(gf_dev->pwr_gpio)) {
- + gpio_set_value(gf_dev->pwr_gpio, 1);
- + }
- + pr_info("---- power off ----\n");
- + return rc;
- +}
- +
- +/********************************************************************
- + *CPU output low level in RST pin to reset GF. This is the MUST action for GF.
- + *Take care of this function. IO Pin driver strength / glitch and so on.
- + ********************************************************************/
- +int gf_hw_reset(struct gf_dev *gf_dev, unsigned int delay_ms)
- +{
- + if (gf_dev == NULL) {
- + pr_info("Input buff is NULL.\n");
- + return -EPERM;
- + }
- + gpio_direction_output(gf_dev->reset_gpio, 1);
- + gpio_set_value(gf_dev->reset_gpio, 0);
- + mdelay(delay_ms > 3 ? delay_ms : 3);
- + gpio_set_value(gf_dev->reset_gpio, 1);
- + return 0;
- +}
- +
- +int gf_irq_num(struct gf_dev *gf_dev)
- +{
- + if (gf_dev == NULL) {
- + pr_info("Input buff is NULL.\n");
- + return -EPERM;
- + } else {
- + return gpio_to_irq(gf_dev->irq_gpio);
- + }
- +}
- +
- diff --git a/drivers/input/fingerprint/goodix_ta/Kconfig b/drivers/input/fingerprint/goodix_ta/Kconfig
- new file mode 100644
- index 0000000..34b1554
- --- /dev/null
- +++ b/drivers/input/fingerprint/goodix_ta/Kconfig
- @@ -0,0 +1,10 @@
- +config FINGERPRINT_GOODIX_TA
- + tristate "Finger print card goodix"
- + depends on INPUT_FINGERPRINT
- + help
- + Say Y here to enable support for retrieving self-test reports.
- +
- + If unsure, say N.
- +
- + To compile this driver as a module, choose M here.
- +
- diff --git a/drivers/input/fingerprint/goodix_ta/Makefile b/drivers/input/fingerprint/goodix_ta/Makefile
- new file mode 100644
- index 0000000..43929c1
- --- /dev/null
- +++ b/drivers/input/fingerprint/goodix_ta/Makefile
- @@ -0,0 +1 @@
- +obj-$(CONFIG_FINGERPRINT_GOODIX_TA) += gf_spi.o platform.o netlink.o
- diff --git a/drivers/input/fingerprint/goodix_ta/gf_spi.c b/drivers/input/fingerprint/goodix_ta/gf_spi.c
- new file mode 100644
- index 0000000..1e76d3e
- --- /dev/null
- +++ b/drivers/input/fingerprint/goodix_ta/gf_spi.c
- @@ -0,0 +1,906 @@
- +/*
- + * TEE driver for goodix fingerprint sensor
- + * Copyright (C) 2016 Goodix
- + * Copyright (C) 2017 XiaoMi, 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.
- + */
- +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
- +
- +#include <linux/init.h>
- +#include <linux/module.h>
- +#include <linux/ioctl.h>
- +#include <linux/fs.h>
- +#include <linux/device.h>
- +#include <linux/input.h>
- +#include <linux/clk.h>
- +#include <linux/err.h>
- +#include <linux/list.h>
- +#include <linux/errno.h>
- +#include <linux/mutex.h>
- +#include <linux/slab.h>
- +#include <linux/compat.h>
- +#include <linux/delay.h>
- +#include <asm/uaccess.h>
- +#include <linux/ktime.h>
- +#include <linux/interrupt.h>
- +#include <linux/irq.h>
- +#include <linux/gpio.h>
- +#include <linux/regulator/consumer.h>
- +#include <linux/of_gpio.h>
- +#include <linux/timer.h>
- +#include <linux/notifier.h>
- +#include <linux/fb.h>
- +#include <linux/pm_qos.h>
- +#include <linux/cpufreq.h>
- +#include <linux/wakelock.h>
- +
- +#include "gf_spi.h"
- +
- +#if defined(USE_SPI_BUS)
- +#include <linux/spi/spi.h>
- +#include <linux/spi/spidev.h>
- +#elif defined(USE_PLATFORM_BUS)
- +#include <linux/platform_device.h>
- +#endif
- +
- +#define VER_MAJOR 1
- +#define VER_MINOR 2
- +#define PATCH_LEVEL 1
- +
- +#define GF_SPIDEV_NAME "goodix,fingerprint"
- +/*device name after register in charater*/
- +#define GF_DEV_NAME "goodix_fp"
- +#define GF_INPUT_NAME "uinput-goodix" /*"goodix_fp" */
- +
- +#define CHRD_DRIVER_NAME "goodix_fp_spi"
- +#define CLASS_NAME "goodix_fp"
- +
- +#define N_SPI_MINORS 32 /* ... up to 256 */
- +static int SPIDEV_MAJOR;
- +
- +static DECLARE_BITMAP(minors, N_SPI_MINORS);
- +static LIST_HEAD(device_list);
- +static DEFINE_MUTEX(device_list_lock);
- +static struct wake_lock fp_wakelock;
- +static struct gf_dev gf;
- +
- +struct gf_key_map maps[] = {
- + { EV_KEY, GF_KEY_INPUT_HOME },
- + { EV_KEY, GF_KEY_INPUT_MENU },
- + { EV_KEY, GF_KEY_INPUT_BACK },
- + { EV_KEY, GF_KEY_INPUT_POWER },
- +#if defined(SUPPORT_NAV_EVENT)
- + { EV_KEY, GF_NAV_INPUT_UP },
- + { EV_KEY, GF_NAV_INPUT_DOWN },
- + { EV_KEY, GF_NAV_INPUT_RIGHT },
- + { EV_KEY, GF_NAV_INPUT_LEFT },
- + { EV_KEY, GF_KEY_INPUT_CAMERA },
- + { EV_KEY, GF_NAV_INPUT_CLICK },
- + { EV_KEY, GF_NAV_INPUT_DOUBLE_CLICK },
- + { EV_KEY, GF_NAV_INPUT_LONG_PRESS },
- + { EV_KEY, GF_NAV_INPUT_HEAVY },
- +#endif
- +};
- +
- +static void gf_enable_irq(struct gf_dev *gf_dev)
- +{
- + if (gf_dev->irq_enabled) {
- + pr_warn("IRQ has been enabled.\n");
- + } else {
- + enable_irq(gf_dev->irq);
- + gf_dev->irq_enabled = 1;
- + }
- +}
- +
- +static void gf_disable_irq(struct gf_dev *gf_dev)
- +{
- + if (gf_dev->irq_enabled) {
- + gf_dev->irq_enabled = 0;
- + disable_irq(gf_dev->irq);
- + } else {
- + pr_warn("IRQ has been disabled.\n");
- + }
- +}
- +
- +#ifdef AP_CONTROL_CLK
- +static long spi_clk_max_rate(struct clk *clk, unsigned long rate)
- +{
- + long lowest_available, nearest_low, step_size, cur;
- + long step_direction = -1;
- + long guess = rate;
- + int max_steps = 10;
- +
- + cur = clk_round_rate(clk, rate);
- + if (cur == rate)
- + return rate;
- +
- + /* if we got here then: cur > rate */
- + lowest_available = clk_round_rate(clk, 0);
- + if (lowest_available > rate)
- + return -EINVAL;
- +
- + step_size = (rate - lowest_available) >> 1;
- + nearest_low = lowest_available;
- +
- + while (max_steps-- && step_size) {
- + guess += step_size * step_direction;
- + cur = clk_round_rate(clk, guess);
- +
- + if ((cur < rate) && (cur > nearest_low))
- + nearest_low = cur;
- + /*
- + * if we stepped too far, then start stepping in the other
- + * direction with half the step size
- + */
- + if (((cur > rate) && (step_direction > 0))
- + || ((cur < rate) && (step_direction < 0))) {
- + step_direction = -step_direction;
- + step_size >>= 1;
- + }
- + }
- + return nearest_low;
- +}
- +
- +static void spi_clock_set(struct gf_dev *gf_dev, int speed)
- +{
- + long rate;
- + int rc;
- +
- + rate = spi_clk_max_rate(gf_dev->core_clk, speed);
- + if (rate < 0) {
- + pr_debug("%s: no match found for requested clock frequency:%d",
- + __func__, speed);
- + return;
- + }
- +
- + rc = clk_set_rate(gf_dev->core_clk, rate);
- +}
- +
- +static int gfspi_ioctl_clk_init(struct gf_dev *data)
- +{
- + pr_debug("%s: enter\n", __func__);
- +
- + data->clk_enabled = 0;
- + data->core_clk = clk_get(&data->spi->dev, "core_clk");
- + if (IS_ERR_OR_NULL(data->core_clk)) {
- + pr_err("%s: fail to get core_clk\n", __func__);
- + return -EPERM;
- + }
- + data->iface_clk = clk_get(&data->spi->dev, "iface_clk");
- + if (IS_ERR_OR_NULL(data->iface_clk)) {
- + pr_err("%s: fail to get iface_clk\n", __func__);
- + clk_put(data->core_clk);
- + data->core_clk = NULL;
- + return -ENOENT;
- + }
- + return 0;
- +}
- +
- +static int gfspi_ioctl_clk_enable(struct gf_dev *data)
- +{
- + int err;
- +
- + pr_debug("%s: enter\n", __func__);
- +
- + if (data->clk_enabled)
- + return 0;
- +
- + err = clk_prepare_enable(data->core_clk);
- + if (err) {
- + pr_err("%s: fail to enable core_clk\n", __func__);
- + return -EPERM;
- + }
- +
- + err = clk_prepare_enable(data->iface_clk);
- + if (err) {
- + pr_err("%s: fail to enable iface_clk\n", __func__);
- + clk_disable_unprepare(data->core_clk);
- + return -ENOENT;
- + }
- +
- + data->clk_enabled = 1;
- +
- + return 0;
- +}
- +
- +static int gfspi_ioctl_clk_disable(struct gf_dev *data)
- +{
- + pr_debug("%s: enter\n", __func__);
- +
- + if (!data->clk_enabled)
- + return 0;
- +
- + clk_disable_unprepare(data->core_clk);
- + clk_disable_unprepare(data->iface_clk);
- + data->clk_enabled = 0;
- +
- + return 0;
- +}
- +
- +static int gfspi_ioctl_clk_uninit(struct gf_dev *data)
- +{
- + pr_debug("%s: enter\n", __func__);
- +
- + if (data->clk_enabled)
- + gfspi_ioctl_clk_disable(data);
- +
- + if (!IS_ERR_OR_NULL(data->core_clk)) {
- + clk_put(data->core_clk);
- + data->core_clk = NULL;
- + }
- +
- + if (!IS_ERR_OR_NULL(data->iface_clk)) {
- + clk_put(data->iface_clk);
- + data->iface_clk = NULL;
- + }
- +
- + return 0;
- +}
- +#endif
- +
- +static void nav_event_input(struct gf_dev *gf_dev, gf_nav_event_t nav_event)
- +{
- + uint32_t nav_input = 0;
- +
- + switch (nav_event) {
- + case GF_NAV_FINGER_DOWN:
- + pr_debug("%s nav finger down\n", __func__);
- + break;
- +
- + case GF_NAV_FINGER_UP:
- + pr_debug("%s nav finger up\n", __func__);
- + break;
- +
- + case GF_NAV_DOWN:
- + nav_input = GF_NAV_INPUT_DOWN;
- + pr_debug("%s nav down\n", __func__);
- + break;
- +
- + case GF_NAV_UP:
- + nav_input = GF_NAV_INPUT_UP;
- + pr_debug("%s nav up\n", __func__);
- + break;
- +
- + case GF_NAV_LEFT:
- + nav_input = GF_NAV_INPUT_LEFT;
- + pr_debug("%s nav left\n", __func__);
- + break;
- +
- + case GF_NAV_RIGHT:
- + nav_input = GF_NAV_INPUT_RIGHT;
- + pr_debug("%s nav right\n", __func__);
- + break;
- +
- + case GF_NAV_CLICK:
- + nav_input = GF_NAV_INPUT_CLICK;
- + pr_debug("%s nav click\n", __func__);
- + break;
- +
- + case GF_NAV_HEAVY:
- + nav_input = GF_NAV_INPUT_HEAVY;
- + pr_debug("%s nav heavy\n", __func__);
- + break;
- +
- + case GF_NAV_LONG_PRESS:
- + nav_input = GF_NAV_INPUT_LONG_PRESS;
- + pr_debug("%s nav long press\n", __func__);
- + break;
- +
- + case GF_NAV_DOUBLE_CLICK:
- + nav_input = GF_NAV_INPUT_DOUBLE_CLICK;
- + pr_debug("%s nav double click\n", __func__);
- + break;
- +
- + default:
- + pr_warn("%s unknown nav event: %d\n", __func__, nav_event);
- + break;
- + }
- +
- + if ((nav_event != GF_NAV_FINGER_DOWN) && (nav_event != GF_NAV_FINGER_UP)) {
- + input_report_key(gf_dev->input, nav_input, 1);
- + input_sync(gf_dev->input);
- + input_report_key(gf_dev->input, nav_input, 0);
- + input_sync(gf_dev->input);
- + }
- +}
- +
- +
- +static void gf_kernel_key_input(struct gf_dev *gf_dev, struct gf_key *gf_key)
- +{
- + uint32_t key_input = 0;
- +
- + if (GF_KEY_HOME == gf_key->key) {
- + key_input = GF_KEY_INPUT_HOME;
- + } else if (GF_KEY_POWER == gf_key->key) {
- + key_input = GF_KEY_INPUT_POWER;
- + } else if (GF_KEY_CAMERA == gf_key->key) {
- + key_input = GF_KEY_INPUT_CAMERA;
- + } else {
- + /* add special key define */
- + key_input = gf_key->key;
- + }
- + pr_debug("%s: received key event[%d], key=%d, value=%d\n",
- + __func__, key_input, gf_key->key, gf_key->value);
- +
- + if ((GF_KEY_POWER == gf_key->key || GF_KEY_CAMERA == gf_key->key)
- + && (gf_key->value == 1)) {
- + input_report_key(gf_dev->input, key_input, 1);
- + input_sync(gf_dev->input);
- + input_report_key(gf_dev->input, key_input, 0);
- + input_sync(gf_dev->input);
- + }
- +
- + if (GF_KEY_HOME == gf_key->key) {
- + input_report_key(gf_dev->input, key_input, gf_key->value);
- + input_sync(gf_dev->input);
- + }
- +}
- +
- +static long gf_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
- +{
- + struct gf_dev *gf_dev = &gf;
- + struct gf_key gf_key;
- +#if defined(SUPPORT_NAV_EVENT)
- + gf_nav_event_t nav_event = GF_NAV_NONE;
- +#endif
- + int retval = 0;
- + u8 netlink_route = NETLINK_TEST;
- + struct gf_ioc_chip_info info;
- +
- + if (_IOC_TYPE(cmd) != GF_IOC_MAGIC)
- + return -ENODEV;
- +
- + if (_IOC_DIR(cmd) & _IOC_READ)
- + retval = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd));
- + else if (_IOC_DIR(cmd) & _IOC_WRITE)
- + retval = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd));
- + if (retval)
- + return -EFAULT;
- +
- + if (gf_dev->device_available == 0) {
- + if ((cmd == GF_IOC_ENABLE_POWER) || (cmd == GF_IOC_DISABLE_POWER)) {
- + pr_debug("power cmd\n");
- + } else {
- + pr_debug("Sensor is power off currently.\n");
- + return -ENODEV;
- + }
- + }
- +
- + switch (cmd) {
- + case GF_IOC_INIT:
- + pr_debug("%s GF_IOC_INIT\n", __func__);
- + if (copy_to_user((void __user *)arg, (void *)&netlink_route, sizeof(u8))) {
- + retval = -EFAULT;
- + break;
- + }
- + break;
- + case GF_IOC_EXIT:
- + pr_debug("%s GF_IOC_EXIT\n", __func__);
- + break;
- + case GF_IOC_DISABLE_IRQ:
- + pr_debug("%s GF_IOC_DISABEL_IRQ\n", __func__);
- + gf_disable_irq(gf_dev);
- + break;
- + case GF_IOC_ENABLE_IRQ:
- + pr_debug("%s GF_IOC_ENABLE_IRQ\n", __func__);
- + gf_enable_irq(gf_dev);
- + break;
- + case GF_IOC_RESET:
- + pr_debug("%s GF_IOC_RESET.\n", __func__);
- + gf_hw_reset(gf_dev, 3);
- + break;
- + case GF_IOC_INPUT_KEY_EVENT:
- + if (copy_from_user(&gf_key, (struct gf_key *)arg, sizeof(struct gf_key))) {
- + pr_debug("Failed to copy input key event from user to kernel\n");
- + retval = -EFAULT;
- + break;
- + }
- +
- + gf_kernel_key_input(gf_dev, &gf_key);
- + break;
- +#if defined(SUPPORT_NAV_EVENT)
- + case GF_IOC_NAV_EVENT:
- + pr_debug("%s GF_IOC_NAV_EVENT\n", __func__);
- + if (copy_from_user(&nav_event, (gf_nav_event_t *)arg, sizeof(gf_nav_event_t))) {
- + pr_debug("Failed to copy nav event from user to kernel\n");
- + retval = -EFAULT;
- + break;
- + }
- +
- + nav_event_input(gf_dev, nav_event);
- + break;
- +#endif
- +
- + case GF_IOC_ENABLE_SPI_CLK:
- + pr_debug("%s GF_IOC_ENABLE_SPI_CLK\n", __func__);
- +#ifdef AP_CONTROL_CLK
- + gfspi_ioctl_clk_enable(gf_dev);
- +#else
- + pr_debug("Doesn't support control clock.\n");
- +#endif
- + break;
- + case GF_IOC_DISABLE_SPI_CLK:
- + pr_debug("%s GF_IOC_DISABLE_SPI_CLK\n", __func__);
- +#ifdef AP_CONTROL_CLK
- + gfspi_ioctl_clk_disable(gf_dev);
- +#else
- + pr_debug("Doesn't support control clock\n");
- +#endif
- + break;
- + case GF_IOC_ENABLE_POWER:
- + pr_debug("%s GF_IOC_ENABLE_POWER\n", __func__);
- + if (gf_dev->device_available == 1)
- + pr_debug("Sensor has already powered-on.\n");
- + else
- + gf_power_on(gf_dev);
- + gf_dev->device_available = 1;
- + break;
- + case GF_IOC_DISABLE_POWER:
- + pr_debug("%s GF_IOC_DISABLE_POWER\n", __func__);
- + if (gf_dev->device_available == 0)
- + pr_debug("Sensor has already powered-off.\n");
- + else
- + gf_power_off(gf_dev);
- + gf_dev->device_available = 0;
- + break;
- + case GF_IOC_ENTER_SLEEP_MODE:
- + pr_debug("%s GF_IOC_ENTER_SLEEP_MODE\n", __func__);
- + break;
- + case GF_IOC_GET_FW_INFO:
- + pr_debug("%s GF_IOC_GET_FW_INFO\n", __func__);
- + break;
- + case GF_IOC_REMOVE:
- + pr_debug("%s GF_IOC_REMOVE\n", __func__);
- + break;
- + case GF_IOC_CHIP_INFO:
- + pr_debug("%s GF_IOC_CHIP_INFO\n", __func__);
- + if (copy_from_user(&info, (struct gf_ioc_chip_info *)arg, sizeof(struct gf_ioc_chip_info))) {
- + retval = -EFAULT;
- + break;
- + }
- + pr_debug("vendor_id : 0x%x\n", info.vendor_id);
- + pr_debug("mode : 0x%x\n", info.mode);
- + pr_debug("operation: 0x%x\n", info.operation);
- + break;
- + default:
- + pr_warn("unsupport cmd:0x%x\n", cmd);
- + break;
- + }
- +
- + return retval;
- +}
- +
- +#ifdef CONFIG_COMPAT
- +static long gf_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
- +{
- + return gf_ioctl(filp, cmd, (unsigned long)compat_ptr(arg));
- +}
- +#endif /*CONFIG_COMPAT*/
- +
- +static irqreturn_t gf_irq(int irq, void *handle)
- +{
- +#if defined(GF_NETLINK_ENABLE)
- + char temp[4] = { 0x0 };
- + temp[0] = GF_NET_EVENT_IRQ;
- + wake_lock_timeout(&fp_wakelock, msecs_to_jiffies(2*1000));
- + sendnlmsg(temp);
- +#elif defined (GF_FASYNC)
- + struct gf_dev *gf_dev = &gf;
- +
- + if (gf_dev->async)
- + kill_fasync(&gf_dev->async, SIGIO, POLL_IN);
- +#endif
- +
- + return IRQ_HANDLED;
- +}
- +
- +static int gf_open(struct inode *inode, struct file *filp)
- +{
- + struct gf_dev *gf_dev;
- + int status = -ENXIO;
- + int rc = 0;
- +
- + mutex_lock(&device_list_lock);
- +
- + list_for_each_entry(gf_dev, &device_list, device_entry) {
- + if (gf_dev->devt == inode->i_rdev) {
- + pr_debug("Found\n");
- + status = 0;
- + break;
- + }
- + }
- +
- + if (status == 0) {
- + if (status == 0) {
- + rc = gpio_request(gf_dev->reset_gpio, "goodix_reset");
- + if (rc) {
- + dev_err(&gf_dev->spi->dev, "Failed to request RESET GPIO. rc = %d\n", rc);
- + mutex_unlock(&device_list_lock);
- + return -EPERM;
- + }
- +
- + gpio_direction_output(gf_dev->reset_gpio, 1);
- +
- + rc = gpio_request(gf_dev->irq_gpio, "goodix_irq");
- + if (rc) {
- + dev_err(&gf_dev->spi->dev, "Failed to request IRQ GPIO. rc = %d\n", rc);
- + mutex_unlock(&device_list_lock);
- + return -EPERM;
- + }
- + gpio_direction_input(gf_dev->irq_gpio);
- +
- + rc = request_threaded_irq(gf_dev->irq, NULL, gf_irq,
- + IRQF_TRIGGER_RISING | IRQF_ONESHOT,
- + "gf", gf_dev);
- +
- + if (!rc) {
- + enable_irq_wake(gf_dev->irq);
- + gf_dev->irq_enabled = 1;
- + gf_disable_irq(gf_dev);
- + }
- +
- + gf_dev->users++;
- + filp->private_data = gf_dev;
- + nonseekable_open(inode, filp);
- + pr_debug("Succeed to open device. irq = %d\n",
- + gf_dev->irq);
- + if (gf_dev->users == 1)
- + gf_enable_irq(gf_dev);
- + gf_hw_reset(gf_dev, 3);
- + gf_dev->device_available = 1;
- + }
- + } else {
- + pr_debug("No device for minor %d\n", iminor(inode));
- + }
- + mutex_unlock(&device_list_lock);
- + return status;
- +}
- +
- +#ifdef GF_FASYNC
- +static int gf_fasync(int fd, struct file *filp, int mode)
- +{
- + struct gf_dev *gf_dev = filp->private_data;
- + int ret;
- +
- + ret = fasync_helper(fd, filp, mode, &gf_dev->async);
- + pr_debug("ret = %d\n", ret);
- + return ret;
- +}
- +#endif
- +
- +static int gf_release(struct inode *inode, struct file *filp)
- +{
- + struct gf_dev *gf_dev;
- + int status = 0;
- +
- + mutex_lock(&device_list_lock);
- + gf_dev = filp->private_data;
- + filp->private_data = NULL;
- +
- + /*last close?? */
- + gf_dev->users--;
- + if (!gf_dev->users) {
- + pr_debug("disble_irq. irq = %d\n", gf_dev->irq);
- + gf_disable_irq(gf_dev);
- + /*power off the sensor*/
- + gf_dev->device_available = 0;
- + free_irq(gf_dev->irq, gf_dev);
- + gpio_free(gf_dev->irq_gpio);
- + gpio_free(gf_dev->reset_gpio);
- + gf_power_off(gf_dev);
- + }
- + mutex_unlock(&device_list_lock);
- + return status;
- +}
- +
- +static const struct file_operations gf_fops = {
- + .owner = THIS_MODULE,
- + /* REVISIT switch to aio primitives, so that userspace
- + * gets more complete API coverage. It'll simplify things
- + * too, except for the locking.
- + */
- + .unlocked_ioctl = gf_ioctl,
- +#ifdef CONFIG_COMPAT
- + .compat_ioctl = gf_compat_ioctl,
- +#endif /*CONFIG_COMPAT*/
- + .open = gf_open,
- + .release = gf_release,
- +#ifdef GF_FASYNC
- + .fasync = gf_fasync,
- +#endif
- +};
- +
- +static int goodix_fb_state_chg_callback(struct notifier_block *nb,
- + unsigned long val, void *data)
- +{
- + struct gf_dev *gf_dev;
- + struct fb_event *evdata = data;
- + unsigned int blank;
- + char temp[4] = { 0x0 };
- +
- + if (val != FB_EVENT_BLANK)
- + return 0;
- + pr_debug("[info] %s go to the goodix_fb_state_chg_callback value = %d\n",
- + __func__, (int)val);
- + gf_dev = container_of(nb, struct gf_dev, notifier);
- + if (evdata && evdata->data && val == FB_EVENT_BLANK && gf_dev) {
- + blank = *(int *)(evdata->data);
- + switch (blank) {
- + case FB_BLANK_POWERDOWN:
- + if (gf_dev->device_available == 1) {
- + gf_dev->fb_black = 1;
- +#if defined(GF_NETLINK_ENABLE)
- + temp[0] = GF_NET_EVENT_FB_BLACK;
- + sendnlmsg(temp);
- +#elif defined (GF_FASYNC)
- + if (gf_dev->async) {
- + kill_fasync(&gf_dev->async, SIGIO, POLL_IN);
- + }
- +#endif
- + }
- + break;
- + case FB_BLANK_UNBLANK:
- + if (gf_dev->device_available == 1) {
- + gf_dev->fb_black = 0;
- +#if defined(GF_NETLINK_ENABLE)
- + temp[0] = GF_NET_EVENT_FB_UNBLACK;
- + sendnlmsg(temp);
- +#elif defined (GF_FASYNC)
- + if (gf_dev->async) {
- + kill_fasync(&gf_dev->async, SIGIO, POLL_IN);
- + }
- +#endif
- + }
- + break;
- + default:
- + pr_debug("%s defalut\n", __func__);
- + break;
- + }
- + }
- + return NOTIFY_OK;
- +}
- +
- +static struct notifier_block goodix_noti_block = {
- + .notifier_call = goodix_fb_state_chg_callback,
- +};
- +
- +static struct class *gf_class;
- +#if defined(USE_SPI_BUS)
- +static int gf_probe(struct spi_device *spi)
- +#elif defined(USE_PLATFORM_BUS)
- +static int gf_probe(struct platform_device *pdev)
- +#endif
- +{
- + struct gf_dev *gf_dev = &gf;
- + int status = -EINVAL;
- + unsigned long minor;
- + int i;
- +
- + /* Initialize the driver data */
- + INIT_LIST_HEAD(&gf_dev->device_entry);
- +#if defined(USE_SPI_BUS)
- + gf_dev->spi = spi;
- +#elif defined(USE_PLATFORM_BUS)
- + gf_dev->spi = pdev;
- +#endif
- + gf_dev->irq_gpio = -EINVAL;
- + gf_dev->reset_gpio = -EINVAL;
- + gf_dev->pwr_gpio = -EINVAL;
- + gf_dev->device_available = 0;
- + gf_dev->fb_black = 0;
- +
- + if (gf_parse_dts(gf_dev))
- + goto error_hw;
- +
- + /* If we can allocate a minor number, hook up this device.
- + * Reusing minors is fine so long as udev or mdev is working.
- + */
- + mutex_lock(&device_list_lock);
- + minor = find_first_zero_bit(minors, N_SPI_MINORS);
- + if (minor < N_SPI_MINORS) {
- + struct device *dev;
- +
- + gf_dev->devt = MKDEV(SPIDEV_MAJOR, minor);
- + dev = device_create(gf_class, &gf_dev->spi->dev, gf_dev->devt,
- + gf_dev, GF_DEV_NAME);
- + status = IS_ERR(dev) ? PTR_ERR(dev) : 0;
- + } else {
- + dev_dbg(&gf_dev->spi->dev, "no minor number available!\n");
- + status = -ENODEV;
- + mutex_unlock(&device_list_lock);
- + goto error_hw;
- + }
- +
- + if (status == 0) {
- + set_bit(minor, minors);
- + list_add(&gf_dev->device_entry, &device_list);
- + } else {
- + gf_dev->devt = 0;
- + }
- + mutex_unlock(&device_list_lock);
- +
- + if (status == 0) {
- + /*input device subsystem */
- + gf_dev->input = input_allocate_device();
- + if (gf_dev->input == NULL) {
- + pr_err("%s, failed to allocate input device\n", __func__);
- + status = -ENOMEM;
- + goto error_dev;
- + }
- + for (i = 0; i < ARRAY_SIZE(maps); i++)
- + input_set_capability(gf_dev->input, maps[i].type, maps[i].code);
- +
- + gf_dev->input->name = GF_INPUT_NAME;
- + status = input_register_device(gf_dev->input);
- + if (status) {
- + pr_err("failed to register input device\n");
- + goto error_input;
- + }
- + }
- +#ifdef AP_CONTROL_CLK
- + pr_debug("Get the clk resource.\n");
- + /* Enable spi clock */
- + if (gfspi_ioctl_clk_init(gf_dev))
- + goto gfspi_probe_clk_init_failed;
- +
- + if (gfspi_ioctl_clk_enable(gf_dev))
- + goto gfspi_probe_clk_enable_failed;
- +
- + spi_clock_set(gf_dev, 1000000);
- +#endif
- +
- + gf_dev->notifier = goodix_noti_block;
- + fb_register_client(&gf_dev->notifier);
- +
- + gf_dev->irq = gf_irq_num(gf_dev);
- +
- + wake_lock_init(&fp_wakelock, WAKE_LOCK_SUSPEND, "fp_wakelock");
- + pr_debug("version V%d.%d.%02d\n", VER_MAJOR, VER_MINOR, PATCH_LEVEL);
- +
- + return status;
- +
- +#ifdef AP_CONTROL_CLK
- +gfspi_probe_clk_enable_failed:
- + gfspi_ioctl_clk_uninit(gf_dev);
- +gfspi_probe_clk_init_failed:
- +#endif
- + input_unregister_device(gf_dev->input);
- +error_input:
- + if (gf_dev->input != NULL)
- + input_free_device(gf_dev->input);
- +error_dev:
- + if (gf_dev->devt != 0) {
- + pr_debug("Err: status = %d\n", status);
- + mutex_lock(&device_list_lock);
- + list_del(&gf_dev->device_entry);
- + device_destroy(gf_class, gf_dev->devt);
- + clear_bit(MINOR(gf_dev->devt), minors);
- + mutex_unlock(&device_list_lock);
- + }
- +error_hw:
- + gf_cleanup(gf_dev);
- + gf_dev->device_available = 0;
- +
- + return status;
- +}
- +
- +#if defined(USE_SPI_BUS)
- +static int gf_remove(struct spi_device *spi)
- +#elif defined(USE_PLATFORM_BUS)
- +static int gf_remove(struct platform_device *pdev)
- +#endif
- +{
- + struct gf_dev *gf_dev = &gf;
- +
- + wake_lock_destroy(&fp_wakelock);
- + /* make sure ops on existing fds can abort cleanly */
- + if (gf_dev->irq)
- + free_irq(gf_dev->irq, gf_dev);
- +
- + if (gf_dev->input != NULL)
- + input_unregister_device(gf_dev->input);
- + input_free_device(gf_dev->input);
- +
- + /* prevent new opens */
- + mutex_lock(&device_list_lock);
- + list_del(&gf_dev->device_entry);
- + device_destroy(gf_class, gf_dev->devt);
- + clear_bit(MINOR(gf_dev->devt), minors);
- + if (gf_dev->users == 0)
- + gf_cleanup(gf_dev);
- +
- +
- + fb_unregister_client(&gf_dev->notifier);
- + mutex_unlock(&device_list_lock);
- +
- + return 0;
- +}
- +
- +static struct of_device_id gx_match_table[] = {
- + { .compatible = GF_SPIDEV_NAME },
- + {},
- +};
- +
- +#if defined(USE_SPI_BUS)
- +static struct spi_driver gf_driver = {
- +#elif defined(USE_PLATFORM_BUS)
- +static struct platform_driver gf_driver = {
- +#endif
- + .driver = {
- + .name = GF_DEV_NAME,
- + .owner = THIS_MODULE,
- + .of_match_table = gx_match_table,
- + },
- + .probe = gf_probe,
- + .remove = gf_remove,
- +};
- +
- +static int __init gf_init(void)
- +{
- + int status;
- +
- + /* Claim our 256 reserved device numbers. Then register a class
- + * that will key udev/mdev to add/remove /dev nodes. Last, register
- + * the driver which manages those device numbers.
- + */
- +
- + BUILD_BUG_ON(N_SPI_MINORS > 256);
- + status = register_chrdev(SPIDEV_MAJOR, CHRD_DRIVER_NAME, &gf_fops);
- + if (status < 0) {
- + pr_warn("Failed to register char device!\n");
- + return status;
- + }
- + SPIDEV_MAJOR = status;
- + gf_class = class_create(THIS_MODULE, CLASS_NAME);
- + if (IS_ERR(gf_class)) {
- + unregister_chrdev(SPIDEV_MAJOR, gf_driver.driver.name);
- + pr_warn("Failed to create class.\n");
- + return PTR_ERR(gf_class);
- + }
- +#if defined(USE_PLATFORM_BUS)
- + status = platform_driver_register(&gf_driver);
- +#elif defined(USE_SPI_BUS)
- + status = spi_register_driver(&gf_driver);
- +#endif
- + if (status < 0) {
- + class_destroy(gf_class);
- + unregister_chrdev(SPIDEV_MAJOR, gf_driver.driver.name);
- + pr_warn("Failed to register SPI driver.\n");
- + }
- +
- +#ifdef GF_NETLINK_ENABLE
- + netlink_init();
- +#endif
- + pr_debug("status = 0x%x\n", status);
- + return 0;
- +}
- +module_init(gf_init);
- +
- +static void __exit gf_exit(void)
- +{
- +#ifdef GF_NETLINK_ENABLE
- + netlink_exit();
- +#endif
- +#if defined(USE_PLATFORM_BUS)
- + platform_driver_unregister(&gf_driver);
- +#elif defined(USE_SPI_BUS)
- + spi_unregister_driver(&gf_driver);
- +#endif
- + class_destroy(gf_class);
- + unregister_chrdev(SPIDEV_MAJOR, gf_driver.driver.name);
- +}
- +module_exit(gf_exit);
- +
- +MODULE_AUTHOR("Jiangtao Yi, <yijiangtao@goodix.com>");
- +MODULE_AUTHOR("Jandy Gou, <gouqingsong@goodix.com>");
- +MODULE_DESCRIPTION("goodix fingerprint sensor device driver");
- +MODULE_LICENSE("GPL");
- diff --git a/drivers/input/fingerprint/goodix_ta/gf_spi.h b/drivers/input/fingerprint/goodix_ta/gf_spi.h
- new file mode 100644
- index 0000000..207e385
- --- /dev/null
- +++ b/drivers/input/fingerprint/goodix_ta/gf_spi.h
- @@ -0,0 +1,155 @@
- +/*
- + * driver definition for sensor driver
- + *
- + * Coypright (c) 2017 Goodix
- + * Copyright (C) 2017 XiaoMi, Inc.
- + */
- +#ifndef __GF_SPI_H
- +#define __GF_SPI_H
- +
- +#include <linux/types.h>
- +#include <linux/notifier.h>
- +/**********************************************************/
- +enum FP_MODE{
- + GF_IMAGE_MODE = 0,
- + GF_KEY_MODE,
- + GF_SLEEP_MODE,
- + GF_FF_MODE,
- + GF_DEBUG_MODE = 0x56
- +};
- +
- +#define SUPPORT_NAV_EVENT
- +
- +#if defined(SUPPORT_NAV_EVENT)
- +#define GF_NAV_INPUT_UP KEY_UP
- +#define GF_NAV_INPUT_DOWN KEY_DOWN
- +#define GF_NAV_INPUT_LEFT KEY_LEFT
- +#define GF_NAV_INPUT_RIGHT KEY_RIGHT
- +#define GF_NAV_INPUT_CLICK KEY_VOLUMEDOWN
- +#define GF_NAV_INPUT_DOUBLE_CLICK KEY_VOLUMEUP
- +#define GF_NAV_INPUT_LONG_PRESS KEY_SEARCH
- +#define GF_NAV_INPUT_HEAVY KEY_CHAT
- +#endif
- +
- +#define GF_KEY_INPUT_HOME KEY_HOME
- +#define GF_KEY_INPUT_MENU KEY_MENU
- +#define GF_KEY_INPUT_BACK KEY_BACK
- +#define GF_KEY_INPUT_POWER KEY_POWER
- +#define GF_KEY_INPUT_CAMERA KEY_CAMERA
- +
- +#if defined(SUPPORT_NAV_EVENT)
- +typedef enum gf_nav_event {
- + GF_NAV_NONE = 0,
- + GF_NAV_FINGER_UP,
- + GF_NAV_FINGER_DOWN,
- + GF_NAV_UP,
- + GF_NAV_DOWN,
- + GF_NAV_LEFT,
- + GF_NAV_RIGHT,
- + GF_NAV_CLICK,
- + GF_NAV_HEAVY,
- + GF_NAV_LONG_PRESS,
- + GF_NAV_DOUBLE_CLICK,
- +} gf_nav_event_t;
- +#endif
- +
- +typedef enum gf_key_event {
- + GF_KEY_NONE = 0,
- + GF_KEY_HOME,
- + GF_KEY_POWER,
- + GF_KEY_MENU,
- + GF_KEY_BACK,
- + GF_KEY_CAMERA,
- +} gf_key_event_t;
- +
- +struct gf_key {
- + enum gf_key_event key;
- + uint32_t value; /* key down = 1, key up = 0 */
- +};
- +
- +struct gf_key_map {
- + unsigned int type;
- + unsigned int code;
- +};
- +
- +struct gf_ioc_chip_info {
- + unsigned char vendor_id;
- + unsigned char mode;
- + unsigned char operation;
- + unsigned char reserved[5];
- +};
- +
- +#define GF_IOC_MAGIC 'g' /*define magic number*/
- +#define GF_IOC_INIT _IOR(GF_IOC_MAGIC, 0, uint8_t)
- +#define GF_IOC_EXIT _IO(GF_IOC_MAGIC, 1)
- +#define GF_IOC_RESET _IO(GF_IOC_MAGIC, 2)
- +#define GF_IOC_ENABLE_IRQ _IO(GF_IOC_MAGIC, 3)
- +#define GF_IOC_DISABLE_IRQ _IO(GF_IOC_MAGIC, 4)
- +#define GF_IOC_ENABLE_SPI_CLK _IOW(GF_IOC_MAGIC, 5, uint32_t)
- +#define GF_IOC_DISABLE_SPI_CLK _IO(GF_IOC_MAGIC, 6)
- +#define GF_IOC_ENABLE_POWER _IO(GF_IOC_MAGIC, 7)
- +#define GF_IOC_DISABLE_POWER _IO(GF_IOC_MAGIC, 8)
- +#define GF_IOC_INPUT_KEY_EVENT _IOW(GF_IOC_MAGIC, 9, struct gf_key)
- +#define GF_IOC_ENTER_SLEEP_MODE _IO(GF_IOC_MAGIC, 10)
- +#define GF_IOC_GET_FW_INFO _IOR(GF_IOC_MAGIC, 11, uint8_t)
- +#define GF_IOC_REMOVE _IO(GF_IOC_MAGIC, 12)
- +#define GF_IOC_CHIP_INFO _IOW(GF_IOC_MAGIC, 13, struct gf_ioc_chip_info)
- +
- +#if defined(SUPPORT_NAV_EVENT)
- +#define GF_IOC_NAV_EVENT _IOW(GF_IOC_MAGIC, 14, gf_nav_event_t)
- +#define GF_IOC_MAXNR 15 /* THIS MACRO IS NOT USED NOW... */
- +#else
- +#define GF_IOC_MAXNR 14 /* THIS MACRO IS NOT USED NOW... */
- +#endif
- +
- +/*#define AP_CONTROL_CLK 1*/
- +#define USE_PLATFORM_BUS 1
- +/*#define USE_SPI_BUS 1*/
- +/*#define GF_FASYNC 1*//*If support fasync mechanism.*/
- +#define GF_NETLINK_ENABLE 1
- +#define GF_NET_EVENT_IRQ 1
- +#define GF_NET_EVENT_FB_BLACK 2
- +#define GF_NET_EVENT_FB_UNBLACK 3
- +#define NETLINK_TEST 25
- +
- +struct gf_dev {
- + dev_t devt;
- + struct list_head device_entry;
- +#if defined(USE_SPI_BUS)
- + struct spi_device *spi;
- +#elif defined(USE_PLATFORM_BUS)
- + struct platform_device *spi;
- +#endif
- + struct clk *core_clk;
- + struct clk *iface_clk;
- +
- + struct input_dev *input;
- + /* buffer is NULL unless this device is open (users > 0) */
- + unsigned users;
- + signed irq_gpio;
- + signed reset_gpio;
- + signed pwr_gpio;
- + int irq;
- + int irq_enabled;
- + int clk_enabled;
- +#ifdef GF_FASYNC
- + struct fasync_struct *async;
- +#endif
- + struct notifier_block notifier;
- + char device_available;
- + char fb_black;
- +};
- +
- +int gf_parse_dts(struct gf_dev *gf_dev);
- +void gf_cleanup(struct gf_dev *gf_dev);
- +
- +int gf_power_on(struct gf_dev *gf_dev);
- +int gf_power_off(struct gf_dev *gf_dev);
- +
- +int gf_hw_reset(struct gf_dev *gf_dev, unsigned int delay_ms);
- +int gf_irq_num(struct gf_dev *gf_dev);
- +
- +void sendnlmsg(char *message);
- +int netlink_init(void);
- +void netlink_exit(void);
- +#endif /*__GF_SPI_H*/
- diff --git a/drivers/input/fingerprint/goodix_ta/netlink.c b/drivers/input/fingerprint/goodix_ta/netlink.c
- new file mode 100644
- index 0000000..9e96fa8
- --- /dev/null
- +++ b/drivers/input/fingerprint/goodix_ta/netlink.c
- @@ -0,0 +1,98 @@
- +/*
- + * netlink interface
- + *
- + * Copyright (c) 2017 Goodix
- + * Copyright (C) 2017 XiaoMi, Inc.
- + */
- +#include <linux/init.h>
- +#include <linux/module.h>
- +#include <linux/timer.h>
- +#include <linux/time.h>
- +#include <linux/types.h>
- +#include <net/sock.h>
- +#include <net/netlink.h>
- +
- +#define NETLINK_TEST 25
- +#define MAX_MSGSIZE 32
- +int stringlength(char *s);
- +void sendnlmsg(char *message);
- +static int pid = -1;
- +struct sock *nl_sk = NULL;
- +
- +void sendnlmsg(char *message)
- +{
- + struct sk_buff *skb_1;
- + struct nlmsghdr *nlh;
- + int len = NLMSG_SPACE(MAX_MSGSIZE);
- + int slen = 0;
- + int ret = 0;
- + if (!message || !nl_sk || !pid) {
- + return;
- + }
- + skb_1 = alloc_skb(len, GFP_KERNEL);
- + if (!skb_1) {
- + pr_err("alloc_skb error\n");
- + return;
- + }
- + slen = strlen(message);
- + nlh = nlmsg_put(skb_1, 0, 0, 0, MAX_MSGSIZE, 0);
- +
- + NETLINK_CB(skb_1).portid = 0;
- + NETLINK_CB(skb_1).dst_group = 0;
- +
- + message[slen] = '\0';
- + memcpy(NLMSG_DATA(nlh), message, slen+1);
- +
- + ret = netlink_unicast(nl_sk, skb_1, pid, MSG_DONTWAIT);
- + if (!ret) {
- + /*kfree_skb(skb_1);*/
- + pr_err("send msg from kernel to usespace failed ret 0x%x\n", ret);
- + }
- +
- +}
- +
- +
- +void nl_data_ready(struct sk_buff *__skb)
- +{
- + struct sk_buff *skb;
- + struct nlmsghdr *nlh;
- + char str[100];
- + skb = skb_get (__skb);
- + if (skb->len >= NLMSG_SPACE(0)) {
- + nlh = nlmsg_hdr(skb);
- + memcpy(str, NLMSG_DATA(nlh), sizeof(str));
- + pid = nlh->nlmsg_pid;
- + kfree_skb(skb);
- + }
- +}
- +
- +
- +int netlink_init(void)
- +{
- + struct netlink_kernel_cfg netlink_cfg;
- + memset(&netlink_cfg, 0, sizeof(struct netlink_kernel_cfg));
- +
- + netlink_cfg.groups = 0;
- + netlink_cfg.flags = 0;
- + netlink_cfg.input = nl_data_ready;
- + netlink_cfg.cb_mutex = NULL;
- +
- + nl_sk = netlink_kernel_create(&init_net, NETLINK_TEST,
- + &netlink_cfg);
- +
- + if (!nl_sk) {
- + pr_err("create netlink socket error\n");
- + return 1;
- + }
- + return 0;
- +}
- +
- +void netlink_exit(void)
- +{
- + if (nl_sk != NULL) {
- + netlink_kernel_release(nl_sk);
- + nl_sk = NULL;
- + }
- + pr_info("self module exited\n");
- +}
- +
- diff --git a/drivers/input/fingerprint/goodix_ta/platform.c b/drivers/input/fingerprint/goodix_ta/platform.c
- new file mode 100644
- index 0000000..3ac2965
- --- /dev/null
- +++ b/drivers/input/fingerprint/goodix_ta/platform.c
- @@ -0,0 +1,98 @@
- +/*
- + * platform indepent driver interface
- + *
- + * Coypritht (c) 2017 Goodix
- + * Copyright (C) 2017 XiaoMi, Inc.
- + */
- +#include <linux/delay.h>
- +#include <linux/workqueue.h>
- +#include <linux/of_gpio.h>
- +#include <linux/gpio.h>
- +#include <linux/regulator/consumer.h>
- +#include <linux/timer.h>
- +#include <linux/err.h>
- +
- +#include "gf_spi.h"
- +
- +#if defined(USE_SPI_BUS)
- +#include <linux/spi/spi.h>
- +#include <linux/spi/spidev.h>
- +#elif defined(USE_PLATFORM_BUS)
- +#include <linux/platform_device.h>
- +#endif
- +
- +int gf_parse_dts(struct gf_dev *gf_dev)
- +{
- + /*get reset resource*/
- + gf_dev->reset_gpio = of_get_named_gpio(gf_dev->spi->dev.of_node, "fp-gpio-reset", 0);
- + if (!gpio_is_valid(gf_dev->reset_gpio)) {
- + pr_info("RESET GPIO is invalid.\n");
- + return -EPERM;
- + }
- +
- + /*get irq resourece*/
- + gf_dev->irq_gpio = of_get_named_gpio(gf_dev->spi->dev.of_node, "fp-gpio-irq", 0);
- + pr_info("gf::irq_gpio:%d\n", gf_dev->irq_gpio);
- + if (!gpio_is_valid(gf_dev->irq_gpio)) {
- + pr_info("IRQ GPIO is invalid.\n");
- + return -EPERM;
- + }
- +
- + return 0;
- +}
- +
- +void gf_cleanup(struct gf_dev *gf_dev)
- +{
- + pr_info("[info] %s\n", __func__);
- + if (gpio_is_valid(gf_dev->irq_gpio)) {
- + gpio_free(gf_dev->irq_gpio);
- + pr_info("remove irq_gpio success\n");
- + }
- + if (gpio_is_valid(gf_dev->reset_gpio)) {
- + gpio_free(gf_dev->reset_gpio);
- + pr_info("remove reset_gpio success\n");
- + }
- +}
- +
- +int gf_power_on(struct gf_dev *gf_dev)
- +{
- + int rc = 0;
- +
- + msleep(10);
- + pr_info("---- power on ok ----\n");
- +
- + return rc;
- +}
- +
- +int gf_power_off(struct gf_dev *gf_dev)
- +{
- + int rc = 0;
- +
- + pr_info("---- power off ----\n");
- + return rc;
- +}
- +
- +int gf_hw_reset(struct gf_dev *gf_dev, unsigned int delay_ms)
- +{
- + if (gf_dev == NULL) {
- + pr_info("Input buff is NULL.\n");
- + return -EPERM;
- + }
- + gpio_direction_output(gf_dev->reset_gpio, 0);
- + gpio_set_value(gf_dev->reset_gpio, 0);
- + mdelay(3);
- + gpio_set_value(gf_dev->reset_gpio, 1);
- + mdelay(delay_ms);
- + return 0;
- +}
- +
- +int gf_irq_num(struct gf_dev *gf_dev)
- +{
- + if (gf_dev == NULL) {
- + pr_info("Input buff is NULL.\n");
- + return -EPERM;
- + } else {
- + return gpio_to_irq(gf_dev->irq_gpio);
- + }
- +}
- +
- diff --git a/drivers/input/input.c b/drivers/input/input.c
- index baaddd1..b063ea1 100644
- --- a/drivers/input/input.c
- +++ b/drivers/input/input.c
- @@ -2,6 +2,7 @@
- * The input core
- *
- * Copyright (c) 1999-2002 Vojtech Pavlik
- + * Copyright (C) 2017 XiaoMi, Inc.
- */
- /*
- @@ -27,6 +28,9 @@
- #include <linux/device.h>
- #include <linux/mutex.h>
- #include <linux/rcupdate.h>
- +#ifdef CONFIG_LAST_TOUCH_EVENTS
- +#include <linux/rtc.h>
- +#endif
- #include "input-compat.h"
- MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
- @@ -50,6 +54,50 @@ static DEFINE_MUTEX(input_mutex);
- static const struct input_value input_value_sync = { EV_SYN, SYN_REPORT, 1 };
- +#ifdef CONFIG_LAST_TOUCH_EVENTS
- +static int input_device_is_touch(struct input_dev *input_dev)
- +{
- + unsigned long mask = BIT_MASK(BTN_TOUCH);
- + return ((input_dev->keybit[BIT_WORD(BTN_TOUCH)] & mask) == mask) ? true:false;
- +}
- +
- +static inline void touch_press_release_events_collect(struct input_dev *dev,
- + unsigned int type, unsigned int code, int value)
- +{
- + if (dev->touch_events) {
- + pr_debug("type %d, code %d, value %d\n", type, code, value);
- + if (code == ABS_MT_TRACKING_ID) {
- + if (value != -1 && !dev->touch_is_pressed) { /* Pressed */
- + getnstimeofday(&dev->latest_touch_event.press_time_stamp);
- + dev->touch_is_pressed = true;
- + }
- + } else if (code == BTN_TOUCH) {
- + if (value == 0 && dev->touch_is_pressed) { /* Released */
- + getnstimeofday(&dev->latest_touch_event.release_time_stamp);
- + dev->touch_events->touch_event_buf[dev->touch_events->touch_event_num] =
- + dev->latest_touch_event;
- + dev->touch_events->touch_event_num++;
- + if (dev->touch_events->touch_event_num >= TOUCH_EVENT_MAX)
- + dev->touch_events->touch_event_num = 0;
- + dev->latest_touch_event.press_pos_x = 0;
- + dev->latest_touch_event.press_pos_y = 0;
- + dev->touch_is_pressed = false;
- + }
- + } else if (code == ABS_MT_POSITION_X) {
- + if (!dev->latest_touch_event.press_pos_x && dev->touch_is_pressed) {
- + dev->latest_touch_event.press_pos_x = value;
- + }
- + dev->latest_touch_event.release_pos_x = value;
- + } else if (code == ABS_MT_POSITION_Y) {
- + if (!dev->latest_touch_event.press_pos_y && dev->touch_is_pressed) {
- + dev->latest_touch_event.press_pos_y = value;
- + }
- + dev->latest_touch_event.release_pos_y = value;
- + }
- + }
- +}
- +#endif
- +
- static inline int is_event_supported(unsigned int code,
- unsigned long *bm, unsigned int max)
- {
- @@ -436,6 +484,9 @@ void input_event(struct input_dev *dev,
- spin_lock_irqsave(&dev->event_lock, flags);
- input_handle_event(dev, type, code, value);
- spin_unlock_irqrestore(&dev->event_lock, flags);
- +#ifdef CONFIG_LAST_TOUCH_EVENTS
- + touch_press_release_events_collect(dev, type, code, value);
- +#endif
- }
- }
- EXPORT_SYMBOL(input_event);
- @@ -1261,6 +1312,59 @@ static const struct file_operations input_handlers_fileops = {
- .release = seq_release,
- };
- +#ifdef CONFIG_LAST_TOUCH_EVENTS
- +static int last_touch_events_show(struct seq_file *seq, void *v)
- +{
- + struct input_dev *dev = container_of(v, struct input_dev, node);
- + int i = 0;
- + struct rtc_time tm;
- +
- + if (!input_device_is_touch(dev) || !dev->touch_events)
- + return 0;
- +
- + seq_printf(seq, "Name=\"%s\"\n", dev->name ? dev->name : "");
- +
- + for (i = 0; i < TOUCH_EVENT_MAX; i++) {
- + if (dev->touch_events->touch_event_buf[i].release_pos_x == 0 &&
- + dev->touch_events->touch_event_buf[i].release_pos_y == 0)
- + continue;
- +
- + rtc_time_to_tm(dev->touch_events->touch_event_buf[i].press_time_stamp.tv_sec, &tm);
- + seq_printf(seq, "%d-%02d-%02d %02d:%02d:%02d.%09lu UTC Postion (%d, %d) pressed\n",
- + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
- + tm.tm_hour, tm.tm_min, tm.tm_sec, dev->touch_events->touch_event_buf[i].press_time_stamp.tv_nsec,
- + dev->touch_events->touch_event_buf[i].press_pos_x, dev->touch_events->touch_event_buf[i].press_pos_y);
- +
- + rtc_time_to_tm(dev->touch_events->touch_event_buf[i].release_time_stamp.tv_sec, &tm);
- + seq_printf(seq, "%d-%02d-%02d %02d:%02d:%02d.%09lu UTC Postion (%d, %d) released\n",
- + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
- + tm.tm_hour, tm.tm_min, tm.tm_sec, dev->touch_events->touch_event_buf[i].release_time_stamp.tv_nsec,
- + dev->touch_events->touch_event_buf[i].release_pos_x, dev->touch_events->touch_event_buf[i].release_pos_y);
- + }
- + return 0;
- +}
- +
- +static const struct seq_operations input_last_touch_events_seq_ops = {
- + .start = input_devices_seq_start,
- + .next = input_devices_seq_next,
- + .stop = input_seq_stop,
- + .show = last_touch_events_show,
- +};
- +
- +static int input_last_touch_events_open(struct inode *inode, struct file *file)
- +{
- + return seq_open(file, &input_last_touch_events_seq_ops);
- +}
- +
- +
- +static const struct file_operations input_last_touch_events_fileops = {
- + .open = input_last_touch_events_open,
- + .read = seq_read,
- + .llseek = seq_lseek,
- + .release = seq_release,
- +};
- +#endif
- +
- static int __init input_proc_init(void)
- {
- struct proc_dir_entry *entry;
- @@ -1278,8 +1382,17 @@ static int __init input_proc_init(void)
- &input_handlers_fileops);
- if (!entry)
- goto fail2;
- +#ifdef CONFIG_LAST_TOUCH_EVENTS
- + entry = proc_create("last_touch_events", 0, proc_bus_input_dir,
- + &input_last_touch_events_fileops);
- + if (!entry)
- + goto fail3;
- +#endif
- return 0;
- +#ifdef CONFIG_LAST_TOUCH_EVENTS
- + fail3: remove_proc_entry("handlers", proc_bus_input_dir);
- +#endif
- fail2: remove_proc_entry("devices", proc_bus_input_dir);
- fail1: remove_proc_entry("bus/input", NULL);
- @@ -1288,6 +1401,9 @@ static int __init input_proc_init(void)
- static void input_proc_exit(void)
- {
- +#ifdef CONFIG_LAST_TOUCH_EVENTS
- + remove_proc_entry("last_touch_events", proc_bus_input_dir);
- +#endif
- remove_proc_entry("devices", proc_bus_input_dir);
- remove_proc_entry("handlers", proc_bus_input_dir);
- remove_proc_entry("bus/input", NULL);
- @@ -2168,6 +2284,19 @@ int input_register_device(struct input_dev *dev)
- __func__, dev_name(&dev->dev));
- devres_add(dev->dev.parent, devres);
- }
- +
- +#ifdef CONFIG_LAST_TOUCH_EVENTS
- + if (input_device_is_touch(dev)) {
- + dev->touch_events = kzalloc(sizeof(struct touch_event_info), GFP_KERNEL);
- + if (dev->touch_events == NULL) {
- + pr_err("Touch event: alloc memory failed\n");
- + }
- +
- + dev->touch_is_pressed = false;
- + dev->latest_touch_event.press_pos_x = 0;
- + dev->latest_touch_event.press_pos_y = 0;
- + }
- +#endif
- return 0;
- err_device_del:
- @@ -2190,6 +2319,12 @@ EXPORT_SYMBOL(input_register_device);
- */
- void input_unregister_device(struct input_dev *dev)
- {
- +#ifdef CONFIG_LAST_TOUCH_EVENTS
- + if (dev->touch_events) {
- + kfree(dev->touch_events);
- + dev->touch_events = NULL;
- + }
- +#endif
- if (dev->devres_managed) {
- WARN_ON(devres_destroy(dev->dev.parent,
- devm_input_device_unregister,
- diff --git a/drivers/input/misc/qpnp-power-on.c b/drivers/input/misc/qpnp-power-on.c
- index 339f94c..d9fdb9a 100644
- --- a/drivers/input/misc/qpnp-power-on.c
- +++ b/drivers/input/misc/qpnp-power-on.c
- @@ -1,4 +1,5 @@
- /* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
- + * Copyright (C) 2017 XiaoMi, 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
- @@ -32,6 +33,7 @@
- #include <linux/regulator/of_regulator.h>
- #include <linux/input/qpnp-power-on.h>
- #include <linux/power_supply.h>
- +#include <linux/wakelock.h>
- #define PMIC_VER_8941 0x01
- #define PMIC_VERSION_REG 0x0105
- @@ -66,6 +68,7 @@
- ((pon)->base + PON_OFFSET((pon)->subtype, 0xA, 0xC2))
- #define QPNP_POFF_REASON1(pon) \
- ((pon)->base + PON_OFFSET((pon)->subtype, 0xC, 0xC5))
- +#define QPNP_POFF_REASON2(pon) ((pon)->base + 0xD)
- #define QPNP_PON_WARM_RESET_REASON2(pon) ((pon)->base + 0xB)
- #define QPNP_PON_OFF_REASON(pon) ((pon)->base + 0xC7)
- #define QPNP_FAULT_REASON1(pon) ((pon)->base + 0xC8)
- @@ -228,6 +231,8 @@ module_param_named(
- ship_mode_en, pon_ship_mode_en, int, 0600
- );
- +static struct wake_lock volume_down_wl;
- +static const char *wake_lock_name = "volume_down_locker";
- static struct qpnp_pon *sys_reset_dev;
- static DEFINE_SPINLOCK(spon_list_slock);
- static LIST_HEAD(spon_dev_list);
- @@ -631,6 +636,103 @@ int qpnp_pon_is_warm_reset(void)
- }
- EXPORT_SYMBOL(qpnp_pon_is_warm_reset);
- +int qpnp_pon_is_ps_hold_reset(void)
- +{
- + struct qpnp_pon *pon = sys_reset_dev;
- + int rc;
- + int reg = 0;
- +
- + if (!pon)
- + return 0;
- +
- + rc = regmap_read(pon->regmap, QPNP_POFF_REASON1(pon), ®);
- + if (rc) {
- + dev_err(&pon->pdev->dev,
- + "Unable to read addr=%x, rc(%d)\n",
- + QPNP_POFF_REASON1(pon), rc);
- + return 0;
- + }
- +
- + /* The bit 1 is 1, means by PS_HOLD/MSM controlled shutdown */
- + if (reg & 0x2)
- + return 1;
- +
- + dev_info(&pon->pdev->dev,
- + "hw_reset reason1 is 0x%x\n",
- + reg);
- +
- + rc = regmap_read(pon->regmap, QPNP_POFF_REASON2(pon), ®);
- +
- + dev_info(&pon->pdev->dev,
- + "hw_reset reason2 is 0x%x\n",
- + reg);
- + return 0;
- +}
- +EXPORT_SYMBOL(qpnp_pon_is_ps_hold_reset);
- +
- +int qpnp_pon_is_lck(void)
- +{
- + struct qpnp_pon *pon = sys_reset_dev;
- + int rc;
- + int reg = 0;
- +
- + if (!pon)
- + return 0;
- +
- + rc = regmap_read(pon->regmap, QPNP_PON_WARM_RESET_REASON1(pon),
- + ®);
- + if (rc) {
- + dev_err(&pon->pdev->dev, "Unable to read addr=%x, rc(%d)\n",
- + QPNP_PON_WARM_RESET_REASON1(pon), rc);
- + return 0;
- + }
- +
- + /* The bit 5 is 1, means the power on reason is KPDPWR_AND_RESIN */
- + if (reg & 0x20)
- + return 1;
- +
- + dev_info(&pon->pdev->dev,
- + "warm_reset reason1 is 0x%x\n",
- + reg);
- +
- + return 0;
- +}
- +EXPORT_SYMBOL(qpnp_pon_is_lck);
- +
- +int qpnp_pon_is_lpk(void)
- +{
- + struct qpnp_pon *pon = sys_reset_dev;
- + int rc;
- + int reg = 0;
- +
- + if (!pon)
- + return 0;
- +
- + rc = regmap_read(pon->regmap, QPNP_POFF_REASON1(pon), ®);
- + if (rc) {
- + dev_err(&pon->pdev->dev,
- + "Unable to read addr=%x, rc(%d)\n",
- + QPNP_POFF_REASON1(pon), rc);
- + return 0;
- + }
- +
- + /* The bit 7 is 1, means the off reason is powerkey */
- + if (reg & 0x80)
- + return 1;
- +
- + dev_info(&pon->pdev->dev,
- + "hw_reset reason1 is 0x%x\n",
- + reg);
- +
- + rc = regmap_read(pon->regmap, QPNP_POFF_REASON2(pon), ®);
- +
- + dev_info(&pon->pdev->dev,
- + "hw_reset reason2 is 0x%x\n",
- + reg);
- + return 0;
- +}
- +EXPORT_SYMBOL(qpnp_pon_is_lpk);
- +
- /**
- * qpnp_pon_wd_config - Disable the wd in a warm reset.
- * @enable: to enable or disable the PON watch dog
- @@ -892,6 +994,7 @@ static irqreturn_t qpnp_resin_irq(int irq, void *_pon)
- int rc;
- struct qpnp_pon *pon = _pon;
- + wake_lock_timeout(&volume_down_wl, 3*HZ);
- rc = qpnp_pon_input_dispatch(pon, PON_RESIN);
- if (rc)
- dev_err(&pon->pdev->dev, "Unable to send input event\n");
- @@ -2360,6 +2463,9 @@ static int qpnp_pon_probe(struct platform_device *pdev)
- "qcom,store-hard-reset-reason");
- qpnp_pon_debugfs_init(pdev);
- + /* if wake_lock not be initied, init it */
- + if (volume_down_wl.ws.name != wake_lock_name)
- + wake_lock_init(&volume_down_wl, WAKE_LOCK_SUSPEND, wake_lock_name);
- return 0;
- }
- @@ -2380,6 +2486,7 @@ static int qpnp_pon_remove(struct platform_device *pdev)
- list_del(&pon->list);
- spin_unlock_irqrestore(&spon_list_slock, flags);
- }
- + wake_lock_destroy(&volume_down_wl);
- return 0;
- }
- diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
- index 2d564aa..bdb4c6f 100644
- --- a/drivers/input/touchscreen/Kconfig
- +++ b/drivers/input/touchscreen/Kconfig
- @@ -12,6 +12,8 @@ menuconfig INPUT_TOUCHSCREEN
- if INPUT_TOUCHSCREEN
- source "drivers/input/touchscreen/synaptics_dsx/Kconfig"
- +source "drivers/input/touchscreen/synaptics_dsx_force/Kconfig"
- +source "drivers/input/touchscreen/ft5x46/Kconfig"
- config OF_TOUCHSCREEN
- def_tristate INPUT
- diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
- index f5be6fc..aee53c9 100644
- --- a/drivers/input/touchscreen/Makefile
- +++ b/drivers/input/touchscreen/Makefile
- @@ -70,6 +70,7 @@ obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o
- obj-$(CONFIG_TOUCHSCREEN_SUN4I) += sun4i-ts.o
- obj-$(CONFIG_TOUCHSCREEN_SUR40) += sur40.o
- obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_v21) += synaptics_dsx/
- +obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FORCE) += synaptics_dsx_force/
- obj-$(CONFIG_TOUCHSCREEN_TI_AM335X_TSC) += ti_am335x_tsc.o
- obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o
- obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o
- @@ -97,4 +98,6 @@ obj-$(CONFIG_TOUCHSCREEN_TPS6507X) += tps6507x-ts.o
- obj-$(CONFIG_TOUCHSCREEN_ZFORCE) += zforce_ts.o
- obj-$(CONFIG_TOUCHSCREEN_COLIBRI_VF50) += colibri-vf50-ts.o
- obj-$(CONFIG_TOUCHSCREEN_ROHM_BU21023) += rohm_bu21023.o
- +obj-$(CONFIG_TOUCHSCREEN_ST_FTS) += fts/
- +obj-$(CONFIG_TOUCHSCREEN_FT5X46) += ft5x46/
- obj-$(CONFIG_TOUCHSCREEN_ST) += st/
- diff --git a/drivers/input/touchscreen/ft5x46/Kconfig b/drivers/input/touchscreen/ft5x46/Kconfig
- new file mode 100644
- index 0000000..8bac8f9
- --- /dev/null
- +++ b/drivers/input/touchscreen/ft5x46/Kconfig
- @@ -0,0 +1,52 @@
- +config TOUCHSCREEN_FT5X46
- + tristate "FocalTech touchscreens"
- + depends on I2C
- + help
- + Say Y here if you have a FT5X46 touchscreen.
- + Ft5x06 controllers are multi touch controllers which can
- + report 5 touches at a time.
- +
- + If unsure, say N.
- +
- + To compile this driver as a module, choose M here: the
- + module will be called ft5x46_ts.
- +
- +config TOUCHSCREEN_FT5X46_CALIBRATE
- + bool "calibrate after flash firmware"
- + depends on TOUCHSCREEN_FT5X46
- + default y
- + help
- + must turn off after all pre-production device get upgrade.
- +
- +config TOUCHSCREEN_FT5X46_TYPEB
- + bool "use type B for touch report"
- + depends on TOUCHSCREEN_FT5X46
- + default y
- + help
- + enable typeB for multi-touch report.
- +
- +config TOUCHSCREEN_FT5X46_I2C
- + tristate "Focaltech FT5X0X I2C touchscreens"
- + depends on I2C
- + select TOUCHSCREEN_FT5X46
- + help
- + Say Y here if you have a Focaltech FT5X46 I2C touchscreen connected
- + to your system.
- +
- + If unsure, say N.
- +
- + To compile this driver as a set of modules, choose M here: the
- + modules will be called ft5x46_ts_i2c.
- +
- +config TOUCHSCREEN_FT5X46_SPI
- + tristate "Focaltech FT5X0X SPI touchscreens"
- + depends on SPI
- + select TOUCHSCREEN_FT5X46
- + help
- + Say Y here if you have a Focaltech FT5X46 SPI touchscreen connected
- + to your system.
- +
- + If unsure, say N.
- +
- + To compile this driver as a set of modules, choose M here: the
- + modules will be called ft5x46_ts_spi.
- diff --git a/drivers/input/touchscreen/ft5x46/Makefile b/drivers/input/touchscreen/ft5x46/Makefile
- new file mode 100644
- index 0000000..21a0bc1
- --- /dev/null
- +++ b/drivers/input/touchscreen/ft5x46/Makefile
- @@ -0,0 +1,8 @@
- +#
- +# Makefile for the FT5X46 touchscreen driver.
- +#
- +
- +#obj-$(CONFIG_TOUCHSCREEN_FT5X46) += ft5x46_ts.o focaltech_test.o focaltech_test_ft5x46.o
- +#obj-$(CONFIG_TOUCHSCREEN_FT5X46_I2C) += ft5x46_ts_i2c.o
- +#obj-$(CONFIG_TOUCHSCREEN_FT5X46_SPI) += ft5x46_ts_spi.o
- +obj-y += ft5x46_ts.o focaltech_test.o focaltech_test_ft5x46.o ft5x46_ts_i2c.o
- diff --git a/drivers/input/touchscreen/ft5x46/focaltech_test.c b/drivers/input/touchscreen/ft5x46/focaltech_test.c
- new file mode 100644
- index 0000000..dabd8c0
- --- /dev/null
- +++ b/drivers/input/touchscreen/ft5x46/focaltech_test.c
- @@ -0,0 +1,313 @@
- +
- +/*
- + * FocalTech TouchScreen driver.
- + * Copyright (c) 2010-2016, FocalTech Systems, Ltd., all rights reserved.
- + * Copyright (C) 2017 XiaoMi, Inc.
- + * 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.
- + */
- +
- + /************************************************************************
- +* File Name: focaltech_test.c
- +* Author: Software Department, FocalTech
- +* Created: 2016-03-24
- +* Modify:
- +* Abstract: create char device and proc node for the comm between APK and TP
- +************************************************************************/
- +
- +/*******************************************************************************
- +* Included header files
- +*******************************************************************************/
- +#include <linux/kernel.h>
- +#include <linux/module.h>
- +#include <linux/slab.h>
- +#include <linux/vmalloc.h>
- +#include <linux/debugfs.h>
- +#include <linux/interrupt.h>
- +#include <linux/uaccess.h>
- +#include <linux/i2c.h>
- +#include <linux/delay.h>
- +#include <linux/proc_fs.h>
- +#include "focaltech_test.h"
- +#include "focaltech_test_ft5x46.h"
- +
- +/*******************************************************************************
- +* Private constant and macro definitions using #define
- +*******************************************************************************/
- +#define FOCALTECH_TEST_INFO "focaltech_test.c:V1.1.0 2016-05-19"
- +#define DEVIDE_MODE_ADDR 0x00
- +#define FTS_MALLOC_TYPE 1
- +static struct proc_dir_entry *fts_selftest_proc;
- +/*******************************************************************************
- +* functions body
- +*******************************************************************************/
- +int fts_test_result = RESULT_INVALID;
- +
- +static int fts_i2c_read_test(unsigned char *writebuf, int writelen,
- + unsigned char *readbuf, int readlen)
- +{
- + int iret = -1;
- +
- + iret = fts_i2c_read(fts_i2c_client, writebuf,
- + writelen, readbuf, readlen);
- + return iret;
- +
- +}
- +
- +static int fts_i2c_write_test(unsigned char *writebuf, int writelen)
- +{
- + int iret = -1;
- +
- + iret = fts_i2c_write(fts_i2c_client, writebuf, writelen);
- + return iret;
- +}
- +
- +void focal_msleep(int ms)
- +{
- + msleep(ms);
- +}
- +void SysDelay(int ms)
- +{
- + msleep(ms);
- +}
- +int focal_abs(int value)
- +{
- + if (value < 0)
- + value = 0 - value;
- + return value;
- +}
- +void *fts_malloc(size_t size)
- +{
- + if (FTS_MALLOC_TYPE == kmalloc_mode)
- + return kmalloc(size, GFP_ATOMIC);
- + if (FTS_MALLOC_TYPE == vmalloc_mode)
- + return vmalloc(size);
- + return NULL;
- +}
- +void fts_free(void *p)
- +{
- + if (FTS_MALLOC_TYPE == kmalloc_mode)
- + kfree(p);
- + if (FTS_MALLOC_TYPE == vmalloc_mode)
- + vfree(p);
- +}
- +
- +/************************************************************************
- +* Name: ReadReg(Same function name as FT_MultipleTest)
- +* Brief: Read Register
- +* Input: RegAddr
- +* Output: RegData
- +* Return: Comm Code. Code = 0x00 is OK, else fail.
- +***********************************************************************/
- +int ReadReg(unsigned char RegAddr, unsigned char *RegData)
- +{
- + int iRet;
- +
- + iRet = fts_i2c_read_test(&RegAddr, 1, RegData, 1);
- +
- + if (iRet >= 0)
- + return ERROR_CODE_OK;
- + else
- + return ERROR_CODE_COMM_ERROR;
- +}
- +/************************************************************************
- +* Name: WriteReg(Same function name as FT_MultipleTest)
- +* Brief: Write Register
- +* Input: RegAddr, RegData
- +* Output: null
- +* Return: Comm Code. Code = 0x00 is OK, else fail.
- +***********************************************************************/
- +int WriteReg(unsigned char RegAddr, unsigned char RegData)
- +{
- + int iRet;
- + unsigned char cmd[2] = {0};
- +
- + cmd[0] = RegAddr;
- + cmd[1] = RegData;
- + iRet = fts_i2c_write_test(cmd, 2);
- +
- + if (iRet >= 0)
- + return ERROR_CODE_OK;
- + else
- + return ERROR_CODE_COMM_ERROR;
- +}
- +/************************************************************************
- +* Name: Comm_Base_IIC_IO(Same function name as FT_MultipleTest)
- +* Brief: Write/Read Data by IIC
- +* Input: pWriteBuffer, iBytesToWrite, iBytesToRead
- +* Output: pReadBuffer
- +* Return: Comm Code. Code = 0x00 is OK, else fail.
- +***********************************************************************/
- +unsigned char Comm_Base_IIC_IO(unsigned char *pWriteBuffer, int iBytesToWrite,
- + unsigned char *pReadBuffer, int iBytesToRead)
- +{
- + int iRet;
- +
- + iRet = fts_i2c_read_test(pWriteBuffer, iBytesToWrite,
- + pReadBuffer, iBytesToRead);
- +
- + if (iRet >= 0)
- + return ERROR_CODE_OK;
- + else
- + return ERROR_CODE_COMM_ERROR;
- +}
- +/************************************************************************
- +* Name: EnterWork(Same function name as FT_MultipleTest)
- +* Brief: Enter Work Mode
- +* Input: null
- +* Output: null
- +* Return: Comm Code. Code = 0x00 is OK, else fail.
- +***********************************************************************/
- +unsigned char EnterWork(void)
- +{
- + unsigned char RunState = 0;
- + unsigned char ReCode = ERROR_CODE_COMM_ERROR;
- +
- + FTS_TEST_DBG("");
- + ReCode = ReadReg(DEVIDE_MODE_ADDR, &RunState);
- + if (ReCode == ERROR_CODE_OK) {
- + if (((RunState>>4)&0x07) == 0x00)
- + ReCode = ERROR_CODE_OK;
- + else {
- + ReCode = WriteReg(DEVIDE_MODE_ADDR, 0);
- + if (ReCode == ERROR_CODE_OK) {
- + ReCode = ReadReg(DEVIDE_MODE_ADDR, &RunState);
- + if (ReCode == ERROR_CODE_OK) {
- + if (((RunState>>4)&0x07) == 0x00)
- + ReCode = ERROR_CODE_OK;
- + else
- + ReCode = ERROR_CODE_COMM_ERROR;
- + }
- + } else
- + pr_err("%s,error\n", __func__);
- + }
- + }
- +
- + return ReCode;
- +}
- +/************************************************************************
- +* Name: EnterFactory
- +* Brief: enter Fcatory Mode
- +* Input: null
- +* Output: null
- +* Return: Comm Code. Code = 0 is OK, else fail.
- +***********************************************************************/
- +unsigned char EnterFactory(void)
- +{
- + unsigned char RunState = 0;
- + unsigned char ReCode = ERROR_CODE_COMM_ERROR;
- +
- + FTS_TEST_DBG("");
- + ReCode = ReadReg(DEVIDE_MODE_ADDR, &RunState);
- + if (ReCode == ERROR_CODE_OK) {
- + if (((RunState>>4)&0x07) == 0x04)
- + ReCode = ERROR_CODE_OK;
- + else {
- + ReCode = WriteReg(DEVIDE_MODE_ADDR, 0x40);
- + if (ReCode == ERROR_CODE_OK) {
- + ReCode = ReadReg(DEVIDE_MODE_ADDR, &RunState);
- + if (ReCode == ERROR_CODE_OK) {
- + if (((RunState>>4)&0x07) == 0x04)
- + ReCode = ERROR_CODE_OK;
- + else
- + ReCode = ERROR_CODE_COMM_ERROR;
- + }
- + }
- + }
- + } else
- + FTS_TEST_ERR("EnterFactory read DEVIDE_MODE_ADDR error 1.");
- +
- + FTS_TEST_DBG(" END");
- + return ReCode;
- +}
- +int fts_i2c_test(struct i2c_client *client)
- +{
- + int retry = 5;
- + int ReCode = ERROR_CODE_OK;
- + unsigned char chip_id = 0;
- +
- + if (client == NULL)
- + return RESULT_INVALID;
- + fts_test_result = RESULT_INVALID;
- + while (retry--) {
- + ReCode = ReadReg(REG_CHIP_ID, &chip_id);
- + if (ReCode == ERROR_CODE_OK)
- + return RESULT_PASS;
- + dev_err(&client->dev, "GTP i2c test failed time %d.\n", retry);
- + msleep(20);
- + }
- + if (ReCode != ERROR_CODE_OK)
- + return RESULT_NG;
- + return RESULT_INVALID;
- +}
- +
- +
- +int fts_tp_selftest_open(struct inode *inode, struct file *file)
- +{
- + return 0;
- +}
- +
- +ssize_t fts_tp_selftest_read(struct file *file, char __user *buf,
- + size_t count, loff_t *pos)
- +{
- + if (*pos != 0)
- + return 0;
- + snprintf(buf, sizeof(fts_test_result), "%d", fts_test_result);
- + *pos += strlen(buf);
- + return strlen(buf);
- +}
- +
- +ssize_t fts_tp_selftest_write(struct file *file, const char __user *buf,
- + size_t count, loff_t *pos)
- +{
- + int retval;
- +
- + if (!fts_i2c_client) {
- + retval = -EINVAL;
- + fts_test_result = RESULT_INVALID;
- + goto out;
- + }
- + disable_irq(fts_i2c_client->irq);
- + if (!strncmp(buf, "short", 5))
- + fts_test_result = FT5X46_TestItem_WeakShortTest(fts_i2c_client);
- + else if (!strncmp(buf, "open", 4))
- + fts_test_result = FT5X46_TestItem_RawDataTest(fts_i2c_client);
- + else if (!strncmp(buf, "i2c", 3))
- + fts_test_result = fts_i2c_test(fts_i2c_client);
- + EnterWork();
- + enable_irq(fts_i2c_client->irq);
- +out:
- + return RESULT_NG;
- +}
- +
- +int fts_tp_selftest_release(struct inode *inode, struct file *file)
- +{
- + return 0;
- +}
- +static const struct file_operations tp_selftest_ops = {
- + .open = fts_tp_selftest_open,
- + .read = fts_tp_selftest_read,
- + .write = fts_tp_selftest_write,
- + .release = fts_tp_selftest_release,
- +};
- +
- +int fts_test_module_init(struct i2c_client *client)
- +{
- +
- + FTS_TEST_DBG("[focal] %s ", FOCALTECH_TEST_INFO);
- + fts_selftest_proc = proc_create("tp_selftest", 0,
- + NULL, &tp_selftest_ops);
- + return 0;
- +}
- +int fts_test_module_exit(struct i2c_client *client)
- +{
- + FTS_TEST_DBG("");
- + if (fts_selftest_proc)
- + remove_proc_entry("tp_selftest", NULL);
- + return 0;
- +}
- diff --git a/drivers/input/touchscreen/ft5x46/focaltech_test.h b/drivers/input/touchscreen/ft5x46/focaltech_test.h
- new file mode 100644
- index 0000000..70f819a
- --- /dev/null
- +++ b/drivers/input/touchscreen/ft5x46/focaltech_test.h
- @@ -0,0 +1,119 @@
- +
- +/************************************************************************
- +* Copyright (C) 2012-2015, Focaltech Systems (R),All Rights Reserved.
- +* Copyright (C) 2017 XiaoMi, Inc.
- +*
- +* File Name: focaltech_test_main.h
- +*
- +* Author: Software Development Team, AE
- +*
- +* Created: 2015-07-14
- +*
- +* Abstract: test entry for all IC
- +*
- +************************************************************************/
- +#ifndef _TEST_LIB_H
- +#define _TEST_LIB_H
- +#include <linux/kernel.h>
- +#define boolean unsigned char
- +#define bool unsigned char
- +#define BYTE unsigned char
- +#define false 0
- +#define true 1
- +
- +
- +#define MIN_HOLE_LEVEL (-1)
- +#define MAX_HOLE_LEVEL 0x7F
- +#define ERROR_CODE_OK 0x00
- +#define ERROR_CODE_CHECKSUM_ERROR 0x01
- +#define ERROR_CODE_INVALID_COMMAND 0x02
- +#define ERROR_CODE_INVALID_PARAM 0x03
- +#define ERROR_CODE_IIC_WRITE_ERROR 0x04
- +#define ERROR_CODE_IIC_READ_ERROR 0x05
- +#define ERROR_CODE_WRITE_USB_ERROR 0x06
- +#define ERROR_CODE_WAIT_RESPONSE_TIMEOUT 0x07
- +#define ERROR_CODE_PACKET_RE_ERROR 0x08
- +#define ERROR_CODE_NO_DEVICE 0x09
- +#define ERROR_CODE_WAIT_WRITE_TIMEOUT 0x0a
- +#define ERROR_CODE_READ_USB_ERROR 0x0b
- +#define ERROR_CODE_COMM_ERROR 0x0c
- +#define ERROR_CODE_ALLOCATE_BUFFER_ERROR 0x0d
- +#define ERROR_CODE_DEVICE_OPENED 0x0e
- +#define ERROR_CODE_DEVICE_CLOSED 0x0f
- +
- +/*-----------------------------------------------------------
- +Test Status
- +-----------------------------------------------------------*/
- +#define RESULT_INVALID 0
- +#define RESULT_PASS 2
- +#define RESULT_NG 1
- +
- +/*-----------------------------------------------------------
- +read write max bytes per time
- +-----------------------------------------------------------*/
- +#define BYTES_PER_TIME 128
- +#define DEVIDE_MODE_ADDR 0x00
- +#define REG_CHIP_ID 0xA3
- +#define FTS_MALLOC_TYPE 1
- +#define TX_NUM_MAX 60
- +#define RX_NUM_MAX 60
- +enum NodeType {
- + NODE_INVALID_TYPE = 0,
- + NODE_VALID_TYPE = 1,
- + NODE_KEY_TYPE = 2,
- + NODE_AST_TYPE = 3,
- +};
- +
- +
- +enum enum_malloc_mode {
- + kmalloc_mode = 0,
- + vmalloc_mode = 1,
- +};
- +
- +
- +enum NORMALIZE_Type {
- + Overall_Normalize = 0,
- + Auto_Normalize = 1,
- +};
- +
- +enum PROOF_TYPE {
- + Proof_Normal,
- + Proof_Level0,
- + Proof_NoWaterProof,
- +};
- +
- +int fts_test_module_init(struct i2c_client *client);
- +int fts_test_module_exit(struct i2c_client *client);
- +extern struct i2c_client *fts_i2c_client;
- +extern int fts_i2c_write(struct i2c_client *client,
- + char *writebuf, int writelen);
- +extern int fts_i2c_read(struct i2c_client *client,
- + char *writebuf, int writelen, char *readbuf, int readlen);
- +void focal_msleep(int ms);
- +void SysDelay(int ms);
- +int focal_abs(int value);
- +int ReadReg(unsigned char RegAddr, unsigned char *RegData);
- +int WriteReg(unsigned char RegAddr, unsigned char RegData);
- +unsigned char Comm_Base_IIC_IO(unsigned char *pWriteBuffer, int iBytesToWrite,
- + unsigned char *pReadBuffer, int iBytesToRead);
- +unsigned char EnterWork(void);
- +unsigned char EnterFactory(void);
- +void *fts_malloc(size_t size);
- +void fts_free(void *p);
- +#define FOCAL_TEST_DEBUG_EN 1
- +
- +#if (FOCAL_TEST_DEBUG_EN)
- +#define FTS_TEST_DBG(fmt, args...) \
- + pr_debug("[FOCAL] %s. line: %d. "fmt"\n",\
- + __func__, __LINE__, ##args)
- +#define FTS_TEST_PRINT(fmt, args...) pr_err(""fmt, ## args)
- +#define FTS_TEST_ERR(fmt, args...) \
- + pr_err("[FOCAL] %s. line: %d. "fmt"\n", \
- + __func__, __LINE__, ##args)
- +#else
- +#define FTS_TEST_DBG(fmt, args...) do {} while (0)
- +#define FTS_TEST_PRINT(fmt, args...) do {} while (0)
- +#endif
- +
- +
- +#endif
- diff --git a/drivers/input/touchscreen/ft5x46/focaltech_test_ft5x46.c b/drivers/input/touchscreen/ft5x46/focaltech_test_ft5x46.c
- new file mode 100644
- index 0000000..3563822
- --- /dev/null
- +++ b/drivers/input/touchscreen/ft5x46/focaltech_test_ft5x46.c
- @@ -0,0 +1,806 @@
- +/************************************************************************
- +* Copyright (C) 2012-2015, Focaltech Systems (R)£¬All Rights Reserved.
- +* Copyright (C) 2017 XiaoMi, Inc.
- +*
- +* File Name: Test_FT5X46.c
- +*
- +* Author: Software Development Team, AE
- +*
- +* Created: 2015-07-14
- +*
- +*
- +************************************************************************/
- +
- +#include <linux/kernel.h>
- +#include <linux/string.h>
- +#include <linux/slab.h>
- +#include <linux/i2c.h>
- +#include <linux/input/ft5x46_ts.h>
- +#include "focaltech_test.h"
- +
- +#define DEVIDE_MODE_ADDR 0x00
- +#define REG_LINE_NUM 0x01
- +#define REG_TX_NUM 0x02
- +#define REG_RX_NUM 0x03
- +#define REG_MAPPING_SWITCH 0x54
- +#define REG_TX_NOMAPPING_NUM 0x55
- +#define REG_RX_NOMAPPING_NUM 0x56
- +#define REG_NORMALIZE_TYPE 0x16
- +#define REG_RawBuf0 0x36
- +static int m_RawData[TX_NUM_MAX][RX_NUM_MAX] = {{0} };
- +static int m_iTempRawData[TX_NUM_MAX * RX_NUM_MAX] = {0};
- +static unsigned char m_ucTempData[TX_NUM_MAX * RX_NUM_MAX*2] = {0};
- +static bool m_bV3TP;
- +struct StruScreenSeting {
- + int iTxNum;
- + int iRxNum;
- + int isNormalize;
- + int iUsedMaxTxNum;
- + int iUsedMaxRxNum;
- + unsigned char iChannelsNum;
- + unsigned char iKeyNum;
- +} g_ScreenSetParam;
- +
- +static int StartScan(void);
- +static unsigned char ReadRawData(unsigned char Freq, unsigned char LineNum,
- + int ByteNum, int *pRevBuffer);
- +static unsigned char GetPanelRows(unsigned char *pPanelRows);
- +static unsigned char GetPanelCols(unsigned char *pPanelCols);
- +static unsigned char GetRawData(void);
- +static unsigned char GetChannelNum(void);
- +static void ShowRawData(void);
- +static unsigned char GetChannelNumNoMapping(void);
- +static unsigned char WeakShort_GetAdcData(int AllAdcDataLen, int *pRevBuffer);
- +
- +void set_max_channel_num(void)
- +{
- + g_ScreenSetParam.iUsedMaxTxNum = TX_NUM_MAX;
- + g_ScreenSetParam.iUsedMaxRxNum = RX_NUM_MAX;
- +
- +}
- +
- +static int InitTest(void)
- +{
- + set_max_channel_num();
- + return 0;
- +}
- +
- +unsigned char FT5X46_TestItem_RawDataTest(struct i2c_client *client)
- +{
- +
- + unsigned char ReCode = 0;
- + bool btmpresult = true;
- + int RawDataMin;
- + unsigned char strSwitch = 0;
- + unsigned char OriginValue = 0xff;
- + int index = 0;
- + int iRow, iCol;
- + int iValue = 0;
- + struct ft5x46_data *ft5x46 = i2c_get_clientdata(client);
- + struct ft5x46_ts_platform_data *pdata = ft5x46->dev->platform_data;
- +
- + m_bV3TP = false;
- + FTS_TEST_DBG("\n\nTest Item:Raw Data Test\n");
- + InitTest();
- +
- + ReCode = EnterFactory();
- + if (ReCode != ERROR_CODE_OK) {
- + FTS_TEST_ERR("\nFailed to Enter factory.%d",
- + ReCode);
- + goto TEST_ERR;
- + }
- +
- + if (m_bV3TP) {
- + ReCode = ReadReg(REG_MAPPING_SWITCH, &strSwitch);
- + if (ReCode != ERROR_CODE_OK) {
- + FTS_TEST_ERR("\n Read REG_MAPPING_SWITCH error%d", ReCode);
- + goto TEST_ERR;
- + }
- + if (strSwitch != 0) {
- + ReCode = WriteReg(REG_MAPPING_SWITCH, 0);
- + if (ReCode != ERROR_CODE_OK) {
- + FTS_TEST_ERR("\n Write REG_MAPPING_SWITCH error%d", ReCode);
- + goto TEST_ERR;
- + }
- + ReCode = GetChannelNum();
- + if (ReCode != ERROR_CODE_OK) {
- + FTS_TEST_ERR("\n GetChannelNum error%d", ReCode);
- + goto TEST_ERR;
- + }
- + }
- + } else {
- + ReCode = GetChannelNum();
- + if (ReCode != ERROR_CODE_OK) {
- + FTS_TEST_ERR("\n GetChannelNum error%d", ReCode);
- + goto TEST_ERR;
- + }
- + }
- +
- + ReCode = ReadReg(REG_NORMALIZE_TYPE, &OriginValue);
- + if (ReCode != ERROR_CODE_OK) {
- + FTS_TEST_ERR("\n Read REG_NORMALIZE_TYPE error. %d", ReCode);
- + goto TEST_ERR;
- + }
- +
- + if (OriginValue != 1) {
- + ReCode = WriteReg(REG_NORMALIZE_TYPE, 0x01);
- + if (ReCode != ERROR_CODE_OK) {
- + FTS_TEST_ERR("\n write REG_NORMALIZE_TYPE error.%d", ReCode);
- + goto TEST_ERR;
- + }
- + }
- +
- + FTS_TEST_DBG("\nSet Frequecy High\n");
- + ReCode = WriteReg(0x0A, 0x81);
- + if (ReCode != ERROR_CODE_OK) {
- + FTS_TEST_ERR("\n Set Frequecy High error. %d", ReCode);
- + goto TEST_ERR;
- + }
- +
- + FTS_TEST_DBG("\nFIR State: OFF");
- + ReCode = WriteReg(0xFB, 0);
- + if (ReCode != ERROR_CODE_OK) {
- + FTS_TEST_ERR("\n FIR on error:%d", ReCode);
- + goto TEST_ERR;
- + }
- +
- + for (index = 0; index < 3; ++index)
- + ReCode = GetRawData();
- +
- + if (ReCode != ERROR_CODE_OK) {
- + FTS_TEST_ERR("\n Get Rawdata failed,Error Code: 0x%x", ReCode);
- + goto TEST_ERR;
- + }
- +
- + ShowRawData();
- + RawDataMin = pdata->open_min;
- + if (pdata->has_key) {
- + for (iRow = 0; iRow < g_ScreenSetParam.iTxNum; iRow++) {
- + for (iCol = 0; iCol < (g_ScreenSetParam.iRxNum - 1); iCol++) {
- + iValue = m_RawData[iRow][iCol];
- + if (iValue < RawDataMin) {
- + btmpresult = false;
- + FTS_TEST_PRINT("rawdata failure.Node=(%d,%d),value=%d",
- + iRow+1, iCol+1, iValue);
- + }
- + }
- + }
- + iValue = m_RawData[pdata->key_rx1 - 1][iCol];
- + if (iValue < RawDataMin) {
- + btmpresult = false;
- + FTS_TEST_PRINT("rawdata failure.Node=(%d,%d),Get_value=%d",
- + 4, iCol+1, iValue);
- + }
- + iValue = m_RawData[pdata->key_rx2 - 1][iCol];
- + if (iValue < RawDataMin) {
- + btmpresult = false;
- + FTS_TEST_PRINT("rawdata failure.Node=(%d,%d),Get_value=%d",
- + 8, iCol+1, iValue);
- + }
- + iValue = m_RawData[pdata->key_rx3 - 1][iCol];
- + if (iValue < RawDataMin) {
- + btmpresult = false;
- + FTS_TEST_PRINT("rawdata test failure.Node=(%d,%d),Get_value=%d",
- + 12, iCol+1, iValue);
- + }
- + } else {
- + for (iRow = 0; iRow < g_ScreenSetParam.iTxNum; iRow++) {
- + for (iCol = 0; iCol < g_ScreenSetParam.iRxNum; iCol++) {
- + iValue = m_RawData[iRow][iCol];
- + if (iValue < RawDataMin) {
- + btmpresult = false;
- + FTS_TEST_PRINT("rawdata failure.Node=(%d,%d),value=%d",
- + iRow+1, iCol+1, iValue);
- + }
- + }
- + }
- + }
- + ReCode = WriteReg(REG_NORMALIZE_TYPE, OriginValue);
- + if (ReCode != ERROR_CODE_OK) {
- + FTS_TEST_ERR("\n Write REG_NORMALIZE_TYPE error:%d", ReCode);
- + goto TEST_ERR;
- + }
- +
- + if (m_bV3TP) {
- + ReCode = WriteReg(REG_MAPPING_SWITCH, strSwitch);
- + if (ReCode != ERROR_CODE_OK) {
- + FTS_TEST_ERR("\n Write REG_MAPPING_SWITCH errore: %d", ReCode);
- + goto TEST_ERR;
- + }
- + }
- +
- + if (btmpresult) {
- + FTS_TEST_ERR("\n\n//RawData Test is OK!");
- + return RESULT_PASS;
- + }
- + if (!btmpresult) {
- + FTS_TEST_ERR("\n\n//RawData Test is NG!");
- + return RESULT_NG;
- + }
- + return RESULT_INVALID;
- +
- +TEST_ERR:
- + FTS_TEST_DBG("\n\n//RawData Test is NG!");
- + return RESULT_INVALID;
- +}
- +
- +static unsigned char GetPanelRows(unsigned char *pPanelRows)
- +{
- + return ReadReg(REG_TX_NUM, pPanelRows);
- +}
- +
- +static unsigned char GetPanelCols(unsigned char *pPanelCols)
- +{
- + return ReadReg(REG_RX_NUM, pPanelCols);
- +}
- +
- +static int StartScan(void)
- +{
- + unsigned char RegVal = 0;
- + unsigned char times = 0;
- + const unsigned char MaxTimes = 20;
- + unsigned char ReCode = ERROR_CODE_COMM_ERROR;
- +
- + ReCode = ReadReg(DEVIDE_MODE_ADDR, &RegVal);
- + if (ReCode == ERROR_CODE_OK) {
- + RegVal |= 0x80;
- + ReCode = WriteReg(DEVIDE_MODE_ADDR, RegVal);
- + if (ReCode == ERROR_CODE_OK) {
- + while (times++ < MaxTimes) {
- + SysDelay(8);
- + ReCode = ReadReg(DEVIDE_MODE_ADDR, &RegVal);
- + if (ReCode == ERROR_CODE_OK) {
- + if ((RegVal>>7) == 0)
- + break;
- + } else {
- + FTS_TEST_DBG("StartScan read DEVIDE_MODE_ADDR error.");
- + break;
- + }
- + }
- + if (times < MaxTimes)
- + ReCode = ERROR_CODE_OK;
- + else {
- + ReCode = ERROR_CODE_COMM_ERROR;
- + FTS_TEST_DBG("times NOT < MaxTimes. error.");
- + }
- + } else
- + FTS_TEST_DBG("StartScan write DEVIDE_MODE_ADDR error.");
- + } else
- + FTS_TEST_DBG("StartScan read DEVIDE_MODE_ADDR error.");
- + return ReCode;
- +}
- +
- +unsigned char ReadRawData(unsigned char Freq, unsigned char LineNum, int ByteNum, int *pRevBuffer)
- +{
- + unsigned char ReCode = ERROR_CODE_COMM_ERROR;
- + unsigned char I2C_wBuffer[3];
- + int i, iReadNum;
- + unsigned short BytesNumInTestMode1 = 0;
- +
- + iReadNum = ByteNum/BYTES_PER_TIME;
- + if (0 != (ByteNum%BYTES_PER_TIME))
- + iReadNum++;
- +
- + if (ByteNum <= BYTES_PER_TIME)
- + BytesNumInTestMode1 = ByteNum;
- + else
- + BytesNumInTestMode1 = BYTES_PER_TIME;
- + ReCode = WriteReg(REG_LINE_NUM, LineNum);
- +
- + if (ReCode != ERROR_CODE_OK) {
- + FTS_TEST_DBG("Failed to write REG_LINE_NUM! ");
- + goto READ_ERR;
- + }
- +
- + I2C_wBuffer[0] = REG_RawBuf0;
- + if (ReCode == ERROR_CODE_OK) {
- + focal_msleep(10);
- + ReCode = Comm_Base_IIC_IO(I2C_wBuffer, 1,
- + m_ucTempData, BytesNumInTestMode1);
- + if (ReCode != ERROR_CODE_OK) {
- + FTS_TEST_DBG("read rawdata Comm_Base_IIC_IO Failed!1 ");
- + goto READ_ERR;
- + }
- + }
- +
- + for (i = 1; i < iReadNum; i++) {
- + if (ReCode != ERROR_CODE_OK)
- + break;
- +
- + if (i == iReadNum-1) {
- + focal_msleep(10);
- + ReCode = Comm_Base_IIC_IO(NULL, 0,
- + m_ucTempData+BYTES_PER_TIME*i, ByteNum-BYTES_PER_TIME*i);
- + if (ReCode != ERROR_CODE_OK) {
- + FTS_TEST_DBG("read rawdata Comm_Base_IIC_IO Failed!2 ");
- + goto READ_ERR;
- + }
- + } else {
- + focal_msleep(10);
- + ReCode = Comm_Base_IIC_IO(NULL, 0,
- + m_ucTempData+BYTES_PER_TIME*i, BYTES_PER_TIME);
- +
- + if (ReCode != ERROR_CODE_OK) {
- + FTS_TEST_DBG("read rawdata Comm_Base_IIC_IO Failed!3 ");
- + goto READ_ERR;
- + }
- + }
- +
- + }
- +
- + if (ReCode == ERROR_CODE_OK)
- + for (i = 0; i < (ByteNum>>1); i++)
- + pRevBuffer[i] = (m_ucTempData[i<<1]<<8)+m_ucTempData[(i<<1)+1];
- +
- +READ_ERR:
- + return ReCode;
- +
- +}
- +
- +static unsigned char GetChannelNum(void)
- +{
- + unsigned char ReCode;
- + unsigned char rBuffer[1];
- +
- + ReCode = GetPanelRows(rBuffer);
- + if (ReCode == ERROR_CODE_OK) {
- + g_ScreenSetParam.iTxNum = rBuffer[0];
- + if (g_ScreenSetParam.iTxNum > g_ScreenSetParam.iUsedMaxTxNum) {
- + FTS_TEST_DBG("Failed to get Tx number, Get num = %d, UsedMaxNum = %d",
- + g_ScreenSetParam.iTxNum, g_ScreenSetParam.iUsedMaxTxNum);
- + g_ScreenSetParam.iTxNum = 0;
- + return ERROR_CODE_INVALID_PARAM;
- + }
- + } else
- + FTS_TEST_DBG("Failed to get Tx number");
- +
- + ReCode = GetPanelCols(rBuffer);
- + if (ReCode == ERROR_CODE_OK) {
- + g_ScreenSetParam.iRxNum = rBuffer[0];
- + if (g_ScreenSetParam.iRxNum > g_ScreenSetParam.iUsedMaxRxNum) {
- + FTS_TEST_DBG("Failed to get Rx number, Get num = %d, UsedMaxNum = %d",
- + g_ScreenSetParam.iRxNum, g_ScreenSetParam.iUsedMaxRxNum);
- + g_ScreenSetParam.iRxNum = 0;
- + return ERROR_CODE_INVALID_PARAM;
- + }
- + } else
- + FTS_TEST_DBG("Failed to get Rx number");
- +
- + return ReCode;
- +
- +}
- +static unsigned char GetRawData(void)
- +{
- + unsigned char ReCode = ERROR_CODE_OK;
- + int iRow = 0;
- + int iCol = 0;
- +
- + ReCode = EnterFactory();
- + if (ERROR_CODE_OK != ReCode) {
- + FTS_TEST_DBG("Failed to Enter Factory Mode...");
- + return ReCode;
- + }
- + if (0 == (g_ScreenSetParam.iTxNum + g_ScreenSetParam.iRxNum)) {
- + ReCode = GetChannelNum();
- + if (ERROR_CODE_OK != ReCode) {
- + FTS_TEST_DBG("Error Channel Num...");
- + return ERROR_CODE_INVALID_PARAM;
- + }
- + }
- +
- + FTS_TEST_DBG("Start Scan ...");
- + ReCode = StartScan();
- + if (ERROR_CODE_OK != ReCode) {
- + FTS_TEST_DBG("Failed to Scan ...");
- + return ReCode;
- + }
- +
- + memset(m_RawData, 0, sizeof(m_RawData));
- + ReCode = ReadRawData(1, 0xAA,
- + (g_ScreenSetParam.iTxNum * g_ScreenSetParam.iRxNum)*2, m_iTempRawData);
- + for (iRow = 0; iRow < g_ScreenSetParam.iTxNum; iRow++)
- + for (iCol = 0; iCol < g_ScreenSetParam.iRxNum; iCol++)
- + m_RawData[iRow][iCol] = m_iTempRawData[iRow*g_ScreenSetParam.iRxNum + iCol];
- + return ReCode;
- +}
- +
- +static void ShowRawData(void)
- +{
- + int iRow, iCol;
- +
- + for (iRow = 0; iRow < g_ScreenSetParam.iTxNum; iRow++) {
- + FTS_TEST_PRINT("Tx%2d: ", iRow+1);
- + for (iCol = 0; iCol < g_ScreenSetParam.iRxNum; iCol++)
- + FTS_TEST_PRINT("%5d ", m_RawData[iRow][iCol]);
- + FTS_TEST_PRINT("\n ");
- + }
- +}
- +
- +static unsigned char GetChannelNumNoMapping(void)
- +{
- + unsigned char ReCode;
- + unsigned char rBuffer[1];
- +
- + FTS_TEST_DBG("Get Tx Num...");
- + ReCode = ReadReg(REG_TX_NOMAPPING_NUM, rBuffer);
- + if (ReCode == ERROR_CODE_OK)
- + g_ScreenSetParam.iTxNum = rBuffer[0];
- + else
- + FTS_TEST_DBG("Failed to get Tx number");
- +
- + FTS_TEST_DBG("Get Rx Num...");
- + ReCode = ReadReg(REG_RX_NOMAPPING_NUM, rBuffer);
- + if (ReCode == ERROR_CODE_OK)
- + g_ScreenSetParam.iRxNum = rBuffer[0];
- + else
- + FTS_TEST_DBG("Failed to get Rx number");
- +
- + return ReCode;
- +}
- +unsigned char FT5X46_TestItem_WeakShortTest(struct i2c_client *client)
- +{
- + unsigned char ReCode = ERROR_CODE_COMM_ERROR;
- + int i = 0;
- + int iAllAdcDataNum = 63;
- + int iMaxTx = 35;
- + unsigned char iTxNum, iRxNum, iChannelNum;
- + int iClbData_Ground, iClbData_Mutual, iOffset;
- + unsigned char IcValue = 0;
- + unsigned char strSwitch = 1;
- + bool bCapShortTest = false;
- + int *iAdcData = NULL;
- + bool btmpresult = true;
- + int fKcal = 0;
- + int *fMShortResistance = NULL, *fGShortResistance = NULL;
- + int iDoffset = 0, iDsen = 0, iDrefn = 0;
- + int iMin_CG = 0;
- + int iCount = 0;
- + int iMin_CC = 0;
- + int iDCal = 0;
- + int iMa = 0;
- + int iRsen = 57;
- + int iCCRsen = 57;
- + struct ft5x46_data *ft5x46 = i2c_get_clientdata(client);
- + struct ft5x46_ts_platform_data *pdata = ft5x46->dev->platform_data;
- +
- + FTS_TEST_DBG("\nTest Item:Weak Short-Circuit Test\n");
- + InitTest();
- + ReCode = EnterWork();
- + if (ReCode != ERROR_CODE_OK) {
- + FTS_TEST_ERR(" EnterWork failed.. Error Code: %d", ReCode);
- + goto TEST_ERR;
- + }
- + SysDelay(200);
- + ReCode = ReadReg(0xB1, &IcValue);
- + if (ReCode != ERROR_CODE_OK) {
- + FTS_TEST_ERR("\n Read 0xB1 IcValue error. Error Code: %d\n", ReCode);
- + goto TEST_ERR;
- + } else
- + FTS_TEST_DBG(" IcValue:0x%02x\n", IcValue);
- + ReCode = EnterFactory();
- + SysDelay(100);
- + if (ReCode != ERROR_CODE_OK) {
- + FTS_TEST_ERR(" EnterFactory failed.. Error Code: %d", ReCode);
- + goto TEST_ERR;
- + }
- +
- + if (m_bV3TP) {
- + ReCode = ReadReg(REG_MAPPING_SWITCH, &strSwitch);
- + if (strSwitch != 1) {
- + ReCode = WriteReg(REG_MAPPING_SWITCH, 1);
- + SysDelay(20);
- + if (ReCode != ERROR_CODE_OK)
- + FTS_TEST_ERR("\r\nFailed to restore mapping type!\r\n ");
- + GetChannelNumNoMapping();
- + iTxNum = g_ScreenSetParam.iTxNum;
- + iRxNum = g_ScreenSetParam.iRxNum;
- + }
- + } else {
- + ReCode = ReadReg(0x02, &iTxNum);
- + ReCode = ReadReg(0x03, &iRxNum);
- + FTS_TEST_DBG("Newly acquired TxNum:%d, RxNum:%d", iTxNum, iRxNum);
- + }
- +
- + if (ReCode != ERROR_CODE_OK) {
- + FTS_TEST_ERR("ReCode error. Error Code: %d\n", ReCode);
- + goto TEST_ERR;
- + }
- +
- + iChannelNum = iTxNum + iRxNum;
- + iMaxTx = iTxNum;
- + iAllAdcDataNum = 1 + (1 + iTxNum + iRxNum)*2;
- + for (i = 0; i < 5; i++) {
- + ReCode = StartScan();
- + if (ReCode != ERROR_CODE_OK) {
- + FTS_TEST_ERR("StartScan Failed!\n");
- + SysDelay(100);
- + } else {
- + FTS_TEST_DBG("StartScan OK!\n");
- + break;
- + }
- + }
- + if (i >= 5) {
- + FTS_TEST_ERR("StartScan Failed for several times.!\n");
- + goto TEST_ERR;
- + }
- + iAdcData = fts_malloc(iAllAdcDataNum*sizeof(int));
- + memset(iAdcData, 0, iAllAdcDataNum);
- + for (i = 0; i < 5; i++) {
- + memset(iAdcData, 0, iAllAdcDataNum);
- +
- + FTS_TEST_DBG("WeakShort_GetAdcData times: %d", i);
- +
- + ReCode = WeakShort_GetAdcData(iAllAdcDataNum*2, iAdcData);
- + SysDelay(50);
- + if (ReCode != ERROR_CODE_OK)
- + continue;
- + else {
- + if (0 == iAdcData[0] && 0 == iAdcData[1])
- + continue;
- + else
- + break;
- + }
- + }
- + if (i >= 5) {
- + FTS_TEST_ERR("WeakShort_GetAdcData or ADC data error. tried times: %d", i);
- + goto TEST_ERR;
- + }
- +
- + FTS_TEST_DBG("");
- +
- + iOffset = iAdcData[0];
- + iClbData_Ground = iAdcData[1];
- + iClbData_Mutual = iAdcData[2 + iChannelNum];
- +
- + for (i = 0; i < iAllAdcDataNum; i++) {
- + if (i <= (iChannelNum + 1)) {
- + if (i == 0)
- + FTS_TEST_PRINT("\n\n\nOffset %02d: %4d,\n", i, iAdcData[i]);
- + else if (i == 1)
- + FTS_TEST_PRINT("Ground %02d: %4d,\n", i, iAdcData[i]);
- + else if (i <= (iMaxTx + 1))
- + FTS_TEST_PRINT("Tx%02d: %4d, ", i-1, iAdcData[i]);
- + else if (i <= (iChannelNum + 1))
- + FTS_TEST_PRINT("Rx%02d: %4d, ", i - iMaxTx-1, iAdcData[i]);
- + if (i % 10 == 0)
- + FTS_TEST_PRINT("\n");
- + } else {
- + if (i == (iChannelNum + 2))
- + FTS_TEST_PRINT("\n\n\nMultual %02d: %4d,\n", i, iAdcData[i]);
- + else if (i <= (iMaxTx)+(iChannelNum + 2))
- + FTS_TEST_PRINT("Tx%02d: %4d, ", i - (iChannelNum + 2), iAdcData[i]);
- + else if (i < iAllAdcDataNum)
- + FTS_TEST_PRINT("Rx%02d: %4d, ", i - iMaxTx - (iChannelNum + 2), iAdcData[i]);
- + if (i % 10 == 0)
- + FTS_TEST_PRINT("\n");
- + }
- + }
- + FTS_TEST_PRINT("\r\n");
- + FTS_TEST_DBG("");
- +
- + fMShortResistance = fts_malloc(iChannelNum*sizeof(int));
- + memset(fMShortResistance, 0, iChannelNum);
- + fGShortResistance = fts_malloc(iChannelNum*sizeof(int));
- + memset(fGShortResistance, 0, iChannelNum);
- +
- + iMin_CG = pdata->imin_cg;
- + iDoffset = iOffset - 1024;
- + iDrefn = iClbData_Ground;
- +
- + FTS_TEST_DBG("Drefp:%5d \r\n", iDrefn);
- + FTS_TEST_DBG("Doffset:%5d\r\n", iDoffset);
- + FTS_TEST_DBG("Rshort(Ground):\n\n\n");
- + fKcal = 1;
- + FTS_TEST_DBG("Short Circuit (Channel and Ground):\r\n");
- + for (i = 0; i < iChannelNum; i++) {
- + iDsen = iAdcData[i+2];
- + FTS_TEST_PRINT("%5d ", iDsen);
- + if (i+1 == iMaxTx)
- + FTS_TEST_PRINT("\n");
- + if ((2047+iDoffset) - iDsen <= 0)
- + continue;
- + if (i == iMaxTx)
- + FTS_TEST_PRINT("\n");
- + if (IcValue <= 0x05 || IcValue == 0xff)
- + fGShortResistance[i] = (iDsen - iDoffset + 410) * 25 * fKcal / (2047 + iDoffset - iDsen) - 3;
- + else {
- + if (iDrefn - iDsen <= 0) {
- + fGShortResistance[i] = iMin_CG;
- + FTS_TEST_PRINT("%02d ", fGShortResistance[i]);
- + continue;
- + }
- + fGShortResistance[i] = (((iDsen - iDoffset + 384) / (iDrefn - iDsen) * 57) - 1);
- + }
- + if (fGShortResistance[i] < 0)
- + fGShortResistance[i] = 0;
- + FTS_TEST_PRINT("%02d ", fGShortResistance[i]);
- + if ((iMin_CG > fGShortResistance[i]) || (iDsen - iDoffset < 0)) {
- + iCount++;
- + if (i+1 <= iMaxTx)
- + FTS_TEST_PRINT("Tx%02d: %02d (k¦¸), ", i+1, fGShortResistance[i]);
- + else
- + FTS_TEST_PRINT("Rx%02d: %02d (k¦¸), ", i+1 - iMaxTx, fGShortResistance[i]);
- + if (iCount % 10 == 0)
- + FTS_TEST_PRINT("\n");
- + }
- + }
- + FTS_TEST_PRINT("\n");
- +
- + if (iCount > 0)
- + btmpresult = false;
- + iMin_CC = pdata->imin_cc;
- + if ((IcValue == 0x06 || IcValue < 0xff) && iRsen != iCCRsen)
- + iRsen = iCCRsen;
- + iDoffset = iOffset - 1024;
- + iDrefn = iClbData_Mutual;
- + fKcal = 1.0;
- +
- + FTS_TEST_DBG("\n\nShort Circuit (Channel and Channel):\n");
- + iCount = 0;
- +
- +
- + FTS_TEST_DBG("Drefp: %5d \r\n", iDrefn);
- + FTS_TEST_DBG("Doffset: %5d \r\n", iDoffset);
- + FTS_TEST_DBG("Rshort(Channel):");
- + iDCal = max(iDrefn, 116 + iDoffset);
- +
- + for (i = 0; i < iChannelNum; i++) {
- + iDsen = iAdcData[i+iChannelNum + 3];
- +
- + FTS_TEST_PRINT("%5d ", iDsen);
- + if (i+1 == iMaxTx)
- + FTS_TEST_PRINT("\n");
- + if (IcValue <= 0x05 || IcValue == 0xff)
- + if (iDsen - iDrefn < 0)
- + continue;
- +
- + if (i == iMaxTx)
- + FTS_TEST_PRINT("\n");
- +
- + if (IcValue <= 0x05 || IcValue == 0xff) {
- + iMa = iDsen - iDCal;
- + iMa = iMa ? iMa : 1;
- + fMShortResistance[i] = ((2047 + iDoffset - iDCal) * 24 / iMa - 27) * fKcal - 6;
- + } else {
- + if (iDrefn - iDsen <= 0) {
- + fMShortResistance[i] = iMin_CC;
- + FTS_TEST_PRINT("%02d ", fMShortResistance[i]);
- + continue;
- + }
- +
- + fMShortResistance[i] = (iDsen - iDoffset - 123) * iRsen * fKcal / (iDrefn - iDsen) - 2;
- + }
- +
- +
- + FTS_TEST_PRINT("%02d ", fMShortResistance[i]);
- +
- + if (fMShortResistance[i] < 0 && fMShortResistance[i] >= -240)
- + fMShortResistance[i] = 0;
- + else if (fMShortResistance[i] < -240)
- + continue;
- +
- + if (fMShortResistance[i] <= 0 || fMShortResistance[i] < iMin_CC) {
- + iCount++;
- + if (i+1 <= iMaxTx)
- + FTS_TEST_PRINT("Tx%02d: %02d(k¦¸), ", i+1, fMShortResistance[i]);
- + else
- + FTS_TEST_PRINT("Rx%02d: %02d(k¦¸), ", i+1 - iMaxTx, fMShortResistance[i]);
- + if (iCount % 10 == 0)
- + FTS_TEST_PRINT("\n");
- + }
- + }
- + FTS_TEST_PRINT("\n");
- +
- + if (iCount > 0 && !bCapShortTest)
- + btmpresult = false;
- +
- + if (bCapShortTest && iCount)
- + FTS_TEST_DBG(" bCapShortTest && iCount. need to add ......");
- +
- + if (m_bV3TP) {
- + ReCode = WriteReg(REG_MAPPING_SWITCH, strSwitch);
- + SysDelay(50);
- + if (ReCode != ERROR_CODE_OK) {
- + FTS_TEST_ERR("Failed to restore mapping type!\r\n");
- + goto TEST_ERR;
- + }
- + ReCode = GetChannelNum();
- + if (ReCode != ERROR_CODE_OK) {
- + FTS_TEST_ERR("\nGetChannelNum error.Code: %d", ReCode);
- + goto TEST_ERR;
- + }
- + ReCode = GetRawData();
- + }
- + if (NULL != iAdcData) {
- + fts_free(iAdcData);
- + iAdcData = NULL;
- + }
- +
- + if (NULL != fMShortResistance) {
- + fts_free(fMShortResistance);
- + fMShortResistance = NULL;
- + }
- +
- + if (NULL != fGShortResistance) {
- + fts_free(fGShortResistance);
- + fGShortResistance = NULL;
- + }
- + if (btmpresult) {
- + FTS_TEST_DBG("\r\n\r\n//Weak Short Test is OK.");
- + return RESULT_PASS;
- + }
- +
- + FTS_TEST_DBG("\r\n\r\n//Weak Short Test is NG.");
- + return RESULT_NG;
- +
- +TEST_ERR:
- + if (NULL != iAdcData) {
- + fts_free(iAdcData);
- + iAdcData = NULL;
- + }
- + if (NULL != fMShortResistance) {
- + fts_free(fMShortResistance);
- + fMShortResistance = NULL;
- + }
- + if (NULL != fGShortResistance) {
- + fts_free(fGShortResistance);
- + fGShortResistance = NULL;
- + }
- + FTS_TEST_DBG("%s invalid\n\n\n\n", __func__);
- + return RESULT_INVALID;
- +}
- +
- +static unsigned char WeakShort_GetAdcData(int AllAdcDataLen, int *pRevBuffer)
- +{
- + unsigned char ReCode = ERROR_CODE_COMM_ERROR;
- + int iReadDataLen = AllAdcDataLen;
- + unsigned char *pDataSend = NULL;
- + unsigned char Data = 0xff;
- + int i = 0;
- + bool bAdcOK = false;
- +
- + FTS_TEST_DBG("\n");
- + pDataSend = fts_malloc(iReadDataLen + 1);
- + if (pDataSend == NULL)
- + return ERROR_CODE_ALLOCATE_BUFFER_ERROR;
- + memset(pDataSend, 0, iReadDataLen + 1);
- + ReCode = WriteReg(0x07, 0x01);
- + if (ReCode != ERROR_CODE_OK) {
- + FTS_TEST_DBG("WriteReg error.\n");
- + return ReCode;
- + }
- + SysDelay(100);
- + for (i = 0; i < 100*5; i++) {
- + SysDelay(10);
- + ReCode = ReadReg(0x07, &Data);
- + if (ReCode == ERROR_CODE_OK)
- + if (Data == 0) {
- + bAdcOK = true;
- + break;
- + }
- + }
- + if (!bAdcOK) {
- + FTS_TEST_ERR("ADC data NOT ready. error.\n");
- + ReCode = ERROR_CODE_COMM_ERROR;
- + goto EndGetAdc;
- + }
- + SysDelay(300);
- + pDataSend[0] = 0xF4;
- + ReCode = Comm_Base_IIC_IO(pDataSend, 1, pDataSend + 1, iReadDataLen);
- + if (ReCode == ERROR_CODE_OK) {
- + FTS_TEST_PRINT("\n Adc Data:\n");
- + for (i = 0; i < iReadDataLen/2; i++) {
- + pRevBuffer[i] = (pDataSend[1 + 2*i]<<8) + pDataSend[1 + 2*i + 1];
- + FTS_TEST_PRINT("%d, ", pRevBuffer[i]);
- + }
- + FTS_TEST_PRINT("\n");
- + } else
- + FTS_TEST_DBG("Comm_Base_IIC_IO error. error:%d.\n", ReCode);
- +EndGetAdc:
- + if (pDataSend != NULL) {
- + fts_free(pDataSend);
- + pDataSend = NULL;
- + }
- + FTS_TEST_DBG(" END.\n");
- + return ReCode;
- +}
- diff --git a/drivers/input/touchscreen/ft5x46/focaltech_test_ft5x46.h b/drivers/input/touchscreen/ft5x46/focaltech_test_ft5x46.h
- new file mode 100644
- index 0000000..245c4e6
- --- /dev/null
- +++ b/drivers/input/touchscreen/ft5x46/focaltech_test_ft5x46.h
- @@ -0,0 +1,22 @@
- +
- +/************************************************************************
- +* Copyright (C) 2012-2015, Focaltech Systems (R),All Rights Reserved.
- +*
- +* File Name: Test_FT8716.c
- +*
- +* Author: Software Development Team, AE
- +*
- +* Created: 2015-07-14
- +*
- +* Abstract: test item for FT8716
- +*
- +************************************************************************/
- +#ifndef _TEST_FT8716_H
- +#define _TEST_FT8716_H
- +
- +
- +unsigned char FT5X46_TestItem_RawDataTest(struct i2c_client *client);
- +unsigned char FT5X46_TestItem_WeakShortTest(struct i2c_client *client);
- +
- +
- +#endif
- diff --git a/drivers/input/touchscreen/ft5x46/ft5x46_ts.c b/drivers/input/touchscreen/ft5x46/ft5x46_ts.c
- new file mode 100644
- index 0000000..079d1a4
- --- /dev/null
- +++ b/drivers/input/touchscreen/ft5x46/ft5x46_ts.c
- @@ -0,0 +1,3051 @@
- +
- +/* Copyright (C) 2017 XiaoMi, Inc.
- + *
- + * 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 <linux/input/ft5x46_ts.h>
- +
- +#define FT5X46_DEBUG_PERMISSION
- +#define FT5X46_APK_DEBUG_CHANNEL
- +
- +#define FT5X0X_REG_DEVIDE_MODE 0x00
- +#define FT5X0X_REG_ROW_ADDR 0x01
- +#define FT5X0X_REG_TD_STATUS 0x02
- +#define FT5X0X_REG_START_SCAN 0x02
- +#define FT5X0X_REG_TOUCH_START 0x03
- +#define FT5X0X_REG_VOLTAGE 0x05
- +#define FT5X0X_REG_CHIP_ID 0xA3
- +#define FT5X0X_ID_G_PMODE 0xA5
- +#define FT5X0X_REG_FW_VER 0xA6
- +#define FT5X0X_ID_G_FT5201ID 0xA8
- +#define FT5X0X_NOISE_FILTER 0x8B
- +#define FT5X0X_REG_POINT_RATE 0x88
- +#define FT5X0X_REG_THGROUP 0x80
- +#define FT5X0X_REG_RESET 0xFC
- +
- +#define FT5X0X_DEVICE_MODE_NORMAL 0x00
- +#define FT5X0X_DEVICE_MODE_TEST 0x40
- +#define FT5X0X_DEVICE_START_CALIB 0x04
- +#define FT5X0X_DEVICE_SAVE_RESULT 0x05
- +
- +#define FT5X0X_POWER_ACTIVE 0x00
- +#define FT5X0X_POWER_MONITOR 0x01
- +#define FT5X0X_POWER_HIBERNATE 0x03
- +
- +#define FT5X0X_REG_CONFIG_INFO 0x92
- +
- +#define FT5X0X_TOUCH_LENGTH 6
- +
- +#define FT5X0X_TOUCH_XH 0x00
- +#define FT5X0X_TOUCH_XL 0x01
- +#define FT5X0X_TOUCH_YH 0x02
- +#define FT5X0X_TOUCH_YL 0x03
- +#define FT5X0X_TOUCH_PRESSURE 0x04
- +#define FT5X0X_TOUCH_SIZE 0x05
- +
- +#define FT5X46_MAX_ID 0x0F
- +#define FT5X46_TOUCH_LENGTH 6
- +#define FT5X46_XH_POS 3
- +#define FT5X46_XL_POS 4
- +#define FT5X46_YH_POS 5
- +#define FT5X46_YL_POS 6
- +#define FT5X46_XY_POS 7
- +#define FT5X46_EVENT_POS 3
- +#define FT5X46_ID_POS 5
- +
- +#define FT5X46_DEF_PRESSURE 8
- +
- +#define FT5X0X_MODE_NORMAL 0x00
- +#define FT5X0X_MODE_SYSINFO 0x10
- +#define FT5X0X_MODE_TEST 0x40
- +#define FT5X0X_MODE_MASK 0x70
- +
- +#define FT5X0X_EVENT_DOWN 0x00
- +#define FT5X0X_EVENT_UP 0x40
- +#define FT5X0X_EVENT_CONTACT 0x80
- +#define FT5X0X_EVENT_MASK 0xc0
- +
- +
- +#define FT5X0X_FIRMWARE_TAIL (-8)
- +#define FT5X0X_FIRMWARE_VERION (-2)
- +#define FT5X46_RD_FLASH_PACKET_SIZE 4
- +#define FT5X0X_PACKET_HEADER 6
- +#define FT5X0X_PACKET_LENGTH 128
- +
- +#define FT5X0X_MAX_PRESSURE 0xff
- +#define FT5X46_PRESSURE 8
- +
- +#define FT5X46_POINT_READ_BUF (3 + FT5X46_TOUCH_LENGTH * FT5X0X_MAX_FINGER)
- +
- +#define NOISE_FILTER_DELAY HZ
- +
- +#define FT_VTG_MIN_UV 2600000
- +#define FT_VTG_MAX_UV 3300000
- +#define FT_I2C_VTG_MIN_UV 1800000
- +#define FT_I2C_VTG_MAX_UV 1800000
- +
- +#define FT5316_UPGRADE_AA_DELAY 50
- +#define FT5316_UPGRADE_55_DELAY 40
- +#define FT5316_UPGRADE_ID_1 0x79
- +#define FT5316_UPGRADE_ID_2 0x07
- +#define FT5316_UPGRADE_READID_DELAY 1
- +
- +#define FT5X36_UPGRADE_AA_DELAY 30
- +#define FT5X36_UPGRADE_55_DELAY 30
- +#define FT5X36_UPGRADE_ID_1 0x79
- +#define FT5X36_UPGRADE_ID_2 0x11
- +#define FT5X36_UPGRADE_READID_DELAY 10
- +
- +#define FT5X46_UPGRADE_AA_DELAY 2
- +#define FT5X46_UPGRADE_55_DELAY 2
- +#define FT5X46_UPGRADE_ID_1 0x54
- +#define FT5X46_UPGRADE_ID_2 0x2C
- +#define FT5X46_UPGRADE_READID_DELAY 20
- +
- +
- +#define FT5316_CHIP_ID 0x0A
- +#define FT5X36_CHIP_ID 0x14
- +#define FT5X46_CHIP_ID 0x54
- +
- +#define FT5316_PROJ_ID "FTS0000x000"
- +#define FT5X36_PROJ_ID "FTS0000P000"
- +
- +#define FT5X0X_UPGRADE_LOOP 3
- +
- +#define BL_VERSION_LZ4 0
- +#define BL_VERSION_Z7 1
- +#define BL_VERSION_GZF 2
- +
- +
- +#ifdef FT5X46_APK_DEBUG_CHANNEL
- +#define FT5X46_PROC_NAME "ftxxxx-debug"
- +
- +#define FT5X46_PROC_UPGRADE 0
- +#define FT5X46_PROC_READ_REGISTER 1
- +#define FT5X46_PROC_WRITE_REGISTER 2
- +#define FT5X46_PROC_AUTOCLB 4
- +#define FT5X46_PROC_UPGRADE_INFO 5
- +#define FT5X46_PROC_WRITE_DATA 6
- +#define FT5X46_PROC_READ_DATA 7
- +
- +#define FT5X46_GESTURE_POINTS_HEADER 8
- +#define FT5X46_GESTURE_UP 0x22
- +#define FT5X46_GESTURE_DBLCLICK 0x24
- +
- +#define FT5X46_INPUT_EVENT_START 0
- +#define FT5X46_INPUT_EVENT_SENSITIVE_MODE_OFF 0
- +#define FT5X46_INPUT_EVENT_SENSITIVE_MODE_ON 1
- +#define FT5X46_INPUT_EVENT_STYLUS_MODE_OFF 2
- +#define FT5X46_INPUT_EVENT_STYLUS_MODE_ON 3
- +#define FT5X46_INPUT_EVENT_WAKUP_MODE_OFF 4
- +#define FT5X46_INPUT_EVENT_WAKUP_MODE_ON 5
- +#define FT5X46_INPUT_EVENT_COVER_MODE_OFF 6
- +#define FT5X46_INPUT_EVENT_COVER_MODE_ON 7
- +#define FT5X46_INPUT_EVENT_END 7
- +
- +#define FT5X46_COVER_REG 0xc1
- +
- +static unsigned char proc_operate_mode = FT5X46_PROC_UPGRADE;
- +static struct proc_dir_entry *ft5x46_proc_entry;
- +#endif
- +
- +struct ft5x46_packet {
- + u8 magic1;
- + u8 magic2;
- + u16 offset;
- + u16 length;
- + u8 payload[FT5X0X_PACKET_LENGTH];
- +};
- +
- +struct ft5x46_rd_flash_packet {
- + u8 magic;
- + u8 addr_h;
- + u8 addr_m;
- + u8 addr_l;
- +};
- +
- +struct ft5x46_finger {
- + int x, y;
- + int size;
- + int pressure;
- + bool detect;
- +};
- +struct ft5x46_mode_switch {
- + struct ft5x46_data *data;
- + u8 mode;
- + struct work_struct switch_mode_work;
- +};
- +
- +static void ft5x46_cover_mode(struct ft5x46_data *ft5x46, bool enable);
- +
- +struct ft5x46_data *ft_data;
- +
- +static int ft5x46_recv_byte(struct ft5x46_data *ft5x46, u8 len, ...)
- +{
- + int error;
- + va_list varg;
- + u8 i, buf[len];
- +
- + error = ft5x46->bops->recv(ft5x46->dev, buf, len);
- + if (error)
- + return error;
- +
- + va_start(varg, len);
- + for (i = 0; i < len; i++)
- + *va_arg(varg, u8 *) = buf[i];
- + va_end(varg);
- +
- + return 0;
- +}
- +
- +static int ft5x46_send_block(struct ft5x46_data *ft5x46,
- + const void *buf, int len)
- +{
- + return ft5x46->bops->send(ft5x46->dev, buf, len);
- +}
- +
- +static int ft5x46_recv_block(struct ft5x46_data *ft5x46,
- + void *buf, int len)
- +{
- + return ft5x46->bops->recv(ft5x46->dev, buf, len);
- +}
- +
- +static int ft5x46_send_byte(struct ft5x46_data *ft5x46, u8 len, ...)
- +{
- + va_list varg;
- + u8 i, buf[len];
- +
- + va_start(varg, len);
- + for (i = 0; i < len; i++)
- + buf[i] = va_arg(varg, int);
- + va_end(varg);
- +
- + return ft5x46_send_block(ft5x46, buf, len);
- +}
- +
- +static int ft5x46_read_block(struct ft5x46_data *ft5x46,
- + u8 addr, void *buf, u8 len)
- +{
- + return ft5x46->bops->read(ft5x46->dev, addr, buf, len);
- +}
- +
- +static int ft5x46_read_byte(struct ft5x46_data *ft5x46, u8 addr, u8 *data)
- +{
- + return ft5x46_read_block(ft5x46, addr, data, sizeof(*data));
- +}
- +
- +static int ft5x46_write_byte(struct ft5x46_data *ft5x46, u8 addr, u8 data)
- +{
- + return ft5x46->bops->write(ft5x46->dev, addr, &data, sizeof(data));
- +}
- +
- +static void ft5x46_charger_state_changed(struct ft5x46_data *ft5x46, bool force_update)
- +{
- + u8 is_usb_exist;
- +
- + is_usb_exist = power_supply_is_system_supplied();
- + if ((is_usb_exist != ft5x46->is_usb_plug_in) || (force_update)) {
- + ft5x46->is_usb_plug_in = is_usb_exist;
- + dev_info(ft5x46->dev, "Power state changed, set noise filter to 0x%x\n", is_usb_exist);
- + mutex_lock(&ft5x46->mutex);
- + ft5x46_write_byte(ft5x46, FT5X0X_NOISE_FILTER, is_usb_exist);
- + mutex_unlock(&ft5x46->mutex);
- + }
- +}
- +
- +static void ft5x46_noise_filter_delayed_work(struct work_struct *work)
- +{
- + struct delayed_work *delayed_work = to_delayed_work(work);
- + struct ft5x46_data *ft5x46 = container_of(delayed_work, struct ft5x46_data, noise_filter_delayed_work);
- +
- + dev_info(ft5x46->dev, "ft5x46_noise_filter_delayed_work called\n");
- + ft5x46_charger_state_changed(ft5x46, true);
- +}
- +
- +static void ft5x46_disable_irq(struct ft5x46_data *ft5x46)
- +{
- + if (likely(ft5x46->irq_enabled)) {
- + disable_irq(ft5x46->irq);
- + ft5x46->irq_enabled = false;
- + }
- +}
- +
- +static void ft5x46_enable_irq(struct ft5x46_data *ft5x46)
- +{
- + if (likely(!ft5x46->irq_enabled)) {
- + enable_irq(ft5x46->irq);
- + ft5x46->irq_enabled = true;
- + }
- +}
- +
- +#ifdef CONFIG_TOUCHSCREEN_FT5X46_CALIBRATE
- +static int ft5x46_auto_calib(struct ft5x46_data *ft5x46)
- +{
- + int error;
- + u8 val1;
- + int i;
- + msleep(200);
- + error = ft5x46_write_byte(ft5x46,
- + FT5X0X_REG_DEVIDE_MODE, FT5X0X_DEVICE_MODE_TEST);
- + if (error)
- + return error;
- + msleep(100);
- +
- + error = ft5x46_write_byte(ft5x46,
- + FT5X0X_REG_START_SCAN, FT5X0X_DEVICE_START_CALIB);
- + if (error)
- + return error;
- + msleep(300);
- +
- + for (i = 0; i < 100; i++) {
- + error = ft5x46_read_byte(ft5x46, FT5X0X_REG_DEVIDE_MODE, &val1);
- + if (error)
- + return error;
- + if (((val1 & 0x70) >> 4) == 0)
- + break;
- + msleep(200);
- + }
- + dev_info(ft5x46->dev, "[FTS] calibration OK.\n");
- +
- + msleep(300);
- + error = ft5x46_write_byte(ft5x46, FT5X0X_REG_DEVIDE_MODE, FT5X0X_DEVICE_MODE_TEST);
- + if (error)
- + return error;
- + msleep(100);
- +
- + error = ft5x46_write_byte(ft5x46,
- + FT5X0X_REG_START_SCAN, FT5X0X_DEVICE_SAVE_RESULT);
- + if (error)
- + return error;
- + msleep(300);
- +
- + error = ft5x46_write_byte(ft5x46,
- + FT5X0X_REG_DEVIDE_MODE, FT5X0X_DEVICE_MODE_NORMAL);
- + if (error)
- + return error;
- + msleep(300);
- + dev_info(ft5x46->dev, "[FTS] Save calib result OK.\n");
- +
- + return 0;
- +}
- +#endif
- +
- +static u8 reset_delay[] = {
- + 30, 33, 36, 39, 42, 45, 27, 24, 11, 18, 15
- +};
- +
- +static int ft5x46_hid_to_std_i2c(struct ft5x46_data *ft5x46)
- +{
- + int error;
- + u8 val1, val2, val3;
- +
- + error = ft5x46_send_byte(ft5x46, 3, 0xEB, 0xAA, 0x09);
- + if (error) {
- + dev_err(ft5x46->dev, "Failed to send EB AA 09\n");
- + return error;
- + }
- +
- + msleep(10);
- + error = ft5x46_recv_byte(ft5x46, 3, &val1, &val2, &val3);
- + if (error) {
- + dev_err(ft5x46->dev, "Failed to receive device id\n");
- + return error;
- + }
- +
- + dev_dbg(ft5x46->dev, "Changed to STDI2C Value: REG1 = 0x%02x, REG2 = 0x%02x, REG3 = 0x%02x\n",
- + val1, val2, val3);
- +
- + if (val1 == 0xEB && val2 == 0xAA && val3 == 0x08) {
- + dev_info(ft5x46->dev, "HidI2c To StdI2c succeed\n");
- + return 0;
- + } else {
- + dev_err(ft5x46->dev, "HidI2c To StdI2c failed\n");
- + return -ENODEV;
- + }
- +}
- +
- +static u8 ft5x46_get_factory_id(struct ft5x46_data *ft5x46)
- +{
- + int error = 0;
- + int i, j;
- + u8 val1, val2;
- + struct ft5x46_rd_flash_packet packet;
- + u8 vid;
- +
- + for (i = 0, error = -1; i < sizeof(reset_delay) && error; i++) {
- + error = ft5x46_write_byte(ft5x46, FT5X0X_REG_RESET, 0xaa);
- + if (error)
- + continue;
- + msleep(50);
- +
- + error = ft5x46_write_byte(ft5x46, FT5X0X_REG_RESET, 0x55);
- + if (error)
- + continue;
- + msleep(200);
- + dev_info(ft5x46->dev, "[FTS] step1: Reset device.\n");
- +
- + if (ft5x46->chip_id != FT5316_CHIP_ID) {
- + error = ft5x46_hid_to_std_i2c(ft5x46);
- + if (error) {
- + dev_err(ft5x46->dev, "HidI2c change to StdI2c fail!\n");
- + }
- + }
- + for (j = 0; j < 10; j++) {
- + error = ft5x46_send_byte(ft5x46, 2, 0x55, 0xaa);
- + msleep(5);
- + if (!error)
- + break;
- + }
- + if (error)
- + continue;
- +
- + dev_info(ft5x46->dev, "[FTS] step2: Enter upgrade mode.\n");
- +
- + error = ft5x46_send_byte(ft5x46, 4, 0x90, 0x00, 0x00, 0x00);
- + if (error) {
- + dev_err(ft5x46->dev, "Failed to send 90 00 00 00\n");
- + continue;
- + }
- +
- + error = ft5x46_recv_byte(ft5x46, 2, &val1, &val2);
- + if (error) {
- + dev_err(ft5x46->dev, "Failed to receive device id\n");
- + continue;
- + }
- +
- + dev_info(ft5x46->dev, "read id = 0x%x, 0x%x\n", val1, val2);
- +
- + dev_info(ft5x46->dev, "[FTS] step3: Check device id.\n");
- +
- + if (val1 == FT5316_UPGRADE_ID_1 && val2 == FT5316_UPGRADE_ID_2) {
- + ft5x46->chip_id = FT5316_CHIP_ID;
- + break;
- + } else if (val1 == FT5X36_UPGRADE_ID_1 && val2 == FT5X36_UPGRADE_ID_2) {
- + ft5x46->chip_id = FT5X36_CHIP_ID;
- + break;
- + } else if (val1 == FT5X46_UPGRADE_ID_1 && val2 == FT5X46_UPGRADE_ID_2) {
- + ft5x46->chip_id = FT5X46_CHIP_ID;
- + break;
- + }
- + }
- +
- + if (error)
- + return error;
- +
- + packet.magic = 0x03;
- + packet.addr_h = 0x00;
- + packet.addr_m = 0xD7;
- + packet.addr_l = 0x84;
- +
- + error = ft5x46_send_block(ft5x46, &packet, FT5X46_RD_FLASH_PACKET_SIZE);
- + if (error)
- + return error;
- + msleep(5);
- +
- + error = ft5x46_recv_byte(ft5x46, 1, &vid);
- + if (error)
- + return error;
- +
- + error = ft5x46_send_byte(ft5x46, 1, 0x07);
- + if (error)
- + return error;
- + msleep(200);
- +
- + return vid;
- +}
- +
- +static void ft5x46_wait_for_ready(struct ft5x46_data *ft5x46,
- + u8 val1, u8 val2, int try_times, int delay_ms)
- +{
- + int i;
- + int error;
- + u8 recv1, recv2;
- + for (i = 0; i < try_times; i++) {
- + error = ft5x46_send_byte(ft5x46, 1, 0x6A);
- + if (error) {
- + dev_err(ft5x46->dev, "write failed\n");
- + return;
- + }
- +
- + error = ft5x46_recv_byte(ft5x46, 2, &recv1, &recv2);
- + if (!error && recv1 == val1 && recv2 == val2) {
- + dev_dbg(ft5x46->dev, "Ready: 0x%02x 0x%02x\n", val1, val2);
- + break;
- + }
- + msleep(delay_ms);
- + }
- +
- + if (i == try_times) {
- + dev_err(ft5x46->dev, "Wait timeout and recv error 0x%02x 0x%02x(0x%02x 0x%02x)\n",
- + recv1, recv2, val1, val2);
- + }
- +}
- +
- +int ft5x06_load_firmware(struct ft5x46_data *ft5x46,
- + struct ft5x46_firmware_data *firmware, bool *upgraded)
- +{
- + int i, j, error = 0;
- + u8 val1, val2, vid, bt_ecc, id;
- + u32 temp;
- + u32 lenght;
- + const struct firmware *fw;
- + int packet_number;
- + u32 dw_lenth;
- + u8 packet_buf[FT5X0X_PACKET_LENGTH + 6];
- + struct ft5x46_ts_platform_data *pdata = ft5x46->dev->platform_data;
- + struct ft5x46_upgrade_info *ui = &pdata->ui;
- +
- + if (upgraded)
- + *upgraded = false;
- +
- + if (firmware == NULL)
- + return 0;
- + error = ft5x46_read_byte(ft5x46, FT5X0X_ID_G_FT5201ID, &vid);
- + if (error)
- + return error;
- +
- + dev_info(ft5x46->dev, "firmware vendor is %02x\n", vid);
- +
- + id = vid;
- + if (vid == FT5X0X_ID_G_FT5201ID ||
- + vid == 0 || ft5x46->chip_id == 0) {
- + vid = ft5x46_get_factory_id(ft5x46);
- + dev_err(ft5x46->dev, "firmware corruption, read real factory id = 0x%x!\n", vid);
- + }
- +
- + for (i = 0; i < pdata->cfg_size; i++, firmware++) {
- + if (vid == firmware->vendor) {
- + if (ft5x46->dev->of_node)
- + if (ft5x46->chip_id == firmware->chip) {
- + dev_info(ft5x46->dev, "chip id = 0x%x, found it!\n",
- + ft5x46->chip_id);
- + ft5x46->current_index = i;
- + break;
- + } else
- + continue;
- + else
- + break;
- + }
- + }
- +
- + if (!ft5x46->dev->of_node && firmware->size == 0) {
- + dev_err(ft5x46->dev, "unknown touch screen vendor, failed!\n");
- + return -ENOENT;
- + } else if (ft5x46->dev->of_node && (i == pdata->cfg_size)) {
- + dev_err(ft5x46->dev, "Failed to find matched config!\n");
- + ft5x46->current_index = 0;
- + firmware->fwname = "ft5216_biel.fw";
- + }
- +
- + if (firmware->size == 0 && ft5x46->dev->of_node) {
- + dev_info(ft5x46->dev, "firmware name = %s\n", firmware->fwname);
- + error = request_firmware(&fw, firmware->fwname, ft5x46->dev);
- + if (!error) {
- + firmware->data = kmalloc((int)fw->size, GFP_KERNEL);
- + if (!firmware->data) {
- + dev_err(ft5x46->dev, "Failed to allocate firmware!\n");
- + return -ENOMEM;
- + } else {
- + memcpy(firmware->data, fw->data, (int)fw->size);
- + firmware->size = (int)fw->size;
- + }
- + release_firmware(fw);
- + } else {
- + dev_err(ft5x46->dev, "Cannot find firmware %s\n", firmware->fwname);
- + return -ENODEV;
- + }
- + }
- +
- +
- + error = ft5x46_read_byte(ft5x46, FT5X0X_REG_FW_VER, &id);
- + if (error)
- + return error;
- + dev_info(ft5x46->dev, "firmware version is %02x\n", id);
- +
- + if (id == firmware->data[firmware->size + FT5X0X_FIRMWARE_VERION])
- + return 0;
- + dev_info(ft5x46->dev, "upgrade firmware to %02x\n",
- + firmware->data[firmware->size + FT5X0X_FIRMWARE_VERION]);
- + dev_info(ft5x46->dev, "[FTS] step1: check fw id\n");
- +
- + for (i = 0, error = -1; i < sizeof(reset_delay) && error; i++) {
- + error = ft5x46_write_byte(ft5x46, FT5X0X_REG_RESET, 0xaa);
- + if (error)
- + continue;
- + msleep(ui->delay_aa);
- +
- + error = ft5x46_write_byte(ft5x46, FT5X0X_REG_RESET, 0x55);
- + msleep(ui->delay_55);
- + if (error)
- + continue;
- + msleep(reset_delay[i]);
- + dev_info(ft5x46->dev, "[FTS] step2: Reset device.\n");
- + msleep(10);
- +
- + for (j = 0; j < 10; j++) {
- + error = ft5x46_send_byte(ft5x46, 2, 0x55, 0xaa);
- + msleep(5);
- + if (!error)
- + break;
- + }
- + if (error)
- + continue;
- +
- + dev_info(ft5x46->dev, "[FTS] step3: Enter upgrade mode.\n");
- +
- + error = ft5x46_send_byte(ft5x46, 4, 0x90, 0x00, 0x00, 0x00);
- + if (error) {
- + dev_err(ft5x46->dev, "Failed to send 90 00 00 00\n");
- + continue;
- + }
- +
- + error = ft5x46_recv_byte(ft5x46, 2, &val1, &val2);
- + if (error) {
- + dev_err(ft5x46->dev, "Failed to receive device id\n");
- + continue;
- + }
- +
- + dev_info(ft5x46->dev, "read id = 0x%x, 0x%x, id = 0x%x, 0x%x\n", val1, val2,
- + ui->upgrade_id_1, ui->upgrade_id_2);
- + if (val1 != ui->upgrade_id_1 || val2 != ui->upgrade_id_2)
- + error = -ENODEV;
- +
- + dev_info(ft5x46->dev, "[FTS] step4: Check device id.\n");
- + }
- +
- + if (error)
- + return error;
- +
- + error = ft5x46_send_byte(ft5x46, 1, 0xcd);
- + if (error)
- + return error;
- + error = ft5x46_recv_byte(ft5x46, 1, &val1);
- + if (error)
- + return error;
- + dev_info(ft5x46->dev, "[FTS] bootloader version is 0x%x\n", val1);
- +
- + dev_info(ft5x46->dev, "[FTS] step5: Erase device.\n");
- + error = ft5x46_send_byte(ft5x46, 1, 0x61);
- + if (error)
- + return error;
- + msleep(ui->delay_erase);
- + error = ft5x46_send_byte(ft5x46, 1, 0x63);
- + if (error)
- + return error;
- + msleep(100);
- +
- + /*********Step 5:write firmware(FW) to ctpm flash*********/
- + bt_ecc = 0;
- +
- + dw_lenth = firmware->size - 8;
- + packet_number = (dw_lenth) / FT5X0X_PACKET_LENGTH;
- + packet_buf[0] = 0xBF;
- + packet_buf[1] = 0x00;
- + for (j = 0; j < packet_number; j++) {
- + temp = j * FT5X0X_PACKET_LENGTH;
- + packet_buf[2] = (u8) (temp >> 8);
- + packet_buf[3] = (u8) temp;
- + lenght = FT5X0X_PACKET_LENGTH;
- + packet_buf[4] = (u8) (lenght >> 8);
- + packet_buf[5] = (u8) lenght;
- + for (i = 0; i < FT5X0X_PACKET_LENGTH; i++) {
- + packet_buf[6 + i] = firmware->data[j * FT5X0X_PACKET_LENGTH + i];
- + bt_ecc ^= packet_buf[6 + i];
- + }
- + ft5x46_send_block(ft5x46, packet_buf, FT5X0X_PACKET_LENGTH + 6);
- + msleep(FT5X0X_PACKET_LENGTH / 6 + 1);
- + }
- + if ((dw_lenth) % FT5X0X_PACKET_LENGTH > 0) {
- + temp = packet_number * FT5X0X_PACKET_LENGTH;
- + packet_buf[2] = (u8) (temp >> 8);
- + packet_buf[3] = (u8) temp;
- + temp = (dw_lenth) % FT5X0X_PACKET_LENGTH;
- + packet_buf[4] = (u8) (temp >> 8);
- + packet_buf[5] = (u8) temp;
- + for (i = 0; i < temp; i++) {
- + packet_buf[6 + i] = firmware->data[packet_number * FT5X0X_PACKET_LENGTH + i];
- + bt_ecc ^= packet_buf[6 + i];
- + }
- +
- + ft5x46_send_block(ft5x46, packet_buf, temp + 6);
- + msleep(20);
- + }
- + /*send the last six byte */
- + for (i = 0; i < 6; i++) {
- + temp = 0x6ffa + i;
- + packet_buf[2] = (u8) (temp >> 8);
- + packet_buf[3] = (u8) temp;
- + temp = 1;
- + packet_buf[4] = (u8) (temp >> 8);
- + packet_buf[5] = (u8) temp;
- + packet_buf[6] = firmware->data[dw_lenth + i];
- + bt_ecc ^= packet_buf[6];
- + ft5x46_send_block(ft5x46, packet_buf, 7);
- + msleep(20);
- + }
- +
- + /*********Step 6: read out checksum***********************/
- + /*send the opration head */
- + dev_info(ft5x46->dev, "Step 6: read out checksum\n");
- + error = ft5x46_read_byte(ft5x46, 0xcc, &val1);
- + if (val1 != bt_ecc) {
- + dev_err(ft5x46->dev, "--ecc error! FW=%02x bt_ecc=%02x\n",
- + val1, bt_ecc);
- + return -EIO;
- + }
- + /*********Step 7: reset the new FW***********************/
- + dev_info(ft5x46->dev, "Step 7: reset the new FW\n");
- + error = ft5x46_send_byte(ft5x46, 1, 0x07);
- + msleep(300);
- + if (upgraded)
- + *upgraded = true;
- +
- + return 0;
- +}
- +
- +static int ft5x46_load_firmware(struct ft5x46_data *ft5x46,
- + struct ft5x46_firmware_data *firmware, bool *upgraded)
- +{
- + struct ft5x46_packet packet;
- + int i, j, length, error = 0;
- + u8 val1, val2, vid, ecc = 0, id;
- +#ifdef CONFIG_TOUCHSCREEN_FT5X46_CALIBRATE
- + const int max_calib_time = 3;
- + bool calib_ok = false;
- +#endif
- + bool is_5336_fwsize_30 = false;
- + const struct firmware *fw;
- + int packet_num;
- + struct ft5x46_ts_platform_data *pdata = ft5x46->dev->platform_data;
- + struct ft5x46_upgrade_info *ui = &pdata->ui;
- +
- + /* step 0a: check and init argument */
- + if (upgraded)
- + *upgraded = false;
- +
- + if (firmware == NULL)
- + return 0;
- +
- + error = ft5x46_hid_to_std_i2c(ft5x46);
- + if (error) {
- + dev_err(ft5x46->dev, "HidI2c change to StdI2c fail!\n");
- + }
- +
- + /* step 0b: find the right firmware for touch screen */
- + error = ft5x46_read_byte(ft5x46, FT5X0X_ID_G_FT5201ID, &vid);
- + if (error)
- + return error;
- +
- + dev_info(ft5x46->dev, "firmware vendor is %02x\n", vid);
- +
- + id = vid;
- + if (vid == FT5X0X_ID_G_FT5201ID ||
- + vid == 0 || ft5x46->chip_id == 0) {
- + vid = ft5x46_get_factory_id(ft5x46);
- + dev_err(ft5x46->dev, "firmware corruption, read real factory id = 0x%x!\n", vid);
- + }
- +
- + for (i = 0; i < pdata->cfg_size; i++, firmware++) {
- + if (vid == firmware->vendor) {
- + if (ft5x46->dev->of_node)
- + if (ft5x46->chip_id == firmware->chip) {
- + dev_info(ft5x46->dev, "chip id = 0x%x, found it!\n",
- + ft5x46->chip_id);
- + ft5x46->current_index = i;
- + break;
- + } else
- + continue;
- + else
- + break;
- + }
- + }
- +
- + if (!ft5x46->dev->of_node && firmware->size == 0) {
- + dev_err(ft5x46->dev, "unknown touch screen vendor, failed!\n");
- + return -ENOENT;
- + } else if (ft5x46->dev->of_node && (i == pdata->cfg_size)) {
- + dev_err(ft5x46->dev, "Failed to find matched config!\n");
- + return -ENOENT;
- + }
- +
- + if (firmware->size == 0 && ft5x46->dev->of_node) {
- + dev_info(ft5x46->dev, "firmware name = %s\n", firmware->fwname);
- + error = request_firmware(&fw, firmware->fwname, ft5x46->dev);
- + if (!error) {
- + firmware->data = kmalloc((int)fw->size, GFP_KERNEL);
- + if (!firmware->data) {
- + dev_err(ft5x46->dev, "Failed to allocate firmware!\n");
- + return -ENOMEM;
- + } else {
- + memcpy(firmware->data, fw->data, (int)fw->size);
- + firmware->size = (int)fw->size;
- + }
- + release_firmware(fw);
- + } else {
- + dev_err(ft5x46->dev, "Cannot find firmware %s\n", firmware->fwname);
- + return -ENODEV;
- + }
- + }
- +
- + if (firmware->data[firmware->size - 12] == 30)
- + is_5336_fwsize_30 = true;
- + else
- + is_5336_fwsize_30 = false;
- +
- + /* step 1: check firmware id is different */
- + error = ft5x46_read_byte(ft5x46, FT5X0X_REG_FW_VER, &id);
- + if (error)
- + return error;
- + dev_info(ft5x46->dev, "firmware version is %02x\n", id);
- +
- + if (id == firmware->data[firmware->size + FT5X0X_FIRMWARE_VERION])
- + return 0;
- + dev_info(ft5x46->dev, "upgrade firmware to %02x\n",
- + firmware->data[firmware->size + FT5X0X_FIRMWARE_VERION]);
- + dev_info(ft5x46->dev, "[FTS] step1: check fw id\n");
- +
- + for (i = 0, error = -1; i < sizeof(reset_delay) && error; i++) {
- + /* step 2: reset device */
- + error = ft5x46_write_byte(ft5x46, FT5X0X_REG_RESET, 0xaa);
- + if (error)
- + continue;
- + msleep(ui->delay_aa);
- +
- + error = ft5x46_write_byte(ft5x46, FT5X0X_REG_RESET, 0x55);
- + if (error)
- + continue;
- + msleep(reset_delay[i]);
- + dev_info(ft5x46->dev, "[FTS] step2: Reset device.\n");
- +
- + error = ft5x46_hid_to_std_i2c(ft5x46);
- + if (error) {
- + dev_err(ft5x46->dev, "HidI2c change to StdI2c fail!\n");
- + }
- + msleep(10);
- +
- + for (j = 0; j < 10; j++) {
- + error = ft5x46_send_byte(ft5x46, 2, 0x55, 0xaa);
- + msleep(5);
- + if (!error)
- + break;
- + }
- + if (error)
- + continue;
- +
- + dev_info(ft5x46->dev, "[FTS] step3: Enter upgrade mode.\n");
- +
- + /* step 4: check device id */
- + error = ft5x46_send_byte(ft5x46, 4, 0x90, 0x00, 0x00, 0x00);
- + if (error) {
- + dev_err(ft5x46->dev, "Failed to send 90 00 00 00\n");
- + continue;
- + }
- +
- + error = ft5x46_recv_byte(ft5x46, 2, &val1, &val2);
- + if (error) {
- + dev_err(ft5x46->dev, "Failed to receive device id\n");
- + continue;
- + }
- +
- + dev_info(ft5x46->dev, "read id = 0x%x, 0x%x, id = 0x%x, 0x%x\n", val1, val2,
- + ui->upgrade_id_1, ui->upgrade_id_2);
- + if (val1 != ui->upgrade_id_1 || val2 != ui->upgrade_id_2)
- + error = -ENODEV;
- +
- + dev_info(ft5x46->dev, "[FTS] step4: Check device id.\n");
- + }
- +
- + if (error) /* check the final result */
- + return error;
- +
- + error = ft5x46_send_byte(ft5x46, 1, 0xcd);
- + if (error)
- + return error;
- + error = ft5x46_recv_byte(ft5x46, 1, &val1);
- + if (error)
- + return error;
- + dev_info(ft5x46->dev, "[FTS] bootloader version is 0x%x\n", val1);
- +
- + /* step 5: erase device */
- + error = ft5x46_send_byte(ft5x46, 1, 0x61);
- + if (error)
- + return error;
- + msleep(1500);
- + if (0) {
- + if (is_5336_fwsize_30) {
- + error = ft5x46_send_byte(ft5x46, 1, 0x63);
- + if (error)
- + return error;
- + msleep(50);
- + }
- + }
- + ft5x46_wait_for_ready(ft5x46, 0xF0, 0xAA, 15, 50);
- +
- + /* Write firmware file length to bootloader */
- + error = ft5x46_send_byte(ft5x46, 4, 0xB0,
- + (u8)((firmware->size >> 16) & 0xFF),
- + (u8)((firmware->size >> 8) & 0xFF),
- + (u8)(firmware->size & 0xFF));
- +
- + dev_info(ft5x46->dev, "[FTS] step5: Erase device.\n");
- +
- + /* step 6: flash firmware to device */
- +
- + /* step 6a: send data in 128 bytes chunk each time */
- + packet.magic1 = 0xbf;
- + packet.magic2 = 0x00;
- + packet_num = firmware->size / FT5X0X_PACKET_LENGTH;
- +
- + for (i = 0; i < packet_num ; i++) {
- + length = FT5X0X_PACKET_LENGTH;
- + packet.offset = cpu_to_be16(i * FT5X0X_PACKET_LENGTH);
- + packet.length = cpu_to_be16(length);
- +
- + for (j = 0; j < length; j++) {
- + packet.payload[j] = firmware->data[i * FT5X0X_PACKET_LENGTH + j];
- + ecc ^= firmware->data[i * FT5X0X_PACKET_LENGTH + j];
- + }
- +
- + error = ft5x46_send_block(ft5x46, &packet,
- + FT5X0X_PACKET_HEADER + length);
- + if (error)
- + return error;
- +
- + ft5x46_wait_for_ready(ft5x46, (u8)((0x1000 + i) >> 8), (u8)((0x1000 + i) & 0xFF), 30, 1);
- + }
- + dev_info(ft5x46->dev, "[FTS] step6a: Send data in 128 bytes chunk each time.\n");
- +
- + /* step 6b: send the last bytes */
- + if (firmware->size % FT5X0X_PACKET_LENGTH > 0) {
- + length = firmware->size % FT5X0X_PACKET_LENGTH;
- +
- + packet.offset = cpu_to_be16(packet_num * FT5X0X_PACKET_LENGTH);
- + packet.length = cpu_to_be16(length);
- +
- + for (j = 0; j < length; j++) {
- + packet.payload[j] = firmware->data[packet_num * FT5X0X_PACKET_LENGTH + j];
- + ecc ^= firmware->data[packet_num * FT5X0X_PACKET_LENGTH + j];
- + }
- +
- + error = ft5x46_send_block(ft5x46, &packet,
- + FT5X0X_PACKET_HEADER + length);
- + if (error)
- + return error;
- + ft5x46_wait_for_ready(ft5x46, (u8)((0x1000 + i) >> 8), (u8)((0x1000 + i) & 0xFF), 30, 1);
- + }
- + dev_info(ft5x46->dev, "[FTS] step6b: Send the last bytes.\n");
- +
- + msleep(100);
- +
- + /* step 7: verify checksum */
- + error = ft5x46_send_byte(ft5x46, 1, 0x64);
- + if (error)
- + return error;
- + msleep(300);
- +
- + error = ft5x46_send_byte(ft5x46, 6, 0x65, 0, 0, 0,
- + (u8)((firmware->size >> 8) & 0xFF),
- + (u8)(firmware->size & 0xFF));
- + if (error)
- + return error;
- + msleep(300);
- +
- + ft5x46_wait_for_ready(ft5x46, 0xF0, 0x55, 10, 10);
- +
- + error = ft5x46_send_byte(ft5x46, 1, 0x66);
- + if (error)
- + return error;
- +
- + error = ft5x46_recv_byte(ft5x46, 1, &val1);
- + if (error)
- + return error;
- +
- + if (val1 != ecc) {
- + dev_err(ft5x46->dev, "ECC error! CHIP=%02x, FW=%02x",
- + val1, ecc);
- + return -ERANGE;
- + }
- + dev_info(ft5x46->dev, "[FTS] step7: Verify checksum.\n");
- +
- + /* step 8: reset to new firmware */
- + error = ft5x46_send_byte(ft5x46, 1, 0x07);
- + if (error)
- + return error;
- + msleep(300);
- + dev_info(ft5x46->dev, "[FTS] step8: Reset to new firmware.\n");
- +
- + error = ft5x46_hid_to_std_i2c(ft5x46);
- + if (error) {
- + dev_err(ft5x46->dev, "[FTS] Change to StdI2C failed\n");
- + }
- +
- +#ifdef CONFIG_TOUCHSCREEN_FT5X46_CALIBRATE
- + /* step 9: calibrate the reference value */
- + for (i = 0; i < max_calib_time; i++) {
- + error = ft5x46_auto_calib(ft5x46);
- + if (!error) {
- + calib_ok = true;
- + dev_info(ft5x46->dev, "[FTS] step9: Calibrate the ref value successfully.\n");
- + break;
- + }
- + }
- + if (!calib_ok) {
- + dev_info(ft5x46->dev, "[FTS] step9: Calibrate the ref value failed.\n");
- + return error;
- + }
- +#endif
- +
- + if (upgraded)
- + *upgraded = true;
- +
- + return 0;
- +}
- +
- +static int ft5x46_read_touchdata(struct ft5x46_data *ft5x46)
- +{
- + struct ft5x46_ts_event *event = &ft5x46->event;
- + u8 buf[FT5X46_POINT_READ_BUF] = {0};
- + int i, ret;
- + u8 point_id;
- + u16 xh, xl, yh, yl;
- +
- + ret = ft5x46_read_block(ft5x46, 0,
- + buf, FT5X46_POINT_READ_BUF);
- + if (ret < 0) {
- + dev_err(ft5x46->dev, "read touchdata failed\n");
- + return ret;
- + }
- +
- + memset(event, 0, sizeof(struct ft5x46_ts_event));
- +
- + for (i = 0; i < FT5X0X_MAX_FINGER; i++) {
- + point_id = (buf[FT5X46_TOUCH_LENGTH * i + FT5X46_ID_POS]) >> 4;
- + if (point_id >= FT5X46_MAX_ID)
- + break;
- + else
- + event->touch_point++;
- +
- + xh = (u16)(buf[FT5X46_TOUCH_LENGTH * i + FT5X46_XH_POS] & 0x0F);
- + xl = (u16)(buf[FT5X46_TOUCH_LENGTH * i + FT5X46_XL_POS] & 0xFF);
- +
- + yh = (u16)(buf[FT5X46_TOUCH_LENGTH * i + FT5X46_YH_POS] & 0x0F);
- + yl = (u16)(buf[FT5X46_TOUCH_LENGTH * i + FT5X46_YL_POS] & 0xFF);
- +
- + event->x[i] = (xh << 8) | xl;
- + event->y[i] = (yh << 8) | yl;
- + event->touch_event[i] = buf[FT5X46_TOUCH_LENGTH * i + FT5X46_EVENT_POS] >> 6;
- + event->finger_id[i] = buf[FT5X46_TOUCH_LENGTH * i + FT5X46_ID_POS] >> 4;
- +
- + pr_debug("[FINGER %d]: id = %d, event = %d, x = %d, y = %d\n",
- + i, event->finger_id[i], event->touch_event[i],
- + event->x[i], event->y[i]);
- + }
- +
- + event->pressure = FT5X46_DEF_PRESSURE;
- +
- + return 0;
- +}
- +
- +static void ft5x46_clear_touch_event(struct ft5x46_data *ft5x46)
- +{
- + struct ft5x46_ts_event *event = &ft5x46->event;
- + int i;
- +
- + for (i = 0; i < FT5X0X_MAX_FINGER; i++) {
- + input_mt_slot(ft5x46->input, i);
- + input_mt_report_slot_state(ft5x46->input, MT_TOOL_FINGER, false);
- + }
- +
- + memset(event, 0, sizeof(struct ft5x46_ts_event));
- + ft5x46->touchs = 0;
- +
- + input_report_key(ft5x46->input, BTN_TOUCH, 0);
- + input_sync(ft5x46->input);
- +}
- +
- +static void ft5x46_report_key(struct ft5x46_data *ft5x46, int x_pos, bool down)
- +{
- + switch (x_pos) {
- + case 200:
- + input_report_key(ft5x46->input, KEY_MENU, (int)down);
- + down ? ft5x46->keys |= 0x01 : ft5x46->keys & 0xfe;
- + break;
- + case 500:
- + input_report_key(ft5x46->input, KEY_HOME, (int)down);
- + down ? ft5x46->keys |= 0x02 : ft5x46->keys & 0xfd;
- + break;
- + case 800:
- + input_report_key(ft5x46->input, KEY_BACK, (int)down);
- + down ? ft5x46->keys |= 0x04 : ft5x46->keys & 0xfb;
- + break;
- + default:
- + break;
- + }
- +}
- +
- +static void ft5x46_report_value(struct ft5x46_data *ft5x46)
- +{
- + struct ft5x46_ts_event *event = &ft5x46->event;
- + int i;
- + int up_point = 0;
- + int touchs = 0;
- + int finger_num = 0;
- +
- + for (i = 0; i < event->touch_point; i++) {
- + if (event->y[i] == 2000) {
- + finger_num++;
- +
- + if (event->touch_event[i] == 0 || event->touch_event[i] == 2)
- + ft5x46_report_key(ft5x46, event->x[i], true);
- + else
- + ft5x46_report_key(ft5x46, event->x[i], false);
- + } else {
- + input_mt_slot(ft5x46->input, event->finger_id[i]);
- +
- + if (event->touch_event[i] == 0 || event->touch_event[i] == 2) {
- + input_mt_report_slot_state(ft5x46->input, MT_TOOL_FINGER, true);
- + input_report_abs(ft5x46->input, ABS_MT_PRESSURE, event->pressure);
- + input_report_abs(ft5x46->input, ABS_MT_TOUCH_MAJOR, event->pressure);
- + input_report_abs(ft5x46->input, ABS_MT_POSITION_X, event->x[i]);
- + input_report_abs(ft5x46->input, ABS_MT_POSITION_Y, event->y[i]);
- +
- + touchs |= BIT(event->finger_id[i]);
- + ft5x46->touchs |= BIT(event->finger_id[i]);
- + } else {
- + up_point++;
- + input_mt_report_slot_state(ft5x46->input, MT_TOOL_FINGER, false);
- +
- + ft5x46->touchs &= ~BIT(event->finger_id[i]);
- + }
- + }
- + }
- +
- +
- + for (i = 0; i < FT5X0X_MAX_FINGER; i++) {
- + if (BIT(i) & (ft5x46->touchs ^ touchs)) {
- + ft5x46->touchs &= ~BIT(i);
- + input_mt_slot(ft5x46->input, i);
- + input_mt_report_slot_state(ft5x46->input, MT_TOOL_FINGER, false);
- + }
- + }
- +
- + event->touch_point -= finger_num;
- +
- + if (event->touch_point == up_point) {
- + ft5x46->touchs = 0;
- + input_report_key(ft5x46->input, BTN_TOUCH, 0);
- + } else {
- + if (ft5x46->keys & 0x01)
- + input_report_key(ft5x46->input, KEY_MENU, 0);
- + if (ft5x46->keys & 0x02)
- + input_report_key(ft5x46->input, KEY_HOME, 0);
- + if (ft5x46->keys & 0x04)
- + input_report_key(ft5x46->input, KEY_BACK, 0);
- +
- + ft5x46->keys = 0;
- +
- + input_report_key(ft5x46->input, BTN_TOUCH, (event->touch_point > 0));
- + }
- +
- + input_sync(ft5x46->input);
- +}
- +
- +static int ft5x46_read_gesture(struct ft5x46_data *ft5x46)
- +{
- + unsigned char buf[FT5X46_GESTURE_POINTS_HEADER] = { 0 };
- + int error;
- +
- + error = ft5x46_read_block(ft5x46, 0xD3, buf,
- + FT5X46_GESTURE_POINTS_HEADER);
- + if (error) {
- + dev_err(ft5x46->dev, "Error reading GESTURE_COOR\n");
- + return error;
- + }
- +
- + dev_info(ft5x46->dev, "Gesture ID = %d, Point num = %d\n", buf[0],
- + buf[1]);
- +
- + if (buf[0] == FT5X46_GESTURE_UP || buf[0] == FT5X46_GESTURE_DBLCLICK) {
- + dev_info(ft5x46->dev, "input report key wakeup\n");
- + input_event(ft5x46->input, EV_KEY, KEY_WAKEUP, 1);
- + input_sync(ft5x46->input);
- + input_event(ft5x46->input, EV_KEY, KEY_WAKEUP, 0);
- + input_sync(ft5x46->input);
- + }
- +
- + return 0;
- +}
- +
- +static int ft5x46_wakeup_reconfigure(struct ft5x46_data *ft5x46, bool enable)
- +{
- + struct ft5x46_ts_platform_data *pdata = ft5x46->dev->platform_data;
- + int error = 0;
- +
- + mutex_lock(&ft5x46->mutex);
- +
- + gpio_set_value(pdata->reset_gpio, 0);
- + mdelay(5);
- + gpio_set_value(pdata->reset_gpio, 1);
- + mdelay(200);
- +
- + if (enable) {
- + error = ft5x46_write_byte(ft5x46, 0xD0, 0x01);
- + error |= ft5x46_write_byte(ft5x46, 0xD1, 0x14);
- + } else {
- + error = ft5x46_write_byte(ft5x46,
- + FT5X0X_ID_G_PMODE, FT5X0X_POWER_HIBERNATE);
- + }
- +
- + mutex_unlock(&ft5x46->mutex);
- +
- + if (enable)
- + ft5x46_enable_irq(ft5x46);
- + else
- + ft5x46_disable_irq(ft5x46);
- +
- + return error;
- +}
- +
- +static irqreturn_t ft5x46_interrupt(int irq, void *dev_id)
- +{
- + struct ft5x46_data *ft5x46 = dev_id;
- + int error = 0;
- + u8 val = 0;
- +
- + mutex_lock(&ft5x46->mutex);
- +
- + if (ft5x46->wakeup_mode && ft5x46->in_suspend) {
- + error = ft5x46_read_byte(ft5x46, 0xD0, &val);
- + if (error)
- + dev_err(ft5x46->dev, "Error reading register 0xD0\n");
- + else
- + if (val == 1) {
- + error = ft5x46_read_gesture(ft5x46);
- + if (error)
- + dev_err(ft5x46->dev, "Failed to read wakeup gesture\n");
- + } else
- + dev_err(ft5x46->dev, "Chip is in suspend, but wakeup gesture is not enabled.\n");
- +
- + goto out;
- + }
- +
- + error = ft5x46_read_touchdata(ft5x46);
- + if (!error) {
- + ft5x46_report_value(ft5x46);
- + }
- +
- +out:
- + mutex_unlock(&ft5x46->mutex);
- + return IRQ_HANDLED;
- +}
- +
- +int ft5x46_suspend(struct ft5x46_data *ft5x46)
- +{
- + int error = 0;
- +
- + if (!ft5x46->wakeup_mode)
- + ft5x46_disable_irq(ft5x46);
- +
- + mutex_lock(&ft5x46->mutex);
- +
- + if (ft5x46->in_suspend)
- + goto out;
- +
- + ft5x46_clear_touch_event(ft5x46);
- + mutex_unlock(&ft5x46->mutex);
- +
- + cancel_delayed_work_sync(&ft5x46->noise_filter_delayed_work);
- +
- + mutex_lock(&ft5x46->mutex);
- + if (ft5x46->wakeup_mode) {
- + dev_info(ft5x46->dev, "enter wakeup gesture mode\n");
- + error = ft5x46_write_byte(ft5x46, 0xD0, 0x01);
- + error |= ft5x46_write_byte(ft5x46, 0xD1, 0x14);
- + } else {
- + error = ft5x46_write_byte(ft5x46,
- + FT5X0X_ID_G_PMODE, FT5X0X_POWER_HIBERNATE);
- + }
- + ft5x46->in_suspend = true;
- +
- +out:
- + mutex_unlock(&ft5x46->mutex);
- + return error;
- +}
- +EXPORT_SYMBOL_GPL(ft5x46_suspend);
- +
- +int ft5x46_resume(struct ft5x46_data *ft5x46)
- +{
- + struct ft5x46_ts_platform_data *pdata = ft5x46->dev->platform_data;
- +
- + if (ft5x46->wakeup_mode)
- + ft5x46_disable_irq(ft5x46);
- +
- + mutex_lock(&ft5x46->mutex);
- +
- + if (!ft5x46->in_suspend)
- + goto out;
- +
- + gpio_set_value(pdata->reset_gpio, 0);
- + mdelay(5);
- + gpio_set_value(pdata->reset_gpio, 1);
- + mdelay(5);
- +
- + mutex_unlock(&ft5x46->mutex);
- +
- + schedule_delayed_work(&ft5x46->noise_filter_delayed_work,
- + NOISE_FILTER_DELAY);
- +
- + mutex_lock(&ft5x46->mutex);
- + ft5x46->in_suspend = false;
- +
- +out:
- + mutex_unlock(&ft5x46->mutex);
- +
- + if (ft5x46->cover_mode) {
- + msleep(100);
- + ft5x46_cover_mode(ft5x46, ft5x46->cover_mode);
- + }
- +
- + ft5x46_enable_irq(ft5x46);
- +
- + return 0;
- +}
- +EXPORT_SYMBOL_GPL(ft5x46_resume);
- +
- +#ifdef CONFIG_HAS_EARLYSUSPEND
- +static void ft5x46_early_suspend(struct early_suspend *h)
- +{
- + struct ft5x46_data *ft5x46 = container_of(h,
- + struct ft5x46_data, early_suspend);
- + ft5x46_suspend(ft5x46);
- +}
- +
- +static void ft5x46_early_resume(struct early_suspend *h)
- +{
- + struct ft5x46_data *ft5x46 = container_of(h,
- + struct ft5x46_data, early_suspend);
- + ft5x46_resume(ft5x46);
- +}
- +#else
- +static int ft5x46_input_disable(struct input_dev *in_dev)
- +{
- + struct ft5x46_data *ft5x46 = input_get_drvdata(in_dev);
- +
- + dev_info(ft5x46->dev, "ft5x46 disable!\n");
- + ft5x46_suspend(ft5x46);
- +
- + return 0;
- +}
- +
- +static int ft5x46_input_enable(struct input_dev *in_dev)
- +{
- + struct ft5x46_data *ft5x46 = input_get_drvdata(in_dev);
- +
- + dev_dbg(ft5x46->dev, "ft5x46 enable!\n");
- + ft5x46_resume(ft5x46);
- +
- + return 0;
- +}
- +#endif
- +
- +static ssize_t ft5x46_vkeys_show(struct kobject *kobj,
- + struct kobj_attribute *attr, char *buf)
- +{
- + return snprintf(buf, PAGE_SIZE,
- + __stringify(EV_KEY) ":" __stringify(KEY_MENU) ":200:2000:10:10:"
- + __stringify(EV_KEY) ":" __stringify(KEY_HOME) ":500:2000:10:10:"
- + __stringify(EV_KEY) ":" __stringify(KEY_BACK) ":800:2000:10:10"
- + "\n");
- +}
- +
- +static int ft5x46_get_lockdown_info(struct ft5x46_data *ft5x46)
- +{
- + int error = 0;
- + int i, j;
- + u8 val1, val2;
- + struct ft5x46_rd_flash_packet packet;
- +
- + for (i = 0, error = -1; i < sizeof(reset_delay) && error; i++) {
- + error = ft5x46_write_byte(ft5x46, FT5X0X_REG_RESET, 0xaa);
- + if (error)
- + continue;
- + msleep(50);
- +
- + error = ft5x46_write_byte(ft5x46, FT5X0X_REG_RESET, 0x55);
- + if (error)
- + continue;
- + msleep(200);
- + dev_info(ft5x46->dev, "[FTS] step1: Reset device.\n");
- + error = ft5x46_hid_to_std_i2c(ft5x46);
- + if (error) {
- + dev_err(ft5x46->dev, "HidI2c change to StdI2c fail!\n");
- + }
- + for (j = 0; j < 10; j++) {
- + error = ft5x46_send_byte(ft5x46, 2, 0x55, 0xaa);
- + msleep(5);
- + if (!error)
- + break;
- + }
- + if (error)
- + continue;
- +
- + dev_info(ft5x46->dev, "[FTS] step2: Enter upgrade mode.\n");
- +
- + error = ft5x46_send_byte(ft5x46, 4, 0x90, 0x00, 0x00, 0x00);
- + if (error) {
- + dev_err(ft5x46->dev, "Failed to send 90 00 00 00\n");
- + continue;
- + }
- +
- + error = ft5x46_recv_byte(ft5x46, 2, &val1, &val2);
- + if (error) {
- + dev_err(ft5x46->dev, "Failed to receive device id\n");
- + continue;
- + }
- +
- + dev_info(ft5x46->dev, "read id = 0x%x, 0x%x\n", val1, val2);
- +
- + dev_info(ft5x46->dev, "[FTS] step3: Check device id.\n");
- +
- + if (val1 == FT5316_UPGRADE_ID_1 && val2 == FT5316_UPGRADE_ID_2) {
- + ft5x46->chip_id = FT5316_CHIP_ID;
- + break;
- + } else if (val1 == FT5X36_UPGRADE_ID_1 && val2 == FT5X36_UPGRADE_ID_2) {
- + ft5x46->chip_id = FT5X36_CHIP_ID;
- + break;
- + } else if (val1 == FT5X46_UPGRADE_ID_1 && val2 == FT5X46_UPGRADE_ID_2) {
- + ft5x46->chip_id = FT5X46_CHIP_ID;
- + break;
- + }
- + }
- +
- + if (error)
- + return error;
- +
- + packet.magic = 0x03;
- + packet.addr_h = 0x00;
- + packet.addr_m = 0xD7;
- + packet.addr_l = 0xA0;
- +
- + error = ft5x46_send_block(ft5x46, &packet, FT5X46_RD_FLASH_PACKET_SIZE);
- + msleep(5);
- + error = ft5x46_recv_byte(ft5x46, 8,
- + &ft5x46->lockdown_info[0], &ft5x46->lockdown_info[1],
- + &ft5x46->lockdown_info[2], &ft5x46->lockdown_info[3],
- + &ft5x46->lockdown_info[4], &ft5x46->lockdown_info[5],
- + &ft5x46->lockdown_info[6], &ft5x46->lockdown_info[7]);
- +
- + for (i = 0; i < 8; i++)
- + dev_info(ft5x46->dev, "Lockdown[%d] val = 0x%x\n", i, ft5x46->lockdown_info[i]);
- +
- + error = ft5x46_send_byte(ft5x46, 1, 0x07);
- + if (error)
- + return error;
- + msleep(200);
- +
- + return error;
- +}
- +
- +static ssize_t ft5x46_object_show(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + static struct {
- + u8 addr;
- + const char *fmt;
- + } reg_list[] = {
- + {0x80, "THGROUP %3d\n" },
- + {0x81, "THPEAK %3d\n" },
- + {0x82, "THCAL %3d\n" },
- + {0x83, "THWATER %3d\n" },
- + {0x84, "THTEMP %3d\n" },
- + {0x85, "THDIFF %3d\n" },
- + {0xae, "THBAREA %3d\n" },
- + {0x86, "CTRL %02x\n"},
- + {0xa0, "AUTOCLB %02x\n"},
- + {0xa4, "MODE %02x\n"},
- + {0xa5, "PMODE %02x\n"},
- + {0xa7, "STATE %02x\n"},
- + {0xa9, "ERR %02x\n"},
- + {0x87, "TIME2MONITOR %3d\n" },
- + {0x88, "PERIODACTIVE %3d\n" },
- + {0x89, "PERIODMONITOR %3d\n" },
- + {0xa1, "LIBVERH %02x\n"},
- + {0xa2, "LIBVERL %02x\n"},
- + {0xa3, "CIPHER %02x\n"},
- + {0xa6, "FIRMID %02x\n"},
- + {0xa8, "FT5201ID %02x\n"},
- + {},
- + };
- +
- + struct ft5x46_data *ft5x46 = dev_get_drvdata(dev);
- + int i, error, count = 0;
- + u8 val;
- +
- + mutex_lock(&ft5x46->mutex);
- + for (i = 0; reg_list[i].addr != 0; i++) {
- + error = ft5x46_read_byte(ft5x46, reg_list[i].addr, &val);
- + if (error)
- + break;
- +
- + count += snprintf(buf+count, PAGE_SIZE-count,
- + reg_list[i].fmt, val);
- + }
- + mutex_unlock(&ft5x46->mutex);
- +
- + return error ? : count;
- +}
- +
- +static ssize_t ft5x46_object_store(struct device *dev,
- + struct device_attribute *attr,
- + const char *buf, size_t count)
- +{
- + struct ft5x46_data *ft5x46 = dev_get_drvdata(dev);
- + u8 addr, val;
- + int error;
- +
- + mutex_lock(&ft5x46->mutex);
- + if (sscanf(buf, "%hhx=%hhx", &addr, &val) == 2)
- + error = ft5x46_write_byte(ft5x46, addr, val);
- + else
- + error = -EINVAL;
- + mutex_unlock(&ft5x46->mutex);
- +
- + return error ? : count;
- +}
- +
- +static ssize_t ft5x46_dbgdump_show(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + struct ft5x46_data *ft5x46 = dev_get_drvdata(dev);
- + int count;
- +
- + mutex_lock(&ft5x46->mutex);
- + count = snprintf(buf, PAGE_SIZE, "%d\n", ft5x46->dbgdump);
- + mutex_unlock(&ft5x46->mutex);
- +
- + return count;
- +}
- +
- +static ssize_t ft5x46_dbgdump_store(struct device *dev,
- + struct device_attribute *attr,
- + const char *buf, size_t count)
- +{
- + struct ft5x46_data *ft5x46 = dev_get_drvdata(dev);
- + unsigned long dbgdump;
- + int error;
- +
- + mutex_lock(&ft5x46->mutex);
- + error = sscanf(buf, "%lu", &dbgdump);
- + if (!error)
- + ft5x46->dbgdump = dbgdump;
- + mutex_unlock(&ft5x46->mutex);
- +
- + return error ? : count;
- +}
- +
- +static int ft5x46_updatefw_with_filename(struct ft5x46_data *ft5x46,
- + const char *filename, bool *upgraded)
- +{
- + struct ft5x46_firmware_data firmware;
- + const struct firmware *fw;
- + int error;
- +
- + error = request_firmware(&fw, filename, ft5x46->dev);
- + if (!error) {
- + firmware.data = kmalloc((int)fw->size, GFP_KERNEL);
- + memcpy(firmware.data, fw->data, (int)fw->size);
- + firmware.size = fw->size;
- +
- + mutex_lock(&ft5x46->mutex);
- + if (ft5x46->chip_id == FT5316_CHIP_ID)
- + error = ft5x06_load_firmware(ft5x46, &firmware, upgraded);
- + else
- + error = ft5x46_load_firmware(ft5x46, &firmware, upgraded);
- + mutex_unlock(&ft5x46->mutex);
- +
- + kfree(firmware.data);
- + release_firmware(fw);
- + }
- +
- + return error;
- +}
- +
- +static ssize_t ft5x46_updatefw_store(struct device *dev,
- + struct device_attribute *attr,
- + const char *buf, size_t count)
- +{
- + struct ft5x46_data *ft5x46 = dev_get_drvdata(dev);
- + int error;
- + bool upgraded;
- +
- + error = ft5x46_updatefw_with_filename(ft5x46,
- + "ft5x06.bin", &upgraded);
- +
- + return error ? : count;
- +}
- +
- +static ssize_t ft5x46_tpfwver_show(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + struct ft5x46_data *ft5x46 = dev_get_drvdata(dev);
- + ssize_t num_read_chars = 0;
- + u8 fwver = 0;
- + int error;
- + mutex_lock(&ft5x46->mutex);
- + error = ft5x46_read_byte(ft5x46, FT5X0X_REG_FW_VER, &fwver);
- + if (error)
- + num_read_chars = snprintf(buf, PAGE_SIZE, "Get firmware version failed!\n");
- + else
- + num_read_chars = snprintf(buf, PAGE_SIZE, "%02X\n", fwver);
- + mutex_unlock(&ft5x46->mutex);
- + return num_read_chars;
- +}
- +
- +static int ft5x46_enter_factory(struct ft5x46_data *ft5x46_ts)
- +{
- + u8 reg_val;
- + int error;
- + int error_code = -1;
- +
- + error = ft5x46_write_byte(ft5x46_ts, FT5X0X_REG_DEVIDE_MODE,
- + FT5X0X_DEVICE_MODE_TEST);
- + if (error)
- + return error_code;
- + msleep(100);
- + error = ft5x46_read_byte(ft5x46_ts, FT5X0X_REG_DEVIDE_MODE, ®_val);
- + if (error)
- + return error_code;
- + if ((reg_val & 0x70) != FT5X0X_DEVICE_MODE_TEST) {
- + dev_info(ft5x46_ts->dev, "ERROR: The Touch Panel was not put in Factory Mode.");
- + return error_code;
- + }
- +
- + return 0;
- +}
- +
- +static int ft5x46_enter_work(struct ft5x46_data *ft5x46_ts)
- +{
- + u8 reg_val;
- + int error;
- + int error_code = -1;
- + error = ft5x46_write_byte(ft5x46_ts, FT5X0X_REG_DEVIDE_MODE,
- + FT5X0X_DEVICE_MODE_NORMAL);
- + if (error)
- + return error_code;
- + msleep(100);
- + error = ft5x46_read_byte(ft5x46_ts, FT5X0X_REG_DEVIDE_MODE, ®_val);
- + if (error)
- + return error_code;
- + if ((reg_val & 0x70) != FT5X0X_DEVICE_MODE_NORMAL) {
- + dev_info(ft5x46_ts->dev, "ERROR: The Touch Panel was not put in Normal Mode.\n");
- + return error_code;
- + }
- +
- + return 0;
- +}
- +
- +#define FT5X0X_MAX_RX_NUM 22
- +static int ft5x46_get_rawData(struct ft5x46_data *ft5x46_ts,
- + u16 *rawdata)
- +{
- + int ret_val = 0;
- + int error;
- + u8 val;
- + int row_num = 0;
- + u8 read_buffer[FT5X0X_MAX_RX_NUM * 2];
- + int read_len;
- + int i;
- + struct ft5x46_ts_platform_data *pdata = ft5x46_ts->dev->platform_data;
- + int index = ft5x46_ts->current_index;
- + int tx_num = pdata->testdata[index].tx_num;
- + int rx_num = pdata->testdata[index].rx_num;
- +
- + error = ft5x46_read_byte(ft5x46_ts, FT5X0X_REG_DEVIDE_MODE, &val);
- + if (error < 0) {
- + dev_err(ft5x46_ts->dev, "ERROR: Read mode failed!\n");
- + ret_val = -1;
- + goto error_return;
- + }
- + val |= 0x80;
- + error = ft5x46_write_byte(ft5x46_ts, FT5X0X_REG_DEVIDE_MODE, val);
- + if (error < 0) {
- + dev_err(ft5x46_ts->dev, "ERROR: Write mode failed!\n");
- + ret_val = -1;
- + goto error_return;
- + }
- + msleep(20);
- + error = ft5x46_read_byte(ft5x46_ts, FT5X0X_REG_DEVIDE_MODE, &val);
- + if (error < 0) {
- + dev_err(ft5x46_ts->dev, "ERROR: Read mode failed!\n");
- + ret_val = -1;
- + goto error_return;
- + }
- + if (0x00 != (val & 0x80)) {
- + dev_err(ft5x46_ts->dev, "ERROR: Read mode failed!\n");
- + ret_val = -1;
- + goto error_return;
- + }
- + dev_info(ft5x46_ts->dev, "Read rawdata......\n");
- + for (row_num = 0; row_num < tx_num; row_num++) {
- + memset(read_buffer, 0x00, rx_num * 2);
- + error = ft5x46_write_byte(ft5x46_ts, FT5X0X_REG_ROW_ADDR, row_num);
- + if (error < 0) {
- + dev_err(ft5x46_ts->dev, "ERROR: Write row addr failed!\n");
- + ret_val = -1;
- + goto error_return;
- + }
- + msleep(1);
- + read_len = rx_num * 2;
- + error = ft5x46_write_byte(ft5x46_ts, 0x10, read_len);
- + if (error < 0) {
- + dev_err(ft5x46_ts->dev, "ERROR: Write len failed!\n");
- + ret_val = -1;
- + goto error_return;
- + }
- + error = ft5x46_read_block(ft5x46_ts, 0x10,
- + read_buffer, rx_num * 2);
- + if (error < 0) {
- + dev_err(ft5x46_ts->dev,
- + "ERROR: Coule not read row %u data!\n", row_num);
- + ret_val = -1;
- + goto error_return;
- + }
- + for (i = 0; i < rx_num; i++) {
- + rawdata[row_num * rx_num + i] = read_buffer[i<<1];
- + rawdata[row_num * rx_num + i] = rawdata[row_num * rx_num + i] << 8;
- + rawdata[row_num * rx_num + i] |= read_buffer[(i<<1)+1];
- + }
- + }
- +error_return:
- + return ret_val;
- +}
- +
- +static ssize_t ft5x46_rawdata_show(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + struct ft5x46_data *ft5x46 = dev_get_drvdata(dev);
- + struct ft5x46_ts_platform_data *pdata = ft5x46->dev->platform_data;
- + int index = ft5x46->current_index;
- + u16 *rawdata;
- + int error;
- + int i = 0, j = 0;
- + int num_read_chars = 0;
- + int tx_num = pdata->testdata[index].tx_num;
- + int rx_num = pdata->testdata[index].rx_num;
- +
- + rawdata = (u16 *)kmalloc(sizeof(u16) * tx_num * rx_num, GFP_KERNEL);
- + if (rawdata == NULL)
- + return -ENOMEM;
- +
- + mutex_lock(&ft5x46->mutex);
- +
- + disable_irq_nosync(ft5x46->irq);
- + error = ft5x46_enter_factory(ft5x46);
- + if (error < 0) {
- + dev_err(ft5x46->dev, "ERROR: Could not enter factory mode!\n");
- + goto end;
- + }
- +
- + error = ft5x46_get_rawData(ft5x46, rawdata);
- + if (error < 0)
- + snprintf(buf, PAGE_SIZE, "%s", "Could not get rawdata\n");
- + else {
- + for (i = 0; i < tx_num; i++) {
- + for (j = 0; j < rx_num; j++) {
- + num_read_chars += snprintf(&buf[num_read_chars], PAGE_SIZE,
- + "%u ", rawdata[i * rx_num + j]);
- + }
- + buf[num_read_chars-1] = '\n';
- + }
- + }
- +
- + error = ft5x46_enter_work(ft5x46);
- + if (error < 0)
- + dev_err(ft5x46->dev, "ERROR: Could not enter work mode!\n");
- +
- +end:
- + enable_irq(ft5x46->irq);
- + mutex_unlock(&ft5x46->mutex);
- + kfree(rawdata);
- + return num_read_chars;
- +}
- +
- +unsigned int ft5x46_do_selftest(struct ft5x46_data *ft5x46)
- +{
- + struct ft5x46_ts_platform_data *pdata = ft5x46->dev->platform_data;
- + int index = ft5x46->current_index;
- + u16 *testdata;
- + int i, j;
- + int error;
- + int tx_num = pdata->testdata[index].tx_num;
- + int rx_num = pdata->testdata[index].rx_num;
- + int final_tx_num = tx_num;
- + int final_rx_num = rx_num;
- +
- + testdata = (u16 *)kmalloc(sizeof(u16) * tx_num * rx_num, GFP_KERNEL);
- + if (testdata == NULL)
- + return -ENOMEM;
- +
- + error = ft5x46_get_rawData(ft5x46, testdata);
- + if (error)
- + return 0;
- +
- + if (tx_num > rx_num)
- + final_tx_num -= 1;
- + else
- + final_rx_num -= 1;
- +
- + for (i = 0; i < final_tx_num; i++) {
- + for (j = 0; j < final_rx_num; j++) {
- + if (testdata[i * rx_num + j] < pdata->raw_min ||
- + testdata[i * rx_num + j] > pdata->raw_max)
- + return 0;
- + }
- + }
- +
- + return 1;
- +}
- +
- +static ssize_t ft5x46_selftest_store(struct device *dev,
- + struct device_attribute *attr,
- + const char *buf, size_t count)
- +{
- + struct ft5x46_data *ft5x46 = dev_get_drvdata(dev);
- + int error;
- + unsigned long val;
- +
- + error = sscanf(buf, "%lu", &val);
- + if (error)
- + return error;
- + if (val != 1)
- + return -EINVAL;
- +
- + mutex_lock(&ft5x46->mutex);
- +
- + disable_irq_nosync(ft5x46->irq);
- + error = ft5x46_enter_factory(ft5x46);
- + if (error < 0) {
- + dev_err(ft5x46->dev, "ERROR: Could not enter factory mode!\n");
- + goto end;
- + }
- +
- + ft5x46->test_result = ft5x46_do_selftest(ft5x46);
- +
- + error = ft5x46_enter_work(ft5x46);
- + if (error < 0)
- + dev_err(ft5x46->dev, "ERROR: Could not enter work mode!\n");
- +
- +end:
- + enable_irq(ft5x46->irq);
- + mutex_unlock(&ft5x46->mutex);
- + return count;
- +}
- +
- +static ssize_t ft5x46_selftest_show(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + struct ft5x46_data *ft5x46 = dev_get_drvdata(dev);
- +
- + return snprintf(&buf[0], PAGE_SIZE, "%u\n", ft5x46->test_result);
- +}
- +
- +static ssize_t ft5x46_lockdown_info_store(struct device *dev,
- + struct device_attribute *attr,
- + const char *buf, size_t count)
- +{
- + struct ft5x46_data *ft5x46 = dev_get_drvdata(dev);
- + int error;
- + unsigned long val;
- +
- + error = sscanf(buf, "%lu", &val);
- + if (error)
- + return error;
- + if (val != 1)
- + return -EINVAL;
- +
- + error = ft5x46_get_lockdown_info(ft5x46);
- + if (error)
- + return -EINVAL;
- + else
- + return count;
- +}
- +
- +static ssize_t ft5x46_lockdown_info_show(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + struct ft5x46_data *ft5x46 = dev_get_drvdata(dev);
- + int error;
- +
- + error = ft5x46_get_lockdown_info(ft5x46);
- + if (error)
- + return snprintf(buf, PAGE_SIZE, "Failed to get lockdown info\n");
- + else
- + return snprintf(buf, PAGE_SIZE, "0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X\n",
- + (int)ft5x46->lockdown_info[0], (int)ft5x46->lockdown_info[1],
- + (int)ft5x46->lockdown_info[2], (int)ft5x46->lockdown_info[3],
- + (int)ft5x46->lockdown_info[4], (int)ft5x46->lockdown_info[5],
- + (int)ft5x46->lockdown_info[6], (int)ft5x46->lockdown_info[7]);
- +}
- +
- +static ssize_t ft5x46_config_info_show(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + struct ft5x46_data *ft5x46 = dev_get_drvdata(dev);
- +
- + return snprintf(buf, PAGE_SIZE, "0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X\n",
- + (int)ft5x46->config_info[0], (int)ft5x46->config_info[1],
- + (int)ft5x46->config_info[2], (int)ft5x46->config_info[3],
- + (int)ft5x46->config_info[4], (int)ft5x46->config_info[5],
- + (int)ft5x46->config_info[6], (int)ft5x46->config_info[7]);
- +}
- +
- +static ssize_t ft5x46_wakeup_mode_store(struct device *dev,
- + struct device_attribute *attr,
- + const char *buf, size_t count)
- +{
- + int error;
- + unsigned long val;
- + struct ft5x46_data *ft5x46 = dev_get_drvdata(dev);
- +
- + error = sscanf(buf, "%lu", &val);
- +
- + if (!error)
- + ft5x46->wakeup_mode = !!val;
- +
- + if (ft5x46->in_suspend)
- + ft5x46_wakeup_reconfigure(ft5x46, (bool)val);
- +
- + return error ? : count;
- +}
- +
- +static ssize_t ft5x46_wakeup_mode_show(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + struct ft5x46_data *ft5x46 = dev_get_drvdata(dev);
- +
- + return snprintf(buf, PAGE_SIZE, "%d\n", (int)ft5x46->wakeup_mode);
- +}
- +
- +static ssize_t ft5x46_panel_color_show(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + struct ft5x46_data *ft5x46 = dev_get_drvdata(dev);
- + int error, count = 0;
- +
- + if (ft5x46->in_suspend)
- + ft5x46_resume(ft5x46);
- +
- + error = ft5x46_get_lockdown_info(ft5x46);
- + if (error || ft5x46->lockdown_info[2] == 0)
- + count = snprintf(buf, PAGE_SIZE, "0\n");
- + else
- + count = snprintf(buf, PAGE_SIZE, "%c\n", ft5x46->lockdown_info[2]);
- +
- + return count;
- +}
- +
- +#ifdef FT5X46_DEBUG_PERMISSION
- +static DEVICE_ATTR(tpfwver, 0400, ft5x46_tpfwver_show, NULL);
- +static DEVICE_ATTR(object, 0600, ft5x46_object_show, ft5x46_object_store);
- +static DEVICE_ATTR(dbgdump, 0600, ft5x46_dbgdump_show, ft5x46_dbgdump_store);
- +static DEVICE_ATTR(updatefw, 0200, NULL, ft5x46_updatefw_store);
- +static DEVICE_ATTR(rawdatashow, 0400, ft5x46_rawdata_show, NULL);
- +static DEVICE_ATTR(selftest, 0600, ft5x46_selftest_show, ft5x46_selftest_store);
- +static DEVICE_ATTR(lockdown_info, 0600, ft5x46_lockdown_info_show, ft5x46_lockdown_info_store);
- +static DEVICE_ATTR(config_info, 0400, ft5x46_config_info_show, NULL);
- +static DEVICE_ATTR(wakeup_mode, 0600, ft5x46_wakeup_mode_show, ft5x46_wakeup_mode_store);
- +static DEVICE_ATTR(panel_color, 0400, ft5x46_panel_color_show, NULL);
- +#else
- +static DEVICE_ATTR(tpfwver, 0400, ft5x46_tpfwver_show, NULL);
- +static DEVICE_ATTR(object, 0600, ft5x46_object_show, ft5x46_object_store);
- +static DEVICE_ATTR(dbgdump, 0600, ft5x46_dbgdump_show, ft5x46_dbgdump_store);
- +static DEVICE_ATTR(updatefw, 0200, NULL, ft5x46_updatefw_store);
- +static DEVICE_ATTR(rawdatashow, 0400, ft5x46_rawdata_show, NULL);
- +static DEVICE_ATTR(selftest, 0600, ft5x46_selftest_show, ft5x46_selftest_store);
- +static DEVICE_ATTR(lockdown_info, 0600, ft5x46_lockdown_info_show, ft5x46_lockdown_info_store);
- +static DEVICE_ATTR(config_info, 0400, ft5x46_config_info_show, NULL);
- +static DEVICE_ATTR(wakeup_mode, 0600, ft5x46_wakeup_mode_show, ft5x46_wakeup_mode_store);
- +static DEVICE_ATTR(panel_color, 0400, ft5x46_panel_color_show, NULL);
- +#endif
- +
- +static struct attribute *ft5x46_attrs[] = {
- + &dev_attr_tpfwver.attr,
- + &dev_attr_object.attr,
- + &dev_attr_dbgdump.attr,
- + &dev_attr_updatefw.attr,
- + &dev_attr_rawdatashow.attr,
- + &dev_attr_selftest.attr,
- + &dev_attr_lockdown_info.attr,
- + &dev_attr_config_info.attr,
- + &dev_attr_wakeup_mode.attr,
- + &dev_attr_panel_color.attr,
- + NULL
- +};
- +
- +static const struct attribute_group ft5x46_attr_group = {
- + .attrs = ft5x46_attrs
- +};
- +
- +static int ft5x46_power_on(struct ft5x46_data *data, bool on)
- +{
- + int rc = 0;
- +
- + if (on) {
- + rc = regulator_enable(data->vddio);
- + if (rc) {
- + dev_err(data->dev,
- + "Regulator vddio enable failed rc=%d\n", rc);
- + return rc;
- + }
- + msleep(1);
- + rc = regulator_enable(data->vdd);
- + if (rc) {
- + dev_err(data->dev,
- + "Regulator vdd enable failed rc=%d\n", rc);
- + return rc;
- + }
- +
- + } else {
- + rc = regulator_disable(data->vddio);
- + if (rc) {
- + dev_err(data->dev,
- + "Regulator vddio disable failed rc=%d\n", rc);
- + return rc;
- + }
- +
- + rc = regulator_disable(data->vdd);
- + if (rc) {
- + dev_err(data->dev,
- + "Regulator vdd disable failed rc=%d\n", rc);
- + return rc;
- + }
- + }
- +
- + return rc;
- +}
- +
- +static int ft5x46_power_init(struct ft5x46_data *data, bool on)
- +{
- + int rc;
- +
- + if (!on)
- + goto pwr_deinit;
- +
- + data->vdd = regulator_get(data->dev, "vdd");
- + if (IS_ERR(data->vdd)) {
- + rc = PTR_ERR(data->vdd);
- + dev_err(data->dev,
- + "Regulator get failed vdd rc=%d\n", rc);
- + goto exit;
- + }
- +
- + data->vddio = regulator_get(data->dev, "vddio");
- + if (IS_ERR(data->vddio)) {
- + rc = PTR_ERR(data->vddio);
- + dev_err(data->dev,
- + "Regulator get failed vddio rc=%d\n", rc);
- + goto err_get_vddio;
- + }
- +
- + return 0;
- +
- +pwr_deinit:
- + regulator_put(data->vddio);
- +err_get_vddio:
- + regulator_put(data->vdd);
- +exit:
- + return rc;
- +}
- +
- +static void ft5x46_dt_dump(struct device *dev,
- + struct ft5x46_ts_platform_data *pdata)
- +{
- + int j;
- +
- + dev_dbg(dev, "i2c-pull-up = %d\n", (int)pdata->i2c_pull_up);
- + dev_dbg(dev, "reset gpio = %d\n", (int)pdata->reset_gpio);
- + dev_dbg(dev, "irq gpio = %d\n", (int)pdata->irq_gpio);
- + dev_dbg(dev, "x_max = %d\n", (int)pdata->x_max);
- + dev_dbg(dev, "y_max = %d\n", (int)pdata->y_max);
- + dev_dbg(dev, "z_max = %d\n", (int)pdata->z_max);
- + dev_dbg(dev, "w_max = %d\n", (int)pdata->w_max);
- + dev_dbg(dev, "landing_jiffies = %d\n", (int)pdata->landing_jiffies);
- + dev_dbg(dev, "landing_threshold = %d\n", (int)pdata->landing_threshold);
- + dev_dbg(dev, "staying_threshold = %d\n", (int)pdata->staying_threshold);
- + dev_dbg(dev, "raw min = %d\n", (int)pdata->raw_min);
- + dev_dbg(dev, "raw max = %d\n", (int)pdata->raw_max);
- + dev_dbg(dev, "fw delay 55 ms = %d\n", (int)pdata->ui.delay_55);
- + dev_dbg(dev, "fw delay aa ms = %d\n", (int)pdata->ui.delay_aa);
- + dev_dbg(dev, "fw upgrade id 1 = %d\n", (int)pdata->ui.upgrade_id_1);
- + dev_dbg(dev, "fw upgrade id 2 = %d\n", (int)pdata->ui.upgrade_id_2);
- + dev_dbg(dev, "fw delay readid ms = %d\n", (int)pdata->ui.delay_readid);
- + dev_dbg(dev, "fw delay readid ms = %d\n", (int)pdata->ui.delay_erase);
- +
- + for (j = 0; j < pdata->cfg_size; j++) {
- + dev_dbg(dev, "firmare %d chip = 0x%x, vendor = 0x%x name = %s\n",
- + j, pdata->firmware[j].chip,
- + pdata->firmware[j].vendor,
- + pdata->firmware[j].fwname);
- + }
- +}
- +
- +static int ft5x46_initialize_pinctrl(struct ft5x46_data *ft5x46)
- +{
- + int ret = 0;
- +
- + ft5x46->ts_pinctrl = devm_pinctrl_get(ft5x46->dev);
- + if (IS_ERR_OR_NULL(ft5x46->ts_pinctrl)) {
- + pr_err("Target does not use pinctrl\n");
- + ret = PTR_ERR(ft5x46->ts_pinctrl);
- + ft5x46->ts_pinctrl = NULL;
- + return ret;
- + }
- +
- + ft5x46->gpio_state_active
- + = pinctrl_lookup_state(ft5x46->ts_pinctrl, "pmx_ts_active");
- + if (IS_ERR_OR_NULL(ft5x46->gpio_state_active)) {
- + pr_err("Can not get ts default pinstate\n");
- + ret = PTR_ERR(ft5x46->gpio_state_active);
- + ft5x46->ts_pinctrl = NULL;
- + return ret;
- + }
- +
- + ft5x46->gpio_state_suspend
- + = pinctrl_lookup_state(ft5x46->ts_pinctrl, "pmx_ts_suspend");
- + if (IS_ERR_OR_NULL(ft5x46->gpio_state_suspend)) {
- + pr_err("Can not get ts sleep pinstate\n");
- + ret = PTR_ERR(ft5x46->gpio_state_suspend);
- + ft5x46->ts_pinctrl = NULL;
- + return ret;
- + }
- +
- + return 0;
- +}
- +
- +static int ft5x46_pinctrl_select(struct ft5x46_data *ft5x46, bool on)
- +{
- + int ret = 0;
- + struct pinctrl_state *pins_state;
- +
- + pins_state = on ? ft5x46->gpio_state_active : ft5x46->gpio_state_suspend;
- + if (!IS_ERR_OR_NULL(pins_state)) {
- + ret = pinctrl_select_state(ft5x46->ts_pinctrl, pins_state);
- + if (ret) {
- + dev_err(ft5x46->dev, "Cannot set %s pins\n",
- + on ? "pmx_ts_active" : "pmx_ts_suspend");
- + return ret;
- + }
- + } else {
- + dev_err(ft5x46->dev, "not a valid '%s' pinstate\n",
- + on ? "pmx_ts_active" : "pmx_ts_suspend");
- + }
- +
- + return 0;
- +}
- +
- +#if defined(CONFIG_FB)
- +static int fb_notifier_cb(struct notifier_block *self,
- + unsigned long event, void *data)
- +{
- + struct fb_event *evdata = data;
- + int *blank;
- + struct ft5x46_data *ft5x46 =
- + container_of(self, struct ft5x46_data, fb_notif);
- +
- + if (evdata && evdata->data && event == FB_EVENT_BLANK && ft5x46) {
- + blank = evdata->data;
- + if (*blank == FB_BLANK_UNBLANK) {
- + dev_dbg(ft5x46->dev, "##### UNBLANK SCREEN #####\n");
- + ft5x46_input_enable(ft5x46->input);
- + } else if (*blank == FB_BLANK_POWERDOWN) {
- + dev_dbg(ft5x46->dev, "##### BLANK SCREEN #####\n");
- + ft5x46_input_disable(ft5x46->input);
- + }
- + }
- +
- + return 0;
- +}
- +
- +static int ft5x46_configure_sleep(struct ft5x46_data *ft5x46, bool enable)
- +{
- + int ret;
- +
- + ft5x46->fb_notif.notifier_call = fb_notifier_cb;
- + if (enable) {
- + ret = fb_register_client(&ft5x46->fb_notif);
- + if (ret) {
- + dev_err(ft5x46->dev,
- + "Unable to register fb_notifier, err: %d\n", ret);
- + }
- + } else {
- + ret = fb_unregister_client(&ft5x46->fb_notif);
- + if (ret) {
- + dev_err(ft5x46->dev,
- + "Unable to unregister fb_notifier, err: %d\n", ret);
- + }
- + }
- + return ret;
- +}
- +#elif defined(CONFIG_HAS_EARLYSUSPEND)
- +static int ft5x46_configure_sleep(struct ft5x46_data *ft5x46, bool enable)
- +{
- + if (enable) {
- + ft5x46->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN+1;
- + ft5x46->early_suspend.suspend = ft5x46_early_suspend;
- + ft5x46->early_suspend.resume = ft5x46_early_resume;
- + register_early_suspend(&ft5x46->early_suspend);
- + } else {
- + unregister_early_suspend(&ft5x46->early_suspend);
- + }
- +
- + return 0;
- +}
- +#else
- +static int ft5x46_configure_sleep(struct ft5x46_data *ft5x46, bool enable)
- +{
- + if (enable)
- +
- + ft5x46_input_enable(ft5x46->input);
- + else
- +
- + ft5x46_input_disable(ft5x46->input);
- + return 0;
- +}
- +#endif
- +
- +#ifdef CONFIG_OF
- +static int ft5x46_parse_dt(struct device *dev,
- + struct ft5x46_ts_platform_data *pdata)
- +{
- + int rc, j;
- + struct device_node *np = dev->of_node;
- + u32 temp_val, num_fw;
- + struct device_node *sub_np;
- +
- + pdata->i2c_pull_up = of_property_read_bool(np,
- + "ft5x46_i2c,i2c-pull-up");
- + pdata->reset_gpio = of_get_named_gpio_flags(np, "ft5x46_i2c,reset-gpio",
- + 0, &pdata->reset_gpio_flags);
- + if (pdata->reset_gpio < 0)
- + return pdata->reset_gpio;
- +
- + pdata->irq_gpio = of_get_named_gpio_flags(np, "ft5x46_i2c,irq-gpio",
- + 0, &pdata->irq_gpio_flags);
- + if (pdata->irq_gpio < 0)
- + return pdata->irq_gpio;
- +
- + rc = of_property_read_u32(np, "ft5x46_i2c,x-max", &pdata->x_max);
- + if (rc) {
- + dev_err(dev, "can't read x-max\n");
- + return rc;
- + }
- + rc = of_property_read_u32(np, "ft5x46_i2c,y-max", &pdata->y_max);
- + if (rc) {
- + dev_err(dev, "can't read y-max\n");
- + return rc;
- + }
- + rc = of_property_read_u32(np, "ft5x46_i2c,z-max", &pdata->z_max);
- + if (rc) {
- + dev_err(dev, "can't read z-max\n");
- + return rc;
- + }
- + rc = of_property_read_u32(np, "ft5x46_i2c,w-max", &pdata->w_max);
- + if (rc) {
- + dev_err(dev, "can't read w-max\n");
- + return rc;
- + }
- +
- + rc = of_property_read_u32(np, "ft5x46_i2c,landing-jiffies", &temp_val);
- + if (rc) {
- + dev_err(dev, "can't read landing-jiffies\n");
- + return rc;
- + } else
- + pdata->landing_jiffies = (unsigned long)temp_val;
- + rc = of_property_read_u32(np, "ft5x46_i2c,landing-threshold", &pdata->landing_threshold);
- + if (rc) {
- + dev_err(dev, "can't read landing-threshold\n");
- + return rc;
- + }
- + rc = of_property_read_u32(np, "ft5x46_i2c,staying-threshold", &pdata->staying_threshold);
- + if (rc) {
- + dev_err(dev, "can't read staying-threshold\n");
- + return rc;
- + }
- +
- + rc = of_property_read_u32(np, "ft5x46_i2c,raw-min", &temp_val);
- + if (rc) {
- + dev_err(dev, "can't read raw-min\n");
- + return rc;
- + } else
- + pdata->raw_min = (u16)temp_val;
- + rc = of_property_read_u32(np, "ft5x46_i2c,raw-max", &temp_val);
- + if (rc) {
- + dev_err(dev, "can't read raw-max\n");
- + return rc;
- + } else
- + pdata->raw_max = (u16)temp_val;
- + rc = of_property_read_u32(np, "ft5x46_i2c,open-min", &temp_val);
- + if (rc)
- + dev_err(dev, "can't read open-min\n");
- + else
- + pdata->open_min = (u16)temp_val;
- + rc = of_property_read_u32(np, "ft5x46_i2c,open-max", &temp_val);
- + if (rc)
- + dev_err(dev, "can't read open-max\n");
- + else
- + pdata->open_max = (u16)temp_val;
- + rc = of_property_read_u32(np, "ft5x46_i2c,short-min", &temp_val);
- + if (rc)
- + dev_err(dev, "can't read short-min\n");
- + else
- + pdata->short_min = (u16)temp_val;
- + rc = of_property_read_u32(np, "ft5x46_i2c,short-max", &temp_val);
- + if (rc)
- + dev_err(dev, "can't read short-max\n");
- + else
- + pdata->short_max = (u32)temp_val;
- + rc = of_property_read_u32(np, "ft5x46_i2c,imin-cc", &temp_val);
- + if (rc)
- + dev_err(dev, "can't read imin-cc\n");
- + else
- + pdata->imin_cc = (u32)temp_val;
- + rc = of_property_read_u32(np, "ft5x46_i2c,imin-cg", &temp_val);
- + if (rc)
- + dev_err(dev, "can't read short-max\n");
- + else
- + pdata->imin_cg = (u32)temp_val;
- +
- + pdata->has_key = of_property_read_bool(np, "ft5x46_i2c,has-key");
- + if (pdata->has_key) {
- + rc = of_property_read_u32(np, "ft5x46_i2c,key-rx1", &temp_val);
- + if (rc)
- + dev_err(dev, "can't read key-rx1\n");
- + else
- + pdata->key_rx1 = (u32)temp_val;
- + rc = of_property_read_u32(np, "ft5x46_i2c,key-rx2", &temp_val);
- + if (rc)
- + dev_err(dev, "can't read key-rx2\n");
- + else
- + pdata->key_rx2 = (u32)temp_val;
- + rc = of_property_read_u32(np, "ft5x46_i2c,key-rx3", &temp_val);
- + if (rc)
- + dev_err(dev, "can't read key-rx3\n");
- + else
- + pdata->key_rx3 = (u32)temp_val;
- + }
- + rc = of_property_read_u32(np, "ft5x46_i2c,fw-delay-55-ms", &temp_val);
- + if (rc) {
- + dev_err(dev, "can't read delay_55\n");
- + return rc;
- + } else
- + pdata->ui.delay_55 = (u16)temp_val;
- +
- + rc = of_property_read_u32(np, "ft5x46_i2c,fw-delay-aa-ms", &temp_val);
- + if (rc) {
- + dev_err(dev, "can't read delay_aa\n");
- + return rc;
- + } else
- + pdata->ui.delay_aa = (u16)temp_val;
- +
- + rc = of_property_read_u32(np, "ft5x46_i2c,fw-upgrade-id1", &temp_val);
- + if (rc) {
- + dev_err(dev, "can't read fw-upgrade-id1\n");
- + return rc;
- + } else
- + pdata->ui.upgrade_id_1 = (u8)temp_val;
- +
- + rc = of_property_read_u32(np, "ft5x46_i2c,fw-upgrade-id2", &temp_val);
- + if (rc) {
- + dev_err(dev, "can't read fw-upgrade-id2\n");
- + return rc;
- + } else
- + pdata->ui.upgrade_id_2 = (u8)temp_val;
- +
- + rc = of_property_read_u32(np, "ft5x46_i2c,fw-delay-readid-ms", &temp_val);
- + if (rc) {
- + dev_err(dev, "can't read fw-delay-readid-ms\n");
- + return rc;
- + } else
- + pdata->ui.delay_readid = (u16)temp_val;
- +
- + rc = of_property_read_u32(np, "ft5x46_i2c,fw-delay-erase-ms", &temp_val);
- + if (rc) {
- + dev_err(dev, "can't read fw-delay-erase-ms\n");
- + return rc;
- + } else
- + pdata->ui.delay_erase = (u16)temp_val;
- + rc = of_property_read_u32(np, "ft5x46_i2c,firmware-array-size", &num_fw);
- + if (rc) {
- + dev_err(dev, "can't get firmware-array-size\n");
- + return rc;
- + }
- +
- + pdata->firmware = kzalloc(sizeof(struct ft5x46_firmware_data) * (num_fw + 1),
- + GFP_KERNEL);
- + if (pdata->firmware == NULL)
- + return -ENOMEM;
- + pdata->testdata = kzalloc(sizeof(struct ft5x46_test_data) * num_fw, GFP_KERNEL);
- + if (pdata->testdata == NULL)
- + return -ENOMEM;
- +
- + pdata->cfg_size = num_fw;
- + j = 0;
- + for_each_child_of_node(np, sub_np) {
- + rc = of_property_read_u32(sub_np, "ft5x46_i2c,chip", &temp_val);
- + if (rc) {
- + dev_err(dev, "can't get chip id\n");
- + return rc;
- + } else
- + pdata->firmware[j].chip = (u8)temp_val;
- +
- + rc = of_property_read_u32(sub_np, "ft5x46_i2c,vendor", &temp_val);
- + if (rc) {
- + dev_err(dev, "can't get vendor id\n");
- + return rc;
- + } else
- + pdata->firmware[j].vendor = (u8)temp_val;
- +
- + rc = of_property_read_string(sub_np, "ft5x46_i2c,fw-name",
- + &pdata->firmware[j].fwname);
- + if (rc && (rc != -EINVAL)) {
- + dev_err(dev, "can't read fw-name\n");
- + return rc;
- + }
- + pdata->firmware[j].size = 0;
- +
- + rc = of_property_read_u32(sub_np, "ft5x46_i2c,tx-num", &pdata->testdata[j].tx_num);
- + if (rc) {
- + dev_err(dev, "can't read tx-num\n");
- + return rc;
- + }
- + rc = of_property_read_u32(sub_np, "ft5x46_i2c,rx-num", &pdata->testdata[j].rx_num);
- + if (rc) {
- + dev_err(dev, "can't read rx-num\n");
- + return rc;
- + }
- +
- + j++;
- + }
- +
- + ft5x46_dt_dump(dev, pdata);
- +
- + return 0;
- +}
- +#else
- +static int ft5x46_parse_dt(struct device *dev,
- + struct ft5x46_ts_platform_data *pdata)
- +{
- + return -ENODEV;
- +}
- +#endif
- +
- +static int ft5x46_read_config_info(struct ft5x46_data *ft5x46)
- +{
- + int error;
- +
- + error = ft5x46_read_block(ft5x46, FT5X0X_REG_CONFIG_INFO,
- + ft5x46->config_info, FT5X46_CONFIG_INFO_SIZE);
- + if (error) {
- + dev_err(ft5x46->dev, "Read config info register %d failed\n",
- + FT5X0X_REG_CONFIG_INFO);
- + return error;
- + }
- +
- + dev_info(ft5x46->dev, "Config info: 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X",
- + ft5x46->config_info[0], ft5x46->config_info[1],
- + ft5x46->config_info[2], ft5x46->config_info[3],
- + ft5x46->config_info[4], ft5x46->config_info[5],
- + ft5x46->config_info[6], ft5x46->config_info[7]);
- +
- + return 0;
- +}
- +
- +static void ft5x46_cover_mode(struct ft5x46_data *ft5x46, bool enable)
- +{
- + ft5x46_write_byte(ft5x46, FT5X46_COVER_REG, enable);
- +}
- +
- +static void ft5x46_switch_mode_work(struct work_struct *work)
- +{
- + struct ft5x46_mode_switch *ms = container_of(work, struct ft5x46_mode_switch, switch_mode_work);
- + struct ft5x46_data *ft5x46 = ms->data;
- + u8 value = ms->mode;
- +
- + if (value == FT5X46_INPUT_EVENT_WAKUP_MODE_ON || value == FT5X46_INPUT_EVENT_WAKUP_MODE_OFF) {
- + if (ft5x46) {
- + ft5x46->wakeup_mode = value - FT5X46_INPUT_EVENT_WAKUP_MODE_OFF;
- +
- + if (ft5x46->in_suspend)
- + ft5x46_wakeup_reconfigure(ft5x46,
- + (bool)(value - FT5X46_INPUT_EVENT_WAKUP_MODE_OFF));
- + }
- + } else if (value == FT5X46_INPUT_EVENT_COVER_MODE_ON || value == FT5X46_INPUT_EVENT_COVER_MODE_OFF) {
- + if (ft5x46) {
- + ft5x46->cover_mode = value - FT5X46_INPUT_EVENT_COVER_MODE_OFF;
- + ft5x46_cover_mode(ft5x46, ft5x46->cover_mode);
- + }
- + }
- +
- + if (ms != NULL) {
- + kfree(ms);
- + ms = NULL;
- + }
- +}
- +
- +static int ft5x46_input_event(struct input_dev *dev,
- + unsigned int type, unsigned int code, int value)
- +{
- + struct ft5x46_data *ft5x46 = input_get_drvdata(dev);
- + struct ft5x46_mode_switch *ms;
- +
- + if (type == EV_SYN && code == SYN_CONFIG) {
- + dev_info(ft5x46->dev,
- + "event write value = %d\n", value);
- +
- + if (value >= FT5X46_INPUT_EVENT_START && value <= FT5X46_INPUT_EVENT_END) {
- + ms = (struct ft5x46_mode_switch *)kmalloc(sizeof(struct ft5x46_mode_switch), GFP_ATOMIC);
- + if (ms != NULL) {
- + ms->data = ft5x46;
- + ms->mode = (u8)value;
- + INIT_WORK(&ms->switch_mode_work, ft5x46_switch_mode_work);
- + schedule_work(&ms->switch_mode_work);
- + } else {
- + dev_err(ft5x46->dev,
- + "Failed in allocating memory for ft5x46_mode_switch!\n");
- + return -ENOMEM;
- + }
- + }
- + }
- +
- + return 0;
- +}
- +
- +#ifdef FT5X46_APK_DEBUG_CHANNEL
- +static ssize_t ft5x46_apk_debug_read(struct file *file, char __user *buffer,
- + size_t buflen, loff_t *fpos)
- +{
- + struct ft5x46_data *ft5x46 = ft_data;
- + int ret = 0;
- + unsigned char *buf = NULL;
- + int num_read_chars = 0;
- + u8 val;
- +
- + buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
- +
- + switch (proc_operate_mode) {
- + case FT5X46_PROC_UPGRADE:
- + ret = ft5x46_read_byte(ft5x46, FT5X0X_REG_FW_VER, &val);
- + if (ret < 0)
- + num_read_chars = snprintf(buf, PAGE_SIZE,
- + "%s", "Get FW version failed.\n");
- + else
- + num_read_chars = snprintf(buf, PAGE_SIZE,
- + "current fw version:0x%02x\n", val);
- + break;
- +
- + case FT5X46_PROC_READ_REGISTER:
- + ret = ft5x46_recv_byte(ft5x46, 1, &val);
- + if (ret < 0) {
- + dev_err(ft5x46->dev, "%s: read register failed\n", __func__);
- + } else {
- + buf[0] = val;
- + num_read_chars = 1;
- + }
- + break;
- +
- + case FT5X46_PROC_READ_DATA:
- + ret = ft5x46_recv_block(ft5x46, buf, buflen);
- + if (ret < 0) {
- + dev_err(ft5x46->dev, "%s: read data failed\n", __func__);
- + } else {
- + num_read_chars = buflen;
- + }
- + break;
- +
- + case FT5X46_PROC_WRITE_REGISTER:
- + case FT5X46_PROC_WRITE_DATA:
- + default:
- + break;
- + }
- +
- + if (ret == 0) {
- + ret = copy_to_user(buffer, buf, min((int)buflen, num_read_chars));
- + }
- +
- + kfree(buf);
- + return ret;
- +}
- +
- +#define FT5X46_MAX_FIRMWARE_LENGTH 128
- +
- +static ssize_t ft5x46_apk_debug_write(struct file *file, const char __user *buffer,
- + size_t buflen, loff_t *fpos)
- +{
- + struct ft5x46_data *ft5x46 = ft_data;
- + unsigned char writebuf[FT5X0X_PACKET_LENGTH];
- + char upgrade_file_name[FT5X46_MAX_FIRMWARE_LENGTH];
- + int ret = 0;
- +
- + if (copy_from_user(&writebuf, buffer,
- + ((buflen < FT5X0X_PACKET_LENGTH) ? buflen : FT5X0X_PACKET_LENGTH))) {
- + dev_err(ft5x46->dev, "%s: copy from user failed\n", __func__);
- + return -EFAULT;
- + }
- +
- + proc_operate_mode = writebuf[0];
- + switch (proc_operate_mode) {
- + case FT5X46_PROC_UPGRADE:
- + memset(upgrade_file_name, 0, FT5X46_MAX_FIRMWARE_LENGTH);
- + snprintf(upgrade_file_name, FT5X46_MAX_FIRMWARE_LENGTH,
- + "%s", writebuf + 1);
- + upgrade_file_name[buflen - 1] = '\0';
- + dev_info(ft5x46->dev, "%s: upgrade file name: %s\n",
- + __func__, upgrade_file_name);
- + ret = ft5x46_updatefw_with_filename(ft5x46, upgrade_file_name, NULL);
- + if (ret < 0) {
- + dev_err(ft5x46->dev, "%s: upgrade failed\n",
- + __func__);
- + return ret;
- + }
- + break;
- +
- + case FT5X46_PROC_READ_REGISTER:
- + dev_info(ft5x46->dev, "%s: read register from %d\n",
- + __func__, writebuf[1]);
- + ret = ft5x46_send_byte(ft5x46, 1, writebuf[1]);
- + if (ret < 0) {
- + dev_err(ft5x46->dev, "%s: read register failed\n", __func__);
- + return ret;
- + }
- + break;
- +
- + case FT5X46_PROC_WRITE_REGISTER:
- + dev_info(ft5x46->dev, "%s: write to register %d: %d\n",
- + __func__, writebuf[1], writebuf[2]);
- + ret = ft5x46_write_byte(ft5x46, writebuf[1], writebuf[2]);
- + if (ret < 0) {
- + dev_err(ft5x46->dev, "%s: write register failed\n", __func__);
- + return ret;
- + }
- + break;
- +
- + case FT5X46_PROC_AUTOCLB:
- +#ifdef CONFIG_TOUCHSCREEN_FT5X46_CALIBRATE
- + dev_info(ft5x46->dev, "%s: Auto calibration\n", __func__);
- + ft5x46_auto_calib(ft5x46);
- +#endif
- + break;
- +
- + case FT5X46_PROC_READ_DATA:
- + case FT5X46_PROC_WRITE_DATA:
- + dev_info(ft5x46->dev, "%s: Read/Write data\n", __func__);
- + ret = ft5x46_send_block(ft5x46, writebuf + 1, buflen - 1);
- + if (ret < 0) {
- + dev_err(ft5x46->dev, "%s: read/write data failed\n", __func__);
- + return ret;
- + }
- + break;
- +
- + default:
- + break;
- + }
- +
- + return buflen;
- +}
- +
- +static const struct file_operations ft5x46_proc_operations = {
- + .read = ft5x46_apk_debug_read,
- + .write = ft5x46_apk_debug_write,
- +};
- +
- +static int ft5x46_create_apk_debug_channel(struct ft5x46_data *ft5x46)
- +{
- + ft5x46_proc_entry = proc_create(FT5X46_PROC_NAME, 0600, NULL, &ft5x46_proc_operations);
- + if (!ft5x46_proc_entry) {
- + dev_err(ft5x46->dev, "Unable to create proc entry\n");
- + return -ENOMEM;
- + } else {
- + dev_info(ft5x46->dev, "Create proc entry successfully\n");
- + }
- +
- + return 0;
- +}
- +
- +static void ft5x46_release_apk_debug_channel(struct ft5x46_data *ft5x46)
- +{
- + if (ft5x46_proc_entry)
- + remove_proc_entry(FT5X46_PROC_NAME, NULL);
- +}
- +#endif
- +
- +#ifdef CONFIG_PM
- +int ft5x46_pm_suspend(struct device *dev)
- +{
- + struct ft5x46_data *ft5x46 = dev_get_drvdata(dev);
- +
- + if (ft5x46->wakeup_mode) {
- + dev_info(dev, "touch enable irq wake\n");
- + disable_irq(ft5x46->irq);
- + enable_irq_wake(ft5x46->irq);
- + }
- +
- + return 0;
- +}
- +EXPORT_SYMBOL_GPL(ft5x46_pm_suspend);
- +
- +int ft5x46_pm_resume(struct device *dev)
- +{
- + struct ft5x46_data *ft5x46 = dev_get_drvdata(dev);
- +
- + if (ft5x46->wakeup_mode) {
- + dev_info(dev, "touch disable irq wake\n");
- + disable_irq_wake(ft5x46->irq);
- + enable_irq(ft5x46->irq);
- + }
- +
- + return 0;
- +}
- +EXPORT_SYMBOL_GPL(ft5x46_pm_resume);
- +#endif
- +
- +struct ft5x46_data *ft5x46_probe(struct device *dev,
- + const struct ft5x46_bus_ops *bops)
- +{
- + int error;
- + struct ft5x46_data *ft5x46;
- + struct ft5x46_ts_platform_data *pdata;
- +
- + /* check input argument */
- + if (dev->of_node) {
- + pdata = devm_kzalloc(dev,
- + sizeof(struct ft5x46_ts_platform_data), GFP_KERNEL);
- + if (!pdata) {
- + dev_err(dev, "Failed to allocate memory!\n");
- + return ERR_PTR(-ENOMEM);
- + }
- +
- + error = ft5x46_parse_dt(dev, pdata);
- + if (error)
- + goto err;
- + } else
- + pdata = dev->platform_data;
- +
- + if (pdata == NULL) {
- + dev_err(dev, "platform data doesn't exist\n");
- + error = -EINVAL;
- + goto err;
- + }
- +
- + /* alloc and init data object */
- + ft5x46 = kzalloc(sizeof(struct ft5x46_data), GFP_KERNEL);
- + if (ft5x46 == NULL) {
- + dev_err(dev, "fail to allocate data object\n");
- + error = -ENOMEM;
- + goto err;
- + }
- + ft_data = ft5x46;
- + ft5x46->dev = dev;
- + ft5x46->irq = gpio_to_irq(pdata->irq_gpio);
- + ft5x46->bops = bops;
- + if (dev->of_node)
- + ft5x46->dev->platform_data = pdata;
- +
- + if (gpio_is_valid(pdata->irq_gpio)) {
- + error = gpio_request(pdata->irq_gpio, "ft5x46_irq_gpio");
- + if (error < 0) {
- + dev_err(dev, "irq gpio request failed");
- + goto err_free_data;
- + }
- + error = gpio_direction_input(pdata->irq_gpio);
- + if (error < 0) {
- + dev_err(dev, "set_direction for irq gpio failed\n");
- + goto free_irq_gpio;
- + }
- + }
- +
- + if (gpio_is_valid(pdata->reset_gpio)) {
- + error = gpio_request(pdata->reset_gpio, "ft5x46_reset_gpio");
- + if (error < 0) {
- + dev_err(dev, "irq gpio request failed");
- + goto free_irq_gpio;
- + }
- + error = gpio_direction_output(pdata->reset_gpio, 0);
- + if (error < 0) {
- + dev_err(dev, "set_direction for irq gpio failed\n");
- + goto free_reset_gpio;
- + }
- + }
- +
- + /* init platform stuff */
- + if (pdata->power_init) {
- + error = pdata->power_init(true);
- + if (error) {
- + dev_err(dev, "fail to power_init platform (pdata)\n");
- + goto free_reset_gpio;
- + }
- + } else {
- + error = ft5x46_power_init(ft5x46, true);
- + if (error) {
- + dev_err(dev, "fail to power_init platform\n");
- + goto free_reset_gpio;
- + }
- + }
- +
- + if (pdata->power_on) {
- + error = pdata->power_on(true);
- + if (error) {
- + dev_err(dev, "fail to power on (pdata)!\n");
- + goto err_power_init;
- + }
- + } else {
- + error = ft5x46_power_on(ft5x46, true);
- + if (error) {
- + dev_err(dev, "fail to power on\n");
- + goto err_power_init;
- + }
- + }
- +
- + error = ft5x46_initialize_pinctrl(ft5x46);
- + if (error || !ft5x46->ts_pinctrl) {
- + dev_err(dev, "Initialize pinctrl failed\n");
- + goto err_power;
- + } else {
- + error = ft5x46_pinctrl_select(ft5x46, true);
- + if (error < 0) {
- + dev_err(dev, "pinctrl select failed\n");
- + goto err_power;
- + }
- + }
- +
- + msleep(10);
- + gpio_set_value_cansleep(pdata->reset_gpio, 1);
- +
- + msleep(200);
- + mutex_init(&ft5x46->mutex);
- +
- + /* alloc and init input device */
- + ft5x46->input = input_allocate_device();
- + if (ft5x46->input == NULL) {
- + dev_err(dev, "fail to allocate input device\n");
- + error = -ENOMEM;
- + goto err_pinctrl_init;
- + }
- +
- + input_set_drvdata(ft5x46->input, ft5x46);
- + ft5x46->input->name = "backtouch";
- + ft5x46->input->id.bustype = bops->bustype;
- + ft5x46->input->id.vendor = 0x4654; /* FocalTech */
- + ft5x46->input->id.product = 0x5000; /* ft5x0x */
- + ft5x46->input->id.version = 0x0100; /* 1.0 */
- + ft5x46->input->dev.parent = dev;
- + ft5x46->input->event = ft5x46_input_event;
- +
- + /* init touch parameter */
- + input_mt_init_slots(ft5x46->input, FT5X0X_MAX_FINGER, 0);
- + set_bit(ABS_MT_TOUCH_MAJOR, ft5x46->input->absbit);
- + set_bit(ABS_MT_POSITION_X, ft5x46->input->absbit);
- + set_bit(ABS_MT_POSITION_Y, ft5x46->input->absbit);
- + set_bit(ABS_MT_WIDTH_MAJOR, ft5x46->input->absbit);
- + set_bit(INPUT_PROP_DIRECT, ft5x46->input->propbit);
- +
- + input_set_abs_params(ft5x46->input,
- + ABS_MT_POSITION_X, 0, pdata->x_max, 0, 0);
- + input_set_abs_params(ft5x46->input,
- + ABS_MT_POSITION_Y, 0, pdata->y_max, 0, 0);
- + input_set_abs_params(ft5x46->input,
- + ABS_MT_TOUCH_MAJOR, 0, pdata->z_max, 0, 0);
- + input_set_abs_params(ft5x46->input,
- + ABS_MT_WIDTH_MAJOR, 0, pdata->w_max, 0, 0);
- + input_set_abs_params(ft5x46->input,
- + ABS_MT_TRACKING_ID, 0, 10, 0, 0);
- + input_set_capability(ft5x46->input, EV_KEY, KEY_WAKEUP);
- +
- + set_bit(EV_KEY, ft5x46->input->evbit);
- + set_bit(EV_ABS, ft5x46->input->evbit);
- + set_bit(BTN_TOUCH, ft5x46->input->keybit);
- +
- + set_bit(KEY_HOME, ft5x46->input->keybit);
- + set_bit(KEY_MENU, ft5x46->input->keybit);
- + set_bit(KEY_BACK, ft5x46->input->keybit);
- +
- + msleep(200);
- + error = ft5x46_hid_to_std_i2c(ft5x46);
- + if (error) {
- + dev_err(dev, "Failed to switch to StdI2C\n");
- +
- + }
- + error = ft5x46_read_byte(ft5x46, FT5X0X_REG_CHIP_ID, &ft5x46->chip_id);
- + if (error) {
- + dev_err(dev, "failed to read chip id\n");
- + goto err_free_input;
- + } else {
- + dev_info(dev, "ft5x46 chip id = %02x\n", ft5x46->chip_id);
- + }
- + error = ft5x46_read_config_info(ft5x46);
- + if (error) {
- + dev_err(dev, "Failed to read config info\n");
- + goto err_free_input;
- + }
- +
- + /* register input device */
- + error = input_register_device(ft5x46->input);
- + if (error) {
- + dev_err(dev, "fail to register input device\n");
- + goto err_free_input;
- + }
- +
- + ft5x46->input->phys =
- + kobject_get_path(&ft5x46->input->dev.kobj, GFP_KERNEL);
- + if (ft5x46->input->phys == NULL) {
- + dev_err(dev, "fail to get input device path\n");
- + error = -ENOMEM;
- + goto err_unregister_input;
- + }
- +
- + /* start interrupt process */
- + error = request_threaded_irq(ft5x46->irq, NULL, ft5x46_interrupt,
- + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "ft5x46", ft5x46);
- + if (error) {
- + dev_err(dev, "fail to request interrupt\n");
- + goto err_free_phys;
- + }
- + ft5x46->irq_enabled = true;
- + /* export sysfs entries */
- + error = sysfs_create_group(&dev->kobj, &ft5x46_attr_group);
- + if (error) {
- + dev_err(dev, "fail to export sysfs entires\n");
- + goto err_free_irq;
- + }
- + error = ft5x46_configure_sleep(ft5x46, true);
- + if (error) {
- + dev_err(dev, "Failed to configure sleep\n");
- + goto err_sysfs_create_group;
- + }
- +
- + ft5x46->vkeys_dir = kobject_create_and_add("board_properties",
- + NULL);
- + if (!ft5x46->vkeys_dir) {
- + error = -ENOMEM;
- + dev_err(dev, "Failed to create board_properties entry\n");
- + goto err_configure_sleep;
- + }
- +
- + sysfs_attr_init(&ft5x46->vkeys_attr.attr);
- + ft5x46->vkeys_attr.attr.name = "virtualkeys.ft5x46";
- + ft5x46->vkeys_attr.attr.mode = S_IRUGO;
- + ft5x46->vkeys_attr.show = ft5x46_vkeys_show;
- +
- + error = sysfs_create_file(ft5x46->vkeys_dir,
- + &ft5x46->vkeys_attr.attr);
- + if (error) {
- + dev_err(dev, "Failed to create virtual keys entry\n");
- + goto err_put_vkeys_dir;
- + }
- +
- +#ifdef FT5X46_APK_DEBUG_CHANNEL
- + error = ft5x46_create_apk_debug_channel(ft5x46);
- + if (error) {
- + dev_err(dev, "Failed to create APK debug channel\n");
- + goto err_sysfs_create_virtualkeys;
- + }
- +#endif
- + INIT_DELAYED_WORK(&ft5x46->noise_filter_delayed_work,
- + ft5x46_noise_filter_delayed_work);
- +
- + return ft5x46;
- +
- +#ifdef FT5X46_APK_DEBUG_CHANNEL
- +err_sysfs_create_virtualkeys:
- + sysfs_remove_file(ft5x46->vkeys_dir, &ft5x46->vkeys_attr.attr);
- +#endif
- +err_put_vkeys_dir:
- + kobject_put(ft5x46->vkeys_dir);
- +err_configure_sleep:
- + ft5x46_configure_sleep(ft5x46, false);
- +err_sysfs_create_group:
- + sysfs_remove_group(&dev->kobj, &ft5x46_attr_group);
- +err_free_irq:
- + free_irq(ft5x46->irq, ft5x46);
- +err_free_phys:
- + kfree(ft5x46->input->phys);
- +err_unregister_input:
- + input_unregister_device(ft5x46->input);
- + ft5x46->input = NULL;
- +err_free_input:
- + input_free_device(ft5x46->input);
- +err_pinctrl_init:
- + if (ft5x46->ts_pinctrl) {
- + devm_pinctrl_put(ft5x46->ts_pinctrl);
- + ft5x46->ts_pinctrl = NULL;
- + }
- +err_power:
- + if (pdata->power_on)
- + pdata->power_on(false);
- + else
- + ft5x46_power_on(ft5x46, false);
- +err_power_init:
- + if (pdata->power_init)
- + pdata->power_init(false);
- + else
- + ft5x46_power_init(ft5x46, false);
- +free_reset_gpio:
- + if (gpio_is_valid(pdata->reset_gpio))
- + gpio_free(pdata->reset_gpio);
- +free_irq_gpio:
- + if (gpio_is_valid(pdata->irq_gpio))
- + gpio_free(pdata->irq_gpio);
- +err_free_data:
- + kfree(ft5x46);
- +err:
- + return ERR_PTR(error);
- +}
- +EXPORT_SYMBOL_GPL(ft5x46_probe);
- +
- +void ft5x46_remove(struct ft5x46_data *ft5x46)
- +{
- + struct ft5x46_ts_platform_data *pdata = ft5x46->dev->platform_data;
- +
- + cancel_delayed_work_sync(&ft5x46->noise_filter_delayed_work);
- + ft5x46_configure_sleep(ft5x46, false);
- +#ifdef FT5X46_APK_DEBUG_CHANNEL
- + ft5x46_release_apk_debug_channel(ft5x46);
- +#endif
- + sysfs_remove_group(&ft5x46->dev->kobj, &ft5x46_attr_group);
- + free_irq(ft5x46->irq, ft5x46);
- + kfree(ft5x46->input->phys);
- + input_unregister_device(ft5x46->input);
- + if (pdata->firmware) {
- + if (pdata->firmware->data)
- + kfree(pdata->firmware->data);
- + kfree(pdata->firmware);
- + }
- + if (pdata->testdata)
- + kfree(pdata->testdata);
- + if (gpio_is_valid(pdata->reset_gpio))
- + gpio_free(pdata->reset_gpio);
- + if (gpio_is_valid(pdata->irq_gpio))
- + gpio_free(pdata->irq_gpio);
- + if (pdata->power_on)
- + pdata->power_on(false);
- + else
- + ft5x46_power_on(ft5x46, false);
- + if (pdata->power_init)
- + pdata->power_init(false);
- + else
- + ft5x46_power_init(ft5x46, false);
- + kfree(ft5x46);
- +}
- +EXPORT_SYMBOL_GPL(ft5x46_remove);
- +
- +MODULE_AUTHOR("Zhang Bo <zhangbo_a@xiaomi.com>");
- +MODULE_DESCRIPTION("ft5x0x touchscreen input driver");
- +MODULE_LICENSE("GPL");
- diff --git a/drivers/input/touchscreen/ft5x46/ft5x46_ts_i2c.c b/drivers/input/touchscreen/ft5x46/ft5x46_ts_i2c.c
- new file mode 100644
- index 0000000..c21b8f3
- --- /dev/null
- +++ b/drivers/input/touchscreen/ft5x46/ft5x46_ts_i2c.c
- @@ -0,0 +1,256 @@
- +/*
- + * Copyright (C) 2017 XiaoMi, Inc.
- + *
- + * 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 <linux/i2c.h>
- +#include <linux/input.h>
- +#include <linux/module.h>
- +#include <linux/interrupt.h>
- +#include <linux/input/ft5x46_ts.h>
- +#include "focaltech_test.h"
- +struct i2c_client *fts_i2c_client;
- +static int ft5x46_i2c_recv(struct device *dev,
- + void *buf, int len)
- +{
- + struct i2c_client *client = to_i2c_client(dev);
- + int count = i2c_master_recv(client, buf, len);
- + return count < 0 ? count : 0;
- +}
- +
- +static int ft5x46_i2c_send(struct device *dev,
- + const void *buf, int len)
- +{
- + struct i2c_client *client = to_i2c_client(dev);
- + int count = i2c_master_send(client, buf, len);
- + return count < 0 ? count : 0;
- +}
- +
- +/*******************************************************************************
- +* Name: fts_i2c_read
- +* Brief:
- +* Input:
- +* Output:
- +* Return:
- +*******************************************************************************/
- +int fts_i2c_read(struct i2c_client *client, char *writebuf,
- + int writelen, char *readbuf, int readlen)
- +{
- + int ret;
- +
- + if (readlen > 0) {
- + 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, "%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;
- +}
- +
- +int fts_i2c_write(struct i2c_client *client, char *writebuf, int writelen)
- +{
- + int ret;
- +
- + struct i2c_msg msgs[] = {
- + {
- + .addr = client->addr,
- + .flags = 0,
- + .len = writelen,
- + .buf = writebuf,
- + },
- + };
- +
- + if (writelen > 0) {
- + ret = i2c_transfer(client->adapter, msgs, 1);
- + if (ret < 0)
- + dev_err(&client->dev, "%s: i2c write error.\n",
- + __func__);
- + }
- + return ret;
- +}
- +
- +static int ft5x46_i2c_read(struct device *dev,
- + u8 addr, void *buf, u8 len)
- +{
- + struct i2c_client *client = to_i2c_client(dev);
- + int i, count = 0;
- +
- + for (i = 0; i < len; i += count) {
- + count = i2c_smbus_read_i2c_block_data(
- + client, addr + i, len - i, buf + i);
- + if (count < 0)
- + break;
- + }
- +
- + return count < 0 ? count : 0;
- +}
- +
- +static int ft5x46_i2c_write(struct device *dev,
- + u8 addr, const void *buf, u8 len)
- +{
- + struct i2c_client *client = to_i2c_client(dev);
- + int i, error = 0;
- +
- + for (i = 0; i < len; i += I2C_SMBUS_BLOCK_MAX) {
- + /* transfer at most I2C_SMBUS_BLOCK_MAX one time */
- + error = i2c_smbus_write_i2c_block_data(
- + client, addr + i, len - i, buf + i);
- + if (error)
- + break;
- + }
- +
- + return error;
- +}
- +
- +static const struct ft5x46_bus_ops ft5x46_i2c_bops = {
- + .bustype = BUS_I2C,
- + .recv = ft5x46_i2c_recv,
- + .send = ft5x46_i2c_send,
- + .read = ft5x46_i2c_read,
- + .write = ft5x46_i2c_write,
- +};
- +
- +static int ft5x46_i2c_probe(struct i2c_client *client,
- + const struct i2c_device_id *id)
- +{
- + struct ft5x46_data *ft5x46;
- +
- + if (!i2c_check_functionality(client->adapter,
- + I2C_FUNC_SMBUS_I2C_BLOCK)) {
- + dev_err(&client->dev, "incompatible i2c adapter.");
- + return -ENODEV;
- + }
- +
- + ft5x46 = ft5x46_probe(&client->dev, &ft5x46_i2c_bops);
- + if (IS_ERR(ft5x46))
- + return PTR_ERR(ft5x46);
- +
- +
- + i2c_set_clientdata(client, ft5x46);
- + fts_i2c_client = client;
- + fts_test_module_init(client);
- + device_init_wakeup(&client->dev, 1);
- +
- + return 0;
- +}
- +
- +static int ft5x46_i2c_remove(struct i2c_client *client)
- +{
- + struct ft5x46_data *ft5x0x = i2c_get_clientdata(client);
- + fts_test_module_exit(client);
- + ft5x46_remove(ft5x0x);
- + return 0;
- +}
- +
- +static const struct i2c_device_id ft5x46_i2c_id[] = {
- + {"ft5x46_i2c", 0},
- + {/* end list */}
- +};
- +MODULE_DEVICE_TABLE(i2c, ft5x0x_i2c_id);
- +
- +#ifdef CONFIG_OF
- +static struct of_device_id ft5x46_match_table[] = {
- + { .compatible = "ft,ft5x46_i2c", },
- + { },
- +};
- +#else
- +#define ft5x46_match_table NULL
- +#endif
- +
- +#ifdef CONFIG_PM
- +static int ft5x46_i2c_suspend(struct device *dev)
- +{
- + int ret = 0;
- +
- + if (device_may_wakeup(dev))
- + ret = ft5x46_pm_suspend(dev);
- +
- + return ret;
- +}
- +
- +static int ft5x46_i2c_resume(struct device *dev)
- +{
- + int ret = 0;
- +
- + if (device_may_wakeup(dev))
- + ret = ft5x46_pm_resume(dev);
- +
- + return ret;
- +}
- +
- +static const struct dev_pm_ops ft5x46_i2c_pm_ops = {
- +#ifndef CONFIG_HAS_EARLYSUSPEND
- + .suspend = ft5x46_i2c_suspend,
- + .resume = ft5x46_i2c_resume,
- +#endif
- +};
- +#endif
- +
- +static struct i2c_driver ft5x46_i2c_driver = {
- + .driver = {
- + .name = "ft5x46_i2c",
- + .owner = THIS_MODULE,
- + .of_match_table = ft5x46_match_table,
- +#ifdef CONFIG_PM
- + .pm = &ft5x46_i2c_pm_ops,
- +#endif
- + },
- + .probe = ft5x46_i2c_probe,
- + .remove = ft5x46_i2c_remove,
- + .id_table = ft5x46_i2c_id,
- +};
- +
- +static int __init ft5x46_i2c_init(void)
- +{
- + return i2c_add_driver(&ft5x46_i2c_driver);
- +}
- +late_initcall(ft5x46_i2c_init);
- +
- +static void __exit ft5x46_i2c_exit(void)
- +{
- + i2c_del_driver(&ft5x46_i2c_driver);
- +}
- +module_exit(ft5x46_i2c_exit);
- +
- +MODULE_ALIAS("i2c:ft5x46_i2c");
- +MODULE_AUTHOR("Tao Jun <taojun@xiaomi.com>");
- +MODULE_DESCRIPTION("i2c driver for ft5x46 touchscreen");
- +MODULE_LICENSE("GPL");
- diff --git a/drivers/input/touchscreen/ft5x46/ft5x46_ts_spi.c b/drivers/input/touchscreen/ft5x46/ft5x46_ts_spi.c
- new file mode 100644
- index 0000000..f7208e1
- --- /dev/null
- +++ b/drivers/input/touchscreen/ft5x46/ft5x46_ts_spi.c
- @@ -0,0 +1,133 @@
- +/*
- + * Copyright (C) 2017 XiaoMi, Inc.
- + *
- + * 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 <linux/input.h>
- +#include <linux/module.h>
- +#include <linux/spi/spi.h>
- +#include "ft5x46_ts.h"
- +
- +#define FT5X0X_SPI_READ 0x8000
- +
- +static int ft5x46_spi_xfer(struct device *dev,
- + u16 addr, const u8 *tx_buf, u8 *rx_buf, u8 len)
- +{
- + struct spi_device *spi = to_spi_device(dev);
- + struct spi_transfer xfers[2];
- + struct spi_message msg;
- +
- + spi_message_init(&msg);
- + memset(xfers, 0, sizeof(xfers));
- +
- + /* 16th bit indicate read(1) or write(0) */
- + if (tx_buf)
- + addr &= ~FT5X0X_SPI_READ;
- + else
- + addr |= FT5X0X_SPI_READ;
- + addr = cpu_to_be16(addr); /* MSB first */
- +
- + xfers[0].tx_buf = &addr;
- + xfers[0].len = sizeof(addr);
- + spi_message_add_tail(&xfers[0], &msg);
- +
- + xfers[1].tx_buf = tx_buf;
- + xfers[1].rx_buf = rx_buf;
- + xfers[1].len = len;
- + spi_message_add_tail(&xfers[1], &msg);
- +
- + return spi_sync(spi, &msg);
- +}
- +
- +static int ft5x46_spi_recv(struct device *dev,
- + void *buf, int len)
- +{
- + return ft5x46_spi_xfer(dev, 0, NULL, buf, len);
- +}
- +
- +static int ft5x46_spi_send(struct device *dev,
- + const void *buf, int len)
- +{
- + return ft5x46_spi_xfer(dev, 0, buf, NULL, len);
- +}
- +
- +static int ft5x46_spi_read(struct device *dev,
- + u8 addr, void *buf, u8 len)
- +{
- + return ft5x46_spi_xfer(dev, addr, NULL, buf, len);
- +}
- +
- +static int ft5x46_spi_write(struct device *dev,
- + u8 addr, const void *buf, u8 len)
- +{
- + return ft5x46_spi_xfer(dev, addr, buf, NULL, len);
- +}
- +
- +static const struct ft5x46_bus_ops ft5x46_spi_bops = {
- + .bustype = BUS_SPI,
- + .recv = ft5x46_spi_recv,
- + .send = ft5x46_spi_send,
- + .read = ft5x46_spi_read,
- + .write = ft5x46_spi_write,
- +};
- +
- +static int ft5x46_spi_probe(struct spi_device *spi)
- +{
- + struct ft5x46_data *ft5x46;
- +
- + ft5x46 = ft5x46_probe(&spi->dev, &ft5x46_spi_bops);
- + if (IS_ERR(ft5x46))
- + return PTR_ERR(ft5x46);
- +
- + spi_set_drvdata(spi, ft5x46);
- + return 0;
- +}
- +
- +static int ft5x46_spi_remove(struct spi_device *spi)
- +{
- + struct ft5x46_data *ft5x46 = spi_get_drvdata(spi);
- + ft5x46_remove(ft5x46);
- + return 0;
- +}
- +
- +static const struct spi_device_id ft5x46_spi_id[] = {
- + {"ft5x46_spi", 0},
- + {/* end list */}
- +};
- +MODULE_DEVICE_TABLE(spi, ft5x46_spi_id);
- +
- +static struct spi_driver ft5x46_spi_driver = {
- + .probe = ft5x46_spi_probe,
- + .remove = ft5x46_spi_remove,
- + .driver = {
- + .name = "ft5x46_spi",
- + .owner = THIS_MODULE,
- + },
- + .id_table = ft5x46_spi_id,
- +};
- +
- +static int __init ft5x46_spi_init(void)
- +{
- + return spi_register_driver(&ft5x46_spi_driver);
- +}
- +module_init(ft5x0x_spi_init);
- +
- +static void __exit ft5x46_spi_exit(void)
- +{
- + spi_unregister_driver(&ft5x46_spi_driver);
- +}
- +module_exit(ft5x46_spi_exit);
- +
- +MODULE_ALIAS("spi:ft5x46_spi");
- +MODULE_AUTHOR("Tao Jun <taojun@xiaomi.com>");
- +MODULE_DESCRIPTION("spi driver for ft5x0x touchscreen");
- +MODULE_LICENSE("GPL");
- diff --git a/drivers/input/touchscreen/synaptics_dsx_force/Kconfig b/drivers/input/touchscreen/synaptics_dsx_force/Kconfig
- new file mode 100644
- index 0000000..b34228f
- --- /dev/null
- +++ b/drivers/input/touchscreen/synaptics_dsx_force/Kconfig
- @@ -0,0 +1,124 @@
- +#
- +# Synaptics DSX touchscreen driver configuration
- +#
- +menuconfig TOUCHSCREEN_SYNAPTICS_DSX_FORCE
- + bool "Synaptics DSX touchscreen"
- + default y
- + help
- + Say Y here if you have a Synaptics DSX touchscreen connected
- + to your system.
- +
- + If unsure, say N.
- +
- +if TOUCHSCREEN_SYNAPTICS_DSX_FORCE
- +
- +choice
- + default TOUCHSCREEN_SYNAPTICS_DSX_I2C_FORCE
- + prompt "Synaptics DSX bus interface"
- +config TOUCHSCREEN_SYNAPTICS_DSX_I2C_FORCE
- + bool "RMI over I2C"
- + depends on I2C
- +config TOUCHSCREEN_SYNAPTICS_DSX_SPI_FORCE
- + bool "RMI over SPI"
- + depends on SPI_MASTER
- +config TOUCHSCREEN_SYNAPTICS_DSX_RMI_HID_I2C_FORCE
- + bool "HID over I2C"
- + depends on I2C
- +endchoice
- +
- +config TOUCHSCREEN_SYNAPTICS_DSX_CORE_FORCE
- + tristate "Synaptics DSX core driver module"
- + depends on I2C || SPI_MASTER
- + help
- + Say Y here to enable basic touch reporting functionality.
- +
- + If unsure, say N.
- +
- + To compile this driver as a module, choose M here: the
- + module will be called synaptics_dsx_core.
- +
- +config TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV_FORCE
- + tristate "Synaptics DSX RMI device module"
- + depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE_FORCE
- + help
- + Say Y here to enable support for direct RMI register access.
- +
- + If unsure, say N.
- +
- + To compile this driver as a module, choose M here: the
- + module will be called synaptics_dsx_rmi_dev.
- +
- +config TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_FORCE
- + tristate "Synaptics DSX firmware update module"
- + depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE_FORCE
- + help
- + Say Y here to enable support for doing firmware update.
- +
- + If unsure, say N.
- +
- + To compile this driver as a module, choose M here: the
- + module will be called synaptics_dsx_fw_update.
- +
- +config TOUCHSCREEN_SYNAPTICS_DSX_TEST_REPORTING_FORCE
- + tristate "Synaptics DSX test reporting module"
- + depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE_FORCE
- + help
- + Say Y here to enable support for retrieving production test reports.
- +
- + If unsure, say N.
- +
- + To compile this driver as a module, choose M here: the
- + module will be called synaptics_dsx_test_reporting.
- +
- +config TOUCHSCREEN_SYNAPTICS_DSX_PROXIMITY_FORCE
- + tristate "Synaptics DSX proximity module"
- + depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE_FORCE
- + help
- + Say Y here to enable support for proximity functionality.
- +
- + If unsure, say N.
- +
- + To compile this driver as a module, choose M here: the
- + module will be called synaptics_dsx_proximity.
- +
- +config TOUCHSCREEN_SYNAPTICS_DSX_ACTIVE_PEN_FORCE
- + tristate "Synaptics DSX active pen module"
- + depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE_FORCE
- + help
- + Say Y here to enable support for active pen functionality.
- +
- + If unsure, say N.
- +
- + To compile this driver as a module, choose M here: the
- + module will be called synaptics_dsx_active_pen.
- +
- +config TOUCHSCREEN_SYNAPTICS_DSX_GESTURE_FORCE
- + tristate "Synaptics DSX user defined gesture module"
- + depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE_FORCE
- + help
- + Say Y here to enable support for user defined gesture functionality.
- +
- + If unsure, say N.
- +
- + To compile this driver as a module, choose M here: the
- + module will be called synaptics_dsx_gesture.
- +
- +config TOUCHSCREEN_SYNAPTICS_DSX_VIDEO_FORCE
- + tristate "Synaptics DSX video module"
- + depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE_FORCE
- + help
- + Say Y here to enable support for video communication functionality.
- +
- + If unsure, say N.
- +
- + To compile this driver as a module, choose M here: the
- + module will be called synaptics_dsx_video.
- +
- +config TOUCH_DEBUG_FS
- + bool "touch debugfs suport"
- + default n
- + depends on DEBUG_FS
- + help
- + Say Y here to enable support for touch debugfs.
- +
- +endif
- diff --git a/drivers/input/touchscreen/synaptics_dsx_force/Makefile b/drivers/input/touchscreen/synaptics_dsx_force/Makefile
- new file mode 100644
- index 0000000..f613ea9
- --- /dev/null
- +++ b/drivers/input/touchscreen/synaptics_dsx_force/Makefile
- @@ -0,0 +1,17 @@
- +#
- +# Makefile for the Synaptics DSX touchscreen driver.
- +#
- +
- +# Each configuration option enables a list of files.
- +
- +obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_I2C_FORCE) += synaptics_dsx_i2c.o
- +obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_SPI_FORCE) += synaptics_dsx_spi.o
- +obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI_HID_I2C_FORCE) += synaptics_dsx_rmi_hid_i2c.o
- +obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE_FORCE) += synaptics_dsx_core.o
- +obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV_FORCE) += synaptics_dsx_rmi_dev.o
- +obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_FORCE) += synaptics_dsx_fw_update.o
- +obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_TEST_REPORTING_FORCE) += synaptics_dsx_test_reporting.o
- +obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_PROXIMITY_FORCE) += synaptics_dsx_proximity.o
- +obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_ACTIVE_PEN_FORCE) += synaptics_dsx_active_pen.o
- +obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_GESTURE_FORCE) += synaptics_dsx_gesture.o
- +obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_VIDEO_FORCE) += synaptics_dsx_video.o
- diff --git a/drivers/input/touchscreen/synaptics_dsx_force/synaptics_dsx_active_pen.c b/drivers/input/touchscreen/synaptics_dsx_force/synaptics_dsx_active_pen.c
- new file mode 100644
- index 0000000..38a0d4b
- --- /dev/null
- +++ b/drivers/input/touchscreen/synaptics_dsx_force/synaptics_dsx_active_pen.c
- @@ -0,0 +1,631 @@
- +/*
- + * Synaptics DSX touchscreen driver
- + *
- + * Copyright (C) 2012-2015 Synaptics Incorporated. All rights reserved.
- + *
- + * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
- + * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
- + * Copyright (C) 2017 XiaoMi, 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.
- + *
- + * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
- + * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
- + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
- + * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
- + * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- + * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
- + * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
- + * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- + * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
- + * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
- + * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
- + * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
- + * DOLLARS.
- + */
- +
- +#include <linux/kernel.h>
- +#include <linux/module.h>
- +#include <linux/slab.h>
- +#include <linux/interrupt.h>
- +#include <linux/delay.h>
- +#include <linux/input.h>
- +#include <linux/platform_device.h>
- +#include <linux/input/synaptics_dsx.h>
- +#include "synaptics_dsx_core.h"
- +
- +#define APEN_PHYS_NAME "synaptics_dsx/active_pen"
- +
- +#define ACTIVE_PEN_MAX_PRESSURE_16BIT 65535
- +#define ACTIVE_PEN_MAX_PRESSURE_8BIT 255
- +
- +struct synaptics_rmi4_f12_query_8 {
- + union {
- + struct {
- + unsigned char size_of_query9;
- + struct {
- + unsigned char data0_is_present:1;
- + unsigned char data1_is_present:1;
- + unsigned char data2_is_present:1;
- + unsigned char data3_is_present:1;
- + unsigned char data4_is_present:1;
- + unsigned char data5_is_present:1;
- + unsigned char data6_is_present:1;
- + unsigned char data7_is_present:1;
- + } __packed;
- + };
- + unsigned char data[2];
- + };
- +};
- +
- +struct apen_data_8b_pressure {
- + union {
- + struct {
- + unsigned char status_pen:1;
- + unsigned char status_invert:1;
- + unsigned char status_barrel:1;
- + unsigned char status_reserved:5;
- + unsigned char x_lsb;
- + unsigned char x_msb;
- + unsigned char y_lsb;
- + unsigned char y_msb;
- + unsigned char pressure_msb;
- + unsigned char battery_state;
- + unsigned char pen_id_0_7;
- + unsigned char pen_id_8_15;
- + unsigned char pen_id_16_23;
- + unsigned char pen_id_24_31;
- + } __packed;
- + unsigned char data[11];
- + };
- +};
- +
- +struct apen_data {
- + union {
- + struct {
- + unsigned char status_pen:1;
- + unsigned char status_invert:1;
- + unsigned char status_barrel:1;
- + unsigned char status_reserved:5;
- + unsigned char x_lsb;
- + unsigned char x_msb;
- + unsigned char y_lsb;
- + unsigned char y_msb;
- + unsigned char pressure_lsb;
- + unsigned char pressure_msb;
- + unsigned char battery_state;
- + unsigned char pen_id_0_7;
- + unsigned char pen_id_8_15;
- + unsigned char pen_id_16_23;
- + unsigned char pen_id_24_31;
- + } __packed;
- + unsigned char data[12];
- + };
- +};
- +
- +struct synaptics_rmi4_apen_handle {
- + bool apen_present;
- + unsigned char intr_mask;
- + unsigned char battery_state;
- + unsigned short query_base_addr;
- + unsigned short control_base_addr;
- + unsigned short data_base_addr;
- + unsigned short command_base_addr;
- + unsigned short apen_data_addr;
- + unsigned short max_pressure;
- + unsigned int pen_id;
- + struct input_dev *apen_dev;
- + struct apen_data *apen_data;
- + struct synaptics_rmi4_data *rmi4_data;
- +};
- +
- +static struct synaptics_rmi4_apen_handle *apen;
- +
- +DECLARE_COMPLETION(apen_remove_complete);
- +
- +static void apen_lift(void)
- +{
- + input_report_key(apen->apen_dev, BTN_TOUCH, 0);
- + input_report_key(apen->apen_dev, BTN_TOOL_PEN, 0);
- + input_report_key(apen->apen_dev, BTN_TOOL_RUBBER, 0);
- + input_sync(apen->apen_dev);
- + apen->apen_present = false;
- +
- + return;
- +}
- +
- +static void apen_report(void)
- +{
- + int retval;
- + int x;
- + int y;
- + int pressure;
- + static int invert = -1;
- + struct apen_data_8b_pressure *apen_data_8b;
- + struct synaptics_rmi4_data *rmi4_data = apen->rmi4_data;
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + apen->apen_data_addr,
- + apen->apen_data->data,
- + sizeof(apen->apen_data->data));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to read active pen data\n",
- + __func__);
- + return;
- + }
- +
- + if (apen->apen_data->status_pen == 0) {
- + if (apen->apen_present)
- + apen_lift();
- +
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: No active pen data\n",
- + __func__);
- +
- + return;
- + }
- +
- + x = (apen->apen_data->x_msb << 8) | (apen->apen_data->x_lsb);
- + y = (apen->apen_data->y_msb << 8) | (apen->apen_data->y_lsb);
- +
- + if ((x == -1) && (y == -1)) {
- + if (apen->apen_present)
- + apen_lift();
- +
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: Active pen in range but no valid x & y\n",
- + __func__);
- +
- + return;
- + }
- +
- + if (!apen->apen_present)
- + invert = -1;
- +
- + if (invert != -1 && invert != apen->apen_data->status_invert)
- + apen_lift();
- +
- + invert = apen->apen_data->status_invert;
- +
- + if (apen->max_pressure == ACTIVE_PEN_MAX_PRESSURE_16BIT) {
- + pressure = (apen->apen_data->pressure_msb << 8) |
- + apen->apen_data->pressure_lsb;
- + apen->battery_state = apen->apen_data->battery_state;
- + apen->pen_id = (apen->apen_data->pen_id_24_31 << 24) |
- + (apen->apen_data->pen_id_16_23 << 16) |
- + (apen->apen_data->pen_id_8_15 << 8) |
- + apen->apen_data->pen_id_0_7;
- + } else {
- + apen_data_8b = (struct apen_data_8b_pressure *)apen->apen_data;
- + pressure = apen_data_8b->pressure_msb;
- + apen->battery_state = apen_data_8b->battery_state;
- + apen->pen_id = (apen_data_8b->pen_id_24_31 << 24) |
- + (apen_data_8b->pen_id_16_23 << 16) |
- + (apen_data_8b->pen_id_8_15 << 8) |
- + apen_data_8b->pen_id_0_7;
- + }
- +
- + input_report_key(apen->apen_dev, BTN_TOUCH, pressure > 0 ? 1 : 0);
- + input_report_key(apen->apen_dev,
- + apen->apen_data->status_invert > 0 ?
- + BTN_TOOL_RUBBER : BTN_TOOL_PEN, 1);
- + input_report_key(apen->apen_dev,
- + BTN_STYLUS, apen->apen_data->status_barrel > 0 ?
- + 1 : 0);
- + input_report_abs(apen->apen_dev, ABS_X, x);
- + input_report_abs(apen->apen_dev, ABS_Y, y);
- + input_report_abs(apen->apen_dev, ABS_PRESSURE, pressure);
- +
- + input_sync(apen->apen_dev);
- +
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: Active pen: "
- + "status = %d, "
- + "invert = %d, "
- + "barrel = %d, "
- + "x = %d, "
- + "y = %d, "
- + "pressure = %d\n",
- + __func__,
- + apen->apen_data->status_pen,
- + apen->apen_data->status_invert,
- + apen->apen_data->status_barrel,
- + x, y, pressure);
- +
- + apen->apen_present = true;
- +
- + return;
- +}
- +
- +static void apen_set_params(void)
- +{
- + input_set_abs_params(apen->apen_dev, ABS_X, 0,
- + apen->rmi4_data->sensor_max_x, 0, 0);
- + input_set_abs_params(apen->apen_dev, ABS_Y, 0,
- + apen->rmi4_data->sensor_max_y, 0, 0);
- + input_set_abs_params(apen->apen_dev, ABS_PRESSURE, 0,
- + apen->max_pressure, 0, 0);
- +
- + return;
- +}
- +
- +static int apen_pressure(struct synaptics_rmi4_f12_query_8 *query_8)
- +{
- + int retval;
- + unsigned char ii;
- + unsigned char data_reg_presence;
- + unsigned char size_of_query_9;
- + unsigned char *query_9;
- + unsigned char *data_desc;
- + struct synaptics_rmi4_data *rmi4_data = apen->rmi4_data;
- +
- + data_reg_presence = query_8->data[1];
- +
- + size_of_query_9 = query_8->size_of_query9;
- + query_9 = kmalloc(size_of_query_9, GFP_KERNEL);
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + apen->query_base_addr + 9,
- + query_9,
- + size_of_query_9);
- + if (retval < 0)
- + goto exit;
- +
- + data_desc = query_9;
- +
- + for (ii = 0; ii < 6; ii++) {
- + if (!(data_reg_presence & (1 << ii)))
- + continue; /* The data register is not present */
- + data_desc++; /* Jump over the size entry */
- + while (*data_desc & (1 << 7))
- + data_desc++;
- + data_desc++; /* Go to the next descriptor */
- + }
- +
- + data_desc++; /* Jump over the size entry */
- + /* Check for the presence of subpackets 1 and 2 */
- + if ((*data_desc & (3 << 1)) == (3 << 1))
- + apen->max_pressure = ACTIVE_PEN_MAX_PRESSURE_16BIT;
- + else
- + apen->max_pressure = ACTIVE_PEN_MAX_PRESSURE_8BIT;
- +
- +exit:
- + kfree(query_9);
- +
- + return retval;
- +}
- +
- +static int apen_reg_init(void)
- +{
- + int retval;
- + unsigned char data_offset;
- + unsigned char size_of_query8;
- + struct synaptics_rmi4_f12_query_8 query_8;
- + struct synaptics_rmi4_data *rmi4_data = apen->rmi4_data;
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + apen->query_base_addr + 7,
- + &size_of_query8,
- + sizeof(size_of_query8));
- + if (retval < 0)
- + return retval;
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + apen->query_base_addr + 8,
- + query_8.data,
- + sizeof(query_8.data));
- + if (retval < 0)
- + return retval;
- +
- + if ((size_of_query8 >= 2) && (query_8.data6_is_present)) {
- + data_offset = query_8.data0_is_present +
- + query_8.data1_is_present +
- + query_8.data2_is_present +
- + query_8.data3_is_present +
- + query_8.data4_is_present +
- + query_8.data5_is_present;
- + apen->apen_data_addr = apen->data_base_addr + data_offset;
- + retval = apen_pressure(&query_8);
- + if (retval < 0)
- + return retval;
- + } else {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Active pen support unavailable\n",
- + __func__);
- + retval = -ENODEV;
- + }
- +
- + return retval;
- +}
- +
- +static int apen_scan_pdt(void)
- +{
- + int retval;
- + unsigned char ii;
- + unsigned char page;
- + unsigned char intr_count = 0;
- + unsigned char intr_off;
- + unsigned char intr_src;
- + unsigned short addr;
- + struct synaptics_rmi4_fn_desc fd;
- + struct synaptics_rmi4_data *rmi4_data = apen->rmi4_data;
- +
- + for (page = 0; page < PAGES_TO_SERVICE; page++) {
- + for (addr = PDT_START; addr > PDT_END; addr -= PDT_ENTRY_SIZE) {
- + addr |= (page << 8);
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + addr,
- + (unsigned char *)&fd,
- + sizeof(fd));
- + if (retval < 0)
- + return retval;
- +
- + addr &= ~(MASK_8BIT << 8);
- +
- + if (fd.fn_number) {
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: Found F%02x\n",
- + __func__, fd.fn_number);
- + switch (fd.fn_number) {
- + case SYNAPTICS_RMI4_F12:
- + goto f12_found;
- + break;
- + }
- + } else {
- + break;
- + }
- +
- + intr_count += fd.intr_src_count;
- + }
- + }
- +
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to find F12\n",
- + __func__);
- + return -EINVAL;
- +
- +f12_found:
- + apen->query_base_addr = fd.query_base_addr | (page << 8);
- + apen->control_base_addr = fd.ctrl_base_addr | (page << 8);
- + apen->data_base_addr = fd.data_base_addr | (page << 8);
- + apen->command_base_addr = fd.cmd_base_addr | (page << 8);
- +
- + retval = apen_reg_init();
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to initialize active pen registers\n",
- + __func__);
- + return retval;
- + }
- +
- + apen->intr_mask = 0;
- + intr_src = fd.intr_src_count;
- + intr_off = intr_count % 8;
- + for (ii = intr_off;
- + ii < (intr_src + intr_off);
- + ii++) {
- + apen->intr_mask |= 1 << ii;
- + }
- +
- + rmi4_data->intr_mask[0] |= apen->intr_mask;
- +
- + addr = rmi4_data->f01_ctrl_base_addr + 1;
- +
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + addr,
- + &(rmi4_data->intr_mask[0]),
- + sizeof(rmi4_data->intr_mask[0]));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to set interrupt enable bit\n",
- + __func__);
- + return retval;
- + }
- +
- + return 0;
- +}
- +
- +static void synaptics_rmi4_apen_attn(struct synaptics_rmi4_data *rmi4_data,
- + unsigned char intr_mask)
- +{
- + if (!apen)
- + return;
- +
- + if (apen->intr_mask & intr_mask)
- + apen_report();
- +
- + return;
- +}
- +
- +static int synaptics_rmi4_apen_init(struct synaptics_rmi4_data *rmi4_data)
- +{
- + int retval;
- +
- + if (apen) {
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: Handle already exists\n",
- + __func__);
- + return 0;
- + }
- +
- + apen = kzalloc(sizeof(*apen), GFP_KERNEL);
- + if (!apen) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to alloc mem for apen\n",
- + __func__);
- + retval = -ENOMEM;
- + goto exit;
- + }
- +
- + apen->apen_data = kzalloc(sizeof(*(apen->apen_data)), GFP_KERNEL);
- + if (!apen->apen_data) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to alloc mem for apen_data\n",
- + __func__);
- + retval = -ENOMEM;
- + goto exit_free_apen;
- + }
- +
- + apen->rmi4_data = rmi4_data;
- +
- + retval = apen_scan_pdt();
- + if (retval < 0)
- + goto exit_free_apen_data;
- +
- + apen->apen_dev = input_allocate_device();
- + if (apen->apen_dev == NULL) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to allocate active pen device\n",
- + __func__);
- + retval = -ENOMEM;
- + goto exit_free_apen_data;
- + }
- +
- + apen->apen_dev->name = ACTIVE_PEN_DRIVER_NAME;
- + apen->apen_dev->phys = APEN_PHYS_NAME;
- + apen->apen_dev->id.product = SYNAPTICS_DSX_DRIVER_PRODUCT;
- + apen->apen_dev->id.version = SYNAPTICS_DSX_DRIVER_VERSION;
- + apen->apen_dev->dev.parent = rmi4_data->pdev->dev.parent;
- + input_set_drvdata(apen->apen_dev, rmi4_data);
- +
- + set_bit(EV_KEY, apen->apen_dev->evbit);
- + set_bit(EV_ABS, apen->apen_dev->evbit);
- + set_bit(BTN_TOUCH, apen->apen_dev->keybit);
- + set_bit(BTN_TOOL_PEN, apen->apen_dev->keybit);
- + set_bit(BTN_TOOL_RUBBER, apen->apen_dev->keybit);
- + set_bit(BTN_STYLUS, apen->apen_dev->keybit);
- +#ifdef INPUT_PROP_DIRECT
- + set_bit(INPUT_PROP_DIRECT, apen->apen_dev->propbit);
- +#endif
- +
- + apen_set_params();
- +
- + retval = input_register_device(apen->apen_dev);
- + if (retval) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to register active pen device\n",
- + __func__);
- + goto exit_free_input_device;
- + }
- +
- + return 0;
- +
- +exit_free_input_device:
- + input_free_device(apen->apen_dev);
- +
- +exit_free_apen_data:
- + kfree(apen->apen_data);
- +
- +exit_free_apen:
- + kfree(apen);
- + apen = NULL;
- +
- +exit:
- + return retval;
- +}
- +
- +static void synaptics_rmi4_apen_remove(struct synaptics_rmi4_data *rmi4_data)
- +{
- + if (!apen)
- + goto exit;
- +
- + input_unregister_device(apen->apen_dev);
- + kfree(apen->apen_data);
- + kfree(apen);
- + apen = NULL;
- +
- +exit:
- + complete(&apen_remove_complete);
- +
- + return;
- +}
- +
- +static void synaptics_rmi4_apen_reset(struct synaptics_rmi4_data *rmi4_data)
- +{
- + if (!apen) {
- + synaptics_rmi4_apen_init(rmi4_data);
- + return;
- + }
- +
- + apen_lift();
- +
- + apen_scan_pdt();
- +
- + return;
- +}
- +
- +static void synaptics_rmi4_apen_reinit(struct synaptics_rmi4_data *rmi4_data)
- +{
- + if (!apen)
- + return;
- +
- + apen_lift();
- +
- + return;
- +}
- +
- +static void synaptics_rmi4_apen_e_suspend(struct synaptics_rmi4_data *rmi4_data)
- +{
- + if (!apen)
- + return;
- +
- + apen_lift();
- +
- + return;
- +}
- +
- +static void synaptics_rmi4_apen_suspend(struct synaptics_rmi4_data *rmi4_data)
- +{
- + if (!apen)
- + return;
- +
- + apen_lift();
- +
- + return;
- +}
- +
- +static struct synaptics_rmi4_exp_fn active_pen_module = {
- + .fn_type = RMI_ACTIVE_PEN,
- + .init = synaptics_rmi4_apen_init,
- + .remove = synaptics_rmi4_apen_remove,
- + .reset = synaptics_rmi4_apen_reset,
- + .reinit = synaptics_rmi4_apen_reinit,
- + .early_suspend = synaptics_rmi4_apen_e_suspend,
- + .suspend = synaptics_rmi4_apen_suspend,
- + .resume = NULL,
- + .late_resume = NULL,
- + .attn = synaptics_rmi4_apen_attn,
- +};
- +
- +static int __init rmi4_active_pen_module_init(void)
- +{
- + synaptics_rmi4_new_function_force(&active_pen_module, true);
- +
- + return 0;
- +}
- +
- +static void __exit rmi4_active_pen_module_exit(void)
- +{
- + synaptics_rmi4_new_function_force(&active_pen_module, false);
- +
- + wait_for_completion(&apen_remove_complete);
- +
- + return;
- +}
- +
- +module_init(rmi4_active_pen_module_init);
- +module_exit(rmi4_active_pen_module_exit);
- +
- +MODULE_AUTHOR("Synaptics, Inc.");
- +MODULE_DESCRIPTION("Synaptics DSX Active Pen Module");
- +MODULE_LICENSE("GPL v2");
- diff --git a/drivers/input/touchscreen/synaptics_dsx_force/synaptics_dsx_core.c b/drivers/input/touchscreen/synaptics_dsx_force/synaptics_dsx_core.c
- new file mode 100644
- index 0000000..f61f2f0
- --- /dev/null
- +++ b/drivers/input/touchscreen/synaptics_dsx_force/synaptics_dsx_core.c
- @@ -0,0 +1,5987 @@
- +/*
- + * Synaptics DSX touchscreen driver
- + *
- + * Copyright (C) 2012-2015 Synaptics Incorporated. All rights reserved.
- + *
- + * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
- + * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
- + * Copyright (C) 2017 XiaoMi, 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.
- + *
- + * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
- + * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
- + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
- + * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
- + * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- + * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
- + * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
- + * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- + * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
- + * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
- + * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
- + * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
- + * DOLLARS.
- + */
- +
- +#include <linux/kernel.h>
- +#include <linux/module.h>
- +#include <linux/slab.h>
- +#include <linux/interrupt.h>
- +#include <linux/delay.h>
- +#include <linux/input.h>
- +#include <linux/gpio.h>
- +#include <linux/platform_device.h>
- +#include <linux/regulator/consumer.h>
- +#include <linux/input/synaptics_dsx.h>
- +#include <linux/hwinfo.h>
- +#include "synaptics_dsx_core.h"
- +#ifdef KERNEL_ABOVE_2_6_38
- +#include <linux/input/mt.h>
- +#endif
- +
- +#if defined(CONFIG_SECURE_TOUCH)
- +#include <linux/pm_runtime.h>
- +#include <linux/errno.h>
- +#endif
- +
- +#ifdef CONFIG_TOUCH_DEBUG_FS
- +#include <linux/fs.h>
- +#include <linux/debugfs.h>
- +#include <linux/uaccess.h>
- +#endif
- +#include <linux/mdss_io_util.h>
- +
- +#define INPUT_PHYS_NAME "synaptics_dsx/touch_input"
- +#define STYLUS_PHYS_NAME "synaptics_dsx/stylus"
- +
- +#define VIRTUAL_KEY_MAP_FILE_NAME "virtualkeys." PLATFORM_DRIVER_NAME
- +
- +#ifdef KERNEL_ABOVE_2_6_38
- +#define TYPE_B_PROTOCOL
- +#endif
- +
- +#define WAKEUP_GESTURE false
- +
- +#define NO_0D_WHILE_2D
- +#define REPORT_2D_Z
- +#define REPORT_2D_W
- +
- +#define REPORT_2D_PRESSURE
- +
- +
- +#define F12_DATA_15_WORKAROUND
- +
- +#define IGNORE_FN_INIT_FAILURE
- +/*
- +#define FB_READY_RESET
- +#define FB_READY_WAIT_MS 100
- +#define FB_READY_TIMEOUT_S 30
- +*/
- +#define RPT_TYPE (1 << 0)
- +#define RPT_X_LSB (1 << 1)
- +#define RPT_X_MSB (1 << 2)
- +#define RPT_Y_LSB (1 << 3)
- +#define RPT_Y_MSB (1 << 4)
- +#define RPT_Z (1 << 5)
- +#define RPT_WX (1 << 6)
- +#define RPT_WY (1 << 7)
- +#define RPT_DEFAULT (RPT_TYPE | RPT_X_LSB | RPT_X_MSB | RPT_Y_LSB | RPT_Y_MSB)
- +
- +#define REBUILD_WORK_DELAY_MS 500 /* ms */
- +
- +#define EXP_FN_WORK_DELAY_MS 500 /* ms */
- +#define MAX_F11_TOUCH_WIDTH 15
- +#define MAX_F12_TOUCH_WIDTH 255
- +#define MAX_F12_TOUCH_PRESSURE 255
- +
- +#define CHECK_STATUS_TIMEOUT_MS 100
- +
- +#define F01_STD_QUERY_LEN 21
- +#define F01_BUID_ID_OFFSET 18
- +#define F01_PROD_ID_OFFSET 11
- +
- +#define STATUS_NO_ERROR 0x00
- +#define STATUS_RESET_OCCURRED 0x01
- +#define STATUS_INVALID_CONFIG 0x02
- +#define STATUS_DEVICE_FAILURE 0x03
- +#define STATUS_CONFIG_CRC_FAILURE 0x04
- +#define STATUS_FIRMWARE_CRC_FAILURE 0x05
- +#define STATUS_CRC_IN_PROGRESS 0x06
- +
- +#define NORMAL_OPERATION (0 << 0)
- +#define SENSOR_SLEEP (1 << 0)
- +#define NO_SLEEP_OFF (0 << 2)
- +#define NO_SLEEP_ON (1 << 2)
- +#define CONFIGURED (1 << 7)
- +
- +#define F11_CONTINUOUS_MODE 0x00
- +#define F11_WAKEUP_GESTURE_MODE 0x04
- +#define F12_CONTINUOUS_MODE 0x00
- +#define F12_WAKEUP_GESTURE_MODE 0x02
- +#define F12_UDG_DETECT 0x0f
- +#define F12_HOMEKEY_DETECT 0x0c
- +
- +#define DOUBLE_TAP 0x01
- +#define HOMEKEY_WAKEUP 0x80
- +
- +#define INPUT_EVENT_START 0
- +#define INPUT_EVENT_SENSITIVE_MODE_OFF 0
- +#define INPUT_EVENT_SENSITIVE_MODE_ON 1
- +#define INPUT_EVENT_STYLUS_MODE_OFF 2
- +#define INPUT_EVENT_STYLUS_MODE_ON 3
- +#define INPUT_EVENT_WAKUP_MODE_OFF 4
- +#define INPUT_EVENT_WAKUP_MODE_ON 5
- +#define INPUT_EVENT_COVER_MODE_OFF 6
- +#define INPUT_EVENT_COVER_MODE_ON 7
- +#define INPUT_EVENT_END 7
- +
- +#define BUTTON_WG_EN 1
- +
- +static int synaptics_rmi4_check_status(struct synaptics_rmi4_data *rmi4_data,
- + bool *was_in_bl_mode);
- +static int synaptics_rmi4_free_fingers(struct synaptics_rmi4_data *rmi4_data);
- +static int synaptics_rmi4_reinit_device(struct synaptics_rmi4_data *rmi4_data);
- +static int synaptics_rmi4_reset_device(struct synaptics_rmi4_data *rmi4_data,
- + bool rebuild);
- +static void synaptics_rmi4_sleep_enable(struct synaptics_rmi4_data *rmi4_data,
- + bool enable);
- +static void synaptics_rmi4_wakeup_gesture(struct synaptics_rmi4_data *rmi4_data,
- + bool enable);
- +static int synaptics_rmi4_irq_enable(struct synaptics_rmi4_data *rmi4_data,
- + bool enable, bool attn_only);
- +static void synaptics_rmi4_wakeup_reconfigure(struct synaptics_rmi4_data *rmi4_data,
- + bool enable);
- +
- +#if defined(CONFIG_SECURE_TOUCH)
- +static ssize_t synaptics_secure_touch_enable_show(struct device *dev,
- + struct device_attribute *attr, char *buf);
- +
- +static ssize_t synaptics_secure_touch_enable_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count);
- +
- +static ssize_t synaptics_secure_touch_show(struct device *dev,
- + struct device_attribute *attr, char *buf);
- +#endif
- +
- +#ifdef CONFIG_FB
- +static int synaptics_rmi4_fb_notifier_cb(struct notifier_block *self,
- + unsigned long event, void *data);
- +static int synaptics_rmi4_fb_notifier_cb_tddi(struct notifier_block *self,
- + unsigned long event, void *data);
- +#endif
- +
- +#define DISP_REG_VDD (1<<0)
- +#define DISP_REG_LAB (1<<1)
- +#define DISP_REG_IBB (1<<2)
- +#define DISP_REG_ALL (DISP_REG_VDD | DISP_REG_LAB | DISP_REG_IBB)
- +
- +static void mdss_regulator_ctrl(struct synaptics_rmi4_data *rmi4_data, unsigned int flag, bool enable);
- +static void mdss_reset_ctrl(const struct synaptics_dsx_board_data *bdata, bool on);
- +static void mdss_reset_action(const struct synaptics_dsx_board_data *bdata);
- +
- +#ifdef CONFIG_HAS_EARLYSUSPEND
- +#ifndef CONFIG_FB
- +#define USE_EARLYSUSPEND
- +#endif
- +#endif
- +
- +#ifdef USE_EARLYSUSPEND
- +static void synaptics_rmi4_early_suspend(struct early_suspend *h);
- +
- +static void synaptics_rmi4_late_resume(struct early_suspend *h);
- +#endif
- +static irqreturn_t synaptics_rmi4_irq(int irq, void *data);
- +static int synaptics_rmi4_suspend(struct device *dev);
- +
- +static int synaptics_rmi4_resume(struct device *dev);
- +
- +static ssize_t synaptics_rmi4_f01_reset_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count);
- +
- +static ssize_t synaptics_rmi4_f01_productinfo_show(struct device *dev,
- + struct device_attribute *attr, char *buf);
- +
- +static ssize_t synaptics_rmi4_f01_buildid_show(struct device *dev,
- + struct device_attribute *attr, char *buf);
- +
- +static ssize_t synaptics_rmi4_f01_flashprog_show(struct device *dev,
- + struct device_attribute *attr, char *buf);
- +
- +static ssize_t synaptics_rmi4_0dbutton_show(struct device *dev,
- + struct device_attribute *attr, char *buf);
- +
- +static ssize_t synaptics_rmi4_0dbutton_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count);
- +
- +static ssize_t synaptics_rmi4_suspend_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count);
- +
- +static ssize_t synaptics_rmi4_wake_gesture_show(struct device *dev,
- + struct device_attribute *attr, char *buf);
- +
- +static ssize_t synaptics_rmi4_wake_gesture_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count);
- +
- +static ssize_t synaptics_rmi4_irq_enable_show(struct device *dev,
- + struct device_attribute *attr, char *buf);
- +
- +static ssize_t synaptics_rmi4_irq_enable_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count);
- +
- +static ssize_t synaptics_rmi4_panel_color_show(struct device *dev,
- + struct device_attribute *attr, char *buf);
- +
- +static ssize_t synaptics_rmi4_panel_vendor_show(struct device *dev,
- + struct device_attribute *attr, char *buf);
- +
- +static ssize_t synaptics_rmi4_virtual_key_map_show(struct kobject *kobj,
- + struct kobj_attribute *attr, char *buf);
- +
- +struct synaptics_rmi4_f01_device_status {
- + union {
- + struct {
- + unsigned char status_code:4;
- + unsigned char reserved:2;
- + unsigned char flash_prog:1;
- + unsigned char unconfigured:1;
- + } __packed;
- + unsigned char data[1];
- + };
- +};
- +
- +struct synaptics_rmi4_f11_query_0_5 {
- + union {
- + struct {
- + /* query 0 */
- + unsigned char f11_query0_b0__2:3;
- + unsigned char has_query_9:1;
- + unsigned char has_query_11:1;
- + unsigned char has_query_12:1;
- + unsigned char has_query_27:1;
- + unsigned char has_query_28:1;
- +
- + /* query 1 */
- + unsigned char num_of_fingers:3;
- + unsigned char has_rel:1;
- + unsigned char has_abs:1;
- + unsigned char has_gestures:1;
- + unsigned char has_sensitibity_adjust:1;
- + unsigned char f11_query1_b7:1;
- +
- + /* query 2 */
- + unsigned char num_of_x_electrodes;
- +
- + /* query 3 */
- + unsigned char num_of_y_electrodes;
- +
- + /* query 4 */
- + unsigned char max_electrodes:7;
- + unsigned char f11_query4_b7:1;
- +
- + /* query 5 */
- + unsigned char abs_data_size:2;
- + unsigned char has_anchored_finger:1;
- + unsigned char has_adj_hyst:1;
- + unsigned char has_dribble:1;
- + unsigned char has_bending_correction:1;
- + unsigned char has_large_object_suppression:1;
- + unsigned char has_jitter_filter:1;
- + } __packed;
- + unsigned char data[6];
- + };
- +};
- +
- +struct synaptics_rmi4_f11_query_7_8 {
- + union {
- + struct {
- + /* query 7 */
- + unsigned char has_single_tap:1;
- + unsigned char has_tap_and_hold:1;
- + unsigned char has_double_tap:1;
- + unsigned char has_early_tap:1;
- + unsigned char has_flick:1;
- + unsigned char has_press:1;
- + unsigned char has_pinch:1;
- + unsigned char has_chiral_scroll:1;
- +
- + /* query 8 */
- + unsigned char has_palm_detect:1;
- + unsigned char has_rotate:1;
- + unsigned char has_touch_shapes:1;
- + unsigned char has_scroll_zones:1;
- + unsigned char individual_scroll_zones:1;
- + unsigned char has_multi_finger_scroll:1;
- + unsigned char has_multi_finger_scroll_edge_motion:1;
- + unsigned char has_multi_finger_scroll_inertia:1;
- + } __packed;
- + unsigned char data[2];
- + };
- +};
- +
- +struct synaptics_rmi4_f11_query_9 {
- + union {
- + struct {
- + unsigned char has_pen:1;
- + unsigned char has_proximity:1;
- + unsigned char has_large_object_sensitivity:1;
- + unsigned char has_suppress_on_large_object_detect:1;
- + unsigned char has_two_pen_thresholds:1;
- + unsigned char has_contact_geometry:1;
- + unsigned char has_pen_hover_discrimination:1;
- + unsigned char has_pen_hover_and_edge_filters:1;
- + } __packed;
- + unsigned char data[1];
- + };
- +};
- +
- +struct synaptics_rmi4_f11_query_12 {
- + union {
- + struct {
- + unsigned char has_small_object_detection:1;
- + unsigned char has_small_object_detection_tuning:1;
- + unsigned char has_8bit_w:1;
- + unsigned char has_2d_adjustable_mapping:1;
- + unsigned char has_general_information_2:1;
- + unsigned char has_physical_properties:1;
- + unsigned char has_finger_limit:1;
- + unsigned char has_linear_cofficient_2:1;
- + } __packed;
- + unsigned char data[1];
- + };
- +};
- +
- +struct synaptics_rmi4_f11_query_27 {
- + union {
- + struct {
- + unsigned char f11_query27_b0:1;
- + unsigned char has_pen_position_correction:1;
- + unsigned char has_pen_jitter_filter_coefficient:1;
- + unsigned char has_group_decomposition:1;
- + unsigned char has_wakeup_gesture:1;
- + unsigned char has_small_finger_correction:1;
- + unsigned char has_data_37:1;
- + unsigned char f11_query27_b7:1;
- + } __packed;
- + unsigned char data[1];
- + };
- +};
- +
- +struct synaptics_rmi4_f11_ctrl_6_9 {
- + union {
- + struct {
- + unsigned char sensor_max_x_pos_7_0;
- + unsigned char sensor_max_x_pos_11_8:4;
- + unsigned char f11_ctrl7_b4__7:4;
- + unsigned char sensor_max_y_pos_7_0;
- + unsigned char sensor_max_y_pos_11_8:4;
- + unsigned char f11_ctrl9_b4__7:4;
- + } __packed;
- + unsigned char data[4];
- + };
- +};
- +
- +struct synaptics_rmi4_f11_data_1_5 {
- + union {
- + struct {
- + unsigned char x_position_11_4;
- + unsigned char y_position_11_4;
- + unsigned char x_position_3_0:4;
- + unsigned char y_position_3_0:4;
- + unsigned char wx:4;
- + unsigned char wy:4;
- + unsigned char z;
- + } __packed;
- + unsigned char data[5];
- + };
- +};
- +
- +struct synaptics_rmi4_f12_query_5 {
- + union {
- + struct {
- + unsigned char size_of_query6;
- + struct {
- + unsigned char ctrl0_is_present:1;
- + unsigned char ctrl1_is_present:1;
- + unsigned char ctrl2_is_present:1;
- + unsigned char ctrl3_is_present:1;
- + unsigned char ctrl4_is_present:1;
- + unsigned char ctrl5_is_present:1;
- + unsigned char ctrl6_is_present:1;
- + unsigned char ctrl7_is_present:1;
- + } __packed;
- + struct {
- + unsigned char ctrl8_is_present:1;
- + unsigned char ctrl9_is_present:1;
- + unsigned char ctrl10_is_present:1;
- + unsigned char ctrl11_is_present:1;
- + unsigned char ctrl12_is_present:1;
- + unsigned char ctrl13_is_present:1;
- + unsigned char ctrl14_is_present:1;
- + unsigned char ctrl15_is_present:1;
- + } __packed;
- + struct {
- + unsigned char ctrl16_is_present:1;
- + unsigned char ctrl17_is_present:1;
- + unsigned char ctrl18_is_present:1;
- + unsigned char ctrl19_is_present:1;
- + unsigned char ctrl20_is_present:1;
- + unsigned char ctrl21_is_present:1;
- + unsigned char ctrl22_is_present:1;
- + unsigned char ctrl23_is_present:1;
- + } __packed;
- + struct {
- + unsigned char ctrl24_is_present:1;
- + unsigned char ctrl25_is_present:1;
- + unsigned char ctrl26_is_present:1;
- + unsigned char ctrl27_is_present:1;
- + unsigned char ctrl28_is_present:1;
- + unsigned char ctrl29_is_present:1;
- + unsigned char ctrl30_is_present:1;
- + unsigned char ctrl31_is_present:1;
- + } __packed;
- + struct {
- + unsigned char ctrl32_is_present:1;
- + unsigned char ctrl33_is_present:1;
- + unsigned char ctrl34_is_present:1;
- + unsigned char ctrl35_is_present:1;
- + unsigned char ctrl36_is_present:1;
- + unsigned char ctrl37_is_present:1;
- + unsigned char ctrl38_is_present:1;
- + unsigned char ctrl39_is_present:1;
- + } __packed;
- + struct {
- + unsigned char ctrl40_is_present:1;
- + unsigned char ctrl41_is_present:1;
- + unsigned char ctrl42_is_present:1;
- + unsigned char ctrl43_is_present:1;
- + unsigned char ctrl44_is_present:1;
- + unsigned char ctrl45_is_present:1;
- + unsigned char ctrl46_is_present:1;
- + unsigned char ctrl47_is_present:1;
- + } __packed;
- + struct {
- + unsigned char ctrl48_is_present:1;
- + unsigned char ctrl49_is_present:1;
- + unsigned char ctrl50_is_present:1;
- + unsigned char ctrl51_is_present:1;
- + unsigned char ctrl52_is_present:1;
- + unsigned char ctrl53_is_present:1;
- + unsigned char ctrl54_is_present:1;
- + unsigned char ctrl55_is_present:1;
- + } __packed;
- + struct {
- + unsigned char ctrl56_is_present:1;
- + unsigned char ctrl57_is_present:1;
- + unsigned char ctrl58_is_present:1;
- + unsigned char ctrl59_is_present:1;
- + unsigned char ctrl60_is_present:1;
- + unsigned char ctrl61_is_present:1;
- + unsigned char ctrl62_is_present:1;
- + unsigned char ctrl63_is_present:1;
- + } __packed;
- + };
- + unsigned char data[9];
- + };
- +};
- +
- +struct synaptics_rmi4_f12_query_8 {
- + union {
- + struct {
- + unsigned char size_of_query9;
- + struct {
- + unsigned char data0_is_present:1;
- + unsigned char data1_is_present:1;
- + unsigned char data2_is_present:1;
- + unsigned char data3_is_present:1;
- + unsigned char data4_is_present:1;
- + unsigned char data5_is_present:1;
- + unsigned char data6_is_present:1;
- + unsigned char data7_is_present:1;
- + } __packed;
- + struct {
- + unsigned char data8_is_present:1;
- + unsigned char data9_is_present:1;
- + unsigned char data10_is_present:1;
- + unsigned char data11_is_present:1;
- + unsigned char data12_is_present:1;
- + unsigned char data13_is_present:1;
- + unsigned char data14_is_present:1;
- + unsigned char data15_is_present:1;
- + } __packed;
- + struct {
- + unsigned char data16_is_present:1;
- + unsigned char data17_is_present:1;
- + unsigned char data18_is_present:1;
- + unsigned char data19_is_present:1;
- + unsigned char data20_is_present:1;
- + unsigned char data21_is_present:1;
- + unsigned char data22_is_present:1;
- + unsigned char data23_is_present:1;
- + } __packed;
- + struct {
- + unsigned char data24_is_present:1;
- + unsigned char data25_is_present:1;
- + unsigned char data26_is_present:1;
- + unsigned char data27_is_present:1;
- + unsigned char data28_is_present:1;
- + unsigned char data29_is_present:1;
- + unsigned char data30_is_present:1;
- + unsigned char data31_is_present:1;
- + } __packed;
- + };
- + unsigned char data[5];
- + };
- +};
- +
- +struct synaptics_rmi4_f12_ctrl_8 {
- + union {
- + struct {
- + unsigned char max_x_coord_lsb;
- + unsigned char max_x_coord_msb;
- + unsigned char max_y_coord_lsb;
- + unsigned char max_y_coord_msb;
- + unsigned char rx_pitch_lsb;
- + unsigned char rx_pitch_msb;
- + unsigned char tx_pitch_lsb;
- + unsigned char tx_pitch_msb;
- + unsigned char low_rx_clip;
- + unsigned char high_rx_clip;
- + unsigned char low_tx_clip;
- + unsigned char high_tx_clip;
- + unsigned char num_of_rx;
- + unsigned char num_of_tx;
- + };
- + unsigned char data[14];
- + };
- +};
- +
- +struct synaptics_rmi4_f12_ctrl_23 {
- + union {
- + struct {
- + unsigned char finger_enable:1;
- + unsigned char active_stylus_enable:1;
- + unsigned char palm_enable:1;
- + unsigned char unclassified_object_enable:1;
- + unsigned char hovering_finger_enable:1;
- + unsigned char gloved_finger_enable:1;
- + unsigned char f12_ctr23_00_b6__7:2;
- + unsigned char max_reported_objects;
- + unsigned char f12_ctr23_02_b0:1;
- + unsigned char report_active_stylus_as_finger:1;
- + unsigned char report_palm_as_finger:1;
- + unsigned char report_unclassified_object_as_finger:1;
- + unsigned char report_hovering_finger_as_finger:1;
- + unsigned char report_gloved_finger_as_finger:1;
- + unsigned char report_narrow_object_swipe_as_finger:1;
- + unsigned char report_handedge_as_finger:1;
- + unsigned char cover_enable:1;
- + unsigned char stylus_enable:1;
- + unsigned char eraser_enable:1;
- + unsigned char small_object_enable:1;
- + unsigned char f12_ctr23_03_b4__7:4;
- + unsigned char report_cover_as_finger:1;
- + unsigned char report_stylus_as_finger:1;
- + unsigned char report_eraser_as_finger:1;
- + unsigned char report_small_object_as_finger:1;
- + unsigned char f12_ctr23_04_b4__7:4;
- + };
- + unsigned char data[5];
- + };
- +};
- +
- +struct synaptics_rmi4_f12_ctrl_31 {
- + union {
- + struct {
- + unsigned char max_x_coord_lsb;
- + unsigned char max_x_coord_msb;
- + unsigned char max_y_coord_lsb;
- + unsigned char max_y_coord_msb;
- + unsigned char rx_pitch_lsb;
- + unsigned char rx_pitch_msb;
- + unsigned char rx_clip_low;
- + unsigned char rx_clip_high;
- + unsigned char wedge_clip_low;
- + unsigned char wedge_clip_high;
- + unsigned char num_of_p;
- + unsigned char num_of_q;
- + };
- + unsigned char data[12];
- + };
- +};
- +
- +struct synaptics_rmi4_f12_ctrl_58 {
- + union {
- + struct {
- + unsigned char reporting_format;
- + unsigned char f12_ctr58_00_reserved;
- + unsigned char min_force_lsb;
- + unsigned char min_force_msb;
- + unsigned char max_force_lsb;
- + unsigned char max_force_msb;
- + unsigned char light_press_threshold_lsb;
- + unsigned char light_press_threshold_msb;
- + unsigned char light_press_hysteresis_lsb;
- + unsigned char light_press_hysteresis_msb;
- + unsigned char hard_press_threshold_lsb;
- + unsigned char hard_press_threshold_msb;
- + unsigned char hard_press_hysteresis_lsb;
- + unsigned char hard_press_hysteresis_msb;
- + };
- + unsigned char data[14];
- + };
- +};
- +
- +struct synaptics_rmi4_f12_finger_data {
- + unsigned char object_type_and_status;
- + unsigned char x_lsb;
- + unsigned char x_msb;
- + unsigned char y_lsb;
- + unsigned char y_msb;
- +#ifdef REPORT_2D_Z
- + unsigned char z;
- +#endif
- +#ifdef REPORT_2D_W
- + unsigned char wx;
- + unsigned char wy;
- +#endif
- +};
- +
- +struct synaptics_rmi4_f1a_query {
- + union {
- + struct {
- + unsigned char max_button_count:3;
- + unsigned char f1a_query0_b3__4:2;
- + unsigned char has_query4:1;
- + unsigned char has_query3:1;
- + unsigned char has_query2:1;
- + unsigned char has_general_control:1;
- + unsigned char has_interrupt_enable:1;
- + unsigned char has_multibutton_select:1;
- + unsigned char has_tx_rx_map:1;
- + unsigned char has_perbutton_threshold:1;
- + unsigned char has_release_threshold:1;
- + unsigned char has_strongestbtn_hysteresis:1;
- + unsigned char has_filter_strength:1;
- + } __packed;
- + unsigned char data[2];
- + };
- +};
- +
- +struct synaptics_rmi4_f1a_query_4 {
- + union {
- + struct {
- + unsigned char has_ctrl19:1;
- + unsigned char f1a_query4_b1__4:4;
- + unsigned char has_ctrl24:1;
- + unsigned char f1a_query4_b6__7:2;
- + } __packed;
- + unsigned char data[1];
- + };
- +};
- +
- +struct synaptics_rmi4_f1a_control_0 {
- + union {
- + struct {
- + unsigned char multibutton_report:2;
- + unsigned char filter_mode:2;
- + unsigned char reserved:4;
- + } __packed;
- + unsigned char data[1];
- + };
- +};
- +
- +struct synaptics_rmi4_f1a_control {
- + struct synaptics_rmi4_f1a_control_0 general_control;
- + unsigned char button_int_enable;
- + unsigned char multi_button;
- + unsigned char *txrx_map;
- + unsigned char *button_threshold;
- + unsigned char button_release_threshold;
- + unsigned char strongest_button_hysteresis;
- + unsigned char filter_strength;
- +};
- +
- +struct synaptics_rmi4_f1a_handle {
- + int button_bitmask_size;
- + unsigned char max_count;
- + unsigned char valid_button_count;
- + unsigned char *button_data_buffer;
- + unsigned char *button_map;
- + struct synaptics_rmi4_f1a_query button_query;
- + struct synaptics_rmi4_f1a_control button_control;
- +};
- +
- +struct synaptics_rmi4_exp_fhandler {
- + struct synaptics_rmi4_exp_fn *exp_fn;
- + bool insert;
- + bool remove;
- + struct list_head link;
- +};
- +
- +struct synaptics_rmi4_exp_fn_data {
- + bool initialized;
- + bool queue_work;
- + struct mutex mutex;
- + struct list_head list;
- + struct delayed_work work;
- + struct workqueue_struct *workqueue;
- + struct synaptics_rmi4_data *rmi4_data;
- +};
- +
- +static struct synaptics_rmi4_exp_fn_data exp_data;
- +
- +static struct synaptics_dsx_button_map *vir_button_map;
- +
- +static struct device_attribute attrs[] = {
- + __ATTR(reset, S_IWUSR,
- + synaptics_rmi4_show_error,
- + synaptics_rmi4_f01_reset_store),
- + __ATTR(productinfo, S_IRUGO,
- + synaptics_rmi4_f01_productinfo_show,
- + synaptics_rmi4_store_error),
- + __ATTR(buildid, S_IRUGO,
- + synaptics_rmi4_f01_buildid_show,
- + synaptics_rmi4_store_error),
- + __ATTR(flashprog, S_IRUGO,
- + synaptics_rmi4_f01_flashprog_show,
- + synaptics_rmi4_store_error),
- + __ATTR(0dbutton, (S_IRUGO | S_IWUSR),
- + synaptics_rmi4_0dbutton_show,
- + synaptics_rmi4_0dbutton_store),
- + __ATTR(suspend, S_IWUSR,
- + synaptics_rmi4_show_error,
- + synaptics_rmi4_suspend_store),
- + __ATTR(wake_gesture, (S_IRUGO | S_IWUSR),
- + synaptics_rmi4_wake_gesture_show,
- + synaptics_rmi4_wake_gesture_store),
- + __ATTR(irq_enable, (S_IRUGO | S_IWUSR),
- + synaptics_rmi4_irq_enable_show,
- + synaptics_rmi4_irq_enable_store),
- +};
- +
- +#if defined(CONFIG_SECURE_TOUCH)
- +static DEVICE_ATTR(secure_touch_enable, (S_IRUGO | S_IWUSR | S_IWGRP), synaptics_secure_touch_enable_show, synaptics_secure_touch_enable_store);
- +static DEVICE_ATTR(secure_touch, S_IRUGO , synaptics_secure_touch_show, NULL);
- +
- +static int synaptics_secure_touch_clk_prepare_enable(
- + struct synaptics_rmi4_data *rmi4_data)
- +{
- + int ret;
- +
- + ret = clk_prepare_enable(rmi4_data->iface_clk);
- + if (ret) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "error on clk_prepare_enable(iface_clk):%d\n", ret);
- + return ret;
- + }
- +
- + ret = clk_prepare_enable(rmi4_data->core_clk);
- + if (ret) {
- + clk_disable_unprepare(rmi4_data->iface_clk);
- + dev_err(rmi4_data->pdev->dev.parent,
- + "error clk_prepare_enable(core_clk):%d\n", ret);
- + }
- + return ret;
- +}
- +
- +static void synaptics_secure_touch_clk_disable_unprepare(
- + struct synaptics_rmi4_data *rmi4_data)
- +{
- + clk_disable_unprepare(rmi4_data->core_clk);
- + clk_disable_unprepare(rmi4_data->iface_clk);
- +}
- +
- +static void synaptics_secure_touch_init(struct synaptics_rmi4_data *data)
- +{
- + int ret = 0;
- +
- + data->st_initialized = 0;
- + init_completion(&data->st_powerdown);
- + init_completion(&data->st_irq_processed);
- + /* Get clocks */
- + data->core_clk = clk_get(data->pdev->dev.parent, "core_clk");
- + if (IS_ERR(data->core_clk)) {
- + ret = PTR_ERR(data->core_clk);
- + dev_err(data->pdev->dev.parent,
- + "%s: error on clk_get(core_clk):%d\n", __func__, ret);
- + return;
- + }
- +
- + data->iface_clk = clk_get(data->pdev->dev.parent, "iface_clk");
- + if (IS_ERR(data->iface_clk)) {
- + ret = PTR_ERR(data->iface_clk);
- + dev_err(data->pdev->dev.parent,
- + "%s: error on clk_get(iface_clk)\n", __func__);
- + goto err_iface_clk;
- + }
- +
- + data->st_initialized = 1;
- + return;
- +
- +err_iface_clk:
- + clk_put(data->core_clk);
- + data->core_clk = NULL;
- +}
- +
- +static void synaptics_secure_touch_notify(struct synaptics_rmi4_data *data)
- +{
- + sysfs_notify(&data->pdev->dev.parent->kobj, NULL, "secure_touch");
- +}
- +
- +static irqreturn_t synaptics_filter_interrupt(struct synaptics_rmi4_data *data)
- +{
- + if (atomic_read(&data->st_enabled)) {
- + if (atomic_cmpxchg(&data->st_pending_irqs, 0, 1) == 0) {
- + synaptics_secure_touch_notify(data);
- + wait_for_completion_interruptible(
- + &data->st_irq_processed);
- + }
- + return IRQ_HANDLED;
- + }
- + return IRQ_NONE;
- +}
- +
- +static void synaptics_secure_touch_stop(
- + struct synaptics_rmi4_data *data,
- + int blocking)
- +{
- + if (atomic_read(&data->st_enabled)) {
- + atomic_set(&data->st_pending_irqs, -1);
- + synaptics_secure_touch_notify(data);
- + if (blocking)
- + wait_for_completion_interruptible(&data->st_powerdown);
- + }
- +}
- +#else
- +static void synaptics_secure_touch_init(struct synaptics_rmi4_data *data)
- +{
- +}
- +
- +static irqreturn_t synaptics_filter_interrupt(struct synaptics_rmi4_data *data)
- +{
- + return IRQ_NONE;
- +}
- +
- +static void synaptics_secure_touch_stop(
- + struct synaptics_rmi4_data *data,
- + int blocking)
- +{
- +}
- +#endif
- +
- +#if defined(CONFIG_SECURE_TOUCH)
- +static ssize_t synaptics_secure_touch_enable_show(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + struct synaptics_rmi4_data *data = dev_get_drvdata(dev);
- +
- + return scnprintf(buf, PAGE_SIZE, "%d", atomic_read(&data->st_enabled));
- +}
- +
- +/*
- + * Accept only "0" and "1" valid values.
- + * "0" will reset the st_enabled flag, then wake up the reading process and
- + * the interrupt handler.
- + * The bus driver is notified via pm_runtime that it is not required to stay
- + * awake anymore.
- + * It will also make sure the queue of events is emptied in the controller,
- + * in case a touch happened in between the secure touch being disabled and
- + * the local ISR being ungated.
- + * "1" will set the st_enabled flag and clear the st_pending_irqs flag.
- + * The bus driver is requested via pm_runtime to stay awake.
- + */
- +static ssize_t synaptics_secure_touch_enable_store(struct device *dev,
- + struct device_attribute *attr,
- + const char *buf, size_t count)
- +{
- + struct synaptics_rmi4_data *data = dev_get_drvdata(dev);
- + struct i2c_client *client = container_of(data->pdev->dev.parent, struct i2c_client, dev);
- + struct device *adapter = client->adapter->dev.parent;
- + unsigned long value;
- + int err = 0;
- +
- + if (count > 2)
- + return -EINVAL;
- +
- + err = kstrtoul(buf, 10, &value);
- + if (err != 0)
- + return err;
- +
- + if (!data->st_initialized)
- + return -EIO;
- +
- + err = count;
- +
- + switch (value) {
- + case 0:
- + if (atomic_read(&data->st_enabled) == 0)
- + break;
- +
- + synaptics_secure_touch_clk_disable_unprepare(data);
- + pm_runtime_put_sync(adapter);
- + atomic_set(&data->st_enabled, 0);
- + synaptics_secure_touch_notify(data);
- + complete(&data->st_irq_processed);
- + synaptics_rmi4_irq(data->irq, data);
- + complete(&data->st_powerdown);
- +
- + break;
- + case 1:
- + if (atomic_read(&data->st_enabled)) {
- + err = -EBUSY;
- + break;
- + }
- +
- + synchronize_irq(data->irq);
- + if (pm_runtime_get_sync(adapter) < 0) {
- + dev_err(data->pdev->dev.parent, "pm_runtime_get_sync failed\n");
- + err = -EIO;
- + break;
- + }
- +
- + if (synaptics_secure_touch_clk_prepare_enable(data) < 0) {
- + pm_runtime_put_sync(adapter);
- + err = -EIO;
- + break;
- + }
- + reinit_completion(&data->st_powerdown);
- + reinit_completion(&data->st_irq_processed);
- + atomic_set(&data->st_enabled, 1);
- + atomic_set(&data->st_pending_irqs, 0);
- + break;
- + default:
- + dev_err(data->pdev->dev.parent,
- + "unsupported value: %lu\n", value);
- + err = -EINVAL;
- + break;
- + }
- + return err;
- +}
- +
- +/*
- + * This function returns whether there are pending interrupts, or
- + * other error conditions that need to be signaled to the userspace library,
- + * according tot he following logic:
- + * - st_enabled is 0 if secure touch is not enabled, returning -EBADF
- + * - st_pending_irqs is -1 to signal that secure touch is in being stopped,
- + * returning -EINVAL
- + * - st_pending_irqs is 1 to signal that there is a pending irq, returning
- + * the value "1" to the sysfs read operation
- + * - st_pending_irqs is 0 (only remaining case left) if the pending interrupt
- + * has been processed, so the interrupt handler can be allowed to continue.
- + */
- +static ssize_t synaptics_secure_touch_show(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + struct synaptics_rmi4_data *data = dev_get_drvdata(dev);
- + int val = 0;
- +
- + if (atomic_read(&data->st_enabled) == 0)
- + return -EBADF;
- +
- + if (atomic_cmpxchg(&data->st_pending_irqs, -1, 0) == -1)
- + return -EINVAL;
- +
- + if (atomic_cmpxchg(&data->st_pending_irqs, 1, 0) == 1)
- + val = 1;
- + else
- + complete(&data->st_irq_processed);
- +
- + return scnprintf(buf, PAGE_SIZE, "%u", val);
- +
- +}
- +#endif
- +
- +static DEVICE_ATTR(panel_color, S_IRUSR, synaptics_rmi4_panel_color_show, NULL);
- +static DEVICE_ATTR(panel_vendor, S_IRUSR, synaptics_rmi4_panel_vendor_show, NULL);
- +
- +static struct kobj_attribute virtual_key_map_attr = {
- + .attr = {
- + .name = VIRTUAL_KEY_MAP_FILE_NAME,
- + .mode = S_IRUGO,
- + },
- + .show = synaptics_rmi4_virtual_key_map_show,
- +};
- +
- +static ssize_t synaptics_rmi4_f01_reset_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count)
- +{
- + int retval;
- + unsigned int reset;
- + struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
- +
- + if (sscanf(buf, "%u", &reset) != 1)
- + return -EINVAL;
- +
- + if (reset != 1)
- + return -EINVAL;
- +
- + retval = synaptics_rmi4_reset_device(rmi4_data, false);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to issue reset command, error = %d\n",
- + __func__, retval);
- + return retval;
- + }
- +
- + return count;
- +}
- +
- +static ssize_t synaptics_rmi4_f01_productinfo_show(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
- +
- + return snprintf(buf, PAGE_SIZE, "0x%02x 0x%02x\n",
- + (rmi4_data->rmi4_mod_info.product_info[0]),
- + (rmi4_data->rmi4_mod_info.product_info[1]));
- +}
- +
- +static ssize_t synaptics_rmi4_f01_buildid_show(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
- +
- + return snprintf(buf, PAGE_SIZE, "%u\n",
- + rmi4_data->firmware_id);
- +}
- +
- +static ssize_t synaptics_rmi4_f01_flashprog_show(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + int retval;
- + struct synaptics_rmi4_f01_device_status device_status;
- + struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + rmi4_data->f01_data_base_addr,
- + device_status.data,
- + sizeof(device_status.data));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to read device status, error = %d\n",
- + __func__, retval);
- + return retval;
- + }
- +
- + return snprintf(buf, PAGE_SIZE, "%u\n",
- + device_status.flash_prog);
- +}
- +
- +static ssize_t synaptics_rmi4_0dbutton_show(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
- +
- + return snprintf(buf, PAGE_SIZE, "%u\n",
- + rmi4_data->button_0d_enabled);
- +}
- +
- +static ssize_t synaptics_rmi4_0dbutton_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count)
- +{
- + int retval;
- + unsigned int input;
- + unsigned char ii;
- + unsigned char intr_enable;
- + struct synaptics_rmi4_fn *fhandler;
- + struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
- + struct synaptics_rmi4_device_info *rmi;
- +
- + rmi = &(rmi4_data->rmi4_mod_info);
- +
- + if (sscanf(buf, "%u", &input) != 1)
- + return -EINVAL;
- +
- + input = input > 0 ? 1 : 0;
- +
- + if (rmi4_data->button_0d_enabled == input)
- + return count;
- +
- + if (list_empty(&rmi->support_fn_list))
- + return -ENODEV;
- +
- + list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
- + if (fhandler->fn_number == SYNAPTICS_RMI4_F1A) {
- + ii = fhandler->intr_reg_num;
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + rmi4_data->f01_ctrl_base_addr + 1 + ii,
- + &intr_enable,
- + sizeof(intr_enable));
- + if (retval < 0)
- + return retval;
- +
- + if (input == 1)
- + intr_enable |= fhandler->intr_mask;
- + else
- + intr_enable &= ~fhandler->intr_mask;
- +
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + rmi4_data->f01_ctrl_base_addr + 1 + ii,
- + &intr_enable,
- + sizeof(intr_enable));
- + if (retval < 0)
- + return retval;
- + }
- + }
- +
- + rmi4_data->button_0d_enabled = input;
- +
- + return count;
- +}
- +
- +static ssize_t synaptics_rmi4_suspend_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count)
- +{
- + unsigned int input;
- +
- + if (sscanf(buf, "%u", &input) != 1)
- + return -EINVAL;
- +
- + if (input == 1)
- + synaptics_rmi4_suspend(dev);
- + else if (input == 0)
- + synaptics_rmi4_resume(dev);
- + else
- + return -EINVAL;
- +
- + return count;
- +}
- +
- +static ssize_t synaptics_rmi4_wake_gesture_show(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
- +
- + return snprintf(buf, PAGE_SIZE, "%u\n",
- + rmi4_data->enable_wakeup_gesture);
- +}
- +
- +static ssize_t synaptics_rmi4_wake_gesture_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count)
- +{
- + unsigned int input;
- + struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
- + const struct synaptics_dsx_board_data *bdata =
- + rmi4_data->hw_if->board_data;
- +
- + if (sscanf(buf, "%u", &input) != 1)
- + return -EINVAL;
- +
- + if (bdata->cut_off_power) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Unable to switch wakeup gesture mode\n", __func__);
- + return count;
- + }
- +
- + input = input > 0 ? 1 : 0;
- +
- + if (rmi4_data->f11_wakeup_gesture || rmi4_data->f12_wakeup_gesture)
- + rmi4_data->enable_wakeup_gesture = input;
- +
- + if (rmi4_data->suspend)
- + synaptics_rmi4_wakeup_reconfigure(rmi4_data, (bool)input);
- +
- + return count;
- +}
- +
- +static ssize_t synaptics_rmi4_irq_enable_show(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
- +
- + return snprintf(buf, PAGE_SIZE, "%u\n",
- + rmi4_data->irq_enabled);
- +}
- +
- +static ssize_t synaptics_rmi4_irq_enable_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count)
- +{
- + unsigned int input;
- + struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
- +
- + if (sscanf(buf, "%u", &input) != 1)
- + return -EINVAL;
- + if (input)
- + enable_irq(rmi4_data->irq);
- + else
- + disable_irq(rmi4_data->irq);
- +
- + return count;
- +}
- +
- +static ssize_t synaptics_rmi4_panel_color_show(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
- +
- + return snprintf(buf, PAGE_SIZE, "%c\n",
- + rmi4_data->lockdown_info[2]);
- +}
- +
- +static ssize_t synaptics_rmi4_panel_vendor_show(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
- +
- + return snprintf(buf, PAGE_SIZE, "%c\n",
- + rmi4_data->lockdown_info[0]);
- +}
- +
- +static ssize_t synaptics_rmi4_virtual_key_map_show(struct kobject *kobj,
- + struct kobj_attribute *attr, char *buf)
- +{
- + int ii;
- + int cnt;
- + int count = 0;
- +
- + for (ii = 0; ii < vir_button_map->nbuttons; ii++) {
- + cnt = snprintf(buf, PAGE_SIZE - count, "0x01:%d:%d:%d:%d:%d\n",
- + vir_button_map->map[ii * 5 + 0],
- + vir_button_map->map[ii * 5 + 1],
- + vir_button_map->map[ii * 5 + 2],
- + vir_button_map->map[ii * 5 + 3],
- + vir_button_map->map[ii * 5 + 4]);
- + buf += cnt;
- + count += cnt;
- + }
- +
- + return count;
- +}
- +
- +static int synaptics_rmi4_f11_abs_report(struct synaptics_rmi4_data *rmi4_data,
- + struct synaptics_rmi4_fn *fhandler)
- +{
- + int retval;
- + unsigned char touch_count = 0; /* number of touch points */
- + unsigned char reg_index;
- + unsigned char finger;
- + unsigned char fingers_supported;
- + unsigned char num_of_finger_status_regs;
- + unsigned char finger_shift;
- + unsigned char finger_status;
- + unsigned char finger_status_reg[3];
- + unsigned char detected_gestures;
- + unsigned short data_addr;
- + unsigned short data_offset;
- + int x;
- + int y;
- + int wx;
- + int wy;
- + int temp;
- + struct synaptics_rmi4_f11_data_1_5 data;
- + struct synaptics_rmi4_f11_extra_data *extra_data;
- +
- + /*
- + * The number of finger status registers is determined by the
- + * maximum number of fingers supported - 2 bits per finger. So
- + * the number of finger status registers to read is:
- + * register_count = ceil(max_num_of_fingers / 4)
- + */
- + fingers_supported = fhandler->num_of_data_points;
- + num_of_finger_status_regs = (fingers_supported + 3) / 4;
- + data_addr = fhandler->full_addr.data_base;
- +
- + extra_data = (struct synaptics_rmi4_f11_extra_data *)fhandler->extra;
- +
- + if (rmi4_data->suspend && rmi4_data->wakeup_en) {
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + data_addr + extra_data->data38_offset,
- + &detected_gestures,
- + sizeof(detected_gestures));
- + if (retval < 0)
- + return 0;
- +
- + if (detected_gestures) {
- + input_report_key(rmi4_data->input_dev, KEY_WAKEUP, 1);
- + input_sync(rmi4_data->input_dev);
- + input_report_key(rmi4_data->input_dev, KEY_WAKEUP, 0);
- + input_sync(rmi4_data->input_dev);
- + }
- +
- + return 0;
- + }
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + data_addr,
- + finger_status_reg,
- + num_of_finger_status_regs);
- + if (retval < 0)
- + return 0;
- +
- + mutex_lock(&(rmi4_data->rmi4_report_mutex));
- +
- + for (finger = 0; finger < fingers_supported; finger++) {
- + reg_index = finger / 4;
- + finger_shift = (finger % 4) * 2;
- + finger_status = (finger_status_reg[reg_index] >> finger_shift)
- + & MASK_2BIT;
- +
- + /*
- + * Each 2-bit finger status field represents the following:
- + * 00 = finger not present
- + * 01 = finger present and data accurate
- + * 10 = finger present but data may be inaccurate
- + * 11 = reserved
- + */
- +#ifdef TYPE_B_PROTOCOL
- + input_mt_slot(rmi4_data->input_dev, finger);
- + input_mt_report_slot_state(rmi4_data->input_dev,
- + MT_TOOL_FINGER, finger_status);
- +#endif
- +
- + if (finger_status) {
- + data_offset = data_addr +
- + num_of_finger_status_regs +
- + (finger * sizeof(data.data));
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + data_offset,
- + data.data,
- + sizeof(data.data));
- + if (retval < 0) {
- + touch_count = 0;
- + goto exit;
- + }
- +
- + x = (data.x_position_11_4 << 4) | data.x_position_3_0;
- + y = (data.y_position_11_4 << 4) | data.y_position_3_0;
- + wx = data.wx;
- + wy = data.wy;
- +
- + if (rmi4_data->hw_if->board_data->swap_axes) {
- + temp = x;
- + x = y;
- + y = temp;
- + temp = wx;
- + wx = wy;
- + wy = temp;
- + }
- +
- + if (rmi4_data->hw_if->board_data->x_flip)
- + x = rmi4_data->sensor_max_x - x;
- + if (rmi4_data->hw_if->board_data->y_flip)
- + y = rmi4_data->sensor_max_y - y;
- +
- + input_report_key(rmi4_data->input_dev,
- + BTN_TOUCH, 1);
- + input_report_key(rmi4_data->input_dev,
- + BTN_TOOL_FINGER, 1);
- + input_report_abs(rmi4_data->input_dev,
- + ABS_MT_POSITION_X, x);
- + input_report_abs(rmi4_data->input_dev,
- + ABS_MT_POSITION_Y, y);
- +#ifdef REPORT_2D_W
- + input_report_abs(rmi4_data->input_dev,
- + ABS_MT_TOUCH_MAJOR, max(wx, wy));
- + input_report_abs(rmi4_data->input_dev,
- + ABS_MT_TOUCH_MINOR, min(wx, wy));
- +#endif
- +#ifndef TYPE_B_PROTOCOL
- + input_mt_sync(rmi4_data->input_dev);
- +#endif
- +
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: Finger %d: "
- + "status = 0x%02x, "
- + "x = %d, "
- + "y = %d, "
- + "wx = %d, "
- + "wy = %d\n",
- + __func__, finger,
- + finger_status,
- + x, y, wx, wy);
- +
- + touch_count++;
- + }
- + }
- +
- + if (touch_count == 0) {
- + input_report_key(rmi4_data->input_dev,
- + BTN_TOUCH, 0);
- + input_report_key(rmi4_data->input_dev,
- + BTN_TOOL_FINGER, 0);
- +#ifndef TYPE_B_PROTOCOL
- + input_mt_sync(rmi4_data->input_dev);
- +#endif
- + }
- +
- + input_sync(rmi4_data->input_dev);
- +
- +exit:
- + mutex_unlock(&(rmi4_data->rmi4_report_mutex));
- +
- + return touch_count;
- +}
- +
- +static int synaptics_rmi4_f12_abs_report(struct synaptics_rmi4_data *rmi4_data,
- + struct synaptics_rmi4_fn *fhandler)
- +{
- + int retval;
- + unsigned char touch_count = 0; /* number of touch points */
- + unsigned char index;
- + unsigned char finger;
- + unsigned char fingers_to_process;
- + unsigned char finger_status;
- + unsigned char size_of_2d_data;
- + unsigned char gesture_type;
- + unsigned short data_addr;
- + int x;
- + int y;
- + int wx;
- + int wy;
- + int temp;
- +#if defined(REPORT_2D_PRESSURE) || defined(F51_DISCRETE_FORCE)
- + int pressure;
- +#endif
- + int touchs;
- +#ifdef REPORT_2D_PRESSURE
- + unsigned char f_fingers;
- + unsigned char f_lsb;
- + unsigned char f_msb;
- + unsigned char *f_data;
- +#endif
- +#ifdef F51_DISCRETE_FORCE
- + unsigned char force_level;
- +#endif
- + struct synaptics_rmi4_f12_extra_data *extra_data;
- + struct synaptics_rmi4_f12_finger_data *data;
- + struct synaptics_rmi4_f12_finger_data *finger_data;
- + static unsigned char finger_presence;
- + static unsigned char stylus_presence;
- +#ifdef F12_DATA_15_WORKAROUND
- + static unsigned char objects_already_present;
- +#endif
- +
- + if (rmi4_data->input_dev == NULL) {
- + dev_err(rmi4_data->pdev->dev.parent, "input_dev is NULL, do not report data\n");
- +
- + return 0;
- + }
- +
- + fingers_to_process = fhandler->num_of_data_points;
- + data_addr = fhandler->full_addr.data_base;
- + extra_data = (struct synaptics_rmi4_f12_extra_data *)fhandler->extra;
- + size_of_2d_data = sizeof(struct synaptics_rmi4_f12_finger_data);
- +
- + if (rmi4_data->suspend && rmi4_data->wakeup_en) {
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + data_addr + extra_data->data4_offset,
- + rmi4_data->gesture_detection,
- + sizeof(rmi4_data->gesture_detection));
- + if (retval < 0)
- + return 0;
- +
- + gesture_type = rmi4_data->gesture_detection[0];
- + if (gesture_type && gesture_type != F12_UDG_DETECT) {
- + input_report_key(rmi4_data->input_dev, KEY_WAKEUP, 1);
- + input_sync(rmi4_data->input_dev);
- + input_report_key(rmi4_data->input_dev, KEY_WAKEUP, 0);
- + input_sync(rmi4_data->input_dev);
- + dev_err(rmi4_data->pdev->dev.parent, "double click send input event\n");
- + }
- +
- + return 0;
- + }
- +
- + /* Determine the total number of fingers to process */
- + if (extra_data->data15_size) {
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + data_addr + extra_data->data15_offset,
- + extra_data->data15_data,
- + extra_data->data15_size);
- + if (retval < 0)
- + return 0;
- +
- + /* Start checking from the highest bit */
- + index = extra_data->data15_size - 1; /* Highest byte */
- + finger = (fingers_to_process - 1) % 8; /* Highest bit */
- + do {
- + if (extra_data->data15_data[index] & (1 << finger))
- + break;
- +
- + if (finger) {
- + finger--;
- + } else if (index > 0) {
- + index--; /* Move to the next lower byte */
- + finger = 7;
- + }
- +
- + fingers_to_process--;
- + } while (fingers_to_process);
- +
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: Number of fingers to process = %d\n",
- + __func__, fingers_to_process);
- + }
- +
- +#ifdef F12_DATA_15_WORKAROUND
- + fingers_to_process = max(fingers_to_process, objects_already_present);
- +#endif
- +
- + if (!fingers_to_process) {
- + synaptics_rmi4_free_fingers(rmi4_data);
- + finger_presence = 0;
- + stylus_presence = 0;
- + rmi4_data->touchs = 0;
- + return 0;
- + }
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + data_addr + extra_data->data1_offset,
- + (unsigned char *)fhandler->data,
- + fingers_to_process * size_of_2d_data);
- + if (retval < 0)
- + return 0;
- +
- + data = (struct synaptics_rmi4_f12_finger_data *)fhandler->data;
- +
- +#ifdef REPORT_2D_PRESSURE
- + if (rmi4_data->report_pressure) {
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + data_addr + extra_data->data29_offset,
- + extra_data->data29_data,
- + extra_data->data29_size);
- + if (retval < 0)
- + return 0;
- + }
- +#endif
- +
- + mutex_lock(&(rmi4_data->rmi4_report_mutex));
- +
- + for (finger = 0; finger < fingers_to_process; finger++) {
- + finger_data = data + finger;
- + finger_status = finger_data->object_type_and_status;
- +
- +#ifdef F12_DATA_15_WORKAROUND
- + objects_already_present = finger + 1;
- +#endif
- +
- + x = (finger_data->x_msb << 8) | (finger_data->x_lsb);
- + y = (finger_data->y_msb << 8) | (finger_data->y_lsb);
- +#ifdef REPORT_2D_W
- + wx = finger_data->wx;
- + wy = finger_data->wy;
- +#endif
- +
- + if (rmi4_data->hw_if->board_data->swap_axes) {
- + temp = x;
- + x = y;
- + y = temp;
- + temp = wx;
- + wx = wy;
- + wy = temp;
- + }
- +
- + if (rmi4_data->hw_if->board_data->x_flip)
- + x = rmi4_data->sensor_max_x - x;
- + if (rmi4_data->hw_if->board_data->y_flip)
- + y = rmi4_data->sensor_max_y - y;
- +
- + switch (finger_status) {
- + case F12_FINGER_STATUS:
- + case F12_GLOVED_FINGER_STATUS:
- + if (stylus_presence) /* Stylus has priority over fingers */
- + break;
- +#ifdef TYPE_B_PROTOCOL
- + input_mt_slot(rmi4_data->input_dev, finger);
- + input_mt_report_slot_state(rmi4_data->input_dev,
- + MT_TOOL_FINGER, 1);
- +#endif
- +
- + input_report_key(rmi4_data->input_dev,
- + BTN_TOUCH, 1);
- + input_report_key(rmi4_data->input_dev,
- + BTN_TOOL_FINGER, 1);
- + input_report_abs(rmi4_data->input_dev,
- + ABS_MT_POSITION_X, x);
- + input_report_abs(rmi4_data->input_dev,
- + ABS_MT_POSITION_Y, y);
- +#ifdef REPORT_2D_W
- + if (rmi4_data->wedge_sensor) {
- + input_report_abs(rmi4_data->input_dev,
- + ABS_MT_TOUCH_MAJOR, wx);
- + input_report_abs(rmi4_data->input_dev,
- + ABS_MT_TOUCH_MINOR, wx);
- + } else {
- + input_report_abs(rmi4_data->input_dev,
- + ABS_MT_TOUCH_MAJOR,
- + max(wx, wy));
- + input_report_abs(rmi4_data->input_dev,
- + ABS_MT_TOUCH_MINOR,
- + min(wx, wy));
- + }
- +#endif
- +#ifdef REPORT_2D_PRESSURE
- + if (rmi4_data->report_pressure) {
- + f_fingers = extra_data->data29_size / 2;
- + f_data = extra_data->data29_data;
- + if (finger + 1 > f_fingers) {
- + pressure = 1;
- + } else {
- + f_lsb = finger * 2;
- + f_msb = finger * 2 + 1;
- + pressure = (int)f_data[f_lsb] << 0 |
- + (int)f_data[f_msb] << 8;
- + }
- + pressure = pressure > 0 ? pressure : 1;
- + if (pressure > rmi4_data->force_max)
- + pressure = rmi4_data->force_max;
- + input_report_abs(rmi4_data->input_dev,
- + ABS_MT_PRESSURE, pressure);
- + }
- +#elif defined(F51_DISCRETE_FORCE)
- + if (finger == 0) {
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + FORCE_LEVEL_ADDR,
- + &force_level,
- + sizeof(force_level));
- + if (retval < 0)
- + return 0;
- + pressure = force_level > 0 ? force_level : 1;
- + } else {
- + pressure = 1;
- + }
- + input_report_abs(rmi4_data->input_dev,
- + ABS_MT_PRESSURE, pressure);
- +#endif
- +#ifndef TYPE_B_PROTOCOL
- + input_mt_sync(rmi4_data->input_dev);
- +#endif
- +
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: Finger %d: "
- + "status = 0x%02x, "
- + "x = %d, "
- + "y = %d, "
- + "wx = %d, "
- + "wy = %d\n",
- + __func__, finger,
- + finger_status,
- + x, y, wx, wy);
- +
- + finger_presence = 1;
- + touch_count++;
- + touchs |= BIT(finger);
- + rmi4_data->touchs |= BIT(finger);
- + break;
- + case F12_PALM_STATUS:
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: Finger %d: "
- + "x = %d, "
- + "y = %d, "
- + "wx = %d, "
- + "wy = %d\n",
- + __func__, finger,
- + x, y, wx, wy);
- + break;
- + case F12_STYLUS_STATUS:
- + case F12_ERASER_STATUS:
- + if (finger_presence) { /* Stylus has priority over fingers */
- + mutex_unlock(&(rmi4_data->rmi4_report_mutex));
- + synaptics_rmi4_free_fingers(rmi4_data);
- + mutex_lock(&(rmi4_data->rmi4_report_mutex));
- + finger_presence = 0;
- + }
- + if (stylus_presence) {/* Allow one stylus at a timee */
- + if (finger + 1 != stylus_presence)
- + break;
- + }
- + input_report_key(rmi4_data->stylus_dev,
- + BTN_TOUCH, 1);
- + if (finger_status == F12_STYLUS_STATUS) {
- + input_report_key(rmi4_data->stylus_dev,
- + BTN_TOOL_PEN, 1);
- + } else {
- + input_report_key(rmi4_data->stylus_dev,
- + BTN_TOOL_RUBBER, 1);
- + }
- + input_report_abs(rmi4_data->stylus_dev,
- + ABS_X, x);
- + input_report_abs(rmi4_data->stylus_dev,
- + ABS_Y, y);
- +
- + stylus_presence = finger + 1;
- + touch_count++;
- + break;
- + default:
- +#ifdef TYPE_B_PROTOCOL
- + input_mt_slot(rmi4_data->input_dev, finger);
- + input_mt_report_slot_state(rmi4_data->input_dev,
- + MT_TOOL_FINGER, 0);
- +#endif
- + rmi4_data->touchs &= ~BIT(finger);
- + touchs &= ~BIT(finger);
- + break;
- + }
- + }
- +
- + for (finger = 0; finger < fhandler->num_of_data_points; finger++) {
- + if (BIT(finger) & (rmi4_data->touchs ^ touchs)) {
- + input_mt_slot(rmi4_data->input_dev, finger);
- + input_mt_report_slot_state(rmi4_data->input_dev,
- + MT_TOOL_FINGER, 0);
- + }
- + }
- +
- + if (touch_count == 0) {
- + finger_presence = 0;
- +#ifdef F12_DATA_15_WORKAROUND
- + objects_already_present = 0;
- +#endif
- + input_report_key(rmi4_data->input_dev,
- + BTN_TOUCH, 0);
- + input_report_key(rmi4_data->input_dev,
- + BTN_TOOL_FINGER, 0);
- +#ifndef TYPE_B_PROTOCOL
- + input_mt_sync(rmi4_data->input_dev);
- +#endif
- +
- + if (rmi4_data->stylus_enable) {
- + stylus_presence = 0;
- + input_report_key(rmi4_data->stylus_dev,
- + BTN_TOUCH, 0);
- + input_report_key(rmi4_data->stylus_dev,
- + BTN_TOOL_PEN, 0);
- + if (rmi4_data->eraser_enable) {
- + input_report_key(rmi4_data->stylus_dev,
- + BTN_TOOL_RUBBER, 0);
- + }
- + }
- +
- + rmi4_data->touchs = 0;
- + }
- +
- + input_sync(rmi4_data->input_dev);
- +
- + mutex_unlock(&(rmi4_data->rmi4_report_mutex));
- +
- + return touch_count;
- +}
- +
- +static void synaptics_rmi4_f1a_report(struct synaptics_rmi4_data *rmi4_data,
- + struct synaptics_rmi4_fn *fhandler)
- +{
- + int retval;
- + unsigned char touch_count = 0;
- + unsigned char button;
- + unsigned char index;
- + unsigned char shift;
- + unsigned char status;
- + unsigned char *data;
- + unsigned short data_addr = fhandler->full_addr.data_base;
- + struct synaptics_rmi4_f1a_handle *f1a = fhandler->data;
- + static unsigned char do_once = 1;
- + static bool current_status[MAX_NUMBER_OF_BUTTONS];
- +#ifdef NO_0D_WHILE_2D
- + static bool before_2d_status[MAX_NUMBER_OF_BUTTONS];
- + static bool while_2d_status[MAX_NUMBER_OF_BUTTONS];
- +#endif
- +
- + if (do_once) {
- + memset(current_status, 0, sizeof(current_status));
- +#ifdef NO_0D_WHILE_2D
- + memset(before_2d_status, 0, sizeof(before_2d_status));
- + memset(while_2d_status, 0, sizeof(while_2d_status));
- +#endif
- + do_once = 0;
- + }
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + data_addr,
- + f1a->button_data_buffer,
- + f1a->button_bitmask_size);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to read button data registers\n",
- + __func__);
- + return;
- + }
- +
- + data = f1a->button_data_buffer;
- +
- + mutex_lock(&(rmi4_data->rmi4_report_mutex));
- +
- + for (button = 0; button < f1a->valid_button_count; button++) {
- + index = button / 8;
- + shift = button % 8;
- + status = ((data[index] >> shift) & MASK_1BIT);
- +
- + if (current_status[button] == status) {
- + if (!rmi4_data->suspend)
- + continue;
- + } else
- + current_status[button] = status;
- +
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Button %d (code %d) ->%d\n",
- + __func__, button,
- + f1a->button_map[button],
- + status);
- +#ifdef NO_0D_WHILE_2D
- + if (rmi4_data->fingers_on_2d == false) {
- + if (status == 1) {
- + before_2d_status[button] = 1;
- + } else {
- + if (while_2d_status[button] == 1) {
- + while_2d_status[button] = 0;
- + continue;
- + } else {
- + before_2d_status[button] = 0;
- + }
- + }
- +
- + touch_count++;
- + input_report_key(rmi4_data->input_dev,
- + f1a->button_map[button],
- + status);
- + } else {
- + if (before_2d_status[button] == 1) {
- + before_2d_status[button] = 0;
- + touch_count++;
- + input_report_key(rmi4_data->input_dev,
- + f1a->button_map[button],
- + status);
- + } else {
- + if (status == 1)
- + while_2d_status[button] = 1;
- + else
- + while_2d_status[button] = 0;
- + }
- + }
- +#else
- + touch_count++;
- + input_report_key(rmi4_data->input_dev,
- + f1a->button_map[button],
- + status);
- +#endif
- + }
- +
- + if (touch_count)
- + input_sync(rmi4_data->input_dev);
- +
- + mutex_unlock(&(rmi4_data->rmi4_report_mutex));
- +
- + return;
- +}
- +
- +static void synaptics_rmi4_report_touch(struct synaptics_rmi4_data *rmi4_data,
- + struct synaptics_rmi4_fn *fhandler)
- +{
- + unsigned char touch_count_2d;
- +
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: Function %02x reporting\n",
- + __func__, fhandler->fn_number);
- +
- + switch (fhandler->fn_number) {
- + case SYNAPTICS_RMI4_F11:
- + touch_count_2d = synaptics_rmi4_f11_abs_report(rmi4_data,
- + fhandler);
- +
- + if (touch_count_2d)
- + rmi4_data->fingers_on_2d = true;
- + else
- + rmi4_data->fingers_on_2d = false;
- + break;
- + case SYNAPTICS_RMI4_F12:
- + touch_count_2d = synaptics_rmi4_f12_abs_report(rmi4_data,
- + fhandler);
- +
- + if (touch_count_2d)
- + rmi4_data->fingers_on_2d = true;
- + else
- + rmi4_data->fingers_on_2d = false;
- + break;
- + case SYNAPTICS_RMI4_F1A:
- + synaptics_rmi4_f1a_report(rmi4_data, fhandler);
- + break;
- + default:
- + break;
- + }
- +
- + return;
- +}
- +
- +static void synaptics_rmi4_sensor_report(struct synaptics_rmi4_data *rmi4_data,
- + bool report)
- +{
- + int retval;
- + unsigned char data[MAX_INTR_REGISTERS + 1];
- + unsigned char *intr = &data[1];
- + bool was_in_bl_mode;
- + struct synaptics_rmi4_f01_device_status status;
- + struct synaptics_rmi4_fn *fhandler;
- + struct synaptics_rmi4_exp_fhandler *exp_fhandler;
- + struct synaptics_rmi4_device_info *rmi;
- +
- + rmi = &(rmi4_data->rmi4_mod_info);
- +
- + /*
- + * Get interrupt status information from F01 Data1 register to
- + * determine the source(s) that are flagging the interrupt.
- + */
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + rmi4_data->f01_data_base_addr,
- + data,
- + rmi4_data->num_of_intr_regs + 1);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to read interrupt status\n",
- + __func__);
- + return;
- + }
- +
- + status.data[0] = data[0];
- + if (status.status_code == STATUS_CRC_IN_PROGRESS) {
- + retval = synaptics_rmi4_check_status(rmi4_data,
- + &was_in_bl_mode);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to check status\n",
- + __func__);
- + return;
- + }
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + rmi4_data->f01_data_base_addr,
- + status.data,
- + sizeof(status.data));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to read device status\n",
- + __func__);
- + return;
- + }
- + }
- + if (status.unconfigured && !status.flash_prog) {
- + pr_notice("%s: spontaneous reset detected\n", __func__);
- + retval = synaptics_rmi4_reinit_device(rmi4_data);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to reinit device\n",
- + __func__);
- + }
- + }
- +
- + if (!report)
- + return;
- +
- + /*
- + * Traverse the function handler list and service the source(s)
- + * of the interrupt accordingly.
- + */
- + if (!list_empty(&rmi->support_fn_list)) {
- + list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
- + if (fhandler->num_of_data_sources) {
- + if (fhandler->intr_mask &
- + intr[fhandler->intr_reg_num]) {
- + synaptics_rmi4_report_touch(rmi4_data,
- + fhandler);
- + }
- + }
- + }
- + }
- +
- + mutex_lock(&exp_data.mutex);
- + if (!list_empty(&exp_data.list)) {
- + list_for_each_entry(exp_fhandler, &exp_data.list, link) {
- + if (!exp_fhandler->insert &&
- + !exp_fhandler->remove &&
- + (exp_fhandler->exp_fn->attn != NULL))
- + exp_fhandler->exp_fn->attn(rmi4_data, intr[0]);
- + }
- + }
- + mutex_unlock(&exp_data.mutex);
- +
- + return;
- +}
- +
- +static irqreturn_t synaptics_rmi4_irq(int irq, void *data)
- +{
- + struct synaptics_rmi4_data *rmi4_data = data;
- + const struct synaptics_dsx_board_data *bdata =
- + rmi4_data->hw_if->board_data;
- +
- + if (gpio_get_value(bdata->irq_gpio) != bdata->irq_on_state)
- + goto exit;
- +
- + if (IRQ_HANDLED == synaptics_filter_interrupt(data))
- + return IRQ_HANDLED;
- +
- + synaptics_rmi4_sensor_report(rmi4_data, true);
- +
- +exit:
- + return IRQ_HANDLED;
- +}
- +
- +static int synaptics_rmi4_int_enable(struct synaptics_rmi4_data *rmi4_data,
- + bool enable)
- +{
- + int retval = 0;
- + unsigned char ii;
- + unsigned char zero = 0x00;
- + unsigned char *intr_mask;
- + unsigned short intr_addr;
- +
- + intr_mask = rmi4_data->intr_mask;
- +
- + for (ii = 0; ii < rmi4_data->num_of_intr_regs; ii++) {
- + if (intr_mask[ii] != 0x00) {
- + intr_addr = rmi4_data->f01_ctrl_base_addr + 1 + ii;
- + if (enable) {
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + intr_addr,
- + &(intr_mask[ii]),
- + sizeof(intr_mask[ii]));
- + if (retval < 0)
- + return retval;
- + } else {
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + intr_addr,
- + &zero,
- + sizeof(zero));
- + if (retval < 0)
- + return retval;
- + }
- + }
- + }
- +
- + return retval;
- +}
- +
- +static int synaptics_rmi4_irq_enable(struct synaptics_rmi4_data *rmi4_data,
- + bool enable, bool attn_only)
- +{
- + int retval = 0;
- + const struct synaptics_dsx_board_data *bdata =
- + rmi4_data->hw_if->board_data;
- +
- + if (attn_only) {
- + retval = synaptics_rmi4_int_enable(rmi4_data, enable);
- + return retval;
- + }
- +
- + if (enable) {
- + if (rmi4_data->irq_enabled)
- + return retval;
- +
- + retval = synaptics_rmi4_int_enable(rmi4_data, false);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to disable synaptics int\n",
- + __func__);
- + return retval;
- + }
- +
- + /* Process and clear interrupts */
- + synaptics_rmi4_sensor_report(rmi4_data, false);
- +
- + retval = request_threaded_irq(rmi4_data->irq, NULL,
- + synaptics_rmi4_irq, bdata->irq_flags,
- + PLATFORM_DRIVER_NAME, rmi4_data);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to create irq thread\n",
- + __func__);
- + return retval;
- + }
- +
- + retval = synaptics_rmi4_int_enable(rmi4_data, true);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to enable synaptics int\n",
- + __func__);
- + return retval;
- + }
- +
- + rmi4_data->irq_enabled = true;
- + } else {
- + if (rmi4_data->irq_enabled) {
- + disable_irq(rmi4_data->irq);
- + free_irq(rmi4_data->irq, rmi4_data);
- + rmi4_data->irq_enabled = false;
- + }
- + }
- +
- + return retval;
- +}
- +
- +static void synaptics_rmi4_set_intr_mask(struct synaptics_rmi4_fn *fhandler,
- + struct synaptics_rmi4_fn_desc *fd,
- + unsigned int intr_count)
- +{
- + unsigned char ii;
- + unsigned char intr_offset;
- +
- + fhandler->intr_reg_num = (intr_count + 7) / 8;
- + if (fhandler->intr_reg_num != 0)
- + fhandler->intr_reg_num -= 1;
- +
- + /* Set an enable bit for each data source */
- + intr_offset = intr_count % 8;
- + fhandler->intr_mask = 0;
- + for (ii = intr_offset;
- + ii < (fd->intr_src_count + intr_offset);
- + ii++)
- + fhandler->intr_mask |= 1 << ii;
- +
- + return;
- +}
- +
- +static int synaptics_rmi4_query_product_id(struct synaptics_rmi4_data *rmi4_data)
- +{
- + int retval;
- + unsigned short lockdown_addr;
- +
- + /* Product ID addr starts from F01_RMI_QUERY11 */
- + lockdown_addr = rmi4_data->f01_query_base_addr + F01_PROD_ID_OFFSET;
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + lockdown_addr,
- + rmi4_data->lockdown_info,
- + LOCKDOWN_INFO_SIZE);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "Failed reading reg %d\n",
- + lockdown_addr);
- + return retval;
- + }
- +
- + dev_info(rmi4_data->pdev->dev.parent,
- + "Lockdown info: 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X",
- + rmi4_data->lockdown_info[0], rmi4_data->lockdown_info[1],
- + rmi4_data->lockdown_info[2], rmi4_data->lockdown_info[3],
- + rmi4_data->lockdown_info[4], rmi4_data->lockdown_info[5],
- + rmi4_data->lockdown_info[6], rmi4_data->lockdown_info[7]);
- +
- + return 0;
- +}
- +
- +static int synaptics_rmi4_query_chip_id(struct synaptics_rmi4_data *rmi4_data)
- +{
- + int retval, i;
- + unsigned short chipdata_addr;
- + unsigned char query_data[8] = {0};
- +
- + chipdata_addr = rmi4_data->f01_query_base_addr + F01_PROD_ID_OFFSET;
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + chipdata_addr,
- + query_data,
- + 8);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "Failed reading reg %d\n",
- + chipdata_addr);
- + return retval;
- + }
- +
- + dev_info(rmi4_data->pdev->dev.parent,
- + "chip info: 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X",
- + query_data[0], query_data[1],
- + query_data[2], query_data[3],
- + query_data[4], query_data[5],
- + query_data[6], query_data[7]);
- +
- + for (i = 0; i < rmi4_data->hw_if->board_data->config_array_size; i++) {
- + if (!memcmp(rmi4_data->hw_if->board_data->config_array[i].chip_id_name,
- + query_data,
- + strlen(rmi4_data->hw_if->board_data->config_array[i].chip_id_name))) {
- + rmi4_data->chip_id = rmi4_data->hw_if->board_data->config_array[i].chip_id;
- + rmi4_data->chip_is_tddi = rmi4_data->hw_if->board_data->config_array[i].chip_is_tddi;
- + rmi4_data->panel_power_seq = rmi4_data->hw_if->board_data->config_array[i].panel_power_seq;
- + if (rmi4_data->chip_is_tddi)
- + rmi4_data->hw_if->board_data->reset_gpio = -1;
- + break;
- + }
- + }
- +
- + if (i >= rmi4_data->hw_if->board_data->config_array_size) {
- + dev_err(rmi4_data->pdev->dev.parent, "failed to match the chip id\n");
- + rmi4_data->chip_id = -1; /* Set chip_id -1 to ensure it won't do firmware upgrading */
- + return -EINVAL;
- + }
- +
- + return 0;
- +}
- +
- +static int synaptics_rmi4_f01_init(struct synaptics_rmi4_data *rmi4_data,
- + struct synaptics_rmi4_fn *fhandler,
- + struct synaptics_rmi4_fn_desc *fd,
- + unsigned int intr_count)
- +{
- + fhandler->fn_number = fd->fn_number;
- + fhandler->num_of_data_sources = fd->intr_src_count;
- + fhandler->data = NULL;
- + fhandler->extra = NULL;
- +
- + synaptics_rmi4_set_intr_mask(fhandler, fd, intr_count);
- +
- + rmi4_data->f01_query_base_addr = fd->query_base_addr;
- + rmi4_data->f01_ctrl_base_addr = fd->ctrl_base_addr;
- + rmi4_data->f01_data_base_addr = fd->data_base_addr;
- + rmi4_data->f01_cmd_base_addr = fd->cmd_base_addr;
- +
- + if (rmi4_data->hw_if->board_data->lockdown_area == LOCKDOWN_AREA_PRODUCT_ID)
- + synaptics_rmi4_query_product_id(rmi4_data);
- +
- + return 0;
- +}
- +
- +static int synaptics_rmi4_f11_init(struct synaptics_rmi4_data *rmi4_data,
- + struct synaptics_rmi4_fn *fhandler,
- + struct synaptics_rmi4_fn_desc *fd,
- + unsigned int intr_count)
- +{
- + int retval;
- + int temp;
- + unsigned char offset;
- + unsigned char fingers_supported;
- + struct synaptics_rmi4_f11_extra_data *extra_data;
- + struct synaptics_rmi4_f11_query_0_5 query_0_5;
- + struct synaptics_rmi4_f11_query_7_8 query_7_8;
- + struct synaptics_rmi4_f11_query_9 query_9;
- + struct synaptics_rmi4_f11_query_12 query_12;
- + struct synaptics_rmi4_f11_query_27 query_27;
- + struct synaptics_rmi4_f11_ctrl_6_9 control_6_9;
- + const struct synaptics_dsx_board_data *bdata =
- + rmi4_data->hw_if->board_data;
- +
- + fhandler->fn_number = fd->fn_number;
- + fhandler->num_of_data_sources = fd->intr_src_count;
- + fhandler->extra = kmalloc(sizeof(*extra_data), GFP_KERNEL);
- + if (!fhandler->extra) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to alloc mem for fhandler->extra\n",
- + __func__);
- + return -ENOMEM;
- + }
- + extra_data = (struct synaptics_rmi4_f11_extra_data *)fhandler->extra;
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + fhandler->full_addr.query_base,
- + query_0_5.data,
- + sizeof(query_0_5.data));
- + if (retval < 0)
- + return retval;
- +
- + /* Maximum number of fingers supported */
- + if (query_0_5.num_of_fingers <= 4)
- + fhandler->num_of_data_points = query_0_5.num_of_fingers + 1;
- + else if (query_0_5.num_of_fingers == 5)
- + fhandler->num_of_data_points = 10;
- +
- + rmi4_data->num_of_fingers = fhandler->num_of_data_points;
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + fhandler->full_addr.ctrl_base + 6,
- + control_6_9.data,
- + sizeof(control_6_9.data));
- + if (retval < 0)
- + return retval;
- +
- + /* Maximum x and y */
- + rmi4_data->sensor_max_x = control_6_9.sensor_max_x_pos_7_0 |
- + (control_6_9.sensor_max_x_pos_11_8 << 8);
- + rmi4_data->sensor_max_y = control_6_9.sensor_max_y_pos_7_0 |
- + (control_6_9.sensor_max_y_pos_11_8 << 8);
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: Function %02x max x = %d max y = %d\n",
- + __func__, fhandler->fn_number,
- + rmi4_data->sensor_max_x,
- + rmi4_data->sensor_max_y);
- +
- + rmi4_data->max_touch_width = MAX_F11_TOUCH_WIDTH;
- +
- + if (bdata->swap_axes) {
- + temp = rmi4_data->sensor_max_x;
- + rmi4_data->sensor_max_x = rmi4_data->sensor_max_y;
- + rmi4_data->sensor_max_y = temp;
- + }
- +
- + synaptics_rmi4_set_intr_mask(fhandler, fd, intr_count);
- +
- + fhandler->data = NULL;
- +
- + offset = sizeof(query_0_5.data);
- +
- + /* query 6 */
- + if (query_0_5.has_rel)
- + offset += 1;
- +
- + /* queries 7 8 */
- + if (query_0_5.has_gestures) {
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + fhandler->full_addr.query_base + offset,
- + query_7_8.data,
- + sizeof(query_7_8.data));
- + if (retval < 0)
- + return retval;
- +
- + offset += sizeof(query_7_8.data);
- + }
- +
- + /* query 9 */
- + if (query_0_5.has_query_9) {
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + fhandler->full_addr.query_base + offset,
- + query_9.data,
- + sizeof(query_9.data));
- + if (retval < 0)
- + return retval;
- +
- + offset += sizeof(query_9.data);
- + }
- +
- + /* query 10 */
- + if (query_0_5.has_gestures && query_7_8.has_touch_shapes)
- + offset += 1;
- +
- + /* query 11 */
- + if (query_0_5.has_query_11)
- + offset += 1;
- +
- + /* query 12 */
- + if (query_0_5.has_query_12) {
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + fhandler->full_addr.query_base + offset,
- + query_12.data,
- + sizeof(query_12.data));
- + if (retval < 0)
- + return retval;
- +
- + offset += sizeof(query_12.data);
- + }
- +
- + /* query 13 */
- + if (query_0_5.has_jitter_filter)
- + offset += 1;
- +
- + /* query 14 */
- + if (query_0_5.has_query_12 && query_12.has_general_information_2)
- + offset += 1;
- +
- + /* queries 15 16 17 18 19 20 21 22 23 24 25 26*/
- + if (query_0_5.has_query_12 && query_12.has_physical_properties)
- + offset += 12;
- +
- + /* query 27 */
- + if (query_0_5.has_query_27) {
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + fhandler->full_addr.query_base + offset,
- + query_27.data,
- + sizeof(query_27.data));
- + if (retval < 0)
- + return retval;
- +
- + rmi4_data->f11_wakeup_gesture = query_27.has_wakeup_gesture;
- + }
- +
- + if (!rmi4_data->f11_wakeup_gesture)
- + return retval;
- +
- + /* data 0 */
- + fingers_supported = fhandler->num_of_data_points;
- + offset = (fingers_supported + 3) / 4;
- +
- + /* data 1 2 3 4 5 */
- + offset += 5 * fingers_supported;
- +
- + /* data 6 7 */
- + if (query_0_5.has_rel)
- + offset += 2 * fingers_supported;
- +
- + /* data 8 */
- + if (query_0_5.has_gestures && query_7_8.data[0])
- + offset += 1;
- +
- + /* data 9 */
- + if (query_0_5.has_gestures && (query_7_8.data[0] || query_7_8.data[1]))
- + offset += 1;
- +
- + /* data 10 */
- + if (query_0_5.has_gestures &&
- + (query_7_8.has_pinch || query_7_8.has_flick))
- + offset += 1;
- +
- + /* data 11 12 */
- + if (query_0_5.has_gestures &&
- + (query_7_8.has_flick || query_7_8.has_rotate))
- + offset += 2;
- +
- + /* data 13 */
- + if (query_0_5.has_gestures && query_7_8.has_touch_shapes)
- + offset += (fingers_supported + 3) / 4;
- +
- + /* data 14 15 */
- + if (query_0_5.has_gestures &&
- + (query_7_8.has_scroll_zones ||
- + query_7_8.has_multi_finger_scroll ||
- + query_7_8.has_chiral_scroll))
- + offset += 2;
- +
- + /* data 16 17 */
- + if (query_0_5.has_gestures &&
- + (query_7_8.has_scroll_zones &&
- + query_7_8.individual_scroll_zones))
- + offset += 2;
- +
- + /* data 18 19 20 21 22 23 24 25 26 27 */
- + if (query_0_5.has_query_9 && query_9.has_contact_geometry)
- + offset += 10 * fingers_supported;
- +
- + /* data 28 */
- + if (query_0_5.has_bending_correction ||
- + query_0_5.has_large_object_suppression)
- + offset += 1;
- +
- + /* data 29 30 31 */
- + if (query_0_5.has_query_9 && query_9.has_pen_hover_discrimination)
- + offset += 3;
- +
- + /* data 32 */
- + if (query_0_5.has_query_12 &&
- + query_12.has_small_object_detection_tuning)
- + offset += 1;
- +
- + /* data 33 34 */
- + if (query_0_5.has_query_27 && query_27.f11_query27_b0)
- + offset += 2;
- +
- + /* data 35 */
- + if (query_0_5.has_query_12 && query_12.has_8bit_w)
- + offset += fingers_supported;
- +
- + /* data 36 */
- + if (query_0_5.has_bending_correction)
- + offset += 1;
- +
- + /* data 37 */
- + if (query_0_5.has_query_27 && query_27.has_data_37)
- + offset += 1;
- +
- + /* data 38 */
- + if (query_0_5.has_query_27 && query_27.has_wakeup_gesture)
- + extra_data->data38_offset = offset;
- +
- + return retval;
- +}
- +
- +static int synaptics_rmi4_f12_set_enables(struct synaptics_rmi4_data *rmi4_data,
- + unsigned short ctrl28)
- +{
- + int retval;
- + static unsigned short ctrl_28_address;
- +
- + if (ctrl28)
- + ctrl_28_address = ctrl28;
- +
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + ctrl_28_address,
- + &rmi4_data->report_enable,
- + sizeof(rmi4_data->report_enable));
- + if (retval < 0)
- + return retval;
- +
- + return retval;
- +}
- +
- +static int synaptics_rmi4_f12_find_sub(struct synaptics_rmi4_data *rmi4_data,
- + struct synaptics_rmi4_fn *fhandler,
- + unsigned char *presence, unsigned char presence_size,
- + unsigned char structure_offset, unsigned char reg,
- + unsigned char sub)
- +{
- + int retval;
- + unsigned char cnt;
- + unsigned char regnum;
- + unsigned char bitnum;
- + unsigned char p_index;
- + unsigned char s_index;
- + unsigned char offset;
- + unsigned char max_reg;
- + unsigned char *structure;
- +
- + max_reg = (presence_size - 1) * 8 - 1;
- +
- + if (reg > max_reg) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Register number (%d) over limit\n",
- + __func__, reg);
- + return -EINVAL;
- + }
- +
- + p_index = reg / 8 + 1;
- + bitnum = reg % 8;
- + if ((presence[p_index] & (1 << bitnum)) == 0x00) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Register %d is not present\n",
- + __func__, reg);
- + return -EINVAL;
- + }
- +
- + structure = kmalloc(presence[0], GFP_KERNEL);
- + if (!structure) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to alloc mem for structure register\n",
- + __func__);
- + return -ENOMEM;
- + }
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + fhandler->full_addr.query_base + structure_offset,
- + structure,
- + presence[0]);
- + if (retval < 0)
- + goto exit;
- +
- + s_index = 0;
- +
- + for (regnum = 0; regnum < reg; regnum++) {
- + p_index = regnum / 8 + 1;
- + bitnum = regnum % 8;
- + if ((presence[p_index] & (1 << bitnum)) == 0x00)
- + continue;
- +
- + if (structure[s_index] == 0x00)
- + s_index += 3;
- + else
- + s_index++;
- +
- + while (structure[s_index] & ~MASK_7BIT)
- + s_index++;
- +
- + s_index++;
- + }
- +
- + cnt = 0;
- + s_index++;
- + offset = sub / 7;
- + bitnum = sub % 7;
- +
- + do {
- + if (cnt == offset) {
- + if (structure[s_index + cnt] & (1 << bitnum))
- + retval = 1;
- + else
- + retval = 0;
- + goto exit;
- + }
- + cnt++;
- + } while (structure[s_index + cnt - 1] & ~MASK_7BIT);
- +
- + retval = 0;
- +
- +exit:
- + kfree(structure);
- +
- + return retval;
- +}
- +
- +static int synaptics_rmi4_f12_init(struct synaptics_rmi4_data *rmi4_data,
- + struct synaptics_rmi4_fn *fhandler,
- + struct synaptics_rmi4_fn_desc *fd,
- + unsigned int intr_count)
- +{
- + int retval = 0;
- + int temp;
- + unsigned char subpacket;
- + unsigned char ctrl_23_size;
- + unsigned char size_of_2d_data;
- + unsigned char size_of_query5;
- + unsigned char size_of_query8;
- + unsigned char ctrl_8_offset;
- + unsigned char ctrl_20_offset;
- + unsigned char ctrl_23_offset;
- + unsigned char ctrl_26_offset;
- + unsigned char ctrl_27_offset;
- + unsigned char ctrl_28_offset;
- + unsigned char ctrl_31_offset;
- + unsigned char ctrl_47_offset;
- + unsigned char ctrl_58_offset;
- + unsigned char num_of_fingers;
- + struct synaptics_rmi4_f12_extra_data *extra_data;
- + struct synaptics_rmi4_f12_query_5 *query_5 = NULL;
- + struct synaptics_rmi4_f12_query_8 *query_8 = NULL;
- + struct synaptics_rmi4_f12_ctrl_8 *ctrl_8 = NULL;
- + struct synaptics_rmi4_f12_ctrl_23 *ctrl_23 = NULL;
- + struct synaptics_rmi4_f12_ctrl_31 *ctrl_31 = NULL;
- + struct synaptics_rmi4_f12_ctrl_58 *ctrl_58 = NULL;
- + const struct synaptics_dsx_board_data *bdata =
- + rmi4_data->hw_if->board_data;
- +
- + fhandler->fn_number = fd->fn_number;
- + fhandler->num_of_data_sources = fd->intr_src_count;
- + fhandler->extra = kmalloc(sizeof(*extra_data), GFP_KERNEL);
- + if (!fhandler->extra) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to alloc mem for fhandler->extra\n",
- + __func__);
- + return -ENOMEM;
- + }
- + extra_data = (struct synaptics_rmi4_f12_extra_data *)fhandler->extra;
- + size_of_2d_data = sizeof(struct synaptics_rmi4_f12_finger_data);
- +
- + query_5 = kzalloc(sizeof(*query_5), GFP_KERNEL);
- + if (!query_5) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to alloc mem for query_5\n",
- + __func__);
- + retval = -ENOMEM;
- + goto exit;
- + }
- +
- + query_8 = kzalloc(sizeof(*query_8), GFP_KERNEL);
- + if (!query_8) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to alloc mem for query_8\n",
- + __func__);
- + retval = -ENOMEM;
- + goto exit;
- + }
- +
- + ctrl_8 = kzalloc(sizeof(*ctrl_8), GFP_KERNEL);
- + if (!ctrl_8) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to alloc mem for ctrl_8\n",
- + __func__);
- + retval = -ENOMEM;
- + goto exit;
- + }
- +
- + ctrl_23 = kzalloc(sizeof(*ctrl_23), GFP_KERNEL);
- + if (!ctrl_23) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to alloc mem for ctrl_23\n",
- + __func__);
- + retval = -ENOMEM;
- + goto exit;
- + }
- +
- + ctrl_31 = kzalloc(sizeof(*ctrl_31), GFP_KERNEL);
- + if (!ctrl_31) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to alloc mem for ctrl_31\n",
- + __func__);
- + retval = -ENOMEM;
- + goto exit;
- + }
- +
- + ctrl_58 = kzalloc(sizeof(*ctrl_58), GFP_KERNEL);
- + if (!ctrl_58) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to alloc mem for ctrl_58\n",
- + __func__);
- + retval = -ENOMEM;
- + goto exit;
- + }
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + fhandler->full_addr.query_base + 4,
- + &size_of_query5,
- + sizeof(size_of_query5));
- + if (retval < 0)
- + goto exit;
- +
- + pr_err("%s %d: fhandler->full_addr.query_base = 0x%04x\n", __func__, __LINE__, fhandler->full_addr.query_base);
- + pr_err("%s %d: fhandler->full_addr.ctrl_base = 0x%04x\n", __func__, __LINE__, fhandler->full_addr.ctrl_base);
- + pr_err("%s %d: size_of_query5 = %d\n", __func__, __LINE__, size_of_query5);
- +
- + if (size_of_query5 > sizeof(query_5->data))
- + size_of_query5 = sizeof(query_5->data);
- + memset(query_5->data, 0x00, sizeof(query_5->data));
- +
- + pr_err("%s %d: size_of_query5 = %d\n", __func__, __LINE__, size_of_query5);
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + fhandler->full_addr.query_base + 5,
- + query_5->data,
- + size_of_query5);
- + if (retval < 0)
- + goto exit;
- +
- + ctrl_8_offset = query_5->ctrl0_is_present +
- + query_5->ctrl1_is_present +
- + query_5->ctrl2_is_present +
- + query_5->ctrl3_is_present +
- + query_5->ctrl4_is_present +
- + query_5->ctrl5_is_present +
- + query_5->ctrl6_is_present +
- + query_5->ctrl7_is_present;
- +
- + ctrl_20_offset = ctrl_8_offset +
- + query_5->ctrl8_is_present +
- + query_5->ctrl9_is_present +
- + query_5->ctrl10_is_present +
- + query_5->ctrl11_is_present +
- + query_5->ctrl12_is_present +
- + query_5->ctrl13_is_present +
- + query_5->ctrl14_is_present +
- + query_5->ctrl15_is_present +
- + query_5->ctrl16_is_present +
- + query_5->ctrl17_is_present +
- + query_5->ctrl18_is_present +
- + query_5->ctrl19_is_present;
- +
- + ctrl_23_offset = ctrl_20_offset +
- + query_5->ctrl20_is_present +
- + query_5->ctrl21_is_present +
- + query_5->ctrl22_is_present;
- +
- +
- + ctrl_26_offset = ctrl_23_offset +
- + query_5->ctrl23_is_present +
- + query_5->ctrl24_is_present +
- + query_5->ctrl25_is_present;
- +
- + ctrl_27_offset = ctrl_26_offset +
- + query_5->ctrl26_is_present;
- +
- + ctrl_28_offset = ctrl_27_offset +
- + query_5->ctrl27_is_present;
- +
- + ctrl_31_offset = ctrl_28_offset +
- + query_5->ctrl28_is_present +
- + query_5->ctrl29_is_present +
- + query_5->ctrl30_is_present;
- +
- + ctrl_47_offset = ctrl_31_offset +
- + query_5->ctrl31_is_present +
- + query_5->ctrl32_is_present +
- + query_5->ctrl33_is_present +
- + query_5->ctrl34_is_present +
- + query_5->ctrl35_is_present +
- + query_5->ctrl36_is_present +
- + query_5->ctrl37_is_present +
- + query_5->ctrl38_is_present +
- + query_5->ctrl39_is_present +
- + query_5->ctrl40_is_present +
- + query_5->ctrl41_is_present +
- + query_5->ctrl42_is_present +
- + query_5->ctrl43_is_present +
- + query_5->ctrl44_is_present +
- + query_5->ctrl45_is_present +
- + query_5->ctrl46_is_present;
- + ctrl_58_offset = ctrl_47_offset +
- + query_5->ctrl47_is_present +
- + query_5->ctrl48_is_present +
- + query_5->ctrl49_is_present +
- + query_5->ctrl50_is_present +
- + query_5->ctrl51_is_present +
- + query_5->ctrl52_is_present +
- + query_5->ctrl53_is_present +
- + query_5->ctrl54_is_present +
- + query_5->ctrl55_is_present +
- + query_5->ctrl56_is_present +
- + query_5->ctrl57_is_present;
- +
- + ctrl_23_size = 2;
- + for (subpacket = 2; subpacket <= 4; subpacket++) {
- + retval = synaptics_rmi4_f12_find_sub(rmi4_data,
- + fhandler, query_5->data, sizeof(query_5->data),
- + 6, 23, subpacket);
- + if (retval == 1)
- + ctrl_23_size++;
- + else if (retval < 0)
- + goto exit;
- + }
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + fhandler->full_addr.ctrl_base + ctrl_23_offset,
- + ctrl_23->data,
- + ctrl_23_size);
- + if (retval < 0)
- + goto exit;
- +
- + /* Maximum number of fingers supported */
- + fhandler->num_of_data_points = min_t(unsigned char,
- + ctrl_23->max_reported_objects,
- + (unsigned char)F12_FINGERS_TO_SUPPORT);
- +
- + num_of_fingers = fhandler->num_of_data_points;
- + rmi4_data->num_of_fingers = num_of_fingers;
- +
- + rmi4_data->stylus_enable = ctrl_23->stylus_enable;
- + rmi4_data->eraser_enable = ctrl_23->eraser_enable;
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + fhandler->full_addr.query_base + 7,
- + &size_of_query8,
- + sizeof(size_of_query8));
- + if (retval < 0)
- + goto exit;
- +
- + if (size_of_query8 > sizeof(query_8->data))
- + size_of_query8 = sizeof(query_8->data);
- + memset(query_8->data, 0x00, sizeof(query_8->data));
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + fhandler->full_addr.query_base + 8,
- + query_8->data,
- + size_of_query8);
- + if (retval < 0)
- + goto exit;
- +
- + /* Determine the presence of the Data0 register */
- + extra_data->data1_offset = query_8->data0_is_present;
- +
- + if ((size_of_query8 >= 3) && (query_8->data15_is_present)) {
- + extra_data->data15_offset = query_8->data0_is_present +
- + query_8->data1_is_present +
- + query_8->data2_is_present +
- + query_8->data3_is_present +
- + query_8->data4_is_present +
- + query_8->data5_is_present +
- + query_8->data6_is_present +
- + query_8->data7_is_present +
- + query_8->data8_is_present +
- + query_8->data9_is_present +
- + query_8->data10_is_present +
- + query_8->data11_is_present +
- + query_8->data12_is_present +
- + query_8->data13_is_present +
- + query_8->data14_is_present;
- + extra_data->data15_size = (num_of_fingers + 7) / 8;
- + } else {
- + extra_data->data15_size = 0;
- + }
- +
- +#ifdef REPORT_2D_PRESSURE
- + if ((size_of_query8 >= 5) && (query_8->data29_is_present)) {
- + extra_data->data29_offset = query_8->data0_is_present +
- + query_8->data1_is_present +
- + query_8->data2_is_present +
- + query_8->data3_is_present +
- + query_8->data4_is_present +
- + query_8->data5_is_present +
- + query_8->data6_is_present +
- + query_8->data7_is_present +
- + query_8->data8_is_present +
- + query_8->data9_is_present +
- + query_8->data10_is_present +
- + query_8->data11_is_present +
- + query_8->data12_is_present +
- + query_8->data13_is_present +
- + query_8->data14_is_present +
- + query_8->data15_is_present +
- + query_8->data16_is_present +
- + query_8->data17_is_present +
- + query_8->data18_is_present +
- + query_8->data19_is_present +
- + query_8->data20_is_present +
- + query_8->data21_is_present +
- + query_8->data22_is_present +
- + query_8->data23_is_present +
- + query_8->data24_is_present +
- + query_8->data25_is_present +
- + query_8->data26_is_present +
- + query_8->data27_is_present +
- + query_8->data28_is_present;
- + extra_data->data29_size = 0;
- + for (subpacket = 0; subpacket <= num_of_fingers; subpacket++) {
- + retval = synaptics_rmi4_f12_find_sub(rmi4_data,
- + fhandler, query_8->data,
- + sizeof(query_8->data),
- + 9, 29, subpacket);
- + if (retval == 1)
- + extra_data->data29_size += 2;
- + else if (retval < 0)
- + goto exit;
- + }
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + fhandler->full_addr.ctrl_base + ctrl_58_offset,
- + ctrl_58->data,
- + sizeof(ctrl_58->data));
- + if (retval < 0)
- + goto exit;
- +
- + pr_err("%s %d: extra_data->data29_offset = %d\n", __func__, __LINE__, extra_data->data29_offset);
- + pr_err("%s %d: extra_data->data29_size = %d\n", __func__, __LINE__, extra_data->data29_size);
- + pr_err("%s %d: ctrl_58_offset = %d\n", __func__, __LINE__, ctrl_58_offset);
- +
- + rmi4_data->force_min =
- + (int)(ctrl_58->min_force_lsb << 0) |
- + (int)(ctrl_58->min_force_msb << 8);
- + rmi4_data->force_max =
- + (int)(ctrl_58->max_force_lsb << 0) |
- + (int)(ctrl_58->max_force_msb << 8);
- +
- + pr_err("%s %d: rmi4_data->force_min = %d\n", __func__, __LINE__, rmi4_data->force_min);
- + pr_err("%s %d: rmi4_data->force_max = %d\n", __func__, __LINE__, rmi4_data->force_max);
- +
- + rmi4_data->report_pressure = true;
- + } else {
- + extra_data->data29_size = 0;
- + rmi4_data->report_pressure = false;
- + }
- +#endif
- +
- + rmi4_data->report_enable = RPT_DEFAULT;
- +#ifdef REPORT_2D_Z
- + rmi4_data->report_enable |= RPT_Z;
- +#endif
- +#ifdef REPORT_2D_W
- + rmi4_data->report_enable |= (RPT_WX | RPT_WY);
- +#endif
- +
- + retval = synaptics_rmi4_f12_set_enables(rmi4_data,
- + fhandler->full_addr.ctrl_base + ctrl_28_offset);
- + if (retval < 0)
- + goto exit;
- +
- + if (query_5->ctrl8_is_present) {
- + rmi4_data->wedge_sensor = false;
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + fhandler->full_addr.ctrl_base + ctrl_8_offset,
- + ctrl_8->data,
- + sizeof(ctrl_8->data));
- + if (retval < 0)
- + goto exit;
- +
- + /* Maximum x and y */
- + rmi4_data->sensor_max_x =
- + ((unsigned int)ctrl_8->max_x_coord_lsb << 0) |
- + ((unsigned int)ctrl_8->max_x_coord_msb << 8);
- + rmi4_data->sensor_max_y =
- + ((unsigned int)ctrl_8->max_y_coord_lsb << 0) |
- + ((unsigned int)ctrl_8->max_y_coord_msb << 8);
- +
- + rmi4_data->max_touch_width = MAX_F12_TOUCH_WIDTH;
- + } else {
- + rmi4_data->wedge_sensor = true;
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + fhandler->full_addr.ctrl_base + ctrl_31_offset,
- + ctrl_31->data,
- + sizeof(ctrl_31->data));
- + if (retval < 0)
- + goto exit;
- +
- + /* Maximum x and y */
- + rmi4_data->sensor_max_x =
- + ((unsigned int)ctrl_31->max_x_coord_lsb << 0) |
- + ((unsigned int)ctrl_31->max_x_coord_msb << 8);
- + rmi4_data->sensor_max_y =
- + ((unsigned int)ctrl_31->max_y_coord_lsb << 0) |
- + ((unsigned int)ctrl_31->max_y_coord_msb << 8);
- +
- + rmi4_data->max_touch_width = MAX_F12_TOUCH_WIDTH;
- + }
- +
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: Function %02x max x = %d max y = %d\n",
- + __func__, fhandler->fn_number,
- + rmi4_data->sensor_max_x,
- + rmi4_data->sensor_max_y);
- +
- + if (bdata->swap_axes) {
- + temp = rmi4_data->sensor_max_x;
- + rmi4_data->sensor_max_x = rmi4_data->sensor_max_y;
- + rmi4_data->sensor_max_y = temp;
- + }
- +
- + rmi4_data->f12_wakeup_gesture = query_5->ctrl27_is_present;
- + if (rmi4_data->f12_wakeup_gesture) {
- + extra_data->ctrl20_offset = ctrl_20_offset;
- + extra_data->data4_offset = query_8->data0_is_present +
- + query_8->data1_is_present +
- + query_8->data2_is_present +
- + query_8->data3_is_present;
- + }
- +
- + synaptics_rmi4_set_intr_mask(fhandler, fd, intr_count);
- +
- + extra_data->ctrl26_offset = ctrl_26_offset;
- + extra_data->ctrl27_offset = ctrl_27_offset;
- +
- + /* Allocate memory for finger data storage space */
- + fhandler->data_size = num_of_fingers * size_of_2d_data;
- + fhandler->data = kmalloc(fhandler->data_size, GFP_KERNEL);
- + if (!fhandler->data) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to alloc mem for fhandler->data\n",
- + __func__);
- + retval = -ENOMEM;
- + goto exit;
- + }
- +
- +exit:
- + kfree(query_5);
- + kfree(query_8);
- + kfree(ctrl_8);
- + kfree(ctrl_23);
- + kfree(ctrl_31);
- + kfree(ctrl_58);
- +
- + return retval;
- +}
- +
- +static int synaptics_rmi4_f1a_alloc_mem(struct synaptics_rmi4_data *rmi4_data,
- + struct synaptics_rmi4_fn *fhandler)
- +{
- + int retval;
- + struct synaptics_rmi4_f1a_handle *f1a;
- +
- + f1a = kzalloc(sizeof(*f1a), GFP_KERNEL);
- + if (!f1a) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to alloc mem for function handle\n",
- + __func__);
- + return -ENOMEM;
- + }
- +
- + fhandler->data = (void *)f1a;
- + fhandler->extra = NULL;
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + fhandler->full_addr.query_base,
- + f1a->button_query.data,
- + sizeof(f1a->button_query.data));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to read query registers\n",
- + __func__);
- + return retval;
- + }
- +
- + f1a->max_count = f1a->button_query.max_button_count + 1;
- +
- + f1a->button_control.txrx_map = kzalloc(f1a->max_count * 2, GFP_KERNEL);
- + if (!f1a->button_control.txrx_map) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to alloc mem for tx rx mapping\n",
- + __func__);
- + return -ENOMEM;
- + }
- +
- + f1a->button_bitmask_size = (f1a->max_count + 7) / 8;
- +
- + f1a->button_data_buffer = kcalloc(f1a->button_bitmask_size,
- + sizeof(*(f1a->button_data_buffer)), GFP_KERNEL);
- + if (!f1a->button_data_buffer) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to alloc mem for data buffer\n",
- + __func__);
- + return -ENOMEM;
- + }
- +
- + f1a->button_map = kcalloc(f1a->max_count,
- + sizeof(*(f1a->button_map)), GFP_KERNEL);
- + if (!f1a->button_map) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to alloc mem for button map\n",
- + __func__);
- + return -ENOMEM;
- + }
- +
- + return 0;
- +}
- +
- +static int synaptics_rmi4_f1a_button_map(struct synaptics_rmi4_data *rmi4_data,
- + struct synaptics_rmi4_fn *fhandler)
- +{
- + int retval;
- + unsigned char ii;
- + unsigned char offset = 0;
- + struct synaptics_rmi4_f1a_query_4 query_4;
- + struct synaptics_rmi4_f1a_handle *f1a = fhandler->data;
- + const struct synaptics_dsx_board_data *bdata =
- + rmi4_data->hw_if->board_data;
- +
- + offset = f1a->button_query.has_general_control +
- + f1a->button_query.has_interrupt_enable +
- + f1a->button_query.has_multibutton_select;
- +
- + if (f1a->button_query.has_tx_rx_map) {
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + fhandler->full_addr.ctrl_base + offset,
- + f1a->button_control.txrx_map,
- + f1a->max_count * 2);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to read tx rx mapping\n",
- + __func__);
- + return retval;
- + }
- +
- + rmi4_data->button_txrx_mapping = f1a->button_control.txrx_map;
- + }
- +
- + if (f1a->button_query.has_query4) {
- + offset = 2 + f1a->button_query.has_query2 +
- + f1a->button_query.has_query3;
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + fhandler->full_addr.query_base + offset,
- + query_4.data,
- + sizeof(query_4.data));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to read button features 4\n",
- + __func__);
- + return retval;
- + }
- +
- + if (query_4.has_ctrl24)
- + rmi4_data->external_afe_buttons = true;
- + else
- + rmi4_data->external_afe_buttons = false;
- + }
- +
- + if (!bdata->cap_button_map) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: cap_button_map is NULL in board file\n",
- + __func__);
- + return -ENODEV;
- + } else if (!bdata->cap_button_map->map) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Button map is missing in board file\n",
- + __func__);
- + return -ENODEV;
- + } else {
- + if (bdata->cap_button_map->nbuttons != f1a->max_count) {
- + f1a->valid_button_count = min(f1a->max_count,
- + bdata->cap_button_map->nbuttons);
- + } else {
- + f1a->valid_button_count = f1a->max_count;
- + }
- +
- + for (ii = 0; ii < f1a->valid_button_count; ii++)
- + f1a->button_map[ii] = bdata->cap_button_map->map[ii];
- + }
- +
- + return 0;
- +}
- +
- +static void synaptics_rmi4_f1a_kfree(struct synaptics_rmi4_fn *fhandler)
- +{
- + struct synaptics_rmi4_f1a_handle *f1a = fhandler->data;
- +
- + if (f1a) {
- + kfree(f1a->button_control.txrx_map);
- + kfree(f1a->button_data_buffer);
- + kfree(f1a->button_map);
- + kfree(f1a);
- + fhandler->data = NULL;
- + }
- +
- + return;
- +}
- +
- +static int synaptics_rmi4_f1a_init(struct synaptics_rmi4_data *rmi4_data,
- + struct synaptics_rmi4_fn *fhandler,
- + struct synaptics_rmi4_fn_desc *fd,
- + unsigned int intr_count)
- +{
- + int retval;
- +
- + fhandler->fn_number = fd->fn_number;
- + fhandler->num_of_data_sources = fd->intr_src_count;
- +
- + synaptics_rmi4_set_intr_mask(fhandler, fd, intr_count);
- +
- + retval = synaptics_rmi4_f1a_alloc_mem(rmi4_data, fhandler);
- + if (retval < 0)
- + goto error_exit;
- +
- + retval = synaptics_rmi4_f1a_button_map(rmi4_data, fhandler);
- + if (retval < 0)
- + goto error_exit;
- +
- + rmi4_data->button_0d_enabled = 1;
- +
- + return 0;
- +
- +error_exit:
- + synaptics_rmi4_f1a_kfree(fhandler);
- +
- + return retval;
- +}
- +
- +static void synaptics_rmi4_empty_fn_list(struct synaptics_rmi4_data *rmi4_data)
- +{
- + struct synaptics_rmi4_fn *fhandler;
- + struct synaptics_rmi4_fn *fhandler_temp;
- + struct synaptics_rmi4_device_info *rmi;
- +
- + rmi = &(rmi4_data->rmi4_mod_info);
- +
- + if (!list_empty(&rmi->support_fn_list)) {
- + list_for_each_entry_safe(fhandler,
- + fhandler_temp,
- + &rmi->support_fn_list,
- + link) {
- + if (fhandler->fn_number == SYNAPTICS_RMI4_F1A) {
- + synaptics_rmi4_f1a_kfree(fhandler);
- + } else {
- + kfree(fhandler->extra);
- + kfree(fhandler->data);
- + }
- + list_del(&fhandler->link);
- + kfree(fhandler);
- + }
- + }
- + INIT_LIST_HEAD(&rmi->support_fn_list);
- +
- + return;
- +}
- +
- +static int synaptics_rmi4_check_status(struct synaptics_rmi4_data *rmi4_data,
- + bool *was_in_bl_mode)
- +{
- + int retval;
- + int timeout = CHECK_STATUS_TIMEOUT_MS;
- + struct synaptics_rmi4_f01_device_status status;
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + rmi4_data->f01_data_base_addr,
- + status.data,
- + sizeof(status.data));
- + if (retval < 0)
- + return retval;
- +
- + while (status.status_code == STATUS_CRC_IN_PROGRESS) {
- + if (timeout > 0)
- + msleep(20);
- + else
- + return -EINVAL;
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + rmi4_data->f01_data_base_addr,
- + status.data,
- + sizeof(status.data));
- + if (retval < 0)
- + return retval;
- +
- + timeout -= 20;
- + }
- +
- + if (timeout != CHECK_STATUS_TIMEOUT_MS)
- + *was_in_bl_mode = true;
- +
- + if (status.flash_prog == 1) {
- + rmi4_data->flash_prog_mode = true;
- + pr_notice("%s: In flash prog mode, status = 0x%02x\n",
- + __func__,
- + status.status_code);
- + } else {
- + rmi4_data->flash_prog_mode = false;
- + }
- +
- + return 0;
- +}
- +
- +static void synaptics_rmi4_set_configured(struct synaptics_rmi4_data *rmi4_data)
- +{
- + int retval;
- + unsigned char device_ctrl;
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + rmi4_data->f01_ctrl_base_addr,
- + &device_ctrl,
- + sizeof(device_ctrl));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to set configured\n",
- + __func__);
- + return;
- + }
- +
- + rmi4_data->no_sleep_setting = device_ctrl & NO_SLEEP_ON;
- + device_ctrl |= CONFIGURED;
- +
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + rmi4_data->f01_ctrl_base_addr,
- + &device_ctrl,
- + sizeof(device_ctrl));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to set configured\n",
- + __func__);
- + }
- +
- + return;
- +}
- +
- +static int synaptics_rmi4_alloc_fh(struct synaptics_rmi4_fn **fhandler,
- + struct synaptics_rmi4_fn_desc *rmi_fd, int page_number)
- +{
- + *fhandler = kzalloc(sizeof(**fhandler), GFP_KERNEL);
- + if (!(*fhandler))
- + return -ENOMEM;
- +
- + (*fhandler)->full_addr.data_base =
- + (rmi_fd->data_base_addr |
- + (page_number << 8));
- + (*fhandler)->full_addr.ctrl_base =
- + (rmi_fd->ctrl_base_addr |
- + (page_number << 8));
- + (*fhandler)->full_addr.cmd_base =
- + (rmi_fd->cmd_base_addr |
- + (page_number << 8));
- + (*fhandler)->full_addr.query_base =
- + (rmi_fd->query_base_addr |
- + (page_number << 8));
- +
- + return 0;
- +}
- +
- +static int synaptics_rmi4_query_device(struct synaptics_rmi4_data *rmi4_data)
- +{
- + int retval;
- + unsigned char page_number;
- + unsigned char intr_count;
- + unsigned char f01_query[F01_STD_QUERY_LEN];
- + unsigned short pdt_entry_addr;
- + bool f01found;
- + bool f35found;
- + bool was_in_bl_mode;
- + struct synaptics_rmi4_fn_desc rmi_fd;
- + struct synaptics_rmi4_fn *fhandler;
- + struct synaptics_rmi4_device_info *rmi;
- +
- + rmi = &(rmi4_data->rmi4_mod_info);
- +
- +rescan_pdt:
- + f01found = false;
- + f35found = false;
- + was_in_bl_mode = false;
- + intr_count = 0;
- + INIT_LIST_HEAD(&rmi->support_fn_list);
- +
- + /* Scan the page description tables of the pages to service */
- + for (page_number = 0; page_number < PAGES_TO_SERVICE; page_number++) {
- + for (pdt_entry_addr = PDT_START; pdt_entry_addr > PDT_END;
- + pdt_entry_addr -= PDT_ENTRY_SIZE) {
- + pdt_entry_addr |= (page_number << 8);
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + pdt_entry_addr,
- + (unsigned char *)&rmi_fd,
- + sizeof(rmi_fd));
- + if (retval < 0)
- + return retval;
- +
- + pdt_entry_addr &= ~(MASK_8BIT << 8);
- +
- + fhandler = NULL;
- +
- + if (rmi_fd.fn_number == 0) {
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: Reached end of PDT\n",
- + __func__);
- + break;
- + }
- +
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: F%02x found (page %d)\n",
- + __func__, rmi_fd.fn_number,
- + page_number);
- +
- + switch (rmi_fd.fn_number) {
- + case SYNAPTICS_RMI4_F01:
- + if (rmi_fd.intr_src_count == 0)
- + break;
- +
- + f01found = true;
- +
- + retval = synaptics_rmi4_alloc_fh(&fhandler,
- + &rmi_fd, page_number);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to alloc for F%d\n",
- + __func__,
- + rmi_fd.fn_number);
- + return retval;
- + }
- +
- + retval = synaptics_rmi4_f01_init(rmi4_data,
- + fhandler, &rmi_fd, intr_count);
- + if (retval < 0)
- + return retval;
- +
- + retval = synaptics_rmi4_check_status(rmi4_data,
- + &was_in_bl_mode);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to check status\n",
- + __func__);
- + return retval;
- + }
- +
- + if (was_in_bl_mode) {
- + kfree(fhandler);
- + fhandler = NULL;
- + goto rescan_pdt;
- + }
- +
- + if (rmi4_data->flash_prog_mode)
- + goto flash_prog_mode;
- +
- + break;
- + case SYNAPTICS_RMI4_F11:
- + if (rmi_fd.intr_src_count == 0)
- + break;
- +
- + retval = synaptics_rmi4_alloc_fh(&fhandler,
- + &rmi_fd, page_number);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to alloc for F%d\n",
- + __func__,
- + rmi_fd.fn_number);
- + return retval;
- + }
- +
- + retval = synaptics_rmi4_f11_init(rmi4_data,
- + fhandler, &rmi_fd, intr_count);
- + if (retval < 0)
- + return retval;
- + break;
- + case SYNAPTICS_RMI4_F12:
- + if (rmi_fd.intr_src_count == 0)
- + break;
- +
- + retval = synaptics_rmi4_alloc_fh(&fhandler,
- + &rmi_fd, page_number);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to alloc for F%d\n",
- + __func__,
- + rmi_fd.fn_number);
- + return retval;
- + }
- +
- + retval = synaptics_rmi4_f12_init(rmi4_data,
- + fhandler, &rmi_fd, intr_count);
- + if (retval < 0)
- + return retval;
- + break;
- + case SYNAPTICS_RMI4_F1A:
- + if (rmi_fd.intr_src_count == 0)
- + break;
- +
- + retval = synaptics_rmi4_alloc_fh(&fhandler,
- + &rmi_fd, page_number);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to alloc for F%d\n",
- + __func__,
- + rmi_fd.fn_number);
- + return retval;
- + }
- +
- + retval = synaptics_rmi4_f1a_init(rmi4_data,
- + fhandler, &rmi_fd, intr_count);
- + if (retval < 0) {
- +#ifdef IGNORE_FN_INIT_FAILURE
- + kfree(fhandler);
- + fhandler = NULL;
- +#else
- + return retval;
- +#endif
- + }
- + break;
- + case SYNAPTICS_RMI4_F35:
- + f35found = true;
- + break;
- +#ifdef F51_DISCRETE_FORCE
- + case SYNAPTICS_RMI4_F51:
- + rmi4_data->f51_query_base_addr =
- + rmi_fd.query_base_addr |
- + (page_number << 8);
- + break;
- +#endif
- + }
- +
- + /* Accumulate the interrupt count */
- + intr_count += rmi_fd.intr_src_count;
- +
- + if (fhandler && rmi_fd.intr_src_count) {
- + list_add_tail(&fhandler->link,
- + &rmi->support_fn_list);
- + }
- + }
- + }
- +
- + if (!f01found) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to find F01\n",
- + __func__);
- + if (!f35found) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to find F35\n",
- + __func__);
- + return -EINVAL;
- + } else {
- + pr_notice("%s: In microbootloader mode\n",
- + __func__);
- + return 0;
- + }
- + }
- +
- +flash_prog_mode:
- + rmi4_data->num_of_intr_regs = (intr_count + 7) / 8;
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: Number of interrupt registers = %d\n",
- + __func__, rmi4_data->num_of_intr_regs);
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + rmi4_data->f01_query_base_addr,
- + f01_query,
- + sizeof(f01_query));
- + if (retval < 0)
- + return retval;
- +
- + /* RMI Version 4.0 currently supported */
- + rmi->version_major = 4;
- + rmi->version_minor = 0;
- +
- + rmi->manufacturer_id = f01_query[0];
- + rmi->product_props = f01_query[1];
- + rmi->product_info[0] = f01_query[2];
- + rmi->product_info[1] = f01_query[3];
- + retval = secure_memcpy(rmi->product_id_string,
- + sizeof(rmi->product_id_string),
- + &f01_query[11],
- + sizeof(f01_query) - 11,
- + PRODUCT_ID_SIZE);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to copy product ID string\n",
- + __func__);
- + }
- +
- + if (rmi->manufacturer_id != 1) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Non-Synaptics device found, manufacturer ID = %d\n",
- + __func__, rmi->manufacturer_id);
- + }
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + rmi4_data->f01_query_base_addr + F01_BUID_ID_OFFSET,
- + rmi->build_id,
- + sizeof(rmi->build_id));
- + if (retval < 0)
- + return retval;
- +
- + rmi4_data->firmware_id = (unsigned int)rmi->build_id[0] +
- + (unsigned int)rmi->build_id[1] * 0x100 +
- + (unsigned int)rmi->build_id[2] * 0x10000;
- +
- + memset(rmi4_data->intr_mask, 0x00, sizeof(rmi4_data->intr_mask));
- +
- + /*
- + * Map out the interrupt bit masks for the interrupt sources
- + * from the registered function handlers.
- + */
- + if (!list_empty(&rmi->support_fn_list)) {
- + list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
- + if (fhandler->num_of_data_sources) {
- + rmi4_data->intr_mask[fhandler->intr_reg_num] |=
- + fhandler->intr_mask;
- + }
- + }
- + }
- +
- + if (rmi4_data->f11_wakeup_gesture || rmi4_data->f12_wakeup_gesture)
- + rmi4_data->enable_wakeup_gesture = WAKEUP_GESTURE;
- + else
- + rmi4_data->enable_wakeup_gesture = false;
- +
- + synaptics_rmi4_set_configured(rmi4_data);
- +
- + return 0;
- +}
- +
- +static int synaptics_rmi4_gpio_setup(int gpio, bool config, int dir, int state, const char *label)
- +{
- + int retval = 0;
- +
- + if (config) {
- + retval = gpio_request(gpio, label);
- + if (retval) {
- + pr_err("%s: Failed to get gpio %d (code: %d)",
- + __func__, gpio, retval);
- + return retval;
- + }
- +
- + if (dir == 0)
- + retval = gpio_direction_input(gpio);
- + else
- + retval = gpio_direction_output(gpio, state);
- + if (retval) {
- + pr_err("%s: Failed to set gpio %d direction",
- + __func__, gpio);
- + return retval;
- + }
- + } else {
- + gpio_free(gpio);
- + }
- +
- + return retval;
- +}
- +
- +static int synaptics_rmi4_pinctrl_init(struct synaptics_rmi4_data *rmi4_data)
- +{
- + int retval;
- +
- + /* Get pinctrl if target uses pinctrl */
- + rmi4_data->ts_pinctrl = devm_pinctrl_get((rmi4_data->pdev->dev.parent));
- + if (IS_ERR_OR_NULL(rmi4_data->ts_pinctrl)) {
- + retval = PTR_ERR(rmi4_data->ts_pinctrl);
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "Target does not use pinctrl %d\n", retval);
- + goto err_pinctrl_get;
- + }
- +
- + rmi4_data->pinctrl_state_active
- + = pinctrl_lookup_state(rmi4_data->ts_pinctrl, PINCTRL_STATE_ACTIVE);
- + if (IS_ERR_OR_NULL(rmi4_data->pinctrl_state_active)) {
- + retval = PTR_ERR(rmi4_data->pinctrl_state_active);
- + dev_err(rmi4_data->pdev->dev.parent,
- + "Can not lookup %s pinstate %d\n",
- + PINCTRL_STATE_ACTIVE, retval);
- + goto err_pinctrl_lookup;
- + }
- +
- + rmi4_data->pinctrl_state_suspend
- + = pinctrl_lookup_state(rmi4_data->ts_pinctrl, PINCTRL_STATE_SUSPEND);
- + if (IS_ERR_OR_NULL(rmi4_data->pinctrl_state_suspend)) {
- + retval = PTR_ERR(rmi4_data->pinctrl_state_suspend);
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "Can not lookup %s pinstate %d\n",
- + PINCTRL_STATE_SUSPEND, retval);
- + goto err_pinctrl_lookup;
- + }
- +
- + return 0;
- +
- +err_pinctrl_lookup:
- + devm_pinctrl_put(rmi4_data->ts_pinctrl);
- +err_pinctrl_get:
- + rmi4_data->ts_pinctrl = NULL;
- + return retval;
- +}
- +
- +static void synaptics_rmi4_set_params(struct synaptics_rmi4_data *rmi4_data)
- +{
- + unsigned char ii;
- + struct synaptics_rmi4_f1a_handle *f1a;
- + struct synaptics_rmi4_fn *fhandler;
- + struct synaptics_rmi4_device_info *rmi;
- +
- + rmi = &(rmi4_data->rmi4_mod_info);
- +
- + input_set_abs_params(rmi4_data->input_dev,
- + ABS_MT_POSITION_X, 0,
- + rmi4_data->sensor_max_x, 0, 0);
- + input_set_abs_params(rmi4_data->input_dev,
- + ABS_MT_POSITION_Y, 0,
- + rmi4_data->sensor_max_y, 0, 0);
- +#ifdef REPORT_2D_W
- + input_set_abs_params(rmi4_data->input_dev,
- + ABS_MT_TOUCH_MAJOR, 0,
- + rmi4_data->max_touch_width, 0, 0);
- + input_set_abs_params(rmi4_data->input_dev,
- + ABS_MT_TOUCH_MINOR, 0,
- + rmi4_data->max_touch_width, 0, 0);
- +#endif
- +
- +#ifdef REPORT_2D_PRESSURE
- + if (rmi4_data->report_pressure) {
- + input_set_abs_params(rmi4_data->input_dev,
- + ABS_MT_PRESSURE, rmi4_data->force_min,
- + rmi4_data->force_max, 0, 0);
- + }
- +#elif defined(F51_DISCRETE_FORCE)
- + input_set_abs_params(rmi4_data->input_dev,
- + ABS_MT_PRESSURE, 0,
- + FORCE_LEVEL_MAX, 0, 0);
- +#endif
- +
- +#ifdef TYPE_B_PROTOCOL
- +#ifdef KERNEL_ABOVE_3_6
- + input_mt_init_slots(rmi4_data->input_dev,
- + rmi4_data->num_of_fingers, INPUT_MT_DIRECT);
- +#else
- + input_mt_init_slots(rmi4_data->input_dev,
- + rmi4_data->num_of_fingers);
- +#endif
- +#endif
- +
- + f1a = NULL;
- + if (!list_empty(&rmi->support_fn_list)) {
- + list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
- + if (fhandler->fn_number == SYNAPTICS_RMI4_F1A)
- + f1a = fhandler->data;
- + }
- + }
- +
- + if (f1a) {
- + for (ii = 0; ii < f1a->valid_button_count; ii++) {
- + set_bit(f1a->button_map[ii],
- + rmi4_data->input_dev->keybit);
- + input_set_capability(rmi4_data->input_dev,
- + EV_KEY, f1a->button_map[ii]);
- + }
- + }
- +
- + if (vir_button_map->nbuttons) {
- + for (ii = 0; ii < vir_button_map->nbuttons; ii++) {
- + set_bit(vir_button_map->map[ii * 5],
- + rmi4_data->input_dev->keybit);
- + input_set_capability(rmi4_data->input_dev,
- + EV_KEY, vir_button_map->map[ii * 5]);
- + }
- + }
- +
- + if (rmi4_data->f11_wakeup_gesture || rmi4_data->f12_wakeup_gesture) {
- + set_bit(KEY_WAKEUP, rmi4_data->input_dev->keybit);
- + input_set_capability(rmi4_data->input_dev, EV_KEY, KEY_WAKEUP);
- + }
- +
- + return;
- +}
- +
- +/* Re-configure touch settings when wakeup gesture mode is switched in suspend */
- +static void synaptics_rmi4_wakeup_reconfigure(struct synaptics_rmi4_data *rmi4_data,
- + bool enable)
- +{
- + struct synaptics_rmi4_exp_fhandler *exp_fhandler;
- +
- + synaptics_rmi4_sleep_enable(rmi4_data, !enable);
- +
- + if (enable) {
- + mdss_regulator_ctrl(rmi4_data, DISP_REG_ALL, true);
- + mdss_reset_ctrl(rmi4_data->hw_if->board_data, true);
- + }
- +
- + synaptics_rmi4_wakeup_gesture(rmi4_data, enable);
- +
- + if (!enable) {
- + mdss_regulator_ctrl(rmi4_data, DISP_REG_ALL, false);
- + mdss_reset_ctrl(rmi4_data->hw_if->board_data, false);
- + }
- +
- + synaptics_rmi4_irq_enable(rmi4_data, enable, false);
- +
- + mutex_lock(&exp_data.mutex);
- + if (!list_empty(&exp_data.list)) {
- + list_for_each_entry(exp_fhandler, &exp_data.list, link) {
- + if (enable) {
- + if (exp_fhandler->exp_fn->resume != NULL)
- + exp_fhandler->exp_fn->resume(rmi4_data);
- + } else {
- + if (exp_fhandler->exp_fn->suspend != NULL)
- + exp_fhandler->exp_fn->suspend(rmi4_data);
- + }
- + }
- + }
- + mutex_unlock(&exp_data.mutex);
- +}
- +
- +static void synaptics_key_ctrl(struct synaptics_rmi4_data *rmi4_data, bool enable)
- +{
- + int retval;
- + unsigned char ii;
- + unsigned char intr_enable;
- + struct synaptics_rmi4_fn *fhandler;
- + struct synaptics_rmi4_device_info *rmi;
- +
- + rmi = &(rmi4_data->rmi4_mod_info);
- +
- + if (list_empty(&rmi->support_fn_list))
- + return ;
- +
- + list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
- + if (fhandler->fn_number == SYNAPTICS_RMI4_F1A) {
- + ii = fhandler->intr_reg_num;
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + rmi4_data->f01_ctrl_base_addr + 1 + ii,
- + &intr_enable,
- + sizeof(intr_enable));
- + if (retval < 0)
- + return ;
- +
- + if (enable == true)
- + intr_enable |= fhandler->intr_mask;
- + else
- + intr_enable &= ~fhandler->intr_mask;
- +
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + rmi4_data->f01_ctrl_base_addr + 1 + ii,
- + &intr_enable,
- + sizeof(intr_enable));
- + if (retval < 0)
- + return ;
- + }
- + }
- +
- + return ;
- +}
- +
- +static void cover_mode_set(struct synaptics_rmi4_data *rmi4_data, int enable)
- +{
- + struct synaptics_rmi4_f12_extra_data *extra_data;
- + struct synaptics_rmi4_fn *fhandler;
- + struct synaptics_rmi4_device_info *rmi;
- + int retval;
- + unsigned char ctrl26_value;
- +
- + mutex_lock(&rmi4_data->rmi4_cover_mutex);
- +
- + if (rmi4_data->suspend)
- + goto end;
- +
- + rmi = &(rmi4_data->rmi4_mod_info);
- +
- + list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
- + if (fhandler->fn_number == SYNAPTICS_RMI4_F12)
- + break;
- + }
- +
- + extra_data = (struct synaptics_rmi4_f12_extra_data *)fhandler->extra;
- +
- + if (enable == 0) {
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + fhandler->full_addr.ctrl_base + extra_data->ctrl26_offset,
- + &ctrl26_value,
- + 1);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to read ctrl26 reg\n",
- + __func__);
- + goto end;
- + }
- +
- + ctrl26_value &= 0xfc;
- +
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + fhandler->full_addr.ctrl_base + extra_data->ctrl26_offset,
- + &ctrl26_value,
- + 1);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to close cover mode\n",
- + __func__);
- + goto end;
- + }
- +
- + synaptics_key_ctrl(rmi4_data, true);
- + } else {
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + fhandler->full_addr.ctrl_base + extra_data->ctrl26_offset,
- + &ctrl26_value,
- + 1);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to read ctrl26 reg\n",
- + __func__);
- + goto end;
- + }
- +
- + ctrl26_value |= 0x03;
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + fhandler->full_addr.ctrl_base + extra_data->ctrl26_offset,
- + &ctrl26_value,
- + 1);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to change cover mode\n",
- + __func__);
- + goto end;
- + }
- +
- + synaptics_key_ctrl(rmi4_data, false);
- + };
- +end:
- + mutex_unlock(&rmi4_data->rmi4_cover_mutex);
- +}
- +
- +static void synaptics_rmi4_switch_mode_work(struct work_struct *work)
- +{
- + struct synaptics_rmi4_mode_switch *ms = container_of(work, struct synaptics_rmi4_mode_switch, switch_mode_work);
- + struct synaptics_rmi4_data *rmi4_data = ms->data;
- + const struct synaptics_dsx_board_data *bdata = rmi4_data->hw_if->board_data;
- + unsigned char value = ms->mode;
- +
- + if (value >= INPUT_EVENT_WAKUP_MODE_OFF && value <= INPUT_EVENT_WAKUP_MODE_ON) {
- + if (bdata->cut_off_power) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Unable to switch wakeup gesture mode\n", __func__);
- + return;
- + }
- +
- + rmi4_data->enable_wakeup_gesture = value - INPUT_EVENT_WAKUP_MODE_OFF;
- + } else if (value >= INPUT_EVENT_COVER_MODE_OFF && value <= INPUT_EVENT_COVER_MODE_ON) {
- + rmi4_data->enable_cover_mode = value - INPUT_EVENT_COVER_MODE_OFF;
- + cover_mode_set(rmi4_data, rmi4_data->enable_cover_mode);
- + } else {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "Does not support touch mode %d\n", value);
- + }
- +
- + if (ms != NULL) {
- + kfree(ms);
- + ms = NULL;
- + }
- +}
- +
- +static int synaptics_rmi4_input_event(struct input_dev *dev,
- + unsigned int type, unsigned int code, int value)
- +{
- + struct synaptics_rmi4_data *rmi4_data = input_get_drvdata(dev);
- + struct synaptics_rmi4_mode_switch *ms;
- +
- + if (type == EV_SYN && code == SYN_CONFIG) {
- + dev_info(rmi4_data->pdev->dev.parent,
- + "Set input event value = %d\n", value);
- +
- + if (value >= INPUT_EVENT_START && value <= INPUT_EVENT_END) {
- + ms = (struct synaptics_rmi4_mode_switch *)kmalloc(sizeof(struct synaptics_rmi4_mode_switch),
- + GFP_ATOMIC);
- + if (ms != NULL) {
- + ms->data = rmi4_data;
- + ms->mode = (unsigned char)value;
- + INIT_WORK(&ms->switch_mode_work, synaptics_rmi4_switch_mode_work);
- + schedule_work(&ms->switch_mode_work);
- + } else {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "Failed in allocating memory for switching mode!\n");
- + return -ENOMEM;
- + }
- + } else {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "Invalid event value %d\n", value);
- + return -EINVAL;
- + }
- + }
- +
- + return 0;
- +}
- +
- +static int synaptics_rmi4_set_input_dev(struct synaptics_rmi4_data *rmi4_data)
- +{
- + int retval;
- + const struct synaptics_dsx_board_data *bdata =
- + rmi4_data->hw_if->board_data;
- +
- + rmi4_data->input_dev = input_allocate_device();
- + if (rmi4_data->input_dev == NULL) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to allocate input device\n",
- + __func__);
- + retval = -ENOMEM;
- + goto err_input_device;
- + }
- +
- + retval = synaptics_rmi4_query_device(rmi4_data);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to query device\n",
- + __func__);
- + goto err_query_device;
- + }
- +
- + rmi4_data->input_dev->name = PLATFORM_DRIVER_NAME;
- + rmi4_data->input_dev->phys = INPUT_PHYS_NAME;
- + rmi4_data->input_dev->id.product = SYNAPTICS_DSX_DRIVER_PRODUCT;
- + rmi4_data->input_dev->id.version = SYNAPTICS_DSX_DRIVER_VERSION;
- + rmi4_data->input_dev->dev.parent = rmi4_data->pdev->dev.parent;
- + rmi4_data->input_dev->event = synaptics_rmi4_input_event;
- + input_set_drvdata(rmi4_data->input_dev, rmi4_data);
- +
- + set_bit(EV_SYN, rmi4_data->input_dev->evbit);
- + set_bit(EV_KEY, rmi4_data->input_dev->evbit);
- + set_bit(EV_ABS, rmi4_data->input_dev->evbit);
- + set_bit(BTN_TOUCH, rmi4_data->input_dev->keybit);
- + set_bit(BTN_TOOL_FINGER, rmi4_data->input_dev->keybit);
- +#ifdef INPUT_PROP_DIRECT
- + set_bit(INPUT_PROP_DIRECT, rmi4_data->input_dev->propbit);
- +#endif
- +
- + if (bdata->max_y_for_2d >= 0)
- + rmi4_data->sensor_max_y = bdata->max_y_for_2d;
- +
- + synaptics_rmi4_set_params(rmi4_data);
- +
- + retval = input_register_device(rmi4_data->input_dev);
- + if (retval) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to register input device\n",
- + __func__);
- + goto err_register_input;
- + }
- +
- + if (!rmi4_data->stylus_enable)
- + return 0;
- +
- + rmi4_data->stylus_dev = input_allocate_device();
- + if (rmi4_data->stylus_dev == NULL) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to allocate stylus device\n",
- + __func__);
- + retval = -ENOMEM;
- + goto err_stylus_device;
- + }
- +
- + rmi4_data->stylus_dev->name = STYLUS_DRIVER_NAME;
- + rmi4_data->stylus_dev->phys = STYLUS_PHYS_NAME;
- + rmi4_data->stylus_dev->id.product = SYNAPTICS_DSX_DRIVER_PRODUCT;
- + rmi4_data->stylus_dev->id.version = SYNAPTICS_DSX_DRIVER_VERSION;
- + rmi4_data->stylus_dev->dev.parent = rmi4_data->pdev->dev.parent;
- + input_set_drvdata(rmi4_data->stylus_dev, rmi4_data);
- +
- + set_bit(EV_KEY, rmi4_data->stylus_dev->evbit);
- + set_bit(EV_ABS, rmi4_data->stylus_dev->evbit);
- + set_bit(BTN_TOUCH, rmi4_data->stylus_dev->keybit);
- + set_bit(BTN_TOOL_PEN, rmi4_data->stylus_dev->keybit);
- + if (rmi4_data->eraser_enable)
- + set_bit(BTN_TOOL_RUBBER, rmi4_data->stylus_dev->keybit);
- +#ifdef INPUT_PROP_DIRECT
- + set_bit(INPUT_PROP_DIRECT, rmi4_data->stylus_dev->propbit);
- +#endif
- +
- + input_set_abs_params(rmi4_data->stylus_dev, ABS_X, 0,
- + rmi4_data->sensor_max_x, 0, 0);
- + input_set_abs_params(rmi4_data->stylus_dev, ABS_Y, 0,
- + rmi4_data->sensor_max_y, 0, 0);
- +
- + retval = input_register_device(rmi4_data->stylus_dev);
- + if (retval) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to register stylus device\n",
- + __func__);
- + goto err_register_stylus;
- + }
- +
- + return 0;
- +
- +err_register_stylus:
- + rmi4_data->stylus_dev = NULL;
- +
- +err_stylus_device:
- + input_unregister_device(rmi4_data->input_dev);
- + rmi4_data->input_dev = NULL;
- +
- +err_register_input:
- +err_query_device:
- + synaptics_rmi4_empty_fn_list(rmi4_data);
- + input_free_device(rmi4_data->input_dev);
- +
- +err_input_device:
- + return retval;
- +}
- +
- +static int synaptics_rmi4_set_gpio(struct synaptics_rmi4_data *rmi4_data)
- +{
- + int retval;
- + const struct synaptics_dsx_board_data *bdata =
- + rmi4_data->hw_if->board_data;
- +
- + retval = synaptics_rmi4_gpio_setup(
- + bdata->irq_gpio,
- + true, 0, 0, bdata->irq_gpio_name);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to configure attention GPIO\n",
- + __func__);
- + goto err_gpio_irq;
- + }
- +
- + if (bdata->power_gpio >= 0) {
- + retval = synaptics_rmi4_gpio_setup(
- + bdata->power_gpio,
- + true, 1, !bdata->power_on_state, bdata->power_gpio_name);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to configure power GPIO\n",
- + __func__);
- + goto err_gpio_power;
- + }
- + }
- +
- + if (bdata->reset_gpio >= 0) {
- + retval = synaptics_rmi4_gpio_setup(
- + bdata->reset_gpio,
- + true, 1, !bdata->reset_on_state, bdata->reset_gpio_name);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to configure reset GPIO\n",
- + __func__);
- + goto err_gpio_reset;
- + }
- + }
- +
- + if (bdata->power_gpio >= 0) {
- + gpio_set_value(bdata->power_gpio, bdata->power_on_state);
- + msleep(bdata->power_delay_ms);
- + }
- +
- + if (bdata->reset_gpio >= 0) {
- + gpio_set_value(bdata->reset_gpio, bdata->reset_on_state);
- + msleep(bdata->reset_active_ms);
- + gpio_set_value(bdata->reset_gpio, !bdata->reset_on_state);
- + msleep(bdata->reset_delay_ms);
- + }
- +
- + return 0;
- +
- +err_gpio_reset:
- + if (bdata->power_gpio >= 0)
- + synaptics_rmi4_gpio_setup(bdata->power_gpio, false, 0, 0, NULL);
- +
- +err_gpio_power:
- + synaptics_rmi4_gpio_setup(bdata->irq_gpio, false, 0, 0, NULL);
- +
- +err_gpio_irq:
- + return retval;
- +}
- +
- +static int synaptics_rmi4_get_reg(struct synaptics_rmi4_data *rmi4_data,
- + bool get)
- +{
- + int retval;
- + const struct synaptics_dsx_board_data *bdata =
- + rmi4_data->hw_if->board_data;
- +
- + if (!get) {
- + retval = 0;
- + goto regulator_put;
- + }
- +
- + if ((bdata->pwr_reg_name != NULL) && (*bdata->pwr_reg_name != 0)) {
- + rmi4_data->pwr_reg = regulator_get(rmi4_data->pdev->dev.parent,
- + bdata->pwr_reg_name);
- + if (IS_ERR(rmi4_data->pwr_reg)) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to get power regulator\n",
- + __func__);
- + retval = PTR_ERR(rmi4_data->pwr_reg);
- + goto regulator_put;
- + }
- + }
- +
- + if ((bdata->lab_reg_name != NULL) && (*bdata->lab_reg_name != 0)) {
- + rmi4_data->lab_reg = regulator_get(rmi4_data->pdev->dev.parent,
- + bdata->lab_reg_name);
- + if (IS_ERR(rmi4_data->lab_reg)) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to get lab regulator\n",
- + __func__);
- + retval = PTR_ERR(rmi4_data->lab_reg);
- + goto regulator_put;
- + }
- + }
- +
- + if ((bdata->ibb_reg_name != NULL) && (*bdata->ibb_reg_name != 0)) {
- + rmi4_data->ibb_reg = regulator_get(rmi4_data->pdev->dev.parent,
- + bdata->ibb_reg_name);
- + if (IS_ERR(rmi4_data->ibb_reg)) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to get ibb regulator\n",
- + __func__);
- + retval = PTR_ERR(rmi4_data->ibb_reg);
- + goto regulator_put;
- + }
- + }
- +
- + if ((bdata->disp_reg_name != NULL) && (*bdata->disp_reg_name != 0)) {
- + rmi4_data->disp_reg = regulator_get(rmi4_data->pdev->dev.parent,
- + bdata->disp_reg_name);
- + if (IS_ERR(rmi4_data->disp_reg)) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to get vddio regulator\n",
- + __func__);
- + retval = PTR_ERR(rmi4_data->disp_reg);
- + goto regulator_put;
- + }
- + }
- +
- + if ((bdata->bus_reg_name != NULL) && (*bdata->bus_reg_name != 0)) {
- + rmi4_data->bus_reg = regulator_get(rmi4_data->pdev->dev.parent,
- + bdata->bus_reg_name);
- + if (IS_ERR(rmi4_data->bus_reg)) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to get bus pullup regulator\n",
- + __func__);
- + retval = PTR_ERR(rmi4_data->bus_reg);
- + goto regulator_put;
- + }
- + }
- +
- + return 0;
- +
- +regulator_put:
- + if (rmi4_data->pwr_reg) {
- + regulator_put(rmi4_data->pwr_reg);
- + rmi4_data->pwr_reg = NULL;
- + }
- +
- + if (rmi4_data->lab_reg) {
- + regulator_put(rmi4_data->lab_reg);
- + rmi4_data->lab_reg = NULL;
- + }
- + if (rmi4_data->ibb_reg) {
- + regulator_put(rmi4_data->ibb_reg);
- + rmi4_data->ibb_reg = NULL;
- + }
- + if (rmi4_data->disp_reg) {
- + regulator_put(rmi4_data->disp_reg);
- + rmi4_data->disp_reg = NULL;
- + }
- +
- + if (rmi4_data->bus_reg) {
- + regulator_put(rmi4_data->bus_reg);
- + rmi4_data->bus_reg = NULL;
- + }
- +
- + return retval;
- +}
- +
- +static int synaptics_rmi4_enable_reg(struct synaptics_rmi4_data *rmi4_data,
- + bool enable)
- +{
- + int retval;
- + const struct synaptics_dsx_board_data *bdata =
- + rmi4_data->hw_if->board_data;
- +
- + if (!enable) {
- + retval = 0;
- + goto disable_pwr_reg;
- + }
- +
- + if (rmi4_data->bus_reg) {
- + retval = regulator_enable(rmi4_data->bus_reg);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to enable bus pullup regulator\n",
- + __func__);
- + goto exit;
- + }
- + }
- +
- + if (rmi4_data->pwr_reg) {
- + retval = regulator_enable(rmi4_data->pwr_reg);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to enable power regulator\n",
- + __func__);
- + goto disable_bus_reg;
- + }
- + msleep(bdata->power_delay_ms);
- + }
- +
- + return 0;
- +
- +disable_pwr_reg:
- + if (rmi4_data->pwr_reg)
- + regulator_disable(rmi4_data->pwr_reg);
- +
- +disable_bus_reg:
- + if (rmi4_data->bus_reg)
- + regulator_disable(rmi4_data->bus_reg);
- +
- +exit:
- + return retval;
- +}
- +
- +static int synaptics_rmi4_free_fingers(struct synaptics_rmi4_data *rmi4_data)
- +{
- + unsigned char ii;
- +
- + mutex_lock(&(rmi4_data->rmi4_report_mutex));
- +
- +#ifdef TYPE_B_PROTOCOL
- + for (ii = 0; ii < rmi4_data->num_of_fingers; ii++) {
- + input_mt_slot(rmi4_data->input_dev, ii);
- + input_mt_report_slot_state(rmi4_data->input_dev,
- + MT_TOOL_FINGER, 0);
- + }
- +#endif
- + input_report_key(rmi4_data->input_dev,
- + BTN_TOUCH, 0);
- + input_report_key(rmi4_data->input_dev,
- + BTN_TOOL_FINGER, 0);
- +#ifndef TYPE_B_PROTOCOL
- + input_mt_sync(rmi4_data->input_dev);
- +#endif
- + input_sync(rmi4_data->input_dev);
- +
- + if (rmi4_data->stylus_enable) {
- + input_report_key(rmi4_data->stylus_dev,
- + BTN_TOUCH, 0);
- + input_report_key(rmi4_data->stylus_dev,
- + BTN_TOOL_PEN, 0);
- + if (rmi4_data->eraser_enable) {
- + input_report_key(rmi4_data->stylus_dev,
- + BTN_TOOL_RUBBER, 0);
- + }
- + input_sync(rmi4_data->stylus_dev);
- + }
- +
- + rmi4_data->touchs = 0;
- +
- + mutex_unlock(&(rmi4_data->rmi4_report_mutex));
- +
- + rmi4_data->fingers_on_2d = false;
- +
- + return 0;
- +}
- +
- +static int synaptics_rmi4_sw_reset(struct synaptics_rmi4_data *rmi4_data)
- +{
- + int retval;
- + unsigned char command = 0x01;
- +
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + rmi4_data->f01_cmd_base_addr,
- + &command,
- + sizeof(command));
- + if (retval < 0)
- + return retval;
- +
- + msleep(rmi4_data->hw_if->board_data->reset_delay_ms);
- +
- + if (rmi4_data->hw_if->ui_hw_init) {
- + retval = rmi4_data->hw_if->ui_hw_init(rmi4_data);
- + if (retval < 0)
- + return retval;
- + }
- +
- + return 0;
- +}
- +
- +static void synaptics_rmi4_rebuild_work(struct work_struct *work)
- +{
- + int retval;
- + unsigned char attr_count;
- + struct synaptics_rmi4_exp_fhandler *exp_fhandler;
- + struct delayed_work *delayed_work =
- + container_of(work, struct delayed_work, work);
- + struct synaptics_rmi4_data *rmi4_data =
- + container_of(delayed_work, struct synaptics_rmi4_data,
- + rb_work);
- +
- + mutex_lock(&(rmi4_data->rmi4_reset_mutex));
- +
- + mutex_lock(&exp_data.mutex);
- +
- + synaptics_rmi4_irq_enable(rmi4_data, false, false);
- +
- + if (!list_empty(&exp_data.list)) {
- + list_for_each_entry(exp_fhandler, &exp_data.list, link)
- + if (exp_fhandler->exp_fn->remove != NULL)
- + exp_fhandler->exp_fn->remove(rmi4_data);
- + }
- +
- + for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
- + sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
- + &attrs[attr_count].attr);
- + }
- +
- + synaptics_rmi4_free_fingers(rmi4_data);
- + synaptics_rmi4_empty_fn_list(rmi4_data);
- + input_unregister_device(rmi4_data->input_dev);
- + rmi4_data->input_dev = NULL;
- + if (rmi4_data->stylus_enable) {
- + input_unregister_device(rmi4_data->stylus_dev);
- + rmi4_data->stylus_dev = NULL;
- + }
- +
- + retval = synaptics_rmi4_sw_reset(rmi4_data);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to issue reset command\n",
- + __func__);
- + goto exit;
- + }
- +
- + retval = synaptics_rmi4_set_input_dev(rmi4_data);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to set up input device\n",
- + __func__);
- + goto exit;
- + }
- +
- + for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
- + retval = sysfs_create_file(&rmi4_data->input_dev->dev.kobj,
- + &attrs[attr_count].attr);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to create sysfs attributes\n",
- + __func__);
- + goto exit;
- + }
- + }
- +
- + if (!list_empty(&exp_data.list)) {
- + list_for_each_entry(exp_fhandler, &exp_data.list, link)
- + if (exp_fhandler->exp_fn->init != NULL)
- + exp_fhandler->exp_fn->init(rmi4_data);
- + }
- +
- + retval = 0;
- +
- +exit:
- + synaptics_rmi4_irq_enable(rmi4_data, true, false);
- +
- + mutex_unlock(&exp_data.mutex);
- +
- + mutex_unlock(&(rmi4_data->rmi4_reset_mutex));
- +
- + return;
- +}
- +
- +static int synaptics_rmi4_reinit_device(struct synaptics_rmi4_data *rmi4_data)
- +{
- + int retval;
- + struct synaptics_rmi4_fn *fhandler;
- + struct synaptics_rmi4_exp_fhandler *exp_fhandler;
- + struct synaptics_rmi4_device_info *rmi;
- +
- + rmi = &(rmi4_data->rmi4_mod_info);
- +
- + mutex_lock(&(rmi4_data->rmi4_reset_mutex));
- +
- + synaptics_rmi4_free_fingers(rmi4_data);
- +
- + if (!list_empty(&rmi->support_fn_list)) {
- + list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
- + if (fhandler->fn_number == SYNAPTICS_RMI4_F12) {
- + synaptics_rmi4_f12_set_enables(rmi4_data, 0);
- + break;
- + }
- + }
- + }
- +
- + retval = synaptics_rmi4_int_enable(rmi4_data, true);
- + if (retval < 0)
- + goto exit;
- +
- + mutex_lock(&exp_data.mutex);
- + if (!list_empty(&exp_data.list)) {
- + list_for_each_entry(exp_fhandler, &exp_data.list, link)
- + if (exp_fhandler->exp_fn->reinit != NULL)
- + exp_fhandler->exp_fn->reinit(rmi4_data);
- + }
- + mutex_unlock(&exp_data.mutex);
- +
- + synaptics_rmi4_set_configured(rmi4_data);
- +
- + retval = 0;
- +
- +exit:
- + mutex_unlock(&(rmi4_data->rmi4_reset_mutex));
- + return retval;
- +}
- +
- +static int synaptics_rmi4_reset_device(struct synaptics_rmi4_data *rmi4_data,
- + bool rebuild)
- +{
- + int retval;
- + struct synaptics_rmi4_exp_fhandler *exp_fhandler;
- +
- + if (rebuild) {
- + queue_delayed_work(rmi4_data->rb_workqueue,
- + &rmi4_data->rb_work,
- + msecs_to_jiffies(REBUILD_WORK_DELAY_MS));
- + return 0;
- + }
- +
- + mutex_lock(&(rmi4_data->rmi4_reset_mutex));
- +
- + synaptics_rmi4_irq_enable(rmi4_data, false, false);
- +
- + retval = synaptics_rmi4_sw_reset(rmi4_data);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to issue reset command\n",
- + __func__);
- + goto exit;
- + }
- +
- + synaptics_rmi4_free_fingers(rmi4_data);
- +
- + synaptics_rmi4_empty_fn_list(rmi4_data);
- +
- + retval = synaptics_rmi4_query_device(rmi4_data);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to query device\n",
- + __func__);
- + goto exit;
- + }
- +
- + mutex_lock(&exp_data.mutex);
- + if (!list_empty(&exp_data.list)) {
- + list_for_each_entry(exp_fhandler, &exp_data.list, link)
- + if (exp_fhandler->exp_fn->reset != NULL)
- + exp_fhandler->exp_fn->reset(rmi4_data);
- + }
- + mutex_unlock(&exp_data.mutex);
- +
- + retval = 0;
- +
- +exit:
- + synaptics_rmi4_irq_enable(rmi4_data, true, false);
- +
- + mutex_unlock(&(rmi4_data->rmi4_reset_mutex));
- +
- + return retval;
- +}
- +
- +#ifdef FB_READY_RESET
- +static void synaptics_rmi4_reset_work(struct work_struct *work)
- +{
- + int retval;
- + unsigned int timeout;
- + struct synaptics_rmi4_data *rmi4_data =
- + container_of(work, struct synaptics_rmi4_data,
- + reset_work);
- +
- + timeout = FB_READY_TIMEOUT_S * 1000 / FB_READY_WAIT_MS + 1;
- +
- + while (!rmi4_data->fb_ready) {
- + msleep(FB_READY_WAIT_MS);
- + timeout--;
- + if (timeout == 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Timed out waiting for FB ready\n",
- + __func__);
- + return;
- + }
- + }
- +
- + mutex_lock(&rmi4_data->rmi4_exp_init_mutex);
- +
- + retval = synaptics_rmi4_reset_device(rmi4_data, false);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to issue reset command\n",
- + __func__);
- + }
- +
- + mutex_unlock(&rmi4_data->rmi4_exp_init_mutex);
- +
- + return;
- +}
- +#endif
- +
- +static void synaptics_rmi4_sleep_enable(struct synaptics_rmi4_data *rmi4_data,
- + bool enable)
- +{
- + int retval;
- + unsigned char device_ctrl;
- + unsigned char no_sleep_setting = rmi4_data->no_sleep_setting;
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + rmi4_data->f01_ctrl_base_addr,
- + &device_ctrl,
- + sizeof(device_ctrl));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to read device control\n",
- + __func__);
- + return;
- + }
- +
- + device_ctrl = device_ctrl & ~MASK_3BIT;
- + if (enable)
- + device_ctrl = device_ctrl | NO_SLEEP_OFF | SENSOR_SLEEP;
- + else
- + device_ctrl = device_ctrl | no_sleep_setting | NORMAL_OPERATION;
- +
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + rmi4_data->f01_ctrl_base_addr,
- + &device_ctrl,
- + sizeof(device_ctrl));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to write device control\n",
- + __func__);
- + return;
- + }
- +
- + rmi4_data->sensor_sleep = enable;
- +
- + return;
- +}
- +
- +static void synaptics_rmi4_exp_fn_work(struct work_struct *work)
- +{
- + struct synaptics_rmi4_exp_fhandler *exp_fhandler;
- + struct synaptics_rmi4_exp_fhandler *exp_fhandler_temp;
- + struct synaptics_rmi4_data *rmi4_data = exp_data.rmi4_data;
- +
- + mutex_lock(&rmi4_data->rmi4_exp_init_mutex);
- + mutex_lock(&rmi4_data->rmi4_reset_mutex);
- + mutex_lock(&exp_data.mutex);
- + if (!list_empty(&exp_data.list)) {
- + list_for_each_entry_safe(exp_fhandler,
- + exp_fhandler_temp,
- + &exp_data.list,
- + link) {
- + if ((exp_fhandler->exp_fn->init != NULL) &&
- + exp_fhandler->insert) {
- + exp_fhandler->exp_fn->init(rmi4_data);
- + exp_fhandler->insert = false;
- + } else if ((exp_fhandler->exp_fn->remove != NULL) &&
- + exp_fhandler->remove) {
- + exp_fhandler->exp_fn->remove(rmi4_data);
- + list_del(&exp_fhandler->link);
- + kfree(exp_fhandler);
- + }
- + }
- + }
- + mutex_unlock(&exp_data.mutex);
- + mutex_unlock(&rmi4_data->rmi4_reset_mutex);
- + mutex_unlock(&rmi4_data->rmi4_exp_init_mutex);
- +
- + return;
- +}
- +
- +void synaptics_rmi4_new_function_force(struct synaptics_rmi4_exp_fn *exp_fn,
- + bool insert)
- +{
- + struct synaptics_rmi4_exp_fhandler *exp_fhandler;
- +
- + if (!exp_data.initialized) {
- + mutex_init(&exp_data.mutex);
- + INIT_LIST_HEAD(&exp_data.list);
- + exp_data.initialized = true;
- + }
- +
- + mutex_lock(&exp_data.mutex);
- + if (insert) {
- + exp_fhandler = kzalloc(sizeof(*exp_fhandler), GFP_KERNEL);
- + if (!exp_fhandler) {
- + pr_err("%s: Failed to alloc mem for expansion function\n",
- + __func__);
- + goto exit;
- + }
- + exp_fhandler->exp_fn = exp_fn;
- + exp_fhandler->insert = true;
- + exp_fhandler->remove = false;
- + list_add_tail(&exp_fhandler->link, &exp_data.list);
- + } else if (!list_empty(&exp_data.list)) {
- + list_for_each_entry(exp_fhandler, &exp_data.list, link) {
- + if (exp_fhandler->exp_fn->fn_type == exp_fn->fn_type) {
- + exp_fhandler->insert = false;
- + exp_fhandler->remove = true;
- + goto exit;
- + }
- + }
- + }
- +
- +exit:
- + mutex_unlock(&exp_data.mutex);
- +
- + if (exp_data.queue_work) {
- + queue_delayed_work(exp_data.workqueue,
- + &exp_data.work,
- + msecs_to_jiffies(EXP_FN_WORK_DELAY_MS));
- + }
- +
- + return;
- +}
- +
- +#ifdef CONFIG_TOUCH_DEBUG_FS
- +static int synaptics_tpdbg_suspend(struct synaptics_rmi4_data *rmi4_data)
- +{
- + struct synaptics_rmi4_exp_fhandler *exp_fhandler;
- +
- + synaptics_rmi4_irq_enable(rmi4_data, false, false);
- + if (!rmi4_data->enable_wakeup_gesture)
- + synaptics_rmi4_sleep_enable(rmi4_data, true);
- +
- + if (rmi4_data->enable_wakeup_gesture) {
- + msleep(300);
- + synaptics_rmi4_wakeup_gesture(rmi4_data, true);
- + synaptics_rmi4_irq_enable(rmi4_data, true, false);
- + goto exit;
- + }
- +
- + mutex_lock(&exp_data.mutex);
- + if (!list_empty(&exp_data.list)) {
- + list_for_each_entry(exp_fhandler, &exp_data.list, link)
- + if (exp_fhandler->exp_fn->suspend != NULL)
- + exp_fhandler->exp_fn->suspend(rmi4_data);
- + }
- + mutex_unlock(&exp_data.mutex);
- +
- +exit:
- + return 0;
- +}
- +
- +static int synaptics_tpdbg_resume(struct synaptics_rmi4_data *rmi4_data)
- +{
- + struct synaptics_rmi4_exp_fhandler *exp_fhandler;
- + const struct synaptics_dsx_board_data *bdata =
- + rmi4_data->hw_if->board_data;
- +
- + if (rmi4_data->enable_wakeup_gesture) {
- + synaptics_rmi4_wakeup_gesture(rmi4_data, false);
- + if (bdata->reset_gpio >= 0) {
- + gpio_set_value(bdata->reset_gpio, bdata->reset_on_state);
- + msleep(bdata->reset_active_ms);
- + gpio_set_value(bdata->reset_gpio, !bdata->reset_on_state);
- + msleep(bdata->reset_delay_ms);
- + }
- + } else {
- + rmi4_data->current_page = MASK_8BIT;
- + if (bdata->reset_gpio >= 0) {
- + gpio_set_value(bdata->reset_gpio, bdata->reset_on_state);
- + msleep(bdata->reset_active_ms);
- + gpio_set_value(bdata->reset_gpio, !bdata->reset_on_state);
- + msleep(bdata->reset_delay_ms);
- + }
- +
- + synaptics_rmi4_sleep_enable(rmi4_data, false);
- + synaptics_rmi4_irq_enable(rmi4_data, true, false);
- +
- + mutex_lock(&exp_data.mutex);
- + if (!list_empty(&exp_data.list)) {
- + list_for_each_entry(exp_fhandler, &exp_data.list, link)
- + if (exp_fhandler->exp_fn->resume != NULL)
- + exp_fhandler->exp_fn->resume(rmi4_data);
- + }
- + mutex_unlock(&exp_data.mutex);
- + }
- +
- + return 0;
- +}
- +
- +static void tpdbg_shutdown(struct synaptics_rmi4_data *rmi4_data, bool sleep)
- +{
- + synaptics_rmi4_sleep_enable(rmi4_data, sleep);
- +}
- +
- +static void tpdbg_suspend(struct synaptics_rmi4_data *rmi4_data, bool enable)
- +{
- + if (enable)
- + synaptics_tpdbg_suspend(rmi4_data);
- + else
- + synaptics_tpdbg_resume(rmi4_data);
- +}
- +
- +static int tpdbg_open(struct inode *inode, struct file *file)
- +{
- + file->private_data = inode->i_private;
- +
- + return 0;
- +}
- +
- +ssize_t tpdbg_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
- +{
- + const char *str = "cmd support as below:\n \
- + \necho \"irq-disable\" or \"irq-enable\" to ctrl irq\n \
- + \necho \"tp-sd-en\" of \"tp-sd-off\" to ctrl panel in or off sleep mode\n \
- + \necho \"tp-suspend-en\" or \"tp-suspend-off\" to ctrl panel in or off suspend status\n";
- +
- + loff_t pos = *ppos;
- + int len = strlen(str);
- +
- + if (pos < 0)
- + return -EINVAL;
- + if (pos >= len)
- + return 0;
- +
- + if (copy_to_user(buf, str, len))
- + return -EFAULT;
- +
- + *ppos = pos + len;
- +
- + return len;
- +}
- +
- +ssize_t tpdbg_write(struct file *file, const char __user *buf, size_t size, loff_t *ppos)
- +{
- + struct synaptics_rmi4_data *rmi4_data = file->private_data;
- + char *cmd = kzalloc(size + 1, GFP_KERNEL);
- + int ret = size;
- +
- + if (!cmd)
- + return -ENOMEM;
- +
- + if (copy_from_user(cmd, buf, size)) {
- + ret = -EFAULT;
- + goto out;
- + }
- +
- + cmd[size] = '\0';
- +
- + if (!strncmp(cmd, "irq-disable", 11))
- + disable_irq(rmi4_data->irq);
- + else if (!strncmp(cmd, "irq-enable", 10))
- + enable_irq(rmi4_data->irq);
- + else if (!strncmp(cmd, "tp-sd-en", 8))
- + tpdbg_shutdown(rmi4_data, true);
- + else if (!strncmp(cmd, "tp-sd-off", 9))
- + tpdbg_shutdown(rmi4_data, false);
- + else if (!strncmp(cmd, "tp-suspend-en", 13))
- + tpdbg_suspend(rmi4_data, true);
- + else if (!strncmp(cmd, "tp-suspend-off", 14))
- + tpdbg_suspend(rmi4_data, false);
- +out:
- + kfree(cmd);
- +
- + return ret;
- +}
- +
- +int tpdbg_release (struct inode *inode, struct file *file)
- +{
- + file->private_data = NULL;
- +
- + return 0;
- +}
- +
- +static const struct file_operations tpdbg_operations = {
- + .owner = THIS_MODULE,
- + .open = tpdbg_open,
- + .read = tpdbg_read,
- + .write = tpdbg_write,
- + .release = tpdbg_release,
- +};
- +#endif
- +
- +extern unsigned int get_hw_version_major(void);
- +
- +static int synaptics_rmi4_probe(struct platform_device *pdev)
- +{
- + int retval;
- + unsigned char attr_count;
- + struct synaptics_rmi4_data *rmi4_data;
- + const struct synaptics_dsx_hw_interface *hw_if;
- + const struct synaptics_dsx_board_data *bdata;
- +
- + hw_if = pdev->dev.platform_data;
- + if (!hw_if) {
- + dev_err(&pdev->dev,
- + "%s: No hardware interface found\n",
- + __func__);
- + return -EINVAL;
- + }
- +
- + bdata = hw_if->board_data;
- + if (!bdata) {
- + dev_err(&pdev->dev,
- + "%s: No board data found\n",
- + __func__);
- + return -EINVAL;
- + }
- +
- + rmi4_data = kzalloc(sizeof(*rmi4_data), GFP_KERNEL);
- + if (!rmi4_data) {
- + dev_err(&pdev->dev,
- + "%s: Failed to alloc mem for rmi4_data\n",
- + __func__);
- + return -ENOMEM;
- + }
- +
- + rmi4_data->pdev = pdev;
- + rmi4_data->current_page = MASK_8BIT;
- + rmi4_data->hw_if = hw_if;
- + rmi4_data->suspend = false;
- + rmi4_data->irq_enabled = false;
- + rmi4_data->fingers_on_2d = false;
- + rmi4_data->wakeup_en = false;
- +
- + rmi4_data->reset_device = synaptics_rmi4_reset_device;
- + rmi4_data->irq_enable = synaptics_rmi4_irq_enable;
- + rmi4_data->sleep_enable = synaptics_rmi4_sleep_enable;
- +// rmi4_data->hw_version = get_hw_version_major();
- +
- + mutex_init(&(rmi4_data->rmi4_reset_mutex));
- + mutex_init(&(rmi4_data->rmi4_report_mutex));
- + mutex_init(&(rmi4_data->rmi4_io_ctrl_mutex));
- + mutex_init(&(rmi4_data->rmi4_exp_init_mutex));
- + mutex_init(&(rmi4_data->rmi4_irq_enable_mutex));
- + mutex_init(&(rmi4_data->rmi4_cover_mutex));
- +
- + init_completion(&rmi4_data->dump_completion);
- +
- + platform_set_drvdata(pdev, rmi4_data);
- +
- + vir_button_map = bdata->vir_button_map;
- +
- + retval = synaptics_rmi4_get_reg(rmi4_data, true);
- + if (retval < 0) {
- + dev_err(&pdev->dev,
- + "%s: Failed to get regulators\n",
- + __func__);
- + goto err_get_reg;
- + }
- +
- + retval = synaptics_rmi4_enable_reg(rmi4_data, true);
- + if (retval < 0) {
- + dev_err(&pdev->dev,
- + "%s: Failed to enable regulators\n",
- + __func__);
- + goto err_enable_reg;
- + }
- +
- + retval = synaptics_rmi4_set_gpio(rmi4_data);
- + if (retval < 0) {
- + dev_err(&pdev->dev,
- + "%s: Failed to set up GPIO's\n",
- + __func__);
- + goto err_set_gpio;
- + }
- +
- + retval = synaptics_rmi4_pinctrl_init(rmi4_data);
- + if (!retval && rmi4_data->ts_pinctrl) {
- + retval = pinctrl_select_state(rmi4_data->ts_pinctrl,
- + rmi4_data->pinctrl_state_active);
- + if (retval < 0) {
- + dev_err(&pdev->dev,
- + "%s: Failed to select %s pinstate %d\n",
- + __func__, PINCTRL_STATE_ACTIVE, retval);
- + goto err_pinctrl_init;
- + }
- + } else {
- + dev_err(&pdev->dev,
- + "%s: Failed to init pinctrl\n",
- + __func__);
- + goto err_pinctrl_init;
- + }
- +
- + if (hw_if->ui_hw_init) {
- + retval = hw_if->ui_hw_init(rmi4_data);
- + if (retval < 0) {
- + dev_err(&pdev->dev,
- + "%s: Failed to initialize hardware interface\n",
- + __func__);
- + goto err_ui_hw_init;
- + }
- + }
- +
- + retval = synaptics_rmi4_set_input_dev(rmi4_data);
- + if (retval < 0) {
- + dev_err(&pdev->dev,
- + "%s: Failed to set up input device\n",
- + __func__);
- + goto err_set_input_dev;
- + }
- +
- + synaptics_rmi4_query_chip_id(rmi4_data);
- +
- +#ifdef CONFIG_FB
- + if (!rmi4_data->chip_is_tddi)
- + rmi4_data->fb_notifier.notifier_call = synaptics_rmi4_fb_notifier_cb;
- + else
- + rmi4_data->fb_notifier.notifier_call = synaptics_rmi4_fb_notifier_cb_tddi;
- + retval = fb_register_client(&rmi4_data->fb_notifier);
- + if (retval < 0) {
- + dev_err(&pdev->dev,
- + "%s: Failed to register fb notifier client\n",
- + __func__);
- + }
- +#endif
- +
- +#ifdef USE_EARLYSUSPEND
- + rmi4_data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
- + rmi4_data->early_suspend.suspend = synaptics_rmi4_early_suspend;
- + rmi4_data->early_suspend.resume = synaptics_rmi4_late_resume;
- + register_early_suspend(&rmi4_data->early_suspend);
- +#endif
- +
- + if (!exp_data.initialized) {
- + mutex_init(&exp_data.mutex);
- + INIT_LIST_HEAD(&exp_data.list);
- + exp_data.initialized = true;
- + }
- +
- + rmi4_data->irq = gpio_to_irq(bdata->irq_gpio);
- +
- + retval = synaptics_rmi4_irq_enable(rmi4_data, true, false);
- + if (retval < 0) {
- + dev_err(&pdev->dev,
- + "%s: Failed to enable attention interrupt\n",
- + __func__);
- + goto err_enable_irq;
- + }
- +
- + if (vir_button_map->nbuttons) {
- + rmi4_data->board_prop_dir = kobject_create_and_add(
- + "board_properties", NULL);
- + if (!rmi4_data->board_prop_dir) {
- + dev_err(&pdev->dev,
- + "%s: Failed to create board_properties directory\n",
- + __func__);
- + goto err_virtual_buttons;
- + } else {
- + retval = sysfs_create_file(rmi4_data->board_prop_dir,
- + &virtual_key_map_attr.attr);
- + if (retval < 0) {
- + dev_err(&pdev->dev,
- + "%s: Failed to create virtual key map file\n",
- + __func__);
- + goto err_virtual_buttons;
- + }
- + }
- + }
- +
- + for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
- + retval = sysfs_create_file(&rmi4_data->input_dev->dev.kobj,
- + &attrs[attr_count].attr);
- + if (retval < 0) {
- + dev_err(&pdev->dev,
- + "%s: Failed to create sysfs attributes\n",
- + __func__);
- + goto err_sysfs;
- + }
- + }
- +
- + retval = sysfs_create_file(&rmi4_data->pdev->dev.parent->kobj, &dev_attr_panel_color.attr);
- +
- + if (retval < 0) {
- + dev_err(&pdev->dev,
- + "%s: Failed to create sysfs attributes\n",
- + __func__);
- + goto err_sysfs;
- + }
- +
- +#if defined(CONFIG_SECURE_TOUCH)
- + retval = sysfs_create_file(&rmi4_data->pdev->dev.parent->kobj, &dev_attr_secure_touch.attr);
- +
- + if (retval < 0) {
- + dev_err(&pdev->dev,
- + "%s: Failed to create sysfs attributes\n",
- + __func__);
- + goto err_sysfs_secure;
- + }
- +
- + retval = sysfs_create_file(&rmi4_data->pdev->dev.parent->kobj, &dev_attr_secure_touch_enable.attr);
- +
- + if (retval < 0) {
- + dev_err(&pdev->dev,
- + "%s: Failed to create sysfs attributes\n",
- + __func__);
- + goto err_sysfs_secure_enable;
- + }
- +#endif
- +
- + retval = sysfs_create_file(&rmi4_data->pdev->dev.parent->kobj, &dev_attr_panel_vendor.attr);
- +
- + if (retval < 0) {
- + dev_err(&pdev->dev,
- + "%s: Failed to create sysfs attributes\n",
- + __func__);
- + goto err_sysfs_panel_vendor;
- + }
- +
- +#ifdef CONFIG_TOUCH_DEBUG_FS
- + rmi4_data->debugfs = debugfs_create_dir("tp_debug", NULL);
- + if (rmi4_data->debugfs) {
- + debugfs_create_file("switch_state", 0660, rmi4_data->debugfs, rmi4_data, &tpdbg_operations);
- + }
- +#endif
- +
- + dev_set_drvdata(rmi4_data->pdev->dev.parent, rmi4_data);
- +
- + rmi4_data->rb_workqueue =
- + create_singlethread_workqueue("dsx_rebuild_workqueue");
- + INIT_DELAYED_WORK(&rmi4_data->rb_work, synaptics_rmi4_rebuild_work);
- +
- + exp_data.workqueue = create_singlethread_workqueue("dsx_exp_workqueue");
- + INIT_DELAYED_WORK(&exp_data.work, synaptics_rmi4_exp_fn_work);
- + exp_data.rmi4_data = rmi4_data;
- + exp_data.queue_work = true;
- + queue_delayed_work(exp_data.workqueue,
- + &exp_data.work,
- + 0);
- +
- +#ifdef FB_READY_RESET
- + rmi4_data->reset_workqueue =
- + create_singlethread_workqueue("dsx_reset_workqueue");
- + INIT_WORK(&rmi4_data->reset_work, synaptics_rmi4_reset_work);
- + queue_work(rmi4_data->reset_workqueue, &rmi4_data->reset_work);
- +#endif
- +
- + device_init_wakeup(&pdev->dev, 1);
- +
- + synaptics_secure_touch_init(rmi4_data);
- + synaptics_secure_touch_stop(rmi4_data, 1);
- +
- + return retval;
- +
- +
- +err_sysfs_panel_vendor:
- +#if defined(CONFIG_SECURE_TOUCH)
- + sysfs_remove_file(&rmi4_data->pdev->dev.parent->kobj, &dev_attr_secure_touch_enable.attr);
- +err_sysfs_secure_enable:
- + sysfs_remove_file(&rmi4_data->pdev->dev.parent->kobj, &dev_attr_secure_touch.attr);
- +err_sysfs_secure:
- + sysfs_remove_file(&rmi4_data->pdev->dev.parent->kobj, &dev_attr_panel_color.attr);
- +#endif
- +err_sysfs:
- + for (attr_count--; attr_count >= 0; attr_count--) {
- + sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
- + &attrs[attr_count].attr);
- + }
- +
- +err_virtual_buttons:
- + if (rmi4_data->board_prop_dir) {
- + sysfs_remove_file(rmi4_data->board_prop_dir,
- + &virtual_key_map_attr.attr);
- + kobject_put(rmi4_data->board_prop_dir);
- + }
- +
- + synaptics_rmi4_irq_enable(rmi4_data, false, false);
- +
- +err_enable_irq:
- +#ifdef CONFIG_FB
- + fb_unregister_client(&rmi4_data->fb_notifier);
- +#endif
- +
- +#ifdef USE_EARLYSUSPEND
- + unregister_early_suspend(&rmi4_data->early_suspend);
- +#endif
- +
- + synaptics_rmi4_empty_fn_list(rmi4_data);
- + input_unregister_device(rmi4_data->input_dev);
- + rmi4_data->input_dev = NULL;
- + if (rmi4_data->stylus_enable) {
- + input_unregister_device(rmi4_data->stylus_dev);
- + rmi4_data->stylus_dev = NULL;
- + }
- +
- +err_set_input_dev:
- + synaptics_rmi4_gpio_setup(bdata->irq_gpio, false, 0, 0, NULL);
- +
- + if (bdata->reset_gpio >= 0)
- + synaptics_rmi4_gpio_setup(bdata->reset_gpio, false, 0, 0, NULL);
- +
- + if (bdata->power_gpio >= 0)
- + synaptics_rmi4_gpio_setup(bdata->power_gpio, false, 0, 0, NULL);
- +
- +err_ui_hw_init:
- +err_pinctrl_init:
- + if (rmi4_data->ts_pinctrl) {
- + devm_pinctrl_put(rmi4_data->ts_pinctrl);
- + rmi4_data->ts_pinctrl = NULL;
- + }
- +
- +err_set_gpio:
- + synaptics_rmi4_enable_reg(rmi4_data, false);
- +
- +err_enable_reg:
- + synaptics_rmi4_get_reg(rmi4_data, false);
- +
- +err_get_reg:
- + kfree(rmi4_data);
- +
- + return retval;
- +}
- +
- +static int synaptics_rmi4_remove(struct platform_device *pdev)
- +{
- + unsigned char attr_count;
- + struct synaptics_rmi4_data *rmi4_data = platform_get_drvdata(pdev);
- + const struct synaptics_dsx_board_data *bdata =
- + rmi4_data->hw_if->board_data;
- +
- +#ifdef FB_READY_RESET
- + cancel_work_sync(&rmi4_data->reset_work);
- + flush_workqueue(rmi4_data->reset_workqueue);
- + destroy_workqueue(rmi4_data->reset_workqueue);
- +#endif
- +
- + cancel_delayed_work_sync(&exp_data.work);
- + flush_workqueue(exp_data.workqueue);
- + destroy_workqueue(exp_data.workqueue);
- +
- + cancel_delayed_work_sync(&rmi4_data->rb_work);
- + flush_workqueue(rmi4_data->rb_workqueue);
- + destroy_workqueue(rmi4_data->rb_workqueue);
- +
- +#ifdef CONFIG_TOUCH_DEBUG_FS
- + debugfs_remove_recursive(rmi4_data->debugfs);
- +#endif
- +
- + sysfs_remove_file(&rmi4_data->pdev->dev.parent->kobj, &dev_attr_panel_vendor.attr);
- +#if defined(CONFIG_SECURE_TOUCH)
- + sysfs_remove_file(&rmi4_data->pdev->dev.parent->kobj, &dev_attr_secure_touch_enable.attr);
- + sysfs_remove_file(&rmi4_data->pdev->dev.parent->kobj, &dev_attr_secure_touch.attr);
- +#endif
- + sysfs_remove_file(&rmi4_data->pdev->dev.parent->kobj, &dev_attr_panel_color.attr);
- +
- + for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
- + sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
- + &attrs[attr_count].attr);
- + }
- +
- + if (rmi4_data->board_prop_dir) {
- + sysfs_remove_file(rmi4_data->board_prop_dir,
- + &virtual_key_map_attr.attr);
- + kobject_put(rmi4_data->board_prop_dir);
- + }
- +
- + synaptics_rmi4_irq_enable(rmi4_data, false, false);
- +
- +#ifdef CONFIG_FB
- + fb_unregister_client(&rmi4_data->fb_notifier);
- +#endif
- +
- +#ifdef USE_EARLYSUSPEND
- + unregister_early_suspend(&rmi4_data->early_suspend);
- +#endif
- +
- + synaptics_rmi4_empty_fn_list(rmi4_data);
- + input_unregister_device(rmi4_data->input_dev);
- + rmi4_data->input_dev = NULL;
- + if (rmi4_data->stylus_enable) {
- + input_unregister_device(rmi4_data->stylus_dev);
- + rmi4_data->stylus_dev = NULL;
- + }
- +
- + synaptics_rmi4_gpio_setup(bdata->irq_gpio, false, 0, 0, NULL);
- +
- + if (bdata->reset_gpio >= 0)
- + synaptics_rmi4_gpio_setup(bdata->reset_gpio, false, 0, 0, NULL);
- +
- + if (bdata->power_gpio >= 0)
- + synaptics_rmi4_gpio_setup(bdata->power_gpio, false, 0, 0, NULL);
- +
- + synaptics_rmi4_enable_reg(rmi4_data, false);
- + synaptics_rmi4_get_reg(rmi4_data, false);
- +
- + kfree(rmi4_data);
- +
- + return 0;
- +}
- +
- +static void synaptics_rmi4_f11_wg(struct synaptics_rmi4_data *rmi4_data,
- + bool enable)
- +{
- + int retval;
- + unsigned char reporting_control;
- + struct synaptics_rmi4_fn *fhandler;
- + struct synaptics_rmi4_device_info *rmi;
- +
- + rmi = &(rmi4_data->rmi4_mod_info);
- +
- + list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
- + if (fhandler->fn_number == SYNAPTICS_RMI4_F11)
- + break;
- + }
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + fhandler->full_addr.ctrl_base,
- + &reporting_control,
- + sizeof(reporting_control));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to change reporting mode\n",
- + __func__);
- + return;
- + }
- +
- + reporting_control = (reporting_control & ~MASK_3BIT);
- + if (enable)
- + reporting_control |= F11_WAKEUP_GESTURE_MODE;
- + else
- + reporting_control |= F11_CONTINUOUS_MODE;
- +
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + fhandler->full_addr.ctrl_base,
- + &reporting_control,
- + sizeof(reporting_control));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to change reporting mode\n",
- + __func__);
- + return;
- + }
- +
- + return;
- +}
- +
- +static void mdss_regulator_ctrl(struct synaptics_rmi4_data *rmi4_data, unsigned int flag, bool enable)
- +{
- + int retval = 0;
- + static unsigned int status = 0;
- +
- + if (rmi4_data == NULL)
- + return;
- + if (!rmi4_data->hw_if->board_data->panel_is_incell)
- + return;
- +
- + if (enable) {
- + if (rmi4_data->disp_reg && (flag & DISP_REG_VDD) && !(status & DISP_REG_VDD)) {
- + retval = regulator_enable(rmi4_data->disp_reg);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to enable disp regulator\n",
- + __func__);
- + return;
- + }
- +
- + status |= DISP_REG_VDD;
- + }
- +
- + if (rmi4_data->lab_reg && (flag & DISP_REG_LAB) && !(status & DISP_REG_LAB)) {
- + retval = regulator_enable(rmi4_data->lab_reg);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to enable lab regulator\n",
- + __func__);
- + return;
- + }
- +
- + status |= DISP_REG_LAB;
- + }
- +
- + if (rmi4_data->ibb_reg && (flag & DISP_REG_IBB) && !(status & DISP_REG_IBB)) {
- + retval = regulator_enable(rmi4_data->ibb_reg);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to enable ibb regulator\n",
- + __func__);
- + return;
- + }
- +
- + status |= DISP_REG_IBB;
- + }
- + } else {
- + if (rmi4_data->ibb_reg && (flag & DISP_REG_IBB) && (status & DISP_REG_IBB)) {
- + retval = regulator_disable(rmi4_data->ibb_reg);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to disable ibb regulator\n",
- + __func__);
- + return;
- + }
- +
- + status &= ~DISP_REG_IBB;
- + }
- +
- + if (rmi4_data->lab_reg && (flag & DISP_REG_LAB) && (status & DISP_REG_LAB)) {
- + retval = regulator_disable(rmi4_data->lab_reg);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to disable lab regulator\n",
- + __func__);
- + return;
- + }
- +
- + status &= ~DISP_REG_LAB;
- + }
- +
- + if (rmi4_data->disp_reg && (flag & DISP_REG_VDD) && (status & DISP_REG_VDD)) {
- + retval = regulator_disable(rmi4_data->disp_reg);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to disable disp regulator\n",
- + __func__);
- + return;
- + }
- +
- + status &= ~DISP_REG_VDD;
- + }
- + }
- +}
- +
- +static void mdss_reset_ctrl(const struct synaptics_dsx_board_data *bdata, bool on)
- +{
- + if (!bdata->panel_is_incell)
- + return;
- +
- + if (bdata->mdss_reset > 0) {
- + if (on)
- + gpio_set_value(bdata->mdss_reset, bdata->mdss_reset_state);
- + else
- + gpio_set_value(bdata->mdss_reset, !bdata->mdss_reset_state);
- + }
- +}
- +
- +#if 0
- +static void mdss_panel_poweron(struct synaptics_rmi4_data *rmi4_data, bool enable)
- +{
- + if (!rmi4_data->hw_if->board_data->panel_is_incell)
- + return;
- +
- + if (enable) {
- +#if 0
- + /*disp regulator always on, so do not control this regulator*/
- + if (rmi4_data->panel_power_seq.disp_pre_on_sleep)
- + msleep(rmi4_data->panel_power_seq.disp_pre_on_sleep);
- + mdss_regulator_ctrl(rmi4_data, DISP_REG_VDD, true);
- + if (rmi4_data->panel_power_seq.disp_post_on_sleep)
- + msleep(rmi4_data->panel_power_seq.disp_post_on_sleep);
- +#endif
- + if (rmi4_data->panel_power_seq.lab_pre_on_sleep)
- + msleep(rmi4_data->panel_power_seq.lab_pre_on_sleep);
- + mdss_regulator_ctrl(rmi4_data, DISP_REG_LAB, true);
- + if (rmi4_data->panel_power_seq.lab_post_on_sleep)
- + msleep(rmi4_data->panel_power_seq.lab_post_on_sleep);
- +
- + if (rmi4_data->panel_power_seq.ibb_pre_on_sleep)
- + msleep(rmi4_data->panel_power_seq.ibb_pre_on_sleep);
- + mdss_regulator_ctrl(rmi4_data, DISP_REG_IBB, true);
- + if (rmi4_data->panel_power_seq.ibb_post_on_sleep)
- + msleep(rmi4_data->panel_power_seq.ibb_post_on_sleep);
- + } else {
- + if (rmi4_data->panel_power_seq.ibb_pre_off_sleep)
- + msleep(rmi4_data->panel_power_seq.ibb_pre_off_sleep);
- + mdss_regulator_ctrl(rmi4_data, DISP_REG_IBB, false);
- + if (rmi4_data->panel_power_seq.ibb_post_off_sleep)
- + msleep(rmi4_data->panel_power_seq.ibb_post_off_sleep);
- +
- + if (rmi4_data->panel_power_seq.lab_pre_off_sleep)
- + msleep(rmi4_data->panel_power_seq.lab_pre_off_sleep);
- + mdss_regulator_ctrl(rmi4_data, DISP_REG_LAB, false);
- + if (rmi4_data->panel_power_seq.lab_post_off_sleep)
- + msleep(rmi4_data->panel_power_seq.lab_post_off_sleep);
- +#if 0
- + /*disp regulator always on, so do not control this regulator*/
- + if (rmi4_data->panel_power_seq.disp_pre_off_sleep)
- + msleep(rmi4_data->panel_power_seq.disp_pre_off_sleep);
- + mdss_regulator_ctrl(rmi4_data, DISP_REG_VDD, false);
- + if (rmi4_data->panel_power_seq.disp_post_off_sleep)
- + msleep(rmi4_data->panel_power_seq.disp_post_off_sleep);
- +#endif
- + }
- + pr_debug("power %s seq:\n", enable ? "on" : "off");
- +#if 0
- + /*disp regulator always on, so do not control this regulator*/
- + pr_debug("IOVDD: preonsleep=%d,postonsleep=%d,preoffsleep=%d,postoffsleep=%d\n",
- + rmi4_data->panel_power_seq.disp_pre_on_sleep,
- + rmi4_data->panel_power_seq.disp_post_on_sleep,
- + rmi4_data->panel_power_seq.disp_pre_off_sleep,
- + rmi4_data->panel_power_seq.disp_post_off_sleep);
- +#endif
- + pr_debug("LAB: preonsleep=%d,postonsleep=%d,preoffsleep=%d,postoffsleep=%d\n",
- + rmi4_data->panel_power_seq.lab_pre_on_sleep,
- + rmi4_data->panel_power_seq.lab_post_on_sleep,
- + rmi4_data->panel_power_seq.lab_pre_off_sleep,
- + rmi4_data->panel_power_seq.lab_post_off_sleep);
- + pr_debug("IBB: preonsleep=%d,postonsleep=%d,preoffsleep=%d,postoffsleep=%d\n",
- + rmi4_data->panel_power_seq.ibb_pre_on_sleep,
- + rmi4_data->panel_power_seq.ibb_post_on_sleep,
- + rmi4_data->panel_power_seq.ibb_pre_off_sleep,
- + rmi4_data->panel_power_seq.ibb_post_off_sleep);
- +}
- +#endif
- +
- +static void mdss_reset_action(const struct synaptics_dsx_board_data *bdata)
- +{
- + if (bdata->mdss_reset > 0) {
- + gpio_set_value(bdata->mdss_reset, !bdata->mdss_reset_state);
- + msleep(10);
- + gpio_set_value(bdata->mdss_reset, bdata->mdss_reset_state);
- + msleep(10);
- + }
- +}
- +
- +static void synaptics_rmi4_f12_wg(struct synaptics_rmi4_data *rmi4_data,
- + bool enable)
- +{
- + int retval;
- + unsigned char offset;
- + unsigned char reporting_control[3];
- + struct synaptics_rmi4_f12_extra_data *extra_data;
- + struct synaptics_rmi4_fn *fhandler;
- + struct synaptics_rmi4_device_info *rmi;
- +
- + rmi = &(rmi4_data->rmi4_mod_info);
- +
- + list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
- + if (fhandler->fn_number == SYNAPTICS_RMI4_F12)
- + break;
- + }
- +
- + extra_data = (struct synaptics_rmi4_f12_extra_data *)fhandler->extra;
- + offset = extra_data->ctrl20_offset;
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + fhandler->full_addr.ctrl_base + offset,
- + reporting_control,
- + sizeof(reporting_control));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to change reporting mode\n",
- + __func__);
- + return;
- + }
- +
- + if (enable)
- + reporting_control[2] = F12_WAKEUP_GESTURE_MODE;
- + else
- + reporting_control[2] = F12_CONTINUOUS_MODE;
- +
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + fhandler->full_addr.ctrl_base + offset,
- + reporting_control,
- + sizeof(reporting_control));
- +
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to change reporting mode\n",
- + __func__);
- + return;
- + }
- +
- + return;
- +}
- +
- +static void synaptics_rmi4_wakeup_gesture(struct synaptics_rmi4_data *rmi4_data,
- + bool enable)
- +{
- + if (rmi4_data->f11_wakeup_gesture)
- + synaptics_rmi4_f11_wg(rmi4_data, enable);
- + else if (rmi4_data->f12_wakeup_gesture)
- + synaptics_rmi4_f12_wg(rmi4_data, enable);
- +
- + return;
- +}
- +
- +#ifdef CONFIG_FB
- +static int synaptics_rmi4_fb_notifier_cb(struct notifier_block *self,
- + unsigned long event, void *data)
- +{
- + int *transition;
- + struct fb_event *evdata = data;
- + struct synaptics_rmi4_data *rmi4_data =
- + container_of(self, struct synaptics_rmi4_data,
- + fb_notifier);
- +
- + const struct synaptics_dsx_board_data *bdata = NULL;
- +
- + if (rmi4_data->hw_if->board_data)
- + bdata = rmi4_data->hw_if->board_data;
- + else
- + return 0;
- +
- + /* Receive notifications from primary panel only */
- + if (evdata && evdata->data && rmi4_data && mdss_panel_is_prim(evdata->info)) {
- + if (event == FB_EVENT_BLANK) {
- + transition = evdata->data;
- + if ((*transition == FB_BLANK_POWERDOWN) || (*transition == FB_BLANK_NORMAL)) {
- + synaptics_rmi4_suspend(&rmi4_data->pdev->dev);
- + rmi4_data->fb_ready = false;
- + } else if ((*transition == FB_BLANK_UNBLANK) || (*transition == FB_BLANK_NORMAL)) {
- + synaptics_rmi4_resume(&rmi4_data->pdev->dev);
- + rmi4_data->fb_ready = true;
- + if (rmi4_data->wakeup_en) {
- + mdss_panel_reset_skip_enable(false);
- + mdss_regulator_ctrl(rmi4_data, DISP_REG_ALL, false);
- + rmi4_data->wakeup_en = false;
- + }
- +
- + rmi4_data->disable_data_dump = false;
- + }
- + } else if (event == FB_EARLY_EVENT_BLANK) {
- + transition = evdata->data;
- + if ((*transition == FB_BLANK_POWERDOWN) || (*transition == FB_BLANK_NORMAL)) {
- + rmi4_data->disable_data_dump = true;
- + if (rmi4_data->dump_flags) {
- + reinit_completion(&rmi4_data->dump_completion);
- + wait_for_completion_timeout(&rmi4_data->dump_completion, 4 * HZ);
- + }
- +
- + if (rmi4_data->enable_wakeup_gesture) {
- + rmi4_data->wakeup_en = true;
- + mdss_regulator_ctrl(rmi4_data, DISP_REG_ALL, true);
- + mdss_panel_reset_skip_enable(true);
- + }
- + } else if ((*transition == FB_BLANK_UNBLANK) || (*transition == FB_BLANK_NORMAL)) {
- + if (bdata->reset_gpio >= 0 && rmi4_data->suspend) {
- + gpio_set_value(bdata->reset_gpio, bdata->reset_on_state);
- + msleep(bdata->reset_active_ms);
- + gpio_set_value(bdata->reset_gpio, !bdata->reset_on_state);
- + }
- + if (rmi4_data->wakeup_en) {
- + mdss_reset_action(bdata);
- + }
- + }
- + }
- + }
- +
- + return 0;
- +}
- +
- +static int synaptics_rmi4_fb_notifier_cb_tddi(struct notifier_block *self,
- + unsigned long event, void *data)
- +{
- + int *transition;
- + struct fb_event *evdata = data;
- + struct synaptics_rmi4_data *rmi4_data =
- + container_of(self, struct synaptics_rmi4_data,
- + fb_notifier);
- +
- + if (mdss_prim_panel_is_dead())
- + return 0;
- +
- + /* Receive notifications from primary panel only */
- + if (evdata && evdata->data && rmi4_data && mdss_panel_is_prim(evdata->info)) {
- + if (event == FB_EVENT_BLANK) {
- + transition = evdata->data;
- + if ((*transition == FB_BLANK_UNBLANK) || (*transition == FB_BLANK_NORMAL)) {
- + if (rmi4_data->wakeup_en) {
- + mdss_panel_reset_skip_enable(false);
- + mdss_regulator_ctrl(rmi4_data, DISP_REG_ALL, false);
- + rmi4_data->wakeup_en = false;
- + } else {
- + synaptics_rmi4_resume(&rmi4_data->pdev->dev);
- + rmi4_data->fb_ready = true;
- + }
- +
- + rmi4_data->disable_data_dump = false;
- + } else if ((*transition == FB_BLANK_POWERDOWN) || (*transition == FB_BLANK_NORMAL)) {
- + if (rmi4_data->wakeup_en) {
- + synaptics_rmi4_suspend(&rmi4_data->pdev->dev);
- + rmi4_data->fb_ready = true;
- + }
- + }
- + } else if (event == FB_EARLY_EVENT_BLANK) {
- + transition = evdata->data;
- + if (*transition == FB_BLANK_UNBLANK) {
- + if (rmi4_data->wakeup_en) {
- + synaptics_rmi4_resume(&rmi4_data->pdev->dev);
- + rmi4_data->fb_ready = true;
- + msleep(30);
- + }
- + } else if ((*transition == FB_BLANK_POWERDOWN) || (*transition == FB_BLANK_NORMAL)) {
- + rmi4_data->disable_data_dump = true;
- + if (rmi4_data->dump_flags) {
- + reinit_completion(&rmi4_data->dump_completion);
- + wait_for_completion_timeout(&rmi4_data->dump_completion, 4 * HZ);
- + }
- +
- + if (rmi4_data->enable_wakeup_gesture) {
- + rmi4_data->wakeup_en = true;
- + mdss_panel_reset_skip_enable(true);
- + mdss_regulator_ctrl(rmi4_data, DISP_REG_ALL, true);
- + }
- +
- + if (!rmi4_data->wakeup_en) {
- + synaptics_rmi4_suspend(&rmi4_data->pdev->dev);
- + rmi4_data->fb_ready = false;
- + }
- + }
- + }
- + }
- +
- + return 0;
- +}
- +#endif
- +
- +#ifdef USE_EARLYSUSPEND
- +static void synaptics_rmi4_early_suspend(struct early_suspend *h)
- +{
- + struct synaptics_rmi4_exp_fhandler *exp_fhandler;
- + struct synaptics_rmi4_data *rmi4_data =
- + container_of(h, struct synaptics_rmi4_data,
- + early_suspend);
- +
- + if (rmi4_data->stay_awake)
- + return;
- +
- + if (rmi4_data->enable_wakeup_gesture) {
- + synaptics_rmi4_wakeup_gesture(rmi4_data, true);
- + enable_irq_wake(rmi4_data->irq);
- + goto exit;
- + }
- +
- + synaptics_rmi4_irq_enable(rmi4_data, false, false);
- + synaptics_rmi4_sleep_enable(rmi4_data, true);
- + synaptics_rmi4_free_fingers(rmi4_data);
- +
- +exit:
- + mutex_lock(&exp_data.mutex);
- + if (!list_empty(&exp_data.list)) {
- + list_for_each_entry(exp_fhandler, &exp_data.list, link)
- + if (exp_fhandler->exp_fn->early_suspend != NULL)
- + exp_fhandler->exp_fn->early_suspend(rmi4_data);
- + }
- + mutex_unlock(&exp_data.mutex);
- +
- + rmi4_data->suspend = true;
- +
- + return;
- +}
- +
- +static void synaptics_rmi4_late_resume(struct early_suspend *h)
- +{
- +#ifdef FB_READY_RESET
- + int retval;
- +#endif
- + struct synaptics_rmi4_exp_fhandler *exp_fhandler;
- + struct synaptics_rmi4_data *rmi4_data =
- + container_of(h, struct synaptics_rmi4_data,
- + early_suspend);
- +
- + if (rmi4_data->stay_awake)
- + return;
- +
- + if (rmi4_data->enable_wakeup_gesture) {
- + synaptics_rmi4_wakeup_gesture(rmi4_data, false);
- + disable_irq_wake(rmi4_data->irq);
- + goto exit;
- + }
- +
- + rmi4_data->current_page = MASK_8BIT;
- +
- + if (rmi4_data->suspend) {
- + synaptics_rmi4_sleep_enable(rmi4_data, false);
- + synaptics_rmi4_irq_enable(rmi4_data, true, false);
- + }
- +
- +exit:
- +#ifdef FB_READY_RESET
- + if (rmi4_data->suspend) {
- + retval = synaptics_rmi4_reset_device(rmi4_data, false);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to issue reset command\n",
- + __func__);
- + }
- + }
- +#endif
- + mutex_lock(&exp_data.mutex);
- + if (!list_empty(&exp_data.list)) {
- + list_for_each_entry(exp_fhandler, &exp_data.list, link)
- + if (exp_fhandler->exp_fn->late_resume != NULL)
- + exp_fhandler->exp_fn->late_resume(rmi4_data);
- + }
- + mutex_unlock(&exp_data.mutex);
- +
- + rmi4_data->suspend = false;
- +
- + return;
- +}
- +#endif
- +
- +static int synaptics_rmi4_suspend(struct device *dev)
- +{
- + struct synaptics_rmi4_exp_fhandler *exp_fhandler;
- + struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
- + const struct synaptics_dsx_board_data *bdata =
- + rmi4_data->hw_if->board_data;
- +
- + if (rmi4_data->stay_awake || rmi4_data->suspend)
- + return 0;
- +
- + if (bdata->cut_off_power || (rmi4_data->chip_is_tddi && !rmi4_data->wakeup_en)) {
- + if (rmi4_data->fw_updating)
- + return 0;
- +
- + synaptics_rmi4_irq_enable(rmi4_data, false, false);
- +
- + if (bdata->power_gpio >= 0)
- + gpio_set_value(bdata->power_gpio,
- + !bdata->power_on_state);
- +
- + if (bdata->reset_gpio >= 0) {
- + gpio_set_value(bdata->reset_gpio,
- + bdata->reset_on_state);
- + mdelay(bdata->reset_active_ms);
- + }
- +
- + synaptics_rmi4_enable_reg(rmi4_data, false);
- + } else {
- + synaptics_secure_touch_stop(rmi4_data, 1);
- +
- + synaptics_rmi4_irq_enable(rmi4_data, false, false);
- +
- + if (!rmi4_data->wakeup_en)
- + synaptics_rmi4_sleep_enable(rmi4_data, true);
- + else {
- + if (!rmi4_data->chip_is_tddi)
- + msleep(300);
- + else
- + msleep(120);
- + synaptics_rmi4_wakeup_gesture(rmi4_data, true);
- + synaptics_rmi4_irq_enable(rmi4_data, true, false);
- + goto exit;
- + }
- +
- + mutex_lock(&exp_data.mutex);
- + if (!list_empty(&exp_data.list)) {
- + list_for_each_entry(exp_fhandler, &exp_data.list, link)
- + if (exp_fhandler->exp_fn->suspend != NULL)
- + exp_fhandler->exp_fn->suspend(rmi4_data);
- + }
- + mutex_unlock(&exp_data.mutex);
- + }
- +
- +exit:
- + synaptics_rmi4_free_fingers(rmi4_data);
- +
- + rmi4_data->suspend = true;
- +
- + return 0;
- +}
- +
- +static int synaptics_rmi4_resume(struct device *dev)
- +{
- +#ifdef FB_READY_RESET
- + int retval;
- +#endif
- + struct synaptics_rmi4_exp_fhandler *exp_fhandler;
- + struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
- + const struct synaptics_dsx_board_data *bdata =
- + rmi4_data->hw_if->board_data;
- +
- +#ifdef CONFIG_FB
- + static int skip = 0;
- +
- + if (skip == 0) {
- + skip = 1;
- + return 0;
- + }
- +#endif
- +
- + if (rmi4_data->stay_awake || !rmi4_data->suspend)
- + return 0;
- +
- + if (bdata->cut_off_power || (rmi4_data->chip_is_tddi && !rmi4_data->wakeup_en)) {
- + synaptics_rmi4_enable_reg(rmi4_data, true);
- +
- + if (bdata->power_gpio >= 0) {
- + gpio_set_value(bdata->power_gpio,
- + bdata->power_on_state);
- + mdelay(bdata->power_delay_ms);
- + }
- +
- + if (bdata->reset_gpio >= 0) {
- + gpio_set_value(bdata->reset_gpio,
- + !bdata->reset_on_state);
- + mdelay(bdata->reset_delay_ms);
- + }
- +
- + synaptics_rmi4_irq_enable(rmi4_data, true, false);
- + } else {
- + synaptics_secure_touch_stop(rmi4_data, 0);
- +
- + if (rmi4_data->wakeup_en) {
- + synaptics_rmi4_wakeup_gesture(rmi4_data, false);
- + } else {
- + rmi4_data->current_page = MASK_8BIT;
- +
- + synaptics_rmi4_sleep_enable(rmi4_data, false);
- + synaptics_rmi4_irq_enable(rmi4_data, true, false);
- +
- +#ifdef FB_READY_RESET
- + retval = synaptics_rmi4_reset_device(rmi4_data, false);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to issue reset command\n",
- + __func__);
- + }
- +#endif
- + mutex_lock(&exp_data.mutex);
- + if (!list_empty(&exp_data.list)) {
- + list_for_each_entry(exp_fhandler, &exp_data.list, link)
- + if (exp_fhandler->exp_fn->resume != NULL)
- + exp_fhandler->exp_fn->resume(rmi4_data);
- + }
- + mutex_unlock(&exp_data.mutex);
- + }
- + }
- +
- + if (rmi4_data->enable_cover_mode)
- + cover_mode_set(rmi4_data, rmi4_data->enable_cover_mode);
- +
- + rmi4_data->suspend = false;
- +
- + return 0;
- +}
- +
- +#ifdef CONFIG_PM
- +static int synaptics_rmi4_pm_suspend(struct device *dev)
- +{
- + struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
- + const struct synaptics_dsx_board_data *bdata =
- + rmi4_data->hw_if->board_data;
- +
- + if (device_may_wakeup(dev) &&
- + rmi4_data->wakeup_en &&
- + !bdata->cut_off_power) {
- + dev_info(rmi4_data->pdev->dev.parent,
- + "Enable touch irq wake\n");
- + disable_irq(rmi4_data->irq);
- + enable_irq_wake(rmi4_data->irq);
- + }
- +
- + return 0;
- +
- +}
- +
- +static int synaptics_rmi4_pm_resume(struct device *dev)
- +{
- + struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
- + const struct synaptics_dsx_board_data *bdata =
- + rmi4_data->hw_if->board_data;
- +
- + if (device_may_wakeup(dev) &&
- + rmi4_data->wakeup_en &&
- + !bdata->cut_off_power) {
- + dev_info(rmi4_data->pdev->dev.parent,
- + "Disable touch irq wake\n");
- + disable_irq_wake(rmi4_data->irq);
- + enable_irq(rmi4_data->irq);
- + }
- +
- + return 0;
- +}
- +
- +static const struct dev_pm_ops synaptics_rmi4_dev_pm_ops = {
- + .suspend = synaptics_rmi4_pm_suspend,
- + .resume = synaptics_rmi4_pm_resume,
- +};
- +#endif
- +
- +static struct platform_driver synaptics_rmi4_driver = {
- + .driver = {
- + .name = PLATFORM_DRIVER_FORCE,
- + .owner = THIS_MODULE,
- +#ifdef CONFIG_PM
- + .pm = &synaptics_rmi4_dev_pm_ops,
- +#endif
- + },
- + .probe = synaptics_rmi4_probe,
- + .remove = synaptics_rmi4_remove,
- +};
- +
- +static int __init synaptics_rmi4_init(void)
- +{
- + int retval;
- +
- + retval = synaptics_rmi4_bus_init_force();
- + if (retval)
- + return retval;
- +
- + return platform_driver_register(&synaptics_rmi4_driver);
- +}
- +
- +static void __exit synaptics_rmi4_exit(void)
- +{
- + platform_driver_unregister(&synaptics_rmi4_driver);
- +
- + synaptics_rmi4_bus_exit_force();
- +
- + return;
- +}
- +
- +module_init(synaptics_rmi4_init);
- +module_exit(synaptics_rmi4_exit);
- +
- +MODULE_AUTHOR("Synaptics, Inc.");
- +MODULE_DESCRIPTION("Synaptics DSX Touch Driver");
- +MODULE_LICENSE("GPL v2");
- diff --git a/drivers/input/touchscreen/synaptics_dsx_force/synaptics_dsx_core.h b/drivers/input/touchscreen/synaptics_dsx_force/synaptics_dsx_core.h
- new file mode 100644
- index 0000000..20298d8
- --- /dev/null
- +++ b/drivers/input/touchscreen/synaptics_dsx_force/synaptics_dsx_core.h
- @@ -0,0 +1,541 @@
- +/*
- + * Synaptics DSX touchscreen driver
- + *
- + * Copyright (C) 2012-2015 Synaptics Incorporated. All rights reserved.
- + *
- + * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
- + * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
- + * Copyright (C) 2017 XiaoMi, 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.
- + *
- + * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
- + * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
- + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
- + * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
- + * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- + * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
- + * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
- + * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- + * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
- + * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
- + * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
- + * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
- + * DOLLARS.
- + */
- +
- +#ifndef _SYNAPTICS_DSX_RMI4_H_
- +#define _SYNAPTICS_DSX_RMI4_H_
- +
- +#define SYNAPTICS_DS4 (1 << 0)
- +#define SYNAPTICS_DS5 (1 << 1)
- +#define SYNAPTICS_DSX_DRIVER_PRODUCT (SYNAPTICS_DS4 | SYNAPTICS_DS5)
- +#define SYNAPTICS_DSX_DRIVER_VERSION 0x2065
- +
- +#include <linux/version.h>
- +#ifdef CONFIG_FB
- +#include <linux/notifier.h>
- +#include <linux/fb.h>
- +#endif
- +#ifdef CONFIG_HAS_EARLYSUSPEND
- +#include <linux/earlysuspend.h>
- +#endif
- +
- +#if defined(CONFIG_SECURE_TOUCH)
- +#include <linux/completion.h>
- +#include <linux/atomic.h>
- +#include <linux/clk.h>
- +#endif
- +
- +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38))
- +#define KERNEL_ABOVE_2_6_38
- +#endif
- +
- +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
- +#define KERNEL_ABOVE_3_6
- +#endif
- +
- +#ifdef KERNEL_ABOVE_2_6_38
- +#define sstrtoul(...) kstrtoul(__VA_ARGS__)
- +#else
- +#define sstrtoul(...) strict_strtoul(__VA_ARGS__)
- +#endif
- +
- +#define PDT_PROPS (0X00EF)
- +#define PDT_START (0x00E9)
- +#define PDT_END (0x00D0)
- +#define PDT_ENTRY_SIZE (0x0006)
- +#define PAGES_TO_SERVICE (10)
- +#define PAGE_SELECT_LEN (2)
- +#define ADDRESS_LEN (2)
- +
- +#define SYNAPTICS_RMI4_F01 (0x01)
- +#define SYNAPTICS_RMI4_F11 (0x11)
- +#define SYNAPTICS_RMI4_F12 (0x12)
- +#define SYNAPTICS_RMI4_F1A (0x1A)
- +#define SYNAPTICS_RMI4_F34 (0x34)
- +#define SYNAPTICS_RMI4_F35 (0x35)
- +#define SYNAPTICS_RMI4_F38 (0x38)
- +#define SYNAPTICS_RMI4_F51 (0x51)
- +#define SYNAPTICS_RMI4_F54 (0x54)
- +#define SYNAPTICS_RMI4_F55 (0x55)
- +#define SYNAPTICS_RMI4_FDB (0xDB)
- +
- +#define PRODUCT_INFO_SIZE 2
- +#define PRODUCT_ID_SIZE 10
- +#define BUILD_ID_SIZE 3
- +#define LOCKDOWN_INFO_SIZE 8
- +
- +#define F12_FINGERS_TO_SUPPORT 10
- +#define F12_NO_OBJECT_STATUS 0x00
- +#define F12_FINGER_STATUS 0x01
- +#define F12_ACTIVE_STYLUS_STATUS 0x02
- +#define F12_PALM_STATUS 0x03
- +#define F12_HOVERING_FINGER_STATUS 0x05
- +#define F12_GLOVED_FINGER_STATUS 0x06
- +#define F12_NARROW_OBJECT_STATUS 0x07
- +#define F12_HAND_EDGE_STATUS 0x08
- +#define F12_COVER_STATUS 0x0A
- +#define F12_STYLUS_STATUS 0x0B
- +#define F12_ERASER_STATUS 0x0C
- +#define F12_SMALL_OBJECT_STATUS 0x0D
- +
- +#define F12_GESTURE_DETECTION_LEN 5
- +
- +#define MAX_NUMBER_OF_BUTTONS 4
- +#define MAX_INTR_REGISTERS 4
- +
- +#define MASK_16BIT 0xFFFF
- +#define MASK_8BIT 0xFF
- +#define MASK_7BIT 0x7F
- +#define MASK_6BIT 0x3F
- +#define MASK_5BIT 0x1F
- +#define MASK_4BIT 0x0F
- +#define MASK_3BIT 0x07
- +#define MASK_2BIT 0x03
- +#define MASK_1BIT 0x01
- +
- +#define PINCTRL_STATE_ACTIVE "pmx_ts_active"
- +#define PINCTRL_STATE_SUSPEND "pmx_ts_suspend"
- +
- +
- +enum exp_fn {
- + RMI_DEV = 0,
- + RMI_FW_UPDATER,
- + RMI_TEST_REPORTING,
- + RMI_PROXIMITY,
- + RMI_ACTIVE_PEN,
- + RMI_GESTURE,
- + RMI_VIDEO,
- + RMI_DEBUG,
- + RMI_LAST,
- +};
- +
- +/*
- + * struct synaptics_rmi4_fn_desc - function descriptor fields in PDT entry
- + * @query_base_addr: base address for query registers
- + * @cmd_base_addr: base address for command registers
- + * @ctrl_base_addr: base address for control registers
- + * @data_base_addr: base address for data registers
- + * @intr_src_count: number of interrupt sources
- + * @fn_version: version of function
- + * @fn_number: function number
- + */
- +struct synaptics_rmi4_fn_desc {
- + union {
- + struct {
- + unsigned char query_base_addr;
- + unsigned char cmd_base_addr;
- + unsigned char ctrl_base_addr;
- + unsigned char data_base_addr;
- + unsigned char intr_src_count:3;
- + unsigned char reserved_1:2;
- + unsigned char fn_version:2;
- + unsigned char reserved_2:1;
- + unsigned char fn_number;
- + } __packed;
- + unsigned char data[6];
- + };
- +};
- +
- +/*
- + * synaptics_rmi4_fn_full_addr - full 16-bit base addresses
- + * @query_base: 16-bit base address for query registers
- + * @cmd_base: 16-bit base address for command registers
- + * @ctrl_base: 16-bit base address for control registers
- + * @data_base: 16-bit base address for data registers
- + */
- +struct synaptics_rmi4_fn_full_addr {
- + unsigned short query_base;
- + unsigned short cmd_base;
- + unsigned short ctrl_base;
- + unsigned short data_base;
- +};
- +
- +/*
- + * struct synaptics_rmi4_f11_extra_data - extra data of F$11
- + * @data38_offset: offset to F11_2D_DATA38 register
- + */
- +struct synaptics_rmi4_f11_extra_data {
- + unsigned char data38_offset;
- +};
- +
- +/*
- + * struct synaptics_rmi4_f12_extra_data - extra data of F$12
- + * @data1_offset: offset to F12_2D_DATA01 register
- + * @data4_offset: offset to F12_2D_DATA04 register
- + * @data15_offset: offset to F12_2D_DATA15 register
- + * @data15_size: size of F12_2D_DATA15 register
- + * @data15_data: buffer for reading F12_2D_DATA15 register
- + * @data29_offset: offset to F12_2D_DATA29 register
- + * @data29_size: size of F12_2D_DATA29 register
- + * @data29_data: buffer for reading F12_2D_DATA29 register
- + * @ctrl20_offset: offset to F12_2D_CTRL20 register
- + */
- +struct synaptics_rmi4_f12_extra_data {
- + unsigned char data1_offset;
- + unsigned char data4_offset;
- + unsigned char data15_offset;
- + unsigned char data15_size;
- + unsigned char data15_data[(F12_FINGERS_TO_SUPPORT + 7) / 8];
- + unsigned char data29_offset;
- + unsigned char data29_size;
- + unsigned char data29_data[F12_FINGERS_TO_SUPPORT * 2];
- + unsigned char ctrl20_offset;
- + unsigned char ctrl26_offset;
- + unsigned char ctrl27_offset;
- +};
- +
- +/*
- + * struct synaptics_rmi4_fn - RMI function handler
- + * @fn_number: function number
- + * @num_of_data_sources: number of data sources
- + * @num_of_data_points: maximum number of fingers supported
- + * @intr_reg_num: index to associated interrupt register
- + * @intr_mask: interrupt mask
- + * @full_addr: full 16-bit base addresses of function registers
- + * @link: linked list for function handlers
- + * @data_size: size of private data
- + * @data: pointer to private data
- + * @extra: pointer to extra data
- + */
- +struct synaptics_rmi4_fn {
- + unsigned char fn_number;
- + unsigned char num_of_data_sources;
- + unsigned char num_of_data_points;
- + unsigned char intr_reg_num;
- + unsigned char intr_mask;
- + struct synaptics_rmi4_fn_full_addr full_addr;
- + struct list_head link;
- + int data_size;
- + void *data;
- + void *extra;
- +};
- +
- +/*
- + * struct synaptics_rmi4_device_info - device information
- + * @version_major: RMI protocol major version number
- + * @version_minor: RMI protocol minor version number
- + * @manufacturer_id: manufacturer ID
- + * @product_props: product properties
- + * @product_info: product information
- + * @product_id_string: product ID
- + * @build_id: firmware build ID
- + * @support_fn_list: linked list for function handlers
- + */
- +struct synaptics_rmi4_device_info {
- + unsigned int version_major;
- + unsigned int version_minor;
- + unsigned char manufacturer_id;
- + unsigned char product_props;
- + unsigned char product_info[PRODUCT_INFO_SIZE];
- + unsigned char product_id_string[PRODUCT_ID_SIZE + 1];
- + unsigned char build_id[BUILD_ID_SIZE];
- + struct list_head support_fn_list;
- +};
- +
- +/*
- + * struct synaptics_rmi4_data - RMI4 device instance data
- + * @pdev: pointer to platform device
- + * @input_dev: pointer to associated input device
- + * @stylus_dev: pointer to associated stylus device
- + * @hw_if: pointer to hardware interface data
- + * @rmi4_mod_info: device information
- + * @board_prop_dir: /sys/board_properties directory for virtual key map file
- + * @pwr_reg: pointer to regulator for power control
- + * @lab_reg: pointer to regulator for LCD lab control
- + * @ibb_reg: pointer to regulator for LCD ibb control
- + * @disp_reg: pointer to regulator for LCD disp control
- + * @bus_reg: pointer to regulator for bus pullup control
- + * @rmi4_reset_mutex: mutex for software reset
- + * @rmi4_report_mutex: mutex for input event reporting
- + * @rmi4_io_ctrl_mutex: mutex for communication interface I/O
- + * @rmi4_exp_init_mutex: mutex for expansion function module initialization
- + * @rmi4_irq_enable_mutex: mutex for enabling/disabling interrupt
- + * @rb_work: work for rebuilding input device
- + * @rb_workqueue: workqueue for rebuilding input device
- + * @fb_notifier: framebuffer notifier client
- + * @reset_work: work for issuing reset after display framebuffer ready
- + * @reset_workqueue: workqueue for issuing reset after display framebuffer ready
- + * @early_suspend: early suspend power management
- + * @current_page: current RMI page for register access
- + * @button_0d_enabled: switch for enabling 0d button support
- + * @num_of_tx: number of Tx channels for 2D touch
- + * @num_of_rx: number of Rx channels for 2D touch
- + * @num_of_fingers: maximum number of fingers for 2D touch
- + * @max_touch_width: maximum touch width
- + * @report_enable: input data to report for F$12
- + * @no_sleep_setting: default setting of NoSleep in F01_RMI_CTRL00 register
- + * @gesture_detection: detected gesture type and properties
- + * @intr_mask: interrupt enable mask
- + * @button_txrx_mapping: Tx Rx mapping of 0D buttons
- + * @num_of_intr_regs: number of interrupt registers
- + * @f01_query_base_addr: query base address for f$01
- + * @f01_cmd_base_addr: command base address for f$01
- + * @f01_ctrl_base_addr: control base address for f$01
- + * @f01_data_base_addr: data base address for f$01
- + * @firmware_id: firmware build ID
- + * @irq: attention interrupt
- + * @sensor_max_x: maximum x coordinate for 2D touch
- + * @sensor_max_y: maximum y coordinate for 2D touch
- + * @flash_prog_mode: flag to indicate flash programming mode status
- + * @irq_enabled: flag to indicate attention interrupt enable status
- + * @fingers_on_2d: flag to indicate presence of fingers in 2D area
- + * @suspend: flag to indicate whether in suspend state
- + * @sensor_sleep: flag to indicate sleep state of sensor
- + * @stay_awake: flag to indicate whether to stay awake during suspend
- + * @fb_ready: flag to indicate whether display framebuffer in ready state
- + * @f11_wakeup_gesture: flag to indicate support for wakeup gestures in F$11
- + * @f12_wakeup_gesture: flag to indicate support for wakeup gestures in F$12
- + * @enable_wakeup_gesture: flag to indicate usage of wakeup gestures
- + * @wedge_sensor: flag to indicate use of wedge sensor
- + * @report_pressure: flag to indicate reporting of pressure data
- + * @stylus_enable: flag to indicate reporting of stylus data
- + * @eraser_enable: flag to indicate reporting of eraser data
- + * @external_afe_buttons: flag to indicate presence of external AFE buttons
- + * @reset_device: pointer to device reset function
- + * @irq_enable: pointer to interrupt enable function
- + * @sleep_enable: pointer to sleep enable function
- + * @report_touch: pointer to touch reporting function
- + */
- +struct synaptics_rmi4_data {
- + struct platform_device *pdev;
- + struct input_dev *input_dev;
- + struct input_dev *stylus_dev;
- + const struct synaptics_dsx_hw_interface *hw_if;
- + struct synaptics_rmi4_device_info rmi4_mod_info;
- + struct kobject *board_prop_dir;
- + struct regulator *pwr_reg;
- + struct regulator *lab_reg;
- + struct regulator *ibb_reg;
- + struct regulator *disp_reg;
- + struct regulator *bus_reg;
- + struct mutex rmi4_reset_mutex;
- + struct mutex rmi4_report_mutex;
- + struct mutex rmi4_io_ctrl_mutex;
- + struct mutex rmi4_exp_init_mutex;
- + struct mutex rmi4_cover_mutex;
- + struct mutex rmi4_irq_enable_mutex;
- + struct delayed_work rb_work;
- + struct workqueue_struct *rb_workqueue;
- + struct synaptics_dsx_panel_power_seq panel_power_seq;
- +#ifdef CONFIG_FB
- + struct notifier_block fb_notifier;
- + struct work_struct reset_work;
- + struct workqueue_struct *reset_workqueue;
- +#endif
- +#ifdef CONFIG_HAS_EARLYSUSPEND
- + struct early_suspend early_suspend;
- +#endif
- + unsigned char current_page;
- + unsigned char button_0d_enabled;
- + unsigned char num_of_tx;
- + unsigned char num_of_rx;
- + unsigned char num_of_fingers;
- + unsigned char max_touch_width;
- + unsigned char report_enable;
- + unsigned char no_sleep_setting;
- + unsigned char gesture_detection[F12_GESTURE_DETECTION_LEN];
- + unsigned char intr_mask[MAX_INTR_REGISTERS];
- + unsigned char *button_txrx_mapping;
- + unsigned short num_of_intr_regs;
- + unsigned short f01_query_base_addr;
- + unsigned short f01_cmd_base_addr;
- + unsigned short f01_ctrl_base_addr;
- + unsigned short f01_data_base_addr;
- +#ifdef F51_DISCRETE_FORCE
- + unsigned short f51_query_base_addr;
- +#endif
- + unsigned int hw_version;
- + unsigned int firmware_id;
- + unsigned char lockdown_info[LOCKDOWN_INFO_SIZE];
- + unsigned char valid_button_count;
- + int irq;
- + int sensor_max_x;
- + int sensor_max_y;
- + int force_min;
- + int force_max;
- + int chip_id;
- + int touchs;
- + bool flash_prog_mode;
- + bool irq_enabled;
- + bool fingers_on_2d;
- + bool suspend;
- + bool sensor_sleep;
- + bool stay_awake;
- + bool fb_ready;
- + bool f11_wakeup_gesture;
- + bool f12_wakeup_gesture;
- + bool enable_wakeup_gesture;
- + bool enable_cover_mode;
- + bool wedge_sensor;
- + bool report_pressure;
- + bool stylus_enable;
- + bool eraser_enable;
- + bool external_afe_buttons;
- + bool fw_updating;
- + bool wakeup_en;
- + bool chip_is_tddi;
- + bool disable_data_dump;
- + bool dump_flags;
- + int (*reset_device)(struct synaptics_rmi4_data *rmi4_data,
- + bool rebuild);
- + int (*irq_enable)(struct synaptics_rmi4_data *rmi4_data, bool enable,
- + bool attn_only);
- + void (*sleep_enable)(struct synaptics_rmi4_data *rmi4_data,
- + bool enable);
- + void (*report_touch)(struct synaptics_rmi4_data *rmi4_data,
- + struct synaptics_rmi4_fn *fhandler);
- + struct pinctrl *ts_pinctrl;
- + struct pinctrl_state *pinctrl_state_active;
- + struct pinctrl_state *pinctrl_state_suspend;
- +
- + struct completion dump_completion;
- +#ifdef CONFIG_TOUCH_DEBUG_FS
- + struct dentry *debugfs;
- +#endif
- +
- +#if defined(CONFIG_SECURE_TOUCH)
- + atomic_t st_enabled;
- + atomic_t st_pending_irqs;
- + bool st_initialized;
- + struct completion st_powerdown;
- + struct completion st_irq_processed;
- + struct clk *core_clk;
- + struct clk *iface_clk;
- +#endif
- +};
- +
- +struct synaptics_dsx_bus_access {
- + unsigned char type;
- + int (*read)(struct synaptics_rmi4_data *rmi4_data, unsigned short addr,
- + unsigned char *data, unsigned short length);
- + int (*write)(struct synaptics_rmi4_data *rmi4_data, unsigned short addr,
- + unsigned char *data, unsigned short length);
- +};
- +
- +struct synaptics_dsx_hw_interface {
- + struct synaptics_dsx_board_data *board_data;
- + const struct synaptics_dsx_bus_access *bus_access;
- + int (*bl_hw_init)(struct synaptics_rmi4_data *rmi4_data);
- + int (*ui_hw_init)(struct synaptics_rmi4_data *rmi4_data);
- +};
- +
- +struct synaptics_rmi4_exp_fn {
- + enum exp_fn fn_type;
- + int (*init)(struct synaptics_rmi4_data *rmi4_data);
- + void (*remove)(struct synaptics_rmi4_data *rmi4_data);
- + void (*reset)(struct synaptics_rmi4_data *rmi4_data);
- + void (*reinit)(struct synaptics_rmi4_data *rmi4_data);
- + void (*early_suspend)(struct synaptics_rmi4_data *rmi4_data);
- + void (*suspend)(struct synaptics_rmi4_data *rmi4_data);
- + void (*resume)(struct synaptics_rmi4_data *rmi4_data);
- + void (*late_resume)(struct synaptics_rmi4_data *rmi4_data);
- + void (*attn)(struct synaptics_rmi4_data *rmi4_data,
- + unsigned char intr_mask);
- +};
- +
- +struct synaptics_rmi4_mode_switch {
- + struct synaptics_rmi4_data *data;
- + unsigned char mode;
- + struct work_struct switch_mode_work;
- +};
- +
- +int synaptics_rmi4_bus_init_force(void);
- +
- +void synaptics_rmi4_bus_exit_force(void);
- +
- +void synaptics_rmi4_new_function_force(struct synaptics_rmi4_exp_fn *exp_fn_module,
- + bool insert);
- +
- +int synaptics_fw_updater(const unsigned char *fw_data);
- +
- +static inline int synaptics_rmi4_reg_read(
- + struct synaptics_rmi4_data *rmi4_data,
- + unsigned short addr,
- + unsigned char *data,
- + unsigned short len)
- +{
- + return rmi4_data->hw_if->bus_access->read(rmi4_data, addr, data, len);
- +}
- +
- +static inline int synaptics_rmi4_reg_write(
- + struct synaptics_rmi4_data *rmi4_data,
- + unsigned short addr,
- + unsigned char *data,
- + unsigned short len)
- +{
- + return rmi4_data->hw_if->bus_access->write(rmi4_data, addr, data, len);
- +}
- +
- +static inline ssize_t synaptics_rmi4_show_error(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + dev_warn(dev, "%s Attempted to read from write-only attribute %s\n",
- + __func__, attr->attr.name);
- + return -EPERM;
- +}
- +
- +static inline ssize_t synaptics_rmi4_store_error(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count)
- +{
- + dev_warn(dev, "%s Attempted to write to read-only attribute %s\n",
- + __func__, attr->attr.name);
- + return -EPERM;
- +}
- +
- +static inline int secure_memcpy(unsigned char *dest, unsigned int dest_size,
- + const unsigned char *src, unsigned int src_size,
- + unsigned int count)
- +{
- + if (dest == NULL || src == NULL)
- + return -EINVAL;
- +
- + if (count > dest_size || count > src_size)
- + return -EINVAL;
- +
- + memcpy((void *)dest, (const void *)src, count);
- +
- + return 0;
- +}
- +
- +static inline void batohs(unsigned short *dest, unsigned char *src)
- +{
- + *dest = src[1] * 0x100 + src[0];
- +}
- +
- +static inline void hstoba(unsigned char *dest, unsigned short src)
- +{
- + dest[0] = src % 0x100;
- + dest[1] = src / 0x100;
- +}
- +
- +#endif
- diff --git a/drivers/input/touchscreen/synaptics_dsx_force/synaptics_dsx_fw_update.c b/drivers/input/touchscreen/synaptics_dsx_force/synaptics_dsx_fw_update.c
- new file mode 100644
- index 0000000..62b03ce
- --- /dev/null
- +++ b/drivers/input/touchscreen/synaptics_dsx_force/synaptics_dsx_fw_update.c
- @@ -0,0 +1,5486 @@
- +/*
- + * Synaptics DSX touchscreen driver
- + *
- + * Copyright (C) 2012-2015 Synaptics Incorporated. All rights reserved.
- + *
- + * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
- + * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
- + * Copyright (C) 2017 XiaoMi, 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.
- + *
- + * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
- + * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
- + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
- + * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
- + * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- + * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
- + * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
- + * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- + * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
- + * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
- + * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
- + * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
- + * DOLLARS.
- + */
- +
- +#include <linux/kernel.h>
- +#include <linux/module.h>
- +#include <linux/slab.h>
- +#include <linux/interrupt.h>
- +#include <linux/delay.h>
- +#include <linux/input.h>
- +#include <linux/firmware.h>
- +#include <linux/platform_device.h>
- +#include <linux/input/synaptics_dsx.h>
- +#include "synaptics_dsx_core.h"
- +#include <linux/hwinfo.h>
- +
- +#define FW_IHEX_NAME "synaptics/startup_fw_update.bin"
- +#define FW_IMAGE_NAME "synaptics/startup_fw_update.img"
- +#define DO_STARTUP_FW_UPDATE
- +
- +/*
- +#ifdef DO_STARTUP_FW_UPDATE
- +#ifdef CONFIG_FB
- +#define WAIT_FOR_FB_READY
- +#define FB_READY_WAIT_MS 100
- +#define FB_READY_TIMEOUT_S 30
- +#endif
- +#endif
- +*/
- +#define MAX_WRITE_SIZE 4096
- +
- +#define FORCE_UPDATE false
- +#define DO_LOCKDOWN false
- +
- +#define MAX_IMAGE_NAME_LEN 256
- +#define MAX_FIRMWARE_ID_LEN 10
- +
- +#define IMAGE_HEADER_VERSION_05 0x05
- +#define IMAGE_HEADER_VERSION_06 0x06
- +#define IMAGE_HEADER_VERSION_10 0x10
- +
- +#define IMAGE_AREA_OFFSET 0x100
- +#define LOCKDOWN_SIZE 0x50
- +
- +#define MAX_UTILITY_PARAMS 20
- +
- +#define V5V6_BOOTLOADER_ID_OFFSET 0
- +#define V5V6_CONFIG_ID_SIZE 4
- +
- +#define V5_PROPERTIES_OFFSET 2
- +#define V5_BLOCK_SIZE_OFFSET 3
- +#define V5_BLOCK_COUNT_OFFSET 5
- +#define V5_BLOCK_NUMBER_OFFSET 0
- +#define V5_BLOCK_DATA_OFFSET 2
- +
- +#define V6_PROPERTIES_OFFSET 1
- +#define V6_BLOCK_SIZE_OFFSET 2
- +#define V6_BLOCK_COUNT_OFFSET 3
- +#define V6_PROPERTIES_2_OFFSET 4
- +#define V6_BLOCK_NUMBER_OFFSET 0
- +#define V6_BLOCK_DATA_OFFSET 1
- +#define V6_FLASH_COMMAND_OFFSET 2
- +#define V6_FLASH_STATUS_OFFSET 3
- +
- +#define V7_CONFIG_ID_SIZE 32
- +
- +#define V7_FLASH_STATUS_OFFSET 0
- +#define V7_PARTITION_ID_OFFSET 1
- +#define V7_BLOCK_NUMBER_OFFSET 2
- +#define V7_TRANSFER_LENGTH_OFFSET 3
- +#define V7_COMMAND_OFFSET 4
- +#define V7_PAYLOAD_OFFSET 5
- +
- +#define V7_PARTITION_SUPPORT_BYTES 4
- +
- +#define F35_ERROR_CODE_OFFSET 0
- +#define F35_FLASH_STATUS_OFFSET 5
- +#define F35_CHUNK_NUM_LSB_OFFSET 0
- +#define F35_CHUNK_NUM_MSB_OFFSET 1
- +#define F35_CHUNK_DATA_OFFSET 2
- +#define F35_CHUNK_COMMAND_OFFSET 18
- +
- +#define F35_CHUNK_SIZE 16
- +#define F35_ERASE_ALL_WAIT_MS 5000
- +#define F35_RESET_WAIT_MS 250
- +
- +#define SLEEP_MODE_NORMAL (0x00)
- +#define SLEEP_MODE_SENSOR_SLEEP (0x01)
- +#define SLEEP_MODE_RESERVED0 (0x02)
- +#define SLEEP_MODE_RESERVED1 (0x03)
- +
- +#define ENABLE_WAIT_MS (1 * 1000)
- +#define WRITE_WAIT_MS (3 * 1000)
- +#define ERASE_WAIT_MS (5 * 1000)
- +
- +#define MIN_SLEEP_TIME_US 50
- +#define MAX_SLEEP_TIME_US 100
- +
- +#define INT_DISABLE_WAIT_MS 20
- +#define ENTER_FLASH_PROG_WAIT_MS 20
- +
- +static int fwu_do_reflash(void);
- +
- +static int fwu_recovery_check_status(void);
- +
- +static int fwu_read_f34_blocks(unsigned short block_cnt, unsigned char cmd);
- +
- +static ssize_t fwu_sysfs_show_image(struct file *data_file,
- + struct kobject *kobj, struct bin_attribute *attributes,
- + char *buf, loff_t pos, size_t count);
- +
- +static ssize_t fwu_sysfs_store_image(struct file *data_file,
- + struct kobject *kobj, struct bin_attribute *attributes,
- + char *buf, loff_t pos, size_t count);
- +
- +static ssize_t fwu_sysfs_do_recovery_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count);
- +
- +static ssize_t fwu_sysfs_do_reflash_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count);
- +
- +static ssize_t fwu_sysfs_write_config_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count);
- +
- +static ssize_t fwu_sysfs_read_config_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count);
- +
- +static ssize_t fwu_sysfs_config_area_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count);
- +
- +static ssize_t fwu_sysfs_image_name_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count);
- +
- +static ssize_t fwu_sysfs_image_size_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count);
- +
- +static ssize_t fwu_sysfs_block_size_show(struct device *dev,
- + struct device_attribute *attr, char *buf);
- +
- +static ssize_t fwu_sysfs_firmware_block_count_show(struct device *dev,
- + struct device_attribute *attr, char *buf);
- +
- +static ssize_t fwu_sysfs_configuration_block_count_show(struct device *dev,
- + struct device_attribute *attr, char *buf);
- +
- +static ssize_t fwu_sysfs_disp_config_block_count_show(struct device *dev,
- + struct device_attribute *attr, char *buf);
- +
- +static ssize_t fwu_sysfs_perm_config_block_count_show(struct device *dev,
- + struct device_attribute *attr, char *buf);
- +
- +static ssize_t fwu_sysfs_bl_config_block_count_show(struct device *dev,
- + struct device_attribute *attr, char *buf);
- +
- +static ssize_t fwu_sysfs_guest_code_block_count_show(struct device *dev,
- + struct device_attribute *attr, char *buf);
- +
- +static ssize_t fwu_sysfs_write_guest_code_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count);
- +
- +static void firmware_force_update(struct synaptics_rmi4_data *rmi4_data);
- +
- +enum f34_version {
- + F34_V0 = 0,
- + F34_V1,
- + F34_V2,
- +};
- +
- +enum bl_version {
- + BL_V5 = 5,
- + BL_V6 = 6,
- + BL_V7 = 7,
- + BL_V8 = 8,
- +};
- +
- +enum flash_area {
- + NONE = 0,
- + UI_FIRMWARE,
- + UI_CONFIG,
- +};
- +
- +enum update_mode {
- + NORMAL = 1,
- + FORCE = 2,
- + LOCKDOWN = 8,
- +};
- +
- +enum config_area {
- + UI_CONFIG_AREA = 0,
- + PM_CONFIG_AREA,
- + BL_CONFIG_AREA,
- + DP_CONFIG_AREA,
- + FLASH_CONFIG_AREA,
- + INVALID_CONFIG_AREA = 0xff,
- +};
- +
- +enum v7_status {
- + SUCCESS = 0x00,
- + DEVICE_NOT_IN_BOOTLOADER_MODE,
- + INVALID_PARTITION,
- + INVALID_COMMAND,
- + INVALID_BLOCK_OFFSET,
- + INVALID_TRANSFER,
- + NOT_ERASED,
- + FLASH_PROGRAMMING_KEY_INCORRECT,
- + BAD_PARTITION_TABLE,
- + CHECKSUM_FAILED,
- + FLASH_HARDWARE_FAILURE = 0x1f,
- +};
- +
- +enum v7_partition_id {
- + BOOTLOADER_PARTITION = 0x01,
- + DEVICE_CONFIG_PARTITION,
- + FLASH_CONFIG_PARTITION,
- + MANUFACTURING_BLOCK_PARTITION,
- + GUEST_SERIALIZATION_PARTITION,
- + GLOBAL_PARAMETERS_PARTITION,
- + CORE_CODE_PARTITION,
- + CORE_CONFIG_PARTITION,
- + GUEST_CODE_PARTITION,
- + DISPLAY_CONFIG_PARTITION,
- + EXTERNAL_TOUCH_AFE_CONFIG_PARTITION,
- + UTILITY_PARAMETER_PARTITION,
- +};
- +
- +enum v7_flash_command {
- + CMD_V7_IDLE = 0x00,
- + CMD_V7_ENTER_BL,
- + CMD_V7_READ,
- + CMD_V7_WRITE,
- + CMD_V7_ERASE,
- + CMD_V7_ERASE_AP,
- + CMD_V7_SENSOR_ID,
- +};
- +
- +enum v5v6_flash_command {
- + CMD_V5V6_IDLE = 0x0,
- + CMD_V5V6_WRITE_FW = 0x2,
- + CMD_V5V6_ERASE_ALL = 0x3,
- + CMD_V5V6_WRITE_LOCKDOWN = 0x4,
- + CMD_V5V6_READ_CONFIG = 0x5,
- + CMD_V5V6_WRITE_CONFIG = 0x6,
- + CMD_V5V6_ERASE_UI_CONFIG = 0x7,
- + CMD_V5V6_ERASE_BL_CONFIG = 0x9,
- + CMD_V5V6_ERASE_DISP_CONFIG = 0xa,
- + CMD_V5V6_ERASE_GUEST_CODE = 0xb,
- + CMD_V5V6_WRITE_GUEST_CODE = 0xc,
- + CMD_V5V6_ENABLE_FLASH_PROG = 0xf,
- + CMD_V5V6_READ_LOCKDOWN_DATA = 0x1b,
- +};
- +
- +enum flash_command {
- + CMD_IDLE = 0,
- + CMD_WRITE_FW,
- + CMD_WRITE_CONFIG,
- + CMD_WRITE_LOCKDOWN,
- + CMD_WRITE_GUEST_CODE,
- + CMD_WRITE_BOOTLOADER,
- + CMD_WRITE_UTILITY_PARAM,
- + CMD_READ_CONFIG,
- + CMD_ERASE_ALL,
- + CMD_ERASE_UI_FIRMWARE,
- + CMD_ERASE_UI_CONFIG,
- + CMD_ERASE_BL_CONFIG,
- + CMD_ERASE_DISP_CONFIG,
- + CMD_ERASE_FLASH_CONFIG,
- + CMD_ERASE_GUEST_CODE,
- + CMD_ERASE_BOOTLOADER,
- + CMD_ERASE_UTILITY_PARAMETER,
- + CMD_ENABLE_FLASH_PROG,
- + CMD_READ_LOCKDOWN_DATA,
- +};
- +
- +enum f35_flash_command {
- + CMD_F35_IDLE = 0x0,
- + CMD_F35_RESERVED = 0x1,
- + CMD_F35_WRITE_CHUNK = 0x2,
- + CMD_F35_ERASE_ALL = 0x3,
- + CMD_F35_RESET = 0x10,
- +};
- +
- +enum container_id {
- + TOP_LEVEL_CONTAINER = 0,
- + UI_CONTAINER,
- + UI_CONFIG_CONTAINER,
- + BL_CONTAINER,
- + BL_IMAGE_CONTAINER,
- + BL_CONFIG_CONTAINER,
- + BL_LOCKDOWN_INFO_CONTAINER,
- + PERMANENT_CONFIG_CONTAINER,
- + GUEST_CODE_CONTAINER,
- + BL_PROTOCOL_DESCRIPTOR_CONTAINER,
- + UI_PROTOCOL_DESCRIPTOR_CONTAINER,
- + RMI_SELF_DISCOVERY_CONTAINER,
- + RMI_PAGE_CONTENT_CONTAINER,
- + GENERAL_INFORMATION_CONTAINER,
- + DEVICE_CONFIG_CONTAINER,
- + FLASH_CONFIG_CONTAINER,
- + GUEST_SERIALIZATION_CONTAINER,
- + GLOBAL_PARAMETERS_CONTAINER,
- + CORE_CODE_CONTAINER,
- + CORE_CONFIG_CONTAINER,
- + DISPLAY_CONFIG_CONTAINER,
- + EXTERNAL_TOUCH_AFE_CONFIG_CONTAINER,
- + UTILITY_CONTAINER,
- + UTILITY_PARAMETER_CONTAINER,
- +};
- +
- +enum utility_parameter_id {
- + UNUSED = 0,
- + FORCE_PARAMETER,
- + ANTI_BENDING_PARAMETER,
- +};
- +
- +struct pdt_properties {
- + union {
- + struct {
- + unsigned char reserved_1:6;
- + unsigned char has_bsr:1;
- + unsigned char reserved_2:1;
- + } __packed;
- + unsigned char data[1];
- + };
- +};
- +
- +struct partition_table {
- + unsigned char partition_id:5;
- + unsigned char byte_0_reserved:3;
- + unsigned char byte_1_reserved;
- + unsigned char partition_length_7_0;
- + unsigned char partition_length_15_8;
- + unsigned char start_physical_address_7_0;
- + unsigned char start_physical_address_15_8;
- + unsigned char partition_properties_7_0;
- + unsigned char partition_properties_15_8;
- +} __packed;
- +
- +struct f01_device_control {
- + union {
- + struct {
- + unsigned char sleep_mode:2;
- + unsigned char nosleep:1;
- + unsigned char reserved:2;
- + unsigned char charger_connected:1;
- + unsigned char report_rate:1;
- + unsigned char configured:1;
- + } __packed;
- + unsigned char data[1];
- + };
- +};
- +
- +struct f34_v7_query_0 {
- + union {
- + struct {
- + unsigned char subpacket_1_size:3;
- + unsigned char has_config_id:1;
- + unsigned char f34_query0_b4:1;
- + unsigned char has_thqa:1;
- + unsigned char f34_query0_b6__7:2;
- + } __packed;
- + unsigned char data[1];
- + };
- +};
- +
- +struct f34_v7_query_1_7 {
- + union {
- + struct {
- + /* query 1 */
- + unsigned char bl_minor_revision;
- + unsigned char bl_major_revision;
- +
- + /* query 2 */
- + unsigned char bl_fw_id_7_0;
- + unsigned char bl_fw_id_15_8;
- + unsigned char bl_fw_id_23_16;
- + unsigned char bl_fw_id_31_24;
- +
- + /* query 3 */
- + unsigned char minimum_write_size;
- + unsigned char block_size_7_0;
- + unsigned char block_size_15_8;
- + unsigned char flash_page_size_7_0;
- + unsigned char flash_page_size_15_8;
- +
- + /* query 4 */
- + unsigned char adjustable_partition_area_size_7_0;
- + unsigned char adjustable_partition_area_size_15_8;
- +
- + /* query 5 */
- + unsigned char flash_config_length_7_0;
- + unsigned char flash_config_length_15_8;
- +
- + /* query 6 */
- + unsigned char payload_length_7_0;
- + unsigned char payload_length_15_8;
- +
- + /* query 7 */
- + unsigned char f34_query7_b0:1;
- + unsigned char has_bootloader:1;
- + unsigned char has_device_config:1;
- + unsigned char has_flash_config:1;
- + unsigned char has_manufacturing_block:1;
- + unsigned char has_guest_serialization:1;
- + unsigned char has_global_parameters:1;
- + unsigned char has_core_code:1;
- + unsigned char has_core_config:1;
- + unsigned char has_guest_code:1;
- + unsigned char has_display_config:1;
- + unsigned char f34_query7_b11__15:5;
- + unsigned char f34_query7_b16__23;
- + unsigned char f34_query7_b24__31;
- + } __packed;
- + unsigned char data[21];
- + };
- +};
- +
- +struct f34_v7_data0 {
- + union {
- + struct {
- + unsigned char operation_status:5;
- + unsigned char device_cfg_status:2;
- + unsigned char bl_mode:1;
- + } __packed;
- + unsigned char data[1];
- + };
- +};
- +
- +struct f34_v7_data_1_5 {
- + union {
- + struct {
- + unsigned char partition_id:5;
- + unsigned char f34_data1_b5__7:3;
- + unsigned char block_offset_7_0;
- + unsigned char block_offset_15_8;
- + unsigned char transfer_length_7_0;
- + unsigned char transfer_length_15_8;
- + unsigned char command;
- + unsigned char payload_0;
- + unsigned char payload_1;
- + } __packed;
- + unsigned char data[8];
- + };
- +};
- +
- +struct f34_v5v6_flash_properties {
- + union {
- + struct {
- + unsigned char reg_map:1;
- + unsigned char unlocked:1;
- + unsigned char has_config_id:1;
- + unsigned char has_pm_config:1;
- + unsigned char has_bl_config:1;
- + unsigned char has_disp_config:1;
- + unsigned char has_ctrl1:1;
- + unsigned char has_query4:1;
- + } __packed;
- + unsigned char data[1];
- + };
- +};
- +
- +struct f34_v5v6_flash_properties_2 {
- + union {
- + struct {
- + unsigned char has_guest_code:1;
- + unsigned char f34_query4_b1:1;
- + unsigned char has_gesture_config_area:1;
- + unsigned char has_force_config_block:1;
- + unsigned char has_lockdown_data_block:1;
- + unsigned char has_lcm_data_block:1;
- + unsigned char has_oem_data_block:1;
- + unsigned char f34_query4_b7:1;
- + } __packed;
- + unsigned char data[1];
- + };
- +};
- +
- +struct register_offset {
- + unsigned char properties;
- + unsigned char properties_2;
- + unsigned char block_size;
- + unsigned char block_count;
- + unsigned char flash_status;
- + unsigned char partition_id;
- + unsigned char block_number;
- + unsigned char transfer_length;
- + unsigned char flash_cmd;
- + unsigned char payload;
- +};
- +
- +struct block_count {
- + unsigned short ui_firmware;
- + unsigned short ui_config;
- + unsigned short dp_config;
- + unsigned short pm_config;
- + unsigned short fl_config;
- + unsigned short bl_image;
- + unsigned short bl_config;
- + unsigned short utility_param;
- + unsigned short lockdown;
- + unsigned short guest_code;
- + unsigned short lockdown_data;
- + unsigned short total_count;
- +};
- +
- +struct physical_address {
- + unsigned short ui_firmware;
- + unsigned short ui_config;
- + unsigned short dp_config;
- + unsigned short pm_config;
- + unsigned short fl_config;
- + unsigned short bl_image;
- + unsigned short bl_config;
- + unsigned short utility_param;
- + unsigned short lockdown;
- + unsigned short guest_code;
- +};
- +
- +struct container_descriptor {
- + unsigned char content_checksum[4];
- + unsigned char container_id[2];
- + unsigned char minor_version;
- + unsigned char major_version;
- + unsigned char reserved_08;
- + unsigned char reserved_09;
- + unsigned char reserved_0a;
- + unsigned char reserved_0b;
- + unsigned char container_option_flags[4];
- + unsigned char content_options_length[4];
- + unsigned char content_options_address[4];
- + unsigned char content_length[4];
- + unsigned char content_address[4];
- +};
- +
- +struct image_header_10 {
- + unsigned char checksum[4];
- + unsigned char reserved_04;
- + unsigned char reserved_05;
- + unsigned char minor_header_version;
- + unsigned char major_header_version;
- + unsigned char reserved_08;
- + unsigned char reserved_09;
- + unsigned char reserved_0a;
- + unsigned char reserved_0b;
- + unsigned char top_level_container_start_addr[4];
- +};
- +
- +struct image_header_05_06 {
- + /* 0x00 - 0x0f */
- + unsigned char checksum[4];
- + unsigned char reserved_04;
- + unsigned char reserved_05;
- + unsigned char options_firmware_id:1;
- + unsigned char options_bootloader:1;
- + unsigned char options_guest_code:1;
- + unsigned char options_tddi:1;
- + unsigned char options_reserved:4;
- + unsigned char header_version;
- + unsigned char firmware_size[4];
- + unsigned char config_size[4];
- + /* 0x10 - 0x1f */
- + unsigned char product_id[PRODUCT_ID_SIZE];
- + unsigned char package_id[2];
- + unsigned char package_id_revision[2];
- + unsigned char product_info[PRODUCT_INFO_SIZE];
- + /* 0x20 - 0x2f */
- + unsigned char bootloader_addr[4];
- + unsigned char bootloader_size[4];
- + unsigned char ui_addr[4];
- + unsigned char ui_size[4];
- + /* 0x30 - 0x3f */
- + unsigned char ds_id[16];
- + /* 0x40 - 0x4f */
- + union {
- + struct {
- + unsigned char cstmr_product_id[PRODUCT_ID_SIZE];
- + unsigned char reserved_4a_4f[6];
- + };
- + struct {
- + unsigned char dsp_cfg_addr[4];
- + unsigned char dsp_cfg_size[4];
- + unsigned char reserved_48_4f[8];
- + };
- + };
- + /* 0x50 - 0x53 */
- + unsigned char firmware_id[4];
- +};
- +
- +struct block_data {
- + unsigned int size;
- + const unsigned char *data;
- +};
- +
- +struct image_metadata {
- + bool contains_firmware_id;
- + bool contains_bootloader;
- + bool contains_guest_code;
- + bool contains_disp_config;
- + bool contains_perm_config;
- + bool contains_flash_config;
- + bool contains_utility_param;
- + unsigned int firmware_id;
- + unsigned int checksum;
- + unsigned int bootloader_size;
- + unsigned int disp_config_offset;
- + unsigned char bl_version;
- + unsigned char product_id[PRODUCT_ID_SIZE + 1];
- + unsigned char cstmr_product_id[PRODUCT_ID_SIZE + 1];
- + unsigned char utility_param_id[MAX_UTILITY_PARAMS];
- + struct block_data bootloader;
- + struct block_data utility;
- + struct block_data ui_firmware;
- + struct block_data ui_config;
- + struct block_data dp_config;
- + struct block_data pm_config;
- + struct block_data fl_config;
- + struct block_data bl_image;
- + struct block_data bl_config;
- + struct block_data utility_param[MAX_UTILITY_PARAMS];
- + struct block_data lockdown;
- + struct block_data guest_code;
- + struct block_count blkcount;
- + struct physical_address phyaddr;
- +};
- +
- +struct synaptics_rmi4_fwu_handle {
- + enum bl_version bl_version;
- + bool initialized;
- + bool in_bl_mode;
- + bool in_ub_mode;
- + bool bl_mode_device;
- + bool force_update;
- + bool do_lockdown;
- + bool has_guest_code;
- + bool has_lockdown_data;
- + bool has_utility_param;
- + bool new_partition_table;
- + bool incompatible_partition_tables;
- + bool write_bootloader;
- + unsigned int data_pos;
- + unsigned char *ext_data_source;
- + unsigned char *read_config_buf;
- + unsigned char intr_mask;
- + unsigned char command;
- + unsigned char bootloader_id[2];
- + unsigned char config_id[32];
- + unsigned char flash_status;
- + unsigned char partitions;
- +#ifdef F51_DISCRETE_FORCE
- + unsigned char *cal_data;
- + unsigned short cal_data_off;
- + unsigned short cal_data_size;
- + unsigned short cal_data_buf_size;
- + unsigned short cal_packet_data_size;
- +#endif
- + unsigned short block_size;
- + unsigned short config_size;
- + unsigned short config_area;
- + unsigned short config_block_count;
- + unsigned short flash_config_length;
- + unsigned short payload_length;
- + unsigned short partition_table_bytes;
- + unsigned short read_config_buf_size;
- + const unsigned char *config_data;
- + const unsigned char *image;
- + unsigned char *image_name;
- + unsigned int image_size;
- + struct image_metadata img;
- + struct register_offset off;
- + struct block_count blkcount;
- + struct physical_address phyaddr;
- + struct f34_v5v6_flash_properties flash_properties;
- + struct synaptics_rmi4_fn_desc f34_fd;
- + struct synaptics_rmi4_fn_desc f35_fd;
- + struct synaptics_rmi4_data *rmi4_data;
- + struct workqueue_struct *fwu_workqueue;
- + struct work_struct fwu_work;
- +};
- +
- +static struct bin_attribute dev_attr_data = {
- + .attr = {
- + .name = "data",
- + .mode = (S_IRUGO | S_IWUGO),
- + },
- + .size = 0,
- + .read = fwu_sysfs_show_image,
- + .write = fwu_sysfs_store_image,
- +};
- +
- +static struct device_attribute attrs[] = {
- + __ATTR(dorecovery, S_IWUSR,
- + synaptics_rmi4_show_error,
- + fwu_sysfs_do_recovery_store),
- + __ATTR(doreflash, S_IWUSR,
- + synaptics_rmi4_show_error,
- + fwu_sysfs_do_reflash_store),
- + __ATTR(writeconfig, S_IWUSR,
- + synaptics_rmi4_show_error,
- + fwu_sysfs_write_config_store),
- + __ATTR(readconfig, S_IWUSR,
- + synaptics_rmi4_show_error,
- + fwu_sysfs_read_config_store),
- + __ATTR(configarea, S_IWUSR,
- + synaptics_rmi4_show_error,
- + fwu_sysfs_config_area_store),
- + __ATTR(imagename, S_IWUSR,
- + synaptics_rmi4_show_error,
- + fwu_sysfs_image_name_store),
- + __ATTR(imagesize, S_IWUSR,
- + synaptics_rmi4_show_error,
- + fwu_sysfs_image_size_store),
- + __ATTR(blocksize, S_IRUGO,
- + fwu_sysfs_block_size_show,
- + synaptics_rmi4_store_error),
- + __ATTR(fwblockcount, S_IRUGO,
- + fwu_sysfs_firmware_block_count_show,
- + synaptics_rmi4_store_error),
- + __ATTR(configblockcount, S_IRUGO,
- + fwu_sysfs_configuration_block_count_show,
- + synaptics_rmi4_store_error),
- + __ATTR(dispconfigblockcount, S_IRUGO,
- + fwu_sysfs_disp_config_block_count_show,
- + synaptics_rmi4_store_error),
- + __ATTR(permconfigblockcount, S_IRUGO,
- + fwu_sysfs_perm_config_block_count_show,
- + synaptics_rmi4_store_error),
- + __ATTR(blconfigblockcount, S_IRUGO,
- + fwu_sysfs_bl_config_block_count_show,
- + synaptics_rmi4_store_error),
- + __ATTR(guestcodeblockcount, S_IRUGO,
- + fwu_sysfs_guest_code_block_count_show,
- + synaptics_rmi4_store_error),
- + __ATTR(writeguestcode, S_IWUSR,
- + synaptics_rmi4_show_error,
- + fwu_sysfs_write_guest_code_store),
- +};
- +
- +static struct synaptics_rmi4_fwu_handle *fwu;
- +
- +DECLARE_COMPLETION(fwu_remove_complete_force);
- +static int fwu_read_f34_guest_serialization_partition(void);
- +
- +static void calculate_checksum(unsigned short *data, unsigned long len,
- + unsigned long *result)
- +{
- + unsigned long temp;
- + unsigned long sum1 = 0xffff;
- + unsigned long sum2 = 0xffff;
- +
- + *result = 0xffffffff;
- +
- + while (len--) {
- + temp = *data;
- + sum1 += temp;
- + sum2 += sum1;
- + sum1 = (sum1 & 0xffff) + (sum1 >> 16);
- + sum2 = (sum2 & 0xffff) + (sum2 >> 16);
- + data++;
- + }
- +
- + *result = sum2 << 16 | sum1;
- +
- + return;
- +}
- +
- +static void convert_to_little_endian(unsigned char *dest, unsigned long src)
- +{
- + dest[0] = (unsigned char)(src & 0xff);
- + dest[1] = (unsigned char)((src >> 8) & 0xff);
- + dest[2] = (unsigned char)((src >> 16) & 0xff);
- + dest[3] = (unsigned char)((src >> 24) & 0xff);
- +
- + return;
- +}
- +
- +static unsigned int le_to_uint(const unsigned char *ptr)
- +{
- + return (unsigned int)ptr[0] +
- + (unsigned int)ptr[1] * 0x100 +
- + (unsigned int)ptr[2] * 0x10000 +
- + (unsigned int)ptr[3] * 0x1000000;
- +}
- +
- +#ifdef F51_DISCRETE_FORCE
- +static int fwu_f51_force_data_init(void)
- +{
- + int retval;
- + unsigned char query_count;
- + unsigned char packet_info;
- + unsigned char offset[2];
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + rmi4_data->f51_query_base_addr + 7,
- + offset,
- + sizeof(offset));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to read force data offset\n",
- + __func__);
- + return retval;
- + }
- +
- + fwu->cal_data_off = offset[0] | offset[1] << 8;
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + rmi4_data->f51_query_base_addr,
- + &query_count,
- + sizeof(query_count));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to read number of F51 query registers\n",
- + __func__);
- + return retval;
- + }
- +
- + if (query_count >= 10) {
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + rmi4_data->f51_query_base_addr + 9,
- + &packet_info,
- + sizeof(packet_info));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to read F51 packet register info\n",
- + __func__);
- + return retval;
- + }
- +
- + if (packet_info & MASK_1BIT) {
- + fwu->cal_packet_data_size = packet_info >> 1;
- + fwu->cal_packet_data_size *= 2;
- + } else {
- + fwu->cal_packet_data_size = 0;
- + }
- + } else {
- + fwu->cal_packet_data_size = 0;
- + }
- +
- + fwu->cal_data_size = CAL_DATA_SIZE + fwu->cal_packet_data_size;
- + if (fwu->cal_data_size > fwu->cal_data_buf_size) {
- + kfree(fwu->cal_data);
- + fwu->cal_data_buf_size = fwu->cal_data_size;
- + fwu->cal_data = kmalloc(fwu->cal_data_buf_size, GFP_KERNEL);
- + if (!fwu->cal_data) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to alloc mem for fwu->cal_data\n",
- + __func__);
- + fwu->cal_data_buf_size = 0;
- + return -ENOMEM;
- + }
- + }
- +
- + return 0;
- +}
- +#endif
- +
- +static int fwu_allocate_read_config_buf(unsigned int count)
- +{
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + if (count > fwu->read_config_buf_size) {
- + kfree(fwu->read_config_buf);
- + fwu->read_config_buf = kzalloc(count, GFP_KERNEL);
- + if (!fwu->read_config_buf) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to alloc mem for fwu->read_config_buf\n",
- + __func__);
- + fwu->read_config_buf_size = 0;
- + return -ENOMEM;
- + }
- + fwu->read_config_buf_size = count;
- + }
- +
- + return 0;
- +}
- +
- +static void fwu_compare_partition_tables(void)
- +{
- + fwu->incompatible_partition_tables = false;
- +
- + if (fwu->phyaddr.bl_image != fwu->img.phyaddr.bl_image)
- + fwu->incompatible_partition_tables = true;
- + else if (fwu->phyaddr.lockdown != fwu->img.phyaddr.lockdown)
- + fwu->incompatible_partition_tables = true;
- + else if (fwu->phyaddr.bl_config != fwu->img.phyaddr.bl_config)
- + fwu->incompatible_partition_tables = true;
- + else if (fwu->phyaddr.utility_param != fwu->img.phyaddr.utility_param)
- + fwu->incompatible_partition_tables = true;
- +
- + if (fwu->bl_version == BL_V7) {
- + if (fwu->phyaddr.fl_config != fwu->img.phyaddr.fl_config)
- + fwu->incompatible_partition_tables = true;
- + }
- +
- + fwu->new_partition_table = false;
- +
- + if (fwu->phyaddr.ui_firmware != fwu->img.phyaddr.ui_firmware)
- + fwu->new_partition_table = true;
- + else if (fwu->phyaddr.ui_config != fwu->img.phyaddr.ui_config)
- + fwu->new_partition_table = true;
- +
- + if (fwu->flash_properties.has_disp_config) {
- + if (fwu->phyaddr.dp_config != fwu->img.phyaddr.dp_config)
- + fwu->new_partition_table = true;
- + }
- +
- + if (fwu->has_guest_code) {
- + if (fwu->phyaddr.guest_code != fwu->img.phyaddr.guest_code)
- + fwu->new_partition_table = true;
- + }
- +
- + return;
- +}
- +
- +static void fwu_parse_partition_table(const unsigned char *partition_table,
- + struct block_count *blkcount, struct physical_address *phyaddr)
- +{
- + unsigned char ii;
- + unsigned char index;
- + unsigned char offset;
- + unsigned short partition_length;
- + unsigned short physical_address;
- + struct partition_table *ptable;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + for (ii = 0; ii < fwu->partitions; ii++) {
- + index = ii * 8 + 2;
- + ptable = (struct partition_table *)&partition_table[index];
- + partition_length = ptable->partition_length_15_8 << 8 |
- + ptable->partition_length_7_0;
- + physical_address = ptable->start_physical_address_15_8 << 8 |
- + ptable->start_physical_address_7_0;
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: Partition entry %d:\n",
- + __func__, ii);
- + for (offset = 0; offset < 8; offset++) {
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: 0x%02x\n",
- + __func__,
- + partition_table[index + offset]);
- + }
- + switch (ptable->partition_id) {
- + case CORE_CODE_PARTITION:
- + blkcount->ui_firmware = partition_length;
- + phyaddr->ui_firmware = physical_address;
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: Core code block count: %d\n",
- + __func__, blkcount->ui_firmware);
- + blkcount->total_count += partition_length;
- + break;
- + case CORE_CONFIG_PARTITION:
- + blkcount->ui_config = partition_length;
- + phyaddr->ui_config = physical_address;
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: Core config block count: %d\n",
- + __func__, blkcount->ui_config);
- + blkcount->total_count += partition_length;
- + break;
- + case BOOTLOADER_PARTITION:
- + blkcount->bl_image = partition_length;
- + phyaddr->bl_image = physical_address;
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: Bootloader block count: %d\n",
- + __func__, blkcount->bl_image);
- + blkcount->total_count += partition_length;
- + break;
- + case UTILITY_PARAMETER_PARTITION:
- + blkcount->utility_param = partition_length;
- + phyaddr->utility_param = physical_address;
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: Utility parameter block count: %d\n",
- + __func__, blkcount->utility_param);
- + blkcount->total_count += partition_length;
- + break;
- + case DISPLAY_CONFIG_PARTITION:
- + blkcount->dp_config = partition_length;
- + phyaddr->dp_config = physical_address;
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: Display config block count: %d\n",
- + __func__, blkcount->dp_config);
- + blkcount->total_count += partition_length;
- + break;
- + case FLASH_CONFIG_PARTITION:
- + blkcount->fl_config = partition_length;
- + phyaddr->fl_config = physical_address;
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: Flash config block count: %d\n",
- + __func__, blkcount->fl_config);
- + blkcount->total_count += partition_length;
- + break;
- + case GUEST_CODE_PARTITION:
- + blkcount->guest_code = partition_length;
- + phyaddr->guest_code = physical_address;
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: Guest code block count: %d\n",
- + __func__, blkcount->guest_code);
- + blkcount->total_count += partition_length;
- + break;
- + case GUEST_SERIALIZATION_PARTITION:
- + blkcount->pm_config = partition_length;
- + phyaddr->pm_config = physical_address;
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: Guest serialization block count: %d\n",
- + __func__, blkcount->pm_config);
- + blkcount->total_count += partition_length;
- + break;
- + case GLOBAL_PARAMETERS_PARTITION:
- + blkcount->bl_config = partition_length;
- + phyaddr->bl_config = physical_address;
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: Global parameters block count: %d\n",
- + __func__, blkcount->bl_config);
- + blkcount->total_count += partition_length;
- + break;
- + case DEVICE_CONFIG_PARTITION:
- + blkcount->lockdown = partition_length;
- + phyaddr->lockdown = physical_address;
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: Device config block count: %d\n",
- + __func__, blkcount->lockdown);
- + blkcount->total_count += partition_length;
- + break;
- + };
- + }
- +
- + return;
- +}
- +
- +static void fwu_parse_image_header_10_utility(const unsigned char *image)
- +{
- + unsigned char ii;
- + unsigned char num_of_containers;
- + unsigned int addr;
- + unsigned int container_id;
- + unsigned int length;
- + const unsigned char *content;
- + struct container_descriptor *descriptor;
- +
- + num_of_containers = fwu->img.utility.size / 4;
- +
- + for (ii = 0; ii < num_of_containers; ii++) {
- + if (ii >= MAX_UTILITY_PARAMS)
- + continue;
- + addr = le_to_uint(fwu->img.utility.data + (ii * 4));
- + descriptor = (struct container_descriptor *)(image + addr);
- + container_id = descriptor->container_id[0] |
- + descriptor->container_id[1] << 8;
- + content = image + le_to_uint(descriptor->content_address);
- + length = le_to_uint(descriptor->content_length);
- + switch (container_id) {
- + case UTILITY_PARAMETER_CONTAINER:
- + fwu->img.utility_param[ii].data = content;
- + fwu->img.utility_param[ii].size = length;
- + fwu->img.utility_param_id[ii] = content[0];
- + break;
- + default:
- + break;
- + };
- + }
- +
- + return;
- +}
- +
- +static void fwu_parse_image_header_10_bootloader(const unsigned char *image)
- +{
- + unsigned char ii;
- + unsigned char num_of_containers;
- + unsigned int addr;
- + unsigned int container_id;
- + unsigned int length;
- + const unsigned char *content;
- + struct container_descriptor *descriptor;
- +
- + num_of_containers = (fwu->img.bootloader.size - 4) / 4;
- +
- + for (ii = 1; ii <= num_of_containers; ii++) {
- + addr = le_to_uint(fwu->img.bootloader.data + (ii * 4));
- + descriptor = (struct container_descriptor *)(image + addr);
- + container_id = descriptor->container_id[0] |
- + descriptor->container_id[1] << 8;
- + content = image + le_to_uint(descriptor->content_address);
- + length = le_to_uint(descriptor->content_length);
- + switch (container_id) {
- + case BL_IMAGE_CONTAINER:
- + fwu->img.bl_image.data = content;
- + fwu->img.bl_image.size = length;
- + break;
- + case BL_CONFIG_CONTAINER:
- + case GLOBAL_PARAMETERS_CONTAINER:
- + fwu->img.bl_config.data = content;
- + fwu->img.bl_config.size = length;
- + break;
- + case BL_LOCKDOWN_INFO_CONTAINER:
- + case DEVICE_CONFIG_CONTAINER:
- + fwu->img.lockdown.data = content;
- + fwu->img.lockdown.size = length;
- + break;
- + default:
- + break;
- + };
- + }
- +
- + return;
- +}
- +
- +static void fwu_parse_image_header_10(void)
- +{
- + unsigned char ii;
- + unsigned char num_of_containers;
- + unsigned int addr;
- + unsigned int offset;
- + unsigned int container_id;
- + unsigned int length;
- + const unsigned char *image;
- + const unsigned char *content;
- + struct container_descriptor *descriptor;
- + struct image_header_10 *header;
- +
- + image = fwu->image;
- + header = (struct image_header_10 *)image;
- +
- + fwu->img.checksum = le_to_uint(header->checksum);
- +
- + /* address of top level container */
- + offset = le_to_uint(header->top_level_container_start_addr);
- + descriptor = (struct container_descriptor *)(image + offset);
- +
- + /* address of top level container content */
- + offset = le_to_uint(descriptor->content_address);
- + num_of_containers = le_to_uint(descriptor->content_length) / 4;
- +
- + for (ii = 0; ii < num_of_containers; ii++) {
- + addr = le_to_uint(image + offset);
- + offset += 4;
- + descriptor = (struct container_descriptor *)(image + addr);
- + container_id = descriptor->container_id[0] |
- + descriptor->container_id[1] << 8;
- + content = image + le_to_uint(descriptor->content_address);
- + length = le_to_uint(descriptor->content_length);
- + switch (container_id) {
- + case UI_CONTAINER:
- + case CORE_CODE_CONTAINER:
- + fwu->img.ui_firmware.data = content;
- + fwu->img.ui_firmware.size = length;
- + break;
- + case UI_CONFIG_CONTAINER:
- + case CORE_CONFIG_CONTAINER:
- + fwu->img.ui_config.data = content;
- + fwu->img.ui_config.size = length;
- + break;
- + case BL_CONTAINER:
- + fwu->img.bl_version = *content;
- + fwu->img.bootloader.data = content;
- + fwu->img.bootloader.size = length;
- + fwu_parse_image_header_10_bootloader(image);
- + break;
- + case UTILITY_CONTAINER:
- + fwu->img.utility.data = content;
- + fwu->img.utility.size = length;
- + fwu_parse_image_header_10_utility(image);
- + break;
- + case GUEST_CODE_CONTAINER:
- + fwu->img.contains_guest_code = true;
- + fwu->img.guest_code.data = content;
- + fwu->img.guest_code.size = length;
- + break;
- + case DISPLAY_CONFIG_CONTAINER:
- + fwu->img.contains_disp_config = true;
- + fwu->img.dp_config.data = content;
- + fwu->img.dp_config.size = length;
- + break;
- + case PERMANENT_CONFIG_CONTAINER:
- + case GUEST_SERIALIZATION_CONTAINER:
- + fwu->img.contains_perm_config = true;
- + fwu->img.pm_config.data = content;
- + fwu->img.pm_config.size = length;
- + break;
- + case FLASH_CONFIG_CONTAINER:
- + fwu->img.contains_flash_config = true;
- + fwu->img.fl_config.data = content;
- + fwu->img.fl_config.size = length;
- + break;
- + case GENERAL_INFORMATION_CONTAINER:
- + fwu->img.contains_firmware_id = true;
- + fwu->img.firmware_id = le_to_uint(content + 4);
- + break;
- + default:
- + break;
- + }
- + }
- +
- + return;
- +}
- +
- +static void fwu_parse_image_header_05_06(void)
- +{
- + int retval;
- + const unsigned char *image;
- + struct image_header_05_06 *header;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + image = fwu->image;
- + header = (struct image_header_05_06 *)image;
- +
- + fwu->img.checksum = le_to_uint(header->checksum);
- +
- + fwu->img.bl_version = header->header_version;
- +
- + fwu->img.contains_bootloader = header->options_bootloader;
- + if (fwu->img.contains_bootloader)
- + fwu->img.bootloader_size = le_to_uint(header->bootloader_size);
- +
- + fwu->img.ui_firmware.size = le_to_uint(header->firmware_size);
- + if (fwu->img.ui_firmware.size) {
- + fwu->img.ui_firmware.data = image + IMAGE_AREA_OFFSET;
- + if (fwu->img.contains_bootloader)
- + fwu->img.ui_firmware.data += fwu->img.bootloader_size;
- + }
- +
- + if ((fwu->img.bl_version == BL_V6) && header->options_tddi)
- + fwu->img.ui_firmware.data = image + IMAGE_AREA_OFFSET;
- +
- + fwu->img.ui_config.size = le_to_uint(header->config_size);
- + if (fwu->img.ui_config.size) {
- + fwu->img.ui_config.data = fwu->img.ui_firmware.data +
- + fwu->img.ui_firmware.size;
- + }
- +
- + if (fwu->img.contains_bootloader || header->options_tddi)
- + fwu->img.contains_disp_config = true;
- + else
- + fwu->img.contains_disp_config = false;
- +
- + if (fwu->img.contains_disp_config) {
- + fwu->img.disp_config_offset = le_to_uint(header->dsp_cfg_addr);
- + fwu->img.dp_config.size = le_to_uint(header->dsp_cfg_size);
- + fwu->img.dp_config.data = image + fwu->img.disp_config_offset;
- + } else {
- + retval = secure_memcpy(fwu->img.cstmr_product_id,
- + sizeof(fwu->img.cstmr_product_id),
- + header->cstmr_product_id,
- + sizeof(header->cstmr_product_id),
- + PRODUCT_ID_SIZE);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to copy custom product ID string\n",
- + __func__);
- + }
- + fwu->img.cstmr_product_id[PRODUCT_ID_SIZE] = 0;
- + }
- +
- + fwu->img.contains_firmware_id = header->options_firmware_id;
- + if (fwu->img.contains_firmware_id)
- + fwu->img.firmware_id = le_to_uint(header->firmware_id);
- +
- + retval = secure_memcpy(fwu->img.product_id,
- + sizeof(fwu->img.product_id),
- + header->product_id,
- + sizeof(header->product_id),
- + PRODUCT_ID_SIZE);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to copy product ID string\n",
- + __func__);
- + }
- + fwu->img.product_id[PRODUCT_ID_SIZE] = 0;
- +
- + fwu->img.lockdown.size = LOCKDOWN_SIZE;
- + fwu->img.lockdown.data = image + IMAGE_AREA_OFFSET - LOCKDOWN_SIZE;
- +
- + return;
- +}
- +
- +static int fwu_parse_image_info(void)
- +{
- + struct image_header_10 *header;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + header = (struct image_header_10 *)fwu->image;
- +
- + memset(&fwu->img, 0x00, sizeof(fwu->img));
- +
- + switch (header->major_header_version) {
- + case IMAGE_HEADER_VERSION_10:
- + fwu_parse_image_header_10();
- + break;
- + case IMAGE_HEADER_VERSION_05:
- + case IMAGE_HEADER_VERSION_06:
- + fwu_parse_image_header_05_06();
- + break;
- + default:
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Unsupported image file format (0x%02x)\n",
- + __func__, header->major_header_version);
- + return -EINVAL;
- + }
- +
- + if (fwu->bl_version == BL_V7 || fwu->bl_version == BL_V8) {
- + if (!fwu->img.contains_flash_config) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: No flash config found in firmware image\n",
- + __func__);
- + return -EINVAL;
- + }
- +
- + fwu_parse_partition_table(fwu->img.fl_config.data,
- + &fwu->img.blkcount, &fwu->img.phyaddr);
- +
- + if (fwu->img.blkcount.utility_param)
- + fwu->img.contains_utility_param = true;
- +
- + fwu_compare_partition_tables();
- + } else {
- + fwu->new_partition_table = false;
- + fwu->incompatible_partition_tables = false;
- + }
- +
- + return 0;
- +}
- +
- +static int fwu_read_flash_status(void)
- +{
- + int retval;
- + unsigned char status;
- + unsigned char command;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + fwu->f34_fd.data_base_addr + fwu->off.flash_status,
- + &status,
- + sizeof(status));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to read flash status\n",
- + __func__);
- + return retval;
- + }
- +
- + fwu->in_bl_mode = status >> 7;
- +
- + if (fwu->bl_version == BL_V5)
- + fwu->flash_status = (status >> 4) & MASK_3BIT;
- + else if (fwu->bl_version == BL_V6)
- + fwu->flash_status = status & MASK_3BIT;
- + else if (fwu->bl_version == BL_V7 || fwu->bl_version == BL_V8)
- + fwu->flash_status = status & MASK_5BIT;
- +
- + if (fwu->write_bootloader)
- + fwu->flash_status = 0x00;
- +
- + if (fwu->flash_status != 0x00) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Flash status = %d, command = 0x%02x, config area = 0x%02x\n",
- + __func__, fwu->flash_status, fwu->command, fwu->config_area);
- + }
- +
- + if (fwu->flash_status == 0x08)
- + fwu->flash_status = 0;
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + fwu->f34_fd.data_base_addr + fwu->off.flash_cmd,
- + &command,
- + sizeof(command));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to read flash command\n",
- + __func__);
- + return retval;
- + }
- +
- + if (fwu->bl_version == BL_V5)
- + fwu->command = command & MASK_4BIT;
- + else if (fwu->bl_version == BL_V6)
- + fwu->command = command & MASK_6BIT;
- + else if (fwu->bl_version == BL_V7 || fwu->bl_version == BL_V8)
- + fwu->command = command;
- +
- + if (fwu->write_bootloader)
- + fwu->command = 0x00;
- +
- + return 0;
- +}
- +
- +static int fwu_wait_for_idle(int timeout_ms, bool poll)
- +{
- + int count = 0;
- + int timeout_count = ((timeout_ms * 1000) / MAX_SLEEP_TIME_US) + 1;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + do {
- + usleep_range(MIN_SLEEP_TIME_US, MAX_SLEEP_TIME_US);
- +
- + count++;
- + if (poll || (count == timeout_count))
- + fwu_read_flash_status();
- +
- + if ((fwu->command == CMD_IDLE) && (fwu->flash_status == 0x00))
- + return 0;
- + } while (count < timeout_count);
- +
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Timed out waiting for idle status\n",
- + __func__);
- +
- + return -ETIMEDOUT;
- +}
- +
- +static int fwu_write_f34_v7_command_single_transaction(unsigned char cmd)
- +{
- + int retval;
- + unsigned char data_base;
- + struct f34_v7_data_1_5 data_1_5;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + data_base = fwu->f34_fd.data_base_addr;
- +
- + memset(data_1_5.data, 0x00, sizeof(data_1_5.data));
- +
- + switch (cmd) {
- + case CMD_ERASE_ALL:
- + data_1_5.partition_id = CORE_CODE_PARTITION;
- + data_1_5.command = CMD_V7_ERASE_AP;
- + break;
- + case CMD_ERASE_UI_FIRMWARE:
- + data_1_5.partition_id = CORE_CODE_PARTITION;
- + data_1_5.command = CMD_V7_ERASE;
- + break;
- + case CMD_ERASE_BL_CONFIG:
- + data_1_5.partition_id = GLOBAL_PARAMETERS_PARTITION;
- + data_1_5.command = CMD_V7_ERASE;
- + break;
- + case CMD_ERASE_UI_CONFIG:
- + data_1_5.partition_id = CORE_CONFIG_PARTITION;
- + data_1_5.command = CMD_V7_ERASE;
- + break;
- + case CMD_ERASE_DISP_CONFIG:
- + data_1_5.partition_id = DISPLAY_CONFIG_PARTITION;
- + data_1_5.command = CMD_V7_ERASE;
- + break;
- + case CMD_ERASE_FLASH_CONFIG:
- + data_1_5.partition_id = FLASH_CONFIG_PARTITION;
- + data_1_5.command = CMD_V7_ERASE;
- + break;
- + case CMD_ERASE_GUEST_CODE:
- + data_1_5.partition_id = GUEST_CODE_PARTITION;
- + data_1_5.command = CMD_V7_ERASE;
- + break;
- + case CMD_ERASE_BOOTLOADER:
- + data_1_5.partition_id = BOOTLOADER_PARTITION;
- + data_1_5.command = CMD_V7_ERASE;
- + break;
- + case CMD_ERASE_UTILITY_PARAMETER:
- + data_1_5.partition_id = UTILITY_PARAMETER_PARTITION;
- + data_1_5.command = CMD_V7_ERASE;
- + break;
- + case CMD_ENABLE_FLASH_PROG:
- + data_1_5.partition_id = BOOTLOADER_PARTITION;
- + data_1_5.command = CMD_V7_ENTER_BL;
- + break;
- + };
- +
- + data_1_5.payload_0 = fwu->bootloader_id[0];
- + data_1_5.payload_1 = fwu->bootloader_id[1];
- +
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + data_base + fwu->off.partition_id,
- + data_1_5.data,
- + sizeof(data_1_5.data));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to write single transaction command\n",
- + __func__);
- + return retval;
- + }
- +
- + return 0;
- +}
- +
- +static int fwu_write_f34_v7_command(unsigned char cmd)
- +{
- + int retval;
- + unsigned char data_base;
- + unsigned char command;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + data_base = fwu->f34_fd.data_base_addr;
- +
- + switch (cmd) {
- + case CMD_WRITE_FW:
- + case CMD_WRITE_CONFIG:
- + case CMD_WRITE_LOCKDOWN:
- + case CMD_WRITE_GUEST_CODE:
- + case CMD_WRITE_BOOTLOADER:
- + case CMD_WRITE_UTILITY_PARAM:
- + command = CMD_V7_WRITE;
- + break;
- + case CMD_READ_CONFIG:
- + command = CMD_V7_READ;
- + break;
- + case CMD_ERASE_ALL:
- + command = CMD_V7_ERASE_AP;
- + break;
- + case CMD_ERASE_UI_FIRMWARE:
- + case CMD_ERASE_BL_CONFIG:
- + case CMD_ERASE_UI_CONFIG:
- + case CMD_ERASE_DISP_CONFIG:
- + case CMD_ERASE_FLASH_CONFIG:
- + case CMD_ERASE_GUEST_CODE:
- + case CMD_ERASE_BOOTLOADER:
- + case CMD_ERASE_UTILITY_PARAMETER:
- + command = CMD_V7_ERASE;
- + break;
- + case CMD_ENABLE_FLASH_PROG:
- + command = CMD_V7_ENTER_BL;
- + break;
- + default:
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Invalid command 0x%02x\n",
- + __func__, cmd);
- + return -EINVAL;
- + };
- +
- + fwu->command = command;
- +
- + switch (cmd) {
- + case CMD_ERASE_ALL:
- + case CMD_ERASE_UI_FIRMWARE:
- + case CMD_ERASE_BL_CONFIG:
- + case CMD_ERASE_UI_CONFIG:
- + case CMD_ERASE_DISP_CONFIG:
- + case CMD_ERASE_FLASH_CONFIG:
- + case CMD_ERASE_GUEST_CODE:
- + case CMD_ERASE_BOOTLOADER:
- + case CMD_ERASE_UTILITY_PARAMETER:
- + case CMD_ENABLE_FLASH_PROG:
- + retval = fwu_write_f34_v7_command_single_transaction(cmd);
- + if (retval < 0)
- + return retval;
- + else
- + return 0;
- + default:
- + break;
- + };
- +
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + data_base + fwu->off.flash_cmd,
- + &command,
- + sizeof(command));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to write flash command\n",
- + __func__);
- + return retval;
- + }
- +
- + return 0;
- +}
- +
- +static int fwu_write_f34_v5v6_command(unsigned char cmd)
- +{
- + int retval;
- + unsigned char data_base;
- + unsigned char command;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + data_base = fwu->f34_fd.data_base_addr;
- +
- + switch (cmd) {
- + case CMD_IDLE:
- + command = CMD_V5V6_IDLE;
- + break;
- + case CMD_WRITE_FW:
- + command = CMD_V5V6_WRITE_FW;
- + break;
- + case CMD_WRITE_CONFIG:
- + command = CMD_V5V6_WRITE_CONFIG;
- + break;
- + case CMD_WRITE_LOCKDOWN:
- + command = CMD_V5V6_WRITE_LOCKDOWN;
- + break;
- + case CMD_WRITE_GUEST_CODE:
- + command = CMD_V5V6_WRITE_GUEST_CODE;
- + break;
- + case CMD_READ_CONFIG:
- + command = CMD_V5V6_READ_CONFIG;
- + break;
- + case CMD_ERASE_ALL:
- + command = CMD_V5V6_ERASE_ALL;
- + break;
- + case CMD_ERASE_UI_CONFIG:
- + command = CMD_V5V6_ERASE_UI_CONFIG;
- + break;
- + case CMD_ERASE_DISP_CONFIG:
- + command = CMD_V5V6_ERASE_DISP_CONFIG;
- + break;
- + case CMD_ERASE_GUEST_CODE:
- + command = CMD_V5V6_ERASE_GUEST_CODE;
- + break;
- + case CMD_ENABLE_FLASH_PROG:
- + command = CMD_V5V6_ENABLE_FLASH_PROG;
- + break;
- + case CMD_READ_LOCKDOWN_DATA:
- + command = CMD_V5V6_READ_LOCKDOWN_DATA;
- + break;
- + default:
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Invalid command 0x%02x\n",
- + __func__, cmd);
- + return -EINVAL;
- + }
- +
- + switch (cmd) {
- + case CMD_ERASE_ALL:
- + case CMD_ERASE_UI_CONFIG:
- + case CMD_ERASE_DISP_CONFIG:
- + case CMD_ERASE_GUEST_CODE:
- + case CMD_ENABLE_FLASH_PROG:
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + data_base + fwu->off.payload,
- + fwu->bootloader_id,
- + sizeof(fwu->bootloader_id));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to write bootloader ID\n",
- + __func__);
- + return retval;
- + }
- + break;
- + default:
- + break;
- + };
- +
- + fwu->command = command;
- +
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + data_base + fwu->off.flash_cmd,
- + &command,
- + sizeof(command));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to write command 0x%02x\n",
- + __func__, command);
- + return retval;
- + }
- +
- + return 0;
- +}
- +
- +static int fwu_write_f34_command(unsigned char cmd)
- +{
- + int retval;
- +
- + if (fwu->bl_version == BL_V7 || fwu->bl_version == BL_V8)
- + retval = fwu_write_f34_v7_command(cmd);
- + else
- + retval = fwu_write_f34_v5v6_command(cmd);
- +
- + return retval;
- +}
- +
- +static int fwu_write_f34_v7_partition_id(unsigned char cmd)
- +{
- + int retval;
- + unsigned char data_base;
- + unsigned char partition;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + data_base = fwu->f34_fd.data_base_addr;
- +
- + switch (cmd) {
- + case CMD_WRITE_FW:
- + partition = CORE_CODE_PARTITION;
- + break;
- + case CMD_WRITE_CONFIG:
- + case CMD_READ_CONFIG:
- + if (fwu->config_area == UI_CONFIG_AREA)
- + partition = CORE_CONFIG_PARTITION;
- + else if (fwu->config_area == DP_CONFIG_AREA)
- + partition = DISPLAY_CONFIG_PARTITION;
- + else if (fwu->config_area == PM_CONFIG_AREA)
- + partition = GUEST_SERIALIZATION_PARTITION;
- + else if (fwu->config_area == BL_CONFIG_AREA)
- + partition = GLOBAL_PARAMETERS_PARTITION;
- + else if (fwu->config_area == FLASH_CONFIG_AREA)
- + partition = FLASH_CONFIG_PARTITION;
- + break;
- + case CMD_WRITE_LOCKDOWN:
- + partition = DEVICE_CONFIG_PARTITION;
- + break;
- + case CMD_WRITE_GUEST_CODE:
- + partition = GUEST_CODE_PARTITION;
- + break;
- + case CMD_WRITE_BOOTLOADER:
- + partition = BOOTLOADER_PARTITION;
- + break;
- + case CMD_WRITE_UTILITY_PARAM:
- + partition = UTILITY_PARAMETER_PARTITION;
- + break;
- + case CMD_ERASE_ALL:
- + partition = CORE_CODE_PARTITION;
- + break;
- + case CMD_ERASE_BL_CONFIG:
- + partition = GLOBAL_PARAMETERS_PARTITION;
- + break;
- + case CMD_ERASE_UI_CONFIG:
- + partition = CORE_CONFIG_PARTITION;
- + break;
- + case CMD_ERASE_DISP_CONFIG:
- + partition = DISPLAY_CONFIG_PARTITION;
- + break;
- + case CMD_ERASE_FLASH_CONFIG:
- + partition = FLASH_CONFIG_PARTITION;
- + break;
- + case CMD_ERASE_GUEST_CODE:
- + partition = GUEST_CODE_PARTITION;
- + break;
- + case CMD_ERASE_BOOTLOADER:
- + partition = BOOTLOADER_PARTITION;
- + break;
- + case CMD_ENABLE_FLASH_PROG:
- + partition = BOOTLOADER_PARTITION;
- + break;
- + default:
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Invalid command 0x%02x\n",
- + __func__, cmd);
- + return -EINVAL;
- + };
- +
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + data_base + fwu->off.partition_id,
- + &partition,
- + sizeof(partition));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to write partition ID\n",
- + __func__);
- + return retval;
- + }
- +
- + return 0;
- +}
- +
- +static int fwu_write_f34_partition_id(unsigned char cmd)
- +{
- + int retval;
- +
- + if (fwu->bl_version == BL_V7 || fwu->bl_version == BL_V8)
- + retval = fwu_write_f34_v7_partition_id(cmd);
- + else
- + retval = 0;
- +
- + return retval;
- +}
- +
- +static int fwu_read_f34_v7_partition_table(unsigned char *partition_table)
- +{
- + int retval;
- + unsigned char data_base;
- + unsigned char length[2];
- + unsigned short block_number = 0;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + data_base = fwu->f34_fd.data_base_addr;
- +
- + fwu->config_area = FLASH_CONFIG_AREA;
- +
- + retval = fwu_write_f34_partition_id(CMD_READ_CONFIG);
- + if (retval < 0)
- + return retval;
- +
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + data_base + fwu->off.block_number,
- + (unsigned char *)&block_number,
- + sizeof(block_number));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to write block number\n",
- + __func__);
- + return retval;
- + }
- +
- + length[0] = (unsigned char)(fwu->flash_config_length & MASK_8BIT);
- + length[1] = (unsigned char)(fwu->flash_config_length >> 8);
- +
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + data_base + fwu->off.transfer_length,
- + length,
- + sizeof(length));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to write transfer length\n",
- + __func__);
- + return retval;
- + }
- +
- + retval = fwu_write_f34_command(CMD_READ_CONFIG);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to write command\n",
- + __func__);
- + return retval;
- + }
- +
- + retval = fwu_wait_for_idle(WRITE_WAIT_MS, true);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to wait for idle status\n",
- + __func__);
- + return retval;
- + }
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + data_base + fwu->off.payload,
- + partition_table,
- + fwu->partition_table_bytes);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to read block data\n",
- + __func__);
- + return retval;
- + }
- +
- + return 0;
- +}
- +
- +static int fwu_read_f34_v7_queries(void)
- +{
- + int retval;
- + unsigned char ii;
- + unsigned char query_base;
- + unsigned char index;
- + unsigned char offset;
- + unsigned char *ptable;
- + struct f34_v7_query_0 query_0;
- + struct f34_v7_query_1_7 query_1_7;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + query_base = fwu->f34_fd.query_base_addr;
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + query_base,
- + query_0.data,
- + sizeof(query_0.data));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to read query 0\n",
- + __func__);
- + return retval;
- + }
- +
- + offset = query_0.subpacket_1_size + 1;
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + query_base + offset,
- + query_1_7.data,
- + sizeof(query_1_7.data));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to read queries 1 to 7\n",
- + __func__);
- + return retval;
- + }
- +
- + fwu->bootloader_id[0] = query_1_7.bl_minor_revision;
- + fwu->bootloader_id[1] = query_1_7.bl_major_revision;
- +
- + if (fwu->bootloader_id[1] == BL_V8)
- + fwu->bl_version = BL_V8;
- +
- + fwu->block_size = query_1_7.block_size_15_8 << 8 |
- + query_1_7.block_size_7_0;
- +
- + fwu->flash_config_length = query_1_7.flash_config_length_15_8 << 8 |
- + query_1_7.flash_config_length_7_0;
- +
- + fwu->payload_length = query_1_7.payload_length_15_8 << 8 |
- + query_1_7.payload_length_7_0;
- +
- + fwu->off.flash_status = V7_FLASH_STATUS_OFFSET;
- + fwu->off.partition_id = V7_PARTITION_ID_OFFSET;
- + fwu->off.block_number = V7_BLOCK_NUMBER_OFFSET;
- + fwu->off.transfer_length = V7_TRANSFER_LENGTH_OFFSET;
- + fwu->off.flash_cmd = V7_COMMAND_OFFSET;
- + fwu->off.payload = V7_PAYLOAD_OFFSET;
- +
- + index = sizeof(query_1_7.data) - V7_PARTITION_SUPPORT_BYTES;
- +
- + fwu->partitions = 0;
- + for (offset = 0; offset < V7_PARTITION_SUPPORT_BYTES; offset++) {
- + for (ii = 0; ii < 8; ii++) {
- + if (query_1_7.data[index + offset] & (1 << ii))
- + fwu->partitions++;
- + }
- +
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: Supported partitions: 0x%02x\n",
- + __func__, query_1_7.data[index + offset]);
- + }
- +
- + fwu->partition_table_bytes = fwu->partitions * 8 + 2;
- +
- + ptable = kzalloc(fwu->partition_table_bytes, GFP_KERNEL);
- + if (!ptable) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to alloc mem for partition table\n",
- + __func__);
- + return -ENOMEM;
- + }
- +
- + retval = fwu_read_f34_v7_partition_table(ptable);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to read partition table\n",
- + __func__);
- + kfree(ptable);
- + return retval;
- + }
- +
- + fwu_parse_partition_table(ptable, &fwu->blkcount, &fwu->phyaddr);
- +
- + if (fwu->blkcount.dp_config)
- + fwu->flash_properties.has_disp_config = 1;
- + else
- + fwu->flash_properties.has_disp_config = 0;
- +
- + if (fwu->blkcount.pm_config)
- + fwu->flash_properties.has_pm_config = 1;
- + else
- + fwu->flash_properties.has_pm_config = 0;
- +
- + if (fwu->blkcount.bl_config)
- + fwu->flash_properties.has_bl_config = 1;
- + else
- + fwu->flash_properties.has_bl_config = 0;
- +
- + if (fwu->blkcount.guest_code)
- + fwu->has_guest_code = 1;
- + else
- + fwu->has_guest_code = 0;
- +
- + if (fwu->blkcount.utility_param)
- + fwu->has_utility_param = 1;
- + else
- + fwu->has_utility_param = 0;
- +
- + kfree(ptable);
- +
- + if (rmi4_data->hw_if->board_data->lockdown_area == LOCKDOWN_AREA_GUEST_SERIALIZATION)
- + fwu_read_f34_guest_serialization_partition();
- +
- + return 0;
- +}
- +
- +static int fwu_read_f34_lockdown_data(void)
- +{
- + int retval = 0;
- + unsigned short block_count;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + if (!fwu->has_lockdown_data)
- + return -EINVAL;
- +
- + block_count = fwu->blkcount.lockdown_data;
- + fwu->config_area = UI_CONFIG_AREA;
- + fwu->config_size = fwu->block_size * block_count;
- +
- + retval = fwu_allocate_read_config_buf(fwu->config_size);
- + if (retval < 0)
- + return retval;
- +
- + retval = fwu_read_f34_blocks(block_count, CMD_READ_LOCKDOWN_DATA);
- + if (retval < 0)
- + return retval;
- +
- + secure_memcpy(rmi4_data->lockdown_info, LOCKDOWN_INFO_SIZE,
- + &fwu->read_config_buf[4], fwu->read_config_buf_size, LOCKDOWN_INFO_SIZE);
- +
- + dev_info(rmi4_data->pdev->dev.parent,
- + "%s: Lockdown info: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
- + __func__, fwu->read_config_buf[4], fwu->read_config_buf[5],
- + fwu->read_config_buf[6], fwu->read_config_buf[7],
- + fwu->read_config_buf[8], fwu->read_config_buf[9],
- + fwu->read_config_buf[10], fwu->read_config_buf[11]);
- +
- + return retval;
- +}
- +
- +static int fwu_read_f34_v5v6_queries(void)
- +{
- + int retval;
- + unsigned char count;
- + unsigned char query_base;
- + unsigned char buf[10];
- + struct f34_v5v6_flash_properties_2 properties_2;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + query_base = fwu->f34_fd.query_base_addr;
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + query_base + V5V6_BOOTLOADER_ID_OFFSET,
- + fwu->bootloader_id,
- + sizeof(fwu->bootloader_id));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to read bootloader ID\n",
- + __func__);
- + return retval;
- + }
- +
- + if (fwu->bl_version == BL_V5) {
- + fwu->off.properties = V5_PROPERTIES_OFFSET;
- + fwu->off.block_size = V5_BLOCK_SIZE_OFFSET;
- + fwu->off.block_count = V5_BLOCK_COUNT_OFFSET;
- + fwu->off.block_number = V5_BLOCK_NUMBER_OFFSET;
- + fwu->off.payload = V5_BLOCK_DATA_OFFSET;
- + } else if (fwu->bl_version == BL_V6) {
- + fwu->off.properties = V6_PROPERTIES_OFFSET;
- + fwu->off.properties_2 = V6_PROPERTIES_2_OFFSET;
- + fwu->off.block_size = V6_BLOCK_SIZE_OFFSET;
- + fwu->off.block_count = V6_BLOCK_COUNT_OFFSET;
- + fwu->off.block_number = V6_BLOCK_NUMBER_OFFSET;
- + fwu->off.payload = V6_BLOCK_DATA_OFFSET;
- + }
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + query_base + fwu->off.block_size,
- + buf,
- + 2);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to read block size info\n",
- + __func__);
- + return retval;
- + }
- +
- + batohs(&fwu->block_size, &(buf[0]));
- +
- + if (fwu->bl_version == BL_V5) {
- + fwu->off.flash_cmd = fwu->off.payload + fwu->block_size;
- + fwu->off.flash_status = fwu->off.flash_cmd;
- + } else if (fwu->bl_version == BL_V6) {
- + fwu->off.flash_cmd = V6_FLASH_COMMAND_OFFSET;
- + fwu->off.flash_status = V6_FLASH_STATUS_OFFSET;
- + }
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + query_base + fwu->off.properties,
- + fwu->flash_properties.data,
- + sizeof(fwu->flash_properties.data));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to read flash properties\n",
- + __func__);
- + return retval;
- + }
- +
- + count = 4;
- +
- + if (fwu->flash_properties.has_pm_config)
- + count += 2;
- +
- + if (fwu->flash_properties.has_bl_config)
- + count += 2;
- +
- + if (fwu->flash_properties.has_disp_config)
- + count += 2;
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + query_base + fwu->off.block_count,
- + buf,
- + count);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to read block count info\n",
- + __func__);
- + return retval;
- + }
- +
- + batohs(&fwu->blkcount.ui_firmware, &(buf[0]));
- + batohs(&fwu->blkcount.ui_config, &(buf[2]));
- +
- + count = 4;
- +
- + if (fwu->flash_properties.has_pm_config) {
- + batohs(&fwu->blkcount.pm_config, &(buf[count]));
- + count += 2;
- + }
- +
- + if (fwu->flash_properties.has_bl_config) {
- + batohs(&fwu->blkcount.bl_config, &(buf[count]));
- + count += 2;
- + }
- +
- + if (fwu->flash_properties.has_disp_config)
- + batohs(&fwu->blkcount.dp_config, &(buf[count]));
- +
- + fwu->has_guest_code = false;
- +
- + fwu->has_lockdown_data = false;
- +
- + if (fwu->flash_properties.has_query4) {
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + query_base + fwu->off.properties_2,
- + properties_2.data,
- + sizeof(properties_2.data));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to read flash properties 2\n",
- + __func__);
- + return retval;
- + }
- +
- + count = 0;
- +
- + if (properties_2.has_guest_code) {
- + count++;
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + query_base + fwu->off.properties_2 + count,
- + buf,
- + 2);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to read guest code block count\n",
- + __func__);
- + return retval;
- + }
- +
- + batohs(&fwu->blkcount.guest_code, &(buf[0]));
- + fwu->has_guest_code = true;
- + }
- +
- + if (properties_2.has_gesture_config_area)
- + count++;
- +
- + if (properties_2.has_force_config_block)
- + count++;
- +
- + if (properties_2.has_lockdown_data_block) {
- + count++;
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + query_base + fwu->off.properties_2 + count,
- + buf,
- + 2);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to read lockdown data block count\n",
- + __func__);
- + return retval;
- + }
- +
- + batohs(&fwu->blkcount.lockdown_data, &(buf[0]));
- + fwu->has_lockdown_data = true;
- +
- + fwu_read_f34_lockdown_data();
- + }
- + }
- +
- + fwu->has_utility_param = false;
- +
- + return 0;
- +}
- +
- +static int fwu_read_f34_queries(void)
- +{
- + int retval;
- +
- + memset(&fwu->blkcount, 0x00, sizeof(fwu->blkcount));
- + memset(&fwu->phyaddr, 0x00, sizeof(fwu->phyaddr));
- +
- + if (fwu->bl_version == BL_V7)
- + retval = fwu_read_f34_v7_queries();
- + else
- + retval = fwu_read_f34_v5v6_queries();
- +
- + return retval;
- +}
- +
- +static int fwu_write_f34_v7_blocks(unsigned char *block_ptr,
- + unsigned short block_cnt, unsigned char command)
- +{
- + int retval;
- + unsigned char data_base;
- + unsigned char length[2];
- + unsigned short transfer;
- + unsigned short remaining = block_cnt;
- + unsigned short block_number = 0;
- + unsigned short left_bytes;
- + unsigned short write_size;
- + unsigned short max_write_size;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + data_base = fwu->f34_fd.data_base_addr;
- +
- + retval = fwu_write_f34_partition_id(command);
- + if (retval < 0)
- + return retval;
- +
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + data_base + fwu->off.block_number,
- + (unsigned char *)&block_number,
- + sizeof(block_number));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to write block number\n",
- + __func__);
- + return retval;
- + }
- +
- + do {
- + if (remaining / fwu->payload_length)
- + transfer = fwu->payload_length;
- + else
- + transfer = remaining;
- +
- + length[0] = (unsigned char)(transfer & MASK_8BIT);
- + length[1] = (unsigned char)(transfer >> 8);
- +
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + data_base + fwu->off.transfer_length,
- + length,
- + sizeof(length));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to write transfer length (remaining = %d)\n",
- + __func__, remaining);
- + return retval;
- + }
- +
- + retval = fwu_write_f34_command(command);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to write command (remaining = %d)\n",
- + __func__, remaining);
- + return retval;
- + }
- +
- +#ifdef MAX_WRITE_SIZE
- + max_write_size = MAX_WRITE_SIZE;
- + if (max_write_size >= transfer * fwu->block_size)
- + max_write_size = transfer * fwu->block_size;
- + else if (max_write_size > fwu->block_size)
- + max_write_size -= max_write_size % fwu->block_size;
- + else
- + max_write_size = fwu->block_size;
- +#else
- + max_write_size = transfer * fwu->block_size;
- +#endif
- + left_bytes = transfer * fwu->block_size;
- +
- + do {
- + if (left_bytes / max_write_size)
- + write_size = max_write_size;
- + else
- + write_size = left_bytes;
- +
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + data_base + fwu->off.payload,
- + block_ptr,
- + write_size);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to write block data (remaining = %d)\n",
- + __func__, remaining);
- + return retval;
- + }
- +
- + block_ptr += write_size;
- + left_bytes -= write_size;
- + } while (left_bytes);
- +
- + retval = fwu_wait_for_idle(WRITE_WAIT_MS, false);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to wait for idle status (remaining = %d)\n",
- + __func__, remaining);
- + return retval;
- + }
- +
- + remaining -= transfer;
- + } while (remaining);
- +
- + return 0;
- +}
- +
- +static int fwu_write_f34_v5v6_blocks(unsigned char *block_ptr,
- + unsigned short block_cnt, unsigned char command)
- +{
- + int retval;
- + unsigned char data_base;
- + unsigned char block_number[] = {0, 0};
- + unsigned short blk;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + data_base = fwu->f34_fd.data_base_addr;
- +
- + block_number[1] |= (fwu->config_area << 5);
- +
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + data_base + fwu->off.block_number,
- + block_number,
- + sizeof(block_number));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to write block number\n",
- + __func__);
- + return retval;
- + }
- +
- + for (blk = 0; blk < block_cnt; blk++) {
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + data_base + fwu->off.payload,
- + block_ptr,
- + fwu->block_size);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to write block data (block %d)\n",
- + __func__, blk);
- + return retval;
- + }
- +
- + retval = fwu_write_f34_command(command);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to write command for block %d\n",
- + __func__, blk);
- + return retval;
- + }
- +
- + retval = fwu_wait_for_idle(WRITE_WAIT_MS, false);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to wait for idle status (block %d)\n",
- + __func__, blk);
- + return retval;
- + }
- +
- + block_ptr += fwu->block_size;
- + }
- +
- + return 0;
- +}
- +
- +static int fwu_write_f34_blocks(unsigned char *block_ptr,
- + unsigned short block_cnt, unsigned char cmd)
- +{
- + int retval;
- +
- + if (fwu->bl_version == BL_V7 || fwu->bl_version == BL_V8)
- + retval = fwu_write_f34_v7_blocks(block_ptr, block_cnt, cmd);
- + else
- + retval = fwu_write_f34_v5v6_blocks(block_ptr, block_cnt, cmd);
- +
- + return retval;
- +}
- +
- +static int fwu_read_f34_v7_blocks(unsigned short block_cnt,
- + unsigned char command)
- +{
- + int retval;
- + unsigned char data_base;
- + unsigned char length[2];
- + unsigned short transfer;
- + unsigned short remaining = block_cnt;
- + unsigned short block_number = 0;
- + unsigned short index = 0;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + data_base = fwu->f34_fd.data_base_addr;
- +
- + retval = fwu_write_f34_partition_id(command);
- + if (retval < 0)
- + return retval;
- +
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + data_base + fwu->off.block_number,
- + (unsigned char *)&block_number,
- + sizeof(block_number));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to write block number\n",
- + __func__);
- + return retval;
- + }
- +
- + do {
- + if (remaining / fwu->payload_length)
- + transfer = fwu->payload_length;
- + else
- + transfer = remaining;
- +
- + length[0] = (unsigned char)(transfer & MASK_8BIT);
- + length[1] = (unsigned char)(transfer >> 8);
- +
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + data_base + fwu->off.transfer_length,
- + length,
- + sizeof(length));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to write transfer length (remaining = %d)\n",
- + __func__, remaining);
- + return retval;
- + }
- +
- + retval = fwu_write_f34_command(command);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to write command (remaining = %d)\n",
- + __func__, remaining);
- + return retval;
- + }
- +
- + retval = fwu_wait_for_idle(WRITE_WAIT_MS, true);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to wait for idle status (remaining = %d)\n",
- + __func__, remaining);
- + return retval;
- + }
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + data_base + fwu->off.payload,
- + &fwu->read_config_buf[index],
- + transfer * fwu->block_size);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to read block data (remaining = %d)\n",
- + __func__, remaining);
- + return retval;
- + }
- +
- + index += (transfer * fwu->block_size);
- + remaining -= transfer;
- + } while (remaining);
- +
- + return 0;
- +}
- +
- +static int fwu_read_f34_v5v6_blocks(unsigned short block_cnt,
- + unsigned char command)
- +{
- + int retval;
- + unsigned char data_base;
- + unsigned char block_number[] = {0, 0};
- + unsigned short blk;
- + unsigned short index = 0;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + data_base = fwu->f34_fd.data_base_addr;
- +
- + block_number[1] |= (fwu->config_area << 5);
- +
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + data_base + fwu->off.block_number,
- + block_number,
- + sizeof(block_number));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to write block number\n",
- + __func__);
- + return retval;
- + }
- +
- + for (blk = 0; blk < block_cnt; blk++) {
- + retval = fwu_write_f34_command(command);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to write read config command\n",
- + __func__);
- + return retval;
- + }
- +
- + retval = fwu_wait_for_idle(WRITE_WAIT_MS, true);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to wait for idle status\n",
- + __func__);
- + return retval;
- + }
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + data_base + fwu->off.payload,
- + &fwu->read_config_buf[index],
- + fwu->block_size);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to read block data (block %d)\n",
- + __func__, blk);
- + return retval;
- + }
- +
- + index += fwu->block_size;
- + }
- +
- + return 0;
- +}
- +
- +static int fwu_read_f34_blocks(unsigned short block_cnt, unsigned char cmd)
- +{
- + int retval;
- +
- + if (fwu->bl_version == BL_V7 || fwu->bl_version == BL_V8)
- + retval = fwu_read_f34_v7_blocks(block_cnt, cmd);
- + else
- + retval = fwu_read_f34_v5v6_blocks(block_cnt, cmd);
- +
- + return retval;
- +}
- +
- +static int fwu_read_f34_guest_serialization_partition(void)
- +{
- + int retval = 0;
- + unsigned short block_count;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + fwu->config_area = PM_CONFIG_AREA;
- + if (!fwu->flash_properties.has_pm_config) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Permanent configuration not supported\n",
- + __func__);
- + return -EINVAL;
- + }
- + block_count = fwu->blkcount.pm_config;
- +
- + fwu->config_size = fwu->block_size * block_count;
- + kfree(fwu->read_config_buf);
- + fwu->read_config_buf = kzalloc(fwu->config_size, GFP_KERNEL);
- + if (!fwu->read_config_buf) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to alloc mem for fwu->read_config_buf\n",
- + __func__);
- + fwu->read_config_buf_size = 0;
- + retval = -ENOMEM;
- + return retval;
- + }
- + fwu->read_config_buf_size = fwu->config_size;
- +
- + retval = fwu_read_f34_blocks(block_count, CMD_READ_CONFIG);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to get guest serialization partition\n",
- + __func__);
- + return retval;
- + }
- +
- + secure_memcpy(rmi4_data->lockdown_info, LOCKDOWN_INFO_SIZE,
- + fwu->read_config_buf, fwu->read_config_buf_size, LOCKDOWN_INFO_SIZE);
- +
- + dev_info(rmi4_data->pdev->dev.parent,
- + "%s: Lockdown info: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
- + __func__, fwu->read_config_buf[0], fwu->read_config_buf[1],
- + fwu->read_config_buf[2], fwu->read_config_buf[3],
- + fwu->read_config_buf[4], fwu->read_config_buf[5],
- + fwu->read_config_buf[6], fwu->read_config_buf[7]);
- +
- + return retval;
- +}
- +
- +static int fwu_get_image_firmware_id(unsigned int *fw_id)
- +{
- + int retval;
- + unsigned char index = 0;
- + char *strptr;
- + char *firmware_id;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + if (fwu->img.contains_firmware_id) {
- + *fw_id = fwu->img.firmware_id;
- + } else {
- + strptr = strnstr(fwu->image_name, "PR", MAX_IMAGE_NAME_LEN);
- + if (!strptr) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: No valid PR number (PRxxxxxxx) "
- + "found in image file name (%s)\n",
- + __func__, fwu->image_name);
- + return -EINVAL;
- + }
- +
- + strptr += 2;
- + firmware_id = kzalloc(MAX_FIRMWARE_ID_LEN, GFP_KERNEL);
- + if (!firmware_id) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to alloc mem for firmware_id\n",
- + __func__);
- + return -ENOMEM;
- + }
- + while (strptr[index] >= '0' && strptr[index] <= '9') {
- + firmware_id[index] = strptr[index];
- + index++;
- + }
- +
- + retval = sstrtoul(firmware_id, 10, (unsigned long *)fw_id);
- + kfree(firmware_id);
- + if (retval) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to obtain image firmware ID\n",
- + __func__);
- + return -EINVAL;
- + }
- + }
- +
- + return 0;
- +}
- +
- +static int fwu_get_device_config_id(void)
- +{
- + int retval;
- + unsigned char config_id_size;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + if (fwu->bl_version == BL_V7 || fwu->bl_version == BL_V8)
- + config_id_size = V7_CONFIG_ID_SIZE;
- + else
- + config_id_size = V5V6_CONFIG_ID_SIZE;
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + fwu->f34_fd.ctrl_base_addr,
- + fwu->config_id,
- + config_id_size);
- + if (retval < 0)
- + return retval;
- +
- + return 0;
- +}
- +
- +static enum flash_area fwu_go_nogo(void)
- +{
- + int retval;
- + enum flash_area flash_area = NONE;
- + unsigned char ii;
- + unsigned char config_id_size;
- + unsigned int device_fw_id;
- + unsigned int image_fw_id;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + if (fwu->force_update) {
- + flash_area = UI_FIRMWARE;
- + goto exit;
- + }
- +
- + /* Update both UI and config if device is in bootloader mode */
- + if (fwu->bl_mode_device) {
- + flash_area = UI_FIRMWARE;
- + goto exit;
- + }
- +
- + /* Get device firmware ID */
- + device_fw_id = rmi4_data->firmware_id;
- + dev_info(rmi4_data->pdev->dev.parent,
- + "%s: Device firmware ID = %d\n",
- + __func__, device_fw_id);
- +
- + /* Get image firmware ID */
- + retval = fwu_get_image_firmware_id(&image_fw_id);
- + if (retval < 0) {
- + flash_area = NONE;
- + goto exit;
- + }
- + dev_info(rmi4_data->pdev->dev.parent,
- + "%s: Image firmware ID = %d\n",
- + __func__, image_fw_id);
- +
- + if (image_fw_id != device_fw_id) {
- + flash_area = UI_FIRMWARE;
- + goto exit;
- + }
- +
- + /* Get device config ID */
- + retval = fwu_get_device_config_id();
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to read device config ID\n",
- + __func__);
- + flash_area = NONE;
- + goto exit;
- + }
- +
- + if (fwu->bl_version == BL_V7 || fwu->bl_version == BL_V8)
- + config_id_size = V7_CONFIG_ID_SIZE;
- + else
- + config_id_size = V5V6_CONFIG_ID_SIZE;
- +
- + for (ii = 0; ii < config_id_size; ii++) {
- + if (fwu->img.ui_config.data[ii] != fwu->config_id[ii]) {
- + flash_area = UI_CONFIG;
- + goto exit;
- + }
- + }
- +
- + flash_area = NONE;
- +
- +exit:
- + if (flash_area == NONE) {
- + dev_info(rmi4_data->pdev->dev.parent,
- + "%s: No need to do reflash\n",
- + __func__);
- + } else {
- + dev_info(rmi4_data->pdev->dev.parent,
- + "%s: Updating %s\n",
- + __func__,
- + flash_area == UI_FIRMWARE ?
- + "UI firmware and config" :
- + "UI config only");
- + }
- +
- + return flash_area;
- +}
- +
- +static int fwu_scan_pdt(void)
- +{
- + int retval;
- + unsigned char ii;
- + unsigned char intr_count = 0;
- + unsigned char intr_off;
- + unsigned char intr_src;
- + unsigned short addr;
- + bool f01found = false;
- + bool f34found = false;
- + bool f35found = false;
- + struct synaptics_rmi4_fn_desc rmi_fd;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + fwu->in_ub_mode = false;
- +
- + for (addr = PDT_START; addr > PDT_END; addr -= PDT_ENTRY_SIZE) {
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + addr,
- + (unsigned char *)&rmi_fd,
- + sizeof(rmi_fd));
- + if (retval < 0)
- + return retval;
- +
- + if (rmi_fd.fn_number) {
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: Found F%02x\n",
- + __func__, rmi_fd.fn_number);
- + switch (rmi_fd.fn_number) {
- + case SYNAPTICS_RMI4_F01:
- + f01found = true;
- +
- + rmi4_data->f01_query_base_addr =
- + rmi_fd.query_base_addr;
- + rmi4_data->f01_ctrl_base_addr =
- + rmi_fd.ctrl_base_addr;
- + rmi4_data->f01_data_base_addr =
- + rmi_fd.data_base_addr;
- + rmi4_data->f01_cmd_base_addr =
- + rmi_fd.cmd_base_addr;
- + break;
- + case SYNAPTICS_RMI4_F34:
- + f34found = true;
- + fwu->f34_fd.query_base_addr =
- + rmi_fd.query_base_addr;
- + fwu->f34_fd.ctrl_base_addr =
- + rmi_fd.ctrl_base_addr;
- + fwu->f34_fd.data_base_addr =
- + rmi_fd.data_base_addr;
- +
- + switch (rmi_fd.fn_version) {
- + case F34_V0:
- + fwu->bl_version = BL_V5;
- + break;
- + case F34_V1:
- + fwu->bl_version = BL_V6;
- + break;
- + case F34_V2:
- + fwu->bl_version = BL_V7;
- + break;
- + default:
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Unrecognized F34 version\n",
- + __func__);
- + return -EINVAL;
- + }
- +
- + fwu->intr_mask = 0;
- + intr_src = rmi_fd.intr_src_count;
- + intr_off = intr_count % 8;
- + for (ii = intr_off;
- + ii < (intr_src + intr_off);
- + ii++) {
- + fwu->intr_mask |= 1 << ii;
- + }
- + break;
- + case SYNAPTICS_RMI4_F35:
- + f35found = true;
- + fwu->f35_fd.query_base_addr =
- + rmi_fd.query_base_addr;
- + fwu->f35_fd.ctrl_base_addr =
- + rmi_fd.ctrl_base_addr;
- + fwu->f35_fd.data_base_addr =
- + rmi_fd.data_base_addr;
- + fwu->f35_fd.cmd_base_addr =
- + rmi_fd.cmd_base_addr;
- + break;
- + }
- + } else {
- + break;
- + }
- +
- + intr_count += rmi_fd.intr_src_count;
- + }
- +
- + if (!f01found || !f34found) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to find both F01 and F34\n",
- + __func__);
- + if (!f35found) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to find F35\n",
- + __func__);
- + return -EINVAL;
- + } else {
- + fwu->in_ub_mode = true;
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: In microbootloader mode\n",
- + __func__);
- + fwu_recovery_check_status();
- + return 0;
- + }
- + }
- +
- + rmi4_data->intr_mask[0] |= fwu->intr_mask;
- +
- + addr = rmi4_data->f01_ctrl_base_addr + 1;
- +
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + addr,
- + &(rmi4_data->intr_mask[0]),
- + sizeof(rmi4_data->intr_mask[0]));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to set interrupt enable bit\n",
- + __func__);
- + return retval;
- + }
- +
- + return 0;
- +}
- +
- +static int fwu_enter_flash_prog(void)
- +{
- + int retval;
- + struct f01_device_control f01_device_control;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + retval = fwu_read_flash_status();
- + if (retval < 0)
- + return retval;
- +
- + if (fwu->in_bl_mode)
- + return 0;
- +
- + retval = rmi4_data->irq_enable(rmi4_data, false, true);
- + if (retval < 0)
- + return retval;
- +
- + msleep(INT_DISABLE_WAIT_MS);
- +
- + retval = fwu_write_f34_command(CMD_ENABLE_FLASH_PROG);
- + if (retval < 0)
- + return retval;
- +
- + retval = fwu_wait_for_idle(ENABLE_WAIT_MS, false);
- + if (retval < 0)
- + return retval;
- +
- + if (!fwu->in_bl_mode) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: BL mode not entered\n",
- + __func__);
- + return -EINVAL;
- + }
- +
- + if (rmi4_data->hw_if->bl_hw_init) {
- + retval = rmi4_data->hw_if->bl_hw_init(rmi4_data);
- + if (retval < 0)
- + return retval;
- + }
- +
- + retval = fwu_scan_pdt();
- + if (retval < 0)
- + return retval;
- +
- + pr_err("%s: fwu->in_ub_mode = %d\n", __func__, fwu->in_ub_mode);
- +
- + retval = fwu_read_f34_queries();
- + if (retval < 0)
- + return retval;
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + rmi4_data->f01_ctrl_base_addr,
- + f01_device_control.data,
- + sizeof(f01_device_control.data));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to read F01 device control\n",
- + __func__);
- + return retval;
- + }
- +
- + f01_device_control.nosleep = true;
- + f01_device_control.sleep_mode = SLEEP_MODE_NORMAL;
- +
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + rmi4_data->f01_ctrl_base_addr,
- + f01_device_control.data,
- + sizeof(f01_device_control.data));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to write F01 device control\n",
- + __func__);
- + return retval;
- + }
- +
- + msleep(ENTER_FLASH_PROG_WAIT_MS);
- +
- + return retval;
- +}
- +
- +static int fwu_check_ui_firmware_size(void)
- +{
- + unsigned short block_count;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + block_count = fwu->img.ui_firmware.size / fwu->block_size;
- +
- + if (block_count != fwu->blkcount.ui_firmware) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: UI firmware size mismatch\n",
- + __func__);
- + return -EINVAL;
- + }
- +
- + return 0;
- +}
- +
- +static int fwu_check_ui_configuration_size(void)
- +{
- + unsigned short block_count;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + block_count = fwu->img.ui_config.size / fwu->block_size;
- +
- + if (block_count != fwu->blkcount.ui_config) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: UI configuration size mismatch\n",
- + __func__);
- + return -EINVAL;
- + }
- +
- + return 0;
- +}
- +
- +static int fwu_check_dp_configuration_size(void)
- +{
- + unsigned short block_count;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + block_count = fwu->img.dp_config.size / fwu->block_size;
- +
- + if (block_count != fwu->blkcount.dp_config) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Display configuration size mismatch\n",
- + __func__);
- + return -EINVAL;
- + }
- +
- + return 0;
- +}
- +
- +static int fwu_check_pm_configuration_size(void)
- +{
- + unsigned short block_count;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + block_count = fwu->img.pm_config.size / fwu->block_size;
- +
- + if (block_count != fwu->blkcount.pm_config) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Permanent configuration size mismatch\n",
- + __func__);
- + return -EINVAL;
- + }
- +
- + return 0;
- +}
- +
- +static int fwu_check_bl_configuration_size(void)
- +{
- + unsigned short block_count;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + block_count = fwu->img.bl_config.size / fwu->block_size;
- +
- + if (block_count != fwu->blkcount.bl_config) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Bootloader configuration size mismatch\n",
- + __func__);
- + return -EINVAL;
- + }
- +
- + return 0;
- +}
- +
- +static int fwu_check_guest_code_size(void)
- +{
- + unsigned short block_count;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + block_count = fwu->img.guest_code.size / fwu->block_size;
- + if (block_count != fwu->blkcount.guest_code) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Guest code size mismatch\n",
- + __func__);
- + return -EINVAL;
- + }
- +
- + return 0;
- +}
- +
- +static int fwu_erase_configuration(void)
- +{
- + int retval;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + switch (fwu->config_area) {
- + case UI_CONFIG_AREA:
- + retval = fwu_write_f34_command(CMD_ERASE_UI_CONFIG);
- + if (retval < 0)
- + return retval;
- + break;
- + case DP_CONFIG_AREA:
- + retval = fwu_write_f34_command(CMD_ERASE_DISP_CONFIG);
- + if (retval < 0)
- + return retval;
- + break;
- + case BL_CONFIG_AREA:
- + retval = fwu_write_f34_command(CMD_ERASE_BL_CONFIG);
- + if (retval < 0)
- + return retval;
- + break;
- + case FLASH_CONFIG_AREA:
- + retval = fwu_write_f34_command(CMD_ERASE_FLASH_CONFIG);
- + if (retval < 0)
- + return retval;
- + break;
- + default:
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Invalid config area\n",
- + __func__);
- + return -EINVAL;
- + }
- +
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: Erase command written\n",
- + __func__);
- +
- + retval = fwu_wait_for_idle(ERASE_WAIT_MS, false);
- + if (retval < 0)
- + return retval;
- +
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: Idle status detected\n",
- + __func__);
- +
- + return retval;
- +}
- +
- +static int fwu_erase_bootloader(void)
- +{
- + int retval;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + retval = fwu_write_f34_command(CMD_ERASE_BOOTLOADER);
- + if (retval < 0)
- + return retval;
- +
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: Erase command written\n",
- + __func__);
- +
- + retval = fwu_wait_for_idle(ERASE_WAIT_MS, false);
- + if (retval < 0)
- + return retval;
- +
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: Idle status detected\n",
- + __func__);
- +
- + return 0;
- +}
- +
- +static int fwu_erase_utility_parameter(void)
- +{
- + int retval;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + retval = fwu_write_f34_command(CMD_ERASE_UTILITY_PARAMETER);
- + if (retval < 0)
- + return retval;
- +
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: Erase command written\n",
- + __func__);
- +
- + retval = fwu_wait_for_idle(ERASE_WAIT_MS, false);
- + if (retval < 0)
- + return retval;
- +
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: Idle status detected\n",
- + __func__);
- +
- + return 0;
- +}
- +
- +static int fwu_erase_guest_code(void)
- +{
- + int retval;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + retval = fwu_write_f34_command(CMD_ERASE_GUEST_CODE);
- + if (retval < 0)
- + return retval;
- +
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: Erase command written\n",
- + __func__);
- +
- + retval = fwu_wait_for_idle(ERASE_WAIT_MS, false);
- + if (retval < 0)
- + return retval;
- +
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: Idle status detected\n",
- + __func__);
- +
- + return 0;
- +}
- +
- +static int fwu_erase_all(void)
- +{
- + int retval;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + if (fwu->bl_version == BL_V7) {
- + fwu->config_area = INVALID_CONFIG_AREA;
- + retval = fwu_write_f34_command(CMD_ERASE_UI_FIRMWARE);
- + if (retval < 0)
- + return retval;
- +
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: Erase command written\n",
- + __func__);
- +
- + retval = fwu_wait_for_idle(ERASE_WAIT_MS, false);
- + if (retval < 0)
- + return retval;
- +
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: Idle status detected\n",
- + __func__);
- +
- + pr_err("erased core code\n");
- +
- + fwu->config_area = UI_CONFIG_AREA;
- + retval = fwu_erase_configuration();
- + if (retval < 0)
- + return retval;
- +
- + pr_err("erased core config\n");
- + } else {
- + retval = fwu_write_f34_command(CMD_ERASE_ALL);
- + if (retval < 0)
- + return retval;
- +
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: Erase all command written\n",
- + __func__);
- +
- + retval = fwu_wait_for_idle(ERASE_WAIT_MS, false);
- + if (!(fwu->bl_version == BL_V8 &&
- + fwu->flash_status == BAD_PARTITION_TABLE)) {
- + if (retval < 0)
- + return retval;
- + }
- +
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: Idle status detected\n",
- + __func__);
- +
- + if (fwu->bl_version == BL_V8)
- + return 0;
- + }
- +
- + if (fwu->flash_properties.has_disp_config &&
- + fwu->img.contains_disp_config) {
- + fwu->config_area = DP_CONFIG_AREA;
- + retval = fwu_erase_configuration();
- + if (retval < 0)
- + return retval;
- + }
- +
- + if (fwu->has_guest_code && fwu->img.contains_guest_code) {
- + retval = fwu_erase_guest_code();
- + if (retval < 0)
- + return retval;
- + }
- +
- + return 0;
- +}
- +
- +static int fwu_write_firmware(void)
- +{
- + unsigned short firmware_block_count;
- +
- + firmware_block_count = fwu->img.ui_firmware.size / fwu->block_size;
- +
- + pr_err("core code block count = %d\n", firmware_block_count);
- +
- + return fwu_write_f34_blocks((unsigned char *)fwu->img.ui_firmware.data,
- + firmware_block_count, CMD_WRITE_FW);
- +}
- +
- +static int fwu_write_bootloader(void)
- +{
- + int retval;
- + unsigned short bootloader_block_count;
- +
- + bootloader_block_count = fwu->img.bl_image.size / fwu->block_size;
- +
- + pr_err("bootloader block count = %d\n", bootloader_block_count);
- +
- + fwu->write_bootloader = true;
- + retval = fwu_write_f34_blocks((unsigned char *)fwu->img.bl_image.data,
- + bootloader_block_count, CMD_WRITE_BOOTLOADER);
- + fwu->write_bootloader = false;
- +
- + return retval;
- +}
- +
- +static int fwu_write_utility_parameter(void)
- +{
- + int retval;
- + unsigned char ii;
- + unsigned char checksum_array[4];
- + unsigned char *pbuf;
- + unsigned short remaining_size;
- + unsigned short utility_param_size;
- + unsigned long checksum;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + utility_param_size = fwu->blkcount.utility_param * fwu->block_size;
- + retval = fwu_allocate_read_config_buf(utility_param_size);
- + if (retval < 0)
- + return retval;
- + memset(fwu->read_config_buf, 0x00, utility_param_size);
- +
- + pbuf = fwu->read_config_buf;
- + remaining_size = utility_param_size - 4;
- +
- + for (ii = 0; ii < MAX_UTILITY_PARAMS; ii++) {
- + if (fwu->img.utility_param_id[ii] == UNUSED)
- + continue;
- +
- +#ifdef F51_DISCRETE_FORCE
- + if (fwu->img.utility_param_id[ii] == FORCE_PARAMETER) {
- + if (fwu->bl_mode_device) {
- + dev_info(rmi4_data->pdev->dev.parent,
- + "%s: Device in bootloader mode, skipping calibration data restoration\n",
- + __func__);
- + goto image_param;
- + }
- + retval = secure_memcpy(&(pbuf[4]),
- + remaining_size - 4,
- + fwu->cal_data,
- + fwu->cal_data_buf_size,
- + fwu->cal_data_size);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to copy force calibration data\n",
- + __func__);
- + return retval;
- + }
- + pbuf[0] = FORCE_PARAMETER;
- + pbuf[1] = 0x00;
- + pbuf[2] = (4 + fwu->cal_data_size) / 2;
- + pbuf += (fwu->cal_data_size + 4);
- + remaining_size -= (fwu->cal_data_size + 4);
- + continue;
- + }
- +image_param:
- +#endif
- +
- + retval = secure_memcpy(pbuf,
- + remaining_size,
- + fwu->img.utility_param[ii].data,
- + fwu->img.utility_param[ii].size,
- + fwu->img.utility_param[ii].size);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to copy utility parameter data\n",
- + __func__);
- + return retval;
- + }
- + pbuf += fwu->img.utility_param[ii].size;
- + remaining_size -= fwu->img.utility_param[ii].size;
- + }
- +
- + calculate_checksum((unsigned short *)fwu->read_config_buf,
- + ((utility_param_size - 4) / 2),
- + &checksum);
- +
- + convert_to_little_endian(checksum_array, checksum);
- +
- + fwu->read_config_buf[utility_param_size - 4] = checksum_array[0];
- + fwu->read_config_buf[utility_param_size - 3] = checksum_array[1];
- + fwu->read_config_buf[utility_param_size - 2] = checksum_array[2];
- + fwu->read_config_buf[utility_param_size - 1] = checksum_array[3];
- +
- + pr_err("utility parameter block count = %d\n", fwu->blkcount.utility_param);
- +
- + retval = fwu_write_f34_blocks((unsigned char *)fwu->read_config_buf,
- + fwu->blkcount.utility_param, CMD_WRITE_UTILITY_PARAM);
- + if (retval < 0)
- + return retval;
- +
- + return 0;
- +}
- +
- +static int fwu_write_configuration(void)
- +{
- + return fwu_write_f34_blocks((unsigned char *)fwu->config_data,
- + fwu->config_block_count, CMD_WRITE_CONFIG);
- +}
- +
- +static int fwu_write_ui_configuration(void)
- +{
- + fwu->config_area = UI_CONFIG_AREA;
- + fwu->config_data = fwu->img.ui_config.data;
- + fwu->config_size = fwu->img.ui_config.size;
- + fwu->config_block_count = fwu->config_size / fwu->block_size;
- +
- + pr_err("core config block count = %d\n", fwu->config_block_count);
- +
- + return fwu_write_configuration();
- +}
- +
- +static int fwu_write_dp_configuration(void)
- +{
- + fwu->config_area = DP_CONFIG_AREA;
- + fwu->config_data = fwu->img.dp_config.data;
- + fwu->config_size = fwu->img.dp_config.size;
- + fwu->config_block_count = fwu->config_size / fwu->block_size;
- +
- + return fwu_write_configuration();
- +}
- +
- +static int fwu_write_pm_configuration(void)
- +{
- + fwu->config_area = PM_CONFIG_AREA;
- + fwu->config_data = fwu->img.pm_config.data;
- + fwu->config_size = fwu->img.pm_config.size;
- + fwu->config_block_count = fwu->config_size / fwu->block_size;
- +
- + return fwu_write_configuration();
- +}
- +
- +static int fwu_write_flash_configuration(void)
- +{
- + int retval;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + fwu->config_area = FLASH_CONFIG_AREA;
- + fwu->config_data = fwu->img.fl_config.data;
- + fwu->config_size = fwu->img.fl_config.size;
- + fwu->config_block_count = fwu->config_size / fwu->block_size;
- +
- + if (fwu->config_block_count != fwu->blkcount.fl_config) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Flash configuration size mismatch\n",
- + __func__);
- + return -EINVAL;
- + }
- +
- + retval = fwu_erase_configuration();
- + if (retval < 0)
- + return retval;
- +
- + retval = fwu_write_configuration();
- + if (retval < 0)
- + return retval;
- +
- + rmi4_data->reset_device(rmi4_data, false);
- +
- + return 0;
- +}
- +
- +static int fwu_write_guest_code(void)
- +{
- + int retval;
- + unsigned short guest_code_block_count;
- +
- + guest_code_block_count = fwu->img.guest_code.size / fwu->block_size;
- +
- + retval = fwu_write_f34_blocks((unsigned char *)fwu->img.guest_code.data,
- + guest_code_block_count, CMD_WRITE_GUEST_CODE);
- + if (retval < 0)
- + return retval;
- +
- + return 0;
- +}
- +
- +static int fwu_write_lockdown(void)
- +{
- + unsigned short lockdown_block_count;
- +
- + lockdown_block_count = fwu->img.lockdown.size / fwu->block_size;
- +
- + return fwu_write_f34_blocks((unsigned char *)fwu->img.lockdown.data,
- + lockdown_block_count, CMD_WRITE_LOCKDOWN);
- +}
- +
- +static int fwu_write_partition_table_v8(void)
- +{
- + int retval;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + fwu->config_area = FLASH_CONFIG_AREA;
- + fwu->config_data = fwu->img.fl_config.data;
- + fwu->config_size = fwu->img.fl_config.size;
- + fwu->config_block_count = fwu->config_size / fwu->block_size;
- +
- + if (fwu->config_block_count != fwu->blkcount.fl_config) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Flash configuration size mismatch\n",
- + __func__);
- + return -EINVAL;
- + }
- +
- + retval = fwu_write_configuration();
- + if (retval < 0)
- + return retval;
- +
- + rmi4_data->reset_device(rmi4_data, false);
- +
- + return 0;
- +}
- +
- +static int fwu_write_partition_table_v7(void)
- +{
- + int retval;
- + unsigned short block_count;
- +
- + block_count = fwu->blkcount.bl_config;
- + fwu->config_area = BL_CONFIG_AREA;
- + fwu->config_size = fwu->block_size * block_count;
- +
- + retval = fwu_allocate_read_config_buf(fwu->config_size);
- + if (retval < 0)
- + return retval;
- +
- + retval = fwu_read_f34_blocks(block_count, CMD_READ_CONFIG);
- + if (retval < 0)
- + return retval;
- +
- + retval = fwu_erase_configuration();
- + if (retval < 0)
- + return retval;
- +
- + retval = fwu_write_flash_configuration();
- + if (retval < 0)
- + return retval;
- +
- + fwu->config_area = BL_CONFIG_AREA;
- + fwu->config_data = fwu->read_config_buf;
- + fwu->config_size = fwu->img.bl_config.size;
- + fwu->config_block_count = fwu->config_size / fwu->block_size;
- +
- + retval = fwu_write_configuration();
- + if (retval < 0)
- + return retval;
- +
- + return 0;
- +}
- +
- +static int fwu_write_bl_area_v7(void)
- +{
- + int retval;
- + bool has_utility_param;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + has_utility_param = fwu->has_utility_param;
- +
- + if (fwu->has_utility_param) {
- + retval = fwu_erase_utility_parameter();
- + if (retval < 0)
- + return retval;
- +
- + pr_err("erased utility parameter\n");
- + }
- +
- + fwu->config_area = BL_CONFIG_AREA;
- + retval = fwu_erase_configuration();
- + if (retval < 0)
- + return retval;
- +
- + pr_err("erased bootloader config\n");
- +
- + fwu->config_area = FLASH_CONFIG_AREA;
- + retval = fwu_erase_configuration();
- + if (retval < 0)
- + return retval;
- +
- + pr_err("erased flash config\n");
- +
- + retval = fwu_erase_bootloader();
- + if (retval < 0)
- + return retval;
- +
- + pr_err("erased bootloader\n");
- +
- + retval = fwu_write_bootloader();
- + if (retval < 0)
- + return retval;
- +
- + pr_err("bootloader written\n");
- +
- + msleep(rmi4_data->hw_if->board_data->reset_delay_ms);
- + rmi4_data->reset_device(rmi4_data, false);
- +
- + pr_err("reset after writing bootloader\n");
- +
- + fwu->config_area = FLASH_CONFIG_AREA;
- + fwu->config_data = fwu->img.fl_config.data;
- + fwu->config_size = fwu->img.fl_config.size;
- + fwu->config_block_count = fwu->config_size / fwu->block_size;
- + pr_err("flash config block count = %d\n", fwu->config_block_count);
- + retval = fwu_write_configuration();
- + if (retval < 0)
- + return retval;
- +
- + pr_err("flash config written\n");
- +
- + rmi4_data->reset_device(rmi4_data, false);
- +
- + pr_err("reset after writing flash config\n");
- +
- + fwu->config_area = BL_CONFIG_AREA;
- + fwu->config_data = fwu->img.bl_config.data;
- + fwu->config_size = fwu->img.bl_config.size;
- + fwu->config_block_count = fwu->config_size / fwu->block_size;
- + pr_err("bootloader config block count = %d\n", fwu->config_block_count);
- + retval = fwu_write_configuration();
- + if (retval < 0)
- + return retval;
- +
- + pr_err("bootloader config written\n");
- +
- + if (fwu->img.contains_utility_param) {
- + retval = fwu_write_utility_parameter();
- + if (retval < 0)
- + return retval;
- +
- + pr_err("utility parameter written\n");
- + }
- +
- + return 0;
- +}
- +
- +static int fwu_do_reflash(void)
- +{
- + int retval;
- + bool do_bl_update = false;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + if (!fwu->new_partition_table) {
- + retval = fwu_check_ui_firmware_size();
- + if (retval < 0)
- + return retval;
- +
- + retval = fwu_check_ui_configuration_size();
- + if (retval < 0)
- + return retval;
- +
- + if (fwu->flash_properties.has_disp_config &&
- + fwu->img.contains_disp_config) {
- + retval = fwu_check_dp_configuration_size();
- + if (retval < 0)
- + return retval;
- + }
- +
- + if (fwu->has_guest_code && fwu->img.contains_guest_code) {
- + retval = fwu_check_guest_code_size();
- + if (retval < 0)
- + return retval;
- + }
- + } else if (fwu->bl_version == BL_V7) {
- + retval = fwu_check_bl_configuration_size();
- + if (retval < 0)
- + return retval;
- + }
- +
- + if (!fwu->has_utility_param && fwu->img.contains_utility_param) {
- + if (fwu->bl_version == BL_V7 || fwu->bl_version == BL_V8)
- + do_bl_update = true;
- + }
- +
- + if (fwu->has_utility_param && !fwu->img.contains_utility_param) {
- + if (fwu->bl_version == BL_V7 || fwu->bl_version == BL_V8)
- + do_bl_update = true;
- + }
- +
- + pr_err("fwu->has_utility_param = %d\n", fwu->has_utility_param);
- + pr_err("fwu->img.contains_utility_param = %d\n", fwu->img.contains_utility_param);
- + pr_err("do_bl_update = %d\n", do_bl_update);
- +
- + if (!do_bl_update && fwu->incompatible_partition_tables) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Incompatible partition tables\n",
- + __func__);
- + return -EINVAL;
- + } else if (!do_bl_update && fwu->new_partition_table) {
- + if (!fwu->force_update) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Partition table mismatch\n",
- + __func__);
- + return -EINVAL;
- + }
- + }
- +
- + retval = fwu_erase_all();
- + if (retval < 0)
- + return retval;
- +
- + if (do_bl_update) {
- + retval = fwu_write_bl_area_v7();
- + if (retval < 0)
- + return retval;
- + pr_notice("%s: Bootloader area programmed\n", __func__);
- + } else if (fwu->bl_version == BL_V7 && fwu->new_partition_table) {
- + retval = fwu_write_partition_table_v7();
- + if (retval < 0)
- + return retval;
- + pr_notice("%s: Partition table programmed\n", __func__);
- + } else if (fwu->bl_version == BL_V8) {
- + retval = fwu_write_partition_table_v8();
- + if (retval < 0)
- + return retval;
- + pr_notice("%s: Partition table programmed\n", __func__);
- + }
- +
- + retval = fwu_write_firmware();
- + if (retval < 0)
- + return retval;
- + pr_notice("%s: Firmware programmed\n", __func__);
- +
- + fwu->config_area = UI_CONFIG_AREA;
- + retval = fwu_write_ui_configuration();
- + if (retval < 0)
- + return retval;
- + pr_notice("%s: Configuration programmed\n", __func__);
- +
- + if (fwu->flash_properties.has_disp_config &&
- + fwu->img.contains_disp_config) {
- + retval = fwu_write_dp_configuration();
- + if (retval < 0)
- + return retval;
- + pr_notice("%s: Display configuration programmed\n", __func__);
- + }
- +
- + if (fwu->has_guest_code && fwu->img.contains_guest_code) {
- + retval = fwu_write_guest_code();
- + if (retval < 0)
- + return retval;
- + pr_notice("%s: Guest code programmed\n", __func__);
- + }
- +
- + return retval;
- +}
- +
- +static int fwu_do_read_config(void)
- +{
- + int retval;
- + unsigned short block_count;
- + unsigned short config_area;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + switch (fwu->config_area) {
- + case UI_CONFIG_AREA:
- + block_count = fwu->blkcount.ui_config;
- + break;
- + case DP_CONFIG_AREA:
- + if (!fwu->flash_properties.has_disp_config) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Display configuration not supported\n",
- + __func__);
- + return -EINVAL;
- + }
- + block_count = fwu->blkcount.dp_config;
- + break;
- + case PM_CONFIG_AREA:
- + if (!fwu->flash_properties.has_pm_config) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Permanent configuration not supported\n",
- + __func__);
- + return -EINVAL;
- + }
- + block_count = fwu->blkcount.pm_config;
- + break;
- + case BL_CONFIG_AREA:
- + if (!fwu->flash_properties.has_bl_config) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Bootloader configuration not supported\n",
- + __func__);
- + return -EINVAL;
- + }
- + block_count = fwu->blkcount.bl_config;
- + break;
- + default:
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Invalid config area\n",
- + __func__);
- + return -EINVAL;
- + }
- +
- + if (block_count == 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Invalid block count\n",
- + __func__);
- + return -EINVAL;
- + }
- +
- + mutex_lock(&rmi4_data->rmi4_exp_init_mutex);
- +
- + if (fwu->bl_version == BL_V5 || fwu->bl_version == BL_V6) {
- + config_area = fwu->config_area;
- + retval = fwu_enter_flash_prog();
- + fwu->config_area = config_area;
- + if (retval < 0)
- + goto exit;
- + }
- +
- + fwu->config_size = fwu->block_size * block_count;
- +
- + retval = fwu_allocate_read_config_buf(fwu->config_size);
- + if (retval < 0)
- + goto exit;
- +
- + retval = fwu_read_f34_blocks(block_count, CMD_READ_CONFIG);
- +
- +exit:
- + if (fwu->bl_version == BL_V5 || fwu->bl_version == BL_V6)
- + rmi4_data->reset_device(rmi4_data, false);
- +
- + mutex_unlock(&rmi4_data->rmi4_exp_init_mutex);
- +
- + return retval;
- +}
- +
- +static int fwu_do_lockdown_v7(void)
- +{
- + int retval;
- + struct f34_v7_data0 status;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + retval = fwu_enter_flash_prog();
- + if (retval < 0)
- + return retval;
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + fwu->f34_fd.data_base_addr + fwu->off.flash_status,
- + status.data,
- + sizeof(status.data));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to read flash status\n",
- + __func__);
- + return retval;
- + }
- +
- + if (status.device_cfg_status == 2) {
- + dev_info(rmi4_data->pdev->dev.parent,
- + "%s: Device already locked down\n",
- + __func__);
- + return 0;
- + }
- +
- + retval = fwu_write_lockdown();
- + if (retval < 0)
- + return retval;
- +
- + pr_notice("%s: Lockdown programmed\n", __func__);
- +
- + return retval;
- +}
- +
- +static int fwu_do_lockdown_v5v6(void)
- +{
- + int retval;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + retval = fwu_enter_flash_prog();
- + if (retval < 0)
- + return retval;
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + fwu->f34_fd.query_base_addr + fwu->off.properties,
- + fwu->flash_properties.data,
- + sizeof(fwu->flash_properties.data));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to read flash properties\n",
- + __func__);
- + return retval;
- + }
- +
- + if (fwu->flash_properties.unlocked == 0) {
- + dev_info(rmi4_data->pdev->dev.parent,
- + "%s: Device already locked down\n",
- + __func__);
- + return 0;
- + }
- +
- + retval = fwu_write_lockdown();
- + if (retval < 0)
- + return retval;
- +
- + pr_notice("%s: Lockdown programmed\n", __func__);
- +
- + return retval;
- +}
- +
- +#ifdef F51_DISCRETE_FORCE
- +static int fwu_do_restore_f51_cal_data(void)
- +{
- + int retval;
- + unsigned char checksum_array[4];
- + unsigned short block_count;
- + unsigned long checksum;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + block_count = fwu->blkcount.ui_config;
- + fwu->config_size = fwu->block_size * block_count;
- + fwu->config_area = UI_CONFIG_AREA;
- +
- + retval = fwu_allocate_read_config_buf(fwu->config_size);
- + if (retval < 0)
- + return retval;
- +
- + retval = fwu_read_f34_blocks(block_count, CMD_READ_CONFIG);
- + if (retval < 0)
- + return retval;
- +
- + retval = secure_memcpy(&fwu->read_config_buf[fwu->cal_data_off],
- + fwu->cal_data_size, fwu->cal_data,
- + fwu->cal_data_buf_size, fwu->cal_data_size);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to restore calibration data\n",
- + __func__);
- + return retval;
- + }
- +
- + calculate_checksum((unsigned short *)fwu->read_config_buf,
- + ((fwu->config_size - 4) / 2),
- + &checksum);
- +
- + convert_to_little_endian(checksum_array, checksum);
- +
- + fwu->read_config_buf[fwu->config_size - 4] = checksum_array[0];
- + fwu->read_config_buf[fwu->config_size - 3] = checksum_array[1];
- + fwu->read_config_buf[fwu->config_size - 2] = checksum_array[2];
- + fwu->read_config_buf[fwu->config_size - 1] = checksum_array[3];
- +
- + retval = fwu_enter_flash_prog();
- + if (retval < 0)
- + return retval;
- +
- + fwu->config_area = UI_CONFIG_AREA;
- + fwu->config_data = fwu->read_config_buf;
- + fwu->config_block_count = fwu->config_size / fwu->block_size;
- +
- + retval = fwu_erase_configuration();
- + if (retval < 0)
- + return retval;
- +
- + retval = fwu_write_configuration();
- + if (retval < 0)
- + return retval;
- +
- + return 0;
- +}
- +#endif
- +
- +static int fwu_start_write_guest_code(void)
- +{
- + int retval;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + retval = fwu_parse_image_info();
- + if (retval < 0)
- + return -EINVAL;
- +
- + if (!fwu->has_guest_code) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Guest code not supported\n",
- + __func__);
- + return -EINVAL;
- + }
- +
- + if (!fwu->img.contains_guest_code) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: No guest code in firmware image\n",
- + __func__);
- + return -EINVAL;
- + }
- +
- + if (rmi4_data->sensor_sleep) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Sensor sleeping\n",
- + __func__);
- + return -ENODEV;
- + }
- +
- + rmi4_data->stay_awake = true;
- +
- + mutex_lock(&rmi4_data->rmi4_exp_init_mutex);
- +
- + pr_notice("%s: Start of write guest code process\n", __func__);
- +
- + retval = fwu_enter_flash_prog();
- + if (retval < 0)
- + goto exit;
- +
- + retval = fwu_check_guest_code_size();
- + if (retval < 0)
- + goto exit;
- +
- + retval = fwu_erase_guest_code();
- + if (retval < 0)
- + goto exit;
- +
- + retval = fwu_write_guest_code();
- + if (retval < 0)
- + goto exit;
- +
- + pr_notice("%s: Guest code programmed\n", __func__);
- +
- +exit:
- + rmi4_data->reset_device(rmi4_data, false);
- +
- + pr_notice("%s: End of write guest code process\n", __func__);
- +
- + mutex_unlock(&rmi4_data->rmi4_exp_init_mutex);
- +
- + rmi4_data->stay_awake = false;
- +
- + return retval;
- +}
- +
- +static int fwu_start_write_config(void)
- +{
- + int retval;
- + unsigned short config_area;
- + unsigned int device_fw_id;
- + unsigned int image_fw_id;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + retval = fwu_parse_image_info();
- + if (retval < 0)
- + return -EINVAL;
- +
- + switch (fwu->config_area) {
- + case UI_CONFIG_AREA:
- + device_fw_id = rmi4_data->firmware_id;
- + retval = fwu_get_image_firmware_id(&image_fw_id);
- + if (retval < 0)
- + return retval;
- + if (device_fw_id != image_fw_id) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Device and image firmware IDs don't match\n",
- + __func__);
- + return -EINVAL;
- + }
- + retval = fwu_check_ui_configuration_size();
- + if (retval < 0)
- + return retval;
- + break;
- + case DP_CONFIG_AREA:
- + if (!fwu->flash_properties.has_disp_config) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Display configuration not supported\n",
- + __func__);
- + return -EINVAL;
- + }
- + if (!fwu->img.contains_disp_config) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: No display configuration in firmware image\n",
- + __func__);
- + return -EINVAL;
- + }
- + retval = fwu_check_dp_configuration_size();
- + if (retval < 0)
- + return retval;
- + break;
- + case PM_CONFIG_AREA:
- + if (!fwu->flash_properties.has_pm_config) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Permanent configuration not supported\n",
- + __func__);
- + return -EINVAL;
- + }
- + if (!fwu->img.contains_perm_config) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: No permanent configuration in firmware image\n",
- + __func__);
- + return -EINVAL;
- + }
- + retval = fwu_check_pm_configuration_size();
- + if (retval < 0)
- + return retval;
- + break;
- + default:
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Configuration not supported\n",
- + __func__);
- + return -EINVAL;
- + }
- +
- + if (rmi4_data->sensor_sleep) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Sensor sleeping\n",
- + __func__);
- + return -ENODEV;
- + }
- +
- + rmi4_data->stay_awake = true;
- +
- + mutex_lock(&rmi4_data->rmi4_exp_init_mutex);
- +
- + pr_notice("%s: Start of write config process\n", __func__);
- +
- + config_area = fwu->config_area;
- +
- + retval = fwu_enter_flash_prog();
- + if (retval < 0)
- + goto exit;
- +
- + fwu->config_area = config_area;
- +
- + if (fwu->config_area != PM_CONFIG_AREA) {
- + retval = fwu_erase_configuration();
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to erase config\n",
- + __func__);
- + goto exit;
- + }
- + }
- +
- + switch (fwu->config_area) {
- + case UI_CONFIG_AREA:
- + retval = fwu_write_ui_configuration();
- + if (retval < 0)
- + goto exit;
- + break;
- + case DP_CONFIG_AREA:
- + retval = fwu_write_dp_configuration();
- + if (retval < 0)
- + goto exit;
- + break;
- + case PM_CONFIG_AREA:
- + retval = fwu_write_pm_configuration();
- + if (retval < 0)
- + goto exit;
- + break;
- + }
- +
- + pr_notice("%s: Config written\n", __func__);
- +
- +exit:
- + switch (fwu->config_area) {
- + case UI_CONFIG_AREA:
- + rmi4_data->reset_device(rmi4_data, true);
- + break;
- + case DP_CONFIG_AREA:
- + case PM_CONFIG_AREA:
- + rmi4_data->reset_device(rmi4_data, false);
- + break;
- + }
- +
- + pr_notice("%s: End of write config process\n", __func__);
- +
- + mutex_unlock(&rmi4_data->rmi4_exp_init_mutex);
- +
- + rmi4_data->stay_awake = false;
- +
- + return retval;
- +}
- +
- +static const char *fwu_get_firmware_name(struct synaptics_rmi4_data *rmi4_data)
- +{
- + const char *fw_name = NULL;
- + const struct synaptics_dsx_board_data *bdata =
- + rmi4_data->hw_if->board_data;
- + int i, j, def = -1;
- + bool found = false;
- +
- + if (bdata->tp_id_num != 0) {
- + for (i = 0; i < bdata->config_array_size; i++) {
- + found = true;
- + if (rmi4_data->chip_id != bdata->config_array[i].chip_id)
- + continue;
- + else
- + def = i;
- +
- + for (j = 0; j < bdata->tp_id_num; j++) {
- + if (bdata->config_array[i].tp_ids[j] !=
- + rmi4_data->lockdown_info[bdata->tp_id_bytes[j]]) {
- + found = false;
- + break;
- + }
- + }
- +
- + if (found) {
- + fw_name = bdata->config_array[i].fw_name;
- + break;
- + }
- + }
- + }
- +
- + if (!fw_name && (def >= 0))
- + fw_name = bdata->config_array[def].fw_name;
- +
- + dev_info(rmi4_data->pdev->dev.parent,
- + "%s: Choose firmware %s\n", __func__, fw_name);
- +
- + return fw_name;
- +}
- +
- +static int fwu_start_reflash(void)
- +{
- + int retval = 0;
- + enum flash_area flash_area;
- + bool do_rebuild = false;
- + const struct firmware *fw_entry = NULL;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- + const char *fw_name;
- +
- + if (rmi4_data->sensor_sleep) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Sensor sleeping\n",
- + __func__);
- + return -ENODEV;
- + }
- +
- + fw_name = fwu_get_firmware_name(rmi4_data);
- +
- + if (fw_name == NULL) {
- + dev_err(rmi4_data->pdev->dev.parent, "%s: do not found fw to update\n", __func__);
- +
- + return -EINVAL;
- + }
- +
- +
- + rmi4_data->stay_awake = true;
- +
- + mutex_lock(&rmi4_data->rmi4_exp_init_mutex);
- +
- + dev_info(rmi4_data->pdev->dev.parent, "%s: Start of reflash process\n", __func__);
- +
- + if (fwu->image == NULL) {
- + retval = secure_memcpy(fwu->image_name, MAX_IMAGE_NAME_LEN,
- + fw_name, sizeof(FW_IMAGE_NAME),
- + strlen(fw_name));
- +
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to copy image file name\n",
- + __func__);
- + goto exit;
- + }
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: Requesting firmware image %s\n",
- + __func__, fwu->image_name);
- +
- + retval = request_firmware(&fw_entry, fwu->image_name,
- + rmi4_data->pdev->dev.parent);
- + if (retval != 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Firmware image %s not available\n",
- + __func__, fwu->image_name);
- + retval = -EINVAL;
- + goto exit;
- + }
- +
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: Firmware image size = %ld\n",
- + __func__, fw_entry->size);
- +
- + fwu->image = fw_entry->data;
- + }
- +
- + retval = fwu_parse_image_info();
- + if (retval < 0)
- + goto exit;
- +
- + if (fwu->blkcount.total_count != fwu->img.blkcount.total_count) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Flash size mismatch\n",
- + __func__);
- + retval = -EINVAL;
- + goto exit;
- + }
- +
- + if (fwu->bl_version != fwu->img.bl_version) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Bootloader version mismatch\n",
- + __func__);
- + retval = -EINVAL;
- + goto exit;
- + }
- +
- + retval = fwu_read_flash_status();
- + if (retval < 0)
- + goto exit;
- +
- + if (fwu->in_bl_mode) {
- + fwu->bl_mode_device = true;
- + dev_info(rmi4_data->pdev->dev.parent,
- + "%s: Device in bootloader mode\n",
- + __func__);
- + } else {
- + fwu->bl_mode_device = false;
- + }
- +
- + flash_area = fwu_go_nogo();
- +
- + if (flash_area != NONE) {
- + retval = fwu_enter_flash_prog();
- + if (retval < 0) {
- + rmi4_data->reset_device(rmi4_data, false);
- + goto exit;
- + }
- + }
- +
- +#ifdef F51_DISCRETE_FORCE
- + if (flash_area != NONE && !fwu->bl_mode_device) {
- + fwu->config_size = fwu->block_size * fwu->blkcount.ui_config;
- + fwu->config_area = UI_CONFIG_AREA;
- +
- + retval = fwu_allocate_read_config_buf(fwu->config_size);
- + if (retval < 0) {
- + rmi4_data->reset_device(rmi4_data, false);
- + goto exit;
- + }
- +
- + retval = fwu_read_f34_blocks(fwu->blkcount.ui_config,
- + CMD_READ_CONFIG);
- + if (retval < 0) {
- + rmi4_data->reset_device(rmi4_data, false);
- + goto exit;
- + }
- +
- + retval = secure_memcpy(fwu->cal_data, fwu->cal_data_buf_size,
- + &fwu->read_config_buf[fwu->cal_data_off],
- + fwu->cal_data_size, fwu->cal_data_size);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to save calibration data\n",
- + __func__);
- + rmi4_data->reset_device(rmi4_data, false);
- + goto exit;
- + }
- + }
- +#endif
- +
- + switch (flash_area) {
- + case UI_FIRMWARE:
- + do_rebuild = true;
- + retval = fwu_do_reflash();
- +#ifdef F51_DISCRETE_FORCE
- + if (retval < 0)
- + break;
- +
- + if (fwu->has_utility_param || fwu->img.contains_utility_param)
- + break;
- +
- + rmi4_data->reset_device(rmi4_data, false);
- +
- + if (fwu->bl_mode_device || fwu->in_bl_mode) {
- + dev_info(rmi4_data->pdev->dev.parent,
- + "%s: Device in bootloader mode, skipping calibration data restoration\n",
- + __func__);
- + break;
- + }
- +
- + retval = fwu_do_restore_f51_cal_data();
- +#endif
- + break;
- + case UI_CONFIG:
- + do_rebuild = true;
- + retval = fwu_check_ui_configuration_size();
- + if (retval < 0)
- + break;
- + fwu->config_area = UI_CONFIG_AREA;
- + retval = fwu_erase_configuration();
- + if (retval < 0)
- + break;
- + retval = fwu_write_ui_configuration();
- +#ifdef F51_DISCRETE_FORCE
- + if (retval < 0)
- + break;
- +
- + if (fwu->has_utility_param)
- + break;
- +
- + retval = fwu_do_restore_f51_cal_data();
- +#endif
- + break;
- + case NONE:
- + default:
- + break;
- + }
- +
- + if (retval < 0) {
- + do_rebuild = false;
- + rmi4_data->reset_device(rmi4_data, false);
- + pr_err("%s: fwu->in_ub_mode = %d\n", __func__, fwu->in_ub_mode);
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to do reflash\n",
- + __func__);
- + goto exit;
- + }
- +
- + if (fwu->do_lockdown && (fwu->img.lockdown.data != NULL)) {
- + switch (fwu->bl_version) {
- + case BL_V5:
- + case BL_V6:
- + retval = fwu_do_lockdown_v5v6();
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to do lockdown\n",
- + __func__);
- + }
- + rmi4_data->reset_device(rmi4_data, false);
- + break;
- + case BL_V7:
- + case BL_V8:
- + retval = fwu_do_lockdown_v7();
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to do lockdown\n",
- + __func__);
- + }
- + rmi4_data->reset_device(rmi4_data, false);
- + break;
- + default:
- + break;
- + }
- + }
- +
- +exit:
- + if (fw_entry)
- + release_firmware(fw_entry);
- +
- + if (do_rebuild)
- + rmi4_data->reset_device(rmi4_data, true);
- +
- + pr_notice("%s: End of reflash process\n", __func__);
- +
- + mutex_unlock(&rmi4_data->rmi4_exp_init_mutex);
- +
- + rmi4_data->stay_awake = false;
- +
- + return retval;
- +}
- +
- +static int fwu_recovery_check_status(void)
- +{
- + int retval;
- + unsigned char data_base;
- + unsigned char status;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + data_base = fwu->f35_fd.data_base_addr;
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + data_base + F35_ERROR_CODE_OFFSET,
- + &status,
- + 1);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to read status\n",
- + __func__);
- + return retval;
- + }
- +
- + status = status & MASK_5BIT;
- +
- + if (status != 0x00) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Recovery mode status = %d\n",
- + __func__, status);
- + return -EINVAL;
- + }
- +
- + return 0;
- +}
- +
- +static int fwu_recovery_erase_completion(void)
- +{
- + int retval;
- + unsigned char data_base;
- + unsigned char command;
- + unsigned char status;
- + unsigned int timeout = F35_ERASE_ALL_WAIT_MS / 20;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + data_base = fwu->f35_fd.data_base_addr;
- +
- + do {
- + command = 0x01;
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + fwu->f35_fd.cmd_base_addr,
- + &command,
- + sizeof(command));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to issue command\n",
- + __func__);
- + return retval;
- + }
- +
- + do {
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + fwu->f35_fd.cmd_base_addr,
- + &command,
- + sizeof(command));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to read command status\n",
- + __func__);
- + return retval;
- + }
- +
- + if ((command & 0x01) == 0x00)
- + break;
- +
- + msleep(20);
- + timeout--;
- + } while (timeout > 0);
- +
- + if (timeout == 0)
- + goto exit;
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + data_base + F35_FLASH_STATUS_OFFSET,
- + &status,
- + sizeof(status));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to read flash status\n",
- + __func__);
- + return retval;
- + }
- +
- + if ((status & 0x01) == 0x00)
- + break;
- +
- + msleep(20);
- + timeout--;
- + } while (timeout > 0);
- +
- +exit:
- + if (timeout == 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Timed out waiting for flash erase completion\n",
- + __func__);
- + return -ETIMEDOUT;
- + }
- +
- + return 0;
- +}
- +
- +static int fwu_recovery_erase_all(void)
- +{
- + int retval;
- + unsigned char ctrl_base;
- + unsigned char command = CMD_F35_ERASE_ALL;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + ctrl_base = fwu->f35_fd.ctrl_base_addr;
- +
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + ctrl_base + F35_CHUNK_COMMAND_OFFSET,
- + &command,
- + sizeof(command));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to issue erase all command\n",
- + __func__);
- + return retval;
- + }
- +
- + if (fwu->f35_fd.cmd_base_addr) {
- + retval = fwu_recovery_erase_completion();
- + if (retval < 0)
- + return retval;
- + } else {
- + msleep(F35_ERASE_ALL_WAIT_MS);
- + }
- +
- + retval = fwu_recovery_check_status();
- + if (retval < 0)
- + return retval;
- +
- + return 0;
- +}
- +
- +static int fwu_recovery_write_chunk(void)
- +{
- + int retval;
- + unsigned char ctrl_base;
- + unsigned char chunk_number[] = {0, 0};
- + unsigned char chunk_spare;
- + unsigned char chunk_size;
- + unsigned char buf[F35_CHUNK_SIZE + 1];
- + unsigned short chunk;
- + unsigned short chunk_total;
- + unsigned short bytes_written = 0;
- + unsigned char *chunk_ptr = (unsigned char *)fwu->image;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + ctrl_base = fwu->f35_fd.ctrl_base_addr;
- +
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + ctrl_base + F35_CHUNK_NUM_LSB_OFFSET,
- + chunk_number,
- + sizeof(chunk_number));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to write chunk number\n",
- + __func__);
- + return retval;
- + }
- +
- + buf[sizeof(buf) - 1] = CMD_F35_WRITE_CHUNK;
- +
- + chunk_total = fwu->image_size / F35_CHUNK_SIZE;
- + chunk_spare = fwu->image_size % F35_CHUNK_SIZE;
- + if (chunk_spare)
- + chunk_total++;
- +
- + for (chunk = 0; chunk < chunk_total; chunk++) {
- + if (chunk_spare && chunk == chunk_total - 1)
- + chunk_size = chunk_spare;
- + else
- + chunk_size = F35_CHUNK_SIZE;
- +
- + memset(buf, 0x00, F35_CHUNK_SIZE);
- + secure_memcpy(buf, sizeof(buf), chunk_ptr,
- + fwu->image_size - bytes_written,
- + chunk_size);
- +
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + ctrl_base + F35_CHUNK_DATA_OFFSET,
- + buf,
- + sizeof(buf));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to write chunk data (chunk %d)\n",
- + __func__, chunk);
- + return retval;
- + }
- + chunk_ptr += chunk_size;
- + bytes_written += chunk_size;
- + }
- +
- + retval = fwu_recovery_check_status();
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to write chunk data\n",
- + __func__);
- + return retval;
- + }
- +
- + return 0;
- +}
- +
- +static int fwu_recovery_reset(void)
- +{
- + int retval;
- + unsigned char ctrl_base;
- + unsigned char command = CMD_F35_RESET;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + ctrl_base = fwu->f35_fd.ctrl_base_addr;
- +
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + ctrl_base + F35_CHUNK_COMMAND_OFFSET,
- + &command,
- + sizeof(command));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to issue reset command\n",
- + __func__);
- + return retval;
- + }
- +
- + msleep(F35_RESET_WAIT_MS);
- +
- + return 0;
- +}
- +
- +static int fwu_start_recovery(void)
- +{
- + int retval;
- + const struct firmware *fw_entry = NULL;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + if (rmi4_data->sensor_sleep) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Sensor sleeping\n",
- + __func__);
- + return -ENODEV;
- + }
- +
- + rmi4_data->stay_awake = true;
- +
- + mutex_lock(&rmi4_data->rmi4_exp_init_mutex);
- +
- + pr_notice("%s: Start of recovery process\n", __func__);
- +
- + if (fwu->image == NULL) {
- + retval = secure_memcpy(fwu->image_name, MAX_IMAGE_NAME_LEN,
- + FW_IHEX_NAME, sizeof(FW_IHEX_NAME),
- + sizeof(FW_IHEX_NAME));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to copy ihex file name\n",
- + __func__);
- + goto exit;
- + }
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: Requesting firmware ihex %s\n",
- + __func__, fwu->image_name);
- +
- + retval = request_firmware(&fw_entry, fwu->image_name,
- + rmi4_data->pdev->dev.parent);
- + if (retval != 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Firmware ihex %s not available\n",
- + __func__, fwu->image_name);
- + retval = -EINVAL;
- + goto exit;
- + }
- +
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: Firmware image size = %d\n",
- + __func__, (unsigned int)fw_entry->size);
- +
- + fwu->image = fw_entry->data;
- + fwu->image_size = fw_entry->size;
- + }
- +
- + retval = rmi4_data->irq_enable(rmi4_data, false, false);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to disable interrupt\n",
- + __func__);
- + goto exit;
- + }
- +
- + retval = fwu_recovery_erase_all();
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to do erase all in recovery mode\n",
- + __func__);
- + goto exit;
- + }
- +
- + pr_notice("%s: External flash erased\n", __func__);
- +
- + retval = fwu_recovery_write_chunk();
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to write chunk data in recovery mode\n",
- + __func__);
- + goto exit;
- + }
- +
- + pr_notice("%s: Chunk data programmed\n", __func__);
- +
- + retval = fwu_recovery_reset();
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to reset device in recovery mode\n",
- + __func__);
- + goto exit;
- + }
- +
- + pr_notice("%s: Recovery mode reset issued\n", __func__);
- +
- + rmi4_data->reset_device(rmi4_data, true);
- +
- + retval = 0;
- +
- +exit:
- + if (fw_entry)
- + release_firmware(fw_entry);
- +
- + pr_notice("%s: End of recovery process\n", __func__);
- +
- + mutex_unlock(&rmi4_data->rmi4_exp_init_mutex);
- +
- + rmi4_data->stay_awake = false;
- +
- + return retval;
- +}
- +
- +int synaptics_fw_updater_force(const unsigned char *fw_data)
- +{
- + int retval;
- +
- + if (!fwu)
- + return -ENODEV;
- +
- + if (!fwu->initialized)
- + return -ENODEV;
- +
- + if (fwu->in_ub_mode)
- + return -ENODEV;
- +
- + fwu->rmi4_data->fw_updating = true;
- + fwu->image = fw_data;
- +
- + retval = fwu_start_reflash();
- +
- + fwu->image = NULL;
- + fwu->rmi4_data->fw_updating = false;
- +
- + return retval;
- +}
- +EXPORT_SYMBOL(synaptics_fw_updater_force);
- +
- +#ifdef DO_STARTUP_FW_UPDATE
- +static void fwu_startup_fw_update_work(struct work_struct *work)
- +{
- + static unsigned char do_once = 1;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- +#ifdef WAIT_FOR_FB_READY
- + unsigned int timeout;
- +#endif
- + if (!do_once)
- + return;
- + do_once = 0;
- +#ifdef WAIT_FOR_FB_READY
- + timeout = FB_READY_TIMEOUT_S * 1000 / FB_READY_WAIT_MS + 1;
- +
- + while (!rmi4_data->fb_ready) {
- + msleep(FB_READY_WAIT_MS);
- + timeout--;
- + if (timeout == 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Timed out waiting for FB ready\n",
- + __func__);
- + return;
- + }
- + }
- +#endif
- +
- + synaptics_fw_updater_force(NULL);
- +
- + if (rmi4_data->chip_is_tddi)
- + firmware_force_update(rmi4_data);
- +
- + return;
- +}
- +#endif
- +
- +static ssize_t fwu_sysfs_show_image(struct file *data_file,
- + struct kobject *kobj, struct bin_attribute *attributes,
- + char *buf, loff_t pos, size_t count)
- +{
- + int retval;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + if (count < fwu->config_size) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Not enough space (%ld bytes) in buffer\n",
- + __func__, count);
- + return -EINVAL;
- + }
- +
- + retval = secure_memcpy(buf, count, fwu->read_config_buf,
- + fwu->read_config_buf_size, fwu->config_size);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to copy config data\n",
- + __func__);
- + return retval;
- + }
- +
- + return fwu->config_size;
- +}
- +
- +static ssize_t fwu_sysfs_store_image(struct file *data_file,
- + struct kobject *kobj, struct bin_attribute *attributes,
- + char *buf, loff_t pos, size_t count)
- +{
- + int retval;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + retval = secure_memcpy(&fwu->ext_data_source[fwu->data_pos],
- + fwu->image_size - fwu->data_pos, buf, count, count);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to copy image data\n",
- + __func__);
- + return retval;
- + }
- +
- + fwu->data_pos += count;
- +
- + return count;
- +}
- +
- +static ssize_t fwu_sysfs_do_recovery_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count)
- +{
- + int retval;
- + unsigned int input;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + if (sscanf(buf, "%u", &input) != 1) {
- + retval = -EINVAL;
- + goto exit;
- + }
- +
- + retval = fwu_scan_pdt();
- + if (retval < 0)
- + goto exit;
- +
- + pr_err("%s: fwu->in_ub_mode = %d\n", __func__, fwu->in_ub_mode);
- +
- + if (!fwu->in_ub_mode) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Not in microbootloader mode\n",
- + __func__);
- + retval = -EINVAL;
- + goto exit;
- + }
- +
- + if (!fwu->ext_data_source)
- + return -EINVAL;
- + else
- + fwu->image = fwu->ext_data_source;
- +
- + retval = fwu_start_recovery();
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to do recovery\n",
- + __func__);
- + goto exit;
- + }
- +
- + retval = count;
- +
- +exit:
- + kfree(fwu->ext_data_source);
- + fwu->ext_data_source = NULL;
- + fwu->image = NULL;
- + return retval;
- +}
- +
- +static ssize_t fwu_sysfs_do_reflash_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count)
- +{
- + int retval;
- + unsigned int input;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + if (sscanf(buf, "%u", &input) != 1) {
- + retval = -EINVAL;
- + goto exit;
- + }
- +
- + if (fwu->in_ub_mode) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: In microbootloader mode\n",
- + __func__);
- + retval = -EINVAL;
- + goto exit;
- + }
- +
- + if (!fwu->ext_data_source)
- + return -EINVAL;
- + else
- + fwu->image = fwu->ext_data_source;
- +
- + if (input & LOCKDOWN) {
- + fwu->do_lockdown = true;
- + input &= ~LOCKDOWN;
- + }
- +
- + if ((input != NORMAL) && (input != FORCE)) {
- + retval = -EINVAL;
- + goto exit;
- + }
- +
- + if (input == FORCE)
- + fwu->force_update = true;
- +
- + retval = synaptics_fw_updater_force(fwu->image);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to do reflash\n",
- + __func__);
- + goto exit;
- + }
- +
- + retval = count;
- +
- +exit:
- + kfree(fwu->ext_data_source);
- + fwu->ext_data_source = NULL;
- + fwu->image = NULL;
- + fwu->force_update = FORCE_UPDATE;
- + fwu->do_lockdown = DO_LOCKDOWN;
- + return retval;
- +}
- +
- +static ssize_t fwu_sysfs_write_config_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count)
- +{
- + int retval;
- + unsigned int input;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + if (sscanf(buf, "%u", &input) != 1) {
- + retval = -EINVAL;
- + goto exit;
- + }
- +
- + if (input != 1) {
- + retval = -EINVAL;
- + goto exit;
- + }
- +
- + if (fwu->in_ub_mode) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: In microbootloader mode\n",
- + __func__);
- + retval = -EINVAL;
- + goto exit;
- + }
- +
- + if (!fwu->ext_data_source)
- + return -EINVAL;
- + else
- + fwu->image = fwu->ext_data_source;
- +
- + retval = fwu_start_write_config();
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to write config\n",
- + __func__);
- + goto exit;
- + }
- +
- + retval = count;
- +
- +exit:
- + kfree(fwu->ext_data_source);
- + fwu->ext_data_source = NULL;
- + fwu->image = NULL;
- + return retval;
- +}
- +
- +static ssize_t fwu_sysfs_read_config_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count)
- +{
- + int retval;
- + unsigned int input;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + if (sscanf(buf, "%u", &input) != 1)
- + return -EINVAL;
- +
- + if (input != 1)
- + return -EINVAL;
- +
- + if (fwu->in_ub_mode) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: In microbootloader mode\n",
- + __func__);
- + return -EINVAL;
- + }
- +
- + retval = fwu_do_read_config();
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to read config\n",
- + __func__);
- + return retval;
- + }
- +
- + return count;
- +}
- +
- +static ssize_t fwu_sysfs_config_area_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count)
- +{
- + int retval;
- + unsigned long config_area;
- +
- + retval = sstrtoul(buf, 10, &config_area);
- + if (retval)
- + return retval;
- +
- + fwu->config_area = config_area;
- +
- + return count;
- +}
- +
- +static ssize_t fwu_sysfs_image_name_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count)
- +{
- + int retval;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + retval = secure_memcpy(fwu->image_name, MAX_IMAGE_NAME_LEN,
- + buf, count, count);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to copy image file name\n",
- + __func__);
- + return retval;
- + }
- +
- + return count;
- +}
- +
- +static ssize_t fwu_sysfs_image_size_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count)
- +{
- + int retval;
- + unsigned long size;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + retval = sstrtoul(buf, 10, &size);
- + if (retval)
- + return retval;
- +
- + fwu->image_size = size;
- + fwu->data_pos = 0;
- +
- + kfree(fwu->ext_data_source);
- + fwu->ext_data_source = kzalloc(fwu->image_size, GFP_KERNEL);
- + if (!fwu->ext_data_source) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to alloc mem for image data\n",
- + __func__);
- + return -ENOMEM;
- + }
- +
- + return count;
- +}
- +
- +static ssize_t fwu_sysfs_block_size_show(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + return snprintf(buf, PAGE_SIZE, "%u\n", fwu->block_size);
- +}
- +
- +static ssize_t fwu_sysfs_firmware_block_count_show(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + return snprintf(buf, PAGE_SIZE, "%u\n", fwu->blkcount.ui_firmware);
- +}
- +
- +static ssize_t fwu_sysfs_configuration_block_count_show(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + return snprintf(buf, PAGE_SIZE, "%u\n", fwu->blkcount.ui_config);
- +}
- +
- +static ssize_t fwu_sysfs_disp_config_block_count_show(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + return snprintf(buf, PAGE_SIZE, "%u\n", fwu->blkcount.dp_config);
- +}
- +
- +static ssize_t fwu_sysfs_perm_config_block_count_show(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + return snprintf(buf, PAGE_SIZE, "%u\n", fwu->blkcount.pm_config);
- +}
- +
- +static ssize_t fwu_sysfs_bl_config_block_count_show(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + return snprintf(buf, PAGE_SIZE, "%u\n", fwu->blkcount.bl_config);
- +}
- +
- +static ssize_t fwu_sysfs_guest_code_block_count_show(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + return snprintf(buf, PAGE_SIZE, "%u\n", fwu->blkcount.guest_code);
- +}
- +
- +static ssize_t fwu_sysfs_write_guest_code_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count)
- +{
- + int retval;
- + unsigned int input;
- + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
- +
- + if (sscanf(buf, "%u", &input) != 1) {
- + retval = -EINVAL;
- + goto exit;
- + }
- +
- + if (input != 1) {
- + retval = -EINVAL;
- + goto exit;
- + }
- +
- + if (fwu->in_ub_mode) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: In microbootloader mode\n",
- + __func__);
- + retval = -EINVAL;
- + goto exit;
- + }
- +
- + if (!fwu->ext_data_source)
- + return -EINVAL;
- + else
- + fwu->image = fwu->ext_data_source;
- +
- + retval = fwu_start_write_guest_code();
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to write guest code\n",
- + __func__);
- + goto exit;
- + }
- +
- + retval = count;
- +
- +exit:
- + kfree(fwu->ext_data_source);
- + fwu->ext_data_source = NULL;
- + fwu->image = NULL;
- + return retval;
- +}
- +
- +static void synaptics_rmi4_fwu_attn(struct synaptics_rmi4_data *rmi4_data,
- + unsigned char intr_mask)
- +{
- + if (!fwu)
- + return;
- +
- + if (fwu->intr_mask & intr_mask)
- + fwu_read_flash_status();
- +
- + return;
- +}
- +
- +static void firmware_force_update(struct synaptics_rmi4_data *rmi4_data)
- +{
- + int retval;
- + const struct firmware *fw_entry = NULL;
- + const struct synaptics_dsx_board_data *bdata = rmi4_data->hw_if->board_data;
- + if (!fwu->in_ub_mode)
- + return;
- +
- + retval = request_firmware(&fw_entry, bdata->backup_fw_name,
- + rmi4_data->pdev->dev.parent);
- + if (retval != 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Firmware image %s not available\n",
- + __func__, fwu->image_name);
- + return;
- + }
- +
- + fwu->image = fw_entry->data;
- + fwu->image_size = fw_entry->size;
- +
- + retval = fwu_start_recovery();
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to do recovery\n",
- + __func__);
- + release_firmware(fw_entry);
- + return;
- + }
- +
- + release_firmware(fw_entry);
- +
- + return;
- +}
- +
- +static int synaptics_rmi4_fwu_init(struct synaptics_rmi4_data *rmi4_data)
- +{
- + int retval;
- + unsigned char attr_count;
- + struct pdt_properties pdt_props;
- +
- + if (fwu) {
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: Handle already exists\n",
- + __func__);
- + return 0;
- + }
- +
- + fwu = kzalloc(sizeof(*fwu), GFP_KERNEL);
- + if (!fwu) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to alloc mem for fwu\n",
- + __func__);
- + retval = -ENOMEM;
- + goto exit;
- + }
- +
- + fwu->image_name = kzalloc(MAX_IMAGE_NAME_LEN, GFP_KERNEL);
- + if (!fwu->image_name) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to alloc mem for image name\n",
- + __func__);
- + retval = -ENOMEM;
- + goto exit_free_fwu;
- + }
- +
- + fwu->rmi4_data = rmi4_data;
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + PDT_PROPS,
- + pdt_props.data,
- + sizeof(pdt_props.data));
- + if (retval < 0) {
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: Failed to read PDT properties, assuming 0x00\n",
- + __func__);
- + } else if (pdt_props.has_bsr) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Reflash for LTS not currently supported\n",
- + __func__);
- + retval = -ENODEV;
- + goto exit_free_mem;
- + }
- +
- + retval = fwu_scan_pdt();
- + if (retval < 0)
- + goto exit_free_mem;
- +
- + pr_err("%s: fwu->in_ub_mode = %d\n", __func__, fwu->in_ub_mode);
- +
- + if (!fwu->in_ub_mode) {
- + retval = fwu_read_f34_queries();
- + if (retval < 0)
- + goto exit_free_mem;
- +
- + retval = fwu_get_device_config_id();
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to read device config ID\n",
- + __func__);
- + goto exit_free_mem;
- + }
- + }
- +
- + fwu->force_update = FORCE_UPDATE;
- + fwu->do_lockdown = DO_LOCKDOWN;
- + fwu->initialized = true;
- +
- + retval = sysfs_create_bin_file(&rmi4_data->input_dev->dev.kobj,
- + &dev_attr_data);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to create sysfs bin file\n",
- + __func__);
- + goto exit_free_mem;
- + }
- +
- + for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
- + retval = sysfs_create_file(&rmi4_data->input_dev->dev.kobj,
- + &attrs[attr_count].attr);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to create sysfs attributes\n",
- + __func__);
- + retval = -ENODEV;
- + goto exit_remove_attrs;
- + }
- + }
- +
- +#ifdef DO_STARTUP_FW_UPDATE
- + fwu->fwu_workqueue = create_singlethread_workqueue("fwu_workqueue");
- + INIT_WORK(&fwu->fwu_work, fwu_startup_fw_update_work);
- + queue_work(fwu->fwu_workqueue,
- + &fwu->fwu_work);
- +#endif
- +
- +#ifdef F51_DISCRETE_FORCE
- + fwu_read_flash_status();
- + if (!fwu->in_bl_mode) {
- + retval = fwu_f51_force_data_init();
- + if (retval < 0)
- + goto exit_remove_attrs;
- + }
- +#endif
- +
- + return 0;
- +
- +exit_remove_attrs:
- + for (attr_count--; attr_count >= 0; attr_count--) {
- + sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
- + &attrs[attr_count].attr);
- + }
- +
- + sysfs_remove_bin_file(&rmi4_data->input_dev->dev.kobj, &dev_attr_data);
- +
- +exit_free_mem:
- + kfree(fwu->image_name);
- +
- +exit_free_fwu:
- + kfree(fwu);
- + fwu = NULL;
- +
- +exit:
- + return retval;
- +}
- +
- +static void synaptics_rmi4_fwu_remove(struct synaptics_rmi4_data *rmi4_data)
- +{
- + unsigned char attr_count;
- +
- + if (!fwu)
- + goto exit;
- +
- +#ifdef DO_STARTUP_FW_UPDATE
- + cancel_work_sync(&fwu->fwu_work);
- + flush_workqueue(fwu->fwu_workqueue);
- + destroy_workqueue(fwu->fwu_workqueue);
- +#endif
- +
- + for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
- + sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
- + &attrs[attr_count].attr);
- + }
- +
- + sysfs_remove_bin_file(&rmi4_data->input_dev->dev.kobj, &dev_attr_data);
- +
- +#ifdef F51_DISCRETE_FORCE
- + kfree(fwu->cal_data);
- +#endif
- + kfree(fwu->read_config_buf);
- + kfree(fwu->image_name);
- + kfree(fwu);
- + fwu = NULL;
- +
- +exit:
- + complete(&fwu_remove_complete_force);
- +
- + return;
- +}
- +
- +static void synaptics_rmi4_fwu_reset(struct synaptics_rmi4_data *rmi4_data)
- +{
- + int retval;
- +
- + if (!fwu) {
- + synaptics_rmi4_fwu_init(rmi4_data);
- + return;
- + }
- +
- + retval = fwu_scan_pdt();
- + if (retval < 0)
- + return;
- +
- + pr_err("%s: fwu->in_ub_mode = %d\n", __func__, fwu->in_ub_mode);
- +
- + if (!fwu->in_ub_mode)
- + fwu_read_f34_queries();
- +
- +#ifdef F51_DISCRETE_FORCE
- + fwu_read_flash_status();
- + if (!fwu->in_bl_mode)
- + fwu_f51_force_data_init();
- +#endif
- +
- + return;
- +}
- +
- +#if 0
- +static void synaptics_rmi4_fwu_resume(struct synaptics_rmi4_data *rmi4_data)
- +{
- + int retval;
- +
- + if (!fwu)
- + return;
- +
- + retval = fwu_scan_pdt();
- + if (retval < 0)
- + return;
- +
- + pr_err("%s: fwu->in_ub_mode = %d\n", __func__, fwu->in_ub_mode);
- +
- + if (!fwu->in_ub_mode)
- + fwu_read_f34_queries();
- +
- + return;
- +}
- +#endif
- +
- +static struct synaptics_rmi4_exp_fn fwu_module = {
- + .fn_type = RMI_FW_UPDATER,
- + .init = synaptics_rmi4_fwu_init,
- + .remove = synaptics_rmi4_fwu_remove,
- + .reset = synaptics_rmi4_fwu_reset,
- + .reinit = NULL,
- + .early_suspend = NULL,
- + .suspend = NULL,
- + .resume = NULL,
- + .late_resume = NULL,
- + .attn = synaptics_rmi4_fwu_attn,
- +};
- +
- +static int __init rmi4_fw_update_module_init(void)
- +{
- + synaptics_rmi4_new_function_force(&fwu_module, true);
- +
- + return 0;
- +}
- +
- +static void __exit rmi4_fw_update_module_exit(void)
- +{
- + synaptics_rmi4_new_function_force(&fwu_module, false);
- +
- + wait_for_completion(&fwu_remove_complete_force);
- +
- + return;
- +}
- +
- +module_init(rmi4_fw_update_module_init);
- +module_exit(rmi4_fw_update_module_exit);
- +
- +MODULE_AUTHOR("Synaptics, Inc.");
- +MODULE_DESCRIPTION("Synaptics DSX FW Update Module");
- +MODULE_LICENSE("GPL v2");
- diff --git a/drivers/input/touchscreen/synaptics_dsx_force/synaptics_dsx_gesture.c b/drivers/input/touchscreen/synaptics_dsx_force/synaptics_dsx_gesture.c
- new file mode 100644
- index 0000000..9ec8235
- --- /dev/null
- +++ b/drivers/input/touchscreen/synaptics_dsx_force/synaptics_dsx_gesture.c
- @@ -0,0 +1,2312 @@
- +/*
- + * Synaptics DSX touchscreen driver
- + *
- + * Copyright (C) 2012-2015 Synaptics Incorporated. All rights reserved.
- + *
- + * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
- + * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
- + * Copyright (C) 2017 XiaoMi, 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.
- + *
- + * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
- + * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
- + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
- + * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
- + * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- + * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
- + * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
- + * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- + * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
- + * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
- + * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
- + * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
- + * DOLLARS.
- + */
- +
- +#include <linux/kernel.h>
- +#include <linux/module.h>
- +#include <linux/slab.h>
- +#include <linux/interrupt.h>
- +#include <linux/delay.h>
- +#include <linux/input.h>
- +#include <linux/platform_device.h>
- +#include <linux/input/synaptics_dsx.h>
- +#include "synaptics_dsx_core.h"
- +
- +#define GESTURE_PHYS_NAME "synaptics_dsx/gesture"
- +
- +#define TUNING_SYSFS_DIR_NAME "tuning"
- +
- +#define STORE_GESTURES
- +#ifdef STORE_GESTURES
- +#define GESTURES_TO_STORE 10
- +#endif
- +
- +#define CTRL23_FINGER_REPORT_ENABLE_BIT 0
- +#define CTRL27_UDG_ENABLE_BIT 4
- +#define WAKEUP_GESTURE_MODE 0x02
- +
- +static ssize_t udg_sysfs_engine_enable_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count);
- +
- +static ssize_t udg_sysfs_detection_enable_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count);
- +
- +static ssize_t udg_sysfs_detection_score_show(struct device *dev,
- + struct device_attribute *attr, char *buf);
- +
- +static ssize_t udg_sysfs_detection_index_show(struct device *dev,
- + struct device_attribute *attr, char *buf);
- +
- +static ssize_t udg_sysfs_registration_enable_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count);
- +
- +static ssize_t udg_sysfs_registration_begin_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count);
- +
- +static ssize_t udg_sysfs_registration_status_show(struct device *dev,
- + struct device_attribute *attr, char *buf);
- +
- +static ssize_t udg_sysfs_template_size_show(struct device *dev,
- + struct device_attribute *attr, char *buf);
- +
- +static ssize_t udg_sysfs_template_max_index_show(struct device *dev,
- + struct device_attribute *attr, char *buf);
- +
- +static ssize_t udg_sysfs_template_detection_show(struct device *dev,
- + struct device_attribute *attr, char *buf);
- +
- +static ssize_t udg_sysfs_template_index_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count);
- +
- +static ssize_t udg_sysfs_template_valid_show(struct device *dev,
- + struct device_attribute *attr, char *buf);
- +
- +static ssize_t udg_sysfs_template_valid_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count);
- +
- +static ssize_t udg_sysfs_template_clear_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count);
- +
- +static ssize_t udg_sysfs_trace_size_show(struct device *dev,
- + struct device_attribute *attr, char *buf);
- +
- +static ssize_t udg_sysfs_template_data_show(struct file *data_file,
- + struct kobject *kobj, struct bin_attribute *attributes,
- + char *buf, loff_t pos, size_t count);
- +
- +static ssize_t udg_sysfs_template_data_store(struct file *data_file,
- + struct kobject *kobj, struct bin_attribute *attributes,
- + char *buf, loff_t pos, size_t count);
- +
- +static ssize_t udg_sysfs_trace_data_show(struct file *data_file,
- + struct kobject *kobj, struct bin_attribute *attributes,
- + char *buf, loff_t pos, size_t count);
- +
- +static ssize_t udg_sysfs_template_displacement_show(struct device *dev,
- + struct device_attribute *attr, char *buf);
- +
- +static ssize_t udg_sysfs_template_displacement_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count);
- +
- +static ssize_t udg_sysfs_rotation_invariance_show(struct device *dev,
- + struct device_attribute *attr, char *buf);
- +
- +static ssize_t udg_sysfs_rotation_invariance_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count);
- +
- +static ssize_t udg_sysfs_scale_invariance_show(struct device *dev,
- + struct device_attribute *attr, char *buf);
- +
- +static ssize_t udg_sysfs_scale_invariance_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count);
- +
- +static ssize_t udg_sysfs_threshold_factor_show(struct device *dev,
- + struct device_attribute *attr, char *buf);
- +
- +static ssize_t udg_sysfs_threshold_factor_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count);
- +
- +static ssize_t udg_sysfs_match_metric_threshold_show(struct device *dev,
- + struct device_attribute *attr, char *buf);
- +
- +static ssize_t udg_sysfs_match_metric_threshold_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count);
- +
- +static ssize_t udg_sysfs_max_inter_stroke_time_show(struct device *dev,
- + struct device_attribute *attr, char *buf);
- +
- +static ssize_t udg_sysfs_max_inter_stroke_time_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count);
- +
- +static int udg_read_tuning_params(void);
- +
- +static int udg_write_tuning_params(void);
- +
- +static int udg_detection_enable(bool enable);
- +
- +static int udg_engine_enable(bool enable);
- +
- +static int udg_set_index(unsigned char index);
- +
- +#ifdef STORE_GESTURES
- +static int udg_read_valid_data(void);
- +static int udg_write_valid_data(void);
- +static int udg_read_template_data(unsigned char index);
- +static int udg_write_template_data(void);
- +#endif
- +
- +enum gesture_type {
- + DETECTION = 0x0f,
- + REGISTRATION = 0x10,
- +};
- +
- +struct udg_tuning {
- + union {
- + struct {
- + unsigned char maximum_number_of_templates;
- + unsigned char template_size;
- + unsigned char template_disp_lsb;
- + unsigned char template_disp_msb;
- + unsigned char rotation_inv_lsb;
- + unsigned char rotation_inv_msb;
- + unsigned char scale_inv_lsb;
- + unsigned char scale_inv_msb;
- + unsigned char thres_factor_lsb;
- + unsigned char thres_factor_msb;
- + unsigned char metric_thres_lsb;
- + unsigned char metric_thres_msb;
- + unsigned char inter_stroke_lsb;
- + unsigned char inter_stroke_msb;
- + } __packed;
- + unsigned char data[14];
- + };
- +};
- +
- +struct udg_addr {
- + unsigned short data_4;
- + unsigned short ctrl_18;
- + unsigned short ctrl_20;
- + unsigned short ctrl_23;
- + unsigned short ctrl_27;
- + unsigned short ctrl_41;
- + unsigned short trace_x;
- + unsigned short trace_y;
- + unsigned short trace_segment;
- + unsigned short template_helper;
- + unsigned short template_data;
- + unsigned short template_flags;
- +};
- +
- +struct synaptics_rmi4_f12_query_0 {
- + union {
- + struct {
- + struct {
- + unsigned char has_register_descriptors:1;
- + unsigned char has_closed_cover:1;
- + unsigned char has_fast_glove_detect:1;
- + unsigned char has_dribble:1;
- + unsigned char has_4p4_jitter_filter_strength:1;
- + unsigned char f12_query0_s0_b5__7:3;
- + } __packed;
- + struct {
- + unsigned char max_num_templates:4;
- + unsigned char f12_query0_s1_b4__7:4;
- + unsigned char template_size_lsb;
- + unsigned char template_size_msb;
- + } __packed;
- + };
- + unsigned char data[4];
- + };
- +};
- +
- +struct synaptics_rmi4_f12_query_5 {
- + union {
- + struct {
- + unsigned char size_of_query6;
- + struct {
- + unsigned char ctrl0_is_present:1;
- + unsigned char ctrl1_is_present:1;
- + unsigned char ctrl2_is_present:1;
- + unsigned char ctrl3_is_present:1;
- + unsigned char ctrl4_is_present:1;
- + unsigned char ctrl5_is_present:1;
- + unsigned char ctrl6_is_present:1;
- + unsigned char ctrl7_is_present:1;
- + } __packed;
- + struct {
- + unsigned char ctrl8_is_present:1;
- + unsigned char ctrl9_is_present:1;
- + unsigned char ctrl10_is_present:1;
- + unsigned char ctrl11_is_present:1;
- + unsigned char ctrl12_is_present:1;
- + unsigned char ctrl13_is_present:1;
- + unsigned char ctrl14_is_present:1;
- + unsigned char ctrl15_is_present:1;
- + } __packed;
- + struct {
- + unsigned char ctrl16_is_present:1;
- + unsigned char ctrl17_is_present:1;
- + unsigned char ctrl18_is_present:1;
- + unsigned char ctrl19_is_present:1;
- + unsigned char ctrl20_is_present:1;
- + unsigned char ctrl21_is_present:1;
- + unsigned char ctrl22_is_present:1;
- + unsigned char ctrl23_is_present:1;
- + } __packed;
- + struct {
- + unsigned char ctrl24_is_present:1;
- + unsigned char ctrl25_is_present:1;
- + unsigned char ctrl26_is_present:1;
- + unsigned char ctrl27_is_present:1;
- + unsigned char ctrl28_is_present:1;
- + unsigned char ctrl29_is_present:1;
- + unsigned char ctrl30_is_present:1;
- + unsigned char ctrl31_is_present:1;
- + } __packed;
- + struct {
- + unsigned char ctrl32_is_present:1;
- + unsigned char ctrl33_is_present:1;
- + unsigned char ctrl34_is_present:1;
- + unsigned char ctrl35_is_present:1;
- + unsigned char ctrl36_is_present:1;
- + unsigned char ctrl37_is_present:1;
- + unsigned char ctrl38_is_present:1;
- + unsigned char ctrl39_is_present:1;
- + } __packed;
- + struct {
- + unsigned char ctrl40_is_present:1;
- + unsigned char ctrl41_is_present:1;
- + unsigned char ctrl42_is_present:1;
- + unsigned char ctrl43_is_present:1;
- + unsigned char ctrl44_is_present:1;
- + unsigned char ctrl45_is_present:1;
- + unsigned char ctrl46_is_present:1;
- + unsigned char ctrl47_is_present:1;
- + } __packed;
- + };
- + unsigned char data[7];
- + };
- +};
- +
- +struct synaptics_rmi4_f12_query_8 {
- + union {
- + struct {
- + unsigned char size_of_query9;
- + struct {
- + unsigned char data0_is_present:1;
- + unsigned char data1_is_present:1;
- + unsigned char data2_is_present:1;
- + unsigned char data3_is_present:1;
- + unsigned char data4_is_present:1;
- + unsigned char data5_is_present:1;
- + unsigned char data6_is_present:1;
- + unsigned char data7_is_present:1;
- + } __packed;
- + struct {
- + unsigned char data8_is_present:1;
- + unsigned char data9_is_present:1;
- + unsigned char data10_is_present:1;
- + unsigned char data11_is_present:1;
- + unsigned char data12_is_present:1;
- + unsigned char data13_is_present:1;
- + unsigned char data14_is_present:1;
- + unsigned char data15_is_present:1;
- + } __packed;
- + struct {
- + unsigned char data16_is_present:1;
- + unsigned char data17_is_present:1;
- + unsigned char data18_is_present:1;
- + unsigned char data19_is_present:1;
- + unsigned char data20_is_present:1;
- + unsigned char data21_is_present:1;
- + unsigned char data22_is_present:1;
- + unsigned char data23_is_present:1;
- + } __packed;
- + };
- + unsigned char data[4];
- + };
- +};
- +
- +struct synaptics_rmi4_f12_control_41 {
- + union {
- + struct {
- + unsigned char enable_registration:1;
- + unsigned char template_index:4;
- + unsigned char begin:1;
- + unsigned char f12_ctrl41_b6__7:2;
- + } __packed;
- + unsigned char data[1];
- + };
- +};
- +
- +struct synaptics_rmi4_udg_handle {
- + atomic_t attn_event;
- + unsigned char intr_mask;
- + unsigned char report_flags;
- + unsigned char object_type_enable1;
- + unsigned char object_type_enable2;
- + unsigned char trace_size;
- + unsigned char template_index;
- + unsigned char max_num_templates;
- + unsigned char detection_score;
- + unsigned char detection_index;
- + unsigned char detection_status;
- + unsigned char registration_status;
- + unsigned char *ctrl_buf;
- + unsigned char *trace_data_buf;
- + unsigned char *template_data_buf;
- +#ifdef STORE_GESTURES
- + unsigned char gestures_to_store;
- + unsigned char *storage_buf;
- + unsigned char valid_buf[2];
- +#endif
- + unsigned short trace_data_buf_size;
- + unsigned short template_size;
- + unsigned short template_data_size;
- + unsigned short query_base_addr;
- + unsigned short control_base_addr;
- + unsigned short data_base_addr;
- + unsigned short command_base_addr;
- + unsigned short ctrl_18_sub10_off;
- + unsigned short ctrl_20_sub1_off;
- + unsigned short ctrl_23_sub3_off;
- + unsigned short ctrl_27_sub5_off;
- + struct input_dev *udg_dev;
- + struct kobject *tuning_dir;
- + struct udg_addr addr;
- + struct udg_tuning tuning;
- + struct synaptics_rmi4_data *rmi4_data;
- +};
- +
- +static struct device_attribute attrs[] = {
- + __ATTR(engine_enable, S_IWUSR,
- + synaptics_rmi4_show_error,
- + udg_sysfs_engine_enable_store),
- + __ATTR(detection_enable, S_IWUSR,
- + synaptics_rmi4_show_error,
- + udg_sysfs_detection_enable_store),
- + __ATTR(detection_score, S_IRUGO,
- + udg_sysfs_detection_score_show,
- + synaptics_rmi4_store_error),
- + __ATTR(detection_index, S_IRUGO,
- + udg_sysfs_detection_index_show,
- + synaptics_rmi4_store_error),
- + __ATTR(registration_enable, S_IWUSR,
- + synaptics_rmi4_show_error,
- + udg_sysfs_registration_enable_store),
- + __ATTR(registration_begin, S_IWUSR,
- + synaptics_rmi4_show_error,
- + udg_sysfs_registration_begin_store),
- + __ATTR(registration_status, S_IRUGO,
- + udg_sysfs_registration_status_show,
- + synaptics_rmi4_store_error),
- + __ATTR(template_size, S_IRUGO,
- + udg_sysfs_template_size_show,
- + synaptics_rmi4_store_error),
- + __ATTR(template_max_index, S_IRUGO,
- + udg_sysfs_template_max_index_show,
- + synaptics_rmi4_store_error),
- + __ATTR(template_detection, S_IRUGO,
- + udg_sysfs_template_detection_show,
- + synaptics_rmi4_store_error),
- + __ATTR(template_index, S_IWUSR,
- + synaptics_rmi4_show_error,
- + udg_sysfs_template_index_store),
- + __ATTR(template_valid, (S_IRUGO | S_IWUSR),
- + udg_sysfs_template_valid_show,
- + udg_sysfs_template_valid_store),
- + __ATTR(template_clear, S_IWUSR,
- + synaptics_rmi4_show_error,
- + udg_sysfs_template_clear_store),
- + __ATTR(trace_size, S_IRUGO,
- + udg_sysfs_trace_size_show,
- + synaptics_rmi4_store_error),
- +};
- +
- +static struct bin_attribute template_data = {
- + .attr = {
- + .name = "template_data",
- + .mode = (S_IRUGO | S_IWUSR),
- + },
- + .size = 0,
- + .read = udg_sysfs_template_data_show,
- + .write = udg_sysfs_template_data_store,
- +};
- +
- +static struct bin_attribute trace_data = {
- + .attr = {
- + .name = "trace_data",
- + .mode = S_IRUGO,
- + },
- + .size = 0,
- + .read = udg_sysfs_trace_data_show,
- + .write = NULL,
- +};
- +
- +static struct device_attribute params[] = {
- + __ATTR(template_displacement, (S_IRUGO | S_IWUSR),
- + udg_sysfs_template_displacement_show,
- + udg_sysfs_template_displacement_store),
- + __ATTR(rotation_invariance, (S_IRUGO | S_IWUSR),
- + udg_sysfs_rotation_invariance_show,
- + udg_sysfs_rotation_invariance_store),
- + __ATTR(scale_invariance, (S_IRUGO | S_IWUSR),
- + udg_sysfs_scale_invariance_show,
- + udg_sysfs_scale_invariance_store),
- + __ATTR(threshold_factor, (S_IRUGO | S_IWUSR),
- + udg_sysfs_threshold_factor_show,
- + udg_sysfs_threshold_factor_store),
- + __ATTR(match_metric_threshold, (S_IRUGO | S_IWUSR),
- + udg_sysfs_match_metric_threshold_show,
- + udg_sysfs_match_metric_threshold_store),
- + __ATTR(max_inter_stroke_time, (S_IRUGO | S_IWUSR),
- + udg_sysfs_max_inter_stroke_time_show,
- + udg_sysfs_max_inter_stroke_time_store),
- +};
- +
- +static struct synaptics_rmi4_udg_handle *udg;
- +
- +static unsigned char ctrl_18_sub_size[] = {10, 10, 10, 2, 3, 4, 3, 3, 1, 1};
- +static unsigned char ctrl_20_sub_size[] = {2};
- +static unsigned char ctrl_23_sub_size[] = {1, 1, 1};
- +static unsigned char ctrl_27_sub_size[] = {1, 5, 2, 1, 7};
- +
- +DECLARE_COMPLETION(udg_remove_complete);
- +
- +static ssize_t udg_sysfs_engine_enable_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count)
- +{
- + int retval;
- + bool enable;
- + unsigned int input;
- +
- + if (sscanf(buf, "%u", &input) != 1)
- + return -EINVAL;
- +
- + if (input == 1)
- + enable = true;
- + else if (input == 0)
- + enable = false;
- + else
- + return -EINVAL;
- +
- + retval = udg_engine_enable(enable);
- + if (retval < 0)
- + return retval;
- +
- + return count;
- +}
- +
- +static ssize_t udg_sysfs_detection_enable_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count)
- +{
- + int retval;
- + bool enable;
- + unsigned int input;
- +
- + if (sscanf(buf, "%u", &input) != 1)
- + return -EINVAL;
- +
- + if (input == 1)
- + enable = true;
- + else if (input == 0)
- + enable = false;
- + else
- + return -EINVAL;
- +
- + udg->detection_status = 0;
- +
- + retval = udg_detection_enable(enable);
- + if (retval < 0)
- + return retval;
- +
- + return count;
- +}
- +
- +static ssize_t udg_sysfs_detection_score_show(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + return snprintf(buf, PAGE_SIZE, "%u\n", udg->detection_score);
- +}
- +
- +static ssize_t udg_sysfs_detection_index_show(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + return snprintf(buf, PAGE_SIZE, "%u\n", udg->detection_index);
- +}
- +
- +static ssize_t udg_sysfs_registration_enable_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count)
- +{
- + int retval;
- + bool enable;
- + unsigned int input;
- + struct synaptics_rmi4_f12_control_41 control_41;
- + struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data;
- +
- + if (sscanf(buf, "%u", &input) != 1)
- + return -EINVAL;
- +
- + if (input == 1)
- + enable = true;
- + else if (input == 0)
- + enable = false;
- + else
- + return -EINVAL;
- +
- + if (enable) {
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + udg->addr.ctrl_23,
- + udg->ctrl_buf,
- + udg->ctrl_23_sub3_off + 1);
- + if (retval < 0)
- + return retval;
- +
- + udg->ctrl_buf[0] = 0;
- + udg->ctrl_buf[0] |= (1 << CTRL23_FINGER_REPORT_ENABLE_BIT);
- + if (udg->ctrl_23_sub3_off)
- + udg->ctrl_buf[udg->ctrl_23_sub3_off] = 0;
- +
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + udg->addr.ctrl_23,
- + udg->ctrl_buf,
- + udg->ctrl_23_sub3_off + 1);
- + if (retval < 0)
- + return retval;
- + } else {
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + udg->addr.ctrl_23,
- + udg->ctrl_buf,
- + udg->ctrl_23_sub3_off + 1);
- + if (retval < 0)
- + return retval;
- +
- + udg->ctrl_buf[0] = udg->object_type_enable1;
- + if (udg->ctrl_23_sub3_off) {
- + udg->ctrl_buf[udg->ctrl_23_sub3_off] =
- + udg->object_type_enable2;
- + }
- +
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + udg->addr.ctrl_23,
- + udg->ctrl_buf,
- + udg->ctrl_23_sub3_off + 1);
- + if (retval < 0)
- + return retval;
- + }
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + udg->addr.ctrl_41,
- + control_41.data,
- + sizeof(control_41.data));
- + if (retval < 0)
- + return retval;
- +
- + control_41.enable_registration = enable ? 1 : 0;
- +
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + udg->addr.ctrl_41,
- + control_41.data,
- + sizeof(control_41.data));
- + if (retval < 0)
- + return retval;
- +
- + return count;
- +}
- +
- +static ssize_t udg_sysfs_registration_begin_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count)
- +{
- + int retval;
- + bool begin;
- + unsigned int input;
- + struct synaptics_rmi4_f12_control_41 control_41;
- + struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data;
- +
- + if (sscanf(buf, "%u", &input) != 1)
- + return -EINVAL;
- +
- + if (input == 1)
- + begin = true;
- + else if (input == 0)
- + begin = false;
- + else
- + return -EINVAL;
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + udg->addr.ctrl_41,
- + control_41.data,
- + sizeof(control_41.data));
- + if (retval < 0)
- + return retval;
- +
- + control_41.begin = begin ? 1 : 0;
- +
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + udg->addr.ctrl_41,
- + control_41.data,
- + sizeof(control_41.data));
- + if (retval < 0)
- + return retval;
- +
- + return count;
- +}
- +
- +static ssize_t udg_sysfs_registration_status_show(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + return snprintf(buf, PAGE_SIZE, "0x%02x\n", udg->registration_status);
- +}
- +
- +static ssize_t udg_sysfs_template_size_show(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + return snprintf(buf, PAGE_SIZE, "%u\n", udg->template_size);
- +}
- +
- +static ssize_t udg_sysfs_template_max_index_show(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + return snprintf(buf, PAGE_SIZE, "%u\n", udg->max_num_templates - 1);
- +}
- +
- +static ssize_t udg_sysfs_template_detection_show(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + int retval;
- + int attn_event;
- + unsigned char detection_status;
- + struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data;
- +
- + attn_event = atomic_read(&udg->attn_event);
- + atomic_set(&udg->attn_event, 0);
- +
- + if (attn_event == 0)
- + return snprintf(buf, PAGE_SIZE, "0\n");
- +
- + if (udg->detection_status == 0) {
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + udg->addr.data_4,
- + rmi4_data->gesture_detection,
- + sizeof(rmi4_data->gesture_detection));
- + if (retval < 0)
- + return retval;
- +
- + udg->detection_status = rmi4_data->gesture_detection[0];
- + }
- +
- + detection_status = udg->detection_status;
- + udg->detection_status = 0;
- +
- + switch (detection_status) {
- + case DETECTION:
- + udg->detection_score = rmi4_data->gesture_detection[1];
- + udg->detection_index = rmi4_data->gesture_detection[4];
- + udg->trace_size = rmi4_data->gesture_detection[3];
- + break;
- + case REGISTRATION:
- + udg->registration_status = rmi4_data->gesture_detection[1];
- + udg->trace_size = rmi4_data->gesture_detection[3];
- + break;
- + default:
- + return snprintf(buf, PAGE_SIZE, "0\n");
- + }
- +
- + return snprintf(buf, PAGE_SIZE, "0x%02x\n", detection_status);
- +}
- +
- +static ssize_t udg_sysfs_template_index_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count)
- +{
- + int retval;
- + unsigned long index;
- +
- + retval = sstrtoul(buf, 10, &index);
- + if (retval)
- + return retval;
- +
- + retval = udg_set_index((unsigned char)index);
- + if (retval < 0)
- + return retval;
- +
- + return count;
- +}
- +
- +static ssize_t udg_sysfs_template_valid_show(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + int retval;
- + unsigned char valid;
- + unsigned char offset;
- + unsigned char byte_num;
- + unsigned char template_flags[2];
- + struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data;
- +
- + byte_num = udg->template_index / 8;
- + offset = udg->template_index % 8;
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + udg->addr.template_flags,
- + template_flags,
- + sizeof(template_flags));
- + if (retval < 0)
- + return retval;
- +
- + valid = (template_flags[byte_num] & (1 << offset)) >> offset;
- +
- + return snprintf(buf, PAGE_SIZE, "%u\n", valid);
- +}
- +
- +static ssize_t udg_sysfs_template_valid_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count)
- +{
- + int retval;
- + unsigned long valid;
- + unsigned char offset;
- + unsigned char byte_num;
- + unsigned char template_flags[2];
- + struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data;
- +
- + retval = sstrtoul(buf, 10, &valid);
- + if (retval)
- + return retval;
- +
- + if (valid > 0)
- + valid = 1;
- +
- + byte_num = udg->template_index / 8;
- + offset = udg->template_index % 8;
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + udg->addr.template_flags,
- + template_flags,
- + sizeof(template_flags));
- + if (retval < 0)
- + return retval;
- +
- + if (valid)
- + template_flags[byte_num] |= (1 << offset);
- + else
- + template_flags[byte_num] &= ~(1 << offset);
- +
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + udg->addr.template_flags,
- + template_flags,
- + sizeof(template_flags));
- + if (retval < 0)
- + return retval;
- +
- +#ifdef STORE_GESTURES
- + udg_read_valid_data();
- +#endif
- +
- + return count;
- +}
- +
- +static ssize_t udg_sysfs_template_clear_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count)
- +{
- + int retval;
- + unsigned int input;
- + const char cmd[] = {'0', 0};
- + struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data;
- +
- + if (sscanf(buf, "%u", &input) != 1)
- + return -EINVAL;
- +
- + if (input != 1)
- + return -EINVAL;
- +
- + memset(udg->template_data_buf, 0x00, udg->template_data_size);
- +
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + udg->addr.template_data,
- + udg->template_data_buf,
- + udg->template_data_size);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to clear template data\n",
- + __func__);
- + return retval;
- + }
- +
- + retval = udg_sysfs_template_valid_store(dev, attr, cmd, 1);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to clear valid bit\n",
- + __func__);
- + return retval;
- + }
- +
- +#ifdef STORE_GESTURES
- + udg_read_template_data(udg->template_index);
- + udg_read_valid_data();
- +#endif
- +
- + return count;
- +}
- +
- +static ssize_t udg_sysfs_trace_size_show(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + return snprintf(buf, PAGE_SIZE, "%u\n", udg->trace_size);
- +}
- +
- +static ssize_t udg_sysfs_trace_data_show(struct file *data_file,
- + struct kobject *kobj, struct bin_attribute *attributes,
- + char *buf, loff_t pos, size_t count)
- +{
- + int retval;
- + unsigned short index = 0;
- + unsigned short trace_data_size;
- + struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data;
- +
- + trace_data_size = udg->trace_size * 5;
- +
- + if (trace_data_size == 0)
- + return -EINVAL;
- +
- + if (count < trace_data_size) {
- +// dev_err(rmi4_data->pdev->dev.parent,
- +// "%s: Not enough space (%d bytes) in buffer\n",
- +// __func__, count);
- + return -EINVAL;
- + }
- +
- + if (udg->trace_data_buf_size < trace_data_size) {
- + if (udg->trace_data_buf_size)
- + kfree(udg->trace_data_buf);
- + udg->trace_data_buf = kzalloc(trace_data_size, GFP_KERNEL);
- + if (!udg->trace_data_buf) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to alloc mem for trace data buffer\n",
- + __func__);
- + udg->trace_data_buf_size = 0;
- + return -ENOMEM;
- + }
- + udg->trace_data_buf_size = trace_data_size;
- + }
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + udg->addr.trace_x,
- + &udg->trace_data_buf[index],
- + udg->trace_size * 2);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to read trace X data\n",
- + __func__);
- + return retval;
- + } else {
- + index += udg->trace_size * 2;
- + }
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + udg->addr.trace_y,
- + &udg->trace_data_buf[index],
- + udg->trace_size * 2);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to read trace Y data\n",
- + __func__);
- + return retval;
- + } else {
- + index += udg->trace_size * 2;
- + }
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + udg->addr.trace_segment,
- + &udg->trace_data_buf[index],
- + udg->trace_size);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to read trace segment data\n",
- + __func__);
- + return retval;
- + }
- +
- + retval = secure_memcpy(buf, count, udg->trace_data_buf,
- + udg->trace_data_buf_size, trace_data_size);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to copy trace data\n",
- + __func__);
- + return retval;
- + }
- +
- + return trace_data_size;
- +}
- +
- +static ssize_t udg_sysfs_template_data_show(struct file *data_file,
- + struct kobject *kobj, struct bin_attribute *attributes,
- + char *buf, loff_t pos, size_t count)
- +{
- + int retval;
- + struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data;
- +
- + if (count < udg->template_data_size) {
- +// dev_err(rmi4_data->pdev->dev.parent,
- +// "%s: Not enough space (%d bytes) in buffer\n",
- +// __func__, count);
- + return -EINVAL;
- + }
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + udg->addr.template_data,
- + udg->template_data_buf,
- + udg->template_data_size);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to read template data\n",
- + __func__);
- + return retval;
- + }
- +
- + retval = secure_memcpy(buf, count, udg->template_data_buf,
- + udg->template_data_size, udg->template_data_size);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to copy template data\n",
- + __func__);
- + return retval;
- + }
- +
- +#ifdef STORE_GESTURES
- + udg_read_template_data(udg->template_index);
- + udg_read_valid_data();
- +#endif
- +
- + return udg->template_data_size;
- +}
- +
- +static ssize_t udg_sysfs_template_data_store(struct file *data_file,
- + struct kobject *kobj, struct bin_attribute *attributes,
- + char *buf, loff_t pos, size_t count)
- +{
- + int retval;
- + struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data;
- +
- + retval = secure_memcpy(udg->template_data_buf, udg->template_data_size,
- + buf, count, count);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to copy template data\n",
- + __func__);
- + return retval;
- + }
- +
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + udg->addr.template_data,
- + udg->template_data_buf,
- + count);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to write template data\n",
- + __func__);
- + return retval;
- + }
- +
- +#ifdef STORE_GESTURES
- + udg_read_template_data(udg->template_index);
- + udg_read_valid_data();
- +#endif
- +
- + return count;
- +}
- +
- +static ssize_t udg_sysfs_template_displacement_show(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + int retval;
- + unsigned short template_displacement;
- +
- + retval = udg_read_tuning_params();
- + if (retval < 0)
- + return retval;
- +
- + template_displacement =
- + ((unsigned short)udg->tuning.template_disp_lsb << 0) |
- + ((unsigned short)udg->tuning.template_disp_msb << 8);
- +
- + return snprintf(buf, PAGE_SIZE, "%u\n", template_displacement);
- +}
- +
- +static ssize_t udg_sysfs_template_displacement_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count)
- +{
- + int retval;
- + unsigned long input;
- +
- + retval = sstrtoul(buf, 10, &input);
- + if (retval)
- + return retval;
- +
- + retval = udg_read_tuning_params();
- + if (retval < 0)
- + return retval;
- +
- + udg->tuning.template_disp_lsb = (unsigned char)(input >> 0);
- + udg->tuning.template_disp_msb = (unsigned char)(input >> 8);
- +
- + retval = udg_write_tuning_params();
- + if (retval < 0)
- + return retval;
- +
- + return count;
- +}
- +
- +static ssize_t udg_sysfs_rotation_invariance_show(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + int retval;
- + unsigned short rotation_invariance;
- +
- + retval = udg_read_tuning_params();
- + if (retval < 0)
- + return retval;
- +
- + rotation_invariance =
- + ((unsigned short)udg->tuning.rotation_inv_lsb << 0) |
- + ((unsigned short)udg->tuning.rotation_inv_msb << 8);
- +
- + return snprintf(buf, PAGE_SIZE, "%u\n", rotation_invariance);
- +}
- +
- +static ssize_t udg_sysfs_rotation_invariance_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count)
- +{
- + int retval;
- + unsigned long input;
- +
- + retval = sstrtoul(buf, 10, &input);
- + if (retval)
- + return retval;
- +
- + retval = udg_read_tuning_params();
- + if (retval < 0)
- + return retval;
- +
- + udg->tuning.rotation_inv_lsb = (unsigned char)(input >> 0);
- + udg->tuning.rotation_inv_msb = (unsigned char)(input >> 8);
- +
- + retval = udg_write_tuning_params();
- + if (retval < 0)
- + return retval;
- +
- + return count;
- +}
- +
- +static ssize_t udg_sysfs_scale_invariance_show(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + int retval;
- + unsigned short scale_invariance;
- +
- + retval = udg_read_tuning_params();
- + if (retval < 0)
- + return retval;
- +
- + scale_invariance =
- + ((unsigned short)udg->tuning.scale_inv_lsb << 0) |
- + ((unsigned short)udg->tuning.scale_inv_msb << 8);
- +
- + return snprintf(buf, PAGE_SIZE, "%u\n", scale_invariance);
- +}
- +
- +static ssize_t udg_sysfs_scale_invariance_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count)
- +{
- + int retval;
- + unsigned long input;
- +
- + retval = sstrtoul(buf, 10, &input);
- + if (retval)
- + return retval;
- +
- + retval = udg_read_tuning_params();
- + if (retval < 0)
- + return retval;
- +
- + udg->tuning.scale_inv_lsb = (unsigned char)(input >> 0);
- + udg->tuning.scale_inv_msb = (unsigned char)(input >> 8);
- +
- + retval = udg_write_tuning_params();
- + if (retval < 0)
- + return retval;
- +
- + return count;
- +}
- +
- +static ssize_t udg_sysfs_threshold_factor_show(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + int retval;
- + unsigned short threshold_factor;
- +
- + retval = udg_read_tuning_params();
- + if (retval < 0)
- + return retval;
- +
- + threshold_factor =
- + ((unsigned short)udg->tuning.thres_factor_lsb << 0) |
- + ((unsigned short)udg->tuning.thres_factor_msb << 8);
- +
- + return snprintf(buf, PAGE_SIZE, "%u\n", threshold_factor);
- +}
- +
- +static ssize_t udg_sysfs_threshold_factor_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count)
- +{
- + int retval;
- + unsigned long input;
- +
- + retval = sstrtoul(buf, 10, &input);
- + if (retval)
- + return retval;
- +
- + retval = udg_read_tuning_params();
- + if (retval < 0)
- + return retval;
- +
- + udg->tuning.thres_factor_lsb = (unsigned char)(input >> 0);
- + udg->tuning.thres_factor_msb = (unsigned char)(input >> 8);
- +
- + retval = udg_write_tuning_params();
- + if (retval < 0)
- + return retval;
- +
- + return count;
- +}
- +
- +static ssize_t udg_sysfs_match_metric_threshold_show(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + int retval;
- + unsigned short match_metric_threshold;
- +
- + retval = udg_read_tuning_params();
- + if (retval < 0)
- + return retval;
- +
- + match_metric_threshold =
- + ((unsigned short)udg->tuning.metric_thres_lsb << 0) |
- + ((unsigned short)udg->tuning.metric_thres_msb << 8);
- +
- + return snprintf(buf, PAGE_SIZE, "%u\n", match_metric_threshold);
- +}
- +
- +static ssize_t udg_sysfs_match_metric_threshold_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count)
- +{
- + int retval;
- + unsigned long input;
- +
- + retval = sstrtoul(buf, 10, &input);
- + if (retval)
- + return retval;
- +
- + retval = udg_read_tuning_params();
- + if (retval < 0)
- + return retval;
- +
- + udg->tuning.metric_thres_lsb = (unsigned char)(input >> 0);
- + udg->tuning.metric_thres_msb = (unsigned char)(input >> 8);
- +
- + retval = udg_write_tuning_params();
- + if (retval < 0)
- + return retval;
- +
- + return count;
- +}
- +
- +static ssize_t udg_sysfs_max_inter_stroke_time_show(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + int retval;
- + unsigned short max_inter_stroke_time;
- +
- + retval = udg_read_tuning_params();
- + if (retval < 0)
- + return retval;
- +
- + max_inter_stroke_time =
- + ((unsigned short)udg->tuning.inter_stroke_lsb << 0) |
- + ((unsigned short)udg->tuning.inter_stroke_msb << 8);
- +
- + return snprintf(buf, PAGE_SIZE, "%u\n", max_inter_stroke_time);
- +}
- +
- +static ssize_t udg_sysfs_max_inter_stroke_time_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count)
- +{
- + int retval;
- + unsigned long input;
- +
- + retval = sstrtoul(buf, 10, &input);
- + if (retval)
- + return retval;
- +
- + retval = udg_read_tuning_params();
- + if (retval < 0)
- + return retval;
- +
- + udg->tuning.inter_stroke_lsb = (unsigned char)(input >> 0);
- + udg->tuning.inter_stroke_msb = (unsigned char)(input >> 8);
- +
- + retval = udg_write_tuning_params();
- + if (retval < 0)
- + return retval;
- +
- + return count;
- +}
- +
- +static int udg_ctrl_subpacket(unsigned char ctrlreg,
- + unsigned char subpacket,
- + struct synaptics_rmi4_f12_query_5 *query_5)
- +{
- + int retval;
- + unsigned char cnt;
- + unsigned char regnum;
- + unsigned char bitnum;
- + unsigned char q5_index;
- + unsigned char q6_index;
- + unsigned char offset;
- + unsigned char max_ctrlreg;
- + unsigned char *query_6;
- + struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data;
- +
- + max_ctrlreg = (sizeof(query_5->data) - 1) * 8 - 1;
- +
- + if (ctrlreg > max_ctrlreg) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Control register number (%d) over limit\n",
- + __func__, ctrlreg);
- + return -EINVAL;
- + }
- +
- + q5_index = ctrlreg / 8 + 1;
- + bitnum = ctrlreg % 8;
- + if ((query_5->data[q5_index] & (1 << bitnum)) == 0x00) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Control %d is not present\n",
- + __func__, ctrlreg);
- + return -EINVAL;
- + }
- +
- + query_6 = kmalloc(query_5->size_of_query6, GFP_KERNEL);
- + if (!query_6) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to alloc mem for query 6\n",
- + __func__);
- + return -ENOMEM;
- + }
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + udg->query_base_addr + 6,
- + query_6,
- + query_5->size_of_query6);
- + if (retval < 0)
- + goto exit;
- +
- + q6_index = 0;
- +
- + for (regnum = 0; regnum < ctrlreg; regnum++) {
- + q5_index = regnum / 8 + 1;
- + bitnum = regnum % 8;
- + if ((query_5->data[q5_index] & (1 << bitnum)) == 0x00)
- + continue;
- +
- + if (query_6[q6_index] == 0x00)
- + q6_index += 3;
- + else
- + q6_index++;
- +
- + while (query_6[q6_index] & ~MASK_7BIT)
- + q6_index++;
- +
- + q6_index++;
- + }
- +
- + cnt = 0;
- + q6_index++;
- + offset = subpacket / 7;
- + bitnum = subpacket % 7;
- +
- + do {
- + if (cnt == offset) {
- + if (query_6[q6_index + cnt] & (1 << bitnum))
- + retval = 1;
- + else
- + retval = 0;
- + goto exit;
- + }
- + cnt++;
- + } while (query_6[q6_index + cnt - 1] & ~MASK_7BIT);
- +
- + retval = 0;
- +
- +exit:
- + kfree(query_6);
- +
- + return retval;
- +}
- +
- +static int udg_read_tuning_params(void)
- +{
- + int retval;
- + struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data;
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + udg->addr.ctrl_18,
- + udg->ctrl_buf,
- + udg->ctrl_18_sub10_off + sizeof(struct udg_tuning));
- + if (retval < 0)
- + return retval;
- +
- + secure_memcpy(udg->tuning.data,
- + sizeof(udg->tuning.data),
- + (unsigned char *)&udg->ctrl_buf[udg->ctrl_18_sub10_off],
- + sizeof(struct udg_tuning),
- + sizeof(struct udg_tuning));
- +
- + return 0;
- +}
- +
- +static int udg_write_tuning_params(void)
- +{
- + int retval;
- + struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data;
- +
- + secure_memcpy((unsigned char *)&udg->ctrl_buf[udg->ctrl_18_sub10_off],
- + sizeof(struct udg_tuning),
- + udg->tuning.data,
- + sizeof(udg->tuning.data),
- + sizeof(struct udg_tuning));
- +
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + udg->addr.ctrl_18,
- + udg->ctrl_buf,
- + udg->ctrl_18_sub10_off + sizeof(struct udg_tuning));
- + if (retval < 0)
- + return retval;
- +
- + return 0;
- +}
- +
- +static int udg_detection_enable(bool enable)
- +{
- + int retval;
- + struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data;
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + udg->addr.ctrl_20,
- + udg->ctrl_buf,
- + udg->ctrl_20_sub1_off + 1);
- + if (retval < 0)
- + return retval;
- +
- + if (enable)
- + udg->ctrl_buf[udg->ctrl_20_sub1_off] = WAKEUP_GESTURE_MODE;
- + else
- + udg->ctrl_buf[udg->ctrl_20_sub1_off] = udg->report_flags;
- +
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + udg->addr.ctrl_20,
- + udg->ctrl_buf,
- + udg->ctrl_20_sub1_off + 1);
- + if (retval < 0)
- + return retval;
- +
- + return 0;
- +}
- +
- +static int udg_engine_enable(bool enable)
- +{
- + int retval;
- + struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data;
- +
- + if (enable) {
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + udg->addr.ctrl_27,
- + udg->ctrl_buf,
- + udg->ctrl_27_sub5_off + 1);
- + if (retval < 0)
- + return retval;
- +
- + udg->ctrl_buf[udg->ctrl_27_sub5_off] |=
- + (1 << CTRL27_UDG_ENABLE_BIT);
- +
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + udg->addr.ctrl_27,
- + udg->ctrl_buf,
- + udg->ctrl_27_sub5_off + 1);
- + if (retval < 0)
- + return retval;
- + } else {
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + udg->addr.ctrl_27,
- + udg->ctrl_buf,
- + udg->ctrl_27_sub5_off + 1);
- + if (retval < 0)
- + return retval;
- +
- + udg->ctrl_buf[udg->ctrl_27_sub5_off] &=
- + ~(1 << CTRL27_UDG_ENABLE_BIT);
- +
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + udg->addr.ctrl_27,
- + udg->ctrl_buf,
- + udg->ctrl_27_sub5_off + 1);
- + if (retval < 0)
- + return retval;
- + }
- +
- + return 0;
- +}
- +
- +static void udg_report(void)
- +{
- + int retval;
- + struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data;
- +
- + atomic_set(&udg->attn_event, 1);
- +
- + if (rmi4_data->suspend) {
- + if (rmi4_data->gesture_detection[0] == 0) {
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + udg->addr.data_4,
- + rmi4_data->gesture_detection,
- + sizeof(rmi4_data->gesture_detection));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to read gesture detection\n",
- + __func__);
- + return;
- + }
- + }
- +
- + udg->detection_status = rmi4_data->gesture_detection[0];
- + rmi4_data->gesture_detection[0] = 0;
- +
- + if (udg->detection_status == DETECTION) {
- + input_report_key(udg->udg_dev, KEY_WAKEUP, 1);
- + input_sync(udg->udg_dev);
- + input_report_key(udg->udg_dev, KEY_WAKEUP, 0);
- + input_sync(udg->udg_dev);
- + rmi4_data->suspend = false;
- + }
- + }
- +
- + return;
- +}
- +
- +static int udg_set_index(unsigned char index)
- +{
- + int retval;
- + struct synaptics_rmi4_f12_control_41 control_41;
- + struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data;
- +
- + if (index >= udg->max_num_templates)
- + return -EINVAL;
- +
- + udg->template_index = index;
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + udg->addr.ctrl_41,
- + control_41.data,
- + sizeof(control_41.data));
- + if (retval < 0)
- + return retval;
- +
- + control_41.template_index = udg->template_index;
- +
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + udg->addr.ctrl_41,
- + control_41.data,
- + sizeof(control_41.data));
- + if (retval < 0)
- + return retval;
- +
- + return 0;
- +}
- +
- +#ifdef STORE_GESTURES
- +static int udg_read_valid_data(void)
- +{
- + int retval;
- + struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data;
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + udg->addr.template_flags,
- + udg->valid_buf,
- + sizeof(udg->valid_buf));
- + if (retval < 0)
- + return retval;
- +
- + return 0;
- +}
- +
- +static int udg_write_valid_data(void)
- +{
- + int retval;
- + struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data;
- +
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + udg->addr.template_flags,
- + udg->valid_buf,
- + sizeof(udg->valid_buf));
- + if (retval < 0)
- + return retval;
- +
- + return 0;
- +}
- +
- +static int udg_read_template_data(unsigned char index)
- +{
- + int retval;
- + unsigned char *storage;
- + struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data;
- +
- + udg_set_index(index);
- + storage = &(udg->storage_buf[index * udg->template_data_size]);
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + udg->addr.template_data,
- + storage,
- + udg->template_data_size);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to read template data\n",
- + __func__);
- + return retval;
- + }
- +
- + return 0;
- +}
- +
- +static int udg_write_template_data(void)
- +{
- + int retval;
- + unsigned char ii;
- + unsigned char *storage;
- + struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data;
- +
- + for (ii = 0; ii < udg->gestures_to_store; ii++) {
- + udg_set_index(ii);
- + storage = &(udg->storage_buf[ii * udg->template_data_size]);
- +
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + udg->addr.template_data,
- + storage,
- + udg->template_data_size);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to write template data\n",
- + __func__);
- + return retval;
- + }
- + }
- +
- + return 0;
- +}
- +#endif
- +
- +static int udg_reg_init(void)
- +{
- + int retval;
- + unsigned char ii;
- + unsigned char data_offset;
- + unsigned char size_of_query;
- + unsigned char ctrl_18_offset;
- + unsigned char ctrl_20_offset;
- + unsigned char ctrl_23_offset;
- + unsigned char ctrl_27_offset;
- + unsigned char ctrl_41_offset;
- + struct synaptics_rmi4_f12_query_0 query_0;
- + struct synaptics_rmi4_f12_query_5 query_5;
- + struct synaptics_rmi4_f12_query_8 query_8;
- + struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data;
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + udg->query_base_addr + 7,
- + &size_of_query,
- + sizeof(size_of_query));
- + if (retval < 0)
- + return retval;
- +
- + if (size_of_query < 4) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: User defined gesture support unavailable "
- + "(missing data registers)\n",
- + __func__);
- + retval = -ENODEV;
- + return retval;
- + }
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + udg->query_base_addr + 8,
- + query_8.data,
- + sizeof(query_8.data));
- + if (retval < 0)
- + return retval;
- +
- + if ((query_8.data16_is_present) &&
- + (query_8.data17_is_present) &&
- + (query_8.data18_is_present) &&
- + (query_8.data19_is_present) &&
- + (query_8.data20_is_present) &&
- + (query_8.data21_is_present)) {
- + data_offset = query_8.data0_is_present +
- + query_8.data1_is_present +
- + query_8.data2_is_present +
- + query_8.data3_is_present;
- + udg->addr.data_4 = udg->data_base_addr + data_offset;
- + data_offset = data_offset +
- + query_8.data4_is_present +
- + query_8.data5_is_present +
- + query_8.data6_is_present +
- + query_8.data7_is_present +
- + query_8.data8_is_present +
- + query_8.data9_is_present +
- + query_8.data10_is_present +
- + query_8.data11_is_present +
- + query_8.data12_is_present +
- + query_8.data13_is_present +
- + query_8.data14_is_present +
- + query_8.data15_is_present;
- + udg->addr.trace_x = udg->data_base_addr + data_offset;
- + udg->addr.trace_y = udg->addr.trace_x + 1;
- + udg->addr.trace_segment = udg->addr.trace_y + 1;
- + udg->addr.template_helper = udg->addr.trace_segment + 1;
- + udg->addr.template_data = udg->addr.template_helper + 1;
- + udg->addr.template_flags = udg->addr.template_data + 1;
- + } else {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: User defined gesture support unavailable "
- + "(missing data registers)\n",
- + __func__);
- + retval = -ENODEV;
- + return retval;
- + }
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + udg->query_base_addr + 4,
- + &size_of_query,
- + sizeof(size_of_query));
- + if (retval < 0)
- + return retval;
- +
- + if (size_of_query < 7) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: User defined gesture support unavailable "
- + "(missing control registers)\n",
- + __func__);
- + retval = -ENODEV;
- + return retval;
- + }
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + udg->query_base_addr + 5,
- + query_5.data,
- + sizeof(query_5.data));
- + if (retval < 0)
- + return retval;
- +
- + ctrl_18_offset = query_5.ctrl0_is_present +
- + query_5.ctrl1_is_present +
- + query_5.ctrl2_is_present +
- + query_5.ctrl3_is_present +
- + query_5.ctrl4_is_present +
- + query_5.ctrl5_is_present +
- + query_5.ctrl6_is_present +
- + query_5.ctrl7_is_present +
- + query_5.ctrl8_is_present +
- + query_5.ctrl9_is_present +
- + query_5.ctrl10_is_present +
- + query_5.ctrl11_is_present +
- + query_5.ctrl12_is_present +
- + query_5.ctrl13_is_present +
- + query_5.ctrl14_is_present +
- + query_5.ctrl15_is_present +
- + query_5.ctrl16_is_present +
- + query_5.ctrl17_is_present;
- +
- + ctrl_20_offset = ctrl_18_offset +
- + query_5.ctrl18_is_present +
- + query_5.ctrl19_is_present;
- +
- + ctrl_23_offset = ctrl_20_offset +
- + query_5.ctrl20_is_present +
- + query_5.ctrl21_is_present +
- + query_5.ctrl22_is_present;
- +
- + ctrl_27_offset = ctrl_23_offset+
- + query_5.ctrl23_is_present +
- + query_5.ctrl24_is_present +
- + query_5.ctrl25_is_present +
- + query_5.ctrl26_is_present;
- +
- + ctrl_41_offset = ctrl_27_offset+
- + query_5.ctrl27_is_present +
- + query_5.ctrl28_is_present +
- + query_5.ctrl29_is_present +
- + query_5.ctrl30_is_present +
- + query_5.ctrl31_is_present +
- + query_5.ctrl32_is_present +
- + query_5.ctrl33_is_present +
- + query_5.ctrl34_is_present +
- + query_5.ctrl35_is_present +
- + query_5.ctrl36_is_present +
- + query_5.ctrl37_is_present +
- + query_5.ctrl38_is_present +
- + query_5.ctrl39_is_present +
- + query_5.ctrl40_is_present;
- +
- + udg->addr.ctrl_18 = udg->control_base_addr + ctrl_18_offset;
- + udg->addr.ctrl_20 = udg->control_base_addr + ctrl_20_offset;
- + udg->addr.ctrl_23 = udg->control_base_addr + ctrl_23_offset;
- + udg->addr.ctrl_27 = udg->control_base_addr + ctrl_27_offset;
- + udg->addr.ctrl_41 = udg->control_base_addr + ctrl_41_offset;
- +
- + udg->ctrl_18_sub10_off = 0;
- + for (ii = 0; ii < 10; ii++) {
- + retval = udg_ctrl_subpacket(18, ii, &query_5);
- + if (retval == 1)
- + udg->ctrl_18_sub10_off += ctrl_18_sub_size[ii];
- + else if (retval < 0)
- + return retval;
- + }
- +
- + udg->ctrl_20_sub1_off = 0;
- + for (ii = 0; ii < 1; ii++) {
- + retval = udg_ctrl_subpacket(20, ii, &query_5);
- + if (retval == 1)
- + udg->ctrl_20_sub1_off += ctrl_20_sub_size[ii];
- + else if (retval < 0)
- + return retval;
- + }
- +
- + udg->ctrl_23_sub3_off = 0;
- + for (ii = 0; ii < 3; ii++) {
- + retval = udg_ctrl_subpacket(23, ii, &query_5);
- + if (retval == 1)
- + udg->ctrl_23_sub3_off += ctrl_23_sub_size[ii];
- + else if (retval < 0)
- + return retval;
- + }
- +
- + retval = udg_ctrl_subpacket(23, 3, &query_5);
- + if (retval == 0)
- + udg->ctrl_23_sub3_off = 0;
- + else if (retval < 0)
- + return retval;
- +
- + udg->ctrl_27_sub5_off = 0;
- + for (ii = 0; ii < 5; ii++) {
- + retval = udg_ctrl_subpacket(27, ii, &query_5);
- + if (retval == 1)
- + udg->ctrl_27_sub5_off += ctrl_27_sub_size[ii];
- + else if (retval < 0)
- + return retval;
- + }
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + udg->query_base_addr + 0,
- + query_0.data,
- + sizeof(query_0.data));
- + if (retval < 0)
- + return retval;
- +
- + udg->max_num_templates = query_0.max_num_templates;
- + udg->template_size =
- + ((unsigned short)query_0.template_size_lsb << 0) |
- + ((unsigned short)query_0.template_size_msb << 8);
- + udg->template_data_size = udg->template_size * 4 * 2 + 4 + 1;
- +
- +#ifdef STORE_GESTURES
- + udg->gestures_to_store = udg->max_num_templates;
- + if (GESTURES_TO_STORE < udg->gestures_to_store)
- + udg->gestures_to_store = GESTURES_TO_STORE;
- +#endif
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + udg->addr.ctrl_20,
- + udg->ctrl_buf,
- + udg->ctrl_20_sub1_off + 1);
- + if (retval < 0)
- + return retval;
- +
- + udg->report_flags = udg->ctrl_buf[udg->ctrl_20_sub1_off];
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + udg->addr.ctrl_23,
- + udg->ctrl_buf,
- + udg->ctrl_23_sub3_off + 1);
- + if (retval < 0)
- + return retval;
- +
- + udg->object_type_enable1 = udg->ctrl_buf[0];
- + if (udg->ctrl_23_sub3_off)
- + udg->object_type_enable2 = udg->ctrl_buf[udg->ctrl_23_sub3_off];
- +
- + return retval;
- +}
- +
- +static int udg_scan_pdt(void)
- +{
- + int retval;
- + unsigned char ii;
- + unsigned char page;
- + unsigned char intr_count = 0;
- + unsigned char intr_off;
- + unsigned char intr_src;
- + unsigned short addr;
- + struct synaptics_rmi4_fn_desc fd;
- + struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data;
- +
- + for (page = 0; page < PAGES_TO_SERVICE; page++) {
- + for (addr = PDT_START; addr > PDT_END; addr -= PDT_ENTRY_SIZE) {
- + addr |= (page << 8);
- +
- + retval = synaptics_rmi4_reg_read(rmi4_data,
- + addr,
- + (unsigned char *)&fd,
- + sizeof(fd));
- + if (retval < 0)
- + return retval;
- +
- + addr &= ~(MASK_8BIT << 8);
- +
- + if (fd.fn_number) {
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: Found F%02x\n",
- + __func__, fd.fn_number);
- + switch (fd.fn_number) {
- + case SYNAPTICS_RMI4_F12:
- + goto f12_found;
- + break;
- + }
- + } else {
- + break;
- + }
- +
- + intr_count += fd.intr_src_count;
- + }
- + }
- +
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to find F12\n",
- + __func__);
- + return -EINVAL;
- +
- +f12_found:
- + udg->query_base_addr = fd.query_base_addr | (page << 8);
- + udg->control_base_addr = fd.ctrl_base_addr | (page << 8);
- + udg->data_base_addr = fd.data_base_addr | (page << 8);
- + udg->command_base_addr = fd.cmd_base_addr | (page << 8);
- +
- + retval = udg_reg_init();
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to initialize user defined gesture registers\n",
- + __func__);
- + return retval;
- + }
- +
- + udg->intr_mask = 0;
- + intr_src = fd.intr_src_count;
- + intr_off = intr_count % 8;
- + for (ii = intr_off;
- + ii < (intr_src + intr_off);
- + ii++) {
- + udg->intr_mask |= 1 << ii;
- + }
- +
- + rmi4_data->intr_mask[0] |= udg->intr_mask;
- +
- + addr = rmi4_data->f01_ctrl_base_addr + 1;
- +
- + retval = synaptics_rmi4_reg_write(rmi4_data,
- + addr,
- + &rmi4_data->intr_mask[0],
- + sizeof(rmi4_data->intr_mask[0]));
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to set interrupt enable bit\n",
- + __func__);
- + return retval;
- + }
- +
- + return 0;
- +}
- +
- +static void synaptics_rmi4_udg_attn(struct synaptics_rmi4_data *rmi4_data,
- + unsigned char intr_mask)
- +{
- + if (!udg)
- + return;
- +
- + if (udg->intr_mask & intr_mask)
- + udg_report();
- +
- + return;
- +}
- +
- +static int synaptics_rmi4_udg_init(struct synaptics_rmi4_data *rmi4_data)
- +{
- + int retval;
- + unsigned char ii;
- + unsigned char size;
- + unsigned char attr_count;
- + unsigned char param_count;
- +
- + if (udg) {
- + dev_dbg(rmi4_data->pdev->dev.parent,
- + "%s: Handle already exists\n",
- + __func__);
- + return 0;
- + }
- +
- + udg = kzalloc(sizeof(*udg), GFP_KERNEL);
- + if (!udg) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to alloc mem for udg\n",
- + __func__);
- + retval = -ENOMEM;
- + goto exit;
- + }
- +
- + size = 0;
- + for (ii = 0; ii < sizeof(ctrl_18_sub_size); ii++)
- + size += ctrl_18_sub_size[ii];
- + size += sizeof(struct udg_tuning);
- + udg->ctrl_buf = kzalloc(size, GFP_KERNEL);
- + if (!udg->ctrl_buf) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to alloc mem for ctrl_buf\n",
- + __func__);
- + retval = -ENOMEM;
- + goto exit_free_udg;
- + }
- +
- + udg->rmi4_data = rmi4_data;
- +
- + retval = udg_scan_pdt();
- + if (retval < 0)
- + goto exit_free_ctrl_buf;
- +
- + udg->template_data_buf = kzalloc(udg->template_data_size, GFP_KERNEL);
- + if (!udg->template_data_buf) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to alloc mem for template_data_buf\n",
- + __func__);
- + retval = -ENOMEM;
- + goto exit_free_ctrl_buf;
- + }
- +
- +#ifdef STORE_GESTURES
- + udg->storage_buf = kzalloc(
- + udg->template_data_size * udg->gestures_to_store,
- + GFP_KERNEL);
- + if (!udg->storage_buf) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to alloc mem for storage_buf\n",
- + __func__);
- + kfree(udg->template_data_buf);
- + retval = -ENOMEM;
- + goto exit_free_ctrl_buf;
- + }
- +#endif
- +
- + udg->udg_dev = input_allocate_device();
- + if (udg->udg_dev == NULL) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to allocate gesture device\n",
- + __func__);
- + retval = -ENOMEM;
- + goto exit_free_template_data_buf;
- + }
- +
- + udg->udg_dev->name = GESTURE_DRIVER_NAME;
- + udg->udg_dev->phys = GESTURE_PHYS_NAME;
- + udg->udg_dev->id.product = SYNAPTICS_DSX_DRIVER_PRODUCT;
- + udg->udg_dev->id.version = SYNAPTICS_DSX_DRIVER_VERSION;
- + udg->udg_dev->dev.parent = rmi4_data->pdev->dev.parent;
- + input_set_drvdata(udg->udg_dev, rmi4_data);
- +
- + set_bit(EV_KEY, udg->udg_dev->evbit);
- + set_bit(KEY_WAKEUP, udg->udg_dev->keybit);
- + input_set_capability(udg->udg_dev, EV_KEY, KEY_WAKEUP);
- +
- + retval = input_register_device(udg->udg_dev);
- + if (retval) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to register gesture device\n",
- + __func__);
- + input_free_device(udg->udg_dev);
- + goto exit_free_template_data_buf;
- + }
- +
- + udg->tuning_dir = kobject_create_and_add(TUNING_SYSFS_DIR_NAME,
- + &udg->udg_dev->dev.kobj);
- + if (!udg->tuning_dir) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to create tuning sysfs directory\n",
- + __func__);
- + goto exit_unregister_input_device;
- + }
- +
- + retval = sysfs_create_bin_file(&udg->udg_dev->dev.kobj, &template_data);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to create template data bin file\n",
- + __func__);
- + goto exit_remove_sysfs_directory;
- + }
- +
- + retval = sysfs_create_bin_file(&udg->udg_dev->dev.kobj, &trace_data);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to create trace data bin file\n",
- + __func__);
- + goto exit_remove_bin_file;
- + }
- +
- + for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
- + retval = sysfs_create_file(&udg->udg_dev->dev.kobj,
- + &attrs[attr_count].attr);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to create sysfs attributes\n",
- + __func__);
- + retval = -ENODEV;
- + goto exit_remove_attrs;
- + }
- + }
- +
- + for (param_count = 0; param_count < ARRAY_SIZE(params); param_count++) {
- + retval = sysfs_create_file(udg->tuning_dir,
- + ¶ms[param_count].attr);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to create tuning parameters\n",
- + __func__);
- + retval = -ENODEV;
- + goto exit_remove_params;
- + }
- + }
- +
- + retval = udg_engine_enable(true);
- + if (retval < 0) {
- + dev_err(rmi4_data->pdev->dev.parent,
- + "%s: Failed to enable gesture engine\n",
- + __func__);
- + goto exit_remove_params;
- + }
- +
- + return 0;
- +
- +exit_remove_params:
- + for (param_count--; param_count >= 0; param_count--) {
- + sysfs_remove_file(udg->tuning_dir,
- + ¶ms[param_count].attr);
- + }
- +
- +exit_remove_attrs:
- + for (attr_count--; attr_count >= 0; attr_count--) {
- + sysfs_remove_file(&udg->udg_dev->dev.kobj,
- + &attrs[attr_count].attr);
- + }
- +
- + sysfs_remove_bin_file(&udg->udg_dev->dev.kobj, &trace_data);
- +
- +exit_remove_bin_file:
- + sysfs_remove_bin_file(&udg->udg_dev->dev.kobj, &template_data);
- +
- +exit_remove_sysfs_directory:
- + kobject_put(udg->tuning_dir);
- +
- +exit_unregister_input_device:
- + input_unregister_device(udg->udg_dev);
- +
- +exit_free_template_data_buf:
- +#ifdef STORE_GESTURES
- + kfree(udg->storage_buf);
- +#endif
- + kfree(udg->template_data_buf);
- +
- +exit_free_ctrl_buf:
- + kfree(udg->ctrl_buf);
- +
- +exit_free_udg:
- + kfree(udg);
- + udg = NULL;
- +
- +exit:
- + return retval;
- +}
- +
- +static void synaptics_rmi4_udg_remove(struct synaptics_rmi4_data *rmi4_data)
- +{
- + unsigned char count;
- +
- + if (!udg)
- + goto exit;
- +
- + for (count = 0; count < ARRAY_SIZE(params); count++) {
- + sysfs_remove_file(udg->tuning_dir,
- + ¶ms[count].attr);
- + }
- +
- + for (count = 0; count < ARRAY_SIZE(attrs); count++) {
- + sysfs_remove_file(&udg->udg_dev->dev.kobj,
- + &attrs[count].attr);
- + }
- +
- + sysfs_remove_bin_file(&udg->udg_dev->dev.kobj, &trace_data);
- + sysfs_remove_bin_file(&udg->udg_dev->dev.kobj, &template_data);
- + kobject_put(udg->tuning_dir);
- +
- + input_unregister_device(udg->udg_dev);
- +#ifdef STORE_GESTURES
- + kfree(udg->storage_buf);
- +#endif
- + kfree(udg->template_data_buf);
- + kfree(udg->trace_data_buf);
- + kfree(udg->ctrl_buf);
- + kfree(udg);
- + udg = NULL;
- +
- +exit:
- + complete(&udg_remove_complete);
- +
- + return;
- +}
- +
- +static void synaptics_rmi4_udg_reset(struct synaptics_rmi4_data *rmi4_data)
- +{
- + if (!udg) {
- + synaptics_rmi4_udg_init(rmi4_data);
- + return;
- + }
- +
- + udg_scan_pdt();
- + udg_engine_enable(true);
- +#ifdef STORE_GESTURES
- + udg_write_template_data();
- + udg_write_valid_data();
- +#endif
- +
- + return;
- +}
- +
- +static void synaptics_rmi4_udg_reinit(struct synaptics_rmi4_data *rmi4_data)
- +{
- + if (!udg)
- + return;
- +
- + udg_engine_enable(true);
- +#ifdef STORE_GESTURES
- + udg_write_template_data();
- + udg_write_valid_data();
- +#endif
- +
- + return;
- +}
- +
- +static void synaptics_rmi4_udg_e_suspend(struct synaptics_rmi4_data *rmi4_data)
- +{
- + if (!udg)
- + return;
- +
- + rmi4_data->sleep_enable(rmi4_data, false);
- + rmi4_data->irq_enable(rmi4_data, true, false);
- + enable_irq_wake(rmi4_data->irq);
- +
- + udg_engine_enable(true);
- + udg_detection_enable(true);
- +
- + return;
- +}
- +
- +static void synaptics_rmi4_udg_suspend(struct synaptics_rmi4_data *rmi4_data)
- +{
- + if (!udg)
- + return;
- +
- + rmi4_data->sleep_enable(rmi4_data, false);
- + rmi4_data->irq_enable(rmi4_data, true, false);
- + enable_irq_wake(rmi4_data->irq);
- +
- + udg_engine_enable(true);
- + udg_detection_enable(true);
- +
- + return;
- +}
- +
- +static void synaptics_rmi4_udg_resume(struct synaptics_rmi4_data *rmi4_data)
- +{
- + if (!udg)
- + return;
- +
- + disable_irq_wake(rmi4_data->irq);
- + udg_detection_enable(false);
- +
- + return;
- +}
- +
- +static void synaptics_rmi4_udg_l_resume(struct synaptics_rmi4_data *rmi4_data)
- +{
- + if (!udg)
- + return;
- +
- + disable_irq_wake(rmi4_data->irq);
- + udg_detection_enable(false);
- +
- + return;
- +}
- +
- +static struct synaptics_rmi4_exp_fn gesture_module = {
- + .fn_type = RMI_GESTURE,
- + .init = synaptics_rmi4_udg_init,
- + .remove = synaptics_rmi4_udg_remove,
- + .reset = synaptics_rmi4_udg_reset,
- + .reinit = synaptics_rmi4_udg_reinit,
- + .early_suspend = synaptics_rmi4_udg_e_suspend,
- + .suspend = synaptics_rmi4_udg_suspend,
- + .resume = synaptics_rmi4_udg_resume,
- + .late_resume = synaptics_rmi4_udg_l_resume,
- + .attn = synaptics_rmi4_udg_attn,
- +};
- +
- +static int __init rmi4_gesture_module_init(void)
- +{
- + synaptics_rmi4_new_function_force(&gesture_module, true);
- +
- + return 0;
- +}
- +
- +static void __exit rmi4_gesture_module_exit(void)
- +{
- + synaptics_rmi4_new_function_force(&gesture_module, false);
- +
- + wait_for_completion(&udg_remove_complete);
- +
- + return;
- +}
- +
- +module_init(rmi4_gesture_module_init);
- +module_exit(rmi4_gesture_module_exit);
- +
- +MODULE_AUTHOR("Synaptics, Inc.");
- +MODULE_DESCRIPTION("Synaptics DSX User Defined Gesture Module");
- +MODULE_LICENSE("GPL v2");
- diff --git a/drivers/input/touchscreen/synaptics_dsx_force/synaptics_dsx_i2c.c b/drivers/input/touchscreen/synaptics_dsx_force/synaptics_dsx_i2c.c
- new file mode 100644
- index 0000000..ca13bdf
- --- /dev/null
- +++ b/drivers/input/touchscreen/synaptics_dsx_force/synaptics_dsx_i2c.c
- @@ -0,0 +1,901 @@
- +/*
- + * Synaptics DSX touchscreen driver
- + *
- + * Copyright (C) 2012-2015 Synaptics Incorporated. All rights reserved.
- + *
- + * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
- + * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
- + * Copyright (C) 2017 XiaoMi, 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.
- + *
- + * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
- + * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
- + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
- + * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
- + * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- + * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
- + * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
- + * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- + * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
- + * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
- + * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
- + * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
- + * DOLLARS.
- + */
- +
- +#include <linux/kernel.h>
- +#include <linux/module.h>
- +#include <linux/slab.h>
- +#include <linux/i2c.h>
- +#include <linux/delay.h>
- +#include <linux/input.h>
- +#include <linux/types.h>
- +#include <linux/of_gpio.h>
- +#include <linux/platform_device.h>
- +#include <linux/input/synaptics_dsx.h>
- +#include "synaptics_dsx_core.h"
- +
- +#define SYN_I2C_RETRY_TIMES 4
- +
- +#define I2C_BURST_LIMIT 2048
- +
- +#define MAX_WRITE_SIZE 4096
- +
- +static unsigned char *wr_buf;
- +
- +static struct synaptics_dsx_hw_interface hw_if;
- +
- +static struct platform_device *synaptics_dsx_i2c_device;
- +
- +#ifdef CONFIG_OF
- +static void dump_dt(struct device *dev, struct synaptics_dsx_board_data *bdata)
- +{
- +}
- +
- +static int parse_dt(struct device *dev, struct synaptics_dsx_board_data *bdata)
- +{
- + int retval;
- + u32 value;
- + const char *name;
- + struct synaptics_dsx_config_info *config_info;
- + struct property *prop;
- + struct device_node *temp, *np = dev->of_node;
- +
- + bdata->irq_gpio = of_get_named_gpio_flags(np,
- + "synaptics,irq-gpio", 0, NULL);
- + if (bdata->irq_gpio < 0)
- + return -EINVAL;
- +
- + retval = of_property_read_u32(np, "synaptics,irq-on-state",
- + &value);
- + if (retval < 0)
- + bdata->irq_on_state = 0;
- + else
- + bdata->irq_on_state = value;
- +
- + retval = of_property_read_u32(np, "synaptics,irq-flags", &value);
- + if (retval < 0)
- + return retval;
- + else
- + bdata->irq_flags = value;
- +
- + retval = of_property_read_string(np, "synaptics,pwr-reg-name", &name);
- + if (retval == -EINVAL)
- + bdata->pwr_reg_name = NULL;
- + else if (retval < 0)
- + return retval;
- + else
- + bdata->pwr_reg_name = name;
- +
- + retval = of_property_read_string(np, "synaptics,bus-reg-name", &name);
- + if (retval == -EINVAL)
- + bdata->bus_reg_name = NULL;
- + else if (retval < 0)
- + return retval;
- + else
- + bdata->bus_reg_name = name;
- +
- + bdata->panel_is_incell = of_property_read_bool(np, "synaptics,panel-is-incell");
- +
- + if (bdata->panel_is_incell) {
- + retval = of_property_read_string(np, "synaptics,lab-reg-name", &name);
- + if (retval == -EINVAL)
- + bdata->lab_reg_name = NULL;
- + else if (retval < 0)
- + return retval;
- + else
- + bdata->lab_reg_name = name;
- +
- + retval = of_property_read_string(np, "synaptics,ibb-reg-name", &name);
- + if (retval == -EINVAL)
- + bdata->ibb_reg_name = NULL;
- + else if (retval < 0)
- + return retval;
- + else
- + bdata->ibb_reg_name = name;
- +
- + retval = of_property_read_string(np, "synaptics,disp-reg-name", &name);
- + if (retval == -EINVAL)
- + bdata->disp_reg_name = NULL;
- + else if (retval < 0)
- + return retval;
- + else
- + bdata->disp_reg_name = name;
- + }
- +
- + retval = of_property_read_string(np, "synaptics,power-gpio-name", &name);
- + if (retval == -EINVAL)
- + bdata->power_gpio_name = NULL;
- + else if (retval < 0)
- + return retval;
- + else
- + bdata->power_gpio_name = name;
- +
- + retval = of_property_read_string(np, "synaptics,reset-gpio-name", &name);
- + if (retval == -EINVAL)
- + bdata->reset_gpio_name = NULL;
- + else if (retval < 0)
- + return retval;
- + else
- + bdata->reset_gpio_name = name;
- +
- + retval = of_property_read_string(np, "synaptics,irq-gpio-name", &name);
- + if (retval == -EINVAL)
- + bdata->irq_gpio_name = NULL;
- + else if (retval < 0)
- + return retval;
- + else
- + bdata->irq_gpio_name = name;
- +
- + bdata->cut_off_power = of_property_read_bool(np, "synaptics,cut-off-power");
- +
- + bdata->power_gpio = of_get_named_gpio_flags(np,
- + "synaptics,power-gpio", 0, NULL);
- + if (bdata->power_gpio >= 0) {
- + retval = of_property_read_u32(np, "synaptics,power-on-state",
- + &value);
- + if (retval < 0)
- + return retval;
- + else
- + bdata->power_on_state = value;
- + } else
- + bdata->power_gpio = -1;
- +
- + retval = of_property_read_u32(np, "synaptics,power-delay-ms",
- + &value);
- + if (retval < 0)
- + bdata->power_delay_ms = 0; /* No power delay by default */
- + else
- + bdata->power_delay_ms = value;
- +
- + bdata->mdss_reset = of_get_named_gpio_flags(np,
- + "synaptics,mdss-dsi-reset", 0, NULL);
- + if (bdata->mdss_reset >= 0) {
- + retval = of_property_read_u32(np, "synaptics,mdss-reset-state",
- + &value);
- + if (retval < 0)
- + return retval;
- + else
- + bdata->mdss_reset_state = value;
- + } else
- + bdata->mdss_reset = -1;
- +
- + bdata->reset_gpio = of_get_named_gpio_flags(np,
- + "synaptics,reset-gpio", 0, NULL);
- + if (bdata->reset_gpio >= 0) {
- + retval = of_property_read_u32(np, "synaptics,reset-on-state",
- + &value);
- + if (retval < 0
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement